File size: 8,019 Bytes
b2644cb c3216d4 b2644cb 23a236c | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 | <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ScribbleSense - Draw and Recognize Text</title>
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://unpkg.com/feather-icons"></script>
<script src="https://cdn.jsdelivr.net/npm/tesseract.js@4/dist/tesseract.min.js"></script>
</head>
<body class="bg-gradient-to-br from-indigo-100 to-purple-50 min-h-screen flex flex-col items-center justify-center p-4">
<div class="max-w-4xl w-full mx-auto text-center">
<h1 class="text-4xl md:text-5xl font-bold text-indigo-800 mb-2">ScribbleSense ✍️</h1>
<p class="text-lg text-indigo-600 mb-8">Draw anything and watch it transform into text!</p>
<div class="bg-white rounded-xl shadow-xl p-6 mb-8">
<div class="relative">
<canvas id="drawingCanvas" class="border-2 border-gray-300 rounded-lg w-full h-64 md:h-96 touch-none bg-white"></canvas>
<div id="clearBtn" class="absolute top-4 right-4 p-2 bg-white rounded-full shadow-md cursor-pointer hover:bg-gray-100 transition">
<i data-feather="x" class="text-gray-600"></i>
</div>
</div>
</div>
<div id="resultContainer" class="bg-white rounded-xl shadow-xl p-6 hidden">
<h2 class="text-2xl font-semibold text-indigo-700 mb-4">Recognized Text</h2>
<div id="resultText" class="text-3xl md:text-4xl font-mono p-4 bg-gray-50 rounded-lg min-h-20 break-all">
<!-- OCR result will appear here -->
</div>
<button id="copyBtn" class="mt-4 px-4 py-2 bg-indigo-600 text-white rounded-lg hover:bg-indigo-700 transition flex items-center justify-center gap-2 mx-auto">
<i data-feather="copy" class="w-5 h-5"></i> Copy Text
</button>
</div>
<div class="mt-8 text-sm text-gray-500">
<p>Draw with left mouse button pressed. The system will automatically recognize your writing after a pause.</p>
<p class="mt-1">Supports: Roman alphabets, numbers, emojis, Chinese, Hangul, and more!</p>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
feather.replace();
const canvas = document.getElementById('drawingCanvas');
const ctx = canvas.getContext('2d');
const resultContainer = document.getElementById('resultContainer');
const resultText = document.getElementById('resultText');
const clearBtn = document.getElementById('clearBtn');
const copyBtn = document.getElementById('copyBtn');
// Set canvas size
function resizeCanvas() {
const containerWidth = canvas.parentElement.clientWidth;
canvas.width = containerWidth - 32; // accounting for padding
canvas.height = Math.min(window.innerHeight * 0.6, 600);
ctx.lineWidth = 4;
ctx.lineCap = 'round';
ctx.strokeStyle = '#4f46e5'; // indigo-600
}
window.addEventListener('resize', resizeCanvas);
resizeCanvas();
// Drawing variables
let isDrawing = false;
let lastX = 0;
let lastY = 0;
let inactivityTimer;
let lastDrawTime = 0;
// Drawing functions
function startDrawing(e) {
isDrawing = true;
[lastX, lastY] = getPosition(e);
clearTimeout(inactivityTimer);
}
function draw(e) {
if (!isDrawing) return;
const [x, y] = getPosition(e);
ctx.beginPath();
ctx.moveTo(lastX, lastY);
ctx.lineTo(x, y);
ctx.stroke();
[lastX, lastY] = [x, y];
lastDrawTime = Date.now();
// Reset inactivity timer
clearTimeout(inactivityTimer);
inactivityTimer = setTimeout(performOCR, 500);
}
function stopDrawing() {
isDrawing = false;
}
function getPosition(e) {
let x, y;
if (e.type.includes('touch')) {
const rect = canvas.getBoundingClientRect();
x = e.touches[0].clientX - rect.left;
y = e.touches[0].clientY - rect.top;
} else {
x = e.offsetX;
y = e.offsetY;
}
return [x, y];
}
// OCR function
function performOCR() {
if (Date.now() - lastDrawTime < 2) return;
Tesseract.recognize(
canvas,
'eng+chi_sim+chi_tra+kor+jpn+equ',
{
logger: m => console.log(m)
}
).then(({ data: { text } }) => {
resultText.textContent = text.trim() || "Couldn't recognize any text";
resultContainer.classList.remove('hidden');
// Scroll to result if needed
resultContainer.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
});
}
// Clear canvas
function clearCanvas() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
resultContainer.classList.add('hidden');
clearTimeout(inactivityTimer);
}
// Copy text function
function copyText() {
navigator.clipboard.writeText(resultText.textContent).then(() => {
const originalText = copyBtn.innerHTML;
copyBtn.innerHTML = '<i data-feather="check" class="w-5 h-5"></i> Copied!';
setTimeout(() => {
copyBtn.innerHTML = originalText;
feather.replace();
}, 2000);
});
}
// Event listeners
canvas.addEventListener('mousedown', startDrawing);
canvas.addEventListener('mousemove', draw);
canvas.addEventListener('mouseup', stopDrawing);
canvas.addEventListener('mouseout', stopDrawing);
// Touch support
canvas.addEventListener('touchstart', (e) => {
e.preventDefault();
startDrawing(e);
});
canvas.addEventListener('touchmove', (e) => {
e.preventDefault();
draw(e);
});
canvas.addEventListener('touchend', stopDrawing);
clearBtn.addEventListener('click', clearCanvas);
copyBtn.addEventListener('click', copyText);
// Instructions tooltip
setTimeout(() => {
const tooltip = document.createElement('div');
tooltip.className = 'absolute bg-indigo-600 text-white px-4 py-2 rounded-lg shadow-lg z-10 animate-bounce';
tooltip.style.top = '20px';
tooltip.style.left = '50%';
tooltip.style.transform = 'translateX(-50%)';
tooltip.textContent = 'Draw here with your mouse or finger!';
canvas.parentElement.appendChild(tooltip);
setTimeout(() => {
tooltip.remove();
}, 3000);
}, 1000);
});
</script>
</body>
</html>
|