reamkit 1.17.0 → 1.19.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 (34) hide show
  1. package/dist/esm/core/document-model/types.d.ts +59 -1
  2. package/dist/esm/core/drawingml/colors.js +13 -6
  3. package/dist/esm/core/images.d.ts +2 -2
  4. package/dist/esm/core/images.js +38 -0
  5. package/dist/esm/core/lzw.d.ts +17 -0
  6. package/dist/esm/core/lzw.js +83 -0
  7. package/dist/esm/core/metafile/emf.d.ts +16 -0
  8. package/dist/esm/core/metafile/emf.js +635 -0
  9. package/dist/esm/core/metafile/picture.d.ts +106 -0
  10. package/dist/esm/core/metafile/picture.js +55 -0
  11. package/dist/esm/core/metafile/wmf.d.ts +9 -0
  12. package/dist/esm/core/metafile/wmf.js +371 -0
  13. package/dist/esm/core/po-helpers.d.ts +9 -0
  14. package/dist/esm/core/po-helpers.js +9 -1
  15. package/dist/esm/core/tiff.d.ts +20 -0
  16. package/dist/esm/core/tiff.js +339 -0
  17. package/dist/esm/core/vector.d.ts +5 -0
  18. package/dist/esm/excel/print-model.js +3 -1
  19. package/dist/esm/html/html-writer.js +3 -2
  20. package/dist/esm/layout/page-doc.d.ts +46 -3
  21. package/dist/esm/layout/styled-layout.js +649 -108
  22. package/dist/esm/pdf/styled-page-emitter.js +78 -3
  23. package/dist/esm/pdf/vector-graphics.d.ts +1 -1
  24. package/dist/esm/pdf/vector-graphics.js +2 -1
  25. package/dist/esm/pdf-reader/image-decode.js +7 -75
  26. package/dist/esm/svg/svg-writer.js +1 -1
  27. package/dist/esm/word/document-parser.js +3 -0
  28. package/dist/esm/word/drawing-parser.d.ts +5 -0
  29. package/dist/esm/word/drawing-parser.js +100 -14
  30. package/dist/esm/word/paragraph-properties.js +2 -2
  31. package/dist/esm/word/run-properties.js +2 -2
  32. package/dist/esm/word/xml-helpers.d.ts +12 -0
  33. package/dist/esm/word/xml-helpers.js +23 -3
  34. package/package.json +1 -1
@@ -0,0 +1,106 @@
1
+ import { StrokeStyle, VectorPath } from '../vector.js';
2
+ /** A path drawn by the metafile: filled, stroked, or both. */
3
+ export interface PicturePath {
4
+ readonly kind: 'path';
5
+ readonly paths: ReadonlyArray<VectorPath>;
6
+ /** 6-hex, no leading `#`. Absent when the path is not filled. */
7
+ readonly fillColorHex?: string;
8
+ readonly stroke?: StrokeStyle;
9
+ }
10
+ /** A run of text the metafile puts at a point, in its own logical units. */
11
+ export interface PictureText {
12
+ readonly kind: 'text';
13
+ readonly text: string;
14
+ /** The reference point, in logical units (y DOWN, as the metafile has it). */
15
+ readonly x: number;
16
+ readonly y: number;
17
+ /** Which corner of the text the point names (MS-WMF §2.1.2.4 TextAlignment). */
18
+ readonly alignH: 'left' | 'center' | 'right';
19
+ /** Whether `y` is the text's TOP (the default) or its baseline. */
20
+ readonly alignBaseline: boolean;
21
+ /** Em size in logical units — the height the font was created with. */
22
+ readonly sizeLu: number;
23
+ readonly colorHex: string;
24
+ readonly fontFamily?: string;
25
+ readonly bold?: boolean;
26
+ readonly italic?: boolean;
27
+ /** Tenths of a degree, counter-clockwise — the font's own escapement. */
28
+ readonly escapement?: number;
29
+ }
30
+ /** A bitmap the metafile blits into a rectangle of its own logical frame. */
31
+ export interface PictureImage {
32
+ readonly kind: 'image';
33
+ /** The destination rectangle in logical units (y down). */
34
+ readonly x: number;
35
+ readonly y: number;
36
+ readonly width: number;
37
+ readonly height: number;
38
+ /** The bitmap as a standalone file (PNG), ready for the resource store. */
39
+ readonly png: Uint8Array;
40
+ }
41
+ export type PicturePrim = PicturePath | PictureText | PictureImage;
42
+ /**
43
+ * One metafile, read: its primitives and the logical box they are drawn in.
44
+ * Coordinates are the metafile's own, with y running DOWN; the caller maps the
45
+ * box onto the picture's frame.
46
+ */
47
+ export interface MetaPicture {
48
+ readonly left: number;
49
+ readonly top: number;
50
+ readonly width: number;
51
+ readonly height: number;
52
+ readonly prims: ReadonlyArray<PicturePrim>;
53
+ /** Records the reader knew of but did not draw, for a loss note. */
54
+ readonly skipped: ReadonlyArray<string>;
55
+ }
56
+ /** A pen, a brush and a font, as the device context holds them. */
57
+ export interface MetaPen {
58
+ readonly kind: 'pen';
59
+ readonly colorHex: string;
60
+ readonly widthLu: number;
61
+ readonly style: 'solid' | 'dash' | 'dot' | 'dashdot' | 'dashdotdot' | 'none';
62
+ }
63
+ export interface MetaBrush {
64
+ readonly kind: 'brush';
65
+ readonly colorHex: string;
66
+ /** `null` for BS_HOLLOW/BS_NULL — a brush that paints nothing. */
67
+ readonly hollow: boolean;
68
+ }
69
+ export interface MetaFont {
70
+ readonly kind: 'font';
71
+ readonly heightLu: number;
72
+ readonly family?: string;
73
+ readonly bold?: boolean;
74
+ readonly italic?: boolean;
75
+ readonly escapement?: number;
76
+ }
77
+ export type MetaObject = MetaPen | MetaBrush | MetaFont;
78
+ /** The device context: everything a record draws THROUGH. */
79
+ export interface DeviceContext {
80
+ pen: MetaPen;
81
+ brush: MetaBrush;
82
+ font?: MetaFont;
83
+ textColorHex: string;
84
+ bkColorHex: string;
85
+ /** MS-WMF §2.1.1.9 — TRANSPARENT leaves the background of text unpainted. */
86
+ bkOpaque: boolean;
87
+ alignH: 'left' | 'center' | 'right';
88
+ alignBaseline: boolean;
89
+ fillRule: 'nonzero' | 'evenodd';
90
+ x: number;
91
+ y: number;
92
+ /** The world→page transform, as `[a, b, c, d, e, f]`. */
93
+ transform: readonly [number, number, number, number, number, number];
94
+ }
95
+ export declare const DEFAULT_PEN: MetaPen;
96
+ export declare const DEFAULT_BRUSH: MetaBrush;
97
+ /** A device context in its documented initial state (MS-WMF §3.1.5). */
98
+ export declare function newDeviceContext(): DeviceContext;
99
+ export declare function cloneDc(dc: DeviceContext): DeviceContext;
100
+ /** A COLORREF (`0x00bbggrr`) as the 6-hex this codebase's colours use. */
101
+ export declare function colorRef(v: number): string;
102
+ /** Apply the world transform to a point. */
103
+ export declare function applyTransform(t: DeviceContext['transform'], x: number, y: number): {
104
+ x: number;
105
+ y: number;
106
+ };
@@ -0,0 +1,55 @@
1
+ //#region src/core/metafile/picture.ts
2
+ var DEFAULT_PEN = {
3
+ kind: "pen",
4
+ colorHex: "000000",
5
+ widthLu: 1,
6
+ style: "solid"
7
+ };
8
+ var DEFAULT_BRUSH = {
9
+ kind: "brush",
10
+ colorHex: "FFFFFF",
11
+ hollow: false
12
+ };
13
+ /** A device context in its documented initial state (MS-WMF §3.1.5). */
14
+ function newDeviceContext() {
15
+ return {
16
+ pen: DEFAULT_PEN,
17
+ brush: DEFAULT_BRUSH,
18
+ textColorHex: "000000",
19
+ bkColorHex: "FFFFFF",
20
+ bkOpaque: true,
21
+ alignH: "left",
22
+ alignBaseline: false,
23
+ fillRule: "evenodd",
24
+ x: 0,
25
+ y: 0,
26
+ transform: [
27
+ 1,
28
+ 0,
29
+ 0,
30
+ 1,
31
+ 0,
32
+ 0
33
+ ]
34
+ };
35
+ }
36
+ function cloneDc(dc) {
37
+ return { ...dc };
38
+ }
39
+ /** A COLORREF (`0x00bbggrr`) as the 6-hex this codebase's colours use. */
40
+ function colorRef(v) {
41
+ return [
42
+ v & 255,
43
+ v >>> 8 & 255,
44
+ v >>> 16 & 255
45
+ ].map((c) => c.toString(16).padStart(2, "0")).join("").toUpperCase();
46
+ }
47
+ /** Apply the world transform to a point. */
48
+ function applyTransform(t, x, y) {
49
+ return {
50
+ x: t[0] * x + t[2] * y + t[4],
51
+ y: t[1] * x + t[3] * y + t[5]
52
+ };
53
+ }
54
+ //#endregion
55
+ export { applyTransform, cloneDc, colorRef, newDeviceContext };
@@ -0,0 +1,9 @@
1
+ import { MetaPicture } from './picture.js';
2
+ /** Whether the bytes open with a WMF header — placeable or bare (§2.3.2.2). */
3
+ export declare function isWmf(bytes: Uint8Array): boolean;
4
+ /**
5
+ * Read a WMF into its primitives.
6
+ *
7
+ * @throws Error when the bytes are not a WMF.
8
+ */
9
+ export declare function readWmf(bytes: Uint8Array): MetaPicture;
@@ -0,0 +1,371 @@
1
+ import { PathBuilder } from "../vector.js";
2
+ import { cloneDc, colorRef, newDeviceContext } from "./picture.js";
3
+ import { ellipseSegments } from "./emf.js";
4
+ //#region src/core/metafile/wmf.ts
5
+ var PLACEABLE_KEY = 2596720087;
6
+ /** Whether the bytes open with a WMF header — placeable or bare (§2.3.2.2). */
7
+ function isWmf(bytes) {
8
+ if (bytes.length < 18) return false;
9
+ const v = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
10
+ if (v.getUint32(0, true) === PLACEABLE_KEY) return true;
11
+ const type = v.getUint16(0, true);
12
+ const headerWords = v.getUint16(2, true);
13
+ return (type === 1 || type === 2) && headerWords === 9;
14
+ }
15
+ var RECORD_NAMES = new Map([
16
+ [2368, "bitmap"],
17
+ [2881, "bitmap"],
18
+ [3907, "bitmap"],
19
+ [2338, "pie"],
20
+ [2096, "chord"],
21
+ [2071, "arc"],
22
+ [1049, "flood fill"],
23
+ [1352, "flood fill"],
24
+ [247, "palette"],
25
+ [1574, "escape"],
26
+ [765, "region"],
27
+ [552, "region fill"],
28
+ [1065, "region frame"],
29
+ [298, "region invert"],
30
+ [299, "region paint"]
31
+ ]);
32
+ /**
33
+ * Read a WMF into its primitives.
34
+ *
35
+ * @throws Error when the bytes are not a WMF.
36
+ */
37
+ function readWmf(bytes) {
38
+ if (!isWmf(bytes)) throw new Error("WMF: not a Windows metafile");
39
+ const v = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
40
+ const placeable = v.getUint32(0, true) === PLACEABLE_KEY;
41
+ const frame = placeable ? {
42
+ left: v.getInt16(6, true),
43
+ top: v.getInt16(8, true),
44
+ right: v.getInt16(10, true),
45
+ bottom: v.getInt16(12, true)
46
+ } : void 0;
47
+ const prims = [];
48
+ const skipped = /* @__PURE__ */ new Set();
49
+ const objects = [];
50
+ const put = (obj) => {
51
+ const free = objects.indexOf(void 0);
52
+ if (free >= 0) objects[free] = obj;
53
+ else objects.push(obj);
54
+ };
55
+ const stack = [];
56
+ let dc = newDeviceContext();
57
+ let win = {
58
+ x: 0,
59
+ y: 0,
60
+ cx: 0,
61
+ cy: 0
62
+ };
63
+ const strokeOf = () => {
64
+ if (dc.pen.style === "none") return void 0;
65
+ const w = Math.max(1, dc.pen.widthLu);
66
+ return {
67
+ colorHex: dc.pen.colorHex,
68
+ widthPt: w,
69
+ ...dc.pen.style === "solid" ? {} : { dash: dc.pen.style === "dot" ? [w, 2 * w] : [4 * w, 3 * w] }
70
+ };
71
+ };
72
+ const paint = (segments, fill, stroke) => {
73
+ if (segments.length === 0) return;
74
+ const path = {
75
+ segments,
76
+ fillRule: dc.fillRule
77
+ };
78
+ const st = stroke ? strokeOf() : void 0;
79
+ const fillHex = fill && !dc.brush.hollow ? dc.brush.colorHex : void 0;
80
+ if (fillHex === void 0 && !st) return;
81
+ prims.push({
82
+ kind: "path",
83
+ paths: [path],
84
+ ...fillHex !== void 0 ? { fillColorHex: fillHex } : {},
85
+ ...st ? { stroke: st } : {}
86
+ });
87
+ };
88
+ const rectSegments = (l, t, r, b) => new PathBuilder().moveTo(l, t).lineTo(r, t).lineTo(r, b).lineTo(l, b).close().build().segments;
89
+ let off = placeable ? 22 : 0;
90
+ off += 18;
91
+ let guard = 0;
92
+ while (off + 6 <= bytes.length && guard++ < 5e5) {
93
+ const size = v.getUint32(off, true);
94
+ const fn = v.getUint16(off + 4, true);
95
+ if (size < 3 || off + size * 2 > bytes.length) break;
96
+ const p = (i) => v.getInt16(off + 6 + i * 2, true);
97
+ const pu = (i) => v.getUint16(off + 6 + i * 2, true);
98
+ const p32 = (i) => v.getUint32(off + 6 + i * 2, true);
99
+ switch (fn) {
100
+ case 0:
101
+ off = bytes.length;
102
+ continue;
103
+ case 523:
104
+ win = {
105
+ ...win,
106
+ x: p(1),
107
+ y: p(0)
108
+ };
109
+ break;
110
+ case 524:
111
+ win = {
112
+ ...win,
113
+ cx: p(1),
114
+ cy: p(0)
115
+ };
116
+ break;
117
+ case 30:
118
+ stack.push(cloneDc(dc));
119
+ break;
120
+ case 295:
121
+ {
122
+ const back = Math.max(1, -p(0));
123
+ for (let i = 0; i < back && stack.length > 0; i++) dc = stack.pop();
124
+ }
125
+ break;
126
+ case 301:
127
+ {
128
+ const obj = objects[pu(0)];
129
+ if (obj?.kind === "pen") dc.pen = obj;
130
+ else if (obj?.kind === "brush") dc.brush = obj;
131
+ else if (obj?.kind === "font") dc.font = obj;
132
+ }
133
+ break;
134
+ case 496:
135
+ objects[pu(0)] = void 0;
136
+ break;
137
+ case 762:
138
+ put({
139
+ kind: "pen",
140
+ style: penStyle(pu(0)),
141
+ widthLu: p(1),
142
+ colorHex: colorRef(p32(3))
143
+ });
144
+ break;
145
+ case 764:
146
+ put({
147
+ kind: "brush",
148
+ colorHex: colorRef(p32(1)),
149
+ hollow: pu(0) === 1
150
+ });
151
+ break;
152
+ case 763:
153
+ put(readLogFont(v, bytes, off + 6));
154
+ break;
155
+ case 258:
156
+ dc.bkOpaque = pu(0) === 2;
157
+ break;
158
+ case 262:
159
+ dc.fillRule = pu(0) === 2 ? "nonzero" : "evenodd";
160
+ break;
161
+ case 302:
162
+ {
163
+ const f = pu(0);
164
+ dc.alignH = (f & 6) === 6 ? "center" : (f & 2) === 2 ? "right" : "left";
165
+ dc.alignBaseline = (f & 24) === 24;
166
+ }
167
+ break;
168
+ case 521:
169
+ dc.textColorHex = colorRef(p32(0));
170
+ break;
171
+ case 513:
172
+ dc.bkColorHex = colorRef(p32(0));
173
+ break;
174
+ case 532:
175
+ dc.x = p(1);
176
+ dc.y = p(0);
177
+ break;
178
+ case 531:
179
+ {
180
+ const x = p(1);
181
+ const y = p(0);
182
+ paint([{
183
+ op: "move",
184
+ x: dc.x,
185
+ y: dc.y
186
+ }, {
187
+ op: "line",
188
+ x,
189
+ y
190
+ }], false, true);
191
+ dc.x = x;
192
+ dc.y = y;
193
+ }
194
+ break;
195
+ case 1051:
196
+ paint(rectSegments(p(3), p(2), p(1), p(0)), true, true);
197
+ break;
198
+ case 1048:
199
+ paint(ellipseSegments((x, y) => ({
200
+ x,
201
+ y
202
+ }), p(3), p(2), p(1), p(0)), true, true);
203
+ break;
204
+ case 1564:
205
+ paint(rectSegments(p(5), p(4), p(3), p(2)), true, true);
206
+ break;
207
+ case 1565:
208
+ {
209
+ const rop = p32(0);
210
+ const h = p(2);
211
+ const w = p(3);
212
+ const y = p(4);
213
+ const x = p(5);
214
+ const hex = rop === 66 ? "000000" : rop === 16711778 ? "FFFFFF" : void 0;
215
+ const brush = dc.brush;
216
+ if (hex !== void 0) dc.brush = {
217
+ kind: "brush",
218
+ colorHex: hex,
219
+ hollow: false
220
+ };
221
+ paint(rectSegments(x, y, x + w, y + h), true, false);
222
+ dc.brush = brush;
223
+ }
224
+ break;
225
+ case 804:
226
+ case 805:
227
+ {
228
+ const count = pu(0);
229
+ const pts = readPoints(v, off + 8, count);
230
+ const closed = fn === 804;
231
+ paint(polySegments(pts, closed), closed, true);
232
+ }
233
+ break;
234
+ case 1336:
235
+ {
236
+ const polys = pu(0);
237
+ const counts = [];
238
+ for (let i = 0; i < polys; i++) counts.push(v.getUint16(off + 8 + i * 2, true));
239
+ let at = off + 8 + polys * 2;
240
+ const segs = [];
241
+ for (const c of counts) {
242
+ segs.push(...polySegments(readPoints(v, at, c), true));
243
+ at += c * 4;
244
+ }
245
+ paint(segs, true, true);
246
+ }
247
+ break;
248
+ case 1313:
249
+ {
250
+ const count = pu(0);
251
+ const text = readString(bytes, off + 8, count, false);
252
+ const words = count + 1 >> 1;
253
+ pushText(prims, dc, text, p(1 + words + 1), p(1 + words));
254
+ }
255
+ break;
256
+ case 2610:
257
+ {
258
+ const y = p(0);
259
+ const x = p(1);
260
+ const count = pu(2);
261
+ const hasRect = (pu(3) & 6) !== 0;
262
+ const text = readString(bytes, off + 6 + (4 + (hasRect ? 4 : 0)) * 2, count, false);
263
+ pushText(prims, dc, text, x, y);
264
+ }
265
+ break;
266
+ default:
267
+ {
268
+ const name = RECORD_NAMES.get(fn);
269
+ if (name) skipped.add(name);
270
+ }
271
+ break;
272
+ }
273
+ off += size * 2;
274
+ }
275
+ const box = frame ?? {
276
+ left: win.x,
277
+ top: win.y,
278
+ right: win.x + (win.cx || 1e3),
279
+ bottom: win.y + (win.cy || 1e3)
280
+ };
281
+ return {
282
+ left: box.left,
283
+ top: box.top,
284
+ width: Math.max(1, Math.abs(box.right - box.left)),
285
+ height: Math.max(1, Math.abs(box.bottom - box.top)),
286
+ prims,
287
+ skipped: [...skipped]
288
+ };
289
+ }
290
+ function pushText(prims, dc, text, x, y) {
291
+ if (text.trim() === "") return;
292
+ prims.push({
293
+ kind: "text",
294
+ text,
295
+ x,
296
+ y,
297
+ alignH: dc.alignH,
298
+ alignBaseline: dc.alignBaseline,
299
+ sizeLu: Math.abs(dc.font?.heightLu ?? 12),
300
+ colorHex: dc.textColorHex,
301
+ ...dc.font?.family ? { fontFamily: dc.font.family } : {},
302
+ ...dc.font?.bold ? { bold: true } : {},
303
+ ...dc.font?.italic ? { italic: true } : {},
304
+ ...dc.font?.escapement ? { escapement: dc.font.escapement } : {}
305
+ });
306
+ }
307
+ function penStyle(style) {
308
+ switch (style & 15) {
309
+ case 1: return "dash";
310
+ case 2: return "dot";
311
+ case 3: return "dashdot";
312
+ case 4: return "dashdotdot";
313
+ case 5: return "none";
314
+ default: return "solid";
315
+ }
316
+ }
317
+ function readLogFont(v, bytes, at) {
318
+ const height = v.getInt16(at, true);
319
+ const escapement = v.getInt16(at + 4, true);
320
+ const weight = v.getInt16(at + 8, true);
321
+ const italic = bytes[at + 10] !== 0;
322
+ const face = readString(bytes, at + 18, 32, false).replace(/\0.*$/u, "");
323
+ return {
324
+ kind: "font",
325
+ heightLu: height,
326
+ ...face ? { family: face } : {},
327
+ ...weight >= 600 ? { bold: true } : {},
328
+ ...italic ? { italic: true } : {},
329
+ ...escapement ? { escapement } : {}
330
+ };
331
+ }
332
+ function readString(bytes, at, count, wide) {
333
+ let out = "";
334
+ for (let i = 0; i < count; i++) {
335
+ const o = at + (wide ? i * 2 : i);
336
+ if (o >= bytes.length) break;
337
+ const code = wide ? bytes[o] | (bytes[o + 1] ?? 0) << 8 : bytes[o];
338
+ if (code === 0) break;
339
+ out += String.fromCharCode(code);
340
+ }
341
+ return out;
342
+ }
343
+ function readPoints(v, at, count) {
344
+ const out = [];
345
+ for (let i = 0; i < count; i++) {
346
+ const o = at + i * 4;
347
+ if (o + 4 > v.byteLength) break;
348
+ out.push({
349
+ x: v.getInt16(o, true),
350
+ y: v.getInt16(o + 2, true)
351
+ });
352
+ }
353
+ return out;
354
+ }
355
+ function polySegments(pts, closed) {
356
+ if (pts.length === 0) return [];
357
+ const segs = [{
358
+ op: "move",
359
+ x: pts[0].x,
360
+ y: pts[0].y
361
+ }];
362
+ for (let i = 1; i < pts.length; i++) segs.push({
363
+ op: "line",
364
+ x: pts[i].x,
365
+ y: pts[i].y
366
+ });
367
+ if (closed) segs.push({ op: "close" });
368
+ return segs;
369
+ }
370
+ //#endregion
371
+ export { isWmf, readWmf };
@@ -34,6 +34,15 @@ export declare function poAttrLocal(node: PoNode | undefined, name: string): str
34
34
  export declare function poIsLocal(node: PoNode | undefined, name: string): boolean;
35
35
  /** {@link poAttr} parsed as a finite number, or undefined when absent/non-numeric. */
36
36
  export declare function poIntAttr(node: PoNode | undefined, name: string): number | undefined;
37
+ /**
38
+ * §22.9.2.15 ST_UniversalMeasure — a number with a UNIT (`"28.35pt"`, `"1cm"`)
39
+ * as twips. Producers write whole page geometries, tab stops and indents this
40
+ * way; read as a plain number they are nothing at all.
41
+ *
42
+ * @param raw The attribute value.
43
+ * @returns The measure in twips, or undefined when it names no unit.
44
+ */
45
+ export declare function universalMeasureTwips(raw: string): number | undefined;
37
46
  /** Shorthand for the `val` attribute (`@w:val`/…). */
38
47
  export declare function poVal(node: PoNode | undefined): string | undefined;
39
48
  /**
@@ -76,6 +76,14 @@ var MEASURE_TWIPS = new Map([
76
76
  ["cm", 1440 / 2.54],
77
77
  ["mm", 144 / 2.54]
78
78
  ]);
79
+ /**
80
+ * §22.9.2.15 ST_UniversalMeasure — a number with a UNIT (`"28.35pt"`, `"1cm"`)
81
+ * as twips. Producers write whole page geometries, tab stops and indents this
82
+ * way; read as a plain number they are nothing at all.
83
+ *
84
+ * @param raw The attribute value.
85
+ * @returns The measure in twips, or undefined when it names no unit.
86
+ */
79
87
  function universalMeasureTwips(raw) {
80
88
  const m = /^\s*(-?[0-9]+(?:\.[0-9]+)?)(pt|pc|pi|in|cm|mm)\s*$/iu.exec(raw);
81
89
  if (!m) return void 0;
@@ -134,4 +142,4 @@ function poFindDescendant(node, tag) {
134
142
  }
135
143
  }
136
144
  //#endregion
137
- export { poAttr, poAttrLocal, poChildren, poChildrenWith, poFindByPath, poFindDescendant, poFirstChild, poIntAttr, poIs, poIsLocal, poTag, poText, poToggle, poVal };
145
+ export { poAttr, poAttrLocal, poChildren, poChildrenWith, poFindByPath, poFindDescendant, poFirstChild, poIntAttr, poIs, poIsLocal, poTag, poText, poToggle, poVal, universalMeasureTwips };
@@ -0,0 +1,20 @@
1
+ /** One decoded TIFF image: 8-bit chunky samples plus an optional alpha plane. */
2
+ export interface DecodedTiff {
3
+ readonly width: number;
4
+ readonly height: number;
5
+ /** Samples per pixel in {@link data} — 1 (grey), 3 (RGB) or 4 (CMYK). */
6
+ readonly channels: 1 | 3 | 4;
7
+ /** Row-major 8-bit samples, `width * height * channels` long. */
8
+ readonly data: Uint8Array;
9
+ /** One byte per pixel when the file carries an alpha channel. */
10
+ readonly alpha?: Uint8Array;
11
+ }
12
+ /** Whether the bytes open with a TIFF header (§2: `II*\0` or `MM\0*`). */
13
+ export declare function isTiff(bytes: Uint8Array): boolean;
14
+ /**
15
+ * Decode the first image of a baseline TIFF into 8-bit chunky samples.
16
+ *
17
+ * @throws Error when the file is malformed or uses a feature outside baseline
18
+ * TIFF (planar separation, JPEG/fax compression, floating-point samples).
19
+ */
20
+ export declare function decodeTiff(bytes: Uint8Array): DecodedTiff;