gutterpress 0.11.20-alpha.2 → 0.11.20-alpha.3
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/api/index.js +3 -2
- package/dist/{build-qmjg9r2d.js → build-a8ycsg80.js} +5 -4
- package/dist/{cli-zacevwcy.js → cli-9k2tb493.js} +181 -431
- package/dist/{cli-7z29z4wz.js → cli-hn9pk0hp.js} +1 -1
- package/dist/cli-sth219v1.js +418 -0
- package/dist/{cli-j802s31j.js → cli-x4p99w8d.js} +2 -2
- package/dist/{cli-gh0ym80r.js → cli-y9bcya7r.js} +121 -20
- package/dist/cli.js +12 -12
- package/dist/{doctor-fe7tcs4v.js → doctor-wbjkrcpc.js} +2 -2
- package/dist/{engine-yax79k9m.js → engine-fdtv01a2.js} +2 -2
- package/dist/{engine-9xb1ky8d.js → engine-yxnnp3hx.js} +1 -1
- package/dist/{ext-ahwxt6gv.js → ext-pesyrs68.js} +5 -4
- package/dist/{gutterpress-viewer-retj6ym2.js → gutterpress-viewer-1yse8cx3.js} +12 -4
- package/dist/{index-6xwtb7cw.js → index-r87y7wzw.js} +1 -1
- package/dist/index-sth219v1.js +418 -0
- package/dist/{index-razpty47.js → index-tjvrchxj.js} +297 -448
- package/dist/{index-3nr5rzzp.js → index-zagagnwq.js} +2 -2
- package/dist/index.js +4 -3
- package/dist/lib/build-fingerprint.d.ts +8 -0
- package/dist/lib/ghostscript.d.ts +70 -16
- package/dist/lib/pdf-inspect.d.ts +45 -0
- package/dist/{manifest.schema-74s1ykyv.json → manifest.schema-c9x8912a.json} +13 -1
- package/dist/{new-ftd4fec4.js → new-8yah8z91.js} +5 -4
- package/dist/pdf-inspect-zdmy7qca.js +35 -0
- package/dist/{preflight-8sqarcsr.js → preflight-8ccx4kdc.js} +5 -4
- package/dist/{preview-q76xn95h.js → preview-w7v9w36q.js} +5 -4
- package/dist/{publish-7gdy6gbf.js → publish-g5nh5myh.js} +5 -4
- package/dist/schema/manifest.types.d.ts +20 -2
- package/dist/test-helpers/testkit.d.ts +2 -2
- package/dist/{validate-e3ryegce.js → validate-1yh59x0x.js} +5 -4
- package/package.json +1 -1
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getSystemDiagnostics,
|
|
3
3
|
log
|
|
4
|
-
} from "./cli-
|
|
4
|
+
} from "./cli-y9bcya7r.js";
|
|
5
5
|
import {
|
|
6
6
|
UsageError,
|
|
7
7
|
rejectExtraPositionals,
|
|
8
8
|
rejectUnknownFlags
|
|
9
|
-
} from "./cli-
|
|
9
|
+
} from "./cli-hn9pk0hp.js";
|
|
10
10
|
import"./cli-46ycxe6r.js";
|
|
11
11
|
import"./cli-asap4t1z.js";
|
|
12
12
|
import"./cli-37x76zdn.js";
|
|
@@ -12,20 +12,21 @@ import {
|
|
|
12
12
|
searchNpmExtensions,
|
|
13
13
|
setExtensionEnabled,
|
|
14
14
|
updateExtensions
|
|
15
|
-
} from "./cli-
|
|
16
|
-
import"./cli-
|
|
15
|
+
} from "./cli-9k2tb493.js";
|
|
16
|
+
import"./cli-y9bcya7r.js";
|
|
17
17
|
import {
|
|
18
18
|
UsageError,
|
|
19
19
|
exitForUsage,
|
|
20
20
|
rejectExtraPositionals,
|
|
21
21
|
rejectUnknownFlags,
|
|
22
22
|
resolveProjectDir
|
|
23
|
-
} from "./cli-
|
|
23
|
+
} from "./cli-hn9pk0hp.js";
|
|
24
24
|
import"./cli-ht1bcqdd.js";
|
|
25
|
-
import"./cli-
|
|
25
|
+
import"./cli-x4p99w8d.js";
|
|
26
26
|
import {
|
|
27
27
|
EXIT_CODES
|
|
28
28
|
} from "./cli-46ycxe6r.js";
|
|
29
|
+
import"./cli-sth219v1.js";
|
|
29
30
|
import"./cli-eyyggect.js";
|
|
30
31
|
import"./cli-asap4t1z.js";
|
|
31
32
|
import"./cli-5qr3z0qa.js";
|
|
@@ -1455,12 +1455,20 @@
|
|
|
1455
1455
|
return head;
|
|
1456
1456
|
}
|
|
1457
1457
|
var pushTargets = new WeakMap;
|
|
1458
|
+
function repeatingHead(table) {
|
|
1459
|
+
const head = table.tHead;
|
|
1460
|
+
return head && getComputedStyle(head).display === "table-header-group" ? head : null;
|
|
1461
|
+
}
|
|
1462
|
+
function repeatingFoot(table) {
|
|
1463
|
+
const foot = table.tFoot;
|
|
1464
|
+
return foot && getComputedStyle(foot).display === "table-footer-group" ? foot : null;
|
|
1465
|
+
}
|
|
1458
1466
|
function compensateRepeatedHeaders(strips, maxPasses = 24) {
|
|
1459
1467
|
const warnings = [];
|
|
1460
1468
|
let passes = 0;
|
|
1461
1469
|
let touched = 0;
|
|
1462
1470
|
for (const strip of strips) {
|
|
1463
|
-
const tables = Array.from(strip.el.querySelectorAll("table")).filter((t) => t
|
|
1471
|
+
const tables = Array.from(strip.el.querySelectorAll("table")).filter((t) => repeatingHead(t) || repeatingFoot(t));
|
|
1464
1472
|
if (!tables.length)
|
|
1465
1473
|
continue;
|
|
1466
1474
|
for (const table of tables) {
|
|
@@ -1485,9 +1493,9 @@
|
|
|
1485
1493
|
const colBottom = strip.el.clientHeight;
|
|
1486
1494
|
const plans = [];
|
|
1487
1495
|
for (const table of tables) {
|
|
1488
|
-
const head = table
|
|
1496
|
+
const head = repeatingHead(table);
|
|
1489
1497
|
const headRect = head?.getClientRects()[0];
|
|
1490
|
-
const footHeight = (table
|
|
1498
|
+
const footHeight = (repeatingFoot(table)?.getBoundingClientRect().height ?? 0) / zoom;
|
|
1491
1499
|
const rows = Array.from(table.querySelectorAll("tbody > tr")).filter((r) => !r.classList.contains("gp-thead-shim") && !r.classList.contains("gp-tfoot-shim"));
|
|
1492
1500
|
if (!rows.length)
|
|
1493
1501
|
continue;
|
|
@@ -1567,7 +1575,7 @@
|
|
|
1567
1575
|
td.colSpan = cell.colSpan;
|
|
1568
1576
|
td.innerHTML = cell.innerHTML;
|
|
1569
1577
|
const cs = getComputedStyle(cell);
|
|
1570
|
-
td.style.cssText = `font:${cs.font};text-align:${cs.textAlign};padding:${cs.padding};border:${cs.border};background:${cs.backgroundColor};`;
|
|
1578
|
+
td.style.cssText = `font:${cs.font};color:${cs.color};letter-spacing:${cs.letterSpacing};text-transform:${cs.textTransform};vertical-align:${cs.verticalAlign};text-align:${cs.textAlign};padding:${cs.padding};border:${cs.border};background:${cs.backgroundColor};`;
|
|
1571
1579
|
shim.appendChild(td);
|
|
1572
1580
|
}
|
|
1573
1581
|
} else {
|
|
@@ -0,0 +1,418 @@
|
|
|
1
|
+
// src/lib/pdf-inspect.ts
|
|
2
|
+
import { stat, readFile } from "node:fs/promises";
|
|
3
|
+
import { getDocumentProxy } from "unpdf";
|
|
4
|
+
import * as pdfjs from "unpdf/pdfjs";
|
|
5
|
+
function getOps(mod) {
|
|
6
|
+
if ("OPS" in mod && mod.OPS && typeof mod.OPS === "object") {
|
|
7
|
+
return mod.OPS;
|
|
8
|
+
}
|
|
9
|
+
throw new Error("unpdf/pdfjs missing OPS export");
|
|
10
|
+
}
|
|
11
|
+
var OPS = getOps(pdfjs);
|
|
12
|
+
var docCache = new Map;
|
|
13
|
+
var DOC_CACHE_MAX = 8;
|
|
14
|
+
function destroyEntry(entry) {
|
|
15
|
+
entry.doc.then((d) => d.destroy()).catch(() => {});
|
|
16
|
+
}
|
|
17
|
+
var EVICT_DESTROY_GRACE_MS = 60000;
|
|
18
|
+
var gracePending = new Map;
|
|
19
|
+
function destroyEntryAfterGrace(entry) {
|
|
20
|
+
const t = setTimeout(() => {
|
|
21
|
+
gracePending.delete(t);
|
|
22
|
+
destroyEntry(entry);
|
|
23
|
+
}, EVICT_DESTROY_GRACE_MS);
|
|
24
|
+
t.unref?.();
|
|
25
|
+
gracePending.set(t, entry);
|
|
26
|
+
}
|
|
27
|
+
function evictLru() {
|
|
28
|
+
while (docCache.size > DOC_CACHE_MAX) {
|
|
29
|
+
const oldestKey = docCache.keys().next().value;
|
|
30
|
+
if (oldestKey === undefined)
|
|
31
|
+
break;
|
|
32
|
+
const evicted = docCache.get(oldestKey);
|
|
33
|
+
docCache.delete(oldestKey);
|
|
34
|
+
if (evicted)
|
|
35
|
+
destroyEntryAfterGrace(evicted);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
async function loadPdf(path) {
|
|
39
|
+
let st;
|
|
40
|
+
try {
|
|
41
|
+
st = await stat(path);
|
|
42
|
+
} catch {
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
const hit = docCache.get(path);
|
|
46
|
+
if (hit && hit.mtimeMs === st.mtimeMs && hit.size === st.size) {
|
|
47
|
+
docCache.delete(path);
|
|
48
|
+
docCache.set(path, hit);
|
|
49
|
+
try {
|
|
50
|
+
return await hit.doc;
|
|
51
|
+
} catch {
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
if (hit)
|
|
56
|
+
destroyEntry(hit);
|
|
57
|
+
const docPromise = readFile(path).then((buf) => getDocumentProxy(new Uint8Array(buf)));
|
|
58
|
+
docCache.delete(path);
|
|
59
|
+
docCache.set(path, { mtimeMs: st.mtimeMs, size: st.size, doc: docPromise });
|
|
60
|
+
evictLru();
|
|
61
|
+
try {
|
|
62
|
+
return await docPromise;
|
|
63
|
+
} catch {
|
|
64
|
+
if (docCache.get(path)?.doc === docPromise)
|
|
65
|
+
docCache.delete(path);
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
var activeRetains = 0;
|
|
70
|
+
function retainPdfCache() {
|
|
71
|
+
activeRetains++;
|
|
72
|
+
let released = false;
|
|
73
|
+
return () => {
|
|
74
|
+
if (released)
|
|
75
|
+
return;
|
|
76
|
+
released = true;
|
|
77
|
+
activeRetains--;
|
|
78
|
+
if (activeRetains === 0)
|
|
79
|
+
clearPdfCache();
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
function clearPdfCache() {
|
|
83
|
+
for (const [t, entry] of gracePending) {
|
|
84
|
+
clearTimeout(t);
|
|
85
|
+
destroyEntry(entry);
|
|
86
|
+
}
|
|
87
|
+
gracePending.clear();
|
|
88
|
+
for (const entry of docCache.values())
|
|
89
|
+
destroyEntry(entry);
|
|
90
|
+
docCache.clear();
|
|
91
|
+
}
|
|
92
|
+
function pendingGraceDestroyCount() {
|
|
93
|
+
return gracePending.size;
|
|
94
|
+
}
|
|
95
|
+
function getPageSize(page) {
|
|
96
|
+
const vp = page.getViewport({ scale: 1 });
|
|
97
|
+
return { w: vp.width, h: vp.height };
|
|
98
|
+
}
|
|
99
|
+
async function getOutlineCount(doc) {
|
|
100
|
+
try {
|
|
101
|
+
const outline = await doc.getOutline();
|
|
102
|
+
return outline ? outline.length : 0;
|
|
103
|
+
} catch {
|
|
104
|
+
return 0;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
async function getPageLabels(doc) {
|
|
108
|
+
try {
|
|
109
|
+
return await doc.getPageLabels();
|
|
110
|
+
} catch {
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
async function countLinkAnnotations(doc, stopAtFirst = false) {
|
|
115
|
+
let count = 0;
|
|
116
|
+
for (let i = 1;i <= doc.numPages; i++) {
|
|
117
|
+
try {
|
|
118
|
+
const page = await doc.getPage(i);
|
|
119
|
+
const annots = await page.getAnnotations();
|
|
120
|
+
for (const a of annots) {
|
|
121
|
+
if (a.subtype === "Link") {
|
|
122
|
+
count++;
|
|
123
|
+
if (stopAtFirst)
|
|
124
|
+
return count;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
} catch {}
|
|
128
|
+
}
|
|
129
|
+
return count;
|
|
130
|
+
}
|
|
131
|
+
var textCache = new WeakMap;
|
|
132
|
+
function getTextPass(doc) {
|
|
133
|
+
let p = textCache.get(doc);
|
|
134
|
+
if (!p) {
|
|
135
|
+
p = (async () => {
|
|
136
|
+
const textByPage = [];
|
|
137
|
+
const positions = [];
|
|
138
|
+
const runsByPage = [];
|
|
139
|
+
for (let i = 1;i <= doc.numPages; i++) {
|
|
140
|
+
try {
|
|
141
|
+
const page = await doc.getPage(i);
|
|
142
|
+
const tc = await page.getTextContent();
|
|
143
|
+
let pageText = "";
|
|
144
|
+
const runs = [];
|
|
145
|
+
for (const item of tc.items) {
|
|
146
|
+
const it = item;
|
|
147
|
+
if (typeof it.str !== "string")
|
|
148
|
+
continue;
|
|
149
|
+
pageText += it.str;
|
|
150
|
+
if (it.transform && it.str.trim().length > 0) {
|
|
151
|
+
const x = it.transform[4];
|
|
152
|
+
const y = it.transform[5];
|
|
153
|
+
positions.push({ x, y });
|
|
154
|
+
runs.push({ s: it.str, x, y, w: it.width ?? 0, h: it.height ?? 0 });
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
textByPage.push(pageText);
|
|
158
|
+
runsByPage.push(runs);
|
|
159
|
+
} catch {
|
|
160
|
+
textByPage.push("");
|
|
161
|
+
runsByPage.push([]);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
return { textByPage, positions, runsByPage };
|
|
165
|
+
})();
|
|
166
|
+
textCache.set(doc, p);
|
|
167
|
+
}
|
|
168
|
+
return p;
|
|
169
|
+
}
|
|
170
|
+
var opCache = new WeakMap;
|
|
171
|
+
function multiply(m1, m2) {
|
|
172
|
+
return [
|
|
173
|
+
m1[0] * m2[0] + m1[2] * m2[1],
|
|
174
|
+
m1[1] * m2[0] + m1[3] * m2[1],
|
|
175
|
+
m1[0] * m2[2] + m1[2] * m2[3],
|
|
176
|
+
m1[1] * m2[2] + m1[3] * m2[3],
|
|
177
|
+
m1[0] * m2[4] + m1[2] * m2[5] + m1[4],
|
|
178
|
+
m1[1] * m2[4] + m1[3] * m2[5] + m1[5]
|
|
179
|
+
];
|
|
180
|
+
}
|
|
181
|
+
function fontIsEmbedded(f) {
|
|
182
|
+
if (f.isType3Font)
|
|
183
|
+
return true;
|
|
184
|
+
if (f.missingFile === true)
|
|
185
|
+
return false;
|
|
186
|
+
if (f.isStandardFont === true)
|
|
187
|
+
return false;
|
|
188
|
+
return true;
|
|
189
|
+
}
|
|
190
|
+
function getOpPass(doc) {
|
|
191
|
+
let p = opCache.get(doc);
|
|
192
|
+
if (!p) {
|
|
193
|
+
p = (async () => {
|
|
194
|
+
const imagesByPage = new Map;
|
|
195
|
+
const fonts = [];
|
|
196
|
+
const seenFonts = new Set;
|
|
197
|
+
for (let i = 1;i <= doc.numPages; i++) {
|
|
198
|
+
let page;
|
|
199
|
+
try {
|
|
200
|
+
page = await doc.getPage(i);
|
|
201
|
+
} catch {
|
|
202
|
+
continue;
|
|
203
|
+
}
|
|
204
|
+
let ops;
|
|
205
|
+
try {
|
|
206
|
+
ops = await page.getOperatorList();
|
|
207
|
+
} catch {
|
|
208
|
+
continue;
|
|
209
|
+
}
|
|
210
|
+
let ctm = [1, 0, 0, 1, 0, 0];
|
|
211
|
+
const stack = [];
|
|
212
|
+
const pageImages = [];
|
|
213
|
+
for (let j = 0;j < ops.fnArray.length; j++) {
|
|
214
|
+
const fn = ops.fnArray[j];
|
|
215
|
+
const args = ops.argsArray[j];
|
|
216
|
+
if (fn === OPS.save) {
|
|
217
|
+
stack.push(ctm.slice());
|
|
218
|
+
} else if (fn === OPS.restore) {
|
|
219
|
+
ctm = stack.pop() ?? ctm;
|
|
220
|
+
} else if (fn === OPS.transform) {
|
|
221
|
+
ctm = multiply(ctm, args);
|
|
222
|
+
} else if (fn === OPS.paintImageXObject || fn === OPS.paintImageXObjectRepeat || fn === OPS.paintInlineImageXObject) {
|
|
223
|
+
const name = typeof args[0] === "string" ? args[0] : "(inline)";
|
|
224
|
+
pageImages.push({
|
|
225
|
+
name,
|
|
226
|
+
placedW: Math.hypot(ctm[0], ctm[1]),
|
|
227
|
+
placedH: Math.hypot(ctm[2], ctm[3]),
|
|
228
|
+
x: ctm[4],
|
|
229
|
+
y: ctm[5],
|
|
230
|
+
page: i
|
|
231
|
+
});
|
|
232
|
+
} else if (fn === OPS.setFont) {
|
|
233
|
+
const ref = args[0];
|
|
234
|
+
if (typeof ref === "string" && !seenFonts.has(ref)) {
|
|
235
|
+
seenFonts.add(ref);
|
|
236
|
+
try {
|
|
237
|
+
if (page.commonObjs.has(ref)) {
|
|
238
|
+
const f = page.commonObjs.get(ref);
|
|
239
|
+
fonts.push({
|
|
240
|
+
name: f?.name ?? ref,
|
|
241
|
+
embedded: fontIsEmbedded(f ?? {})
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
} catch {}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
if (pageImages.length > 0)
|
|
249
|
+
imagesByPage.set(i, pageImages);
|
|
250
|
+
}
|
|
251
|
+
return { imagesByPage, fonts };
|
|
252
|
+
})();
|
|
253
|
+
opCache.set(doc, p);
|
|
254
|
+
}
|
|
255
|
+
return p;
|
|
256
|
+
}
|
|
257
|
+
var opSet = (names) => new Set(names.map((name) => OPS[name]).filter((op) => op !== undefined));
|
|
258
|
+
var FILL_COLOR_OPS = opSet(["setFillGray", "setFillRGBColor", "setFillCMYKColor", "setFillColor"]);
|
|
259
|
+
var STROKE_COLOR_OPS = opSet(["setStrokeGray", "setStrokeRGBColor", "setStrokeCMYKColor", "setStrokeColor"]);
|
|
260
|
+
var SHOW_TEXT_OPS = opSet(["showText", "showSpacedText", "nextLineShowText", "nextLineSetSpacingShowText"]);
|
|
261
|
+
async function unsplittableTextReasons(pdfBytes, pages) {
|
|
262
|
+
const GSTATE_BIT = { ca: 1, CA: 2, BM: 4, SMask: 8 };
|
|
263
|
+
const COMPOSITING = 15;
|
|
264
|
+
const FILL_PATTERN = 16;
|
|
265
|
+
const STROKE_PATTERN = 32;
|
|
266
|
+
const CLIP_TEXT = 64;
|
|
267
|
+
const doc = await getDocumentProxy(new Uint8Array(pdfBytes));
|
|
268
|
+
const reasons = new Map;
|
|
269
|
+
try {
|
|
270
|
+
const scan = pages ?? Array.from({ length: doc.numPages }, (_, i) => i + 1);
|
|
271
|
+
for (const i of scan) {
|
|
272
|
+
const page = await doc.getPage(i);
|
|
273
|
+
const ops = await page.getOperatorList();
|
|
274
|
+
let state = 0;
|
|
275
|
+
const groups = [];
|
|
276
|
+
const stack = [];
|
|
277
|
+
let showsText = false;
|
|
278
|
+
for (let j = 0;j < ops.fnArray.length; j++) {
|
|
279
|
+
const fn = ops.fnArray[j];
|
|
280
|
+
if (fn === OPS.save || fn === OPS.paintFormXObjectBegin)
|
|
281
|
+
stack.push(state);
|
|
282
|
+
else if (fn === OPS.restore || fn === OPS.paintFormXObjectEnd)
|
|
283
|
+
state = stack.pop() ?? 0;
|
|
284
|
+
else if (fn === OPS.beginGroup) {
|
|
285
|
+
const group = ops.argsArray[j][0];
|
|
286
|
+
groups.push((state & COMPOSITING) !== 0 || !!(group.smask || group.knockout));
|
|
287
|
+
} else if (fn === OPS.endGroup)
|
|
288
|
+
groups.pop();
|
|
289
|
+
else if (fn === OPS.setFont) {
|
|
290
|
+
const ref = ops.argsArray[j][0];
|
|
291
|
+
const font = typeof ref === "string" && page.commonObjs.has(ref) ? page.commonObjs.get(ref) : undefined;
|
|
292
|
+
if (font?.isType3Font) {
|
|
293
|
+
reasons.set(i, "type3-font");
|
|
294
|
+
break;
|
|
295
|
+
}
|
|
296
|
+
} else if (fn === OPS.setFillColorN || fn === OPS.setStrokeColorN) {
|
|
297
|
+
const bit = fn === OPS.setFillColorN ? FILL_PATTERN : STROKE_PATTERN;
|
|
298
|
+
const kind = ops.argsArray[j][0];
|
|
299
|
+
state = kind === "TilingPattern" || kind === "Shading" ? state | bit : state & ~bit;
|
|
300
|
+
} else if (FILL_COLOR_OPS.has(fn))
|
|
301
|
+
state &= ~FILL_PATTERN;
|
|
302
|
+
else if (STROKE_COLOR_OPS.has(fn))
|
|
303
|
+
state &= ~STROKE_PATTERN;
|
|
304
|
+
else if (fn === OPS.setTextRenderingMode) {
|
|
305
|
+
state = ops.argsArray[j][0] >= 4 ? state | CLIP_TEXT : state & ~CLIP_TEXT;
|
|
306
|
+
} else if (fn === OPS.setGState) {
|
|
307
|
+
for (const [key, value] of ops.argsArray[j][0]) {
|
|
308
|
+
const bit = GSTATE_BIT[key];
|
|
309
|
+
if (!bit)
|
|
310
|
+
continue;
|
|
311
|
+
const on = key === "BM" ? value !== "source-over" : key === "SMask" ? !!value : value < 1;
|
|
312
|
+
state = on ? state | bit : state & ~bit;
|
|
313
|
+
}
|
|
314
|
+
} else if (SHOW_TEXT_OPS.has(fn)) {
|
|
315
|
+
showsText = true;
|
|
316
|
+
if (state || groups.includes(true)) {
|
|
317
|
+
const paint = state & (FILL_PATTERN | STROKE_PATTERN | CLIP_TEXT);
|
|
318
|
+
reasons.set(i, paint ? "text-pattern-or-clip" : "text-transparency");
|
|
319
|
+
break;
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
if (!showsText && !reasons.has(i))
|
|
324
|
+
reasons.set(i, "no-text");
|
|
325
|
+
}
|
|
326
|
+
} finally {
|
|
327
|
+
await doc.destroy();
|
|
328
|
+
}
|
|
329
|
+
return reasons;
|
|
330
|
+
}
|
|
331
|
+
function getImagePixelSize(page, name, timeoutMs = 2000) {
|
|
332
|
+
return new Promise((resolve) => {
|
|
333
|
+
let done = false;
|
|
334
|
+
const finish = (v) => {
|
|
335
|
+
if (!done) {
|
|
336
|
+
done = true;
|
|
337
|
+
resolve(v);
|
|
338
|
+
}
|
|
339
|
+
};
|
|
340
|
+
const t = setTimeout(() => finish(null), timeoutMs);
|
|
341
|
+
try {
|
|
342
|
+
page.objs.get(name, (obj) => {
|
|
343
|
+
clearTimeout(t);
|
|
344
|
+
finish(obj && obj.width && obj.height ? { width: obj.width, height: obj.height } : null);
|
|
345
|
+
});
|
|
346
|
+
} catch {
|
|
347
|
+
clearTimeout(t);
|
|
348
|
+
finish(null);
|
|
349
|
+
}
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
var PAINT_OPS = new Set([
|
|
353
|
+
"stroke",
|
|
354
|
+
"closeStroke",
|
|
355
|
+
"fill",
|
|
356
|
+
"eoFill",
|
|
357
|
+
"fillStroke",
|
|
358
|
+
"eoFillStroke",
|
|
359
|
+
"closeFillStroke",
|
|
360
|
+
"closeEOFillStroke",
|
|
361
|
+
"shadingFill",
|
|
362
|
+
"paintImageXObject",
|
|
363
|
+
"paintInlineImageXObject",
|
|
364
|
+
"paintImageXObjectRepeat",
|
|
365
|
+
"paintImageMaskXObject",
|
|
366
|
+
"paintImageMaskXObjectGroup",
|
|
367
|
+
"paintImageMaskXObjectRepeat",
|
|
368
|
+
"paintSolidColorImageMask",
|
|
369
|
+
"showText",
|
|
370
|
+
"showSpacedText",
|
|
371
|
+
"nextLineShowText",
|
|
372
|
+
"nextLineSetSpacingShowText"
|
|
373
|
+
].map((name) => OPS[name]).filter((op) => op !== undefined));
|
|
374
|
+
async function pageHasMarks(doc, pageNum) {
|
|
375
|
+
const ops = await (await doc.getPage(pageNum)).getOperatorList();
|
|
376
|
+
return ops.fnArray.some((fn, i) => fn === OPS.constructPath ? PAINT_OPS.has(ops.argsArray[i][0]) : PAINT_OPS.has(fn));
|
|
377
|
+
}
|
|
378
|
+
async function getImageResolutions(doc) {
|
|
379
|
+
const { imagesByPage } = await getOpPass(doc);
|
|
380
|
+
const out = [];
|
|
381
|
+
for (const [pageNum, imgs] of imagesByPage) {
|
|
382
|
+
let page;
|
|
383
|
+
try {
|
|
384
|
+
page = await doc.getPage(pageNum);
|
|
385
|
+
} catch {
|
|
386
|
+
continue;
|
|
387
|
+
}
|
|
388
|
+
for (const img of imgs) {
|
|
389
|
+
if (img.name === "(inline)")
|
|
390
|
+
continue;
|
|
391
|
+
const px = await getImagePixelSize(page, img.name);
|
|
392
|
+
if (!px)
|
|
393
|
+
continue;
|
|
394
|
+
const placedWin = img.placedW / 72;
|
|
395
|
+
const placedHin = img.placedH / 72;
|
|
396
|
+
if (placedWin <= 0 || placedHin <= 0)
|
|
397
|
+
continue;
|
|
398
|
+
out.push({
|
|
399
|
+
page: pageNum,
|
|
400
|
+
xDpi: px.width / placedWin,
|
|
401
|
+
yDpi: px.height / placedHin
|
|
402
|
+
});
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
return out;
|
|
406
|
+
}
|
|
407
|
+
async function isLoadable(doc) {
|
|
408
|
+
try {
|
|
409
|
+
for (let i = 1;i <= doc.numPages; i++) {
|
|
410
|
+
await doc.getPage(i);
|
|
411
|
+
}
|
|
412
|
+
return true;
|
|
413
|
+
} catch {
|
|
414
|
+
return false;
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
export { DOC_CACHE_MAX, loadPdf, retainPdfCache, clearPdfCache, pendingGraceDestroyCount, getPageSize, getOutlineCount, getPageLabels, countLinkAnnotations, getTextPass, getOpPass, unsplittableTextReasons, pageHasMarks, getImageResolutions, isLoadable };
|