@scanmate/ocr 0.2.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.esm.js
CHANGED
|
@@ -727,8 +727,20 @@ function templateKey(run, character) {
|
|
|
727
727
|
* @param runs - Its text layer.
|
|
728
728
|
* @returns Glyph images, by {@link templateKey}.
|
|
729
729
|
*/
|
|
730
|
-
|
|
731
|
-
|
|
730
|
+
/**
|
|
731
|
+
* Folds one page's glyphs into a store that already holds others.
|
|
732
|
+
*
|
|
733
|
+
* Templates are filed by face, size and turn, and a PDF renders those
|
|
734
|
+
* identically wherever they appear - so a glyph from page 4 is as good a
|
|
735
|
+
* template as one from page 1, and on many documents it is the only one there
|
|
736
|
+
* is. Measured on a real order confirmation: the face its page-1 total is set
|
|
737
|
+
* in carries six distinct digits on that page and nine across the document, and
|
|
738
|
+
* six is below the bar for checking anything at all.
|
|
739
|
+
*
|
|
740
|
+
* The per-character cap applies to the store as a whole, so a long document
|
|
741
|
+
* costs no more memory than a short one.
|
|
742
|
+
*/
|
|
743
|
+
function collectInto(templates, page, dpi, runs) {
|
|
732
744
|
for (const run of runs) {
|
|
733
745
|
const characters = [...run.text].filter(character => character.trim() !== '');
|
|
734
746
|
const lightOnDark = printPolarity(page, dpi, run) === 'light-on-dark';
|
|
@@ -743,6 +755,9 @@ function collectTemplates(page, dpi, runs) {
|
|
|
743
755
|
}
|
|
744
756
|
return templates;
|
|
745
757
|
}
|
|
758
|
+
function collectTemplates(page, dpi, runs) {
|
|
759
|
+
return collectInto(new Map(), page, dpi, runs);
|
|
760
|
+
}
|
|
746
761
|
/** Files one glyph under its key, up to the few that are worth keeping. */
|
|
747
762
|
function keep(templates, key, glyph) {
|
|
748
763
|
if (glyph === null) return;
|
|
@@ -1457,6 +1472,24 @@ function luminance(data, i) {
|
|
|
1457
1472
|
async function ocrPages(pages, options = {}) {
|
|
1458
1473
|
const engine = options.engine ?? (await createTesseractEngine(options.tesseract));
|
|
1459
1474
|
try {
|
|
1475
|
+
// The glyphs of the whole document, gathered before any page is read.
|
|
1476
|
+
//
|
|
1477
|
+
// A page's own figures are often set in a face it uses for little else, and
|
|
1478
|
+
// a run cannot be checked against rivals that are not there - on a real
|
|
1479
|
+
// order confirmation the face of the page-1 total carries six distinct
|
|
1480
|
+
// digits on that page and nine across the document, and six is below the
|
|
1481
|
+
// bar for checking anything at all. The same face at the same size renders
|
|
1482
|
+
// identically on every page, so a glyph from page 4 is as good a template
|
|
1483
|
+
// as one from page 1.
|
|
1484
|
+
//
|
|
1485
|
+
// Each page's greyscale is dropped as soon as its glyphs are taken, so this
|
|
1486
|
+
// holds one page of pixels at a time, not the document.
|
|
1487
|
+
const templates = new Map();
|
|
1488
|
+
if (options.printCheck !== false) for (const page of pages) {
|
|
1489
|
+
const items = page.metadata?.original?.textItems;
|
|
1490
|
+
if (items === undefined || items === null || items.length === 0) continue;
|
|
1491
|
+
collectInto(templates, toGrayscale(page.original.raster), page.original.dpi ?? options.assumeDpi ?? 150, items);
|
|
1492
|
+
}
|
|
1460
1493
|
const results = [];
|
|
1461
1494
|
for (const [position, page] of pages.entries()) {
|
|
1462
1495
|
const index = position + 1;
|
|
@@ -1468,7 +1501,7 @@ async function ocrPages(pages, options = {}) {
|
|
|
1468
1501
|
index,
|
|
1469
1502
|
total: pages.length
|
|
1470
1503
|
});
|
|
1471
|
-
const result = await readPage(page, engine, options);
|
|
1504
|
+
const result = await readPage(page, engine, options, templates);
|
|
1472
1505
|
results.push({
|
|
1473
1506
|
...page,
|
|
1474
1507
|
text: result
|
|
@@ -1506,7 +1539,7 @@ async function ocrPages(pages, options = {}) {
|
|
|
1506
1539
|
if (options.engine === undefined) await engine.terminate();
|
|
1507
1540
|
}
|
|
1508
1541
|
}
|
|
1509
|
-
async function readPage(page, engine, options) {
|
|
1542
|
+
async function readPage(page, engine, options, templates) {
|
|
1510
1543
|
const {
|
|
1511
1544
|
original: originalSource = 'auto',
|
|
1512
1545
|
targetDpi = 300,
|
|
@@ -1600,7 +1633,6 @@ async function readPage(page, engine, options) {
|
|
|
1600
1633
|
const printed = items.map(item => ({
|
|
1601
1634
|
...item
|
|
1602
1635
|
}));
|
|
1603
|
-
const templates = collectTemplates(originalGray, originalDpi, printed);
|
|
1604
1636
|
for (const [r, run] of printed.entries()) {
|
|
1605
1637
|
const verified = verifyPrintedRun(originalGray, scanGray, originalDpi, run, templates, printCheck);
|
|
1606
1638
|
if (verified === null) continue;
|
|
@@ -1714,5 +1746,5 @@ function mean(values) {
|
|
|
1714
1746
|
return values.length === 0 ? 0 : values.reduce((a, b) => a + b, 0) / values.length;
|
|
1715
1747
|
}
|
|
1716
1748
|
|
|
1717
|
-
export { DEFAULT_NORMALISE, DEFAULT_RECHECK_PASSES, DEFAULT_TESSERACT_OPTIONS, FIGURE_CHARACTERS$1 as FIGURE_CHARACTERS, TEXT_CHARACTERS, claimWords, collectTemplates, compareTexts, cosine, createTesseractEngine, diacriticsMap, dice, foldConfusables, foldDiacritics, glyphCells, glyphWords, jaccard, jaroWinkler, judgeRun, judgeRuns, levenshtein, levenshteinSimilarity, matchWords, normaliseText, ocrPages, placeGlyphs, printPolarity, readRun, recheckRun, templateKey, tokenise, verifyPrintedRun, wordDistance, wordRecall };
|
|
1749
|
+
export { DEFAULT_NORMALISE, DEFAULT_RECHECK_PASSES, DEFAULT_TESSERACT_OPTIONS, FIGURE_CHARACTERS$1 as FIGURE_CHARACTERS, TEXT_CHARACTERS, claimWords, collectInto, collectTemplates, compareTexts, cosine, createTesseractEngine, diacriticsMap, dice, foldConfusables, foldDiacritics, glyphCells, glyphWords, jaccard, jaroWinkler, judgeRun, judgeRuns, levenshtein, levenshteinSimilarity, matchWords, normaliseText, ocrPages, placeGlyphs, printPolarity, readRun, recheckRun, templateKey, tokenise, verifyPrintedRun, wordDistance, wordRecall };
|
|
1718
1750
|
//# sourceMappingURL=index.esm.js.map
|
package/dist/src/index.d.ts
CHANGED
|
@@ -30,8 +30,8 @@ export { compareTexts } from './text-similarity/index.js';
|
|
|
30
30
|
export type { ScoreMetric, TextMetrics } from './text-similarity/index.js';
|
|
31
31
|
export { DEFAULT_NORMALISE, normaliseText, tokenise } from './text-normalisation/index.js';
|
|
32
32
|
export type { NormaliseOptions } from './text-normalisation/index.js';
|
|
33
|
-
export { collectTemplates, FIGURE_CHARACTERS, glyphCells, glyphWords, placeGlyphs, printPolarity, templateKey, TEXT_CHARACTERS, verifyPrintedRun } from './print-verification/index.js';
|
|
34
|
-
export type { CellOptions, PrintPolarity, PrintVerification, Templates, VerifyOptions } from './print-verification/index.js';
|
|
33
|
+
export { collectInto, collectTemplates, FIGURE_CHARACTERS, glyphCells, glyphWords, placeGlyphs, printPolarity, templateKey, TEXT_CHARACTERS, verifyPrintedRun } from './print-verification/index.js';
|
|
34
|
+
export type { CellOptions, PrintPolarity, PrintVerification, TemplateStore, Templates, VerifyOptions } from './print-verification/index.js';
|
|
35
35
|
export { claimWords, DEFAULT_RECHECK_PASSES, judgeRun, judgeRuns, matchWords, readRun, recheckRun } from './page-reading/index.js';
|
|
36
36
|
export type { Claims, MatchOptions, Recheck, RecheckOptions, RecheckPass, Reference, Verdict, WordMatch } from './page-reading/index.js';
|
|
37
37
|
export { cosine, dice, jaccard, jaroWinkler, levenshtein, levenshteinSimilarity, wordDistance, wordRecall } from './text-similarity/index.js';
|
|
@@ -15,6 +15,8 @@ import type { GrayImage, ScanmateOrientedRect, TextRun } from '@scanmate/ink';
|
|
|
15
15
|
/** A run of the original's text layer, where it sits and how it is set. */
|
|
16
16
|
/** Glyph images by face, size and character. */
|
|
17
17
|
export type Templates = ReadonlyMap<string, GrayImage[]>;
|
|
18
|
+
/** A store still being filled. Readers take {@link Templates}; only the collector writes. */
|
|
19
|
+
export type TemplateStore = Map<string, GrayImage[]>;
|
|
18
20
|
/** The key a run's glyphs are filed under. */
|
|
19
21
|
export declare function templateKey(run: TextRun, character: string): string;
|
|
20
22
|
/**
|
|
@@ -25,6 +27,20 @@ export declare function templateKey(run: TextRun, character: string): string;
|
|
|
25
27
|
* @param runs - Its text layer.
|
|
26
28
|
* @returns Glyph images, by {@link templateKey}.
|
|
27
29
|
*/
|
|
30
|
+
/**
|
|
31
|
+
* Folds one page's glyphs into a store that already holds others.
|
|
32
|
+
*
|
|
33
|
+
* Templates are filed by face, size and turn, and a PDF renders those
|
|
34
|
+
* identically wherever they appear - so a glyph from page 4 is as good a
|
|
35
|
+
* template as one from page 1, and on many documents it is the only one there
|
|
36
|
+
* is. Measured on a real order confirmation: the face its page-1 total is set
|
|
37
|
+
* in carries six distinct digits on that page and nine across the document, and
|
|
38
|
+
* six is below the bar for checking anything at all.
|
|
39
|
+
*
|
|
40
|
+
* The per-character cap applies to the store as a whole, so a long document
|
|
41
|
+
* costs no more memory than a short one.
|
|
42
|
+
*/
|
|
43
|
+
export declare function collectInto(templates: TemplateStore, page: GrayImage, dpi: number, runs: readonly TextRun[]): Templates;
|
|
28
44
|
export declare function collectTemplates(page: GrayImage, dpi: number, runs: readonly TextRun[]): Templates;
|
|
29
45
|
/**
|
|
30
46
|
* The greyscale of one box of the page, or `null` when it lies outside it;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { glyphCells, glyphWords, placeGlyphs } from './glyph-cells.use-case.js';
|
|
2
2
|
export type { CellOptions } from './glyph-cells.use-case.js';
|
|
3
|
-
export { collectTemplates, templateKey } from './glyph-templates.use-case.js';
|
|
4
|
-
export type { Templates } from './glyph-templates.use-case.js';
|
|
3
|
+
export { collectInto, collectTemplates, templateKey } from './glyph-templates.use-case.js';
|
|
4
|
+
export type { TemplateStore, Templates } from './glyph-templates.use-case.js';
|
|
5
5
|
export { mergeVerifiedFigures } from './merge-reading.mapper.js';
|
|
6
6
|
export { printPolarity } from './print-polarity.policy.js';
|
|
7
7
|
export type { PrintPolarity } from './print-polarity.policy.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@scanmate/ocr",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "How closely a scan's text matches the original's: OCR matched run by run on the page, figures held exact, every difference located.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Eduardo Russo",
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"!**/*.js.map"
|
|
42
42
|
],
|
|
43
43
|
"dependencies": {
|
|
44
|
-
"@scanmate/ink": "^0.
|
|
44
|
+
"@scanmate/ink": "^0.3.0",
|
|
45
45
|
"@tesseract.js-data/eng": "^1.0.0",
|
|
46
46
|
"fastest-levenshtein": "^1.0.16",
|
|
47
47
|
"tesseract.js": "^7.0.0"
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
"access": "public"
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|
|
53
|
-
"@scanmate/align": "^0.
|
|
54
|
-
"@scanmate/extract": "^0.
|
|
53
|
+
"@scanmate/align": "^0.3.0",
|
|
54
|
+
"@scanmate/extract": "^0.3.0"
|
|
55
55
|
}
|
|
56
56
|
}
|