@segnavia/render 0.1.0 → 0.3.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.
Files changed (42) hide show
  1. package/dist/color/binary.js +27 -0
  2. package/dist/color/black-point.js +121 -0
  3. package/dist/color/engine.js +18 -0
  4. package/dist/color/interpolation.js +74 -0
  5. package/dist/color/profile.js +98 -0
  6. package/dist/color/spaces.js +138 -0
  7. package/dist/color/tables.js +255 -0
  8. package/dist/color/types.js +21 -0
  9. package/dist/deck-pdf.js +152 -0
  10. package/dist/effects/adapter.js +336 -0
  11. package/dist/effects/content-replacement.js +35 -0
  12. package/dist/effects/function-evaluator.js +72 -0
  13. package/dist/effects/policy.js +10 -0
  14. package/dist/effects/rule-1.js +40 -0
  15. package/dist/effects/rule-c.js +354 -0
  16. package/dist/effects/structure.js +86 -0
  17. package/dist/effects/types.d.ts +15 -0
  18. package/dist/effects/types.js +4 -0
  19. package/dist/errors.d.ts +8 -0
  20. package/dist/errors.js +9 -0
  21. package/dist/index.d.ts +18 -8
  22. package/dist/index.js +96 -76
  23. package/dist/page-paper.js +94 -0
  24. package/dist/pages-imposition.js +65 -0
  25. package/dist/pages-pdf.js +67 -0
  26. package/dist/pdf-compose.js +35 -0
  27. package/dist/pdf-geometry.js +27 -0
  28. package/dist/press/adapter.js +275 -0
  29. package/dist/press/affine.js +60 -0
  30. package/dist/press/calculator-ops.js +277 -0
  31. package/dist/press/calculator.js +130 -0
  32. package/dist/press/color-policy.js +31 -0
  33. package/dist/press/content.js +292 -0
  34. package/dist/press/pattern-bounds.js +275 -0
  35. package/dist/press/pattern-path.js +102 -0
  36. package/dist/press/pdf-objects.js +88 -0
  37. package/dist/press/policy.js +126 -0
  38. package/dist/press/report.js +89 -0
  39. package/dist/press/sample-shading.js +266 -0
  40. package/dist/press/types.d.ts +18 -0
  41. package/dist/press/visitor.js +163 -0
  42. package/package.json +3 -3
@@ -0,0 +1,266 @@
1
+ import { RenderRefusedError } from "../errors.js";
2
+ import { IDENTITY_MATRIX, applyAffine, invertAffine, multiplyAffine } from "./affine.js";
3
+ import { MAX_DOCUMENT_CONTENT_BYTES, arrayNumbers, decodeContent, rawStreamOf } from "./pdf-objects.js";
4
+ import { evaluateCalculator, parseCalculator, staticOperatorCount } from "./calculator.js";
5
+ import { PDFArray, PDFName, PDFNumber, PDFRef } from "pdf-lib";
6
+ import { deflateSync } from "node:zlib";
7
+ //#region src/press/sample-shading.ts
8
+ const SHADING_SAMPLE_SPACING_PT = .5;
9
+ const MAX_SHADING_SAMPLES = 1048576;
10
+ const MAX_DOCUMENT_SHADING_SAMPLES = 4 * MAX_SHADING_SAMPLES;
11
+ const MAX_DOCUMENT_CALCULATOR_OPERATIONS = 8 * MAX_SHADING_SAMPLES * 52;
12
+ const MAX_SAMPLING_COLOR_CACHE = 4096;
13
+ const SAMPLE_CHANNELS = 4;
14
+ const SAMPLE_BYTES = 1;
15
+ function refuse(found, supported) {
16
+ throw new RenderRefusedError(`The PDF has unsupported ${found}; supported: ${supported}.`);
17
+ }
18
+ function clamp01(value) {
19
+ if (value < 0) return 0;
20
+ if (value > 1) return 1;
21
+ return value;
22
+ }
23
+ function requireFinite(values, found) {
24
+ if (values.some((value) => !Number.isFinite(value))) refuse(found, "finite numbers");
25
+ }
26
+ function shadingNumbers(dictionary, key, count) {
27
+ const expected = count === 4 ? "four finite numbers" : "six finite numbers";
28
+ const array = dictionary.lookupMaybe(PDFName.of(key), PDFArray);
29
+ if (!array || array.size() !== count) refuse(`shading ${key}`, expected);
30
+ const values = Array.from({ length: count }, (_, index) => array.lookupMaybe(index, PDFNumber)?.asNumber());
31
+ if (values.some((value) => value === void 0 || !Number.isFinite(value))) refuse(`shading ${key}`, expected);
32
+ return values;
33
+ }
34
+ function shadingDomainOf(shading) {
35
+ return shadingNumbers(shading, "Domain", 4);
36
+ }
37
+ function axisSamples(span, columnA, columnB) {
38
+ if (![
39
+ span,
40
+ columnA,
41
+ columnB
42
+ ].every(Number.isFinite)) refuse("shading axis length", "a finite length");
43
+ const extent = Math.hypot(columnA, columnB) * Math.abs(span) / SHADING_SAMPLE_SPACING_PT;
44
+ if (!Number.isFinite(extent)) refuse("shading axis length", "a finite length");
45
+ return Math.min(MAX_SHADING_SAMPLES, Math.max(1, Math.ceil(extent)));
46
+ }
47
+ function packedRgb8(rgb) {
48
+ return Math.round(clamp01(rgb[0]) * 255) << 16 | Math.round(clamp01(rgb[1]) * 255) << 8 | Math.round(clamp01(rgb[2]) * 255);
49
+ }
50
+ function unpackRgb8(key) {
51
+ return [
52
+ (key >> 16) / 255,
53
+ (key >> 8 & 255) / 255,
54
+ (key & 255) / 255
55
+ ];
56
+ }
57
+ function createSamplingColorConverter(convert) {
58
+ const cache = /* @__PURE__ */ new Map();
59
+ return {
60
+ size: () => cache.size,
61
+ convert: (rgb) => {
62
+ const key = packedRgb8(rgb);
63
+ const cached = cache.get(key);
64
+ if (cached) return cached;
65
+ const converted = convert(unpackRgb8(key));
66
+ if (cache.size < 4096) cache.set(key, converted);
67
+ return converted;
68
+ }
69
+ };
70
+ }
71
+ function sampleDomainForPainted(domain, matrix, painted) {
72
+ const original = [
73
+ domain[0] ?? 0,
74
+ domain[1] ?? 0,
75
+ domain[2] ?? 0,
76
+ domain[3] ?? 0
77
+ ];
78
+ if (!painted || painted === "unbounded") return original;
79
+ const inverse = invertAffine(matrix);
80
+ if (!inverse) return original;
81
+ const corners = [
82
+ applyAffine(inverse, painted.x0, painted.y0),
83
+ applyAffine(inverse, painted.x1, painted.y0),
84
+ applyAffine(inverse, painted.x0, painted.y1),
85
+ applyAffine(inverse, painted.x1, painted.y1)
86
+ ];
87
+ const xs = corners.map((point) => point.x);
88
+ const ys = corners.map((point) => point.y);
89
+ const x0 = Math.max(original[0] ?? 0, Math.min(...xs));
90
+ const x1 = Math.min(original[1] ?? 0, Math.max(...xs));
91
+ const y0 = Math.max(original[2] ?? 0, Math.min(...ys));
92
+ const y1 = Math.min(original[3] ?? 0, Math.max(...ys));
93
+ if (!(x0 < x1) || !(y0 < y1)) return original;
94
+ return [
95
+ x0,
96
+ x1,
97
+ y0,
98
+ y1
99
+ ];
100
+ }
101
+ function unionSampleDomain(left, right) {
102
+ return [
103
+ Math.min(left[0] ?? 0, right[0] ?? 0),
104
+ Math.max(left[1] ?? 0, right[1] ?? 0),
105
+ Math.min(left[2] ?? 0, right[2] ?? 0),
106
+ Math.max(left[3] ?? 0, right[3] ?? 0)
107
+ ];
108
+ }
109
+ function sampleDomainForUses(domain, uses) {
110
+ const original = [
111
+ domain[0] ?? 0,
112
+ domain[1] ?? 0,
113
+ domain[2] ?? 0,
114
+ domain[3] ?? 0
115
+ ];
116
+ if (uses.length === 0) return original;
117
+ let union;
118
+ for (const use of uses) {
119
+ const next = sampleDomainForPainted(domain, use.matrix, use.painted);
120
+ if (!use.painted || use.painted === "unbounded") return original;
121
+ union = union ? unionSampleDomain(union, next) : next;
122
+ }
123
+ return union ?? original;
124
+ }
125
+ function matrixOf(dictionary) {
126
+ if (!dictionary?.has(PDFName.of("Matrix"))) return IDENTITY_MATRIX.slice();
127
+ return arrayNumbers(dictionary, "Matrix", 6);
128
+ }
129
+ function shadingDeviceMatrix(shading, pattern) {
130
+ const shadingMatrix = shading.has(PDFName.of("Matrix")) ? shadingNumbers(shading, "Matrix", 6) : IDENTITY_MATRIX.slice();
131
+ return pattern ? multiplyAffine(matrixOf(pattern), shadingMatrix) : shadingMatrix;
132
+ }
133
+ function capSampleGrid(n, m) {
134
+ if (n * m <= 1048576) return {
135
+ n,
136
+ m
137
+ };
138
+ const scale = Math.sqrt(MAX_SHADING_SAMPLES / (n * m));
139
+ let nextN = Math.max(1, Math.floor(n * scale));
140
+ let nextM = Math.max(1, Math.floor(m * scale));
141
+ while (nextN * nextM > MAX_SHADING_SAMPLES) if (nextN >= nextM && nextN > 1) nextN--;
142
+ else if (nextM > 1) nextM--;
143
+ else break;
144
+ return {
145
+ n: nextN,
146
+ m: nextM
147
+ };
148
+ }
149
+ function shadingSampleGrid(domain, matrix) {
150
+ const x0 = domain[0] ?? 0;
151
+ const x1 = domain[1] ?? 0;
152
+ const y0 = domain[2] ?? 0;
153
+ const y1 = domain[3] ?? 0;
154
+ requireFinite([
155
+ x0,
156
+ x1,
157
+ y0,
158
+ y1
159
+ ], "shading Domain");
160
+ const columnAx = matrix[0] ?? 1;
161
+ const columnAy = matrix[1] ?? 0;
162
+ const columnBx = matrix[2] ?? 0;
163
+ const columnBy = matrix[3] ?? 1;
164
+ requireFinite([
165
+ columnAx,
166
+ columnAy,
167
+ columnBx,
168
+ columnBy,
169
+ matrix[4] ?? 0,
170
+ matrix[5] ?? 0
171
+ ], "shading Matrix");
172
+ return capSampleGrid(axisSamples(x1 - x0, columnAx, columnAy), axisSamples(y1 - y0, columnBx, columnBy));
173
+ }
174
+ function shadingSampleGridForUses(domain, matrices) {
175
+ if (matrices.length === 0) return shadingSampleGrid(domain, IDENTITY_MATRIX);
176
+ let n = 1;
177
+ let m = 1;
178
+ for (const matrix of matrices) {
179
+ const grid = shadingSampleGrid(domain, matrix);
180
+ n = Math.max(n, grid.n);
181
+ m = Math.max(m, grid.m);
182
+ }
183
+ return capSampleGrid(n, m);
184
+ }
185
+ function domainValue(min, max, index, size) {
186
+ if (size <= 1) return min;
187
+ return min + (max - min) * index / (size - 1);
188
+ }
189
+ function sampleShadingToCmyk(program, domain, size, convert) {
190
+ const x0 = domain[0] ?? 0;
191
+ const x1 = domain[1] ?? 0;
192
+ const y0 = domain[2] ?? 0;
193
+ const y1 = domain[3] ?? 0;
194
+ const samples = new Uint8Array(size.n * size.m * SAMPLE_CHANNELS * SAMPLE_BYTES);
195
+ const toCmyk = createSamplingColorConverter(convert).convert;
196
+ let offset = 0;
197
+ for (let j = 0; j < size.m; j++) {
198
+ const y = domainValue(y0, y1, j, size.m);
199
+ for (let i = 0; i < size.n; i++) {
200
+ const x = domainValue(x0, x1, i, size.n);
201
+ const rgb = evaluateCalculator(program, [x, y]);
202
+ if (rgb.length !== 3) refuse("shading function outputs", "3 numbers");
203
+ const cmyk = toCmyk([
204
+ clamp01(rgb[0] ?? 0),
205
+ clamp01(rgb[1] ?? 0),
206
+ clamp01(rgb[2] ?? 0)
207
+ ]);
208
+ for (const channel of cmyk) {
209
+ samples[offset] = Math.round(clamp01(channel) * 255);
210
+ offset += SAMPLE_BYTES;
211
+ }
212
+ }
213
+ }
214
+ return samples;
215
+ }
216
+ function chargeShadingSamples(budget, samples, operations) {
217
+ const bytes = samples * SAMPLE_CHANNELS * SAMPLE_BYTES;
218
+ if (!Number.isFinite(samples) || samples < 0 || !Number.isFinite(bytes) || bytes < 0) refuse(`document shading samples ${samples}`, "a finite non-negative sample count and byte charge");
219
+ if (!Number.isFinite(operations) || operations < 0) refuse(`document calculator operations ${operations}`, "a finite non-negative operator count");
220
+ const totalSamples = (budget.shadingSamples ?? 0) + samples;
221
+ const totalBytes = budget.decodedBytes + bytes;
222
+ const totalOperations = (budget.calculatorOperations ?? 0) + operations;
223
+ if (!Number.isFinite(totalSamples) || totalSamples > 4194304) refuse(`document shading samples ${totalSamples}`, `at most ${MAX_DOCUMENT_SHADING_SAMPLES} samples`);
224
+ if (!Number.isFinite(totalOperations) || totalOperations > 436207616) refuse(`document calculator operations ${totalOperations}`, `at most ${MAX_DOCUMENT_CALCULATOR_OPERATIONS} operators`);
225
+ if (!Number.isFinite(totalBytes) || totalBytes > 134217728) refuse(`total decoded content length ${totalBytes}`, `at most ${MAX_DOCUMENT_CONTENT_BYTES} bytes`);
226
+ budget.shadingSamples = totalSamples;
227
+ budget.decodedBytes = totalBytes;
228
+ budget.calculatorOperations = totalOperations;
229
+ }
230
+ const resolved = (document, object) => object instanceof PDFRef ? document.context.lookup(object) : object;
231
+ function replaceType1Function(document, shading, pattern, convert, budget, painted, sampleDomain, sampleSize) {
232
+ const existing = shading.get(PDFName.of("Function"));
233
+ const stream = rawStreamOf(resolved(document, existing));
234
+ if (!stream) return refuse("shading FunctionType 4 stream", "a FunctionType 4 stream");
235
+ const shadingDomain = shadingDomainOf(shading);
236
+ const matrix = shadingDeviceMatrix(shading, pattern);
237
+ requireFinite(matrix, "shading Matrix");
238
+ const domain = sampleDomain ? [...sampleDomain] : sampleDomainForPainted(shadingDomain, matrix, painted);
239
+ const size = sampleSize ?? shadingSampleGrid(domain, matrix);
240
+ const program = parseCalculator(new TextDecoder("latin1").decode(decodeContent(stream, budget)));
241
+ const samples = size.n * size.m;
242
+ chargeShadingSamples(budget, samples, samples * staticOperatorCount(program));
243
+ const data = sampleShadingToCmyk(program, domain, size, convert);
244
+ const replacement = document.context.stream(deflateSync(data), {
245
+ FunctionType: 0,
246
+ Domain: domain,
247
+ Range: [
248
+ 0,
249
+ 1,
250
+ 0,
251
+ 1,
252
+ 0,
253
+ 1,
254
+ 0,
255
+ 1
256
+ ],
257
+ Size: [size.n, size.m],
258
+ BitsPerSample: 8,
259
+ Order: 1,
260
+ Filter: "FlateDecode"
261
+ });
262
+ shading.set(PDFName.of("Function"), document.context.register(replacement));
263
+ return size;
264
+ }
265
+ //#endregion
266
+ export { MAX_DOCUMENT_CALCULATOR_OPERATIONS, MAX_DOCUMENT_SHADING_SAMPLES, MAX_SAMPLING_COLOR_CACHE, MAX_SHADING_SAMPLES, SHADING_SAMPLE_SPACING_PT, chargeShadingSamples, createSamplingColorConverter, domainValue, matrixOf, packedRgb8, replaceType1Function, sampleDomainForPainted, sampleDomainForUses, sampleShadingToCmyk, shadingDeviceMatrix, shadingDomainOf, shadingSampleGrid, shadingSampleGridForUses, unionSampleDomain, unpackRgb8 };
@@ -0,0 +1,18 @@
1
+ //#region src/press/types.d.ts
2
+ export interface PressImage {
3
+ width: number;
4
+ height: number;
5
+ colorSpace: 'DeviceRGB' | 'CalRGB' | 'ICCBased' | 'Indexed';
6
+ }
7
+ export interface PressReport {
8
+ /** Authored raster images left in RGB, read back from the finished PDF. */
9
+ images: PressImage[];
10
+ /** CMYK painting and group counts read back from the finished PDF. */
11
+ fills: number;
12
+ strokes: number;
13
+ gradientStops: number;
14
+ /** Function-based shadings rewritten as DeviceCMYK sampled functions. */
15
+ sampledShadings: number;
16
+ groups: number;
17
+ }
18
+ //#endregion
@@ -0,0 +1,163 @@
1
+ import { shadingFunctionAction } from "./policy.js";
2
+ import { dictionaryOf, nameOf, numberOf, rawStreamOf } from "./pdf-objects.js";
3
+ import { PDFArray, PDFDict, PDFName, PDFRef } from "pdf-lib";
4
+ //#region src/press/visitor.ts
5
+ const key = (name) => PDFName.of(name);
6
+ const resolved = (state, object) => object instanceof PDFRef ? state.document.context.lookup(object) : object;
7
+ const dictionary = (state, object) => dictionaryOf(resolved(state, object));
8
+ const stream = (state, object) => rawStreamOf(resolved(state, object));
9
+ function rememberRef(state, object) {
10
+ if (!(object instanceof PDFRef)) return false;
11
+ const label = object.toString();
12
+ if (state.references.has(label)) return true;
13
+ state.references.add(label);
14
+ return false;
15
+ }
16
+ function visitContent(state, object, replace, enclosing, replay = false, nestResources = true) {
17
+ if (!object) return;
18
+ const seenRef = rememberRef(state, object);
19
+ const found = stream(state, object);
20
+ if (!found) return;
21
+ const seenStream = state.streams.has(found);
22
+ if (!seenStream) state.streams.add(found);
23
+ const seen = seenRef || seenStream;
24
+ if (seen && !replay) return;
25
+ const own = found.dict.lookupMaybe(key("Resources"), PDFDict);
26
+ if (!seen) state.actions?.group(found.dict, found, state.maskSources.has(found));
27
+ state.actions?.content(object, found, replace, own ?? enclosing);
28
+ if (nestResources && !seen) visitResources(state, own);
29
+ }
30
+ function visitSoftMask(state, object, enclosing) {
31
+ const graphicsState = dictionary(state, object);
32
+ const mask = dictionary(state, graphicsState?.get(key("SMask")));
33
+ const sourceObject = mask?.get(key("G"));
34
+ const source = stream(state, sourceObject);
35
+ if (!graphicsState || !mask || !source || !sourceObject) return;
36
+ state.actions?.softMask?.(graphicsState, mask, source, source.dict.lookupMaybe(key("Resources"), PDFDict) ?? enclosing);
37
+ state.maskSources.add(source);
38
+ visitContent(state, sourceObject, (replacement) => mask?.set(key("G"), replacement), enclosing);
39
+ }
40
+ function visitAppearances(state, page, enclosing) {
41
+ const annotations = resolved(state, page.get(key("Annots")));
42
+ if (!(annotations instanceof PDFArray)) return;
43
+ for (let index = 0; index < annotations.size(); index++) {
44
+ const appearance = dictionary(state, dictionary(state, annotations.get(index))?.get(key("AP")));
45
+ for (const name of [
46
+ "N",
47
+ "R",
48
+ "D"
49
+ ]) {
50
+ const object = appearance?.get(key(name));
51
+ if (!object) continue;
52
+ if (stream(state, object)) visitContent(state, object, (replacement) => appearance?.set(key(name), replacement), enclosing);
53
+ else {
54
+ const states = dictionary(state, object);
55
+ for (const [stateName, stateObject] of states?.entries() ?? []) visitContent(state, stateObject, (replacement) => states?.set(stateName, replacement), enclosing);
56
+ }
57
+ }
58
+ }
59
+ }
60
+ function visitFunction(state, object) {
61
+ const fn = dictionary(state, object);
62
+ if (fn && state.functions.has(fn)) return;
63
+ if (fn) state.functions.add(fn);
64
+ const type = fn ? numberOf(fn, "FunctionType") : void 0;
65
+ const functions = type === 3 ? fn?.lookupMaybe(key("Functions"), PDFArray) : void 0;
66
+ const decision = shadingFunctionAction(type, Boolean(fn), type !== 3 || Boolean(functions));
67
+ state.actions?.function(fn, decision);
68
+ for (let index = 0; index < (functions?.size() ?? 0); index++) visitFunction(state, functions?.get(index));
69
+ }
70
+ function visitShading(state, shading, pattern) {
71
+ if (state.actions?.shading(shading, pattern)) visitFunction(state, shading.get(key("Function")));
72
+ }
73
+ function visitShadings(state, resources) {
74
+ const shadings = resources.lookupMaybe(key("Shading"), PDFDict);
75
+ for (const [, object] of shadings?.entries() ?? []) {
76
+ const found = dictionary(state, object);
77
+ if (found) visitShading(state, found);
78
+ }
79
+ }
80
+ function visitPatterns(state, resources) {
81
+ const patterns = resources.lookupMaybe(key("Pattern"), PDFDict);
82
+ for (const [name, object] of patterns?.entries() ?? []) {
83
+ const found = dictionary(state, object);
84
+ if (!found) continue;
85
+ if (numberOf(found, "PatternType") === 2) {
86
+ const shading = dictionary(state, found.get(key("Shading")));
87
+ if (shading) visitShading(state, shading, found);
88
+ } else visitContent(state, object, (replacement) => patterns?.set(name, replacement), found.lookupMaybe(key("Resources"), PDFDict) ?? resources);
89
+ visitResources(state, found.lookupMaybe(key("Resources"), PDFDict));
90
+ }
91
+ }
92
+ function visitGraphicsStates(state, resources) {
93
+ const graphicsStates = resources.lookupMaybe(key("ExtGState"), PDFDict);
94
+ for (const [, object] of graphicsStates?.entries() ?? []) visitSoftMask(state, object, resources);
95
+ }
96
+ function visitXObjects(state, resources) {
97
+ const xObjects = resources.lookupMaybe(key("XObject"), PDFDict);
98
+ for (const [name, object] of xObjects?.entries() ?? []) {
99
+ const found = stream(state, object);
100
+ if (!found) continue;
101
+ if (nameOf(found.dict.get(key("Subtype"))) === "Image") state.actions?.image(found);
102
+ else visitContent(state, object, (replacement) => xObjects?.set(name, replacement), found.dict.lookupMaybe(key("Resources"), PDFDict) ?? resources);
103
+ }
104
+ }
105
+ function visitFonts(state, resources) {
106
+ const fonts = resources.lookupMaybe(key("Font"), PDFDict);
107
+ for (const [, object] of fonts?.entries() ?? []) {
108
+ const font = dictionary(state, object);
109
+ if (!font || nameOf(font.get(key("Subtype"))) !== "Type3") continue;
110
+ const charProcs = font.lookupMaybe(key("CharProcs"), PDFDict);
111
+ for (const [name, glyph] of charProcs?.entries() ?? []) visitContent(state, glyph, (replacement) => charProcs?.set(name, replacement), font.lookupMaybe(key("Resources"), PDFDict) ?? resources);
112
+ visitResources(state, font.lookupMaybe(key("Resources"), PDFDict));
113
+ }
114
+ }
115
+ function visitResources(state, resources) {
116
+ if (!resources || state.resources.has(resources)) return;
117
+ state.resources.add(resources);
118
+ visitGraphicsStates(state, resources);
119
+ visitXObjects(state, resources);
120
+ visitFonts(state, resources);
121
+ visitShadings(state, resources);
122
+ visitPatterns(state, resources);
123
+ }
124
+ function visitPageContents(state, page, contents, pageResources) {
125
+ const replay = Boolean(state.actions?.replayPageContents);
126
+ const nested = [];
127
+ const feed = (object, replace) => {
128
+ visitContent(state, object, replace, pageResources, replay, false);
129
+ const own = stream(state, object)?.dict.lookupMaybe(key("Resources"), PDFDict);
130
+ if (own) nested.push(own);
131
+ };
132
+ if (contents instanceof PDFArray) {
133
+ state.actions?.beginContentsSequence?.();
134
+ for (let index = 0; index < contents.size(); index++) feed(contents.get(index), (replacement) => contents.set(index, replacement));
135
+ state.actions?.endContentsSequence?.();
136
+ } else feed(contents, (replacement) => page.set(key("Contents"), replacement));
137
+ for (const resources of nested) visitResources(state, resources);
138
+ }
139
+ function traverse(document, maskSources, actions) {
140
+ const state = {
141
+ document,
142
+ maskSources,
143
+ actions,
144
+ functions: /* @__PURE__ */ new WeakSet(),
145
+ references: /* @__PURE__ */ new Set(),
146
+ resources: /* @__PURE__ */ new WeakSet(),
147
+ streams: /* @__PURE__ */ new WeakSet()
148
+ };
149
+ for (const page of document.getPages()) {
150
+ actions?.group(page.node, void 0, false);
151
+ const pageResources = page.node.Resources();
152
+ visitPageContents(state, page.node, page.node.Contents(), pageResources);
153
+ visitResources(state, pageResources);
154
+ visitAppearances(state, page.node, pageResources);
155
+ }
156
+ }
157
+ function walkPressGraph(document, actions) {
158
+ const maskSources = /* @__PURE__ */ new WeakSet();
159
+ traverse(document, maskSources);
160
+ traverse(document, maskSources, actions);
161
+ }
162
+ //#endregion
163
+ export { walkPressGraph };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@segnavia/render",
3
- "version": "0.1.0",
3
+ "version": "0.3.0",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -26,8 +26,8 @@
26
26
  }
27
27
  },
28
28
  "dependencies": {
29
- "@segnavia/format": "0.1.0",
30
- "@segnavia/frame": "0.1.0",
29
+ "@segnavia/format": "0.3.0",
30
+ "@segnavia/frame": "0.3.0",
31
31
  "playwright-core": "1.55.1",
32
32
  "pdf-lib": "^1.17.1"
33
33
  }