Browse Source

Initial commit

main
Harish Karumuthil 4 years ago
commit
19743356f1
  1. 59
      .gitignore
  2. 24
      app.js
  3. 30
      package.json
  4. 90
      public/app.js
  5. 114
      public/index.html
  6. BIN
      public/sample.png
  7. 27
      routes/README.md
  8. 30
      routes/root.js
  9. 1
      uploads
  10. 3252
      yarn.lock

59
.gitignore

@ -0,0 +1,59 @@
# Logs
logs
*.log
npm-debug.log*
# Runtime data
pids
*.pid
*.seed
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
# nyc test coverage
.nyc_output
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# node-waf configuration
.lock-wscript
# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules
jspm_packages
# Optional npm cache directory
.npm
# Optional REPL history
.node_repl_history
# 0x
profile-*
# mac files
.DS_Store
# vim swap files
*.swp
# webstorm
.idea
# vscode
.vscode
*code-workspace
# clinic
profile*
*clinic*
*flamegraph*
.bash_history

24
app.js

@ -0,0 +1,24 @@
'use strict'
const path = require('path')
const AutoLoad = require('fastify-autoload')
module.exports = async function (fastify, opts) {
fastify.register(require('fastify-static'), {
root: path.join(__dirname, 'public'),
prefix: '/', // optional: default '/'
})
// Place here your custom code!
// Do not touch the following lines
// This loads all plugins defined in routes
// define your routes in one of these
fastify.register(AutoLoad, {
dir: path.join(__dirname, 'routes'),
options: Object.assign({}, opts)
})
}

30
package.json

@ -0,0 +1,30 @@
{
"name": "ocrapp",
"version": "1.0.0",
"description": "",
"main": "app.js",
"directories": {
"test": "test"
},
"scripts": {
"test": "tap \"test/**/*.test.js\"",
"start": "fastify start -l info app.js",
"dev": "fastify start -w -l info -P app.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"fastify": "^3.0.0",
"fastify-autoload": "^3.3.1",
"fastify-cli": "^2.13.0",
"fastify-multipart": "^5.0.0",
"fastify-plugin": "^3.0.0",
"fastify-sensible": "^3.1.0",
"fastify-static": "^4.2.3",
"mime-types": "^2.1.32"
},
"devDependencies": {
"tap": "^15.0.9"
}
}

90
public/app.js

@ -0,0 +1,90 @@
/*
* ഓം ബ്രഹ്മാർപ്പണം
* app.js
* Created: Mon Mar 09 2020 02:16:15 GMT+0530 (GMT+05:30)
* Copyright 2020 Harish.K<harish2704@gmail.com>
*/
function ocrByServer(image) {
var data = new FormData();
data.append("image", image);
return fetch(
"/ocr",
{
method: "POST",
body: data,
}
).then((res) => res.json());
}
new Vue({
el: "#main",
components: {
},
data: {
scalingFactor: 1,
selectedFileName: "",
currentFileBlob: null,
isLoading: false,
ocrOutput: "",
},
methods: {
doOcr: function () {
this.isLoading = true;
ocrByServer(this.currentFileBlob)
.then((data) => {
console.log("success", data);
this.ocrOutput = data.text;
this.isLoading = false;
})
.catch((error) => {
console.log("error", error);
alert("Some error occurred while Calling OCR API");
this.isLoading = false;
});
},
setImage: function (file) {
var self = this;
var canvas = this.$refs.canvas;
var ctx = canvas.getContext("2d");
var img = new Image();
this.currentFileBlob = file;
img.onload = function () {
canvas.width = img.width;
canvas.height = img.height;
ctx.drawImage(img, 0, 0);
self.scalingFactor = canvas.clientWidth / canvas.width;
};
img.src = URL.createObjectURL(file);
},
onChangeFile: function File(e) {
this.setImage(e.target.files[0]);
this.selectedFileName = e.target.files[0].name;
},
},
mounted: function () {
var self = this;
fetch("./sample.png")
.then((v) => v.blob())
.then((blob) => this.setImage(blob));
document.onpaste = function (event) {
var items = (event.clipboardData || event.originalEvent.clipboardData)
.items;
for (var index in items) {
var item = items[index];
if (item.kind === "file") {
var blob = item.getAsFile();
self.setImage(blob);
self.ocrOutput = "";
}
}
};
window.addEventListener("resize", function () {
var canvas = self.$refs.canvas;
self.scalingFactor = canvas.clientWidth / canvas.width;
});
},
});

114
public/index.html

@ -0,0 +1,114 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Tesseract OCR Malayalam demo</title>
<link
rel="stylesheet"
href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css"
integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh"
crossorigin="anonymous"
/>
<style type="text/css" media="all">
.btn .spinner-border,
.btn .txt-loading,
.btn[disabled] .txt-button {
display: none;
}
.btn[disabled] .spinner-border,
.btn[disabled] .txt-loading,
.btn .txt-button {
display: inline-block;
}
</style>
</head>
<body>
<div class="container-fluid" id="main">
<div class="row">
<div class="col-md-12">
<h2>Tesseract OCR Malayalam</h2>
<h4 class="text-danger">Please note</h4>
<ol>
<li>It can detect both Malayalam & English script</li>
<li>Pasting image from clip board is supported</li>
</ol>
</div>
<div class="col-md-12">
<div class="col-md-6 col-sm-12">
<div class="form-group">
<input
type="file"
accept="image/*"
style="visibility: hidden; height: 0"
@change="onChangeFile($event)"
ref="file_input"
/>
<div class="input-group input-file">
<input
type="text"
readonly
v-model="selectedFileName"
class="form-control"
placeholder="Choose a file..."
@click="$refs.file_input.click()"
/>
<div class="input-group-append">
<button
class="btn btn-primary btn-choose"
type="button"
@click="$refs.file_input.click()"
>
Choose another image
</button>
<button
class="btn btn-success pull-right"
@click="doOcr()"
:disabled="isLoading"
>
<span
class="spinner-border spinner-border-sm"
role="status"
aria-hidden="true"
></span>
<span class="txt-loading">Loading...</span>
<span class="txt-button">Run OCR</span>
</button>
</div>
</div>
</div>
</div>
</div>
<div class="row w-100">
<div class="col-md-6 col-sm-12">
<div>
<canvas
ref="canvas"
class="w-100"
alt="Selected image"
@resize="onCanvasResize($event)"
></canvas>
</div>
</div>
<div class="col-md-6 col-sm-12">
<div class="card">
<div class="card-body">
<h5 class="card-title text-primary">OCR Output</h5>
<div id="output">
<textarea
class="form-control"
rows="15"
v-model="ocrOutput"
></textarea>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.min.js"></script>
<script src="./app.js" type="text/javascript" charset="utf-8"></script>
</body>
</html>

BIN
public/sample.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

27
routes/README.md

@ -0,0 +1,27 @@
# Routes Folder
Routes define routes within your application. Fastify provides an
easy path to a microservice architecture, in the future you might want
to independently deploy some of those.
In this folder you should define all the routes that define the endpoints
of your web application.
Each service is a [Fastify
plugin](https://www.fastify.io/docs/latest/Plugins/), it is
encapsulated (it can have its own independent plugins) and it is
typically stored in a file; be careful to group your routes logically,
e.g. all `/users` routes in a `users.js` file. We have added
a `root.js` file for you with a '/' root added.
If a single file become too large, create a folder and add a `index.js` file there:
this file must be a Fastify plugin, and it will be loaded automatically
by the application. You can now add as many files as you want inside that folder.
In this way you can create complex routes within a single monolith,
and eventually extract them.
If you need to share functionality between routes, place that
functionality into the `plugins` folder, and share it via
[decorators](https://www.fastify.io/docs/latest/Decorators/).
If you're a bit confused about using `async/await` to write routes, you would
better take a look at [Promise resolution](https://www.fastify.io/docs/latest/Routes/#promise-resolution) for more details.

30
routes/root.js

@ -0,0 +1,30 @@
"use strict";
const fs = require("fs");
const util = require("util");
const path = require("path");
const { pipeline } = require("stream");
const pump = util.promisify(pipeline);
const crypto = require("crypto");
const mime = require("mime-types");
const exec = util.promisify(require("child_process").execFile);
const UPLOAD_PATH = "./uploads";
module.exports = async function (fastify, opts) {
fastify.register(require("fastify-multipart"));
fastify.post("/ocr", async function (req, reply) {
const data = await req.file();
const uid = crypto.randomBytes(16).toString("hex");
const filename = `${UPLOAD_PATH}/${uid}.${mime.extension(data.mimetype)}`;
const lang = "mal+eng";
await pump(data.file, fs.createWriteStream(filename));
const args = [filename, "stdout", "-l", lang];
const { stdout, stderr } = await exec("tesseract", args);
exec("rm", ["-f", filename]);
return {
text: stdout,
error: stderr,
};
});
};

1
uploads

@ -0,0 +1 @@
../uploads

3252
yarn.lock

File diff suppressed because it is too large
Loading…
Cancel
Save