//Credits for document.write : https://ancientbrain.com/world.php?world=0970890261
//Writing into ancient brain's html
document.write(`
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Optical character recognition from Doodle</title>
<style>
body{
padding: 0px 100px;
font-family: sans-serif;
}
/* Some CSS styling */
.leftside {
float:left;
width:220px;
height:285px;
background-color:#e4caff;
padding:10px;
border-radius:4px;
}
.rightside {
float:left;
margin-left:10px;
}
#doodlepad {
float:left;
height:300px;
width:400px;
border:2px solid #888;
border-radius:4px;
position:relative;
}
#clearbutton, #recognize {
font-size: 15px;
-webkit-appearance: none;
background: #eee;
border: 1px solid #888;
}
/* Credit for the button : https://getcssscan.com/css-buttons-examples by Michael Millan */
.button-54 {
text-decoration: none;
text-transform: uppercase;
color: #000;
cursor: pointer;
border: 3px solid;
padding: 0.25em 0.5em;
box-shadow: 1px 1px 0px 0px, 2px 2px 0px 0px, 3px 3px 0px 0px, 4px 4px 0px 0px, 5px 5px 0px 0px;
position: relative;
user-select: none;
-webkit-user-select: none;
touch-action: manipulation;
}
.button-54:active {
box-shadow: 0px 0px 0px 0px;
top: 5px;
left: 5px;
}
@media (min-width: 768px) {
.button-54 {
padding: 0.25em 0.75em;
}
}
/* CSS credits : https://codepen.io/Founts/pen/AJyVOr */
.talk-bubble {
margin: 40px;
display: inline-block;
position: relative;
width: 200px;
height: auto;
background-color:#e4caff;
}
.border{
border: 8px solid #666;
}
.round{
border-radius: 30px;
-webkit-border-radius: 30px;
-moz-border-radius: 30px;
}
.tri-right.left-top:after{
content: ' ';
position: absolute;
width: 0;
height: 0;
left: -20px;
right: auto;
top: 0px;
bottom: auto;
border: 22px solid;
border-color: lightyellow transparent transparent transparent;
}
/* talk bubble contents */
.talktext{
padding: 1em;
text-align: left;
line-height: 1.5em;
}
</style>
</head>
<body onload="init()">
<header>
<h1>Simple Doodle Recognizer using Tesseract.js</h1>
</header>
<div id="thedoodlepad">
<div class="leftside">
<p>Doodle an alphabet( or word) by tapping or dragging.</p>
<p>Touch and mouse supported!</p>
<p>Should work on most devices!(Firefox,chrome,brave,IOS and android)</p>
<p>Hit the initialize recognition after you're done doodling!</p>
<button class="button-54" role="button"id="clearbutton" onclick="clearCanvas(canvas,ctx);">Clear Doodle</button>
<button class="button-54" role="button"id="recognize">Initialize Recognition</button>
</div>
<div class="rightside">
<canvas id="doodlepad" height="300" width="400">
</canvas>
</div>
</div>
<div class="container">
<div class="upper">
<div class="talk-bubble round border left-top">
<div class="talktext">
<h4 placeholder="output will come here"></h4>
</div>
</div>
</div>
</div>
<script src="https://unpkg.com/tesseract.js@v2.0.0-alpha.13/dist/tesseract.min.js"></script>
</body>
`)
//credits: https://stackoverflow.com/questions/39050460/drawing-on-canvas-using-touchscreen-devices
/*~~~~~~~~~~~~~~~~~~~~~ Doodlepad code starts here~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
var canvas, ctx;
// Variables to keep track of the mouse position and left-button status
var mouseX, mouseY, mouseDown = 0;
// Variables to keep track of the touch position
var touchX, touchY;
var doodlePenSize = 10; // Change this to change the size of the doodle pen
// Draws a dot at a specific position on the supplied canvas name
// Parameters are: A canvas context, the x position, the y position, the size of the dot
function drawDot(ctx, x, y, size) {
// Settings values for black dot and alpha value 255 for opaque
//Credit: https://rgbacolorpicker.com/
r = 0;
g = 0;
b = 0;
a = 255;
// Select a fill style
ctx.fillStyle = "rgba(" + r + "," + g + "," + b + "," + (a / 255) + ")";
// Draw a filled circle
ctx.beginPath();
ctx.arc(x, y, size, 0, Math.PI * 2, true);
ctx.closePath();
ctx.fill();
}
// Clear the canvas context using the canvas width and height
function clearCanvas(canvas, ctx) {
ctx.clearRect(0, 0, canvas.width, canvas.height);
}
// Keep track of the mouse button being pressed and draw a dot at current location
function doodlepad_mouseDown() {
mouseDown = 1;
drawDot(ctx, mouseX, mouseY, doodlePenSize);
}
// Keep track of the mouse button being released
function doodlepad_mouseUp() {
mouseDown = 0;
}
// Keep track of the mouse position and draw a dot if mouse button is currently pressed
function doodlepad_mouseMove(e) {
// Update the mouse co-ordinates when moved
getMousePos(e);
// Draw a dot if the mouse button is currently being pressed
if (mouseDown == 1) {
drawDot(ctx, mouseX, mouseY, doodlePenSize);
}
}
// Get the current mouse position relative to the top-left of the canvas
function getMousePos(e) {
if (!e)
var e = event;
if (e.offsetX) {
mouseX = e.offsetX;
mouseY = e.offsetY;
} else if (e.layerX) {
mouseX = e.layerX;
mouseY = e.layerY;
}
}
// Draw something when a touch start is detected
function doodlepad_touchStart() {
// Update the touch co-ordinates
getTouchPos();
drawDot(ctx, touchX, touchY, 12);
// Prevents an additional mousedown event being triggered
event.preventDefault();
}
// Draw something and prevent the default scrolling when touch movement is detected
function doodlepad_touchMove(e) {
// Update the touch co-ordinates
getTouchPos(e);
// During a touchmove event, unlike a mousemove event, we don't need to check if the touch is engaged, since there will always be contact with the screen by definition.
drawDot(ctx, touchX, touchY, 12);
// Prevent a scrolling action as a result of this touchmove triggering.
event.preventDefault();
}
// Get the touch position relative to the top-left of the canvas
// When we get the raw values of pageX and pageY below, they take into account the scrolling on the page
// but not the position relative to our target div. We'll adjust them using "target.offsetLeft" and
// "target.offsetTop" to get the correct values in relation to the top left of the canvas.
function getTouchPos(e) {
if (!e)
var e = event;
if (e.touches) {
if (e.touches.length == 1) { // Only deal with one finger
var touch = e.touches[0]; // Get the information for finger #1
touchX = touch.pageX - touch.target.offsetLeft;
touchY = touch.pageY - touch.target.offsetTop;
}
}
}
// Set-up the canvas and add our event handlers after the page has loaded
function init() {
// Get the specific canvas element from the HTML document
canvas = document.getElementById('doodlepad');
// If the browser supports the canvas tag, get the 2d drawing context for this canvas
if (canvas.getContext)
ctx = canvas.getContext('2d');
// Check that we have a valid context to draw on/with before adding event handlers
if (ctx) {
// React to mouse events on the canvas, and mouseup on the entire document
canvas.addEventListener('mousedown', doodlepad_mouseDown, false);
canvas.addEventListener('mousemove', doodlepad_mouseMove, false);
window.addEventListener('mouseup', doodlepad_mouseUp, false);
// React to touch events on the canvas
canvas.addEventListener('touchstart', doodlepad_touchStart, false);
canvas.addEventListener('touchmove', doodlepad_touchMove, false);
}
}
/*~~~~~~~~~~~~~~~~~~~~~ Doodlepad code ends here~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
/*~~~~~~~~~~~~~~~~~~~~~ The below code is for tesseract implementation~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
//JavaScript Promises In 10 Minutes:
//https://www.youtube.com/watch?v=DHvZLI7Db8E
// get the recognize button
const recognize = document.getElementById('recognize');
//get the h4 element where we will display final output
const resultHeader = document.querySelector('h4');
// Start text recognition on click of the recognize button
recognize.onclick = () => {
//Select the canvas using its ID
var canvasimage = document.querySelector('#doodlepad');
//convert canvas element to DataURL
//documentation : https://github.com/naptha/tesseract.js/blob/master/docs/image-format.md
//Tesseract.js's recognize() method accepts image as a parameter.
//The accepted formats include image,file,blob,string with base64 encoded image(which is basically the dataURL) and Canvas
//I misread the documentation at first so the below line is not needed, we can directly pass canvasimage! but still leaving it here
// As it is a good example of different formats we can pass through Recognize
var dataURI = canvasimage.toDataURL();
resultHeader.innerHTML = '';
//https://github.com/naptha/tesseract.js/blob/master/docs/api.md#worker-recognize documentation
// View the old version of the documentation by clicking the history button and viewing the 2019 version.
const rec = new Tesseract.TesseractWorker();
rec.recognize(dataURI) //rec.recognize(canvasimage) also works...
.then(function(data) {
console.log(data);
data.text === '' ? resultHeader.innerHTML = "Recognition failed. Hmmm it couldn't handle the awesomeness of your doodle! ( but on a serious note check logs)" : resultHeader.innerHTML = "The doodle has been recognized as: " + data.text;
});
}