Jerome Wu
6 years ago
4 changed files with 319 additions and 298 deletions
@ -1,24 +1,30 @@ |
|||||||
|
/* eslint-disable no-bitwise */ |
||||||
|
/* eslint-disable max-len */ |
||||||
|
|
||||||
// This converts an image to grayscale
|
// This converts an image to grayscale
|
||||||
|
module.exports = (image) => { |
||||||
|
if (image.data) { |
||||||
|
const src = image.data; |
||||||
|
const { width, height } = image; |
||||||
|
const dst = new Uint8Array(width * height); |
||||||
|
const srcLength = src.length | 0; |
||||||
|
const srcLength16 = (srcLength - 16) | 0; |
||||||
|
let i = 0; |
||||||
|
let j = 0; |
||||||
|
|
||||||
module.exports = function desaturate(image){ |
for (; i <= srcLength16; i += 16, j += 4) { |
||||||
var width, height; |
// convert to grayscale 4 pixels at a time; eveything with alpha gets put in front of 50% gray
|
||||||
if(image.data){ |
dst[j] = (((src[i] * 77 + src[i + 1] * 151 + src[i + 2] * 28) * src[i + 3]) + ((255 - src[i + 3]) << 15) + 32768) >> 16; |
||||||
var src = image.data; |
dst[j + 1] = (((src[i + 4] * 77 + src[i + 5] * 151 + src[i + 6] * 28) * src[i + 7]) + ((255 - src[i + 7]) << 15) + 32768) >> 16; |
||||||
width = image.width, |
dst[j + 2] = (((src[i + 8] * 77 + src[i + 9] * 151 + src[i + 10] * 28) * src[i + 11]) + ((255 - src[i + 11]) << 15) + 32768) >> 16; |
||||||
height = image.height; |
dst[j + 3] = (((src[i + 12] * 77 + src[i + 13] * 151 + src[i + 14] * 28) * src[i + 15]) + ((255 - src[i + 15]) << 15) + 32768) >> 16; |
||||||
var dst = new Uint8Array(width * height); |
} |
||||||
var srcLength = src.length | 0, srcLength_16 = (srcLength - 16) | 0; |
// finish up
|
||||||
|
for (; i < srcLength; i += 4, j += 1) { |
||||||
for (var i = 0, j = 0; i <= srcLength_16; i += 16, j += 4) { |
dst[j] = (((src[i] * 77 + src[i + 1] * 151 + src[i + 2] * 28) * src[i + 3]) + ((255 - src[i + 3]) << 15) + 32768) >> 16; |
||||||
// convert to grayscale 4 pixels at a time; eveything with alpha gets put in front of 50% gray
|
} |
||||||
dst[j] = (((src[i] * 77 + src[i+1] * 151 + src[i+2] * 28) * src[i+3]) + ((255-src[i+3]) << 15) + 32768) >> 16 |
return dst; |
||||||
dst[j+1] = (((src[i+4] * 77 + src[i+5] * 151 + src[i+6] * 28) * src[i+7]) + ((255-src[i+7]) << 15) + 32768) >> 16 |
} |
||||||
dst[j+2] = (((src[i+8] * 77 + src[i+9] * 151 + src[i+10] * 28) * src[i+11]) + ((255-src[i+11]) << 15) + 32768) >> 16 |
return null; |
||||||
dst[j+3] = (((src[i+12] * 77 + src[i+13] * 151 + src[i+14] * 28) * src[i+15]) + ((255-src[i+15]) << 15) + 32768) >> 16 |
// throw { err: 'Invalid ImageData' };
|
||||||
} |
}; |
||||||
for (; i < srcLength; i += 4, ++j) //finish up
|
|
||||||
dst[j] = (((src[i] * 77 + src[i+1] * 151 + src[i+2] * 28) * src[i+3]) + ((255-src[i+3]) << 15) + 32768) >> 16 |
|
||||||
image = dst; |
|
||||||
} else { throw 'Invalid ImageData' } |
|
||||||
return image |
|
||||||
} |
|
||||||
|
@ -1,164 +1,158 @@ |
|||||||
module.exports = function DumpLiterallyEverything(Module, base){ |
// the generated HOCR is excessively indented, so
|
||||||
var ri = base.GetIterator(); |
// we get rid of that indentation
|
||||||
var blocks = []; |
|
||||||
var block, para, textline, word, symbol; |
|
||||||
|
|
||||||
function enumToString(value, prefix){ |
const deindent = (html) => { |
||||||
return (Object.keys(Module) |
const lines = html.split('\n'); |
||||||
.filter(function(e){ return e.substr(0, prefix.length + 1) == prefix + '_' }) |
if (lines[0].substring(0, 2) === ' ') { |
||||||
.filter(function(e){ return Module[e] === value }) |
for (let i = 0; i < lines.length; i += 1) { |
||||||
.map(function(e){ return e.slice(prefix.length + 1) })[0]) |
if (lines[i].substring(0, 2) === ' ') { |
||||||
|
lines[i] = lines[i].slice(2); |
||||||
|
} |
||||||
} |
} |
||||||
|
} |
||||||
ri.Begin() |
return lines.join('\n'); |
||||||
do { |
}; |
||||||
if(ri.IsAtBeginningOf(Module.RIL_BLOCK)){ |
|
||||||
var poly = ri.BlockPolygon(); |
module.exports = (Module, base) => { |
||||||
var polygon = null; |
const ri = base.GetIterator(); |
||||||
// BlockPolygon() returns null when automatic page segmentation is off
|
const blocks = []; |
||||||
if(Module.getPointer(poly) > 0){ |
let block; |
||||||
var n = poly.get_n(), |
let para; |
||||||
px = poly.get_x(), |
let textline; |
||||||
py = poly.get_y(), |
let word; |
||||||
polygon = []; |
let symbol; |
||||||
for(var i = 0; i < n; i++){ |
|
||||||
polygon.push([px.getValue(i), py.getValue(i)]); |
const enumToString = (value, prefix) => ( |
||||||
} |
Object.keys(Module) |
||||||
Module._ptaDestroy(Module.getPointer(poly)); |
.filter(e => (e.substr(0, prefix.length + 1) === `${prefix}_`)) |
||||||
} |
.filter(e => Module[e] === value) |
||||||
|
.map(e => e.slice(prefix.length + 1))[0] |
||||||
block = { |
); |
||||||
paragraphs: [], |
|
||||||
|
ri.Begin(); |
||||||
text: ri.GetUTF8Text(Module.RIL_BLOCK), |
do { |
||||||
confidence: ri.Confidence(Module.RIL_BLOCK), |
if (ri.IsAtBeginningOf(Module.RIL_BLOCK)) { |
||||||
baseline: ri.getBaseline(Module.RIL_BLOCK), |
const poly = ri.BlockPolygon(); |
||||||
bbox: ri.getBoundingBox(Module.RIL_BLOCK), |
let polygon = null; |
||||||
|
// BlockPolygon() returns null when automatic page segmentation is off
|
||||||
blocktype: enumToString(ri.BlockType(), 'PT'), |
if (Module.getPointer(poly) > 0) { |
||||||
polygon: polygon |
const n = poly.get_n(); |
||||||
} |
const px = poly.get_x(); |
||||||
blocks.push(block) |
const py = poly.get_y(); |
||||||
} |
polygon = []; |
||||||
if(ri.IsAtBeginningOf(Module.RIL_PARA)){ |
for (let i = 0; i < n; i += 1) { |
||||||
para = { |
polygon.push([px.getValue(i), py.getValue(i)]); |
||||||
lines: [], |
|
||||||
|
|
||||||
text: ri.GetUTF8Text(Module.RIL_PARA), |
|
||||||
confidence: ri.Confidence(Module.RIL_PARA), |
|
||||||
baseline: ri.getBaseline(Module.RIL_PARA), |
|
||||||
bbox: ri.getBoundingBox(Module.RIL_PARA), |
|
||||||
|
|
||||||
is_ltr: !!ri.ParagraphIsLtr() |
|
||||||
} |
|
||||||
block.paragraphs.push(para) |
|
||||||
} |
|
||||||
if(ri.IsAtBeginningOf(Module.RIL_TEXTLINE)){ |
|
||||||
textline = { |
|
||||||
words: [], |
|
||||||
|
|
||||||
text: ri.GetUTF8Text(Module.RIL_TEXTLINE), |
|
||||||
confidence: ri.Confidence(Module.RIL_TEXTLINE), |
|
||||||
baseline: ri.getBaseline(Module.RIL_TEXTLINE), |
|
||||||
bbox: ri.getBoundingBox(Module.RIL_TEXTLINE) |
|
||||||
} |
|
||||||
para.lines.push(textline) |
|
||||||
} |
|
||||||
if(ri.IsAtBeginningOf(Module.RIL_WORD)){ |
|
||||||
var fontInfo = ri.getWordFontAttributes(), |
|
||||||
wordDir = ri.WordDirection(); |
|
||||||
word = { |
|
||||||
symbols: [], |
|
||||||
choices: [], |
|
||||||
|
|
||||||
text: ri.GetUTF8Text(Module.RIL_WORD), |
|
||||||
confidence: ri.Confidence(Module.RIL_WORD), |
|
||||||
baseline: ri.getBaseline(Module.RIL_WORD), |
|
||||||
bbox: ri.getBoundingBox(Module.RIL_WORD), |
|
||||||
|
|
||||||
is_numeric: !!ri.WordIsNumeric(), |
|
||||||
in_dictionary: !!ri.WordIsFromDictionary(), |
|
||||||
direction: enumToString(wordDir, 'DIR'), |
|
||||||
language: ri.WordRecognitionLanguage(), |
|
||||||
|
|
||||||
is_bold: fontInfo.is_bold, |
|
||||||
is_italic: fontInfo.is_italic, |
|
||||||
is_underlined: fontInfo.is_underlined, |
|
||||||
is_monospace: fontInfo.is_monospace, |
|
||||||
is_serif: fontInfo.is_serif, |
|
||||||
is_smallcaps: fontInfo.is_smallcaps, |
|
||||||
font_size: fontInfo.pointsize, |
|
||||||
font_id: fontInfo.font_id, |
|
||||||
font_name: fontInfo.font_name, |
|
||||||
} |
|
||||||
var wc = new Module.WordChoiceIterator(ri); |
|
||||||
do { |
|
||||||
word.choices.push({ |
|
||||||
text: wc.GetUTF8Text(), |
|
||||||
confidence: wc.Confidence() |
|
||||||
}) |
|
||||||
} while (wc.Next()); |
|
||||||
Module.destroy(wc) |
|
||||||
textline.words.push(word) |
|
||||||
} |
} |
||||||
|
Module._ptaDestroy(Module.getPointer(poly)); |
||||||
var image = null; |
} |
||||||
// var pix = ri.GetBinaryImage(Module.RIL_SYMBOL)
|
|
||||||
// var image = pix2array(pix);
|
block = { |
||||||
// // for some reason it seems that things stop working if you destroy pics
|
paragraphs: [], |
||||||
// Module._pixDestroy(Module.getPointer(pix));
|
text: ri.GetUTF8Text(Module.RIL_BLOCK), |
||||||
if(ri.IsAtBeginningOf(Module.RIL_SYMBOL)){ |
confidence: ri.Confidence(Module.RIL_BLOCK), |
||||||
symbol = { |
baseline: ri.getBaseline(Module.RIL_BLOCK), |
||||||
choices: [], |
bbox: ri.getBoundingBox(Module.RIL_BLOCK), |
||||||
image: image, |
blocktype: enumToString(ri.BlockType(), 'PT'), |
||||||
|
polygon, |
||||||
text: ri.GetUTF8Text(Module.RIL_SYMBOL), |
}; |
||||||
confidence: ri.Confidence(Module.RIL_SYMBOL), |
blocks.push(block); |
||||||
baseline: ri.getBaseline(Module.RIL_SYMBOL), |
} |
||||||
bbox: ri.getBoundingBox(Module.RIL_SYMBOL), |
if (ri.IsAtBeginningOf(Module.RIL_PARA)) { |
||||||
|
para = { |
||||||
is_superscript: !!ri.SymbolIsSuperscript(), |
lines: [], |
||||||
is_subscript: !!ri.SymbolIsSubscript(), |
text: ri.GetUTF8Text(Module.RIL_PARA), |
||||||
is_dropcap: !!ri.SymbolIsDropcap(), |
confidence: ri.Confidence(Module.RIL_PARA), |
||||||
} |
baseline: ri.getBaseline(Module.RIL_PARA), |
||||||
word.symbols.push(symbol) |
bbox: ri.getBoundingBox(Module.RIL_PARA), |
||||||
var ci = new Module.ChoiceIterator(ri); |
is_ltr: !!ri.ParagraphIsLtr(), |
||||||
do { |
}; |
||||||
symbol.choices.push({ |
block.paragraphs.push(para); |
||||||
text: ci.GetUTF8Text(), |
} |
||||||
confidence: ci.Confidence() |
if (ri.IsAtBeginningOf(Module.RIL_TEXTLINE)) { |
||||||
}) |
textline = { |
||||||
} while (ci.Next()); |
words: [], |
||||||
Module.destroy(ci) |
text: ri.GetUTF8Text(Module.RIL_TEXTLINE), |
||||||
} |
confidence: ri.Confidence(Module.RIL_TEXTLINE), |
||||||
} while (ri.Next(Module.RIL_SYMBOL)); |
baseline: ri.getBaseline(Module.RIL_TEXTLINE), |
||||||
Module.destroy(ri) |
bbox: ri.getBoundingBox(Module.RIL_TEXTLINE), |
||||||
|
}; |
||||||
return { |
para.lines.push(textline); |
||||||
text: base.GetUTF8Text(), |
} |
||||||
html: deindent(base.GetHOCRText()), |
if (ri.IsAtBeginningOf(Module.RIL_WORD)) { |
||||||
|
const fontInfo = ri.getWordFontAttributes(); |
||||||
confidence: base.MeanTextConf(), |
const wordDir = ri.WordDirection(); |
||||||
|
word = { |
||||||
blocks: blocks, |
symbols: [], |
||||||
|
choices: [], |
||||||
psm: enumToString(base.GetPageSegMode(), 'PSM'), |
|
||||||
oem: enumToString(base.oem(), 'OEM'), |
text: ri.GetUTF8Text(Module.RIL_WORD), |
||||||
version: base.Version(), |
confidence: ri.Confidence(Module.RIL_WORD), |
||||||
|
baseline: ri.getBaseline(Module.RIL_WORD), |
||||||
|
bbox: ri.getBoundingBox(Module.RIL_WORD), |
||||||
|
|
||||||
|
is_numeric: !!ri.WordIsNumeric(), |
||||||
|
in_dictionary: !!ri.WordIsFromDictionary(), |
||||||
|
direction: enumToString(wordDir, 'DIR'), |
||||||
|
language: ri.WordRecognitionLanguage(), |
||||||
|
|
||||||
|
is_bold: fontInfo.is_bold, |
||||||
|
is_italic: fontInfo.is_italic, |
||||||
|
is_underlined: fontInfo.is_underlined, |
||||||
|
is_monospace: fontInfo.is_monospace, |
||||||
|
is_serif: fontInfo.is_serif, |
||||||
|
is_smallcaps: fontInfo.is_smallcaps, |
||||||
|
font_size: fontInfo.pointsize, |
||||||
|
font_id: fontInfo.font_id, |
||||||
|
font_name: fontInfo.font_name, |
||||||
|
}; |
||||||
|
const wc = new Module.WordChoiceIterator(ri); |
||||||
|
do { |
||||||
|
word.choices.push({ |
||||||
|
text: wc.GetUTF8Text(), |
||||||
|
confidence: wc.Confidence(), |
||||||
|
}); |
||||||
|
} while (wc.Next()); |
||||||
|
Module.destroy(wc); |
||||||
|
textline.words.push(word); |
||||||
} |
} |
||||||
} |
|
||||||
|
|
||||||
// the generated HOCR is excessively indented, so
|
|
||||||
// we get rid of that indentation
|
|
||||||
|
|
||||||
function deindent(html){ |
// let image = null;
|
||||||
var lines = html.split('\n') |
// var pix = ri.GetBinaryImage(Module.RIL_SYMBOL)
|
||||||
if(lines[0].substring(0, 2) === " "){ |
// var image = pix2array(pix);
|
||||||
for (var i = 0; i < lines.length; i++) { |
// // for some reason it seems that things stop working if you destroy pics
|
||||||
if (lines[i].substring(0,2) === " ") { |
// Module._pixDestroy(Module.getPointer(pix));
|
||||||
lines[i] = lines[i].slice(2) |
if (ri.IsAtBeginningOf(Module.RIL_SYMBOL)) { |
||||||
} |
symbol = { |
||||||
}; |
choices: [], |
||||||
|
image: null, |
||||||
|
text: ri.GetUTF8Text(Module.RIL_SYMBOL), |
||||||
|
confidence: ri.Confidence(Module.RIL_SYMBOL), |
||||||
|
baseline: ri.getBaseline(Module.RIL_SYMBOL), |
||||||
|
bbox: ri.getBoundingBox(Module.RIL_SYMBOL), |
||||||
|
is_superscript: !!ri.SymbolIsSuperscript(), |
||||||
|
is_subscript: !!ri.SymbolIsSubscript(), |
||||||
|
is_dropcap: !!ri.SymbolIsDropcap(), |
||||||
|
}; |
||||||
|
word.symbols.push(symbol); |
||||||
|
const ci = new Module.ChoiceIterator(ri); |
||||||
|
do { |
||||||
|
symbol.choices.push({ |
||||||
|
text: ci.GetUTF8Text(), |
||||||
|
confidence: ci.Confidence(), |
||||||
|
}); |
||||||
|
} while (ci.Next()); |
||||||
|
// Module.destroy(i);
|
||||||
} |
} |
||||||
return lines.join('\n') |
} while (ri.Next(Module.RIL_SYMBOL)); |
||||||
} |
Module.destroy(ri); |
||||||
|
|
||||||
|
return { |
||||||
|
text: base.GetUTF8Text(), |
||||||
|
html: deindent(base.GetHOCRText()), |
||||||
|
confidence: base.MeanTextConf(), |
||||||
|
blocks, |
||||||
|
psm: enumToString(base.GetPageSegMode(), 'PSM'), |
||||||
|
oem: enumToString(base.oem(), 'OEM'), |
||||||
|
version: base.Version(), |
||||||
|
}; |
||||||
|
}; |
||||||
|
@ -1,81 +1,86 @@ |
|||||||
const adapter = require('../node/index.js') |
const adapter = require('../node/'); |
||||||
|
|
||||||
let jobCounter = 0; |
let jobCounter = 0; |
||||||
|
|
||||||
module.exports = class TesseractJob { |
module.exports = class TesseractJob { |
||||||
constructor(instance){ |
constructor(instance) { |
||||||
this.id = 'Job-' + (++jobCounter) + '-' + Math.random().toString(16).slice(3, 8) |
jobCounter += 1; |
||||||
|
this.id = `Job-${jobCounter}-${Math.random().toString(16).slice(3, 8)}`; |
||||||
|
|
||||||
this._instance = instance; |
this._instance = instance; |
||||||
this._resolve = [] |
this._resolve = []; |
||||||
this._reject = [] |
this._reject = []; |
||||||
this._progress = [] |
this._progress = []; |
||||||
this._finally = [] |
this._finally = []; |
||||||
|
} |
||||||
|
|
||||||
|
then(resolve, reject) { |
||||||
|
if (this._resolve.push) { |
||||||
|
this._resolve.push(resolve); |
||||||
|
} else { |
||||||
|
resolve(this._resolve); |
||||||
} |
} |
||||||
|
|
||||||
then(resolve, reject){ |
if (reject) this.catch(reject); |
||||||
if(this._resolve.push){ |
return this; |
||||||
this._resolve.push(resolve) |
} |
||||||
}else{ |
|
||||||
resolve(this._resolve) |
|
||||||
} |
|
||||||
|
|
||||||
if(reject) this.catch(reject); |
catch(reject) { |
||||||
return this; |
if (this._reject.push) { |
||||||
} |
this._reject.push(reject); |
||||||
catch(reject){ |
} else { |
||||||
if(this._reject.push){ |
reject(this._reject); |
||||||
this._reject.push(reject) |
|
||||||
}else{ |
|
||||||
reject(this._reject) |
|
||||||
} |
|
||||||
return this; |
|
||||||
} |
|
||||||
progress(fn){ |
|
||||||
this._progress.push(fn) |
|
||||||
return this; |
|
||||||
} |
|
||||||
finally(fn) { |
|
||||||
this._finally.push(fn) |
|
||||||
return this; |
|
||||||
} |
|
||||||
_send(action, payload){ |
|
||||||
adapter.sendPacket(this._instance, { |
|
||||||
jobId: this.id, |
|
||||||
action: action, |
|
||||||
payload: payload |
|
||||||
}) |
|
||||||
} |
} |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
_handle(packet){ |
progress(fn) { |
||||||
var data = packet.data; |
this._progress.push(fn); |
||||||
let runFinallyCbs = false; |
return this; |
||||||
|
} |
||||||
|
|
||||||
if(packet.status === 'resolve'){ |
finally(fn) { |
||||||
if(this._resolve.length === 0) console.log(data); |
this._finally.push(fn); |
||||||
this._resolve.forEach(fn => { |
return this; |
||||||
var ret = fn(data); |
} |
||||||
if(ret && typeof ret.then == 'function'){ |
|
||||||
console.warn('TesseractJob instances do not chain like ES6 Promises. To convert it into a real promise, use Promise.resolve.') |
_send(action, payload) { |
||||||
} |
adapter.sendPacket(this._instance, { |
||||||
}) |
jobId: this.id, |
||||||
this._resolve = data; |
action, |
||||||
this._instance._dequeue() |
payload, |
||||||
runFinallyCbs = true; |
}); |
||||||
}else if(packet.status === 'reject'){ |
} |
||||||
if(this._reject.length === 0) console.error(data); |
|
||||||
this._reject.forEach(fn => fn(data)) |
|
||||||
this._reject = data; |
|
||||||
this._instance._dequeue() |
|
||||||
runFinallyCbs = true; |
|
||||||
}else if(packet.status === 'progress'){ |
|
||||||
this._progress.forEach(fn => fn(data)) |
|
||||||
}else{ |
|
||||||
console.warn('Message type unknown', packet.status) |
|
||||||
} |
|
||||||
|
|
||||||
if (runFinallyCbs) { |
_handle(packet) { |
||||||
this._finally.forEach(fn => fn(data)); |
const { data } = packet; |
||||||
|
let runFinallyCbs = false; |
||||||
|
|
||||||
|
if (packet.status === 'resolve') { |
||||||
|
if (this._resolve.length === 0) console.log(data); |
||||||
|
this._resolve.forEach((fn) => { |
||||||
|
const ret = fn(data); |
||||||
|
if (ret && typeof ret.then === 'function') { |
||||||
|
console.warn('TesseractJob instances do not chain like ES6 Promises. To convert it into a real promise, use Promise.resolve.'); |
||||||
} |
} |
||||||
|
}); |
||||||
|
this._resolve = data; |
||||||
|
this._instance._dequeue(); |
||||||
|
runFinallyCbs = true; |
||||||
|
} else if (packet.status === 'reject') { |
||||||
|
if (this._reject.length === 0) console.error(data); |
||||||
|
this._reject.forEach(fn => fn(data)); |
||||||
|
this._reject = data; |
||||||
|
this._instance._dequeue(); |
||||||
|
runFinallyCbs = true; |
||||||
|
} else if (packet.status === 'progress') { |
||||||
|
this._progress.forEach(fn => fn(data)); |
||||||
|
} else { |
||||||
|
console.warn('Message type unknown', packet.status); |
||||||
|
} |
||||||
|
|
||||||
|
if (runFinallyCbs) { |
||||||
|
this._finally.forEach(fn => fn(data)); |
||||||
} |
} |
||||||
} |
} |
||||||
|
}; |
||||||
|
Loading…
Reference in new issue