@reportwright/pdf 0.1.0-beta.8 → 0.1.0-beta.9
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 +7 -0
- package/dist/index.js +114 -13
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1133,6 +1133,13 @@ bidi algorithm, hyphenation, kerning of the standard fonts, WOFF fonts; popup an
|
|
|
1133
1133
|
|
|
1134
1134
|
## Changes
|
|
1135
1135
|
|
|
1136
|
+
0.1.0-beta.9: stamping every page (`page.draw` then `save()`) is about 35% faster on a 1,000-page file: a page's open
|
|
1137
|
+
graphics states are counted with a byte scan instead of a full parse, and FlateDecode inflates whole, valid zlib
|
|
1138
|
+
streams with Node's zlib (damaged, truncated, raw or over-budget streams still go through fflate as before); the output
|
|
1139
|
+
is byte-identical. `bulk` starts an item's `itemTimeoutMs` clock when its worker is ready, so a respawned worker's
|
|
1140
|
+
start-up no longer fails good files; a stopped export (`timeoutMs` or `signal`) aborts its WritableStream even when
|
|
1141
|
+
the stop lands between two calls.
|
|
1142
|
+
|
|
1136
1143
|
0.1.0-beta.2: a left-to-right shaped cluster in an ActualText span has its text only in the ActualText, so MuPDF
|
|
1137
1144
|
no longer reads it twice (pdf.js, which ignores ActualText, now misses those clusters; poppler, PDFium and
|
|
1138
1145
|
`extractText` read them); `extractText` drops WJ (U+2060) and reads a code a ToUnicode skips as nothing (U+FFFD
|
package/dist/index.js
CHANGED
|
@@ -12059,9 +12059,9 @@ function encryptor(opt, doc) {
|
|
|
12059
12059
|
const v = iv();
|
|
12060
12060
|
return sealSync(k, v, b) ?? aesCbc(k, v, b).then((c) => concat([v, c]));
|
|
12061
12061
|
};
|
|
12062
|
-
let
|
|
12062
|
+
let ready2 = false;
|
|
12063
12063
|
setup.then(() => {
|
|
12064
|
-
|
|
12064
|
+
ready2 = true;
|
|
12065
12065
|
}, () => {
|
|
12066
12066
|
});
|
|
12067
12067
|
const LIT = (x) => {
|
|
@@ -12105,12 +12105,12 @@ function encryptor(opt, doc) {
|
|
|
12105
12105
|
dict(n, d) {
|
|
12106
12106
|
if (n === self.ref) return d;
|
|
12107
12107
|
if (!meta && /^<< \/Type \/Metadata\b/.test(d) && !d.includes("/Filter")) return d.replace(/>>\s*$/, "/Filter /Crypt /DecodeParms << /Name /Identity >> >>");
|
|
12108
|
-
return
|
|
12108
|
+
return ready2 ? dictNow(n, d) : setup.then(() => dictNow(n, d));
|
|
12109
12109
|
},
|
|
12110
12110
|
/** @param {number} n @param {Uint8Array} b @param {string} d */
|
|
12111
12111
|
stream(n, b, d) {
|
|
12112
12112
|
if (!meta && /\/Type\s*\/Metadata\b/.test(d)) return b;
|
|
12113
|
-
return
|
|
12113
|
+
return ready2 ? seal(keyOf2(n), b) : setup.then(() => seal(keyOf2(n), b));
|
|
12114
12114
|
}
|
|
12115
12115
|
};
|
|
12116
12116
|
return self;
|
|
@@ -12920,9 +12920,9 @@ function sinkOf(budget) {
|
|
|
12920
12920
|
};
|
|
12921
12921
|
}
|
|
12922
12922
|
function flate(data, budget) {
|
|
12923
|
-
const run2 = (
|
|
12923
|
+
const run2 = (Z2) => {
|
|
12924
12924
|
const s = sinkOf(budget);
|
|
12925
|
-
const z = new
|
|
12925
|
+
const z = new Z2((c) => s.push(c));
|
|
12926
12926
|
let ok = true;
|
|
12927
12927
|
try {
|
|
12928
12928
|
for (let at = 0; at < data.length; at += CHUNK2) z.push(data.subarray(at, Math.min(data.length, at + CHUNK2)), at + CHUNK2 >= data.length);
|
|
@@ -12936,6 +12936,18 @@ function flate(data, budget) {
|
|
|
12936
12936
|
}
|
|
12937
12937
|
return { out: s.out(), ok, n: s.n };
|
|
12938
12938
|
};
|
|
12939
|
+
const Z = builtin("node:zlib");
|
|
12940
|
+
if (Z && data.length) {
|
|
12941
|
+
let out = null;
|
|
12942
|
+
try {
|
|
12943
|
+
out = Z.inflateSync(data, { maxOutputLength: Math.max(1, Math.min(2 ** 30, budget.maxStream, budget.maxDecoded - budget.decoded)) });
|
|
12944
|
+
} catch {
|
|
12945
|
+
}
|
|
12946
|
+
if (out) {
|
|
12947
|
+
budget.take(out.length, 0);
|
|
12948
|
+
return new Uint8Array(out.buffer, out.byteOffset, out.length);
|
|
12949
|
+
}
|
|
12950
|
+
}
|
|
12939
12951
|
const F2 = fflateNow();
|
|
12940
12952
|
if (!F2) throw new Error("internal: FlateDecode before fflate was loaded");
|
|
12941
12953
|
const r = run2(F2.Unzlib);
|
|
@@ -15843,6 +15855,7 @@ var init_fill = __esm({
|
|
|
15843
15855
|
var save_exports = {};
|
|
15844
15856
|
__export(save_exports, {
|
|
15845
15857
|
MAX_OPEN: () => MAX_OPEN,
|
|
15858
|
+
countSaves: () => countSaves,
|
|
15846
15859
|
openSaves: () => openSaves,
|
|
15847
15860
|
save: () => save2,
|
|
15848
15861
|
saveTo: () => saveTo
|
|
@@ -15852,7 +15865,10 @@ function openSaves(data, budget) {
|
|
|
15852
15865
|
let depth2 = 0;
|
|
15853
15866
|
for (; ; ) {
|
|
15854
15867
|
const v = parseValue(lx);
|
|
15855
|
-
if (v === void 0)
|
|
15868
|
+
if (v === void 0) {
|
|
15869
|
+
if (lx.pos < data.length) continue;
|
|
15870
|
+
break;
|
|
15871
|
+
}
|
|
15856
15872
|
if (!(v instanceof Op)) continue;
|
|
15857
15873
|
if (v.v === "q") depth2++;
|
|
15858
15874
|
else if (v.v === "Q") depth2 = Math.max(0, depth2 - 1);
|
|
@@ -15867,6 +15883,80 @@ function openSaves(data, budget) {
|
|
|
15867
15883
|
}
|
|
15868
15884
|
return depth2;
|
|
15869
15885
|
}
|
|
15886
|
+
function countSaves(b, budget) {
|
|
15887
|
+
const e = b.length;
|
|
15888
|
+
if (e >= 4e6) return openSaves(b, budget);
|
|
15889
|
+
const st = [];
|
|
15890
|
+
let depth2 = 0, i = 0;
|
|
15891
|
+
for (; ; ) {
|
|
15892
|
+
for (; ; ) {
|
|
15893
|
+
while (i < e && CLASS[b[i]] === 1) i++;
|
|
15894
|
+
if (i < e && b[i] === 37) {
|
|
15895
|
+
while (i < e && b[i] !== 10 && b[i] !== 13) i++;
|
|
15896
|
+
continue;
|
|
15897
|
+
}
|
|
15898
|
+
break;
|
|
15899
|
+
}
|
|
15900
|
+
if (i >= e) return depth2;
|
|
15901
|
+
budget.tick();
|
|
15902
|
+
const c = b[i];
|
|
15903
|
+
if (c === 91 || c === 60 && b[i + 1] === 60) {
|
|
15904
|
+
if (st.length >= MAX_DEPTH4) return openSaves(b, budget);
|
|
15905
|
+
st.push(c === 91 ? 1 : 2);
|
|
15906
|
+
i += c === 91 ? 1 : 2;
|
|
15907
|
+
continue;
|
|
15908
|
+
}
|
|
15909
|
+
if (c === 93 || c === 62) {
|
|
15910
|
+
if (!st.length) {
|
|
15911
|
+
i += c === 62 && b[i + 1] === 62 ? 2 : 1;
|
|
15912
|
+
continue;
|
|
15913
|
+
}
|
|
15914
|
+
if (st[st.length - 1] === (c === 93 ? 1 : 2)) st.pop();
|
|
15915
|
+
i += c === 62 && b[i + 1] === 62 ? 2 : 1;
|
|
15916
|
+
continue;
|
|
15917
|
+
}
|
|
15918
|
+
if (c === 60) {
|
|
15919
|
+
const s2 = i;
|
|
15920
|
+
i++;
|
|
15921
|
+
while (i < e && b[i] !== 62) i++;
|
|
15922
|
+
if (i < e) i++;
|
|
15923
|
+
budget.tick(1 + (i - s2 >> 11));
|
|
15924
|
+
continue;
|
|
15925
|
+
}
|
|
15926
|
+
if (c === 40) {
|
|
15927
|
+
const s2 = i;
|
|
15928
|
+
i++;
|
|
15929
|
+
for (let d = 1; i < e; i++) {
|
|
15930
|
+
const x = b[i];
|
|
15931
|
+
if (x === 92) i++;
|
|
15932
|
+
else if (x === 40) d++;
|
|
15933
|
+
else if (x === 41 && --d === 0) break;
|
|
15934
|
+
}
|
|
15935
|
+
i = Math.min(i + 1, e);
|
|
15936
|
+
budget.tick(1 + (i - s2 >> 10));
|
|
15937
|
+
continue;
|
|
15938
|
+
}
|
|
15939
|
+
if (c === 47) {
|
|
15940
|
+
i++;
|
|
15941
|
+
while (i < e && CLASS[b[i]] === 0) i++;
|
|
15942
|
+
continue;
|
|
15943
|
+
}
|
|
15944
|
+
if (CLASS[c] === 2) {
|
|
15945
|
+
i++;
|
|
15946
|
+
continue;
|
|
15947
|
+
}
|
|
15948
|
+
const s = i;
|
|
15949
|
+
while (i < e && CLASS[b[i]] === 0) i++;
|
|
15950
|
+
if (c >= 48 && c <= 57 || c === 43 || c === 45 || c === 46) continue;
|
|
15951
|
+
const w = i - s > 5 ? "" : latin12(b.subarray(s, i));
|
|
15952
|
+
if (w === "true" || w === "false" || w === "null") continue;
|
|
15953
|
+
if (w === "R" && st.length) return openSaves(b, budget);
|
|
15954
|
+
if (w === "BI") return openSaves(b, budget);
|
|
15955
|
+
st.length = 0;
|
|
15956
|
+
if (w === "q") depth2++;
|
|
15957
|
+
else if (w === "Q") depth2 = Math.max(0, depth2 - 1);
|
|
15958
|
+
}
|
|
15959
|
+
}
|
|
15870
15960
|
function options(self, o = {}) {
|
|
15871
15961
|
if (o == null || typeof o !== "object") throw new TypeError(`save: options are { ${KEYS2.join(", ")} }`);
|
|
15872
15962
|
for (const k of Object.keys(o)) if (!KEYS2.includes(k)) throw new TypeError(`save: unknown option ${JSON.stringify(k.slice(0, 40))} (${KEYS2.join(", ")})`);
|
|
@@ -15999,7 +16089,7 @@ async function run(self, sink, o) {
|
|
|
15999
16089
|
});
|
|
16000
16090
|
const qRef = { n: 0 };
|
|
16001
16091
|
const made = /* @__PURE__ */ new Map();
|
|
16002
|
-
const
|
|
16092
|
+
const ready2 = async (v, kind) => {
|
|
16003
16093
|
let h = made.get(v);
|
|
16004
16094
|
if (!h) {
|
|
16005
16095
|
h = kind === "image" ? await pdf.embedImage(v) : typeof v === "string" ? pdf.standardFont(v) : await pdf.embedFont(v);
|
|
@@ -16038,8 +16128,8 @@ async function run(self, sink, o) {
|
|
|
16038
16128
|
const xobjs = [];
|
|
16039
16129
|
for (const dr of p.draws) {
|
|
16040
16130
|
const fonts = {}, images = {};
|
|
16041
|
-
for (const [n2, v] of Object.entries(dr.fonts)) fonts[n2] = await
|
|
16042
|
-
for (const [n2, v] of Object.entries(dr.images)) images[n2] = await
|
|
16131
|
+
for (const [n2, v] of Object.entries(dr.fonts)) fonts[n2] = await ready2(v, "font");
|
|
16132
|
+
for (const [n2, v] of Object.entries(dr.images)) images[n2] = await ready2(v, "image");
|
|
16043
16133
|
xobjs.push({ ref: appearance(page, W, H, (ap) => dr.fn(ap, { fonts, images, pdf })), m: `1 0 0 1 ${numText(b.mediaBox[0])} ${numText(b.mediaBox[1])}` });
|
|
16044
16134
|
}
|
|
16045
16135
|
const list = OR(d.get("Annots"));
|
|
@@ -16080,7 +16170,7 @@ async function run(self, sink, o) {
|
|
|
16080
16170
|
}
|
|
16081
16171
|
if (xobjs.length) {
|
|
16082
16172
|
const res2 = OR(pg.inh.Resources), xo = res2 instanceof Map ? OR(res2.get("XObject")) : null;
|
|
16083
|
-
const open =
|
|
16173
|
+
const open = countSaves(contentBytes(src, d.get("Contents")), src.budget);
|
|
16084
16174
|
if (open > MAX_OPEN) throw new PdfReadError("E_MALFORMED", `Page ${k + 1} leaves ${open > 1e6 ? "over a million" : open} graphics states open (more than ${MAX_OPEN}): it cannot be drawn on or flattened safely`);
|
|
16085
16175
|
let tail = "Q\n".repeat(1 + open), i = 0;
|
|
16086
16176
|
for (const x of xobjs) {
|
|
@@ -17660,7 +17750,7 @@ async function bulk(inputs, task, o = {}) {
|
|
|
17660
17750
|
);
|
|
17661
17751
|
const arm = () => {
|
|
17662
17752
|
clearTimeout(timer);
|
|
17663
|
-
timer = flight.length ? setTimeout(() => dead({ name: "Error", code: "E_TIMEOUT", message: `the item took longer than itemTimeoutMs (${itemTimeoutMs} ms)` }), itemTimeoutMs) : null;
|
|
17753
|
+
timer = flight.length && ready.has(worker) ? setTimeout(() => dead({ name: "Error", code: "E_TIMEOUT", message: `the item took longer than itemTimeoutMs (${itemTimeoutMs} ms)` }), itemTimeoutMs) : null;
|
|
17664
17754
|
};
|
|
17665
17755
|
const fill2 = () => {
|
|
17666
17756
|
while (queue.length && (!flight.length || flight.length < DEPTH && bytes < BATCH_BYTES)) {
|
|
@@ -17681,6 +17771,11 @@ async function bulk(inputs, task, o = {}) {
|
|
|
17681
17771
|
}
|
|
17682
17772
|
};
|
|
17683
17773
|
const onMessage = (m) => {
|
|
17774
|
+
if (m?.ready === true && !("id" in m)) {
|
|
17775
|
+
ready.add(worker);
|
|
17776
|
+
arm();
|
|
17777
|
+
return;
|
|
17778
|
+
}
|
|
17684
17779
|
flight = flight.filter((i) => i !== m.id);
|
|
17685
17780
|
bytes -= sizeOf(list[m.id]);
|
|
17686
17781
|
const { id, ...r } = m;
|
|
@@ -17760,8 +17855,9 @@ function __bulkWorker() {
|
|
|
17760
17855
|
}
|
|
17761
17856
|
});
|
|
17762
17857
|
});
|
|
17858
|
+
parentPort.postMessage({ ready: true });
|
|
17763
17859
|
}
|
|
17764
|
-
var TASKS, BULK_TASKS, load, errorOf, DEPTH, BATCH_BYTES, MAX_WORKERS, IDLE_MS, idle, sizeOf;
|
|
17860
|
+
var TASKS, BULK_TASKS, load, errorOf, DEPTH, BATCH_BYTES, MAX_WORKERS, IDLE_MS, idle, ready, sizeOf;
|
|
17765
17861
|
var init_bulk = __esm({
|
|
17766
17862
|
"src/bulk.js"() {
|
|
17767
17863
|
init_pdf();
|
|
@@ -17796,6 +17892,7 @@ var init_bulk = __esm({
|
|
|
17796
17892
|
MAX_WORKERS = 64;
|
|
17797
17893
|
IDLE_MS = 2e3;
|
|
17798
17894
|
idle = /* @__PURE__ */ new Map();
|
|
17895
|
+
ready = /* @__PURE__ */ new WeakSet();
|
|
17799
17896
|
sizeOf = (input) => Array.isArray(input) ? input.reduce((n, b) => n + (b?.byteLength || 0), 0) : input?.byteLength || 0;
|
|
17800
17897
|
}
|
|
17801
17898
|
});
|
|
@@ -17880,6 +17977,10 @@ function createPdf(sink, options2 = {}) {
|
|
|
17880
17977
|
});
|
|
17881
17978
|
let ended = false;
|
|
17882
17979
|
const live = () => {
|
|
17980
|
+
if (ctl.signal.aborted) {
|
|
17981
|
+
cleanup();
|
|
17982
|
+
out.abort(ctl.signal.reason);
|
|
17983
|
+
}
|
|
17883
17984
|
ctl.signal.throwIfAborted();
|
|
17884
17985
|
if (doc.failed) throw doc.failed;
|
|
17885
17986
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@reportwright/pdf",
|
|
3
|
-
"version": "0.1.0-beta.
|
|
3
|
+
"version": "0.1.0-beta.9",
|
|
4
4
|
"description": "A streaming PDF writer for Node and browsers with no runtime dependencies: flat memory, PDF/A-1b to 3a, PDF/UA-1, Factur-X, embedded TrueType with Unicode text.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|