reamkit 1.27.0 → 1.29.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 +6 -5
- package/dist/esm/core/converter/ream.d.ts +8 -9
- package/dist/esm/core/converter/ream.js +0 -1
- package/dist/esm/core/document-model/types.d.ts +5 -3
- package/dist/esm/core/font/index.d.ts +1 -0
- package/dist/esm/core/font/ligatures.d.ts +17 -0
- package/dist/esm/core/font/ligatures.js +49 -0
- package/dist/esm/core/font/ttf-parser.d.ts +2 -1
- package/dist/esm/core/font/ttf-parser.js +11 -2
- package/dist/esm/core/fonts/remote-fonts.d.ts +1 -1
- package/dist/esm/core/fonts/remote-fonts.js +47 -2
- package/dist/esm/core/fonts/scripts.js +10 -5
- package/dist/esm/excel/header-footer.js +53 -8
- package/dist/esm/layout/styled-layout.js +53 -3
- package/dist/esm/pdf/cid-font.js +35 -8
- package/dist/esm/pdf-reader/annot-draw.js +114 -1
- package/dist/esm/pdf-reader/annots.d.ts +0 -14
- package/dist/esm/pdf-reader/annots.js +13 -1
- package/dist/esm/pdf-reader/ccitt.d.ts +2 -3
- package/dist/esm/pdf-reader/ccitt.js +32 -4
- package/dist/esm/pdf-reader/cff-outline.d.ts +36 -0
- package/dist/esm/pdf-reader/cff-outline.js +1122 -0
- package/dist/esm/pdf-reader/cmap.js +16 -6
- package/dist/esm/pdf-reader/content.d.ts +91 -0
- package/dist/esm/pdf-reader/content.js +156 -60
- package/dist/esm/pdf-reader/dingbats.d.ts +11 -0
- package/dist/esm/pdf-reader/dingbats.js +1033 -0
- package/dist/esm/pdf-reader/display.js +41 -1
- package/dist/esm/pdf-reader/document.d.ts +8 -0
- package/dist/esm/pdf-reader/document.js +26 -9
- package/dist/esm/pdf-reader/embedded-fonts.d.ts +11 -0
- package/dist/esm/pdf-reader/embedded-fonts.js +14 -1
- package/dist/esm/pdf-reader/encodings.d.ts +25 -0
- package/dist/esm/pdf-reader/encodings.js +110 -0
- package/dist/esm/pdf-reader/flow-build.d.ts +15 -4
- package/dist/esm/pdf-reader/flow-build.js +24 -11
- package/dist/esm/pdf-reader/font.js +329 -8
- package/dist/esm/pdf-reader/glyf-outline.d.ts +43 -0
- package/dist/esm/pdf-reader/glyf-outline.js +351 -0
- package/dist/esm/pdf-reader/glyph-names.js +20 -0
- package/dist/esm/pdf-reader/icc.d.ts +10 -0
- package/dist/esm/pdf-reader/icc.js +210 -0
- package/dist/esm/pdf-reader/image-decode.d.ts +4 -3
- package/dist/esm/pdf-reader/image-decode.js +85 -64
- package/dist/esm/pdf-reader/images.d.ts +6 -0
- package/dist/esm/pdf-reader/images.js +50 -7
- package/dist/esm/pdf-reader/jbig2.js +104 -19
- package/dist/esm/pdf-reader/layout.js +1531 -55
- package/dist/esm/pdf-reader/math-rows.d.ts +23 -0
- package/dist/esm/pdf-reader/math-rows.js +198 -0
- package/dist/esm/pdf-reader/predefined-cmap.d.ts +21 -0
- package/dist/esm/pdf-reader/predefined-cmap.js +102 -0
- package/dist/esm/pdf-reader/reader.d.ts +6 -9
- package/dist/esm/pdf-reader/reader.js +34 -21
- package/dist/esm/pdf-reader/shading.d.ts +81 -2
- package/dist/esm/pdf-reader/shading.js +191 -25
- package/dist/esm/pdf-reader/stream-filters.d.ts +6 -0
- package/dist/esm/pdf-reader/stream-filters.js +67 -0
- package/dist/esm/pdf-reader/tagged.js +1 -1
- package/dist/esm/pdf-reader/text-rules.js +83 -10
- package/dist/esm/pdf-reader/text.js +82 -3
- package/dist/esm/pdf-reader/type1-outline.d.ts +21 -0
- package/dist/esm/pdf-reader/type1-outline.js +576 -0
- package/dist/esm/pdf-reader/vector.d.ts +2 -0
- package/dist/esm/pdf-reader/vector.js +44 -4
- package/dist/esm/word/document-parser.js +4 -1
- package/dist/esm/word/docx-writer.js +28 -11
- package/package.json +1 -1
|
@@ -32,7 +32,8 @@ function parseToUnicodeCMap(bytes) {
|
|
|
32
32
|
if (src.kind !== "hexstr") continue;
|
|
33
33
|
const dst = lexer.nextToken();
|
|
34
34
|
if (dst.kind !== "hexstr") continue;
|
|
35
|
-
|
|
35
|
+
const text = stated(utf16be(dst.bytes));
|
|
36
|
+
if (text !== void 0) map.set(bytesToInt(src.bytes), text);
|
|
36
37
|
}
|
|
37
38
|
else if (tok.value === "beginbfrange") for (;;) {
|
|
38
39
|
const lo = lexer.nextToken();
|
|
@@ -44,14 +45,17 @@ function parseToUnicodeCMap(bytes) {
|
|
|
44
45
|
const hiN = bytesToInt(hi.bytes);
|
|
45
46
|
const dst = lexer.nextToken();
|
|
46
47
|
if (dst.kind === "hexstr") {
|
|
47
|
-
const base = utf16be(dst.bytes);
|
|
48
|
-
for (let i = 0; loN + i <= hiN && i < MAX_RANGE; i++) map.set(loN + i, incString(base, i));
|
|
48
|
+
const base = stated(utf16be(dst.bytes));
|
|
49
|
+
if (base !== void 0) for (let i = 0; loN + i <= hiN && i < MAX_RANGE; i++) map.set(loN + i, incString(base, i));
|
|
49
50
|
} else if (dst.kind === "arrayOpen") {
|
|
50
51
|
let i = 0;
|
|
51
52
|
for (;;) {
|
|
52
53
|
const el = lexer.nextToken();
|
|
53
54
|
if (el.kind === "arrayClose" || el.kind === "eof") break;
|
|
54
|
-
if (el.kind
|
|
55
|
+
if (el.kind !== "hexstr") continue;
|
|
56
|
+
const text = stated(utf16be(el.bytes));
|
|
57
|
+
if (text !== void 0) map.set(loN + i, text);
|
|
58
|
+
i++;
|
|
55
59
|
}
|
|
56
60
|
}
|
|
57
61
|
}
|
|
@@ -61,6 +65,9 @@ function parseToUnicodeCMap(bytes) {
|
|
|
61
65
|
codeBytes
|
|
62
66
|
};
|
|
63
67
|
}
|
|
68
|
+
function stated(text) {
|
|
69
|
+
for (const ch of text) if (ch !== "\0") return text;
|
|
70
|
+
}
|
|
64
71
|
function bytesToInt(bytes) {
|
|
65
72
|
let n = 0;
|
|
66
73
|
for (const b of bytes) n = n * 256 + b;
|
|
@@ -74,8 +81,11 @@ function utf16be(bytes) {
|
|
|
74
81
|
}
|
|
75
82
|
function incString(base, i) {
|
|
76
83
|
if (i === 0) return base;
|
|
77
|
-
|
|
78
|
-
return base;
|
|
84
|
+
const chars = [...base];
|
|
85
|
+
if (chars.length === 0) return base;
|
|
86
|
+
const last = chars[chars.length - 1].codePointAt(0) + i;
|
|
87
|
+
if (last > 1114111 || last >= 55296 && last <= 57343) return base;
|
|
88
|
+
return chars.slice(0, -1).join("") + String.fromCodePoint(last);
|
|
79
89
|
}
|
|
80
90
|
//#endregion
|
|
81
91
|
export { parseToUnicodeCMap };
|
|
@@ -11,10 +11,25 @@ import { PdfDict, PdfStream } from '../pdf/objects.js';
|
|
|
11
11
|
export interface ContentFont {
|
|
12
12
|
/** Bytes per character code: simple fonts read 1 byte/code, Type0 reads 2. */
|
|
13
13
|
readonly bytesPerCode: 1 | 2;
|
|
14
|
+
/**
|
|
15
|
+
* §9.7.6.2 — how a shown string breaks into codes, where the CMap is not
|
|
16
|
+
* fixed-width. A named CMap like `90ms-RKSJ-H` mixes one-byte and two-byte
|
|
17
|
+
* codes, and split down the middle a Japanese line came apart into nonsense.
|
|
18
|
+
* Absent means the fixed width above.
|
|
19
|
+
*/
|
|
20
|
+
readonly splitCodes?: (bytes: Uint8Array) => Array<number>;
|
|
14
21
|
/** Decode a sequence of character codes to a Unicode string. */
|
|
15
22
|
decode: (codes: ReadonlyArray<number>) => string;
|
|
16
23
|
/** Glyph advance for one code, in 1000-unit text space. */
|
|
17
24
|
width: (code: number) => number;
|
|
25
|
+
/**
|
|
26
|
+
* §9.4.4 / §9.7.4.3 — the face sets its text DOWN the page, not across, and
|
|
27
|
+
* the pen advances by the vertical displacement `w1` rather than by `w0`.
|
|
28
|
+
* A `…-V` CMap asks for this; `/DW2`'s default `[880 -1000]` is one em down.
|
|
29
|
+
* The number here is that displacement in 1000-unit text space, and it is
|
|
30
|
+
* negative because the page's y runs up.
|
|
31
|
+
*/
|
|
32
|
+
readonly verticalAdvance?: (code: number) => number;
|
|
18
33
|
/** §9.6.2 — the face's own `/BaseFont` name, for a document that embeds it. */
|
|
19
34
|
readonly name?: string;
|
|
20
35
|
/** §9.8.1 — the face is a bold one (weight, the ForceBold flag, or its name). */
|
|
@@ -27,6 +42,19 @@ export interface ContentFont {
|
|
|
27
42
|
* procedure paints, in the resources the font states.
|
|
28
43
|
*/
|
|
29
44
|
readonly type3?: Type3Face;
|
|
45
|
+
/**
|
|
46
|
+
* §9.6.6 — the OUTLINE a code draws, for a code that stands for no
|
|
47
|
+
* character. A face that can say what its characters are never has one:
|
|
48
|
+
* this is the last resort before a blank page.
|
|
49
|
+
*/
|
|
50
|
+
readonly outline?: GlyphOutline;
|
|
51
|
+
}
|
|
52
|
+
/** §9.6.6 — the outlines of a face read by glyph index, and their glyph space. */
|
|
53
|
+
export interface GlyphOutline {
|
|
54
|
+
/** Glyph space to text space, as a Type 3 font's `/FontMatrix` is. */
|
|
55
|
+
readonly matrix: Matrix;
|
|
56
|
+
/** The contours one code draws, or `undefined` where it draws none. */
|
|
57
|
+
readonly path: (code: number) => Array<PathSeg> | undefined;
|
|
30
58
|
}
|
|
31
59
|
/** §9.6.5 — the parts of a Type 3 font a caller needs to run its glyphs. */
|
|
32
60
|
export interface Type3Face {
|
|
@@ -94,6 +122,12 @@ export interface TextRun {
|
|
|
94
122
|
* fill colour still standing from before is not what the page shows.
|
|
95
123
|
*/
|
|
96
124
|
readonly fillPatternName?: string;
|
|
125
|
+
/**
|
|
126
|
+
* §8.7.4.5 — the glyphs are filled with a SHADING pattern: a sweep from one
|
|
127
|
+
* colour to another, of which the run carries the middle. The colour is not
|
|
128
|
+
* lost, the shape of it is.
|
|
129
|
+
*/
|
|
130
|
+
readonly gradientFill?: boolean;
|
|
97
131
|
/**
|
|
98
132
|
* §9.3.6 — the page painted these glyphs NOWHERE: mode 3 shows nothing and
|
|
99
133
|
* mode 7 only adds to the clip. A scanned page carries its recognised words
|
|
@@ -157,6 +191,8 @@ export interface ImagePlacement {
|
|
|
157
191
|
*/
|
|
158
192
|
readonly fillHex: string;
|
|
159
193
|
readonly mcid?: number;
|
|
194
|
+
/** §11.6.4.4 `/ca` — how opaque the picture is drawn, when the page asked for less. */
|
|
195
|
+
readonly alpha?: number;
|
|
160
196
|
/** §11.3.5 `/BM` — a blend the page asked for that nothing here performs. */
|
|
161
197
|
readonly blend?: string;
|
|
162
198
|
/** §11.6.5 `/SMask` — the paint faded from place to place; nothing here does. */
|
|
@@ -222,6 +258,13 @@ export interface VectorPlacement {
|
|
|
222
258
|
readonly blend?: string;
|
|
223
259
|
/** §11.6.5 `/SMask` — the paint faded from place to place; nothing here does. */
|
|
224
260
|
readonly masked?: boolean;
|
|
261
|
+
/**
|
|
262
|
+
* §9.6.6 — this path is a GLYPH, traced from the face because its code stands
|
|
263
|
+
* for no character. It is type, not artwork, so the de-cluttering a page's
|
|
264
|
+
* paths go through does not apply: a full stop is a mark one point across and
|
|
265
|
+
* every filter there would throw it out.
|
|
266
|
+
*/
|
|
267
|
+
readonly glyph?: boolean;
|
|
225
268
|
/**
|
|
226
269
|
* §8.7.3 — the TILING pattern resource name the path is filled with. Its
|
|
227
270
|
* content is a stream of its own, so what the fill actually shows is only
|
|
@@ -241,18 +284,66 @@ export interface InterpretResult {
|
|
|
241
284
|
readonly vectors: Array<VectorPlacement>;
|
|
242
285
|
/** §9.6.5 — every Type 3 glyph the stream showed, with where to run it. */
|
|
243
286
|
readonly glyphs: Array<Type3Call>;
|
|
287
|
+
/**
|
|
288
|
+
* §8.7.4.3 — every region the stream painted with a bare `sh`, which fills
|
|
289
|
+
* the CLIP rather than a path. What a caller can do with one depends on the
|
|
290
|
+
* shading's own type, so the placement is carried rather than counted.
|
|
291
|
+
*/
|
|
292
|
+
readonly shadings: Array<ShadingPaint>;
|
|
293
|
+
/**
|
|
294
|
+
* §9.6.6 — every glyph the stream showed that stands for NO character, as
|
|
295
|
+
* the path it draws in page space. There is nothing to write for one, and
|
|
296
|
+
* there is something to draw.
|
|
297
|
+
*/
|
|
298
|
+
readonly outlines: Array<VectorPlacement>;
|
|
244
299
|
}
|
|
245
300
|
/**
|
|
246
301
|
* §9.6.5 — one showing of a Type 3 glyph: which procedure, and the matrix that
|
|
247
302
|
* puts glyph space on the page.
|
|
248
303
|
*/
|
|
304
|
+
/** §8.7.4.3 — one `sh`: which shading, where the CTM put it, what bounded it. */
|
|
305
|
+
export interface ShadingPaint {
|
|
306
|
+
/** The `/Shading` resource name (no leading slash). */
|
|
307
|
+
readonly name: string;
|
|
308
|
+
/** The CTM in force, which maps the shading's own space onto the page. */
|
|
309
|
+
readonly ctm: Matrix;
|
|
310
|
+
/** §8.5.4 — the clip the paint was bounded by, which is its whole extent. */
|
|
311
|
+
readonly clip?: ClipRegion;
|
|
312
|
+
/**
|
|
313
|
+
* §11.6.5 `/SMask` — the paint was faded from place to place. For a `sh` that
|
|
314
|
+
* is not a detail: the mask is the SHAPE, and the clip is only its outer
|
|
315
|
+
* bound.
|
|
316
|
+
*/
|
|
317
|
+
readonly masked?: boolean;
|
|
318
|
+
/** §11.6.4.4 `/ca` — how opaque the paint is, when the page asked for less. */
|
|
319
|
+
readonly alpha?: number;
|
|
320
|
+
/** §11.3.5 `/BM` — the paint only DARKENS what it covers. */
|
|
321
|
+
readonly darkens?: boolean;
|
|
322
|
+
/** Where it fell in the painting order (§8.5.3). */
|
|
323
|
+
readonly order: number;
|
|
324
|
+
}
|
|
249
325
|
export interface Type3Call {
|
|
250
326
|
readonly stream: PdfStream;
|
|
251
327
|
readonly resources: PdfDict | undefined;
|
|
252
328
|
readonly ctm: Matrix;
|
|
253
329
|
/** §8.5.3 — its place in the stream's painting order, as a form call has. */
|
|
254
330
|
readonly order: number;
|
|
331
|
+
/**
|
|
332
|
+
* §9.6.5/§9.10 — the font SAYS what character this glyph stands for. A
|
|
333
|
+
* flowing reading re-sets that character in a face of its own, so drawing the
|
|
334
|
+
* procedure as well puts two copies of the letter on the page.
|
|
335
|
+
*/
|
|
336
|
+
readonly readable: boolean;
|
|
255
337
|
}
|
|
338
|
+
/**
|
|
339
|
+
* §9.10 — whether the font says what character a glyph stands for: text that is
|
|
340
|
+
* neither empty nor the replacement character a reader writes where nothing is
|
|
341
|
+
* stated.
|
|
342
|
+
*
|
|
343
|
+
* @param text What the font's decode gave for the code.
|
|
344
|
+
* @returns Whether a flowing reading can write it as a letter.
|
|
345
|
+
*/
|
|
346
|
+
export declare function statesACharacter(text: string): boolean;
|
|
256
347
|
/**
|
|
257
348
|
* 2D affine matrix `[a b c d e f]`, row-vector convention (`[x y 1] · M`):
|
|
258
349
|
* ```
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { PDF_NULL, PdfHexString, PdfName } from "../pdf/objects.js";
|
|
2
2
|
import { Lexer } from "./lexer.js";
|
|
3
|
-
import {
|
|
3
|
+
import { cmykHex, grayHex, rgbHex, spaceColor } from "./shading.js";
|
|
4
4
|
//#region src/pdf-reader/content.ts
|
|
5
5
|
/**
|
|
6
6
|
* A painted path emitted by the path-painting operators (§8.5.3), captured in
|
|
@@ -35,6 +35,18 @@ function pathBox(segs) {
|
|
|
35
35
|
}
|
|
36
36
|
/** The area of a box, for choosing the smaller of two clip regions. */
|
|
37
37
|
var area = (b) => Math.max(0, b.maxX - b.minX) * Math.max(0, b.maxY - b.minY);
|
|
38
|
+
/**
|
|
39
|
+
* §9.10 — whether the font says what character a glyph stands for: text that is
|
|
40
|
+
* neither empty nor the replacement character a reader writes where nothing is
|
|
41
|
+
* stated.
|
|
42
|
+
*
|
|
43
|
+
* @param text What the font's decode gave for the code.
|
|
44
|
+
* @returns Whether a flowing reading can write it as a letter.
|
|
45
|
+
*/
|
|
46
|
+
function statesACharacter(text) {
|
|
47
|
+
const trimmed = text.trim();
|
|
48
|
+
return trimmed.length > 0 && !trimmed.includes("�");
|
|
49
|
+
}
|
|
38
50
|
/** The identity {@link Matrix} (no transform). */
|
|
39
51
|
var IDENTITY = [
|
|
40
52
|
1,
|
|
@@ -136,39 +148,42 @@ function spaceOf(operands, spaces) {
|
|
|
136
148
|
}
|
|
137
149
|
}
|
|
138
150
|
/**
|
|
139
|
-
* §8.
|
|
140
|
-
*
|
|
141
|
-
*
|
|
142
|
-
*
|
|
143
|
-
* there is. One number is the ambiguous case — grey in a device space, but the
|
|
144
|
-
* strength of a colorant in a Separation, where 1 is the ink at full and reads
|
|
145
|
-
* dark — so a lone component is only taken where the space said what it means.
|
|
151
|
+
* §8.7.4.5 — one colour for a whole sweep: the stop at its middle, or the mean
|
|
152
|
+
* of the two it falls between. A gradient is a shape a run cannot carry, and
|
|
153
|
+
* the end it starts at is no more the colour of the words than the end it
|
|
154
|
+
* finishes at.
|
|
146
155
|
*/
|
|
147
|
-
function
|
|
148
|
-
const
|
|
149
|
-
if (
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
156
|
+
function midGradient(gradient) {
|
|
157
|
+
const stops = [...gradient.stops].sort((a, b) => a.offset - b.offset);
|
|
158
|
+
if (stops.length === 0) return "000000";
|
|
159
|
+
const exact = stops.find((s) => Math.abs(s.offset - .5) < 1e-6);
|
|
160
|
+
if (exact) return exact.colorHex;
|
|
161
|
+
const before = [...stops].reverse().find((s) => s.offset <= .5) ?? stops[0];
|
|
162
|
+
const after = stops.find((s) => s.offset >= .5) ?? stops[stops.length - 1];
|
|
163
|
+
const span = after.offset - before.offset;
|
|
164
|
+
const t = span > 0 ? (.5 - before.offset) / span : 0;
|
|
165
|
+
const mix = (at) => {
|
|
166
|
+
const a = parseInt(before.colorHex.slice(at, at + 2), 16);
|
|
167
|
+
const b = parseInt(after.colorHex.slice(at, at + 2), 16);
|
|
168
|
+
return Number.isFinite(a) && Number.isFinite(b) ? Math.round(a + (b - a) * t) : 0;
|
|
169
|
+
};
|
|
170
|
+
return [
|
|
171
|
+
mix(0),
|
|
172
|
+
mix(2),
|
|
173
|
+
mix(4)
|
|
174
|
+
].map((c) => Math.max(0, Math.min(255, c)).toString(16).padStart(2, "0")).join("").toUpperCase();
|
|
175
|
+
}
|
|
176
|
+
/** §8.6.8 — the colour a run of `sc` / `scn` operands comes to (see `spaceColor`). */
|
|
177
|
+
function colorOfOperands(operands, space) {
|
|
178
|
+
return spaceColor(operands.filter((o) => typeof o === "number"), space);
|
|
166
179
|
}
|
|
167
180
|
function interpretContent(bytes, fonts, initialCtm = IDENTITY, shadings = /* @__PURE__ */ new Map(), alphas = /* @__PURE__ */ new Map(), spaces = /* @__PURE__ */ new Map(), hiddenOc = /* @__PURE__ */ new Set()) {
|
|
168
181
|
const runs = [];
|
|
169
182
|
const images = [];
|
|
170
183
|
const vectors = [];
|
|
171
184
|
const glyphs = [];
|
|
185
|
+
const painted = [];
|
|
186
|
+
const outlines = [];
|
|
172
187
|
const lexer = new Lexer(bytes);
|
|
173
188
|
const stack = [];
|
|
174
189
|
let state = initialState();
|
|
@@ -281,16 +296,46 @@ function interpretContent(bytes, fonts, initialCtm = IDENTITY, shadings = /* @__
|
|
|
281
296
|
stream,
|
|
282
297
|
resources: type3.resources,
|
|
283
298
|
ctm: multiply(type3.matrix, multiply(scale, multiply(tm, state.ctm))),
|
|
284
|
-
order: paintOrder
|
|
299
|
+
order: paintOrder++,
|
|
300
|
+
readable: statesACharacter(state.font.decode([code]))
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
const outline = state.font.outline;
|
|
305
|
+
if (outline && visible() && state.renderMode !== 3 && state.renderMode !== 7) {
|
|
306
|
+
const segs = outline.path(code);
|
|
307
|
+
if (segs) {
|
|
308
|
+
const scale = [
|
|
309
|
+
state.fontSize * state.hScale,
|
|
310
|
+
0,
|
|
311
|
+
0,
|
|
312
|
+
state.fontSize,
|
|
313
|
+
0,
|
|
314
|
+
state.rise
|
|
315
|
+
];
|
|
316
|
+
const place = multiply(outline.matrix, multiply(scale, multiply(tm, state.ctm)));
|
|
317
|
+
outlines.push({
|
|
318
|
+
order: paintOrder++,
|
|
319
|
+
segs: segs.map((seg) => mapSeg(seg, place)),
|
|
320
|
+
...state.clip ? { clip: state.clip } : {},
|
|
321
|
+
fillHex: state.fillColor,
|
|
322
|
+
...state.fillAlpha < 1 ? { alpha: state.fillAlpha } : {},
|
|
323
|
+
glyph: true
|
|
285
324
|
});
|
|
286
325
|
}
|
|
287
326
|
}
|
|
288
|
-
const w0 = state.font.width(code) / 1e3;
|
|
289
327
|
const isSpace = state.font.bytesPerCode === 1 && code === 32;
|
|
290
|
-
|
|
328
|
+
const spacing = state.charSpacing + (isSpace ? state.wordSpacing : 0);
|
|
329
|
+
const down = state.font.verticalAdvance;
|
|
330
|
+
if (down) {
|
|
331
|
+
tm = multiply(translation(0, down(code) / 1e3 * state.fontSize - spacing), tm);
|
|
332
|
+
return;
|
|
333
|
+
}
|
|
334
|
+
tm = multiply(translation((state.font.width(code) / 1e3 * state.fontSize + spacing) * state.hScale, 0), tm);
|
|
291
335
|
};
|
|
292
336
|
const consume = (operand) => {
|
|
293
|
-
const
|
|
337
|
+
const bytes = toBytes(operand);
|
|
338
|
+
const codes = state.font.splitCodes ? state.font.splitCodes(bytes) : splitCodes(bytes, state.font.bytesPerCode);
|
|
294
339
|
for (const code of codes) advanceGlyph(code);
|
|
295
340
|
return state.font.decode(codes);
|
|
296
341
|
};
|
|
@@ -316,13 +361,14 @@ function interpretContent(bytes, fonts, initialCtm = IDENTITY, shadings = /* @__
|
|
|
316
361
|
...state.font.type3 ? { type3: true } : {},
|
|
317
362
|
...state.renderMode === 3 || state.renderMode === 7 ? { invisible: true } : {},
|
|
318
363
|
...state.fillPattern !== void 0 ? { fillPatternName: state.fillPattern } : {},
|
|
364
|
+
...state.fillGradient ? { gradientFill: true } : {},
|
|
319
365
|
...strokesText(state.renderMode) ? {
|
|
320
366
|
outlineHex: state.strokeColor,
|
|
321
367
|
outlineWidthPt: ctmLineWidth()
|
|
322
368
|
} : {},
|
|
323
369
|
...state.font.bold ? { bold: true } : {},
|
|
324
370
|
...state.font.italic ? { italic: true } : {},
|
|
325
|
-
colorHex: state.fillColor,
|
|
371
|
+
colorHex: state.fillGradient ? midGradient(state.fillGradient) : state.fillColor,
|
|
326
372
|
...mcid !== void 0 ? { mcid } : {}
|
|
327
373
|
});
|
|
328
374
|
};
|
|
@@ -438,7 +484,9 @@ function interpretContent(bytes, fonts, initialCtm = IDENTITY, shadings = /* @__
|
|
|
438
484
|
...state.clip ? { clip: state.clip } : {},
|
|
439
485
|
fillHex: state.fillColor,
|
|
440
486
|
...mcid !== void 0 ? { mcid } : {},
|
|
441
|
-
...state.
|
|
487
|
+
...state.fillAlpha < 1 ? { alpha: state.fillAlpha } : {},
|
|
488
|
+
...state.blendMode !== void 0 ? { blend: state.blendMode } : {},
|
|
489
|
+
...state.softMask ? { masked: true } : {}
|
|
442
490
|
});
|
|
443
491
|
}
|
|
444
492
|
break;
|
|
@@ -473,7 +521,7 @@ function interpretContent(bytes, fonts, initialCtm = IDENTITY, shadings = /* @__
|
|
|
473
521
|
state.fillPattern = state.fillGradient ? void 0 : named;
|
|
474
522
|
break;
|
|
475
523
|
}
|
|
476
|
-
const hex =
|
|
524
|
+
const hex = colorOfOperands(operands, state.fillSpace);
|
|
477
525
|
if (hex !== void 0) {
|
|
478
526
|
state.fillColor = hex;
|
|
479
527
|
state.fillGradient = void 0;
|
|
@@ -484,7 +532,7 @@ function interpretContent(bytes, fonts, initialCtm = IDENTITY, shadings = /* @__
|
|
|
484
532
|
case "SCN":
|
|
485
533
|
case "SC": {
|
|
486
534
|
if (operands[operands.length - 1] instanceof PdfName) break;
|
|
487
|
-
const hex =
|
|
535
|
+
const hex = colorOfOperands(operands, state.strokeSpace);
|
|
488
536
|
if (hex !== void 0) state.strokeColor = hex;
|
|
489
537
|
break;
|
|
490
538
|
}
|
|
@@ -536,17 +584,32 @@ function interpretContent(bytes, fonts, initialCtm = IDENTITY, shadings = /* @__
|
|
|
536
584
|
path.push({ op: "close" });
|
|
537
585
|
paintPath(true, true);
|
|
538
586
|
break;
|
|
587
|
+
case "sh": {
|
|
588
|
+
const nm = operands[0];
|
|
589
|
+
if (nm instanceof PdfName && visible()) painted.push({
|
|
590
|
+
name: nm.value,
|
|
591
|
+
ctm: state.ctm,
|
|
592
|
+
...state.clip ? { clip: state.clip } : {},
|
|
593
|
+
...state.softMask ? { masked: true } : {},
|
|
594
|
+
...state.fillAlpha < 1 ? { alpha: state.fillAlpha } : {},
|
|
595
|
+
...state.fillDarkens ? { darkens: true } : {},
|
|
596
|
+
order: paintOrder++
|
|
597
|
+
});
|
|
598
|
+
break;
|
|
599
|
+
}
|
|
539
600
|
case "n":
|
|
540
601
|
paintPath(false, false);
|
|
541
602
|
break;
|
|
542
603
|
case "gs": {
|
|
543
604
|
const nm = operands[operands.length - 1];
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
state.fillAlpha = paint
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
605
|
+
const paint = nm instanceof PdfName ? alphas.get(nm.value) : void 0;
|
|
606
|
+
if (paint) {
|
|
607
|
+
if (paint.alpha !== void 0) state.fillAlpha = paint.alpha;
|
|
608
|
+
if (paint.statesBlend === true) {
|
|
609
|
+
state.fillDarkens = paint.darkens ?? false;
|
|
610
|
+
state.blendMode = paint.blend;
|
|
611
|
+
}
|
|
612
|
+
if (paint.masked !== void 0) state.softMask = paint.masked;
|
|
550
613
|
}
|
|
551
614
|
break;
|
|
552
615
|
}
|
|
@@ -605,7 +668,34 @@ function interpretContent(bytes, fonts, initialCtm = IDENTITY, shadings = /* @__
|
|
|
605
668
|
texts: runs,
|
|
606
669
|
images,
|
|
607
670
|
vectors,
|
|
608
|
-
glyphs
|
|
671
|
+
glyphs,
|
|
672
|
+
shadings: painted,
|
|
673
|
+
outlines
|
|
674
|
+
};
|
|
675
|
+
}
|
|
676
|
+
/** One path segment through a matrix — the glyph's own space onto the page. */
|
|
677
|
+
function mapSeg(seg, m) {
|
|
678
|
+
const at = (x, y) => [m[0] * x + m[2] * y + m[4], m[1] * x + m[3] * y + m[5]];
|
|
679
|
+
if (seg.op === "close") return seg;
|
|
680
|
+
if (seg.op === "cubic") {
|
|
681
|
+
const [x1, y1] = at(seg.x1, seg.y1);
|
|
682
|
+
const [x2, y2] = at(seg.x2, seg.y2);
|
|
683
|
+
const [x, y] = at(seg.x, seg.y);
|
|
684
|
+
return {
|
|
685
|
+
op: "cubic",
|
|
686
|
+
x1,
|
|
687
|
+
y1,
|
|
688
|
+
x2,
|
|
689
|
+
y2,
|
|
690
|
+
x,
|
|
691
|
+
y
|
|
692
|
+
};
|
|
693
|
+
}
|
|
694
|
+
const [x, y] = at(seg.x, seg.y);
|
|
695
|
+
return {
|
|
696
|
+
op: seg.op,
|
|
697
|
+
x,
|
|
698
|
+
y
|
|
609
699
|
};
|
|
610
700
|
}
|
|
611
701
|
/** §9.3.6 — the rendering modes that put a line round the glyphs. */
|
|
@@ -657,21 +747,6 @@ function isRightToLeft(text) {
|
|
|
657
747
|
function isRtl(cp) {
|
|
658
748
|
return cp >= 1424 && cp <= 1535 || cp >= 1536 && cp <= 1791 || cp >= 1792 && cp <= 1871 || cp >= 1920 && cp <= 1983 || cp >= 2208 && cp <= 2303 || cp >= 64285 && cp <= 65023 || cp >= 65136 && cp <= 65279;
|
|
659
749
|
}
|
|
660
|
-
function clamp255(v) {
|
|
661
|
-
return Math.max(0, Math.min(255, Math.round(v * 255)));
|
|
662
|
-
}
|
|
663
|
-
function hex2(v) {
|
|
664
|
-
return clamp255(v).toString(16).padStart(2, "0");
|
|
665
|
-
}
|
|
666
|
-
function rgbHex(r, g, b) {
|
|
667
|
-
return (hex2(r) + hex2(g) + hex2(b)).toUpperCase();
|
|
668
|
-
}
|
|
669
|
-
function grayHex(v) {
|
|
670
|
-
return rgbHex(v, v, v);
|
|
671
|
-
}
|
|
672
|
-
function cmykHex(c, m, y, k) {
|
|
673
|
-
return rgbHex((1 - c) * (1 - k), (1 - m) * (1 - k), (1 - y) * (1 - k));
|
|
674
|
-
}
|
|
675
750
|
function matrixFromOperands(operands) {
|
|
676
751
|
const n = (i) => typeof operands[i] === "number" ? operands[i] : 0;
|
|
677
752
|
return [
|
|
@@ -705,9 +780,30 @@ function readArray(lexer) {
|
|
|
705
780
|
for (;;) {
|
|
706
781
|
const tok = lexer.nextToken();
|
|
707
782
|
if (tok.kind === "arrayClose" || tok.kind === "eof") break;
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
783
|
+
switch (tok.kind) {
|
|
784
|
+
case "num":
|
|
785
|
+
out.push(tok.value);
|
|
786
|
+
break;
|
|
787
|
+
case "str":
|
|
788
|
+
out.push(tok.value);
|
|
789
|
+
break;
|
|
790
|
+
case "hexstr":
|
|
791
|
+
out.push(new PdfHexString(tok.bytes));
|
|
792
|
+
break;
|
|
793
|
+
case "name":
|
|
794
|
+
out.push(new PdfName(tok.value));
|
|
795
|
+
break;
|
|
796
|
+
case "arrayOpen":
|
|
797
|
+
out.push(readArray(lexer));
|
|
798
|
+
break;
|
|
799
|
+
case "dictOpen":
|
|
800
|
+
out.push(readDict(lexer));
|
|
801
|
+
break;
|
|
802
|
+
case "keyword":
|
|
803
|
+
if (tok.value === "true" || tok.value === "false") out.push(tok.value === "true");
|
|
804
|
+
break;
|
|
805
|
+
default: break;
|
|
806
|
+
}
|
|
711
807
|
}
|
|
712
808
|
return out;
|
|
713
809
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** The character a ZapfDingbats code stands for, or `undefined` for an unused one. */
|
|
2
|
+
export declare function zapfDingbatsChar(code: number): string | undefined;
|
|
3
|
+
/**
|
|
4
|
+
* The character a dingbat's glyph NAME stands for — `a38` is ✫ — for a font
|
|
5
|
+
* that names its glyphs through `/Differences` (§9.6.6.1).
|
|
6
|
+
*
|
|
7
|
+
* @param name The glyph name.
|
|
8
|
+
*/
|
|
9
|
+
export declare function dingbatChar(name: string): string | undefined;
|
|
10
|
+
/** Whether a base font names the ZapfDingbats face (§9.6.2.2 Table 109). */
|
|
11
|
+
export declare function isZapfDingbats(baseFont: string): boolean;
|