@u1f992/pdfdiff 0.1.0 → 0.2.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/browser.js +194 -125
- package/dist/browser.js.map +1 -1
- package/dist/cli.js +213 -161
- package/dist/cli.js.map +1 -1
- package/dist/coi-serviceworker.min.js +2 -0
- package/dist/diff.d.ts +3 -3
- package/dist/diff.d.ts.map +1 -1
- package/dist/image.d.ts +1 -1
- package/dist/image.d.ts.map +1 -1
- package/dist/index.d.ts +6 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.html +5 -0
- package/dist/index.js +186 -125
- package/dist/index.js.map +1 -1
- package/dist/index.test.d.ts +2 -0
- package/dist/index.test.d.ts.map +1 -0
- package/dist/jimp.d.ts +1 -1
- package/dist/jimp.d.ts.map +1 -1
- package/dist/pdf.d.ts +2 -374
- package/dist/pdf.d.ts.map +1 -1
- package/dist/worker.d.ts +41 -1
- package/dist/worker.d.ts.map +1 -1
- package/dist/worker.js +3173 -38
- package/dist/worker.js.map +1 -1
- package/package.json +2 -1
- package/rollup.config.js +29 -42
- package/src/browser.ts +13 -1
- package/src/cli.ts +21 -1
- package/src/diff.ts +42 -27
- package/src/image.ts +31 -9
- package/src/index.html +5 -0
- package/src/index.test.ts +97 -0
- package/src/index.ts +195 -106
- package/src/jimp.ts +1 -0
- package/src/pdf.ts +34 -2
- package/src/worker.ts +136 -39
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@u1f992/pdfdiff",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Visualize and quantify differences between two PDF files.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -30,6 +30,7 @@
|
|
|
30
30
|
"@rollup/plugin-node-resolve": "^16.0.1",
|
|
31
31
|
"@rollup/plugin-typescript": "^12.1.4",
|
|
32
32
|
"@types/node": "^22.18.7",
|
|
33
|
+
"coi-serviceworker": "^0.1.7",
|
|
33
34
|
"http-server": "^14.1.1",
|
|
34
35
|
"nodehog": "^0.1.2",
|
|
35
36
|
"prettier": "^3.5.3",
|
package/rollup.config.js
CHANGED
|
@@ -15,6 +15,10 @@ const plugins = [
|
|
|
15
15
|
src: "node_modules/mupdf/dist/mupdf-wasm.wasm",
|
|
16
16
|
dest: "dist",
|
|
17
17
|
},
|
|
18
|
+
{
|
|
19
|
+
src: "node_modules/coi-serviceworker/coi-serviceworker.min.js",
|
|
20
|
+
dest: "dist",
|
|
21
|
+
},
|
|
18
22
|
{
|
|
19
23
|
src: "src/index.html",
|
|
20
24
|
dest: "dist",
|
|
@@ -27,6 +31,26 @@ const plugins = [
|
|
|
27
31
|
}),
|
|
28
32
|
];
|
|
29
33
|
|
|
34
|
+
const jimpAlias = alias({
|
|
35
|
+
entries: [
|
|
36
|
+
{
|
|
37
|
+
find: "jimp",
|
|
38
|
+
replacement: path.resolve("node_modules/jimp/dist/browser/index.js"),
|
|
39
|
+
},
|
|
40
|
+
],
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
const webWorkerAlias = alias({
|
|
44
|
+
entries: [
|
|
45
|
+
{
|
|
46
|
+
find: "web-worker",
|
|
47
|
+
replacement: path.resolve(
|
|
48
|
+
"node_modules/web-worker/dist/browser/index.cjs",
|
|
49
|
+
),
|
|
50
|
+
},
|
|
51
|
+
],
|
|
52
|
+
});
|
|
53
|
+
|
|
30
54
|
const rollupConfig = defineConfig([
|
|
31
55
|
{
|
|
32
56
|
input: "src/index.ts",
|
|
@@ -35,22 +59,8 @@ const rollupConfig = defineConfig([
|
|
|
35
59
|
sourcemap: true,
|
|
36
60
|
},
|
|
37
61
|
plugins: [
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
{
|
|
41
|
-
find: "jimp",
|
|
42
|
-
replacement: path.resolve(
|
|
43
|
-
"node_modules/jimp/dist/browser/index.js",
|
|
44
|
-
),
|
|
45
|
-
},
|
|
46
|
-
{
|
|
47
|
-
find: "web-worker",
|
|
48
|
-
replacement: path.resolve(
|
|
49
|
-
"node_modules/web-worker/dist/browser/index.cjs",
|
|
50
|
-
),
|
|
51
|
-
},
|
|
52
|
-
],
|
|
53
|
-
}),
|
|
62
|
+
jimpAlias,
|
|
63
|
+
webWorkerAlias,
|
|
54
64
|
typescript({ tsconfig: "./tsconfig.json" }),
|
|
55
65
|
...plugins,
|
|
56
66
|
],
|
|
@@ -62,16 +72,7 @@ const rollupConfig = defineConfig([
|
|
|
62
72
|
sourcemap: true,
|
|
63
73
|
},
|
|
64
74
|
plugins: [
|
|
65
|
-
|
|
66
|
-
entries: [
|
|
67
|
-
{
|
|
68
|
-
find: "jimp",
|
|
69
|
-
replacement: path.resolve(
|
|
70
|
-
"node_modules/jimp/dist/browser/index.js",
|
|
71
|
-
),
|
|
72
|
-
},
|
|
73
|
-
],
|
|
74
|
-
}),
|
|
75
|
+
jimpAlias,
|
|
75
76
|
typescript({ tsconfig: "./tsconfig.json" }),
|
|
76
77
|
...plugins,
|
|
77
78
|
],
|
|
@@ -96,22 +97,8 @@ const rollupConfig = defineConfig([
|
|
|
96
97
|
sourcemap: true,
|
|
97
98
|
},
|
|
98
99
|
plugins: [
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
{
|
|
102
|
-
find: "jimp",
|
|
103
|
-
replacement: path.resolve(
|
|
104
|
-
"node_modules/jimp/dist/browser/index.js",
|
|
105
|
-
),
|
|
106
|
-
},
|
|
107
|
-
{
|
|
108
|
-
find: "web-worker",
|
|
109
|
-
replacement: path.resolve(
|
|
110
|
-
"node_modules/web-worker/dist/browser/index.cjs",
|
|
111
|
-
),
|
|
112
|
-
},
|
|
113
|
-
],
|
|
114
|
-
}),
|
|
100
|
+
jimpAlias,
|
|
101
|
+
webWorkerAlias,
|
|
115
102
|
typescript({ tsconfig: "./tsconfig.json" }),
|
|
116
103
|
...plugins,
|
|
117
104
|
],
|
package/src/browser.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/// <reference lib="dom" />
|
|
2
2
|
|
|
3
|
-
import * as pdfdiff from "./index.
|
|
3
|
+
import * as pdfdiff from "./index.ts";
|
|
4
4
|
|
|
5
5
|
async function readFileAsUint8Array(file: File): Promise<Uint8Array> {
|
|
6
6
|
return new Promise((resolve, reject) => {
|
|
@@ -62,6 +62,17 @@ document
|
|
|
62
62
|
throw new Error();
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
+
const workers = ((
|
|
66
|
+
val = (document.getElementById("workers") as HTMLInputElement | null)
|
|
67
|
+
?.value,
|
|
68
|
+
) => (typeof val !== "undefined" ? parseInt(val, 10) : undefined))();
|
|
69
|
+
if (
|
|
70
|
+
typeof workers !== "undefined" &&
|
|
71
|
+
(Number.isNaN(workers) || workers < 1)
|
|
72
|
+
) {
|
|
73
|
+
throw new Error();
|
|
74
|
+
}
|
|
75
|
+
|
|
65
76
|
const additionColorHex = (
|
|
66
77
|
document.getElementById("addition-color") as HTMLInputElement | null
|
|
67
78
|
)?.value;
|
|
@@ -93,6 +104,7 @@ document
|
|
|
93
104
|
if (alpha !== undefined) options.alpha = alpha;
|
|
94
105
|
if (pdfMask !== undefined) options.mask = pdfMask;
|
|
95
106
|
if (align !== undefined) options.align = align;
|
|
107
|
+
if (workers !== undefined) options.workers = workers;
|
|
96
108
|
if (additionColor || deletionColor || modificationColor) {
|
|
97
109
|
options.pallet = {};
|
|
98
110
|
if (additionColor) options.pallet.addition = additionColor;
|
package/src/cli.ts
CHANGED
|
@@ -28,7 +28,7 @@ import {
|
|
|
28
28
|
parseHex,
|
|
29
29
|
formatHex,
|
|
30
30
|
visualizeDifferences,
|
|
31
|
-
} from "./index.
|
|
31
|
+
} from "./index.ts";
|
|
32
32
|
|
|
33
33
|
const {
|
|
34
34
|
positionals,
|
|
@@ -40,6 +40,7 @@ const {
|
|
|
40
40
|
"addition-color": additionColorHex,
|
|
41
41
|
"deletion-color": deletionColorHex,
|
|
42
42
|
"modification-color": modificationColorHex,
|
|
43
|
+
workers: workers_,
|
|
43
44
|
version,
|
|
44
45
|
help,
|
|
45
46
|
},
|
|
@@ -53,6 +54,7 @@ const {
|
|
|
53
54
|
"addition-color": { type: "string" },
|
|
54
55
|
"deletion-color": { type: "string" },
|
|
55
56
|
"modification-color": { type: "string" },
|
|
57
|
+
workers: { type: "string" },
|
|
56
58
|
version: { type: "boolean", short: "v" },
|
|
57
59
|
help: { type: "boolean", short: "h" },
|
|
58
60
|
},
|
|
@@ -72,8 +74,17 @@ OPTIONS:
|
|
|
72
74
|
--addition-color <#HEX> default: ${formatHex(defaultOptions.pallet.addition)}
|
|
73
75
|
--deletion-color <#HEX> default: ${formatHex(defaultOptions.pallet.deletion)}
|
|
74
76
|
--modification-color <#HEX> default: ${formatHex(defaultOptions.pallet.modification)}
|
|
77
|
+
--workers <N> default: ${defaultOptions.workers}
|
|
75
78
|
-v, --version
|
|
76
79
|
-h, --help
|
|
80
|
+
|
|
81
|
+
NOTES:
|
|
82
|
+
Approximate per-worker memory:
|
|
83
|
+
a_size_MB + b_size_MB [+ mask_size_MB] (PDF buffers in wasm)
|
|
84
|
+
+ 300 MB (mupdf + V8 base)
|
|
85
|
+
+ (dpi / 150)^2 * 50 MB (pixmap working set)
|
|
86
|
+
The main process adds ~500 MB - 1 GB (varies with --workers).
|
|
87
|
+
Choose --workers so the total stays under ~80% of available memory.
|
|
77
88
|
`);
|
|
78
89
|
process.exit(0);
|
|
79
90
|
}
|
|
@@ -137,6 +148,14 @@ if (
|
|
|
137
148
|
throw new Error("Invalid color format");
|
|
138
149
|
}
|
|
139
150
|
|
|
151
|
+
const workers =
|
|
152
|
+
typeof workers_ !== "undefined"
|
|
153
|
+
? parseInt(workers_, 10)
|
|
154
|
+
: defaultOptions.workers;
|
|
155
|
+
if (Number.isNaN(workers) || workers < 1) {
|
|
156
|
+
throw new Error("Invalid workers value");
|
|
157
|
+
}
|
|
158
|
+
|
|
140
159
|
fs.mkdirSync(outDir, { recursive: true });
|
|
141
160
|
for await (const [
|
|
142
161
|
i,
|
|
@@ -152,6 +171,7 @@ for await (const [
|
|
|
152
171
|
deletion: deletionColor,
|
|
153
172
|
modification: modificationColor,
|
|
154
173
|
},
|
|
174
|
+
workers,
|
|
155
175
|
}),
|
|
156
176
|
1,
|
|
157
177
|
)) {
|
package/src/diff.ts
CHANGED
|
@@ -15,11 +15,9 @@
|
|
|
15
15
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
|
-
import
|
|
19
|
-
|
|
20
|
-
import { type
|
|
21
|
-
import { alignSize, createEmptyImage, type AlignStrategy } from "./image.js";
|
|
22
|
-
import { type RGBAColor } from "./rgba-color.js";
|
|
18
|
+
import { type JimpInstance } from "./jimp.ts";
|
|
19
|
+
import { alignSize, createEmptyImage, type AlignStrategy } from "./image.ts";
|
|
20
|
+
import { type RGBAColor } from "./rgba-color.ts";
|
|
23
21
|
|
|
24
22
|
export type Pallet = {
|
|
25
23
|
addition: RGBAColor;
|
|
@@ -35,34 +33,51 @@ export function drawDifference(
|
|
|
35
33
|
align: AlignStrategy,
|
|
36
34
|
) {
|
|
37
35
|
const [aNew, bNew, maskNew] = alignSize([a, b, mask], align);
|
|
36
|
+
const width = aNew.width;
|
|
37
|
+
const height = aNew.height;
|
|
38
|
+
const aData = aNew.bitmap.data;
|
|
39
|
+
const bData = bNew.bitmap.data;
|
|
40
|
+
const mData = maskNew.bitmap.data;
|
|
38
41
|
|
|
39
|
-
const
|
|
40
|
-
const
|
|
41
|
-
const modColor = jimp.rgbaToInt(...pallet.modification);
|
|
42
|
+
const diffImage = createEmptyImage(width, height);
|
|
43
|
+
const dData = diffImage.bitmap.data;
|
|
42
44
|
|
|
43
|
-
const
|
|
44
|
-
const
|
|
45
|
-
const
|
|
46
|
-
const modification = [] as [number, number][];
|
|
45
|
+
const addition: [number, number][] = [];
|
|
46
|
+
const deletion: [number, number][] = [];
|
|
47
|
+
const modification: [number, number][] = [];
|
|
47
48
|
|
|
48
|
-
for (let x = 0; x <
|
|
49
|
-
for (let y = 0; y <
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
const
|
|
53
|
-
const
|
|
54
|
-
|
|
55
|
-
|
|
49
|
+
for (let x = 0; x < width; x++) {
|
|
50
|
+
for (let y = 0; y < height; y++) {
|
|
51
|
+
const idx = (y * width + x) * 4;
|
|
52
|
+
if (mData[idx + 3]! !== 0) continue;
|
|
53
|
+
const aAlpha = aData[idx + 3]!;
|
|
54
|
+
const bAlpha = bData[idx + 3]!;
|
|
55
|
+
if (
|
|
56
|
+
aAlpha === bAlpha &&
|
|
57
|
+
aData[idx] === bData[idx] &&
|
|
58
|
+
aData[idx + 1] === bData[idx + 1] &&
|
|
59
|
+
aData[idx + 2] === bData[idx + 2]
|
|
60
|
+
) {
|
|
56
61
|
continue;
|
|
57
62
|
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
63
|
+
if (aAlpha === 0 && bAlpha === 0) continue;
|
|
64
|
+
let target: [number, number][];
|
|
65
|
+
let color: Readonly<RGBAColor>;
|
|
66
|
+
if (aAlpha === 0) {
|
|
67
|
+
target = addition;
|
|
68
|
+
color = pallet.addition;
|
|
69
|
+
} else if (bAlpha === 0) {
|
|
70
|
+
target = deletion;
|
|
71
|
+
color = pallet.deletion;
|
|
72
|
+
} else {
|
|
73
|
+
target = modification;
|
|
74
|
+
color = pallet.modification;
|
|
75
|
+
}
|
|
64
76
|
target.push([x, y]);
|
|
65
|
-
|
|
77
|
+
dData[idx] = color[0];
|
|
78
|
+
dData[idx + 1] = color[1];
|
|
79
|
+
dData[idx + 2] = color[2];
|
|
80
|
+
dData[idx + 3] = color[3];
|
|
66
81
|
}
|
|
67
82
|
}
|
|
68
83
|
|
package/src/image.ts
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
18
|
import * as jimp from "jimp";
|
|
19
|
-
import { type JimpInstance } from "./jimp.
|
|
19
|
+
import { type JimpInstance } from "./jimp.ts";
|
|
20
20
|
|
|
21
21
|
export function createEmptyImage(width: number, height: number) {
|
|
22
22
|
return new jimp.Jimp({
|
|
@@ -117,12 +117,34 @@ export function composeLayers(
|
|
|
117
117
|
canvasHeight: number,
|
|
118
118
|
layers: [JimpInstance, number][],
|
|
119
119
|
) {
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
120
|
+
const canvas = createEmptyImage(canvasWidth, canvasHeight);
|
|
121
|
+
const dData = canvas.bitmap.data;
|
|
122
|
+
for (const [image, opacity] of layers) {
|
|
123
|
+
const sData = image.bitmap.data;
|
|
124
|
+
const srcWidth = image.width;
|
|
125
|
+
const w = Math.min(canvasWidth, srcWidth);
|
|
126
|
+
const h = Math.min(canvasHeight, image.height);
|
|
127
|
+
for (let y = 0; y < h; y++) {
|
|
128
|
+
for (let x = 0; x < w; x++) {
|
|
129
|
+
const dIdx = (y * canvasWidth + x) * 4;
|
|
130
|
+
const sIdx = (y * srcWidth + x) * 4;
|
|
131
|
+
const sa = (sData[sIdx + 3]! / 255) * opacity;
|
|
132
|
+
if (sa === 0) continue;
|
|
133
|
+
const da = dData[dIdx + 3]! / 255;
|
|
134
|
+
const oa = sa + da * (1 - sa);
|
|
135
|
+
if (oa === 0) continue;
|
|
136
|
+
const sw = sa / oa;
|
|
137
|
+
const dw = (da * (1 - sa)) / oa;
|
|
138
|
+
dData[dIdx] = Math.round(sData[sIdx]! * sw + dData[dIdx]! * dw);
|
|
139
|
+
dData[dIdx + 1] = Math.round(
|
|
140
|
+
sData[sIdx + 1]! * sw + dData[dIdx + 1]! * dw,
|
|
141
|
+
);
|
|
142
|
+
dData[dIdx + 2] = Math.round(
|
|
143
|
+
sData[sIdx + 2]! * sw + dData[dIdx + 2]! * dw,
|
|
144
|
+
);
|
|
145
|
+
dData[dIdx + 3] = Math.round(oa * 255);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return canvas;
|
|
128
150
|
}
|
package/src/index.html
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
6
|
<title>pdfdiff</title>
|
|
7
7
|
<link rel="stylesheet" href="./style.css" />
|
|
8
|
+
<script src="./coi-serviceworker.min.js"></script>
|
|
8
9
|
<script type="module" src="./browser.js"></script>
|
|
9
10
|
</head>
|
|
10
11
|
<body>
|
|
@@ -46,6 +47,10 @@
|
|
|
46
47
|
<option value="bottom-right">bottom-right</option>
|
|
47
48
|
</select>
|
|
48
49
|
</div>
|
|
50
|
+
<div>
|
|
51
|
+
<label for="workers">Workers:</label>
|
|
52
|
+
<input type="number" id="workers" value="1" min="1" />
|
|
53
|
+
</div>
|
|
49
54
|
<div>
|
|
50
55
|
<label for="addition-color">Addition:</label>
|
|
51
56
|
<input type="color" id="addition-color" value="#4cae4f" />
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (C) 2025 Koutaro Mukai
|
|
3
|
+
*
|
|
4
|
+
* This program is free software: you can redistribute it and/or modify
|
|
5
|
+
* it under the terms of the GNU General Public License as published by
|
|
6
|
+
* the Free Software Foundation, either version 3 of the License, or
|
|
7
|
+
* (at your option) any later version.
|
|
8
|
+
*
|
|
9
|
+
* This program is distributed in the hope that it will be useful,
|
|
10
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
+
* GNU General Public License for more details.
|
|
13
|
+
*
|
|
14
|
+
* You should have received a copy of the GNU General Public License
|
|
15
|
+
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import assert from "node:assert/strict";
|
|
19
|
+
import fs from "node:fs";
|
|
20
|
+
import test from "node:test";
|
|
21
|
+
|
|
22
|
+
import {
|
|
23
|
+
defaultOptions,
|
|
24
|
+
formatHex,
|
|
25
|
+
isValidAlignStrategy,
|
|
26
|
+
parseHex,
|
|
27
|
+
visualizeDifferences,
|
|
28
|
+
withIndex,
|
|
29
|
+
} from "./index.ts";
|
|
30
|
+
|
|
31
|
+
const fixtures = new URL("../test/", import.meta.url);
|
|
32
|
+
const readFixture = (name: string) =>
|
|
33
|
+
new Uint8Array(fs.readFileSync(new URL(name, fixtures)));
|
|
34
|
+
|
|
35
|
+
test("re-exports are exposed as runtime values", () => {
|
|
36
|
+
assert.equal(typeof withIndex, "function");
|
|
37
|
+
assert.equal(typeof isValidAlignStrategy, "function");
|
|
38
|
+
assert.equal(typeof parseHex, "function");
|
|
39
|
+
assert.equal(typeof formatHex, "function");
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
test("defaultOptions", () => {
|
|
43
|
+
assert.deepEqual(defaultOptions, {
|
|
44
|
+
dpi: 150,
|
|
45
|
+
alpha: true,
|
|
46
|
+
mask: undefined,
|
|
47
|
+
align: "resize",
|
|
48
|
+
pallet: {
|
|
49
|
+
addition: [0x4c, 0xae, 0x4f, 0xff],
|
|
50
|
+
deletion: [0xff, 0x57, 0x24, 0xff],
|
|
51
|
+
modification: [0xff, 0xc1, 0x05, 0xff],
|
|
52
|
+
},
|
|
53
|
+
workers: 1,
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
test("isValidAlignStrategy", async (ctx) => {
|
|
58
|
+
for (const s of [
|
|
59
|
+
"resize",
|
|
60
|
+
"top-left",
|
|
61
|
+
"top-center",
|
|
62
|
+
"top-right",
|
|
63
|
+
"middle-left",
|
|
64
|
+
"middle-center",
|
|
65
|
+
"middle-right",
|
|
66
|
+
"bottom-left",
|
|
67
|
+
"bottom-center",
|
|
68
|
+
"bottom-right",
|
|
69
|
+
]) {
|
|
70
|
+
await ctx.test(s, () => {
|
|
71
|
+
assert.equal(isValidAlignStrategy(s), true);
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
await ctx.test("invalid", () => {
|
|
75
|
+
assert.equal(isValidAlignStrategy("invalid"), false);
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
test("visualizeDifferences pins counts for fixtures at dpi 300", async () => {
|
|
80
|
+
const a = readFixture("a.pdf");
|
|
81
|
+
const b = readFixture("b.pdf");
|
|
82
|
+
const mask = readFixture("mask.pdf");
|
|
83
|
+
|
|
84
|
+
const pages: { addition: number; deletion: number; modification: number }[] =
|
|
85
|
+
[];
|
|
86
|
+
for await (const page of visualizeDifferences(a, b, { dpi: 300, mask })) {
|
|
87
|
+
pages.push({
|
|
88
|
+
addition: page.addition.length,
|
|
89
|
+
deletion: page.deletion.length,
|
|
90
|
+
modification: page.modification.length,
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
assert.deepEqual(pages, [
|
|
95
|
+
{ addition: 7500, deletion: 7500, modification: 7500 },
|
|
96
|
+
]);
|
|
97
|
+
});
|