Initial commit
This commit is contained in:
+59
@@ -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
|
||||||
@@ -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)
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -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"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -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>
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 108 KiB |
@@ -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.
|
||||||
@@ -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,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user