reamkit 1.22.0 → 1.24.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/dist/esm/core/bmp.d.ts +33 -0
- package/dist/esm/core/bmp.js +276 -0
- package/dist/esm/core/converter/ream.d.ts +16 -0
- package/dist/esm/core/converter/ream.js +59 -9
- package/dist/esm/core/document-model/types.d.ts +55 -0
- package/dist/esm/core/drawingml/chart-geometry.js +14 -7
- package/dist/esm/core/drawingml/colors.d.ts +4 -2
- package/dist/esm/core/drawingml/colors.js +15 -0
- package/dist/esm/core/drawingml/diagram/colors.d.ts +52 -0
- package/dist/esm/core/drawingml/diagram/colors.js +125 -0
- package/dist/esm/core/drawingml/diagram/data-model.d.ts +47 -0
- package/dist/esm/core/drawingml/diagram/data-model.js +119 -0
- package/dist/esm/core/drawingml/diagram/layout-engine.d.ts +46 -0
- package/dist/esm/core/drawingml/diagram/layout-engine.js +948 -0
- package/dist/esm/core/drawingml/diagram/run.d.ts +37 -0
- package/dist/esm/core/drawingml/diagram/run.js +50 -0
- package/dist/esm/core/drawingml/diagram/to-drawing.d.ts +16 -0
- package/dist/esm/core/drawingml/diagram/to-drawing.js +86 -0
- package/dist/esm/core/drawingml/preset-geometry.js +116 -6
- package/dist/esm/core/drawingml/text-warp.d.ts +58 -0
- package/dist/esm/core/drawingml/text-warp.js +355 -0
- package/dist/esm/core/drawingml/theme-parser.d.ts +38 -0
- package/dist/esm/core/drawingml/theme-parser.js +73 -4
- package/dist/esm/core/font/measure.d.ts +12 -0
- package/dist/esm/core/font/measure.js +36 -0
- package/dist/esm/core/fonts/families.d.ts +10 -0
- package/dist/esm/core/fonts/families.js +44 -0
- package/dist/esm/core/fonts/index.d.ts +3 -2
- package/dist/esm/core/fonts/remote-fonts.d.ts +50 -0
- package/dist/esm/core/fonts/remote-fonts.js +114 -8
- package/dist/esm/core/fonts/scripts.d.ts +26 -0
- package/dist/esm/core/fonts/scripts.js +177 -0
- package/dist/esm/core/images.d.ts +30 -2
- package/dist/esm/core/images.js +121 -5
- package/dist/esm/core/metafile/blit.d.ts +33 -0
- package/dist/esm/core/metafile/blit.js +67 -0
- package/dist/esm/core/metafile/dib.d.ts +61 -0
- package/dist/esm/core/metafile/dib.js +205 -0
- package/dist/esm/core/metafile/emf.js +280 -38
- package/dist/esm/core/metafile/picture.d.ts +61 -1
- package/dist/esm/core/metafile/picture.js +70 -1
- package/dist/esm/core/metafile/wmf.js +202 -13
- package/dist/esm/core/ole/escher-blip.d.ts +12 -0
- package/dist/esm/core/ole/escher-blip.js +98 -0
- package/dist/esm/{pdf-reader → core}/png-encode.js +1 -1
- package/dist/esm/excel/print-model.js +5 -3
- package/dist/esm/excel/sheet-drawing.js +1 -1
- package/dist/esm/excel/sheet-to-flow.js +16 -2
- package/dist/esm/excel/styles-parser.js +1 -1
- package/dist/esm/excel/xls/biff-reader.js +53 -18
- package/dist/esm/excel/xls/biff-styles.d.ts +5 -2
- package/dist/esm/excel/xls/biff-styles.js +9 -7
- package/dist/esm/excel/xls/escher.js +90 -24
- package/dist/esm/html/html-writer.js +2 -1
- package/dist/esm/layout/page-doc.d.ts +74 -0
- package/dist/esm/layout/page-doc.js +14 -1
- package/dist/esm/layout/styled-layout.d.ts +2 -2
- package/dist/esm/layout/styled-layout.js +475 -48
- package/dist/esm/pdf/shading.js +8 -6
- package/dist/esm/pdf/styled-page-emitter.js +77 -5
- package/dist/esm/pdf/vector-graphics.js +1 -1
- package/dist/esm/pdf-reader/image-decode.js +1 -1
- package/dist/esm/pptx/embedded-fonts.d.ts +31 -0
- package/dist/esm/pptx/embedded-fonts.js +104 -0
- package/dist/esm/pptx/placeholder-cascade.d.ts +73 -6
- package/dist/esm/pptx/placeholder-cascade.js +114 -18
- package/dist/esm/pptx/ppt/ppt-reader.js +191 -13
- package/dist/esm/pptx/ppt/ppt-text.d.ts +107 -1
- package/dist/esm/pptx/ppt/ppt-text.js +873 -144
- package/dist/esm/pptx/pptx-reader.d.ts +8 -0
- package/dist/esm/pptx/pptx-reader.js +117 -15
- package/dist/esm/pptx/preset-table-styles.d.ts +9 -0
- package/dist/esm/pptx/preset-table-styles.js +27 -0
- package/dist/esm/pptx/slide-parser.d.ts +11 -2
- package/dist/esm/pptx/slide-parser.js +203 -44
- package/dist/esm/pptx/sp-helpers.d.ts +9 -4
- package/dist/esm/pptx/sp-helpers.js +48 -9
- package/dist/esm/pptx/table-style.d.ts +16 -1
- package/dist/esm/pptx/table-style.js +104 -10
- package/dist/esm/svg/svg-writer.js +1 -0
- package/dist/esm/word/document-parser.d.ts +11 -2
- package/dist/esm/word/document-parser.js +10 -7
- package/dist/esm/word/docx-reader.js +32 -16
- package/dist/esm/word/docx-to-pdf.d.ts +8 -7
- package/dist/esm/word/docx-to-pdf.js +25 -7
- package/dist/esm/word/docx-writer.js +4 -0
- package/dist/esm/word/drawing-parser.d.ts +20 -0
- package/dist/esm/word/drawing-parser.js +67 -22
- package/dist/esm/word/numbering-parser.d.ts +2 -1
- package/dist/esm/word/numbering-parser.js +6 -6
- package/dist/esm/word/paragraph-properties.d.ts +2 -1
- package/dist/esm/word/paragraph-properties.js +2 -2
- package/dist/esm/word/run-properties.d.ts +5 -2
- package/dist/esm/word/run-properties.js +13 -8
- package/dist/esm/word/styles-parser.d.ts +2 -1
- package/dist/esm/word/styles-parser.js +12 -12
- package/dist/esm/word/table-parser.js +6 -3
- package/dist/esm/word/theme-fonts.d.ts +10 -0
- package/dist/esm/word/theme-fonts.js +28 -0
- package/package.json +1 -1
- /package/dist/esm/{pdf-reader → core}/png-encode.d.ts +0 -0
package/dist/esm/pdf/shading.js
CHANGED
|
@@ -284,14 +284,16 @@ function normalizeStops(stops) {
|
|
|
284
284
|
colorHex: "000000",
|
|
285
285
|
alpha: 1
|
|
286
286
|
}];
|
|
287
|
-
out[0]
|
|
288
|
-
|
|
287
|
+
const first = out[0];
|
|
288
|
+
if (first.offset > 0) out.unshift({
|
|
289
|
+
...first,
|
|
289
290
|
offset: 0
|
|
290
|
-
};
|
|
291
|
-
out[out.length - 1]
|
|
292
|
-
|
|
291
|
+
});
|
|
292
|
+
const last = out[out.length - 1];
|
|
293
|
+
if (last.offset < 1) out.push({
|
|
294
|
+
...last,
|
|
293
295
|
offset: 1
|
|
294
|
-
};
|
|
296
|
+
});
|
|
295
297
|
return out;
|
|
296
298
|
}
|
|
297
299
|
function rgb01(hex) {
|
|
@@ -7,6 +7,7 @@ import { GLUE_SHRINK_RATIO } from "../layout/styled-layout.js";
|
|
|
7
7
|
import { paintPlan } from "../layout/page-doc.js";
|
|
8
8
|
import { emitClipPath, emitVectorShape, shadowBlurLayers } from "./vector-graphics.js";
|
|
9
9
|
import { buildGradientAlphaMask, buildGradientPattern, shapeBbox } from "./shading.js";
|
|
10
|
+
import { warpGlyphMatrix } from "../core/drawingml/text-warp.js";
|
|
10
11
|
import { sanitizeHref } from "../core/links.js";
|
|
11
12
|
import { embedAssociatedFile } from "./embedded-file.js";
|
|
12
13
|
import { buildSrgbIccProfile } from "./icc-profile.js";
|
|
@@ -111,7 +112,11 @@ function assembleStyledPdf(laid, options, doc) {
|
|
|
111
112
|
if (!pdfaProfile) for (const page of renderedPages) {
|
|
112
113
|
const ph = page.height;
|
|
113
114
|
const plan = paintPlan(page.commands);
|
|
114
|
-
const shapesNeedingPatterns = [...plan.shapes, ...[
|
|
115
|
+
const shapesNeedingPatterns = [...plan.shapes, ...[
|
|
116
|
+
...plan.behind,
|
|
117
|
+
...plan.pictures.flat(),
|
|
118
|
+
...plan.ordered.flat()
|
|
119
|
+
].filter((i) => i.type === "shape")];
|
|
115
120
|
for (const item of shapesNeedingPatterns) {
|
|
116
121
|
const gradient = item.shape.fillGradient;
|
|
117
122
|
if (!gradient) continue;
|
|
@@ -211,7 +216,11 @@ function assembleStyledPdf(laid, options, doc) {
|
|
|
211
216
|
wantAlpha(img.alpha);
|
|
212
217
|
wantDuotone(img, page.height);
|
|
213
218
|
}
|
|
214
|
-
for (const item of [
|
|
219
|
+
for (const item of [
|
|
220
|
+
...plan.behind,
|
|
221
|
+
...plan.pictures.flat(),
|
|
222
|
+
...plan.ordered.flat()
|
|
223
|
+
]) {
|
|
215
224
|
if (item.type === "image") {
|
|
216
225
|
wantAlpha(washVeil(item.wash)?.alpha);
|
|
217
226
|
wantAlpha(item.alpha);
|
|
@@ -621,6 +630,7 @@ var BORDER_DASHES = new Map([
|
|
|
621
630
|
2.5
|
|
622
631
|
]]
|
|
623
632
|
]);
|
|
633
|
+
var FAUX_ITALIC_SHEAR = .2126;
|
|
624
634
|
/** The PDF dash array for a border style; an empty string means a solid rule. */
|
|
625
635
|
function dashPatternFor(style) {
|
|
626
636
|
const pattern = style !== void 0 ? BORDER_DASHES.get(style) : void 0;
|
|
@@ -642,6 +652,8 @@ function emitPageContent(page, tagging, gradientNames, alphaStateNames, duotoneS
|
|
|
642
652
|
let lastTc = 0;
|
|
643
653
|
let lastSize = -1;
|
|
644
654
|
let lastColor = "";
|
|
655
|
+
let lastFauxWidth = 0;
|
|
656
|
+
let lastTz = 100;
|
|
645
657
|
const switchFontIfNeeded = (tok) => {
|
|
646
658
|
const fontKey = tok.font.resourceName;
|
|
647
659
|
if (fontKey !== lastFont || tok.fontSizePt !== lastSize) {
|
|
@@ -649,6 +661,16 @@ function emitPageContent(page, tagging, gradientNames, alphaStateNames, duotoneS
|
|
|
649
661
|
lastFont = fontKey;
|
|
650
662
|
lastSize = tok.fontSizePt;
|
|
651
663
|
}
|
|
664
|
+
const fauxWidth = tok.synthetic?.bold === true ? tok.fontSizePt * .03 : 0;
|
|
665
|
+
if (fauxWidth !== lastFauxWidth) {
|
|
666
|
+
out.push(fauxWidth > 0 ? `2 Tr ${formatNumber(fauxWidth)} w` : "0 Tr");
|
|
667
|
+
lastFauxWidth = fauxWidth;
|
|
668
|
+
}
|
|
669
|
+
const tz = Math.round((tok.synthetic?.widthScale ?? 1) * 100);
|
|
670
|
+
if (tz !== lastTz) {
|
|
671
|
+
out.push(`${formatNumber(tz)} Tz`);
|
|
672
|
+
lastTz = tz;
|
|
673
|
+
}
|
|
652
674
|
const tc = tok.resolvedRun.letterSpacingPt ?? 0;
|
|
653
675
|
if (tc !== lastTc) {
|
|
654
676
|
out.push(`${formatNumber(tc)} Tc`);
|
|
@@ -670,6 +692,12 @@ function emitPageContent(page, tagging, gradientNames, alphaStateNames, duotoneS
|
|
|
670
692
|
const b = tok.drawBox;
|
|
671
693
|
const ox = x + (b?.dxPt ?? 0);
|
|
672
694
|
const oy = baselineY + (b?.dyPt ?? 0);
|
|
695
|
+
for (const img of meta.images ?? []) {
|
|
696
|
+
if (img.resourceName === "") continue;
|
|
697
|
+
out.push("q");
|
|
698
|
+
out.push(...placeImage(ox + img.x, oy + img.y, img.width, img.height, void 0, img.rotationDeg));
|
|
699
|
+
out.push(`/${img.resourceName} Do`, "Q");
|
|
700
|
+
}
|
|
673
701
|
for (const sh of meta.shapes) for (const op of emitVectorShape({
|
|
674
702
|
...sh,
|
|
675
703
|
transform: [
|
|
@@ -693,6 +721,8 @@ function emitPageContent(page, tagging, gradientNames, alphaStateNames, duotoneS
|
|
|
693
721
|
out.push("ET");
|
|
694
722
|
}
|
|
695
723
|
lastFont = "";
|
|
724
|
+
lastFauxWidth = 0;
|
|
725
|
+
lastTz = 100;
|
|
696
726
|
lastSize = -1;
|
|
697
727
|
lastColor = "";
|
|
698
728
|
return;
|
|
@@ -739,6 +769,8 @@ function emitPageContent(page, tagging, gradientNames, alphaStateNames, duotoneS
|
|
|
739
769
|
out.push("Q");
|
|
740
770
|
}
|
|
741
771
|
lastFont = "";
|
|
772
|
+
lastFauxWidth = 0;
|
|
773
|
+
lastTz = 100;
|
|
742
774
|
lastSize = -1;
|
|
743
775
|
lastColor = "";
|
|
744
776
|
lastTc = 0;
|
|
@@ -771,6 +803,8 @@ function emitPageContent(page, tagging, gradientNames, alphaStateNames, duotoneS
|
|
|
771
803
|
out.push("f");
|
|
772
804
|
out.push("Q");
|
|
773
805
|
lastFont = "";
|
|
806
|
+
lastFauxWidth = 0;
|
|
807
|
+
lastTz = 100;
|
|
774
808
|
lastSize = -1;
|
|
775
809
|
lastColor = "";
|
|
776
810
|
} else {
|
|
@@ -796,6 +830,8 @@ function emitPageContent(page, tagging, gradientNames, alphaStateNames, duotoneS
|
|
|
796
830
|
};
|
|
797
831
|
for (const op of emitVectorShape(shape)) out.push(op);
|
|
798
832
|
lastFont = "";
|
|
833
|
+
lastFauxWidth = 0;
|
|
834
|
+
lastTz = 100;
|
|
799
835
|
lastSize = -1;
|
|
800
836
|
lastColor = "";
|
|
801
837
|
}
|
|
@@ -813,6 +849,8 @@ function emitPageContent(page, tagging, gradientNames, alphaStateNames, duotoneS
|
|
|
813
849
|
out.push("q");
|
|
814
850
|
out.push(`${formatNumber(clip.x)} ${formatNumber(H - clip.y - clip.height)} ${formatNumber(clip.width)} ${formatNumber(clip.height)} re W n`);
|
|
815
851
|
lastFont = "";
|
|
852
|
+
lastFauxWidth = 0;
|
|
853
|
+
lastTz = 100;
|
|
816
854
|
lastSize = -1;
|
|
817
855
|
lastColor = "";
|
|
818
856
|
lastTc = 0;
|
|
@@ -825,6 +863,8 @@ function emitPageContent(page, tagging, gradientNames, alphaStateNames, duotoneS
|
|
|
825
863
|
}
|
|
826
864
|
out.push("Q");
|
|
827
865
|
lastFont = "";
|
|
866
|
+
lastFauxWidth = 0;
|
|
867
|
+
lastTz = 100;
|
|
828
868
|
lastSize = -1;
|
|
829
869
|
lastColor = "";
|
|
830
870
|
lastTc = 0;
|
|
@@ -977,6 +1017,35 @@ function emitPageContent(page, tagging, gradientNames, alphaStateNames, duotoneS
|
|
|
977
1017
|
out.push("Q");
|
|
978
1018
|
}
|
|
979
1019
|
const hasRise = line.tokens.some((t) => t.kind === "text" && t.risePt !== void 0);
|
|
1020
|
+
const hasFauxItalic = line.tokens.some((t) => t.kind === "text" && t.synthetic?.italic === true);
|
|
1021
|
+
const warp = cmd.warp;
|
|
1022
|
+
if (warp) {
|
|
1023
|
+
if (!inBT) {
|
|
1024
|
+
out.push("BT");
|
|
1025
|
+
inBT = true;
|
|
1026
|
+
}
|
|
1027
|
+
let cursor = originX;
|
|
1028
|
+
for (const tok of line.tokens) {
|
|
1029
|
+
if (tok.kind !== "text" || tok.isSpace) {
|
|
1030
|
+
cursor += tok.widthPt;
|
|
1031
|
+
continue;
|
|
1032
|
+
}
|
|
1033
|
+
switchFontIfNeeded(tok);
|
|
1034
|
+
const chars = [...tok.text];
|
|
1035
|
+
const raw = chars.map((c) => tok.font.measure.textWidthPt(c, tok.fontSizePt));
|
|
1036
|
+
const total = raw.reduce((a, b) => a + b, 0);
|
|
1037
|
+
const k = total > 0 ? tok.widthPt / total : 1;
|
|
1038
|
+
for (let i = 0; i < chars.length; i++) {
|
|
1039
|
+
const adv = raw[i] * k;
|
|
1040
|
+
const m = warpGlyphMatrix(warp, cursor, adv, cmd.baselineY);
|
|
1041
|
+
cursor += adv;
|
|
1042
|
+
if (!m) continue;
|
|
1043
|
+
out.push(`${formatNumber(m[0])} ${formatNumber(-m[1])} ${formatNumber(m[2])} ${formatNumber(-m[3])} ${formatNumber(m[4])} ${formatNumber(H - m[5])} Tm`);
|
|
1044
|
+
out.push(tok.font.measure.showText(chars[i]));
|
|
1045
|
+
}
|
|
1046
|
+
}
|
|
1047
|
+
return;
|
|
1048
|
+
}
|
|
980
1049
|
if (rotationDeg !== 0 && !hasImageToken && !hasMathToken) {
|
|
981
1050
|
if (!inBT) {
|
|
982
1051
|
out.push("BT");
|
|
@@ -991,7 +1060,7 @@ function emitPageContent(page, tagging, gradientNames, alphaStateNames, duotoneS
|
|
|
991
1060
|
switchFontIfNeeded(tok);
|
|
992
1061
|
out.push(tok.font.measure.showText(tok.text));
|
|
993
1062
|
}
|
|
994
|
-
} else if (extraPerSpace !== 0 || hasImageToken || hasMathToken || hasRtl || hasRise || hasTab) {
|
|
1063
|
+
} else if (extraPerSpace !== 0 || hasImageToken || hasMathToken || hasRtl || hasRise || hasFauxItalic || hasTab) {
|
|
995
1064
|
const order = hasRtl ? lineVisualOrder(line) : line.tokens.map((_, i) => i);
|
|
996
1065
|
let x = originX;
|
|
997
1066
|
for (const ti of order) {
|
|
@@ -1013,7 +1082,8 @@ function emitPageContent(page, tagging, gradientNames, alphaStateNames, duotoneS
|
|
|
1013
1082
|
inBT = true;
|
|
1014
1083
|
}
|
|
1015
1084
|
switchFontIfNeeded(tok);
|
|
1016
|
-
|
|
1085
|
+
const slant = tok.synthetic?.italic === true ? FAUX_ITALIC_SHEAR : 0;
|
|
1086
|
+
out.push(`1 0 ${formatNumber(slant)} 1 ${formatNumber(x)} ${formatNumber(baselineY + (tok.risePt ?? 0))} Tm`);
|
|
1017
1087
|
out.push(showToken(tok));
|
|
1018
1088
|
const tokenX0 = x;
|
|
1019
1089
|
x += tok.widthPt;
|
|
@@ -1071,6 +1141,7 @@ function emitPageContent(page, tagging, gradientNames, alphaStateNames, duotoneS
|
|
|
1071
1141
|
if (item.type === "shape") {
|
|
1072
1142
|
const t = item.shape.transform;
|
|
1073
1143
|
const fillAlpha = item.shape.fillAlpha;
|
|
1144
|
+
const layer = item.shape.shadow ? shadowBlurLayers(item.shape.shadow) : void 0;
|
|
1074
1145
|
for (const op of emitVectorShape({
|
|
1075
1146
|
...item.shape,
|
|
1076
1147
|
transform: [
|
|
@@ -1081,7 +1152,7 @@ function emitPageContent(page, tagging, gradientNames, alphaStateNames, duotoneS
|
|
|
1081
1152
|
t[4],
|
|
1082
1153
|
H - t[5]
|
|
1083
1154
|
]
|
|
1084
|
-
}, gradientNames?.get(item.shape), void 0, gradientMaskNames?.get(item.shape) ?? (fillAlpha !== void 0 && fillAlpha < 1 ? alphaStateNames?.get(Math.round(fillAlpha * 1e3) / 1e3) : void 0))) out.push(op);
|
|
1155
|
+
}, gradientNames?.get(item.shape), layer && layer.alpha < 1 ? alphaStateNames?.get(Math.round(layer.alpha * 1e3) / 1e3) : void 0, gradientMaskNames?.get(item.shape) ?? (fillAlpha !== void 0 && fillAlpha < 1 ? alphaStateNames?.get(Math.round(fillAlpha * 1e3) / 1e3) : void 0))) out.push(op);
|
|
1085
1156
|
return;
|
|
1086
1157
|
}
|
|
1087
1158
|
if (item.type === "image") {
|
|
@@ -1254,6 +1325,7 @@ function emitPageContent(page, tagging, gradientNames, alphaStateNames, duotoneS
|
|
|
1254
1325
|
for (const item of run) emitInOrder(item);
|
|
1255
1326
|
if (tagging) out.push("EMC");
|
|
1256
1327
|
}
|
|
1328
|
+
for (const run of plan.ordered) for (const item of run) emitInOrder(item);
|
|
1257
1329
|
emitLinesPass();
|
|
1258
1330
|
return {
|
|
1259
1331
|
content: encoder.encode(out.join("\n")),
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { PDF_NULL, PdfHexString, PdfName, PdfStream } from "../pdf/objects.js";
|
|
2
|
+
import { encodePng } from "../core/png-encode.js";
|
|
2
3
|
import { lzwDecodeMsb } from "../core/lzw.js";
|
|
3
4
|
import { reversePredictor } from "./predictor.js";
|
|
4
5
|
import { decodeCcitt } from "./ccitt.js";
|
|
5
|
-
import { encodePng } from "./png-encode.js";
|
|
6
6
|
import { unzlibSync } from "fflate";
|
|
7
7
|
//#region src/pdf-reader/image-decode.ts
|
|
8
8
|
var MAX_PIXELS = 4e7;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { Loss } from '../core/ir/index.js';
|
|
2
|
+
import { OpcPackage } from '../core/opc/index.js';
|
|
3
|
+
import { PoNode } from '../core/po-helpers.js';
|
|
4
|
+
import { FontRegistry } from '../core/font/index.js';
|
|
5
|
+
/** What an `fntdata` part turned out to hold. */
|
|
6
|
+
type FaceBytes = {
|
|
7
|
+
readonly kind: 'font';
|
|
8
|
+
readonly bytes: Uint8Array;
|
|
9
|
+
} | {
|
|
10
|
+
readonly kind: 'compressed';
|
|
11
|
+
} | {
|
|
12
|
+
readonly kind: 'unreadable';
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Read one `fntdata` part: the font itself when the container stores it
|
|
16
|
+
* plainly, and what stopped it otherwise.
|
|
17
|
+
*
|
|
18
|
+
* @param data The part's bytes.
|
|
19
|
+
*/
|
|
20
|
+
export declare function readFntData(data: Uint8Array): FaceBytes;
|
|
21
|
+
/**
|
|
22
|
+
* §19.2.1.13 — the fonts a deck embeds, by normalized family name.
|
|
23
|
+
*
|
|
24
|
+
* @param pkg The opened `.pptx` package.
|
|
25
|
+
* @param presPath The presentation part's path (relationships resolve from it).
|
|
26
|
+
* @param pres Its parsed `p:presentation` element.
|
|
27
|
+
* @param onLoss Where a face that cannot be unpacked records itself.
|
|
28
|
+
* @returns The families whose faces were readable (empty when none were).
|
|
29
|
+
*/
|
|
30
|
+
export declare function loadPptxEmbeddedFonts(pkg: OpcPackage, presPath: string, pres: PoNode | undefined, onLoss: (loss: Loss) => void): Map<string, FontRegistry>;
|
|
31
|
+
export {};
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { FontRegistry } from "../core/font/font-registry.js";
|
|
2
|
+
import { poAttr, poChildren, poIs } from "../core/po-helpers.js";
|
|
3
|
+
//#region src/pptx/embedded-fonts.ts
|
|
4
|
+
var REL_FONT = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/font";
|
|
5
|
+
/** §19.2.1.13 — the four faces a `p:embeddedFont` may name, by element. */
|
|
6
|
+
var VARIANTS = [
|
|
7
|
+
["p:regular", "regular"],
|
|
8
|
+
["p:bold", "bold"],
|
|
9
|
+
["p:italic", "italic"],
|
|
10
|
+
["p:boldItalic", "boldItalic"]
|
|
11
|
+
];
|
|
12
|
+
var EOT_VERSIONS = new Set([
|
|
13
|
+
65536,
|
|
14
|
+
131073,
|
|
15
|
+
131074
|
|
16
|
+
]);
|
|
17
|
+
var TTEMBED_TTCOMPRESSED = 4;
|
|
18
|
+
var TTEMBED_XORENCRYPTDATA = 268435456;
|
|
19
|
+
/**
|
|
20
|
+
* Read one `fntdata` part: the font itself when the container stores it
|
|
21
|
+
* plainly, and what stopped it otherwise.
|
|
22
|
+
*
|
|
23
|
+
* @param data The part's bytes.
|
|
24
|
+
*/
|
|
25
|
+
function readFntData(data) {
|
|
26
|
+
if (isSfnt(data)) return {
|
|
27
|
+
kind: "font",
|
|
28
|
+
bytes: data
|
|
29
|
+
};
|
|
30
|
+
if (data.length < 82) return { kind: "unreadable" };
|
|
31
|
+
const v = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
32
|
+
const eotSize = v.getUint32(0, true);
|
|
33
|
+
const version = v.getUint32(8, true);
|
|
34
|
+
const flags = v.getUint32(12, true);
|
|
35
|
+
if (eotSize !== data.length || !EOT_VERSIONS.has(version)) return { kind: "unreadable" };
|
|
36
|
+
if ((flags & (TTEMBED_TTCOMPRESSED | TTEMBED_XORENCRYPTDATA)) !== 0) return { kind: "compressed" };
|
|
37
|
+
let at = 82;
|
|
38
|
+
for (let i = 0; i < 4; i++) {
|
|
39
|
+
if (at + 2 > data.length) return { kind: "unreadable" };
|
|
40
|
+
at += 2 + v.getUint16(at, true) + 2;
|
|
41
|
+
}
|
|
42
|
+
if (version !== 65536) {
|
|
43
|
+
if (at + 2 > data.length) return { kind: "unreadable" };
|
|
44
|
+
at += 2 + v.getUint16(at, true);
|
|
45
|
+
at = data.length - v.getUint32(4, true);
|
|
46
|
+
}
|
|
47
|
+
const bytes = data.subarray(at);
|
|
48
|
+
return isSfnt(bytes) ? {
|
|
49
|
+
kind: "font",
|
|
50
|
+
bytes
|
|
51
|
+
} : { kind: "unreadable" };
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* §19.2.1.13 — the fonts a deck embeds, by normalized family name.
|
|
55
|
+
*
|
|
56
|
+
* @param pkg The opened `.pptx` package.
|
|
57
|
+
* @param presPath The presentation part's path (relationships resolve from it).
|
|
58
|
+
* @param pres Its parsed `p:presentation` element.
|
|
59
|
+
* @param onLoss Where a face that cannot be unpacked records itself.
|
|
60
|
+
* @returns The families whose faces were readable (empty when none were).
|
|
61
|
+
*/
|
|
62
|
+
function loadPptxEmbeddedFonts(pkg, presPath, pres, onLoss) {
|
|
63
|
+
const out = /* @__PURE__ */ new Map();
|
|
64
|
+
const list = pres ? poChildren(pres).find((c) => poIs(c, "p:embeddedFontLst")) : void 0;
|
|
65
|
+
if (!list) return out;
|
|
66
|
+
const relById = new Map(pkg.getPartRelationships(presPath).map((r) => [r.id, r]));
|
|
67
|
+
for (const font of poChildren(list).filter((c) => poIs(c, "p:embeddedFont"))) {
|
|
68
|
+
const bytes = {};
|
|
69
|
+
let compressed = false;
|
|
70
|
+
for (const [tag, variant] of VARIANTS) {
|
|
71
|
+
const node = poChildren(font).find((c) => poIs(c, tag));
|
|
72
|
+
const rId = node ? poAttr(node, "r:id") : void 0;
|
|
73
|
+
const rel = rId !== void 0 ? relById.get(rId) : void 0;
|
|
74
|
+
if (!rel || rel.type !== REL_FONT) continue;
|
|
75
|
+
const part = pkg.resolveRelatedPart(presPath, rel);
|
|
76
|
+
if (!part) continue;
|
|
77
|
+
const face = readFntData(part.data);
|
|
78
|
+
if (face.kind === "compressed") compressed = true;
|
|
79
|
+
if (face.kind === "font") bytes[variant] = face.bytes;
|
|
80
|
+
}
|
|
81
|
+
const typeface = poChildren(font).find((c) => poIs(c, "p:font"));
|
|
82
|
+
const name = (typeface ? poAttr(typeface, "typeface") : void 0)?.trim() ?? "";
|
|
83
|
+
if (bytes.regular) try {
|
|
84
|
+
out.set(name.toLowerCase(), FontRegistry.fromBytes({
|
|
85
|
+
...bytes,
|
|
86
|
+
regular: bytes.regular
|
|
87
|
+
}));
|
|
88
|
+
continue;
|
|
89
|
+
} catch {}
|
|
90
|
+
if (compressed) onLoss({
|
|
91
|
+
feature: "font",
|
|
92
|
+
detail: `the deck embeds ${name || "a font"}, packed with MicroType Express (EOT TTEMBED_TTCOMPRESSED); it renders in a substitute`,
|
|
93
|
+
severity: "substituted"
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
return out;
|
|
97
|
+
}
|
|
98
|
+
function isSfnt(data) {
|
|
99
|
+
if (data.length < 4) return false;
|
|
100
|
+
const sig = (data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3]) >>> 0;
|
|
101
|
+
return sig === 65536 || sig === 1330926671 || sig === 1953658213 || sig === 1953784678;
|
|
102
|
+
}
|
|
103
|
+
//#endregion
|
|
104
|
+
export { loadPptxEmbeddedFonts };
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { ParagraphProperties, RunProperties } from '../core/document-model/index.js';
|
|
2
2
|
import { ColorResolver } from '../core/drawingml/colors.js';
|
|
3
|
+
import { ThemeFonts } from '../core/drawingml/theme-parser.js';
|
|
3
4
|
import { PoNode } from '../core/po-helpers.js';
|
|
4
5
|
import { PlaceholderRef, ShapeBoxEmu } from './sp-helpers.js';
|
|
6
|
+
import { Pt } from '../core/ir/index.js';
|
|
5
7
|
/**
|
|
6
8
|
* The placeholder cascade (PX2): the resolver a slide parser consults whenever a
|
|
7
9
|
* slide placeholder shape (`p:sp` with a `p:ph`) lacks its own geometry or run
|
|
@@ -27,17 +29,32 @@ export interface PlaceholderCascade {
|
|
|
27
29
|
*/
|
|
28
30
|
readonly anchorFor: (ph: PlaceholderRef) => 't' | 'ctr' | 'b' | undefined;
|
|
29
31
|
/**
|
|
30
|
-
* The
|
|
31
|
-
*
|
|
32
|
-
*
|
|
32
|
+
* The prototypes' own `p:spPr`, nearest first — the layout's, then the
|
|
33
|
+
* master's — for the properties a slide placeholder inherits rather than
|
|
34
|
+
* states: its fill, its outline, its geometry.
|
|
35
|
+
*
|
|
36
|
+
* A CHAIN and not one node, because the inheritance is per property. The
|
|
37
|
+
* layout's prototype may state a box and nothing else, and the fill then
|
|
38
|
+
* comes from the master: tdf104015's title is red in every reader and was a
|
|
39
|
+
* bare outline here, because the layout's `p:spPr` existed and stopped the
|
|
40
|
+
* search.
|
|
33
41
|
*/
|
|
34
|
-
readonly shapePropsFor: (ph: PlaceholderRef) => PoNode
|
|
42
|
+
readonly shapePropsFor: (ph: PlaceholderRef) => ReadonlyArray<PoNode>;
|
|
35
43
|
}
|
|
36
44
|
/** One level of a text style: how its paragraphs sit and how their runs read. */
|
|
37
45
|
interface LevelStyle {
|
|
38
46
|
readonly run: RunProperties;
|
|
39
47
|
readonly paragraph: ParagraphProperties;
|
|
40
48
|
readonly bullet?: LevelBullet;
|
|
49
|
+
/**
|
|
50
|
+
* §21.1.2.2.9/.10 — the space around the paragraph stated as a FRACTION of a
|
|
51
|
+
* line rather than a distance. A fraction of WHAT is only known once the
|
|
52
|
+
* levels have merged and the size is settled, so it travels this far raw.
|
|
53
|
+
*/
|
|
54
|
+
readonly spacingPct?: {
|
|
55
|
+
readonly before?: number;
|
|
56
|
+
readonly after?: number;
|
|
57
|
+
};
|
|
41
58
|
}
|
|
42
59
|
/**
|
|
43
60
|
* §21.1.2.4.4/.5/.6 — the bullet a level declares: none at all, a literal
|
|
@@ -78,8 +95,24 @@ export declare function parseBullet(pPr: PoNode | undefined, colors?: ColorResol
|
|
|
78
95
|
* @param layoutTree The parsed `p:sldLayout` part.
|
|
79
96
|
* @param masterTree The parsed `p:sldMaster` part, when present.
|
|
80
97
|
* @param colors The deck's colour resolver, for scheme colours in the text styles.
|
|
98
|
+
* @param deckDefaults The presentation's own default text style, as the floor.
|
|
99
|
+
* @param themeFonts The theme's font scheme, for the `+mn-lt` tokens.
|
|
100
|
+
*/
|
|
101
|
+
export declare function buildPlaceholderCascade(layoutTree: ReadonlyArray<PoNode>, masterTree: ReadonlyArray<PoNode> | undefined, colors: ColorResolver, deckDefaults?: ReadonlyArray<LevelStyle>, themeFonts?: ThemeFonts): PlaceholderCascade;
|
|
102
|
+
/**
|
|
103
|
+
* §21.1.2.2.9/.10 — the space a paragraph states as a FRACTION of a line, in
|
|
104
|
+
* points.
|
|
105
|
+
*
|
|
106
|
+
* A "line" here is the paragraph's own text at its natural height, which is the
|
|
107
|
+
* size times the same 1.2 the layout gives an unstated line. A level that
|
|
108
|
+
* states the fraction and leaves the size to another level is resolved once
|
|
109
|
+
* they have merged, which is why this is not read where the fraction is.
|
|
110
|
+
*
|
|
111
|
+
* @param pct The fraction, `0..n` (20% arrives as 0.2).
|
|
112
|
+
* @param sizePt The paragraph's resolved font size.
|
|
113
|
+
* @returns The distance, or `undefined` when the size is not known.
|
|
81
114
|
*/
|
|
82
|
-
export declare function
|
|
115
|
+
export declare function spacingFromLineFraction(pct: number | undefined, sizePt: number | undefined): Pt | undefined;
|
|
83
116
|
/**
|
|
84
117
|
* `a:lstStyle` (or a `p:txStyles` family) → its nine levels. Shared by the
|
|
85
118
|
* deck's default text style, the master's families and a prototype's own list,
|
|
@@ -90,5 +123,39 @@ export declare function buildPlaceholderCascade(layoutTree: ReadonlyArray<PoNode
|
|
|
90
123
|
* @param prefix The level element prefix: `a:lvl` here, always.
|
|
91
124
|
* @returns The nine levels, or an empty list when there is no such node.
|
|
92
125
|
*/
|
|
93
|
-
export declare function parseLevelStyles(list: PoNode | undefined, colors: ColorResolver): Array<LevelStyle>;
|
|
126
|
+
export declare function parseLevelStyles(list: PoNode | undefined, colors: ColorResolver, themeFonts?: ThemeFonts): Array<LevelStyle>;
|
|
127
|
+
/**
|
|
128
|
+
* A level's paragraph shape — §21.1.2.2.7 `@algn`, `@marL`/`@indent`, and the
|
|
129
|
+
* space around and between its lines.
|
|
130
|
+
*
|
|
131
|
+
* Both spacings come in two spellings: `a:spcPts` is a distance (hundredths of
|
|
132
|
+
* a point) and `a:spcPct` a FRACTION of a line (thousandths of a percent). Only
|
|
133
|
+
* the distance was read, so a deck that spaces its bullets the usual way — by
|
|
134
|
+
* fraction — set them solid.
|
|
135
|
+
*/
|
|
136
|
+
export declare function pPrToParagraphProps(lvlPr: PoNode | undefined): ParagraphProperties;
|
|
137
|
+
/**
|
|
138
|
+
* §21.1.2.2.5 `a:lnSpc` — the height of each line: a fraction of the natural
|
|
139
|
+
* one (`a:spcPct`) or a distance (`a:spcPts`).
|
|
140
|
+
*
|
|
141
|
+
* The model states a multiple the way §17.3.1.33 does — 12pt under the `auto`
|
|
142
|
+
* rule IS single — so a fraction needs no font size to express, which is why
|
|
143
|
+
* this resolves here and the paragraph SPACING has to wait for the size.
|
|
144
|
+
*
|
|
145
|
+
* @param pPr The paragraph properties (a level's or a paragraph's own).
|
|
146
|
+
* @returns The line spacing, or nothing when the node states none.
|
|
147
|
+
*/
|
|
148
|
+
export declare function lineSpacing(pPr: PoNode | undefined): ParagraphProperties;
|
|
149
|
+
/**
|
|
150
|
+
* §21.1.2.2.9/.10 — the fraction of a line a paragraph puts before and after
|
|
151
|
+
* itself, when it states one. The distance form is read beside it; this is what
|
|
152
|
+
* the caller must still resolve against the size.
|
|
153
|
+
*
|
|
154
|
+
* @param pPr The paragraph properties.
|
|
155
|
+
* @returns The two fractions (`0..n`), each present only when stated.
|
|
156
|
+
*/
|
|
157
|
+
export declare function spacingFractions(pPr: PoNode | undefined): {
|
|
158
|
+
readonly before?: number;
|
|
159
|
+
readonly after?: number;
|
|
160
|
+
} | undefined;
|
|
94
161
|
export {};
|