reamkit 1.27.0 → 1.28.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 +0 -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 +5 -2
- package/dist/esm/pdf-reader/content.d.ts +76 -0
- package/dist/esm/pdf-reader/content.js +142 -59
- 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.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 +9 -3
- package/dist/esm/pdf-reader/flow-build.js +13 -7
- 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 +1148 -45
- 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/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.js +43 -4
- package/dist/esm/word/document-parser.js +4 -1
- package/dist/esm/word/docx-writer.js +1 -0
- package/package.json +1 -1
|
@@ -66,7 +66,47 @@ function placeRuns(runs, d) {
|
|
|
66
66
|
endY: end.y,
|
|
67
67
|
...Math.abs(angle) > .5 ? { angleDeg: angle } : {}
|
|
68
68
|
};
|
|
69
|
-
}).filter((r) => shows(d, Math.min(r.x, r.endX), Math.min(r.y, r.endY) - r.fontSizePt * .25, Math.max(r.x, r.endX), Math.max(r.y, r.endY) + r.fontSizePt * .85));
|
|
69
|
+
}).filter((r) => shows(d, Math.min(r.x, r.endX), Math.min(r.y, r.endY) - r.fontSizePt * .25, Math.max(r.x, r.endX), Math.max(r.y, r.endY) + r.fontSizePt * .85)).map((r) => cropped(r, d));
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* §14.11.2 — a run the crop's edge cuts through, as the letters it shows.
|
|
73
|
+
*
|
|
74
|
+
* A run that reaches into the shown page was kept whole, which is right where
|
|
75
|
+
* the crop trims a hair and wrong where it trims a line: endchar.pdf is one
|
|
76
|
+
* line of a poster, "LE HOLD-UP PLANÉTAIRE", cropped to the fourteen points
|
|
77
|
+
* that hold its É. Every viewer shows that one letter. Reflowed, the whole
|
|
78
|
+
* line was re-set into a column fourteen points wide and came back as four
|
|
79
|
+
* pages of one letter each.
|
|
80
|
+
*
|
|
81
|
+
* A letter is kept where any part of it is inside, so a crop that shaves an
|
|
82
|
+
* edge takes nothing. Where in the run each letter falls is estimated from the
|
|
83
|
+
* run's own width, which is exact for a face set solid and near enough for one
|
|
84
|
+
* that is not — the answer is a letter either way.
|
|
85
|
+
*
|
|
86
|
+
* @param run The run, already placed on the shown page.
|
|
87
|
+
* @param d The page's shown geometry.
|
|
88
|
+
* @returns The run, or the part of it the page shows.
|
|
89
|
+
*/
|
|
90
|
+
function cropped(run, d) {
|
|
91
|
+
const from = Math.min(run.x, run.endX);
|
|
92
|
+
const to = Math.max(run.x, run.endX);
|
|
93
|
+
const chars = [...run.text];
|
|
94
|
+
if (from >= 0 && to <= d.width) return run;
|
|
95
|
+
if (run.angleDeg !== void 0 || chars.length < 2 || !(to > from)) return run;
|
|
96
|
+
const step = (to - from) / chars.length;
|
|
97
|
+
const first = Math.max(0, Math.floor((0 - from) / step));
|
|
98
|
+
const last = Math.min(chars.length - 1, Math.ceil((d.width - from) / step) - 1);
|
|
99
|
+
if (first > last) return run;
|
|
100
|
+
if (first === 0 && last === chars.length - 1) return run;
|
|
101
|
+
const backwards = run.endX < run.x;
|
|
102
|
+
const startX = from + first * step;
|
|
103
|
+
const endX = from + (last + 1) * step;
|
|
104
|
+
return {
|
|
105
|
+
...run,
|
|
106
|
+
text: chars.slice(first, last + 1).join(""),
|
|
107
|
+
x: backwards ? endX : startX,
|
|
108
|
+
endX: backwards ? startX : endX
|
|
109
|
+
};
|
|
70
110
|
}
|
|
71
111
|
/**
|
|
72
112
|
* §14.11.2 — whether a box falls inside the region the page SHOWS.
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { PDF_NULL, PdfName, PdfRef, PdfStream } from "../pdf/objects.js";
|
|
2
|
+
import { lzwDecodeMsb } from "../core/lzw.js";
|
|
2
3
|
import { buildDecryptor } from "./decrypt.js";
|
|
3
4
|
import { Lexer } from "./lexer.js";
|
|
4
5
|
import { parseIndirectObject, parseObject } from "./parser.js";
|
|
5
6
|
import { reversePredictor } from "./predictor.js";
|
|
7
|
+
import { ascii85Decode, asciiHexDecode, runLengthDecode } from "./stream-filters.js";
|
|
6
8
|
import { unzlibSync } from "fflate";
|
|
7
9
|
//#region src/pdf-reader/document.ts
|
|
8
10
|
var DEFAULT_MEDIA_BOX = [
|
|
@@ -219,7 +221,19 @@ var PdfFile = class PdfFile {
|
|
|
219
221
|
data = unzlibSync(data);
|
|
220
222
|
flate = true;
|
|
221
223
|
} catch {}
|
|
222
|
-
else if (
|
|
224
|
+
else if (GENERAL_FILTERS[f.value]) {
|
|
225
|
+
data = GENERAL_FILTERS[f.value](data);
|
|
226
|
+
flate = true;
|
|
227
|
+
} else if (f.value === "LZWDecode" || f.value === "LZW") {
|
|
228
|
+
const parms = this.resolve(stream.dict.get("DecodeParms") ?? PDF_NULL);
|
|
229
|
+
const p = Array.isArray(parms) ? this.resolve(parms[0] ?? PDF_NULL) : parms;
|
|
230
|
+
const early = p instanceof Map ? this.resolve(p.get("EarlyChange") ?? PDF_NULL) : void 0;
|
|
231
|
+
data = lzwDecodeMsb(data, {
|
|
232
|
+
earlyChange: early === 0 ? 0 : 1,
|
|
233
|
+
limit: MAX_LZW_OUT
|
|
234
|
+
});
|
|
235
|
+
flate = true;
|
|
236
|
+
} else if (this.filters[f.value]) {
|
|
223
237
|
const decoded = runFilter(this.filters[f.value], data);
|
|
224
238
|
if (decoded) data = decoded;
|
|
225
239
|
else this.unknownFilters.add(f.value);
|
|
@@ -240,15 +254,18 @@ function runFilter(filter, data) {
|
|
|
240
254
|
return;
|
|
241
255
|
}
|
|
242
256
|
}
|
|
257
|
+
/** A decompressed LZW stream larger than this is a bomb, not a document. */
|
|
258
|
+
var MAX_LZW_OUT = 1 << 28;
|
|
259
|
+
/** §7.4.2–7.4.5 — the filters that are transport, whatever the stream holds. */
|
|
260
|
+
var GENERAL_FILTERS = {
|
|
261
|
+
ASCIIHexDecode: asciiHexDecode,
|
|
262
|
+
AHx: asciiHexDecode,
|
|
263
|
+
ASCII85Decode: ascii85Decode,
|
|
264
|
+
A85: ascii85Decode,
|
|
265
|
+
RunLengthDecode: runLengthDecode,
|
|
266
|
+
RL: runLengthDecode
|
|
267
|
+
};
|
|
243
268
|
var PASSTHROUGH_FILTERS = new Set([
|
|
244
|
-
"LZWDecode",
|
|
245
|
-
"LZW",
|
|
246
|
-
"RunLengthDecode",
|
|
247
|
-
"RL",
|
|
248
|
-
"ASCII85Decode",
|
|
249
|
-
"A85",
|
|
250
|
-
"ASCIIHexDecode",
|
|
251
|
-
"AHx",
|
|
252
269
|
"DCTDecode",
|
|
253
270
|
"DCT",
|
|
254
271
|
"JPXDecode",
|
|
@@ -38,3 +38,14 @@ export declare function collectEmbeddedFonts(file: PdfFile, pages: ReadonlyArray
|
|
|
38
38
|
* @returns The name, or `undefined` when the font states none.
|
|
39
39
|
*/
|
|
40
40
|
export declare function embeddedFontName(file: PdfFile, fontDict: PdfDict): string | undefined;
|
|
41
|
+
/**
|
|
42
|
+
* Whether this font carries a program this pipeline can set the page in.
|
|
43
|
+
*
|
|
44
|
+
* Only `/FontFile2` is liftable, and a run in such a face is filed under the
|
|
45
|
+
* face's own name — so that name must be left exactly as it is. Every other
|
|
46
|
+
* face is SUBSTITUTED, and its name is free to say what it is.
|
|
47
|
+
*
|
|
48
|
+
* @param file The document.
|
|
49
|
+
* @param fontDict The font dictionary.
|
|
50
|
+
*/
|
|
51
|
+
export declare function hasLiftableProgram(file: PdfFile, fontDict: PdfDict): boolean;
|
|
@@ -92,6 +92,19 @@ function embeddedFontName(file, fontDict) {
|
|
|
92
92
|
const name = base.value.replace(/^[A-Z]{6}\+/u, "").trim();
|
|
93
93
|
return name.length > 0 ? name.toLowerCase() : void 0;
|
|
94
94
|
}
|
|
95
|
+
/**
|
|
96
|
+
* Whether this font carries a program this pipeline can set the page in.
|
|
97
|
+
*
|
|
98
|
+
* Only `/FontFile2` is liftable, and a run in such a face is filed under the
|
|
99
|
+
* face's own name — so that name must be left exactly as it is. Every other
|
|
100
|
+
* face is SUBSTITUTED, and its name is free to say what it is.
|
|
101
|
+
*
|
|
102
|
+
* @param file The document.
|
|
103
|
+
* @param fontDict The font dictionary.
|
|
104
|
+
*/
|
|
105
|
+
function hasLiftableProgram(file, fontDict) {
|
|
106
|
+
return fontProgram(file, fontDict) !== void 0;
|
|
107
|
+
}
|
|
95
108
|
/** §9.9 `/FontFile2` — the TrueType program, off the font or its descendant. */
|
|
96
109
|
function fontProgram(file, fontDict) {
|
|
97
110
|
const owner = descendant(file, fontDict) ?? fontDict;
|
|
@@ -110,4 +123,4 @@ function descendant(file, fontDict) {
|
|
|
110
123
|
return first instanceof Map ? first : void 0;
|
|
111
124
|
}
|
|
112
125
|
//#endregion
|
|
113
|
-
export { collectEmbeddedFonts, embeddedFontName };
|
|
126
|
+
export { collectEmbeddedFonts, embeddedFontName, hasLiftableProgram };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/** One of the base encodings this reader has a table for (Annex D.2). */
|
|
2
|
+
export type BaseEncodingName = 'StandardEncoding' | 'WinAnsiEncoding' | 'MacRomanEncoding';
|
|
3
|
+
/**
|
|
4
|
+
* The glyph names of a base encoding, or `undefined` for a name this has no
|
|
5
|
+
* table for — `/MacExpertEncoding`, whose repertory no reader here can set.
|
|
6
|
+
*
|
|
7
|
+
* @param name The `/Encoding` or `/BaseEncoding` name, without the slash.
|
|
8
|
+
*/
|
|
9
|
+
export declare function baseEncodingTable(name: string): ReadonlyMap<number, string> | undefined;
|
|
10
|
+
/** The encoding built into the standard Latin text faces (§9.6.2.2). */
|
|
11
|
+
export declare function standardEncodingTable(): ReadonlyMap<number, string>;
|
|
12
|
+
/**
|
|
13
|
+
* The name a `post` table's glyph-name index below 258 stands for.
|
|
14
|
+
*
|
|
15
|
+
* @param index The index as the table states it.
|
|
16
|
+
* @returns The name, or `undefined` for an index outside the standard order.
|
|
17
|
+
*/
|
|
18
|
+
export declare function macGlyphName(index: number): string | undefined;
|
|
19
|
+
/**
|
|
20
|
+
* Whether a `/BaseFont` names one of the standard Latin faces, whose built-in
|
|
21
|
+
* encoding is StandardEncoding.
|
|
22
|
+
*
|
|
23
|
+
* @param baseFont The name as the font dictionary states it.
|
|
24
|
+
*/
|
|
25
|
+
export declare function isStandardLatinFace(baseFont: string): boolean;
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
//#region src/pdf-reader/encodings.ts
|
|
2
|
+
/**
|
|
3
|
+
* Code → glyph name, from names read in code order. `.` marks a code the
|
|
4
|
+
* encoding leaves unused, and the rows are the spec's own — sixteen to a line,
|
|
5
|
+
* so a row can be checked against Annex D at a glance.
|
|
6
|
+
*/
|
|
7
|
+
function table(start, ...rows) {
|
|
8
|
+
const out = /* @__PURE__ */ new Map();
|
|
9
|
+
let code = start;
|
|
10
|
+
for (const row of rows) for (const name of row.split(/\s+/u).filter(Boolean)) {
|
|
11
|
+
if (name !== ".") out.set(code, name);
|
|
12
|
+
code++;
|
|
13
|
+
}
|
|
14
|
+
return out;
|
|
15
|
+
}
|
|
16
|
+
var ASCII = table(32, "space exclam quotedbl numbersign dollar percent ampersand quotesingle parenleft parenright asterisk plus comma hyphen period slash", "zero one two three four five six seven eight nine colon semicolon less equal greater question", "at A B C D E F G H I J K L M N O", "P Q R S T U V W X Y Z bracketleft backslash bracketright asciicircum underscore", "grave a b c d e f g h i j k l m n o", "p q r s t u v w x y z braceleft bar braceright asciitilde .");
|
|
17
|
+
/** Annex D.2 STD — the built-in encoding of the standard Latin text faces. */
|
|
18
|
+
var STANDARD = new Map([
|
|
19
|
+
...ASCII,
|
|
20
|
+
...table(39, "quoteright"),
|
|
21
|
+
...table(96, "quoteleft"),
|
|
22
|
+
...table(160, ". exclamdown cent sterling fraction yen florin section currency quotesingle quotedblleft guillemotleft guilsinglleft guilsinglright fi fl", ". endash dagger daggerdbl periodcentered . paragraph bullet quotesinglbase quotedblbase quotedblright guillemotright ellipsis perthousand . questiondown", ". grave acute circumflex tilde macron breve dotaccent dieresis . ring cedilla . hungarumlaut ogonek caron", "emdash . . . . . . . . . . . . . . .", ". AE . ordfeminine . . . . Lslash Oslash OE ordmasculine . . . .", ". ae . . . dotlessi . . lslash oslash oe germandbls . . . .")
|
|
23
|
+
]);
|
|
24
|
+
var TABLES = {
|
|
25
|
+
StandardEncoding: STANDARD,
|
|
26
|
+
WinAnsiEncoding: new Map([...ASCII, ...table(128, "Euro . quotesinglbase florin quotedblbase ellipsis dagger daggerdbl circumflex perthousand Scaron guilsinglleft OE . Zcaron .", ". quoteleft quoteright quotedblleft quotedblright bullet endash emdash tilde trademark scaron guilsinglright oe . zcaron Ydieresis")]),
|
|
27
|
+
MacRomanEncoding: new Map([...ASCII, ...table(128, "Adieresis Aring Ccedilla Eacute Ntilde Odieresis Udieresis aacute agrave acircumflex adieresis atilde aring ccedilla eacute egrave", "ecircumflex edieresis iacute igrave icircumflex idieresis ntilde oacute ograve ocircumflex odieresis otilde uacute ugrave ucircumflex udieresis", "dagger degree cent sterling section bullet paragraph germandbls registered copyright trademark acute dieresis notequal AE Oslash", "infinity plusminus lessequal greaterequal yen mu partialdiff summation product pi integral ordfeminine ordmasculine Omega ae oslash", "questiondown exclamdown logicalnot radical florin approxequal Delta guillemotleft guillemotright ellipsis space Agrave Atilde Otilde OE oe", "endash emdash quotedblleft quotedblright quoteleft quoteright divide lozenge ydieresis Ydieresis fraction currency guilsinglleft guilsinglright fi fl", "daggerdbl periodcentered quotesinglbase quotedblbase perthousand Acircumflex Ecircumflex Aacute Edieresis Egrave Iacute Icircumflex Idieresis Igrave Oacute Ocircumflex", ". Ograve Uacute Ucircumflex Ugrave dotlessi circumflex tilde macron breve dotaccent ring cedilla hungarumlaut ogonek caron")])
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* The glyph names of a base encoding, or `undefined` for a name this has no
|
|
31
|
+
* table for — `/MacExpertEncoding`, whose repertory no reader here can set.
|
|
32
|
+
*
|
|
33
|
+
* @param name The `/Encoding` or `/BaseEncoding` name, without the slash.
|
|
34
|
+
*/
|
|
35
|
+
function baseEncodingTable(name) {
|
|
36
|
+
return name in TABLES ? TABLES[name] : void 0;
|
|
37
|
+
}
|
|
38
|
+
/** The encoding built into the standard Latin text faces (§9.6.2.2). */
|
|
39
|
+
function standardEncodingTable() {
|
|
40
|
+
return STANDARD;
|
|
41
|
+
}
|
|
42
|
+
var STANDARD_LATIN_FACES = new Set([
|
|
43
|
+
"courier",
|
|
44
|
+
"courier-bold",
|
|
45
|
+
"courier-oblique",
|
|
46
|
+
"courier-boldoblique",
|
|
47
|
+
"helvetica",
|
|
48
|
+
"helvetica-bold",
|
|
49
|
+
"helvetica-oblique",
|
|
50
|
+
"helvetica-boldoblique",
|
|
51
|
+
"times-roman",
|
|
52
|
+
"times-bold",
|
|
53
|
+
"times-italic",
|
|
54
|
+
"times-bolditalic"
|
|
55
|
+
]);
|
|
56
|
+
var MAC_ORDER = `
|
|
57
|
+
.notdef .null nonmarkingreturn space exclam quotedbl numbersign dollar
|
|
58
|
+
percent ampersand quotesingle parenleft parenright asterisk plus comma
|
|
59
|
+
hyphen period slash zero one two three four
|
|
60
|
+
five six seven eight nine colon semicolon less
|
|
61
|
+
equal greater question at A B C D
|
|
62
|
+
E F G H I J K L
|
|
63
|
+
M N O P Q R S T
|
|
64
|
+
U V W X Y Z bracketleft backslash
|
|
65
|
+
bracketright asciicircum underscore grave a b c d
|
|
66
|
+
e f g h i j k l
|
|
67
|
+
m n o p q r s t
|
|
68
|
+
u v w x y z braceleft bar
|
|
69
|
+
braceright asciitilde Adieresis Aring Ccedilla Eacute Ntilde Odieresis
|
|
70
|
+
Udieresis aacute agrave acircumflex adieresis atilde aring ccedilla
|
|
71
|
+
eacute egrave ecircumflex edieresis iacute igrave icircumflex idieresis
|
|
72
|
+
ntilde oacute ograve ocircumflex odieresis otilde uacute ugrave
|
|
73
|
+
ucircumflex udieresis dagger degree cent sterling section bullet
|
|
74
|
+
paragraph germandbls registered copyright trademark acute dieresis notequal
|
|
75
|
+
AE Oslash infinity plusminus lessequal greaterequal yen mu
|
|
76
|
+
partialdiff summation product pi integral ordfeminine ordmasculine Omega
|
|
77
|
+
ae oslash questiondown exclamdown logicalnot radical florin approxequal
|
|
78
|
+
Delta guillemotleft guillemotright ellipsis nonbreakingspace Agrave Atilde Otilde
|
|
79
|
+
OE oe endash emdash quotedblleft quotedblright quoteleft quoteright
|
|
80
|
+
divide lozenge ydieresis Ydieresis fraction currency guilsinglleft guilsinglright
|
|
81
|
+
fi fl daggerdbl periodcentered quotesinglbase quotedblbase perthousand Acircumflex
|
|
82
|
+
Ecircumflex Aacute Edieresis Egrave Iacute Icircumflex Idieresis Igrave
|
|
83
|
+
Oacute Ocircumflex apple Ograve Uacute Ucircumflex Ugrave dotlessi
|
|
84
|
+
circumflex tilde macron breve dotaccent ring cedilla hungarumlaut
|
|
85
|
+
ogonek caron Lslash lslash Scaron scaron Zcaron zcaron
|
|
86
|
+
brokenbar Eth eth Yacute yacute Thorn thorn minus
|
|
87
|
+
multiply onesuperior twosuperior threesuperior onehalf onequarter threequarters franc
|
|
88
|
+
Gbreve gbreve Idotaccent Scedilla scedilla Cacute cacute Ccaron
|
|
89
|
+
ccaron dcroat
|
|
90
|
+
`.split(/\s+/u).filter(Boolean);
|
|
91
|
+
/**
|
|
92
|
+
* The name a `post` table's glyph-name index below 258 stands for.
|
|
93
|
+
*
|
|
94
|
+
* @param index The index as the table states it.
|
|
95
|
+
* @returns The name, or `undefined` for an index outside the standard order.
|
|
96
|
+
*/
|
|
97
|
+
function macGlyphName(index) {
|
|
98
|
+
return MAC_ORDER[index];
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Whether a `/BaseFont` names one of the standard Latin faces, whose built-in
|
|
102
|
+
* encoding is StandardEncoding.
|
|
103
|
+
*
|
|
104
|
+
* @param baseFont The name as the font dictionary states it.
|
|
105
|
+
*/
|
|
106
|
+
function isStandardLatinFace(baseFont) {
|
|
107
|
+
return STANDARD_LATIN_FACES.has(baseFont.trim().replace(/^[A-Za-z]{6}\+/u, "").toLowerCase());
|
|
108
|
+
}
|
|
109
|
+
//#endregion
|
|
110
|
+
export { baseEncodingTable, isStandardLatinFace, macGlyphName, standardEncodingTable };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { BodyElement, ParagraphProperties, SectionProperties, TextOutline } from '../core/document-model/index.js';
|
|
1
|
+
import { BodyElement, ParagraphProperties, Section, SectionProperties, TextOutline } from '../core/document-model/index.js';
|
|
2
2
|
import { FlowDoc } from '../core/ir/flow.js';
|
|
3
3
|
import { FontRegistry } from '../core/font/index.js';
|
|
4
4
|
import { Loss, ResourceStore } from '../core/ir/index.js';
|
|
@@ -51,6 +51,12 @@ export interface TextSpan {
|
|
|
51
51
|
readonly bold?: boolean;
|
|
52
52
|
/** §9.8.1 — the face was a slanted one. */
|
|
53
53
|
readonly italic?: boolean;
|
|
54
|
+
/**
|
|
55
|
+
* §17.3.2.42 — the glyphs stood OFF the baseline the line is set on, and
|
|
56
|
+
* smaller: a footnote mark, an exponent, an index. The page states it by
|
|
57
|
+
* placement, and a document by the property.
|
|
58
|
+
*/
|
|
59
|
+
readonly script?: 'superscript' | 'subscript';
|
|
54
60
|
/** §12.5.6.10 — a text-markup annotation marks these words. */
|
|
55
61
|
readonly markup?: TextMarkup;
|
|
56
62
|
}
|
|
@@ -60,7 +66,7 @@ export interface TextSpan {
|
|
|
60
66
|
* survives as its own run) and squashing whitespace. With no hrefs this
|
|
61
67
|
* collapses to a single run — the same shape {@link paragraphBlock} produces.
|
|
62
68
|
*/
|
|
63
|
-
export declare function paragraphFromRuns(spans: ReadonlyArray<TextSpan>, outlineLevel?: number, placement?: Pick<ParagraphProperties, 'alignment' | 'spacingBefore'>): BodyElement;
|
|
69
|
+
export declare function paragraphFromRuns(spans: ReadonlyArray<TextSpan>, outlineLevel?: number, placement?: Pick<ParagraphProperties, 'alignment' | 'spacingBefore' | 'indentLeft' | 'indentFirstLine'>): BodyElement;
|
|
64
70
|
/**
|
|
65
71
|
* Store a {@link PdfImage}'s bytes (content-addressed dedup) and build the image
|
|
66
72
|
* {@link BodyElement} that references them, sized in points from the placement
|
|
@@ -128,4 +134,4 @@ export declare function withMeasuredMargins(section: SectionProperties | undefin
|
|
|
128
134
|
* both reconstruction paths (the tagged fast-path EP3 and the heuristic layout
|
|
129
135
|
* path EP4).
|
|
130
136
|
*/
|
|
131
|
-
export declare function buildFlowDoc(body: ReadonlyArray<BodyElement>, resources?: ResourceStore, section?: SectionProperties, embeddedFonts?: ReadonlyMap<string, FontRegistry
|
|
137
|
+
export declare function buildFlowDoc(body: ReadonlyArray<BodyElement>, resources?: ResourceStore, section?: SectionProperties, embeddedFonts?: ReadonlyMap<string, FontRegistry>, sections?: ReadonlyArray<Section>, headersFooters?: ReadonlyMap<string, ReadonlyArray<BodyElement>>): FlowDoc;
|
|
@@ -31,7 +31,7 @@ function paragraphFromRuns(spans, outlineLevel, placement) {
|
|
|
31
31
|
const merged = [];
|
|
32
32
|
for (const s of spans) {
|
|
33
33
|
const last = merged[merged.length - 1];
|
|
34
|
-
if (last && last.href === s.href && last.sizePt === s.sizePt && last.colorHex === s.colorHex && last.fontName === s.fontName && last.outline?.colorHex === s.outline?.colorHex && last.outline?.widthPt === s.outline?.widthPt && last.bold === s.bold && last.italic === s.italic && sameMarkup(last.markup, s.markup)) last.text += s.text;
|
|
34
|
+
if (last && last.href === s.href && last.sizePt === s.sizePt && last.colorHex === s.colorHex && last.fontName === s.fontName && last.outline?.colorHex === s.outline?.colorHex && last.outline?.widthPt === s.outline?.widthPt && last.bold === s.bold && last.italic === s.italic && last.script === s.script && sameMarkup(last.markup, s.markup)) last.text += s.text;
|
|
35
35
|
else merged.push({
|
|
36
36
|
text: s.text,
|
|
37
37
|
...s.href !== void 0 ? { href: s.href } : {},
|
|
@@ -41,12 +41,13 @@ function paragraphFromRuns(spans, outlineLevel, placement) {
|
|
|
41
41
|
...s.outline !== void 0 ? { outline: s.outline } : {},
|
|
42
42
|
...s.bold !== void 0 ? { bold: s.bold } : {},
|
|
43
43
|
...s.italic !== void 0 ? { italic: s.italic } : {},
|
|
44
|
+
...s.script !== void 0 ? { script: s.script } : {},
|
|
44
45
|
...s.markup !== void 0 ? { markup: s.markup } : {}
|
|
45
46
|
});
|
|
46
47
|
}
|
|
47
48
|
const runs = merged.map((m) => ({
|
|
48
49
|
...m,
|
|
49
|
-
text: m.text.replace(
|
|
50
|
+
text: m.text.replace(/[^\S\t]+/gu, " ")
|
|
50
51
|
})).filter((m) => m.text.length > 0);
|
|
51
52
|
if (runs.length > 0) {
|
|
52
53
|
runs[0].text = runs[0].text.replace(/^ /, "");
|
|
@@ -68,6 +69,7 @@ function paragraphFromRuns(spans, outlineLevel, placement) {
|
|
|
68
69
|
...r.outline !== void 0 ? { textOutline: r.outline } : {},
|
|
69
70
|
...r.bold ? { bold: true } : {},
|
|
70
71
|
...r.italic ? { italic: true } : {},
|
|
72
|
+
...r.script !== void 0 ? { verticalAlign: r.script } : {},
|
|
71
73
|
...r.markup?.highlightHex !== void 0 ? { shadingColorHex: r.markup.highlightHex } : {},
|
|
72
74
|
...r.markup?.underline !== void 0 ? { underline: r.markup.underline } : {},
|
|
73
75
|
...r.markup?.underlineHex !== void 0 ? { underlineColorHex: r.markup.underlineHex } : {},
|
|
@@ -111,6 +113,7 @@ function imageBlock(image, resources, alt, frame, zOrder, behind = false) {
|
|
|
111
113
|
height: pt(image.heightPt),
|
|
112
114
|
...image.rotationDeg !== void 0 ? { rotation60k: Math.round(-image.rotationDeg * 6e4) } : {},
|
|
113
115
|
...image.crop ? { crop: image.crop } : {},
|
|
116
|
+
...image.alpha !== void 0 ? { alpha: image.alpha } : {},
|
|
114
117
|
paragraphProperties: {},
|
|
115
118
|
...alt ? { altText: alt } : {}
|
|
116
119
|
}
|
|
@@ -324,6 +327,8 @@ function sectionFromPdfPages(pages) {
|
|
|
324
327
|
*/
|
|
325
328
|
/** What the measure gives back, so the widest line still fits when re-set. */
|
|
326
329
|
var SLACK = .01;
|
|
330
|
+
/** How much of the sheet a margin down the page may take. */
|
|
331
|
+
var DEEPEST_MARGIN = .5;
|
|
327
332
|
/** How far a face's ascender stands above its baseline, as a fraction of the size. */
|
|
328
333
|
var ASCENDER = .8;
|
|
329
334
|
/** And its descender below — the two together are a little over one em. */
|
|
@@ -369,14 +374,14 @@ function withMeasuredMargins(section, shown, pageRuns) {
|
|
|
369
374
|
const s = [...xs].sort((a, b) => a - b);
|
|
370
375
|
return s[Math.floor(s.length / 2)] ?? 0;
|
|
371
376
|
};
|
|
372
|
-
const clamp = (v, span) => pt(Math.max(0, Math.min(v, span
|
|
377
|
+
const clamp = (v, span, most = 1 / 3) => pt(Math.max(0, Math.min(v, span * most)));
|
|
373
378
|
return {
|
|
374
379
|
...section,
|
|
375
380
|
margins: {
|
|
376
381
|
left: clamp(median(lefts), width),
|
|
377
382
|
right: clamp(median(rights) - width * SLACK, width),
|
|
378
|
-
top: clamp(
|
|
379
|
-
bottom: clamp(
|
|
383
|
+
top: clamp(Math.min(...tops), height, DEEPEST_MARGIN),
|
|
384
|
+
bottom: clamp(Math.min(...bottoms) - height * SLACK, height, DEEPEST_MARGIN)
|
|
380
385
|
}
|
|
381
386
|
};
|
|
382
387
|
}
|
|
@@ -387,11 +392,12 @@ function withMeasuredMargins(section, shown, pageRuns) {
|
|
|
387
392
|
* both reconstruction paths (the tagged fast-path EP3 and the heuristic layout
|
|
388
393
|
* path EP4).
|
|
389
394
|
*/
|
|
390
|
-
function buildFlowDoc(body, resources = new ResourceStore(), section, embeddedFonts) {
|
|
395
|
+
function buildFlowDoc(body, resources = new ResourceStore(), section, embeddedFonts, sections = [], headersFooters) {
|
|
391
396
|
return {
|
|
392
397
|
kind: "flow",
|
|
393
398
|
body: resolveBodyStyles([...body], EMPTY_STYLE_SHEET),
|
|
394
|
-
sections
|
|
399
|
+
sections,
|
|
400
|
+
...headersFooters && headersFooters.size > 0 ? { headersFooters } : {},
|
|
395
401
|
...section ? { section } : {},
|
|
396
402
|
...embeddedFonts && embeddedFonts.size > 0 ? { embeddedFonts } : {},
|
|
397
403
|
styles: EMPTY_STYLE_SHEET,
|