reamkit 1.26.0 → 1.27.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 +9 -4
- package/dist/esm/pdf-reader/annot-draw.d.ts +65 -0
- package/dist/esm/pdf-reader/annot-draw.js +374 -0
- package/dist/esm/pdf-reader/annots.d.ts +3 -1
- package/dist/esm/pdf-reader/annots.js +18 -4
- package/dist/esm/pdf-reader/ccitt.d.ts +18 -0
- package/dist/esm/pdf-reader/ccitt.js +70 -2
- package/dist/esm/pdf-reader/cie-color.d.ts +33 -0
- package/dist/esm/pdf-reader/cie-color.js +112 -0
- package/dist/esm/pdf-reader/content.d.ts +47 -3
- package/dist/esm/pdf-reader/content.js +108 -13
- package/dist/esm/pdf-reader/display.d.ts +1 -1
- package/dist/esm/pdf-reader/display.js +21 -6
- package/dist/esm/pdf-reader/document.d.ts +6 -0
- package/dist/esm/pdf-reader/document.js +29 -1
- package/dist/esm/pdf-reader/embedded-fonts.d.ts +12 -3
- package/dist/esm/pdf-reader/embedded-fonts.js +22 -3
- package/dist/esm/pdf-reader/flow-build.d.ts +12 -4
- package/dist/esm/pdf-reader/flow-build.js +102 -8
- package/dist/esm/pdf-reader/font.js +77 -16
- package/dist/esm/pdf-reader/function.d.ts +16 -0
- package/dist/esm/pdf-reader/function.js +414 -0
- package/dist/esm/pdf-reader/image-decode.d.ts +8 -4
- package/dist/esm/pdf-reader/image-decode.js +192 -11
- package/dist/esm/pdf-reader/images.d.ts +12 -0
- package/dist/esm/pdf-reader/images.js +109 -9
- package/dist/esm/pdf-reader/jbig2.d.ts +23 -0
- package/dist/esm/pdf-reader/jbig2.js +23 -14
- package/dist/esm/pdf-reader/layout.d.ts +32 -0
- package/dist/esm/pdf-reader/layout.js +189 -40
- package/dist/esm/pdf-reader/lexer.d.ts +2 -0
- package/dist/esm/pdf-reader/lexer.js +4 -0
- package/dist/esm/pdf-reader/optional-content.d.ts +36 -0
- package/dist/esm/pdf-reader/optional-content.js +93 -0
- package/dist/esm/pdf-reader/reader.d.ts +5 -2
- package/dist/esm/pdf-reader/reader.js +80 -7
- package/dist/esm/pdf-reader/shading.d.ts +60 -8
- package/dist/esm/pdf-reader/shading.js +124 -20
- package/dist/esm/pdf-reader/standard-metrics.d.ts +8 -0
- package/dist/esm/pdf-reader/standard-metrics.js +18 -0
- package/dist/esm/pdf-reader/standard-widths.d.ts +20 -0
- package/dist/esm/pdf-reader/standard-widths.js +62 -0
- package/dist/esm/pdf-reader/tagged.js +204 -32
- package/dist/esm/pdf-reader/text-rules.d.ts +16 -0
- package/dist/esm/pdf-reader/text-rules.js +112 -0
- package/dist/esm/pdf-reader/text.js +78 -4
- package/dist/esm/pdf-reader/vector.d.ts +5 -0
- package/dist/esm/pdf-reader/vector.js +39 -26
- package/dist/esm/word/docx-writer.js +73 -11
- package/package.json +1 -1
|
@@ -0,0 +1,414 @@
|
|
|
1
|
+
import { PDF_NULL, PdfStream } from "../pdf/objects.js";
|
|
2
|
+
import { Lexer } from "./lexer.js";
|
|
3
|
+
//#region src/pdf-reader/function.ts
|
|
4
|
+
/** A sampled function bigger than this is not read: it is a DoS, not a table. */
|
|
5
|
+
var MAX_SAMPLES = 1 << 22;
|
|
6
|
+
/** A type-4 program deeper than this is not run. */
|
|
7
|
+
var MAX_PS_DEPTH = 32;
|
|
8
|
+
/** …nor one with more tokens than this. */
|
|
9
|
+
var MAX_PS_TOKENS = 65536;
|
|
10
|
+
/** How far a stitching or array function may nest before this gives up. */
|
|
11
|
+
var MAX_NESTING = 8;
|
|
12
|
+
/**
|
|
13
|
+
* Read a `/Function` entry into something callable (§7.10).
|
|
14
|
+
*
|
|
15
|
+
* The entry may also be an ARRAY of functions, each giving one output, which is
|
|
16
|
+
* what a `/DeviceN` with a per-colorant transform states; that comes back as
|
|
17
|
+
* one function returning all of them in order.
|
|
18
|
+
*
|
|
19
|
+
* @param file The owning file.
|
|
20
|
+
* @param value The `/Function` (or `/TintTransform`) entry, unresolved.
|
|
21
|
+
* @returns The function, or `undefined` for one this cannot run.
|
|
22
|
+
*/
|
|
23
|
+
function readFunction(file, value) {
|
|
24
|
+
return readAt(file, value, 0);
|
|
25
|
+
}
|
|
26
|
+
function readAt(file, value, depth) {
|
|
27
|
+
if (value === void 0 || depth > MAX_NESTING) return void 0;
|
|
28
|
+
const resolved = file.resolve(value);
|
|
29
|
+
if (Array.isArray(resolved)) {
|
|
30
|
+
const parts = resolved.map((v) => readAt(file, v, depth + 1));
|
|
31
|
+
if (parts.some((p) => p === void 0)) return void 0;
|
|
32
|
+
return (inputs) => parts.flatMap((p) => p(inputs));
|
|
33
|
+
}
|
|
34
|
+
const dict = resolved instanceof PdfStream ? resolved.dict : resolved instanceof Map ? resolved : void 0;
|
|
35
|
+
if (!dict) return void 0;
|
|
36
|
+
const type = file.get(dict, "FunctionType");
|
|
37
|
+
const domain = numbers(file, dict.get("Domain"));
|
|
38
|
+
if (type === 2) return exponential(file, dict, domain);
|
|
39
|
+
if (type === 3) return stitching(file, dict, domain, depth);
|
|
40
|
+
if (type === 0 && resolved instanceof PdfStream) return sampled(file, resolved, domain);
|
|
41
|
+
if (type === 4 && resolved instanceof PdfStream) return calculator(file, resolved, domain);
|
|
42
|
+
}
|
|
43
|
+
/** §7.10.2 — a sampled function: a table, interpolated between its samples. */
|
|
44
|
+
function sampled(file, stream, domain) {
|
|
45
|
+
const d = stream.dict;
|
|
46
|
+
const size = numbers(file, d.get("Size"));
|
|
47
|
+
const range = numbers(file, d.get("Range"));
|
|
48
|
+
const bps = file.get(d, "BitsPerSample");
|
|
49
|
+
const m = size.length;
|
|
50
|
+
const n = range.length >> 1;
|
|
51
|
+
if (m === 0 || n === 0 || domain.length < m * 2 || typeof bps !== "number") return void 0;
|
|
52
|
+
if (!size.every((s) => Number.isInteger(s) && s >= 1)) return void 0;
|
|
53
|
+
let total = n;
|
|
54
|
+
for (const s of size) {
|
|
55
|
+
total *= s;
|
|
56
|
+
if (total > MAX_SAMPLES) return void 0;
|
|
57
|
+
}
|
|
58
|
+
const encode = orDefault(numbers(file, d.get("Encode")), m * 2, (i) => i % 2 === 0 ? 0 : size[i - 1 >> 1] - 1);
|
|
59
|
+
const decode = orDefault(numbers(file, d.get("Decode")), n * 2, (i) => range[i] ?? 0);
|
|
60
|
+
const data = file.streamData(stream);
|
|
61
|
+
const max = 2 ** bps - 1;
|
|
62
|
+
const sample = (flat, out) => {
|
|
63
|
+
let bit = (flat * n + out) * bps;
|
|
64
|
+
let v = 0;
|
|
65
|
+
for (let k = 0; k < bps; k++) {
|
|
66
|
+
v = v * 2 + ((data[bit >> 3] ?? 0) >> 7 - (bit & 7) & 1);
|
|
67
|
+
bit++;
|
|
68
|
+
}
|
|
69
|
+
return v / max;
|
|
70
|
+
};
|
|
71
|
+
return (inputs) => {
|
|
72
|
+
const base = [];
|
|
73
|
+
const frac = [];
|
|
74
|
+
for (let i = 0; i < m; i++) {
|
|
75
|
+
const at = clamp(interpolate(clamp(inputs[i] ?? 0, domain[i * 2], domain[i * 2 + 1]), domain[i * 2], domain[i * 2 + 1], encode[i * 2], encode[i * 2 + 1]), 0, size[i] - 1);
|
|
76
|
+
const lo = Math.min(Math.floor(at), Math.max(0, size[i] - 2));
|
|
77
|
+
base.push(size[i] === 1 ? 0 : lo);
|
|
78
|
+
frac.push(size[i] === 1 ? 0 : at - lo);
|
|
79
|
+
}
|
|
80
|
+
const out = new Array(n).fill(0);
|
|
81
|
+
for (let corner = 0; corner < 1 << m; corner++) {
|
|
82
|
+
let weight = 1;
|
|
83
|
+
let flat = 0;
|
|
84
|
+
let stride = 1;
|
|
85
|
+
for (let i = 0; i < m; i++) {
|
|
86
|
+
const up = corner >> i & 1;
|
|
87
|
+
weight *= up ? frac[i] : 1 - frac[i];
|
|
88
|
+
flat += Math.min(base[i] + up, size[i] - 1) * stride;
|
|
89
|
+
stride *= size[i];
|
|
90
|
+
}
|
|
91
|
+
if (weight === 0) continue;
|
|
92
|
+
for (let j = 0; j < n; j++) out[j] = (out[j] ?? 0) + weight * sample(flat, j);
|
|
93
|
+
}
|
|
94
|
+
return out.map((v, j) => clamp(interpolate(v, 0, 1, decode[j * 2], decode[j * 2 + 1]), Math.min(range[j * 2], range[j * 2 + 1]), Math.max(range[j * 2], range[j * 2 + 1])));
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
/** §7.10.3 — an exponential interpolation between two colours. */
|
|
98
|
+
function exponential(file, dict, domain) {
|
|
99
|
+
if (domain.length < 2) return void 0;
|
|
100
|
+
const c0 = numbers(file, dict.get("C0"));
|
|
101
|
+
const c1 = numbers(file, dict.get("C1"));
|
|
102
|
+
const nExp = file.get(dict, "N");
|
|
103
|
+
if (typeof nExp !== "number") return void 0;
|
|
104
|
+
const from = c0.length > 0 ? c0 : [0];
|
|
105
|
+
const to = c1.length > 0 ? c1 : [1];
|
|
106
|
+
const n = Math.max(from.length, to.length);
|
|
107
|
+
return (inputs) => {
|
|
108
|
+
const x = clamp(inputs[0] ?? 0, domain[0], domain[1]);
|
|
109
|
+
const t = nExp === 1 ? x : Math.max(0, x) ** nExp;
|
|
110
|
+
const out = [];
|
|
111
|
+
for (let i = 0; i < n; i++) out.push((from[i] ?? 0) + t * ((to[i] ?? 0) - (from[i] ?? 0)));
|
|
112
|
+
return out;
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
/** §7.10.4 — k functions laid end to end along one input. */
|
|
116
|
+
function stitching(file, dict, domain, depth) {
|
|
117
|
+
if (domain.length < 2) return void 0;
|
|
118
|
+
const list = file.resolve(dict.get("Functions") ?? PDF_NULL);
|
|
119
|
+
if (!Array.isArray(list) || list.length === 0) return void 0;
|
|
120
|
+
const parts = list.map((v) => readAt(file, v, depth + 1));
|
|
121
|
+
if (parts.some((p) => p === void 0)) return void 0;
|
|
122
|
+
const bounds = numbers(file, dict.get("Bounds"));
|
|
123
|
+
const encode = orDefault(numbers(file, dict.get("Encode")), parts.length * 2, (i) => i % 2);
|
|
124
|
+
const d0 = domain[0];
|
|
125
|
+
const d1 = domain[1];
|
|
126
|
+
return (inputs) => {
|
|
127
|
+
const x = clamp(inputs[0] ?? 0, d0, d1);
|
|
128
|
+
let k = 0;
|
|
129
|
+
while (k < bounds.length && x >= bounds[k]) k++;
|
|
130
|
+
k = Math.min(k, parts.length - 1);
|
|
131
|
+
const lo = k === 0 ? d0 : bounds[k - 1];
|
|
132
|
+
const hi = k === bounds.length ? d1 : bounds[k];
|
|
133
|
+
return parts[k]([interpolate(x, lo, hi, encode[k * 2], encode[k * 2 + 1])]);
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
/** §7.10.5 — a PostScript calculator: a program in braces, run on a stack. */
|
|
137
|
+
function calculator(file, stream, domain) {
|
|
138
|
+
const range = numbers(file, stream.dict.get("Range"));
|
|
139
|
+
const program = parseProgram(file.streamData(stream));
|
|
140
|
+
if (!program || range.length < 2) return void 0;
|
|
141
|
+
const n = range.length >> 1;
|
|
142
|
+
return (inputs) => {
|
|
143
|
+
const stack = [];
|
|
144
|
+
for (let i = 0; i * 2 + 1 < domain.length; i++) stack.push(clamp(inputs[i] ?? 0, domain[i * 2], domain[i * 2 + 1]));
|
|
145
|
+
if (domain.length === 0) stack.push(...inputs);
|
|
146
|
+
run(program, stack, 0);
|
|
147
|
+
const out = stack.slice(-n);
|
|
148
|
+
while (out.length < n) out.unshift(0);
|
|
149
|
+
return out.map((v, j) => clamp(v, Math.min(range[j * 2], range[j * 2 + 1]), Math.max(range[j * 2], range[j * 2 + 1])));
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
/** Read `{ … }` into nested token lists, or `undefined` where it is not one. */
|
|
153
|
+
function parseProgram(bytes) {
|
|
154
|
+
const lexer = new Lexer(bytes);
|
|
155
|
+
let count = 0;
|
|
156
|
+
const read = (depth) => {
|
|
157
|
+
if (depth > MAX_PS_DEPTH) return void 0;
|
|
158
|
+
const out = [];
|
|
159
|
+
for (;;) {
|
|
160
|
+
if (++count > MAX_PS_TOKENS) return void 0;
|
|
161
|
+
const tok = lexer.nextToken();
|
|
162
|
+
if (tok.kind === "eof") return depth === 0 ? out : void 0;
|
|
163
|
+
if (tok.kind === "num") out.push(tok.value);
|
|
164
|
+
else if (tok.kind === "keyword") if (tok.value === "{") {
|
|
165
|
+
const inner = read(depth + 1);
|
|
166
|
+
if (!inner) return void 0;
|
|
167
|
+
out.push(inner);
|
|
168
|
+
} else if (tok.value === "}") return out;
|
|
169
|
+
else out.push(tok.value);
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
|
+
const top = read(0);
|
|
173
|
+
return top && top.length === 1 && Array.isArray(top[0]) ? top[0] : top;
|
|
174
|
+
}
|
|
175
|
+
/** Run a token list against the stack (§7.10.5, Table 42). */
|
|
176
|
+
function run(program, stack, depth) {
|
|
177
|
+
if (depth > MAX_PS_DEPTH) return;
|
|
178
|
+
const pop = () => stack.pop() ?? 0;
|
|
179
|
+
const blocks = [];
|
|
180
|
+
for (const tok of program) {
|
|
181
|
+
if (typeof tok === "number") {
|
|
182
|
+
stack.push(tok);
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
if (Array.isArray(tok)) {
|
|
186
|
+
blocks.push(tok);
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
switch (tok) {
|
|
190
|
+
case "abs":
|
|
191
|
+
stack.push(Math.abs(pop()));
|
|
192
|
+
break;
|
|
193
|
+
case "add": {
|
|
194
|
+
const b = pop();
|
|
195
|
+
stack.push(pop() + b);
|
|
196
|
+
break;
|
|
197
|
+
}
|
|
198
|
+
case "atan": {
|
|
199
|
+
const den = pop();
|
|
200
|
+
const numr = pop();
|
|
201
|
+
stack.push((Math.atan2(numr, den) * 180 / Math.PI + 360) % 360);
|
|
202
|
+
break;
|
|
203
|
+
}
|
|
204
|
+
case "ceiling":
|
|
205
|
+
stack.push(Math.ceil(pop()));
|
|
206
|
+
break;
|
|
207
|
+
case "cos":
|
|
208
|
+
stack.push(Math.cos(pop() * Math.PI / 180));
|
|
209
|
+
break;
|
|
210
|
+
case "cvi":
|
|
211
|
+
stack.push(Math.trunc(pop()));
|
|
212
|
+
break;
|
|
213
|
+
case "cvr": break;
|
|
214
|
+
case "div": {
|
|
215
|
+
const b = pop();
|
|
216
|
+
const a = pop();
|
|
217
|
+
stack.push(b === 0 ? 0 : a / b);
|
|
218
|
+
break;
|
|
219
|
+
}
|
|
220
|
+
case "exp": {
|
|
221
|
+
const b = pop();
|
|
222
|
+
stack.push(pop() ** b);
|
|
223
|
+
break;
|
|
224
|
+
}
|
|
225
|
+
case "floor":
|
|
226
|
+
stack.push(Math.floor(pop()));
|
|
227
|
+
break;
|
|
228
|
+
case "idiv": {
|
|
229
|
+
const b = pop();
|
|
230
|
+
const a = pop();
|
|
231
|
+
stack.push(b === 0 ? 0 : Math.trunc(a / b));
|
|
232
|
+
break;
|
|
233
|
+
}
|
|
234
|
+
case "ln": {
|
|
235
|
+
const a = pop();
|
|
236
|
+
stack.push(a > 0 ? Math.log(a) : 0);
|
|
237
|
+
break;
|
|
238
|
+
}
|
|
239
|
+
case "log": {
|
|
240
|
+
const a = pop();
|
|
241
|
+
stack.push(a > 0 ? Math.log10(a) : 0);
|
|
242
|
+
break;
|
|
243
|
+
}
|
|
244
|
+
case "mod": {
|
|
245
|
+
const b = pop();
|
|
246
|
+
const a = pop();
|
|
247
|
+
stack.push(b === 0 ? 0 : Math.trunc(a) % Math.trunc(b));
|
|
248
|
+
break;
|
|
249
|
+
}
|
|
250
|
+
case "mul": {
|
|
251
|
+
const b = pop();
|
|
252
|
+
stack.push(pop() * b);
|
|
253
|
+
break;
|
|
254
|
+
}
|
|
255
|
+
case "neg":
|
|
256
|
+
stack.push(-pop());
|
|
257
|
+
break;
|
|
258
|
+
case "round":
|
|
259
|
+
stack.push(Math.round(pop()));
|
|
260
|
+
break;
|
|
261
|
+
case "sin":
|
|
262
|
+
stack.push(Math.sin(pop() * Math.PI / 180));
|
|
263
|
+
break;
|
|
264
|
+
case "sqrt":
|
|
265
|
+
stack.push(Math.sqrt(Math.max(0, pop())));
|
|
266
|
+
break;
|
|
267
|
+
case "sub": {
|
|
268
|
+
const b = pop();
|
|
269
|
+
stack.push(pop() - b);
|
|
270
|
+
break;
|
|
271
|
+
}
|
|
272
|
+
case "truncate":
|
|
273
|
+
stack.push(Math.trunc(pop()));
|
|
274
|
+
break;
|
|
275
|
+
case "and": {
|
|
276
|
+
const b = pop();
|
|
277
|
+
stack.push(int(pop()) & int(b));
|
|
278
|
+
break;
|
|
279
|
+
}
|
|
280
|
+
case "bitshift": {
|
|
281
|
+
const s = int(pop());
|
|
282
|
+
const a = int(pop());
|
|
283
|
+
stack.push(s >= 0 ? a << s : a >> -s);
|
|
284
|
+
break;
|
|
285
|
+
}
|
|
286
|
+
case "eq": {
|
|
287
|
+
const b = pop();
|
|
288
|
+
stack.push(pop() === b ? 1 : 0);
|
|
289
|
+
break;
|
|
290
|
+
}
|
|
291
|
+
case "false":
|
|
292
|
+
stack.push(0);
|
|
293
|
+
break;
|
|
294
|
+
case "ge": {
|
|
295
|
+
const b = pop();
|
|
296
|
+
stack.push(pop() >= b ? 1 : 0);
|
|
297
|
+
break;
|
|
298
|
+
}
|
|
299
|
+
case "gt": {
|
|
300
|
+
const b = pop();
|
|
301
|
+
stack.push(pop() > b ? 1 : 0);
|
|
302
|
+
break;
|
|
303
|
+
}
|
|
304
|
+
case "le": {
|
|
305
|
+
const b = pop();
|
|
306
|
+
stack.push(pop() <= b ? 1 : 0);
|
|
307
|
+
break;
|
|
308
|
+
}
|
|
309
|
+
case "lt": {
|
|
310
|
+
const b = pop();
|
|
311
|
+
stack.push(pop() < b ? 1 : 0);
|
|
312
|
+
break;
|
|
313
|
+
}
|
|
314
|
+
case "ne": {
|
|
315
|
+
const b = pop();
|
|
316
|
+
stack.push(pop() !== b ? 1 : 0);
|
|
317
|
+
break;
|
|
318
|
+
}
|
|
319
|
+
case "not": {
|
|
320
|
+
const a = pop();
|
|
321
|
+
stack.push(a === 0 ? 1 : a === 1 ? 0 : ~int(a));
|
|
322
|
+
break;
|
|
323
|
+
}
|
|
324
|
+
case "or": {
|
|
325
|
+
const b = pop();
|
|
326
|
+
stack.push(int(pop()) | int(b));
|
|
327
|
+
break;
|
|
328
|
+
}
|
|
329
|
+
case "true":
|
|
330
|
+
stack.push(1);
|
|
331
|
+
break;
|
|
332
|
+
case "xor": {
|
|
333
|
+
const b = pop();
|
|
334
|
+
stack.push(int(pop()) ^ int(b));
|
|
335
|
+
break;
|
|
336
|
+
}
|
|
337
|
+
case "if": {
|
|
338
|
+
const body = blocks.pop();
|
|
339
|
+
if (body && pop() !== 0) run(body, stack, depth + 1);
|
|
340
|
+
break;
|
|
341
|
+
}
|
|
342
|
+
case "ifelse": {
|
|
343
|
+
const otherwise = blocks.pop();
|
|
344
|
+
const body = blocks.pop();
|
|
345
|
+
const branch = pop() !== 0 ? body : otherwise;
|
|
346
|
+
if (branch) run(branch, stack, depth + 1);
|
|
347
|
+
break;
|
|
348
|
+
}
|
|
349
|
+
case "copy": {
|
|
350
|
+
const k = int(pop());
|
|
351
|
+
if (k > 0 && k <= stack.length) stack.push(...stack.slice(-k));
|
|
352
|
+
break;
|
|
353
|
+
}
|
|
354
|
+
case "dup": {
|
|
355
|
+
const a = pop();
|
|
356
|
+
stack.push(a, a);
|
|
357
|
+
break;
|
|
358
|
+
}
|
|
359
|
+
case "exch": {
|
|
360
|
+
const b = pop();
|
|
361
|
+
const a = pop();
|
|
362
|
+
stack.push(b, a);
|
|
363
|
+
break;
|
|
364
|
+
}
|
|
365
|
+
case "index": {
|
|
366
|
+
const k = int(pop());
|
|
367
|
+
stack.push(k >= 0 && k < stack.length ? stack[stack.length - 1 - k] : 0);
|
|
368
|
+
break;
|
|
369
|
+
}
|
|
370
|
+
case "pop":
|
|
371
|
+
pop();
|
|
372
|
+
break;
|
|
373
|
+
case "roll": {
|
|
374
|
+
const j = int(pop());
|
|
375
|
+
const k = int(pop());
|
|
376
|
+
if (k > 0 && k <= stack.length) {
|
|
377
|
+
const part = stack.splice(stack.length - k, k);
|
|
378
|
+
const by = (j % k + k) % k;
|
|
379
|
+
stack.push(...part.slice(k - by), ...part.slice(0, k - by));
|
|
380
|
+
}
|
|
381
|
+
break;
|
|
382
|
+
}
|
|
383
|
+
default: break;
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
/** A stack value as the 32-bit integer the bitwise operators work on. */
|
|
388
|
+
function int(v) {
|
|
389
|
+
return Number.isFinite(v) ? v | 0 : 0;
|
|
390
|
+
}
|
|
391
|
+
function clamp(v, lo, hi) {
|
|
392
|
+
if (!Number.isFinite(v)) return lo;
|
|
393
|
+
return v < lo ? lo : v > hi ? hi : v;
|
|
394
|
+
}
|
|
395
|
+
/** §7.10.2 — one number carried from one interval onto another. */
|
|
396
|
+
function interpolate(x, xLo, xHi, yLo, yHi) {
|
|
397
|
+
if (xHi === xLo) return yLo;
|
|
398
|
+
return yLo + (x - xLo) * (yHi - yLo) / (xHi - xLo);
|
|
399
|
+
}
|
|
400
|
+
function numbers(file, v) {
|
|
401
|
+
const r = v !== void 0 ? file.resolve(v) : void 0;
|
|
402
|
+
if (!Array.isArray(r)) return [];
|
|
403
|
+
return r.map((x) => {
|
|
404
|
+
const n = file.resolve(x);
|
|
405
|
+
return typeof n === "number" ? n : 0;
|
|
406
|
+
});
|
|
407
|
+
}
|
|
408
|
+
/** The stated array, where it is the right length; otherwise the default. */
|
|
409
|
+
function orDefault(stated, length, fallback) {
|
|
410
|
+
if (stated.length === length) return stated;
|
|
411
|
+
return Array.from({ length }, (_, i) => fallback(i));
|
|
412
|
+
}
|
|
413
|
+
//#endregion
|
|
414
|
+
export { readFunction };
|
|
@@ -27,10 +27,14 @@ export type DecodedImage = {
|
|
|
27
27
|
* Supports DeviceGray/RGB/CMYK, CalGray/CalRGB, ICCBased (by `/N`) and Indexed
|
|
28
28
|
* colour spaces; Flate, LZW (EP12), RunLength, ASCII85, ASCIIHex and CCITT
|
|
29
29
|
* Group 4 / Group 3 1-D fax (EP15) filters; PNG/TIFF predictors; bit depths
|
|
30
|
-
* 1/2/4/8/16;
|
|
31
|
-
*
|
|
32
|
-
* 2-D) return a typed failure so the
|
|
30
|
+
* 1/2/4/8/16; an `/SMask` folded in as the PNG alpha channel; and a stencil
|
|
31
|
+
* `/ImageMask` (§8.9.6.2) given back as RGBA in `fillHex`. Unsupported inputs
|
|
32
|
+
* (Separation/DeviceN/Lab, CCITT Group 3 2-D) return a typed failure so the
|
|
33
|
+
* caller records a loss.
|
|
33
34
|
*
|
|
35
|
+
* @param file The owning file.
|
|
36
|
+
* @param stream The image XObject, or an inline image wrapped as one.
|
|
37
|
+
* @param fillHex §8.9.6.2 — the non-stroking colour a stencil mask paints in.
|
|
34
38
|
* @returns The decoded image, or `{ ok: false }` with the loss severity and reason.
|
|
35
39
|
*/
|
|
36
|
-
export declare function decodePdfImage(file: PdfFile, stream: PdfStream): DecodedImage;
|
|
40
|
+
export declare function decodePdfImage(file: PdfFile, stream: PdfStream, fillHex?: string): DecodedImage;
|