reamkit 1.26.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 +14 -8
- 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.d.ts +65 -0
- package/dist/esm/pdf-reader/annot-draw.js +487 -0
- package/dist/esm/pdf-reader/annots.d.ts +0 -12
- package/dist/esm/pdf-reader/annots.js +30 -4
- package/dist/esm/pdf-reader/ccitt.d.ts +20 -3
- package/dist/esm/pdf-reader/ccitt.js +102 -6
- 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/cie-color.d.ts +33 -0
- package/dist/esm/pdf-reader/cie-color.js +112 -0
- package/dist/esm/pdf-reader/cmap.js +5 -2
- package/dist/esm/pdf-reader/content.d.ts +123 -3
- package/dist/esm/pdf-reader/content.js +232 -54
- 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.d.ts +1 -1
- package/dist/esm/pdf-reader/display.js +61 -6
- package/dist/esm/pdf-reader/document.d.ts +6 -0
- package/dist/esm/pdf-reader/document.js +55 -10
- package/dist/esm/pdf-reader/embedded-fonts.d.ts +23 -3
- package/dist/esm/pdf-reader/embedded-fonts.js +36 -4
- 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 +19 -5
- package/dist/esm/pdf-reader/flow-build.js +111 -11
- package/dist/esm/pdf-reader/font.js +403 -21
- package/dist/esm/pdf-reader/function.d.ts +16 -0
- package/dist/esm/pdf-reader/function.js +414 -0
- 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 +9 -4
- package/dist/esm/pdf-reader/image-decode.js +274 -72
- package/dist/esm/pdf-reader/images.d.ts +18 -0
- package/dist/esm/pdf-reader/images.js +154 -11
- package/dist/esm/pdf-reader/jbig2.d.ts +23 -0
- package/dist/esm/pdf-reader/jbig2.js +126 -32
- package/dist/esm/pdf-reader/layout.d.ts +32 -0
- package/dist/esm/pdf-reader/layout.js +1316 -64
- package/dist/esm/pdf-reader/lexer.d.ts +2 -0
- package/dist/esm/pdf-reader/lexer.js +4 -0
- 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/optional-content.d.ts +36 -0
- package/dist/esm/pdf-reader/optional-content.js +93 -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 -6
- package/dist/esm/pdf-reader/reader.js +102 -16
- package/dist/esm/pdf-reader/shading.d.ts +139 -8
- package/dist/esm/pdf-reader/shading.js +309 -39
- package/dist/esm/pdf-reader/standard-metrics.d.ts +8 -0
- package/dist/esm/pdf-reader/standard-metrics.js +18 -0
- package/dist/esm/pdf-reader/standard-widths.d.ts +20 -0
- package/dist/esm/pdf-reader/standard-widths.js +62 -0
- 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 +204 -32
- package/dist/esm/pdf-reader/text-rules.d.ts +16 -0
- package/dist/esm/pdf-reader/text-rules.js +185 -0
- package/dist/esm/pdf-reader/text.js +157 -4
- 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 +5 -0
- package/dist/esm/pdf-reader/vector.js +79 -27
- package/dist/esm/word/document-parser.js +4 -1
- package/dist/esm/word/docx-writer.js +74 -11
- package/package.json +1 -1
|
@@ -1,35 +1,66 @@
|
|
|
1
1
|
import { PDF_NULL, PdfName, PdfStream } from "../pdf/objects.js";
|
|
2
2
|
import { FEATURES } from "../core/ir/features.js";
|
|
3
|
+
import { buildAlphaMap, buildColorSpaceMap, buildShadingMap, gradientShading, shadingTypeOf } from "./shading.js";
|
|
3
4
|
import { IDENTITY, interpretContent, multiply } from "./content.js";
|
|
4
5
|
import { collectPageAppearances } from "./annots.js";
|
|
6
|
+
import { hiddenProperties, hiddenXObject } from "./optional-content.js";
|
|
5
7
|
import { buildFonts } from "./text.js";
|
|
6
|
-
import { buildAlphaMap, buildColorSpaceMap, buildShadingMap } from "./shading.js";
|
|
7
8
|
//#region src/pdf-reader/vector.ts
|
|
8
|
-
|
|
9
|
-
* Every vector the page paints, its FORM XOBJECTS included (§8.8).
|
|
10
|
-
*
|
|
11
|
-
* A `Do` of a form is a call: its content stream draws in the caller's space
|
|
12
|
-
* through the form's own `/Matrix`. Interpreting the page stream alone reads
|
|
13
|
-
* only what the page drew directly, and a document that puts its artwork in
|
|
14
|
-
* forms — as every CAD and drawing producer does — comes back with none of it.
|
|
15
|
-
* 22060_A1_01_Plans.pdf holds eleven, and its floor plans were simply absent.
|
|
16
|
-
*
|
|
17
|
-
* The same walk `collectPageImages` already makes, with the same depth and
|
|
18
|
-
* cycle guards, collecting paths instead of pictures.
|
|
19
|
-
*/
|
|
20
|
-
function paintedVectors(file, page, shadings, alphas, spaces) {
|
|
9
|
+
function paintedVectors(file, page) {
|
|
21
10
|
const out = [];
|
|
11
|
+
let bareShadings = 0;
|
|
22
12
|
const visiting = /* @__PURE__ */ new Set();
|
|
13
|
+
const stateCache = /* @__PURE__ */ new Map();
|
|
14
|
+
const mapsOf = (resources) => {
|
|
15
|
+
const had = stateCache.get(resources);
|
|
16
|
+
if (had) return had;
|
|
17
|
+
const made = {
|
|
18
|
+
shadings: buildShadingMap(file, resources),
|
|
19
|
+
alphas: buildAlphaMap(file, resources),
|
|
20
|
+
spaces: buildColorSpaceMap(file, resources)
|
|
21
|
+
};
|
|
22
|
+
stateCache.set(resources, made);
|
|
23
|
+
return made;
|
|
24
|
+
};
|
|
23
25
|
const walk = (resources, content, baseCtm, depth, prefix) => {
|
|
24
26
|
if (out.length >= MAX_VECTORS) return;
|
|
25
27
|
const xobjects = resources ? file.get(resources, "XObject") : PDF_NULL;
|
|
26
28
|
const xobjDict = xobjects instanceof Map ? xobjects : void 0;
|
|
27
|
-
const
|
|
29
|
+
const maps = mapsOf(resources);
|
|
30
|
+
const result = interpretContent(content, buildFonts(file, resources), baseCtm, maps.shadings, maps.alphas, maps.spaces, hiddenProperties(file, resources));
|
|
31
|
+
for (const paint of result.shadings) {
|
|
32
|
+
if (out.length >= MAX_VECTORS) break;
|
|
33
|
+
const dict = resources ? file.get(resources, "Shading") : PDF_NULL;
|
|
34
|
+
const found = dict instanceof Map ? file.resolve(dict.get(paint.name) ?? PDF_NULL) : PDF_NULL;
|
|
35
|
+
const sh = found instanceof PdfStream ? found.dict : found instanceof Map ? found : void 0;
|
|
36
|
+
if (sh && shadingTypeOf(file, sh) === 1) continue;
|
|
37
|
+
const gradient = sh ? gradientShading(file, sh) : void 0;
|
|
38
|
+
if (paint.masked) {
|
|
39
|
+
bareShadings++;
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
if (!sh || !gradient || !paint.clip) {
|
|
43
|
+
bareShadings++;
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
out.push({
|
|
47
|
+
order: paint.order,
|
|
48
|
+
segs: paint.clip.segs,
|
|
49
|
+
gradient,
|
|
50
|
+
...paint.alpha !== void 0 ? { alpha: paint.alpha } : {},
|
|
51
|
+
...paint.darkens ? { darkens: true } : {},
|
|
52
|
+
orderKey: [...prefix, paint.order]
|
|
53
|
+
});
|
|
54
|
+
}
|
|
28
55
|
const events = [
|
|
29
56
|
...result.vectors.map((vector) => ({
|
|
30
57
|
order: vector.order,
|
|
31
58
|
vector
|
|
32
59
|
})),
|
|
60
|
+
...result.outlines.map((vector) => ({
|
|
61
|
+
order: vector.order,
|
|
62
|
+
vector
|
|
63
|
+
})),
|
|
33
64
|
...result.images.map((xobject) => ({
|
|
34
65
|
order: xobject.order,
|
|
35
66
|
xobject
|
|
@@ -60,6 +91,7 @@ function paintedVectors(file, page, shadings, alphas, spaces) {
|
|
|
60
91
|
if (depth >= MAX_FORM_DEPTH) continue;
|
|
61
92
|
const stream = xobjDict ? file.resolve(xobjDict.get(placement.name) ?? PDF_NULL) : PDF_NULL;
|
|
62
93
|
if (!(stream instanceof PdfStream) || visiting.has(stream)) continue;
|
|
94
|
+
if (hiddenXObject(file, stream)) continue;
|
|
63
95
|
const subtype = file.get(stream.dict, "Subtype");
|
|
64
96
|
if (!(subtype instanceof PdfName) || subtype.value !== "Form") continue;
|
|
65
97
|
visiting.add(stream);
|
|
@@ -72,7 +104,10 @@ function paintedVectors(file, page, shadings, alphas, spaces) {
|
|
|
72
104
|
collectPageAppearances(file, page).forEach((appearance, index) => {
|
|
73
105
|
walk(appearance.resources ?? page.resources, file.streamData(appearance.stream), appearance.ctm, 1, [Number.MAX_SAFE_INTEGER, index]);
|
|
74
106
|
});
|
|
75
|
-
return
|
|
107
|
+
return {
|
|
108
|
+
placements: out,
|
|
109
|
+
bareShadings
|
|
110
|
+
};
|
|
76
111
|
}
|
|
77
112
|
/** §8.10.2 `/Matrix` — the form's own space, composed onto the placement CTM. */
|
|
78
113
|
function formMatrix(file, dict) {
|
|
@@ -116,14 +151,24 @@ var MAX_FORM_DEPTH = 12;
|
|
|
116
151
|
* clutter. Clips and the bare `sh` operator are not captured (a documented loss).
|
|
117
152
|
*/
|
|
118
153
|
function collectPageVectors(file, page, occupied = []) {
|
|
119
|
-
const [px0, py0, px1, py1] = page.
|
|
154
|
+
const [px0, py0, px1, py1] = page.cropBox;
|
|
120
155
|
const pageArea = Math.max(1, Math.abs((px1 - px0) * (py1 - py0)));
|
|
121
|
-
const shadings = buildShadingMap(file, page);
|
|
122
|
-
const alphas = buildAlphaMap(file, page);
|
|
123
|
-
const spaces = buildColorSpaceMap(file, page);
|
|
124
156
|
const out = [];
|
|
125
157
|
const painted = [...occupied];
|
|
126
|
-
const
|
|
158
|
+
const lifted = paintedVectors(file, page);
|
|
159
|
+
const raws = lifted.placements;
|
|
160
|
+
const losses = [];
|
|
161
|
+
const bareShadings = lifted.bareShadings;
|
|
162
|
+
const asked = /* @__PURE__ */ new Set();
|
|
163
|
+
for (const raw of raws) {
|
|
164
|
+
if (raw.masked === true) asked.add("PDF soft mask (/SMask in the graphics state) is not applied; the shape is drawn at full opacity throughout");
|
|
165
|
+
if (raw.blend !== void 0) asked.add(`PDF blend mode /${raw.blend} is not performed; the shape is drawn over what it was to blend with`);
|
|
166
|
+
}
|
|
167
|
+
for (const detail of asked) losses.push({
|
|
168
|
+
severity: "degraded",
|
|
169
|
+
feature: FEATURES.images,
|
|
170
|
+
detail
|
|
171
|
+
});
|
|
127
172
|
for (const raw of raws) {
|
|
128
173
|
if (out.length >= MAX_VECTORS) break;
|
|
129
174
|
const v = clipped(raw);
|
|
@@ -139,7 +184,7 @@ function collectPageVectors(file, page, occupied = []) {
|
|
|
139
184
|
const short = Math.min(w, h);
|
|
140
185
|
const isBox = short >= MIN_SIDE && area >= MIN_AREA;
|
|
141
186
|
const isRule = long >= MIN_RULE_LEN && short > 0;
|
|
142
|
-
const filled = (v.gradient !== void 0 || solidFill) && (isBox || isRule
|
|
187
|
+
const filled = (v.gradient !== void 0 || solidFill) && (isBox || isRule || v.glyph === true);
|
|
143
188
|
const stroked = v.strokeHex !== void 0 && (v.strokeHex !== "FFFFFF" || painted.some((box) => overlaps(box, b))) && Math.max(w, h) >= MIN_STROKE_LEN && area <= .85 * pageArea;
|
|
144
189
|
if (!filled && !stroked) continue;
|
|
145
190
|
painted.push(b);
|
|
@@ -148,6 +193,7 @@ function collectPageVectors(file, page, occupied = []) {
|
|
|
148
193
|
segs: v.segs,
|
|
149
194
|
...filled ? v.gradient ? { gradient: v.gradient } : v.fillHex !== void 0 ? { fillHex: v.fillHex } : {} : {},
|
|
150
195
|
...filled && v.alpha !== void 0 ? { alpha: v.alpha } : {},
|
|
196
|
+
...filled && v.darkens === true ? { darkens: true } : {},
|
|
151
197
|
...stroked ? {
|
|
152
198
|
strokeHex: v.strokeHex,
|
|
153
199
|
...v.lineWidth !== void 0 ? { lineWidth: v.lineWidth } : {}
|
|
@@ -156,13 +202,19 @@ function collectPageVectors(file, page, occupied = []) {
|
|
|
156
202
|
...v.mcid !== void 0 ? { mcid: v.mcid } : {}
|
|
157
203
|
});
|
|
158
204
|
}
|
|
205
|
+
if (out.length >= MAX_VECTORS || raws.length >= MAX_VECTORS) losses.push({
|
|
206
|
+
severity: "dropped",
|
|
207
|
+
feature: FEATURES.shapes,
|
|
208
|
+
detail: `page carries more than ${String(MAX_VECTORS)} painted paths; the rest were not read`
|
|
209
|
+
});
|
|
210
|
+
if (bareShadings > 0) losses.push({
|
|
211
|
+
severity: "dropped",
|
|
212
|
+
feature: FEATURES.images,
|
|
213
|
+
detail: `${String(bareShadings)} bare-shading (sh) region${bareShadings === 1 ? "" : "s"} painted the clip rather than a path, and ${bareShadings === 1 ? "was" : "were"} not reconstructed`
|
|
214
|
+
});
|
|
159
215
|
return {
|
|
160
216
|
vectors: out,
|
|
161
|
-
losses
|
|
162
|
-
severity: "dropped",
|
|
163
|
-
feature: FEATURES.shapes,
|
|
164
|
-
detail: `page carries more than ${String(MAX_VECTORS)} painted paths; the rest were not read`
|
|
165
|
-
}] : []
|
|
217
|
+
losses
|
|
166
218
|
};
|
|
167
219
|
}
|
|
168
220
|
/** Whether two boxes share any area at all. */
|
|
@@ -262,7 +262,10 @@ function parseSectPrNode(sectPr) {
|
|
|
262
262
|
const type = poAttr(child, "type") ?? "default";
|
|
263
263
|
const pitch = poIntAttr(child, "linePitch");
|
|
264
264
|
if ((type === "lines" || type === "linesAndChars") && pitch !== void 0 && pitch > 0) gridLinePitchPt = twipsToPt(pitch);
|
|
265
|
-
} else if (poIs(child, "w:type"))
|
|
265
|
+
} else if (poIs(child, "w:type")) {
|
|
266
|
+
const val = poAttr(child, "val");
|
|
267
|
+
sectionStart = val === "continuous" || val === "oddPage" || val === "evenPage" ? val : "nextPage";
|
|
268
|
+
}
|
|
266
269
|
return {
|
|
267
270
|
pageSize,
|
|
268
271
|
...margins ? { margins } : {},
|
|
@@ -616,8 +616,8 @@ function geomXml(g) {
|
|
|
616
616
|
case "close": return "<a:close/>";
|
|
617
617
|
}
|
|
618
618
|
}).join("");
|
|
619
|
-
const w = c1(g.custom.pathWidth);
|
|
620
|
-
const h = c1(g.custom.pathHeight);
|
|
619
|
+
const w = Math.max(1, c1(g.custom.pathWidth));
|
|
620
|
+
const h = Math.max(1, c1(g.custom.pathHeight));
|
|
621
621
|
return `<a:custGeom><a:avLst/><a:gdLst/><a:rect l="0" t="0" r="${w}" b="${h}"/><a:pathLst><a:path w="${w}" h="${h}">${cmds}</a:path></a:pathLst></a:custGeom>`;
|
|
622
622
|
}
|
|
623
623
|
const gds = g.adjust && g.adjust.size > 0 ? [...g.adjust].map(([n, v]) => `<a:gd name="${escapeAttr(n)}" fmla="val ${v}"/>`).join("") : "";
|
|
@@ -826,19 +826,27 @@ function runXml(run, state, scope) {
|
|
|
826
826
|
}
|
|
827
827
|
function rPrXml(r) {
|
|
828
828
|
const out = [];
|
|
829
|
+
const fonts = rFontsXml(r.fontFamily);
|
|
830
|
+
if (fonts) out.push(fonts);
|
|
829
831
|
if (r.bold !== DEFAULT_RUN.bold) out.push(toggle("w:b", r.bold));
|
|
830
832
|
if (r.italic !== DEFAULT_RUN.italic) out.push(toggle("w:i", r.italic));
|
|
831
833
|
if (r.strike !== DEFAULT_RUN.strike) out.push(toggle("w:strike", r.strike));
|
|
832
|
-
if (r.underline !== DEFAULT_RUN.underline) out.push(`<w:u w:val="${r.underline}"/>`);
|
|
833
|
-
const fonts = rFontsXml(r.fontFamily);
|
|
834
|
-
if (fonts) out.push(fonts);
|
|
835
|
-
if (r.fontSizePt !== DEFAULT_RUN.fontSizePt) out.push(`<w:sz w:val="${Math.round(r.fontSizePt * 2)}"/>`);
|
|
836
834
|
if (r.colorHex !== DEFAULT_RUN.colorHex) out.push(`<w:color w:val="${r.colorHex}"/>`);
|
|
835
|
+
if (r.fontSizePt !== DEFAULT_RUN.fontSizePt) out.push(`<w:sz w:val="${Math.round(r.fontSizePt * 2)}"/>`);
|
|
836
|
+
if (r.underline !== DEFAULT_RUN.underline) out.push(underlineXml(r));
|
|
837
|
+
if (r.shadingColorHex !== void 0) out.push(runShdXml(r.shadingColorHex));
|
|
837
838
|
if (r.verticalAlign !== DEFAULT_RUN.verticalAlign) out.push(`<w:vertAlign w:val="${r.verticalAlign}"/>`);
|
|
838
839
|
if (r.rtl !== DEFAULT_RUN.rtl) out.push(toggle("w:rtl", r.rtl));
|
|
839
840
|
if (r.lang !== void 0) out.push(`<w:lang w:val="${escapeAttr(r.lang)}"/>`);
|
|
840
841
|
return out.length > 0 ? `<w:rPr>${out.join("")}</w:rPr>` : "";
|
|
841
842
|
}
|
|
843
|
+
function underlineXml(r) {
|
|
844
|
+
const color = r.underlineColorHex !== void 0 ? ` w:color="${r.underlineColorHex}"` : "";
|
|
845
|
+
return `<w:u w:val="${r.underline}"${color}/>`;
|
|
846
|
+
}
|
|
847
|
+
function runShdXml(fill) {
|
|
848
|
+
return `<w:shd w:val="clear" w:color="auto" w:fill="${fill}"/>`;
|
|
849
|
+
}
|
|
842
850
|
function pPrBody(p) {
|
|
843
851
|
const out = [];
|
|
844
852
|
if (p.numbering) out.push(`<w:numPr><w:ilvl w:val="${p.numbering.ilvl}"/><w:numId w:val="${escapeAttr(p.numbering.numId)}"/></w:numPr>`);
|
|
@@ -942,14 +950,18 @@ function rawParaPrXml(p) {
|
|
|
942
950
|
}
|
|
943
951
|
function rawRunPrXml(r) {
|
|
944
952
|
const out = [];
|
|
953
|
+
const fonts = r.fontFamily ? rawRFontsXml(r.fontFamily) : "";
|
|
954
|
+
if (fonts) out.push(fonts);
|
|
945
955
|
if (r.bold !== void 0) out.push(toggle("w:b", r.bold));
|
|
946
956
|
if (r.italic !== void 0) out.push(toggle("w:i", r.italic));
|
|
947
957
|
if (r.strike !== void 0) out.push(toggle("w:strike", r.strike));
|
|
948
|
-
if (r.underline !== void 0) out.push(`<w:u w:val="${r.underline}"/>`);
|
|
949
|
-
const fonts = r.fontFamily ? rawRFontsXml(r.fontFamily) : "";
|
|
950
|
-
if (fonts) out.push(fonts);
|
|
951
|
-
if (r.fontSizePt !== void 0) out.push(`<w:sz w:val="${Math.round(r.fontSizePt * 2)}"/>`);
|
|
952
958
|
if (r.colorHex !== void 0) out.push(`<w:color w:val="${r.colorHex}"/>`);
|
|
959
|
+
if (r.fontSizePt !== void 0) out.push(`<w:sz w:val="${Math.round(r.fontSizePt * 2)}"/>`);
|
|
960
|
+
if (r.underline !== void 0) out.push(underlineXml({
|
|
961
|
+
...r,
|
|
962
|
+
underline: r.underline
|
|
963
|
+
}));
|
|
964
|
+
if (r.shadingColorHex !== void 0) out.push(runShdXml(r.shadingColorHex));
|
|
953
965
|
if (r.verticalAlign !== void 0) out.push(`<w:vertAlign w:val="${r.verticalAlign}"/>`);
|
|
954
966
|
return out.length > 0 ? `<w:rPr>${out.join("")}</w:rPr>` : "";
|
|
955
967
|
}
|
|
@@ -964,6 +976,7 @@ function sectPrXml(s, hf) {
|
|
|
964
976
|
const parts = [];
|
|
965
977
|
for (const h of hf.headers) parts.push(`<w:headerReference w:type="${h.type}" r:id="${h.relId}"/>`);
|
|
966
978
|
for (const f of hf.footers) parts.push(`<w:footerReference w:type="${f.type}" r:id="${f.relId}"/>`);
|
|
979
|
+
if (s.sectionStart !== void 0 && s.sectionStart !== "nextPage") parts.push(`<w:type w:val="${s.sectionStart}"/>`);
|
|
967
980
|
if (s.pageSize) {
|
|
968
981
|
const orient = s.pageSize.orientation === "landscape" ? " w:orient=\"landscape\"" : "";
|
|
969
982
|
parts.push(`<w:pgSz w:w="${twips(s.pageSize.width)}" w:h="${twips(s.pageSize.height)}"${orient}/>`);
|
|
@@ -987,8 +1000,58 @@ function colsXml(cols) {
|
|
|
987
1000
|
return `<w:cols w:num="${cols.count}" w:space="${twips(cols.spacePt)}"/>`;
|
|
988
1001
|
}
|
|
989
1002
|
var twips = (pt) => Math.round(pt * 20);
|
|
1003
|
+
/**
|
|
1004
|
+
* XML 1.0 §2.2 — the characters a document may contain at all.
|
|
1005
|
+
*
|
|
1006
|
+
* Everything below U+0020 except tab, newline and return is FORBIDDEN, and no
|
|
1007
|
+
* escape exists for them: `` is as ill-formed as the byte. A package with
|
|
1008
|
+
* one in it is not a document — LibreOffice says "source file could not be
|
|
1009
|
+
* loaded" and Word says nothing useful either.
|
|
1010
|
+
*
|
|
1011
|
+
* They reach here from the PDF reader. A subset font that states neither a
|
|
1012
|
+
* `/ToUnicode` nor an `/Encoding /Differences` says nothing about what its
|
|
1013
|
+
* codes mean, and the codes of a subset start at 1, 2, 3 — so the last-resort
|
|
1014
|
+
* Latin-1 reading turns a page of text into control characters. Reading it
|
|
1015
|
+
* better is `font.ts`'s business; what this must guarantee is that nothing the
|
|
1016
|
+
* reader believes can produce a package that will not open.
|
|
1017
|
+
*
|
|
1018
|
+
* A lone surrogate is the same case: a half of a pair is not a character.
|
|
1019
|
+
*/
|
|
1020
|
+
/**
|
|
1021
|
+
* XML 1.0 §2.2 — whether a code point may appear in a document at all.
|
|
1022
|
+
*
|
|
1023
|
+
* Everything below U+0020 except tab, newline and return is forbidden, and no
|
|
1024
|
+
* escape exists for them: `` is as ill-formed as the byte itself. So is a
|
|
1025
|
+
* lone surrogate — half a pair is not a character — and so are U+FFFE/U+FFFF.
|
|
1026
|
+
*/
|
|
1027
|
+
function xmlAllows(cp) {
|
|
1028
|
+
if (cp === 9 || cp === 10 || cp === 13) return true;
|
|
1029
|
+
if (cp < 32) return false;
|
|
1030
|
+
if (cp >= 55296 && cp <= 57343) return false;
|
|
1031
|
+
if (cp === 65534 || cp === 65535) return false;
|
|
1032
|
+
return cp <= 1114111;
|
|
1033
|
+
}
|
|
1034
|
+
/**
|
|
1035
|
+
* Escape text for XML, and drop what XML cannot carry.
|
|
1036
|
+
*
|
|
1037
|
+
* The dropping is not fussiness: a package with one control character in it is
|
|
1038
|
+
* not a document. LibreOffice answers "source file could not be loaded" and
|
|
1039
|
+
* Word refuses it too, so the whole conversion is lost over one byte.
|
|
1040
|
+
*
|
|
1041
|
+
* They reach here from the PDF reader. A subset font that states neither a
|
|
1042
|
+
* `/ToUnicode` nor an `/Encoding /Differences` says nothing about what its
|
|
1043
|
+
* codes mean, and a subset's codes start at 1, 2, 3 — so the last-resort
|
|
1044
|
+
* Latin-1 reading turns a page of prose into control characters. Reading such
|
|
1045
|
+
* a font better is `font.ts`'s business; what this guarantees is that nothing
|
|
1046
|
+
* the reader believes can produce a package that will not open.
|
|
1047
|
+
*/
|
|
990
1048
|
function escapeXml(s) {
|
|
991
|
-
|
|
1049
|
+
let out = "";
|
|
1050
|
+
for (const ch of s) {
|
|
1051
|
+
if (!xmlAllows(ch.codePointAt(0) ?? 0)) continue;
|
|
1052
|
+
out += ch === "&" ? "&" : ch === "<" ? "<" : ch === ">" ? ">" : ch;
|
|
1053
|
+
}
|
|
1054
|
+
return out;
|
|
992
1055
|
}
|
|
993
1056
|
function escapeAttr(s) {
|
|
994
1057
|
return escapeXml(s).replace(/"/g, """);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "reamkit",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.28.0",
|
|
4
4
|
"description": "Ream — convert DOCX, XLSX, PPTX and PDF to PDF, SVG, HTML, DOCX and XLSX, built from scratch on the ECMA-376 and ISO 32000 specifications. Parse once, convert anywhere.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Alex Krassavin <info@reamkit.dev>",
|