@scanmate/diff 0.7.1 → 0.8.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/README.md +4 -2
- package/dist/index.esm.js +14 -9
- package/dist/src/change-detection/page-diff.contract.d.ts +19 -13
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -48,7 +48,9 @@ Rectangles are in PDF points from the page's top-left by default, the same frame
|
|
|
48
48
|
|
|
49
49
|
A region is **identified** when it has at least `minFillArea` (2 mm²) of new ink and is not **overfilled** — covered or struck through, which `maxFill` (0.5) draws the line on. Form rules showing through a slight misregistration are discounted: a component spanning 90% of the region and no thicker than 0.6 mm is the box's own printed line.
|
|
50
50
|
|
|
51
|
-
People sign past the box they are given, so each region also claims the ink within
|
|
51
|
+
People sign past the box they are given, so each region also claims the ink within its **bleed** - 6 points on every side unless told otherwise - and the regions claim it **together**, so one stroke running through two fields is not left over as an unexpected mark. What a region reports is still the rectangle it was given; the band is drawn in pink.
|
|
52
|
+
|
|
53
|
+
The bleed can be set per side: `bleed` for all four, and `bleedTop`, `bleedRight`, `bleedBottom` or `bleedLeft` to override one. A signature descends more than it climbs, so `{ bleedTop: 2, bleedBottom: 12 }` keeps a field clear of the printed line above it and gives the pen room below. `Scanmate.mark` in `@scanmate/scan` draws exactly this band on the original, so a region can be checked before anything is measured with it.
|
|
52
54
|
|
|
53
55
|
Each region reports its shape too — how many separate changes, the largest, the bounds as a share of the box, how much ink touches the border — so a signature can be told from a stray line without looking at the picture.
|
|
54
56
|
|
|
@@ -61,7 +63,7 @@ Each region reports its shape too — how many separate changes, the largest, th
|
|
|
61
63
|
| `faintInk` | `0.25` | Fraction of the normal threshold for "still there". |
|
|
62
64
|
| `minFillArea` | `2` mm² | New ink a region needs. |
|
|
63
65
|
| `maxFill` | `0.5` | Above this the region is covered, not filled. |
|
|
64
|
-
| `
|
|
66
|
+
| `bleed` | `6` pt | How far outside a region its ink may lie, every side. `bleedTop`, `bleedRight`, `bleedBottom` and `bleedLeft` override one side. |
|
|
65
67
|
| `formLineSpan` | `0.9` | Span that makes a component a printed rule... |
|
|
66
68
|
| `formLineThickness` | `0.6` mm | ...if it is no thicker than this. |
|
|
67
69
|
| `minChangeArea` | `1` mm² | Smallest change reported. |
|
package/dist/index.esm.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createRaster, decodeImage, binarize, inkMap, toGrayscale, otsuThreshold, dilate, coverage, encodeImage } from '@scanmate/ink';
|
|
1
|
+
import { createRaster, decodeImage, binarize, inkMap, toGrayscale, otsuThreshold, dilate, coverage, resolveBleed, growBy, hasBleed, encodeImage } from '@scanmate/ink';
|
|
2
2
|
|
|
3
3
|
/** The area in question, drawn on the original: a statement of where, not of what. */
|
|
4
4
|
const REFERENCE = [0, 23, 252, 255];
|
|
@@ -720,7 +720,6 @@ async function diffPage(page, expected = [], options = {}) {
|
|
|
720
720
|
mergeGap = 3,
|
|
721
721
|
assumeDpi = 150,
|
|
722
722
|
regionOverlap = 0.5,
|
|
723
|
-
expectedMargin = 6,
|
|
724
723
|
maxChanges = 50,
|
|
725
724
|
probes = [],
|
|
726
725
|
keepMasks = false,
|
|
@@ -736,10 +735,11 @@ async function diffPage(page, expected = [], options = {}) {
|
|
|
736
735
|
const masks = await buildMasks(page.original.raster, page.aligned.raster, ink, tolerance, faintInk);
|
|
737
736
|
// People sign past the box they are given, so each region claims the ink a little
|
|
738
737
|
// way outside it too; what it reports is still the region it was given.
|
|
738
|
+
const bleed = resolveBleed(options);
|
|
739
739
|
const regions = expected.map(e => ({
|
|
740
740
|
id: e.id,
|
|
741
741
|
rect: scaleRect(e, toPixels),
|
|
742
|
-
claim: scaleRect(
|
|
742
|
+
claim: scaleRect(growBy(e, bleed), toPixels)
|
|
743
743
|
}));
|
|
744
744
|
const findChanges = (mask, minArea) => {
|
|
745
745
|
const components = connectedComponents(mask).filter(c => c.pixels >= 2);
|
|
@@ -806,28 +806,28 @@ async function diffPage(page, expected = [], options = {}) {
|
|
|
806
806
|
const unexpected = outside.slice(0, maxChanges).map(box => toChange(box));
|
|
807
807
|
const missing = lost.slice(0, maxChanges).map(box => toChange(box));
|
|
808
808
|
// The band first, so a region's own outline draws over it where they meet.
|
|
809
|
-
const margins =
|
|
809
|
+
const margins = hasBleed(bleed) ? regions.map(region => ({
|
|
810
810
|
rect: region.claim,
|
|
811
811
|
color: EXPECTED_MARGIN
|
|
812
812
|
})) : [];
|
|
813
813
|
const verdicts = regions.map((region, i) => ({
|
|
814
|
-
rect:
|
|
814
|
+
rect: pad(region.rect, 2),
|
|
815
815
|
color: expectedResults[i].identified ? IDENTIFIED : NOT_IDENTIFIED
|
|
816
816
|
}));
|
|
817
817
|
const reported = [...margins, ...verdicts, ...outside.slice(0, maxChanges).map(box => ({
|
|
818
|
-
rect:
|
|
818
|
+
rect: pad(box, 4),
|
|
819
819
|
color: UNEXPECTED
|
|
820
820
|
}))];
|
|
821
821
|
// On the original, every region is simply the area in question; the answers belong to the scan.
|
|
822
822
|
const asAsked = regions.map(region => ({
|
|
823
|
-
rect:
|
|
823
|
+
rect: pad(region.rect, 2),
|
|
824
824
|
color: REFERENCE
|
|
825
825
|
}));
|
|
826
826
|
const diffRaster = paintOverlay(masks);
|
|
827
827
|
if (annotate) annotateOverlay(diffRaster, reported);
|
|
828
828
|
// Lines about a point thick at any dpi, so the boxes read the same on every page.
|
|
829
829
|
const losses = lost.slice(0, maxChanges).map(box => ({
|
|
830
|
-
rect:
|
|
830
|
+
rect: pad(box, 4),
|
|
831
831
|
color: MISSING
|
|
832
832
|
}));
|
|
833
833
|
const sideBySideRaster = sideBySide ? composeSideBySide(page.original.raster, page.aligned.raster, {
|
|
@@ -925,7 +925,12 @@ function scaleRect(rect, factor) {
|
|
|
925
925
|
height: rect.height * factor
|
|
926
926
|
};
|
|
927
927
|
}
|
|
928
|
-
|
|
928
|
+
/**
|
|
929
|
+
* A box drawn a little outside what it marks, in pixels, so the outline does not
|
|
930
|
+
* cover the ink it is pointing at. Purely how the evidence is drawn; the room a
|
|
931
|
+
* region is allowed is its bleed, and that is decided by `resolveBleed`.
|
|
932
|
+
*/
|
|
933
|
+
function pad(rect, by) {
|
|
929
934
|
return {
|
|
930
935
|
x: rect.x - by,
|
|
931
936
|
y: rect.y - by,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AlignedPage, ImageFormat, InkOptions, ProgressCallback, Raster, ScanmateRect } from '@scanmate/ink';
|
|
1
|
+
import type { AlignedPage, Bleed, ImageFormat, InkOptions, ProgressCallback, Raster, ScanmateRect } from '@scanmate/ink';
|
|
2
2
|
import type { Masks } from '../region-comparison/index.js';
|
|
3
3
|
/**
|
|
4
4
|
* Coordinates for regions going in and changes coming out.
|
|
@@ -33,7 +33,24 @@ export interface ExpectedChange {
|
|
|
33
33
|
export type ComparedPage<Page extends AlignedPage = AlignedPage> = Page & {
|
|
34
34
|
diff: PageDiff;
|
|
35
35
|
};
|
|
36
|
-
|
|
36
|
+
/**
|
|
37
|
+
* How the comparison is run.
|
|
38
|
+
*
|
|
39
|
+
* The bleed - `bleed`, and `bleedTop`, `bleedRight`, `bleedBottom`, `bleedLeft`
|
|
40
|
+
* to override a side - is how far outside an expected region its ink may still
|
|
41
|
+
* lie, in `units`. Default 6 on every side, 2 mm at 72 points to the inch.
|
|
42
|
+
*
|
|
43
|
+
* People sign past the box they are given - a descender below the rule, a
|
|
44
|
+
* flourish out to the side - and that is the signature, not a mark someone made
|
|
45
|
+
* elsewhere. The region claims the ink within its bleed and measures it, while
|
|
46
|
+
* still reporting the rectangle it was given. Ink inside the bleed of any
|
|
47
|
+
* expected region counts towards them all, so one stroke crossing two fields is
|
|
48
|
+
* not left over as unexpected.
|
|
49
|
+
*
|
|
50
|
+
* It is the same rule `Scanmate.mark` draws, so the band a reviewer is shown is
|
|
51
|
+
* the band that is measured.
|
|
52
|
+
*/
|
|
53
|
+
export interface DiffOptions extends Bleed {
|
|
37
54
|
/** Units of `ExpectedChange` rectangles and of every rectangle reported back. Default `'points'`. */
|
|
38
55
|
units?: CoordinateUnits;
|
|
39
56
|
/**
|
|
@@ -56,17 +73,6 @@ export interface DiffOptions {
|
|
|
56
73
|
* 150 dpi, so a caller is expected to drop them as soon as it has asked.
|
|
57
74
|
*/
|
|
58
75
|
keepMasks?: boolean;
|
|
59
|
-
/**
|
|
60
|
-
* How far outside an expected region its ink may still lie, in `units`. Default `6`
|
|
61
|
-
* (2 mm at 72 points to the inch).
|
|
62
|
-
*
|
|
63
|
-
* People sign past the box they are given - a descender below the rule, a flourish
|
|
64
|
-
* out to the side - and that is the signature, not a mark someone made elsewhere. The
|
|
65
|
-
* region claims the ink within this band and measures it, while still reporting the
|
|
66
|
-
* rectangle it was given. Ink inside the band of any expected region counts towards
|
|
67
|
-
* them all, so one stroke crossing two fields is not left over as unexpected.
|
|
68
|
-
*/
|
|
69
|
-
expectedMargin?: number;
|
|
70
76
|
/** Pixels the original's ink is fattened by before diffing, to absorb sub-pixel misalignment. Default `2`. */
|
|
71
77
|
tolerance?: number;
|
|
72
78
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@scanmate/diff",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "What changed between an original and its aligned scan: expected regions filled in, unexpected marks, lost ink, and a side-by-side evidence image.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Eduardo Russo",
|
|
@@ -39,12 +39,12 @@
|
|
|
39
39
|
"!**/*.js.map"
|
|
40
40
|
],
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@scanmate/ink": "^0.
|
|
42
|
+
"@scanmate/ink": "^0.8.0"
|
|
43
43
|
},
|
|
44
44
|
"publishConfig": {
|
|
45
45
|
"access": "public"
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
48
|
-
"@scanmate/align": "^0.
|
|
48
|
+
"@scanmate/align": "^0.8.0"
|
|
49
49
|
}
|
|
50
50
|
}
|