reamkit 1.5.0 → 1.7.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 (58) hide show
  1. package/README.md +2 -2
  2. package/dist/esm/core/converter/facade.js +6 -1
  3. package/dist/esm/core/converter/ream.js +2 -1
  4. package/dist/esm/core/document-model/types.d.ts +9 -1
  5. package/dist/esm/core/drawingml/chart-serializer.d.ts +2 -0
  6. package/dist/esm/core/drawingml/chart-serializer.js +53 -0
  7. package/dist/esm/core/spreadsheet-model/index.d.ts +1 -1
  8. package/dist/esm/core/spreadsheet-model/types.d.ts +5 -0
  9. package/dist/esm/excel/column-bands.d.ts +7 -0
  10. package/dist/esm/excel/column-bands.js +87 -0
  11. package/dist/esm/excel/conditional-format.js +22 -0
  12. package/dist/esm/excel/print-model.js +33 -11
  13. package/dist/esm/excel/worksheet-parser.js +26 -0
  14. package/dist/esm/excel/xlsx-writer.js +88 -17
  15. package/dist/esm/html/html-writer.js +100 -5
  16. package/dist/esm/layout/styled-layout.js +88 -19
  17. package/dist/esm/pdf-reader/cmap.d.ts +5 -0
  18. package/dist/esm/pdf-reader/cmap.js +72 -0
  19. package/dist/esm/pdf-reader/content.d.ts +52 -0
  20. package/dist/esm/pdf-reader/content.js +420 -0
  21. package/dist/esm/pdf-reader/crypto.d.ts +7 -0
  22. package/dist/esm/pdf-reader/crypto.js +609 -0
  23. package/dist/esm/pdf-reader/decrypt.d.ts +5 -0
  24. package/dist/esm/pdf-reader/decrypt.js +199 -0
  25. package/dist/esm/pdf-reader/document.d.ts +30 -0
  26. package/dist/esm/pdf-reader/document.js +413 -0
  27. package/dist/esm/pdf-reader/flow-build.d.ts +19 -0
  28. package/dist/esm/pdf-reader/flow-build.js +126 -0
  29. package/dist/esm/pdf-reader/font.d.ts +4 -0
  30. package/dist/esm/pdf-reader/font.js +69 -0
  31. package/dist/esm/pdf-reader/image-decode.d.ts +15 -0
  32. package/dist/esm/pdf-reader/image-decode.js +442 -0
  33. package/dist/esm/pdf-reader/images.d.ts +16 -0
  34. package/dist/esm/pdf-reader/images.js +90 -0
  35. package/dist/esm/pdf-reader/layout.d.ts +3 -0
  36. package/dist/esm/pdf-reader/layout.js +103 -0
  37. package/dist/esm/pdf-reader/lexer.d.ts +43 -0
  38. package/dist/esm/pdf-reader/lexer.js +250 -0
  39. package/dist/esm/pdf-reader/parser.d.ts +10 -0
  40. package/dist/esm/pdf-reader/parser.js +86 -0
  41. package/dist/esm/pdf-reader/png-encode.d.ts +2 -0
  42. package/dist/esm/pdf-reader/png-encode.js +98 -0
  43. package/dist/esm/pdf-reader/predictor.d.ts +7 -0
  44. package/dist/esm/pdf-reader/predictor.js +61 -0
  45. package/dist/esm/pdf-reader/reader.d.ts +4 -0
  46. package/dist/esm/pdf-reader/reader.js +50 -0
  47. package/dist/esm/pdf-reader/struct-tree.d.ts +14 -0
  48. package/dist/esm/pdf-reader/struct-tree.js +92 -0
  49. package/dist/esm/pdf-reader/tagged.d.ts +3 -0
  50. package/dist/esm/pdf-reader/tagged.js +141 -0
  51. package/dist/esm/pdf-reader/text.d.ts +3 -0
  52. package/dist/esm/pdf-reader/text.js +65 -0
  53. package/dist/esm/pdf-reader/vector.d.ts +12 -0
  54. package/dist/esm/pdf-reader/vector.js +54 -0
  55. package/dist/esm/word/docx-writer.js +96 -7
  56. package/dist/esm/word/omml-serializer.d.ts +2 -0
  57. package/dist/esm/word/omml-serializer.js +48 -0
  58. package/package.json +2 -2
@@ -0,0 +1,126 @@
1
+ import { pt } from "../core/ir/units.js";
2
+ import { ResourceStore } from "../core/ir/resources.js";
3
+ import { EMPTY_STYLE_SHEET, resolveBodyStyles } from "../core/style-cascade/resolver.js";
4
+ import "../core/style-cascade/index.js";
5
+ //#region src/pdf-reader/flow-build.ts
6
+ function paragraphBlock(text, outlineLevel) {
7
+ return {
8
+ kind: "paragraph",
9
+ paragraph: {
10
+ properties: outlineLevel !== void 0 ? { outlineLevel } : {},
11
+ runs: text.length > 0 ? [{
12
+ text,
13
+ properties: {}
14
+ }] : []
15
+ }
16
+ };
17
+ }
18
+ function paragraphFromRuns(spans, outlineLevel) {
19
+ const merged = [];
20
+ for (const s of spans) {
21
+ const last = merged[merged.length - 1];
22
+ if (last && last.href === s.href) last.text += s.text;
23
+ else if (s.href !== void 0) merged.push({
24
+ text: s.text,
25
+ href: s.href
26
+ });
27
+ else merged.push({ text: s.text });
28
+ }
29
+ const runs = merged.map((m) => ({
30
+ text: m.text.replace(/\s+/g, " "),
31
+ href: m.href
32
+ })).filter((m) => m.text.length > 0);
33
+ if (runs.length > 0) {
34
+ runs[0].text = runs[0].text.replace(/^ /, "");
35
+ runs[runs.length - 1].text = runs[runs.length - 1].text.replace(/ $/, "");
36
+ }
37
+ return {
38
+ kind: "paragraph",
39
+ paragraph: {
40
+ properties: outlineLevel !== void 0 ? { outlineLevel } : {},
41
+ runs: runs.filter((r) => r.text.length > 0).map((r) => ({
42
+ text: r.text,
43
+ properties: {},
44
+ ...r.href ? { href: r.href } : {}
45
+ }))
46
+ }
47
+ };
48
+ }
49
+ function imageBlock(image, resources, alt) {
50
+ return {
51
+ kind: "image",
52
+ image: {
53
+ resource: resources.put(image.bytes),
54
+ width: pt(image.widthPt),
55
+ height: pt(image.heightPt),
56
+ paragraphProperties: {},
57
+ ...alt ? { altText: alt } : {}
58
+ }
59
+ };
60
+ }
61
+ function dedupeLosses(losses) {
62
+ const byDetail = /* @__PURE__ */ new Map();
63
+ for (const loss of losses) if (!byDetail.has(loss.detail)) byDetail.set(loss.detail, loss);
64
+ return [...byDetail.values()];
65
+ }
66
+ function shapeBlock(v) {
67
+ const w = v.maxX - v.minX;
68
+ const h = v.maxY - v.minY;
69
+ const fx = (x) => x - v.minX;
70
+ const fy = (y) => v.maxY - y;
71
+ const commands = v.segs.map((s) => {
72
+ switch (s.op) {
73
+ case "move": return {
74
+ cmd: "move",
75
+ x: fx(s.x),
76
+ y: fy(s.y)
77
+ };
78
+ case "line": return {
79
+ cmd: "line",
80
+ x: fx(s.x),
81
+ y: fy(s.y)
82
+ };
83
+ case "cubic": return {
84
+ cmd: "cubic",
85
+ x1: fx(s.x1),
86
+ y1: fy(s.y1),
87
+ x2: fx(s.x2),
88
+ y2: fy(s.y2),
89
+ x: fx(s.x),
90
+ y: fy(s.y)
91
+ };
92
+ case "close": return { cmd: "close" };
93
+ }
94
+ });
95
+ return {
96
+ kind: "shape",
97
+ shape: {
98
+ width: pt(w),
99
+ height: pt(h),
100
+ geometry: {
101
+ kind: "custom",
102
+ custom: {
103
+ pathWidth: w,
104
+ pathHeight: h,
105
+ commands
106
+ }
107
+ },
108
+ fill: {
109
+ kind: "solid",
110
+ colorHex: v.fillHex
111
+ },
112
+ paragraphProperties: {}
113
+ }
114
+ };
115
+ }
116
+ function buildFlowDoc(body, resources = new ResourceStore()) {
117
+ return {
118
+ kind: "flow",
119
+ body: resolveBodyStyles([...body], EMPTY_STYLE_SHEET),
120
+ sections: [],
121
+ styles: EMPTY_STYLE_SHEET,
122
+ resources
123
+ };
124
+ }
125
+ //#endregion
126
+ export { buildFlowDoc, dedupeLosses, imageBlock, paragraphBlock, paragraphFromRuns, shapeBlock };
@@ -0,0 +1,4 @@
1
+ import { PdfDict } from '../pdf/objects.js';
2
+ import { ContentFont } from './content.js';
3
+ import { PdfFile } from './document.js';
4
+ export declare function buildContentFont(file: PdfFile, fontDict: PdfDict): ContentFont;
@@ -0,0 +1,69 @@
1
+ import { PDF_NULL, PdfName, PdfStream } from "../pdf/objects.js";
2
+ import { parseToUnicodeCMap } from "./cmap.js";
3
+ //#region src/pdf-reader/font.ts
4
+ function buildContentFont(file, fontDict) {
5
+ const isType0 = asName(file.resolve(fontDict.get("Subtype") ?? PDF_NULL)) === "Type0";
6
+ let toUnicode = /* @__PURE__ */ new Map();
7
+ let codeBytes = isType0 ? 2 : 1;
8
+ const tu = file.resolve(fontDict.get("ToUnicode") ?? PDF_NULL);
9
+ if (tu instanceof PdfStream) {
10
+ const parsed = parseToUnicodeCMap(file.streamData(tu));
11
+ toUnicode = parsed.map;
12
+ codeBytes = parsed.codeBytes;
13
+ }
14
+ const width = isType0 ? cidWidths(file, fontDict) : simpleWidths(file, fontDict);
15
+ const bytesPerCode = codeBytes;
16
+ return {
17
+ bytesPerCode,
18
+ decode: (codes) => codes.map((c) => toUnicode.get(c) ?? (bytesPerCode === 1 ? String.fromCharCode(c) : "")).join(""),
19
+ width
20
+ };
21
+ }
22
+ function simpleWidths(file, fontDict) {
23
+ const first = asNumber(file.resolve(fontDict.get("FirstChar") ?? PDF_NULL), 0);
24
+ const widthsVal = file.resolve(fontDict.get("Widths") ?? PDF_NULL);
25
+ const widths = Array.isArray(widthsVal) ? widthsVal : [];
26
+ const descriptor = file.resolve(fontDict.get("FontDescriptor") ?? PDF_NULL);
27
+ const missing = descriptor instanceof Map ? asNumber(file.resolve(descriptor.get("MissingWidth") ?? PDF_NULL), 0) : 0;
28
+ return (code) => {
29
+ const w = widths[code - first];
30
+ return typeof w === "number" ? w : missing > 0 ? missing : 500;
31
+ };
32
+ }
33
+ function cidWidths(file, fontDict) {
34
+ const descFonts = file.resolve(fontDict.get("DescendantFonts") ?? PDF_NULL);
35
+ const desc0 = Array.isArray(descFonts) ? file.resolve(descFonts[0] ?? PDF_NULL) : PDF_NULL;
36
+ const cidFont = desc0 instanceof Map ? desc0 : /* @__PURE__ */ new Map();
37
+ const dw = asNumber(file.resolve(cidFont.get("DW") ?? PDF_NULL), 1e3);
38
+ const wMap = parseCidW(file, file.resolve(cidFont.get("W") ?? PDF_NULL));
39
+ return (cid) => wMap.get(cid) ?? (dw || 1e3);
40
+ }
41
+ function parseCidW(file, wVal) {
42
+ const out = /* @__PURE__ */ new Map();
43
+ if (!Array.isArray(wVal)) return out;
44
+ let i = 0;
45
+ while (i < wVal.length) {
46
+ const c = file.resolve(wVal[i++]);
47
+ if (typeof c !== "number") break;
48
+ const next = file.resolve(wVal[i] ?? PDF_NULL);
49
+ if (Array.isArray(next)) {
50
+ i++;
51
+ next.forEach((w, k) => {
52
+ if (typeof w === "number") out.set(c + k, w);
53
+ });
54
+ } else if (typeof next === "number") {
55
+ i++;
56
+ const w = file.resolve(wVal[i++] ?? PDF_NULL);
57
+ if (typeof w === "number") for (let cc = c; cc <= next && cc - c < 65536; cc++) out.set(cc, w);
58
+ } else break;
59
+ }
60
+ return out;
61
+ }
62
+ function asName(v) {
63
+ return v instanceof PdfName ? v.value : "";
64
+ }
65
+ function asNumber(v, dflt) {
66
+ return typeof v === "number" ? v : dflt;
67
+ }
68
+ //#endregion
69
+ export { buildContentFont };
@@ -0,0 +1,15 @@
1
+ import { PdfFile } from './document.js';
2
+ import { PdfStream } from '../pdf/objects.js';
3
+ export type DecodedImage = {
4
+ readonly ok: true;
5
+ readonly bytes: Uint8Array;
6
+ readonly format: 'png' | 'jpeg' | 'jpeg2000';
7
+ readonly widthPx: number;
8
+ readonly heightPx: number;
9
+ readonly degraded?: string;
10
+ } | {
11
+ readonly ok: false;
12
+ readonly severity: 'dropped' | 'degraded';
13
+ readonly detail: string;
14
+ };
15
+ export declare function decodePdfImage(file: PdfFile, stream: PdfStream): DecodedImage;
@@ -0,0 +1,442 @@
1
+ import { PDF_NULL, PdfHexString, PdfName, PdfStream } from "../pdf/objects.js";
2
+ import { reversePredictor } from "./predictor.js";
3
+ import { encodePng } from "./png-encode.js";
4
+ import { unzlibSync } from "fflate";
5
+ //#region src/pdf-reader/image-decode.ts
6
+ var MAX_PIXELS = 4e7;
7
+ function decodePdfImage(file, stream) {
8
+ const d = stream.dict;
9
+ const width = intOf(file.get(d, "Width")) || intOf(file.get(d, "W"));
10
+ const height = intOf(file.get(d, "Height")) || intOf(file.get(d, "H"));
11
+ if (width <= 0 || height <= 0) return fail("dropped", "image with no dimensions");
12
+ if (width * height > MAX_PIXELS) return fail("dropped", "image too large to decode");
13
+ if (boolOf(d.get("ImageMask")) || boolOf(d.get("IM"))) return fail("dropped", "stencil image mask not reconstructed");
14
+ const filters = filterNames(file, d);
15
+ const last = filters[filters.length - 1];
16
+ if (last === "DCTDecode" || last === "DCT") {
17
+ const degraded = hasSMask(file, d) ? "image transparency dropped (JPEG carries no alpha)" : void 0;
18
+ return {
19
+ ok: true,
20
+ bytes: applyChainExceptLast(filters, stream.data),
21
+ format: "jpeg",
22
+ widthPx: width,
23
+ heightPx: height,
24
+ ...degraded ? { degraded } : {}
25
+ };
26
+ }
27
+ if (last === "JPXDecode") return {
28
+ ok: true,
29
+ bytes: applyChainExceptLast(filters, stream.data),
30
+ format: "jpeg2000",
31
+ widthPx: width,
32
+ heightPx: height,
33
+ degraded: "JPEG 2000 image — limited viewer support"
34
+ };
35
+ if (last === "CCITTFaxDecode" || last === "CCF" || last === "JBIG2Decode") return fail("dropped", "fax-encoded (CCITT/JBIG2) image not decoded");
36
+ if (last === "LZWDecode" || last === "LZW") return fail("dropped", "LZW-encoded image not decoded");
37
+ const decoded = decodeToSamples(file, stream, filters, width, height);
38
+ if (typeof decoded === "string") return fail("dropped", decoded);
39
+ const alpha = decodeSMask(file, d, width, height);
40
+ const { color, samples } = alpha ? combineAlpha(decoded, alpha) : decoded;
41
+ return {
42
+ ok: true,
43
+ bytes: encodePng(width, height, color, samples),
44
+ format: "png",
45
+ widthPx: width,
46
+ heightPx: height
47
+ };
48
+ }
49
+ function decodeToSamples(file, stream, filters, width, height) {
50
+ const d = stream.dict;
51
+ const raw = decodeChain(file, stream, filters);
52
+ if (!raw) return "undecodable image stream";
53
+ const cs = resolveColorSpace(file, d.get("ColorSpace") ?? d.get("CS"));
54
+ if (!cs) return "unsupported image colour space";
55
+ const bpc = intOf(file.get(d, "BitsPerComponent")) || intOf(file.get(d, "BPC")) || 8;
56
+ const decodeArr = decodeArrayOf(file, d);
57
+ return toColor(cs, unpackSamples(raw, width, height, cs.components, bpc), width * height, bpc, decodeArr);
58
+ }
59
+ function resolveColorSpace(file, csVal) {
60
+ const cs = file.resolve(csVal ?? PDF_NULL);
61
+ if (cs instanceof PdfName) return namedColorSpace(cs.value);
62
+ if (!Array.isArray(cs) || cs.length === 0) return void 0;
63
+ const head = file.resolve(cs[0]);
64
+ const tag = head instanceof PdfName ? head.value : "";
65
+ if (tag === "ICCBased") {
66
+ const profile = file.resolve(cs[1]);
67
+ if (profile instanceof PdfStream) {
68
+ const n = intOf(file.get(profile.dict, "N"));
69
+ if (n === 1) return {
70
+ kind: "gray",
71
+ components: 1
72
+ };
73
+ if (n === 3) return {
74
+ kind: "rgb",
75
+ components: 3
76
+ };
77
+ if (n === 4) return {
78
+ kind: "cmyk",
79
+ components: 4
80
+ };
81
+ const alt = resolveColorSpace(file, profile.dict.get("Alternate"));
82
+ if (alt) return alt;
83
+ }
84
+ return;
85
+ }
86
+ if (tag === "CalGray" || tag === "G") return {
87
+ kind: "gray",
88
+ components: 1
89
+ };
90
+ if (tag === "CalRGB" || tag === "RGB") return {
91
+ kind: "rgb",
92
+ components: 3
93
+ };
94
+ if (tag === "Indexed" || tag === "I") {
95
+ const base = resolveColorSpace(file, cs[1]);
96
+ const hival = intOf(file.resolve(cs[2] ?? PDF_NULL));
97
+ const lookup = valueToBytes(file, cs[3]);
98
+ if (!base || base.kind === "indexed" || !lookup) return void 0;
99
+ return {
100
+ kind: "indexed",
101
+ components: 1,
102
+ base,
103
+ hival,
104
+ lookup
105
+ };
106
+ }
107
+ }
108
+ function namedColorSpace(name) {
109
+ if (name === "DeviceGray" || name === "G" || name === "CalGray") return {
110
+ kind: "gray",
111
+ components: 1
112
+ };
113
+ if (name === "DeviceRGB" || name === "RGB" || name === "CalRGB") return {
114
+ kind: "rgb",
115
+ components: 3
116
+ };
117
+ if (name === "DeviceCMYK" || name === "CMYK") return {
118
+ kind: "cmyk",
119
+ components: 4
120
+ };
121
+ }
122
+ function toColor(cs, s, px, bpc, decode) {
123
+ const maxv = (1 << Math.min(bpc, 15)) * (bpc >= 16 ? 2 : 1) - 1;
124
+ const c01 = (v, comp) => {
125
+ const t = maxv > 0 ? v / maxv : 0;
126
+ if (decode && decode.length >= (comp + 1) * 2) {
127
+ const dmin = decode[comp * 2];
128
+ const dmax = decode[comp * 2 + 1];
129
+ return clamp01(dmin + t * (dmax - dmin));
130
+ }
131
+ return t;
132
+ };
133
+ const to8 = (v, comp) => Math.round(c01(v, comp) * 255);
134
+ if (cs.kind === "gray") {
135
+ const out = new Uint8Array(px);
136
+ for (let i = 0; i < px; i++) out[i] = to8(s[i], 0);
137
+ return {
138
+ color: "gray",
139
+ samples: out
140
+ };
141
+ }
142
+ if (cs.kind === "rgb") {
143
+ const out = new Uint8Array(px * 3);
144
+ for (let i = 0; i < px; i++) {
145
+ out[i * 3] = to8(s[i * 3], 0);
146
+ out[i * 3 + 1] = to8(s[i * 3 + 1], 1);
147
+ out[i * 3 + 2] = to8(s[i * 3 + 2], 2);
148
+ }
149
+ return {
150
+ color: "rgb",
151
+ samples: out
152
+ };
153
+ }
154
+ if (cs.kind === "cmyk") {
155
+ const out = new Uint8Array(px * 3);
156
+ for (let i = 0; i < px; i++) {
157
+ const c = c01(s[i * 4], 0);
158
+ const m = c01(s[i * 4 + 1], 1);
159
+ const y = c01(s[i * 4 + 2], 2);
160
+ const k = c01(s[i * 4 + 3], 3);
161
+ out[i * 3] = Math.round(255 * (1 - c) * (1 - k));
162
+ out[i * 3 + 1] = Math.round(255 * (1 - m) * (1 - k));
163
+ out[i * 3 + 2] = Math.round(255 * (1 - y) * (1 - k));
164
+ }
165
+ return {
166
+ color: "rgb",
167
+ samples: out
168
+ };
169
+ }
170
+ const base = cs.base;
171
+ const lookup = cs.lookup;
172
+ const hival = cs.hival ?? 255;
173
+ const bn = base.components;
174
+ if (base.kind === "gray") {
175
+ const out = new Uint8Array(px);
176
+ for (let i = 0; i < px; i++) out[i] = lookup[Math.min(s[i], hival) * bn] ?? 0;
177
+ return {
178
+ color: "gray",
179
+ samples: out
180
+ };
181
+ }
182
+ const out = new Uint8Array(px * 3);
183
+ for (let i = 0; i < px; i++) {
184
+ const [r, g, b] = paletteRgb(base, lookup, Math.min(s[i], hival) * bn);
185
+ out[i * 3] = r;
186
+ out[i * 3 + 1] = g;
187
+ out[i * 3 + 2] = b;
188
+ }
189
+ return {
190
+ color: "rgb",
191
+ samples: out
192
+ };
193
+ }
194
+ function paletteRgb(base, lookup, off) {
195
+ if (base.kind === "rgb") return [
196
+ lookup[off] ?? 0,
197
+ lookup[off + 1] ?? 0,
198
+ lookup[off + 2] ?? 0
199
+ ];
200
+ if (base.kind === "cmyk") {
201
+ const c = (lookup[off] ?? 0) / 255;
202
+ const m = (lookup[off + 1] ?? 0) / 255;
203
+ const y = (lookup[off + 2] ?? 0) / 255;
204
+ const k = (lookup[off + 3] ?? 0) / 255;
205
+ return [
206
+ Math.round(255 * (1 - c) * (1 - k)),
207
+ Math.round(255 * (1 - m) * (1 - k)),
208
+ Math.round(255 * (1 - y) * (1 - k))
209
+ ];
210
+ }
211
+ const g = lookup[off] ?? 0;
212
+ return [
213
+ g,
214
+ g,
215
+ g
216
+ ];
217
+ }
218
+ function unpackSamples(raw, width, height, ncomp, bpc) {
219
+ const perRow = width * ncomp;
220
+ const out = new Uint16Array(perRow * height);
221
+ const rowBytes = Math.ceil(perRow * bpc / 8);
222
+ for (let y = 0; y < height; y++) {
223
+ const rowOff = y * rowBytes;
224
+ const base = y * perRow;
225
+ if (bpc === 8) for (let i = 0; i < perRow; i++) out[base + i] = raw[rowOff + i] ?? 0;
226
+ else if (bpc === 16) for (let i = 0; i < perRow; i++) out[base + i] = (raw[rowOff + 2 * i] ?? 0) << 8 | (raw[rowOff + 2 * i + 1] ?? 0);
227
+ else {
228
+ const mask = (1 << bpc) - 1;
229
+ let bit = 0;
230
+ for (let i = 0; i < perRow; i++) {
231
+ const bytePos = rowOff + (bit >> 3);
232
+ const shift = 8 - bpc - (bit & 7);
233
+ out[base + i] = ((raw[bytePos] ?? 0) >> shift & mask) >>> 0;
234
+ bit += bpc;
235
+ }
236
+ }
237
+ }
238
+ return out;
239
+ }
240
+ function decodeSMask(file, d, width, height) {
241
+ const sm = file.resolve(d.get("SMask") ?? PDF_NULL);
242
+ if (!(sm instanceof PdfStream)) return void 0;
243
+ const sw = intOf(file.get(sm.dict, "Width"));
244
+ const sh = intOf(file.get(sm.dict, "Height"));
245
+ if (sw <= 0 || sh <= 0) return void 0;
246
+ const decoded = decodeToSamples(file, sm, filterNames(file, sm.dict), sw, sh);
247
+ if (typeof decoded === "string") return void 0;
248
+ const ch = decoded.color === "rgb" ? 3 : 1;
249
+ const gray = new Uint8Array(sw * sh);
250
+ for (let i = 0; i < sw * sh; i++) gray[i] = decoded.samples[i * ch];
251
+ if (sw === width && sh === height) return { data: gray };
252
+ const out = new Uint8Array(width * height);
253
+ for (let y = 0; y < height; y++) {
254
+ const sy = Math.min(sh - 1, Math.floor(y * sh / height));
255
+ for (let x = 0; x < width; x++) {
256
+ const sx = Math.min(sw - 1, Math.floor(x * sw / width));
257
+ out[y * width + x] = gray[sy * sw + sx];
258
+ }
259
+ }
260
+ return { data: out };
261
+ }
262
+ function combineAlpha(color, alpha) {
263
+ const px = alpha.data.length;
264
+ if (color.color === "gray") {
265
+ const out = new Uint8Array(px * 2);
266
+ for (let i = 0; i < px; i++) {
267
+ out[i * 2] = color.samples[i];
268
+ out[i * 2 + 1] = alpha.data[i];
269
+ }
270
+ return {
271
+ color: "gray-alpha",
272
+ samples: out
273
+ };
274
+ }
275
+ const out = new Uint8Array(px * 4);
276
+ for (let i = 0; i < px; i++) {
277
+ out[i * 4] = color.samples[i * 3];
278
+ out[i * 4 + 1] = color.samples[i * 3 + 1];
279
+ out[i * 4 + 2] = color.samples[i * 3 + 2];
280
+ out[i * 4 + 3] = alpha.data[i];
281
+ }
282
+ return {
283
+ color: "rgba",
284
+ samples: out
285
+ };
286
+ }
287
+ function filterNames(file, d) {
288
+ const f = file.resolve(d.get("Filter") ?? PDF_NULL);
289
+ const arr = Array.isArray(f) ? f : [f];
290
+ const out = [];
291
+ for (const x of arr) {
292
+ const r = file.resolve(x);
293
+ if (r instanceof PdfName) out.push(r.value);
294
+ }
295
+ return out;
296
+ }
297
+ function decodeChain(file, stream, filters) {
298
+ let data = stream.data;
299
+ let flate = false;
300
+ for (const f of filters) if (f === "FlateDecode" || f === "Fl") try {
301
+ data = unzlibSync(data);
302
+ flate = true;
303
+ } catch {
304
+ return;
305
+ }
306
+ else if (f === "RunLengthDecode" || f === "RL") data = runLengthDecode(data);
307
+ else if (f === "ASCII85Decode" || f === "A85") data = ascii85Decode(data);
308
+ else if (f === "ASCIIHexDecode" || f === "AHx") data = asciiHexDecode(data);
309
+ else return;
310
+ return flate ? applyPredictor(file, stream.dict, data) : data;
311
+ }
312
+ function applyChainExceptLast(filters, raw) {
313
+ let data = raw;
314
+ for (let i = 0; i < filters.length - 1; i++) {
315
+ const f = filters[i];
316
+ if (f === "FlateDecode" || f === "Fl") try {
317
+ data = unzlibSync(data);
318
+ } catch {}
319
+ else if (f === "RunLengthDecode" || f === "RL") data = runLengthDecode(data);
320
+ else if (f === "ASCII85Decode" || f === "A85") data = ascii85Decode(data);
321
+ else if (f === "ASCIIHexDecode" || f === "AHx") data = asciiHexDecode(data);
322
+ }
323
+ return data;
324
+ }
325
+ function applyPredictor(file, d, data) {
326
+ const parms = decodeParmsOf(file, d);
327
+ if (!parms) return data;
328
+ const predictor = intOf(file.get(parms, "Predictor"));
329
+ if (predictor < 2) return data;
330
+ return reversePredictor(data, {
331
+ predictor,
332
+ colors: intOf(file.get(parms, "Colors")) || 1,
333
+ bitsPerComponent: intOf(file.get(parms, "BitsPerComponent")) || 8,
334
+ columns: intOf(file.get(parms, "Columns")) || 1
335
+ });
336
+ }
337
+ function runLengthDecode(data) {
338
+ const out = [];
339
+ let i = 0;
340
+ while (i < data.length) {
341
+ const len = data[i++];
342
+ if (len === 128) break;
343
+ if (len < 128) for (let j = 0; j <= len && i < data.length; j++) out.push(data[i++]);
344
+ else {
345
+ const b = data[i++] ?? 0;
346
+ for (let j = 0; j < 257 - len; j++) out.push(b);
347
+ }
348
+ }
349
+ return Uint8Array.from(out);
350
+ }
351
+ function ascii85Decode(data) {
352
+ const out = [];
353
+ let tuple = 0;
354
+ let count = 0;
355
+ for (const c of data) {
356
+ if (c === 126) break;
357
+ if (c <= 32) continue;
358
+ if (c === 122 && count === 0) {
359
+ out.push(0, 0, 0, 0);
360
+ continue;
361
+ }
362
+ if (c < 33 || c > 117) continue;
363
+ tuple = tuple * 85 + (c - 33);
364
+ if (++count === 5) {
365
+ out.push(tuple >>> 24 & 255, tuple >>> 16 & 255, tuple >>> 8 & 255, tuple & 255);
366
+ tuple = 0;
367
+ count = 0;
368
+ }
369
+ }
370
+ if (count > 0) {
371
+ for (let i = count; i < 5; i++) tuple = tuple * 85 + 84;
372
+ for (let i = 0; i < count - 1; i++) out.push(tuple >>> 24 - i * 8 & 255);
373
+ }
374
+ return Uint8Array.from(out);
375
+ }
376
+ function asciiHexDecode(data) {
377
+ const out = [];
378
+ let hi = -1;
379
+ for (const c of data) {
380
+ if (c === 62) break;
381
+ const v = hexVal(c);
382
+ if (v < 0) continue;
383
+ if (hi < 0) hi = v;
384
+ else {
385
+ out.push(hi << 4 | v);
386
+ hi = -1;
387
+ }
388
+ }
389
+ if (hi >= 0) out.push(hi << 4);
390
+ return Uint8Array.from(out);
391
+ }
392
+ function decodeParmsOf(file, d) {
393
+ const p = file.resolve(d.get("DecodeParms") ?? d.get("DP") ?? PDF_NULL);
394
+ if (p instanceof Map) return p;
395
+ if (Array.isArray(p)) for (const e of p) {
396
+ const r = file.resolve(e);
397
+ if (r instanceof Map) return r;
398
+ }
399
+ }
400
+ function decodeArrayOf(file, d) {
401
+ const v = file.resolve(d.get("Decode") ?? d.get("D") ?? PDF_NULL);
402
+ if (!Array.isArray(v)) return void 0;
403
+ const nums = v.map((x) => typeof x === "number" ? x : NaN);
404
+ return nums.some((n) => !Number.isFinite(n)) ? void 0 : nums;
405
+ }
406
+ function hasSMask(file, d) {
407
+ return file.resolve(d.get("SMask") ?? PDF_NULL) instanceof PdfStream;
408
+ }
409
+ function valueToBytes(file, v) {
410
+ const r = file.resolve(v ?? PDF_NULL);
411
+ if (r instanceof PdfHexString) return r.bytes;
412
+ if (typeof r === "string") {
413
+ const out = new Uint8Array(r.length);
414
+ for (let i = 0; i < r.length; i++) out[i] = r.charCodeAt(i) & 255;
415
+ return out;
416
+ }
417
+ if (r instanceof PdfStream) return file.streamData(r);
418
+ }
419
+ function intOf(v) {
420
+ return typeof v === "number" ? Math.round(v) : 0;
421
+ }
422
+ function boolOf(v) {
423
+ return v === true;
424
+ }
425
+ function clamp01(x) {
426
+ return x < 0 ? 0 : x > 1 ? 1 : x;
427
+ }
428
+ function hexVal(c) {
429
+ if (c >= 48 && c <= 57) return c - 48;
430
+ if (c >= 65 && c <= 70) return c - 65 + 10;
431
+ if (c >= 97 && c <= 102) return c - 97 + 10;
432
+ return -1;
433
+ }
434
+ function fail(severity, detail) {
435
+ return {
436
+ ok: false,
437
+ severity,
438
+ detail
439
+ };
440
+ }
441
+ //#endregion
442
+ export { decodePdfImage };
@@ -0,0 +1,16 @@
1
+ import { Loss } from '../core/ir/index.js';
2
+ import { PdfFile, PdfPage } from './document.js';
3
+ export interface PdfImage {
4
+ readonly bytes: Uint8Array;
5
+ readonly format: 'png' | 'jpeg' | 'jpeg2000';
6
+ readonly widthPt: number;
7
+ readonly heightPt: number;
8
+ readonly x: number;
9
+ readonly y: number;
10
+ readonly mcid?: number;
11
+ }
12
+ export interface PageImages {
13
+ readonly images: Array<PdfImage>;
14
+ readonly losses: Array<Loss>;
15
+ }
16
+ export declare function collectPageImages(file: PdfFile, page: PdfPage): PageImages;