reamkit 1.21.0 → 1.23.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/bytes.d.ts +22 -4
- package/dist/esm/core/bytes.js +73 -5
- 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 +78 -0
- package/dist/esm/core/drawingml/chart-geometry.js +11 -5
- package/dist/esm/core/drawingml/chart-parser.d.ts +2 -1
- package/dist/esm/core/drawingml/chart-parser.js +23 -1
- package/dist/esm/core/drawingml/colors.d.ts +30 -4
- package/dist/esm/core/drawingml/colors.js +45 -6
- package/dist/esm/core/drawingml/preset-geometry.js +236 -0
- package/dist/esm/core/drawingml/theme-parser.d.ts +38 -0
- package/dist/esm/core/drawingml/theme-parser.js +64 -1
- 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/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 +139 -24
- package/dist/esm/core/metafile/picture.d.ts +12 -1
- package/dist/esm/core/metafile/symbol-fonts.d.ts +42 -0
- package/dist/esm/core/metafile/symbol-fonts.js +154 -0
- package/dist/esm/core/metafile/wmf.js +183 -10
- package/dist/esm/core/ole/escher-blip.d.ts +12 -0
- package/dist/esm/core/ole/escher-blip.js +88 -0
- package/dist/esm/{pdf-reader → core}/png-encode.js +1 -1
- package/dist/esm/core/vector.d.ts +5 -0
- package/dist/esm/excel/print-model.js +3 -1
- package/dist/esm/excel/sheet-shape-parser.js +1 -12
- 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/excel/xlsx-reader.d.ts +1 -1
- package/dist/esm/excel/xlsx-reader.js +3 -3
- package/dist/esm/layout/page-doc.d.ts +77 -0
- package/dist/esm/layout/page-doc.js +34 -18
- package/dist/esm/layout/styled-layout.d.ts +2 -2
- package/dist/esm/layout/styled-layout.js +467 -76
- package/dist/esm/pdf/shading.d.ts +19 -0
- package/dist/esm/pdf/shading.js +84 -11
- package/dist/esm/pdf/styled-page-emitter.js +647 -444
- 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/ole-preview.d.ts +10 -0
- package/dist/esm/pptx/ole-preview.js +52 -0
- package/dist/esm/pptx/placeholder-cascade.d.ts +136 -5
- package/dist/esm/pptx/placeholder-cascade.js +260 -27
- package/dist/esm/pptx/ppt/ppt-reader.js +120 -10
- package/dist/esm/pptx/ppt/ppt-text.d.ts +66 -1
- package/dist/esm/pptx/ppt/ppt-text.js +576 -137
- package/dist/esm/pptx/pptx-reader.d.ts +8 -0
- package/dist/esm/pptx/pptx-reader.js +271 -41
- 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 +78 -10
- package/dist/esm/pptx/slide-parser.js +396 -95
- package/dist/esm/pptx/sp-helpers.d.ts +2 -1
- package/dist/esm/pptx/sp-helpers.js +22 -6
- package/dist/esm/pptx/table-style.d.ts +64 -0
- package/dist/esm/pptx/table-style.js +203 -0
- package/dist/esm/svg/svg-writer.js +53 -5
- package/dist/esm/word/document-parser.d.ts +7 -1
- package/dist/esm/word/document-parser.js +6 -6
- package/dist/esm/word/docx-reader.js +8 -5
- 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/drawing-parser.d.ts +34 -0
- package/dist/esm/word/drawing-parser.js +173 -15
- 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 +3 -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
|
@@ -6,7 +6,7 @@ import { reverseByCodePoint } from "../core/bidi/index.js";
|
|
|
6
6
|
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
|
-
import { buildGradientPattern, shapeBbox } from "./shading.js";
|
|
9
|
+
import { buildGradientAlphaMask, buildGradientPattern, shapeBbox } from "./shading.js";
|
|
10
10
|
import { sanitizeHref } from "../core/links.js";
|
|
11
11
|
import { embedAssociatedFile } from "./embedded-file.js";
|
|
12
12
|
import { buildSrgbIccProfile } from "./icc-profile.js";
|
|
@@ -99,11 +99,20 @@ function assembleStyledPdf(laid, options, doc) {
|
|
|
99
99
|
let annotParentCount = 0;
|
|
100
100
|
const fontResourceDict = buildFontResourceDict(laid.fontResources, embeddedFonts);
|
|
101
101
|
const xobjectResourceDict = buildXObjectResourceDict(laid.imageResources, embeddedImages);
|
|
102
|
+
const imageRefByName = /* @__PURE__ */ new Map();
|
|
103
|
+
for (const [resourceId, res] of laid.imageResources) {
|
|
104
|
+
const r = embeddedImages.get(resourceId);
|
|
105
|
+
if (r) imageRefByName.set(res.resourceName, r);
|
|
106
|
+
}
|
|
102
107
|
const gradientNames = /* @__PURE__ */ new Map();
|
|
108
|
+
const gradientMaskNames = /* @__PURE__ */ new Map();
|
|
103
109
|
const patternEntries = {};
|
|
110
|
+
const extGStateEntries = {};
|
|
104
111
|
if (!pdfaProfile) for (const page of renderedPages) {
|
|
105
112
|
const ph = page.height;
|
|
106
|
-
|
|
113
|
+
const plan = paintPlan(page.commands);
|
|
114
|
+
const shapesNeedingPatterns = [...plan.shapes, ...[...plan.behind, ...plan.pictures.flat()].filter((i) => i.type === "shape")];
|
|
115
|
+
for (const item of shapesNeedingPatterns) {
|
|
107
116
|
const gradient = item.shape.fillGradient;
|
|
108
117
|
if (!gradient) continue;
|
|
109
118
|
const bbox = shapeBbox(item.shape);
|
|
@@ -120,10 +129,65 @@ function assembleStyledPdf(laid, options, doc) {
|
|
|
120
129
|
const nm = `Sh${gradientNames.size}`;
|
|
121
130
|
patternEntries[nm] = ref(buildGradientPattern(doc, gradient, bbox, ctm).id);
|
|
122
131
|
gradientNames.set(item.shape, nm);
|
|
132
|
+
const mask = buildGradientAlphaMask(doc, gradient, bbox, ctm);
|
|
133
|
+
if (mask) {
|
|
134
|
+
const gs = `GSm${gradientMaskNames.size}`;
|
|
135
|
+
gradientMaskNames.set(item.shape, gs);
|
|
136
|
+
extGStateEntries[gs] = dict({ SMask: dict({
|
|
137
|
+
S: name("Luminosity"),
|
|
138
|
+
G: ref(mask.id),
|
|
139
|
+
BC: [0]
|
|
140
|
+
}) });
|
|
141
|
+
}
|
|
123
142
|
}
|
|
124
143
|
}
|
|
144
|
+
const duotoneStates = /* @__PURE__ */ new Map();
|
|
145
|
+
const wantDuotone = (item, pageHeight) => {
|
|
146
|
+
if (!item.duotone || item.imageResourceName === "" || pdfaProfile) return void 0;
|
|
147
|
+
const key = [
|
|
148
|
+
item.imageResourceName,
|
|
149
|
+
Math.round(item.x * 100),
|
|
150
|
+
Math.round(item.y * 100),
|
|
151
|
+
Math.round(item.width * 100),
|
|
152
|
+
Math.round(item.height * 100)
|
|
153
|
+
].join("|");
|
|
154
|
+
const known = duotoneStates.get(key);
|
|
155
|
+
if (known !== void 0) return known;
|
|
156
|
+
const imageRef = imageRefByName.get(item.imageResourceName);
|
|
157
|
+
if (!imageRef) return void 0;
|
|
158
|
+
const form = doc.add(stream({
|
|
159
|
+
Type: name("XObject"),
|
|
160
|
+
Subtype: name("Form"),
|
|
161
|
+
BBox: [
|
|
162
|
+
0,
|
|
163
|
+
0,
|
|
164
|
+
item.width,
|
|
165
|
+
item.height
|
|
166
|
+
],
|
|
167
|
+
Matrix: [
|
|
168
|
+
1,
|
|
169
|
+
0,
|
|
170
|
+
0,
|
|
171
|
+
1,
|
|
172
|
+
item.x,
|
|
173
|
+
pageHeight - item.y - item.height
|
|
174
|
+
],
|
|
175
|
+
Group: dict({
|
|
176
|
+
S: name("Transparency"),
|
|
177
|
+
CS: name("DeviceGray")
|
|
178
|
+
}),
|
|
179
|
+
Resources: dict({ XObject: dict({ [item.imageResourceName]: ref(imageRef.id) }) })
|
|
180
|
+
}, encoder.encode(`q ${formatNumber(item.width)} 0 0 ${formatNumber(item.height)} 0 0 cm /${item.imageResourceName} Do Q`)));
|
|
181
|
+
const nm = `GSd${duotoneStates.size}`;
|
|
182
|
+
duotoneStates.set(key, nm);
|
|
183
|
+
extGStateEntries[nm] = dict({ SMask: dict({
|
|
184
|
+
S: name("Luminosity"),
|
|
185
|
+
G: ref(form.id),
|
|
186
|
+
BC: [0]
|
|
187
|
+
}) });
|
|
188
|
+
return nm;
|
|
189
|
+
};
|
|
125
190
|
const alphaStateNames = /* @__PURE__ */ new Map();
|
|
126
|
-
const extGStateEntries = {};
|
|
127
191
|
const wantAlpha = (alpha) => {
|
|
128
192
|
if (alpha === void 0 || alpha >= 1) return;
|
|
129
193
|
const key = Math.round(alpha * 1e3) / 1e3;
|
|
@@ -142,7 +206,23 @@ function assembleStyledPdf(laid, options, doc) {
|
|
|
142
206
|
if (s) wantAlpha(shadowBlurLayers(s).alpha);
|
|
143
207
|
wantAlpha(item.shape.fillAlpha);
|
|
144
208
|
}
|
|
145
|
-
for (const img of plan.images)
|
|
209
|
+
for (const img of plan.images) {
|
|
210
|
+
wantAlpha(washVeil(img.wash)?.alpha);
|
|
211
|
+
wantAlpha(img.alpha);
|
|
212
|
+
wantDuotone(img, page.height);
|
|
213
|
+
}
|
|
214
|
+
for (const item of [...plan.behind, ...plan.pictures.flat()]) {
|
|
215
|
+
if (item.type === "image") {
|
|
216
|
+
wantAlpha(washVeil(item.wash)?.alpha);
|
|
217
|
+
wantAlpha(item.alpha);
|
|
218
|
+
wantDuotone(item, page.height);
|
|
219
|
+
}
|
|
220
|
+
if (item.type === "shape") {
|
|
221
|
+
const s = item.shape.shadow;
|
|
222
|
+
if (s) wantAlpha(shadowBlurLayers(s).alpha);
|
|
223
|
+
wantAlpha(item.shape.fillAlpha);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
146
226
|
for (const line of plan.lines) for (const tok of line.line.tokens) {
|
|
147
227
|
if (tok.kind === "image" && tok.shadow) wantAlpha(shadowBlurLayers(tok.shadow).alpha);
|
|
148
228
|
if (tok.kind === "image") wantAlpha(washVeil(tok.wash)?.alpha);
|
|
@@ -179,7 +259,7 @@ function assembleStyledPdf(laid, options, doc) {
|
|
|
179
259
|
tagFor: (structId) => builder.node(structId).type
|
|
180
260
|
};
|
|
181
261
|
}
|
|
182
|
-
const { content: contentBytes, links } = emitPageContent(page, pageTagging, gradientNames, alphaStateNames);
|
|
262
|
+
const { content: contentBytes, links } = emitPageContent(page, pageTagging, gradientNames, alphaStateNames, wantDuotone, gradientMaskNames);
|
|
183
263
|
const contentsRef = doc.add(stream({}, contentBytes));
|
|
184
264
|
const pageEntries = {
|
|
185
265
|
Type: name("Page"),
|
|
@@ -449,6 +529,32 @@ function buildFontResourceDict(resources, embedded) {
|
|
|
449
529
|
}
|
|
450
530
|
return dict(entries);
|
|
451
531
|
}
|
|
532
|
+
/**
|
|
533
|
+
* The operators that paint one picture: normally the XObject itself, but for a
|
|
534
|
+
* §20.1.8.23 duotone the two colours it is recoloured between, composited
|
|
535
|
+
* through the picture's own luminosity (`state` is that soft-mask ExtGState).
|
|
536
|
+
*
|
|
537
|
+
* @param item The image to paint.
|
|
538
|
+
* @param yUp Its bottom edge in the page's y-up frame.
|
|
539
|
+
* @param state The duotone's soft-mask state name, when it has one.
|
|
540
|
+
* @returns The operators, without the surrounding `q`/`Q`.
|
|
541
|
+
*/
|
|
542
|
+
function paintImageBody(item, yUp, state) {
|
|
543
|
+
const place = placeImage(item.x, yUp, item.width, item.height, item.crop, item.rotationDeg, item.flipH, item.flipV);
|
|
544
|
+
if (state === void 0 || !item.duotone) return [...place, `/${item.imageResourceName} Do`];
|
|
545
|
+
const rect = `${formatNumber(item.x)} ${formatNumber(yUp)} ${formatNumber(item.width)} ${formatNumber(item.height)} re`;
|
|
546
|
+
const [sr, sg, sb] = hexToRgb01(item.duotone.shadowHex);
|
|
547
|
+
const [hr, hg, hb] = hexToRgb01(item.duotone.highlightHex);
|
|
548
|
+
return [
|
|
549
|
+
`${formatNumber(sr)} ${formatNumber(sg)} ${formatNumber(sb)} rg`,
|
|
550
|
+
rect,
|
|
551
|
+
"f",
|
|
552
|
+
`/${state} gs`,
|
|
553
|
+
`${formatNumber(hr)} ${formatNumber(hg)} ${formatNumber(hb)} rg`,
|
|
554
|
+
rect,
|
|
555
|
+
"f"
|
|
556
|
+
];
|
|
557
|
+
}
|
|
452
558
|
function buildXObjectResourceDict(resources, embedded) {
|
|
453
559
|
if (embedded.size === 0) return void 0;
|
|
454
560
|
const entries = {};
|
|
@@ -515,12 +621,13 @@ var BORDER_DASHES = new Map([
|
|
|
515
621
|
2.5
|
|
516
622
|
]]
|
|
517
623
|
]);
|
|
624
|
+
var FAUX_ITALIC_SHEAR = .2126;
|
|
518
625
|
/** The PDF dash array for a border style; an empty string means a solid rule. */
|
|
519
626
|
function dashPatternFor(style) {
|
|
520
627
|
const pattern = style !== void 0 ? BORDER_DASHES.get(style) : void 0;
|
|
521
628
|
return pattern ? `[${pattern.map(formatNumber).join(" ")}]` : "";
|
|
522
629
|
}
|
|
523
|
-
function emitPageContent(page, tagging, gradientNames, alphaStateNames) {
|
|
630
|
+
function emitPageContent(page, tagging, gradientNames, alphaStateNames, duotoneStateFor, gradientMaskNames) {
|
|
524
631
|
const commands = page.commands;
|
|
525
632
|
const links = [];
|
|
526
633
|
if (commands.length === 0) return {
|
|
@@ -530,17 +637,535 @@ function emitPageContent(page, tagging, gradientNames, alphaStateNames) {
|
|
|
530
637
|
const H = page.height;
|
|
531
638
|
const out = [];
|
|
532
639
|
const plan = paintPlan(commands);
|
|
640
|
+
const lines = plan.lines;
|
|
641
|
+
let inBT = false;
|
|
642
|
+
let lastFont = "";
|
|
643
|
+
let lastTc = 0;
|
|
644
|
+
let lastSize = -1;
|
|
645
|
+
let lastColor = "";
|
|
646
|
+
let lastFauxWidth = 0;
|
|
647
|
+
let lastTz = 100;
|
|
648
|
+
const switchFontIfNeeded = (tok) => {
|
|
649
|
+
const fontKey = tok.font.resourceName;
|
|
650
|
+
if (fontKey !== lastFont || tok.fontSizePt !== lastSize) {
|
|
651
|
+
out.push(`/${fontKey} ${formatNumber(tok.fontSizePt)} Tf`);
|
|
652
|
+
lastFont = fontKey;
|
|
653
|
+
lastSize = tok.fontSizePt;
|
|
654
|
+
}
|
|
655
|
+
const fauxWidth = tok.synthetic?.bold === true ? tok.fontSizePt * .03 : 0;
|
|
656
|
+
if (fauxWidth !== lastFauxWidth) {
|
|
657
|
+
out.push(fauxWidth > 0 ? `2 Tr ${formatNumber(fauxWidth)} w` : "0 Tr");
|
|
658
|
+
lastFauxWidth = fauxWidth;
|
|
659
|
+
}
|
|
660
|
+
const tz = Math.round((tok.synthetic?.widthScale ?? 1) * 100);
|
|
661
|
+
if (tz !== lastTz) {
|
|
662
|
+
out.push(`${formatNumber(tz)} Tz`);
|
|
663
|
+
lastTz = tz;
|
|
664
|
+
}
|
|
665
|
+
const tc = tok.resolvedRun.letterSpacingPt ?? 0;
|
|
666
|
+
if (tc !== lastTc) {
|
|
667
|
+
out.push(`${formatNumber(tc)} Tc`);
|
|
668
|
+
lastTc = tc;
|
|
669
|
+
}
|
|
670
|
+
if (tok.resolvedRun.colorHex !== lastColor) {
|
|
671
|
+
const [r, g, b] = hexToRgb01(tok.resolvedRun.colorHex);
|
|
672
|
+
out.push(`${formatNumber(r)} ${formatNumber(g)} ${formatNumber(b)} rg`);
|
|
673
|
+
lastColor = tok.resolvedRun.colorHex;
|
|
674
|
+
}
|
|
675
|
+
};
|
|
676
|
+
const emitImageToken = (tok, x, baselineY) => {
|
|
677
|
+
const meta = tok.metafile;
|
|
678
|
+
if (meta) {
|
|
679
|
+
if (inBT) {
|
|
680
|
+
out.push("ET");
|
|
681
|
+
inBT = false;
|
|
682
|
+
}
|
|
683
|
+
const b = tok.drawBox;
|
|
684
|
+
const ox = x + (b?.dxPt ?? 0);
|
|
685
|
+
const oy = baselineY + (b?.dyPt ?? 0);
|
|
686
|
+
for (const img of meta.images ?? []) {
|
|
687
|
+
if (img.resourceName === "") continue;
|
|
688
|
+
out.push("q");
|
|
689
|
+
out.push(...placeImage(ox + img.x, oy + img.y, img.width, img.height, void 0, img.rotationDeg));
|
|
690
|
+
out.push(`/${img.resourceName} Do`, "Q");
|
|
691
|
+
}
|
|
692
|
+
for (const sh of meta.shapes) for (const op of emitVectorShape({
|
|
693
|
+
...sh,
|
|
694
|
+
transform: [
|
|
695
|
+
1,
|
|
696
|
+
0,
|
|
697
|
+
0,
|
|
698
|
+
1,
|
|
699
|
+
ox,
|
|
700
|
+
oy
|
|
701
|
+
]
|
|
702
|
+
})) out.push(op);
|
|
703
|
+
for (const t of meta.texts) {
|
|
704
|
+
const first = t.line.tokens.find((k) => k.kind === "text");
|
|
705
|
+
if (!first) continue;
|
|
706
|
+
const [r, g, bl] = hexToRgb01(first.resolvedRun.colorHex);
|
|
707
|
+
out.push("BT");
|
|
708
|
+
out.push(`/${first.font.resourceName} ${formatNumber(first.fontSizePt)} Tf`);
|
|
709
|
+
out.push(`${formatNumber(r)} ${formatNumber(g)} ${formatNumber(bl)} rg`);
|
|
710
|
+
out.push(`1 0 0 1 ${formatNumber(ox + t.x)} ${formatNumber(oy + t.y)} Tm`);
|
|
711
|
+
out.push(first.font.measure.showText(first.text));
|
|
712
|
+
out.push("ET");
|
|
713
|
+
}
|
|
714
|
+
lastFont = "";
|
|
715
|
+
lastFauxWidth = 0;
|
|
716
|
+
lastTz = 100;
|
|
717
|
+
lastSize = -1;
|
|
718
|
+
lastColor = "";
|
|
719
|
+
return;
|
|
720
|
+
}
|
|
721
|
+
if (!tok.imageResourceName) return;
|
|
722
|
+
if (inBT) {
|
|
723
|
+
out.push("ET");
|
|
724
|
+
inBT = false;
|
|
725
|
+
}
|
|
726
|
+
const shdw = tok.shadow;
|
|
727
|
+
if (shdw) {
|
|
728
|
+
const bx = tok.drawBox;
|
|
729
|
+
const [shr, shg, shb] = hexToRgb01(shdw.colorHex);
|
|
730
|
+
const layers = shadowBlurLayers(shdw);
|
|
731
|
+
const state = layers.alpha < 1 ? alphaStateNames?.get(Math.round(layers.alpha * 1e3) / 1e3) : void 0;
|
|
732
|
+
const sx = x + (bx?.dxPt ?? 0) + shdw.dxPt;
|
|
733
|
+
const sy = baselineY + (bx?.dyPt ?? 0) - shdw.dyPt;
|
|
734
|
+
const sw = bx?.widthPt ?? tok.widthPt;
|
|
735
|
+
const sh = bx?.heightPt ?? tok.heightPt;
|
|
736
|
+
out.push("q");
|
|
737
|
+
if (state) out.push(`/${state} gs`);
|
|
738
|
+
out.push(`${formatNumber(shr)} ${formatNumber(shg)} ${formatNumber(shb)} rg`);
|
|
739
|
+
for (let i = 0; i < layers.count; i++) {
|
|
740
|
+
const grow = layers.count > 1 ? -shdw.blurPt / 2 + (i + .5) * shdw.blurPt / layers.count : 0;
|
|
741
|
+
out.push(`${formatNumber(sx - grow)} ${formatNumber(sy - grow)} ${formatNumber(Math.max(sw + 2 * grow, 0))} ${formatNumber(Math.max(sh + 2 * grow, 0))} re`);
|
|
742
|
+
out.push("f");
|
|
743
|
+
}
|
|
744
|
+
out.push("Q");
|
|
745
|
+
}
|
|
746
|
+
out.push("q");
|
|
747
|
+
const b = tok.drawBox;
|
|
748
|
+
out.push(...b ? placeImage(x + b.dxPt, baselineY + b.dyPt, b.widthPt, b.heightPt, tok.crop, tok.rotationDeg, tok.flipH, tok.flipV) : placeImage(x, baselineY, tok.widthPt, tok.heightPt, tok.crop, tok.rotationDeg, tok.flipH, tok.flipV));
|
|
749
|
+
out.push(`/${tok.imageResourceName} Do`);
|
|
750
|
+
out.push(...washItems(tok.wash, alphaStateNames));
|
|
751
|
+
out.push("Q");
|
|
752
|
+
const frame = tok.outline;
|
|
753
|
+
if (frame) {
|
|
754
|
+
const [fr, fg, fb] = hexToRgb01(frame.colorHex);
|
|
755
|
+
out.push("q");
|
|
756
|
+
out.push(`${formatNumber(frame.widthPt)} w`);
|
|
757
|
+
out.push(`${formatNumber(fr)} ${formatNumber(fg)} ${formatNumber(fb)} RG`);
|
|
758
|
+
out.push(`${formatNumber(x + (b?.dxPt ?? 0))} ${formatNumber(baselineY + (b?.dyPt ?? 0))} ${formatNumber(b?.widthPt ?? tok.widthPt)} ${formatNumber(b?.heightPt ?? tok.heightPt)} re`);
|
|
759
|
+
out.push("S");
|
|
760
|
+
out.push("Q");
|
|
761
|
+
}
|
|
762
|
+
lastFont = "";
|
|
763
|
+
lastFauxWidth = 0;
|
|
764
|
+
lastTz = 100;
|
|
765
|
+
lastSize = -1;
|
|
766
|
+
lastColor = "";
|
|
767
|
+
lastTc = 0;
|
|
768
|
+
};
|
|
769
|
+
const emitMathToken = (tok, originX, baselineY) => {
|
|
770
|
+
for (const it of tok.items) if (it.kind === "glyph") {
|
|
771
|
+
if (!inBT) {
|
|
772
|
+
out.push("BT");
|
|
773
|
+
inBT = true;
|
|
774
|
+
}
|
|
775
|
+
if (it.font.resourceName !== lastFont || it.sizePt !== lastSize) {
|
|
776
|
+
out.push(`/${it.font.resourceName} ${formatNumber(it.sizePt)} Tf`);
|
|
777
|
+
lastFont = it.font.resourceName;
|
|
778
|
+
lastSize = it.sizePt;
|
|
779
|
+
}
|
|
780
|
+
if (lastColor !== "000000") {
|
|
781
|
+
out.push("0 0 0 rg");
|
|
782
|
+
lastColor = "000000";
|
|
783
|
+
}
|
|
784
|
+
out.push(`1 0 0 1 ${formatNumber(originX + it.x)} ${formatNumber(baselineY + it.y)} Tm`);
|
|
785
|
+
out.push(it.font.measure.showText(it.text));
|
|
786
|
+
} else if (it.kind === "rule") {
|
|
787
|
+
if (inBT) {
|
|
788
|
+
out.push("ET");
|
|
789
|
+
inBT = false;
|
|
790
|
+
}
|
|
791
|
+
out.push("q");
|
|
792
|
+
out.push("0 0 0 rg");
|
|
793
|
+
out.push(`${formatNumber(originX + it.x)} ${formatNumber(baselineY + it.y)} ${formatNumber(it.w)} ${formatNumber(it.h)} re`);
|
|
794
|
+
out.push("f");
|
|
795
|
+
out.push("Q");
|
|
796
|
+
lastFont = "";
|
|
797
|
+
lastFauxWidth = 0;
|
|
798
|
+
lastTz = 100;
|
|
799
|
+
lastSize = -1;
|
|
800
|
+
lastColor = "";
|
|
801
|
+
} else {
|
|
802
|
+
if (inBT) {
|
|
803
|
+
out.push("ET");
|
|
804
|
+
inBT = false;
|
|
805
|
+
}
|
|
806
|
+
const shape = {
|
|
807
|
+
paths: [{ segments: it.segments }],
|
|
808
|
+
...it.fill ? { fillColorHex: "000000" } : {},
|
|
809
|
+
...it.strokeWidthPt !== void 0 ? { stroke: {
|
|
810
|
+
colorHex: "000000",
|
|
811
|
+
widthPt: it.strokeWidthPt
|
|
812
|
+
} } : {},
|
|
813
|
+
transform: [
|
|
814
|
+
1,
|
|
815
|
+
0,
|
|
816
|
+
0,
|
|
817
|
+
1,
|
|
818
|
+
originX,
|
|
819
|
+
baselineY
|
|
820
|
+
]
|
|
821
|
+
};
|
|
822
|
+
for (const op of emitVectorShape(shape)) out.push(op);
|
|
823
|
+
lastFont = "";
|
|
824
|
+
lastFauxWidth = 0;
|
|
825
|
+
lastTz = 100;
|
|
826
|
+
lastSize = -1;
|
|
827
|
+
lastColor = "";
|
|
828
|
+
}
|
|
829
|
+
};
|
|
830
|
+
const emitClipped = (cmd, body) => {
|
|
831
|
+
const clip = cmd.clip;
|
|
832
|
+
if (!clip) {
|
|
833
|
+
body(cmd);
|
|
834
|
+
return;
|
|
835
|
+
}
|
|
836
|
+
if (inBT) {
|
|
837
|
+
out.push("ET");
|
|
838
|
+
inBT = false;
|
|
839
|
+
}
|
|
840
|
+
out.push("q");
|
|
841
|
+
out.push(`${formatNumber(clip.x)} ${formatNumber(H - clip.y - clip.height)} ${formatNumber(clip.width)} ${formatNumber(clip.height)} re W n`);
|
|
842
|
+
lastFont = "";
|
|
843
|
+
lastFauxWidth = 0;
|
|
844
|
+
lastTz = 100;
|
|
845
|
+
lastSize = -1;
|
|
846
|
+
lastColor = "";
|
|
847
|
+
lastTc = 0;
|
|
848
|
+
out.push("BT");
|
|
849
|
+
inBT = true;
|
|
850
|
+
body(cmd);
|
|
851
|
+
if (inBT) {
|
|
852
|
+
out.push("ET");
|
|
853
|
+
inBT = false;
|
|
854
|
+
}
|
|
855
|
+
out.push("Q");
|
|
856
|
+
lastFont = "";
|
|
857
|
+
lastFauxWidth = 0;
|
|
858
|
+
lastTz = 100;
|
|
859
|
+
lastSize = -1;
|
|
860
|
+
lastColor = "";
|
|
861
|
+
lastTc = 0;
|
|
862
|
+
};
|
|
863
|
+
const emitOneLine = (cmd) => {
|
|
864
|
+
const line = cmd.line;
|
|
865
|
+
const originX = cmd.originX;
|
|
866
|
+
const baselineY = H - cmd.baselineY;
|
|
867
|
+
const rotationDeg = cmd.rotationDeg ?? 0;
|
|
868
|
+
const lineFs = line.maxFontSizePt || 12;
|
|
869
|
+
const linkAscent = Math.max(lineFs, line.mathAscentPt ?? 0);
|
|
870
|
+
const linkDescent = Math.max(lineFs * .2, line.mathDescentPt ?? 0);
|
|
871
|
+
let linkHref;
|
|
872
|
+
let linkAnchor;
|
|
873
|
+
let linkText = "";
|
|
874
|
+
let linkX0 = 0;
|
|
875
|
+
let linkX1 = 0;
|
|
876
|
+
const flushLink = () => {
|
|
877
|
+
if (linkHref === void 0 && linkAnchor === void 0) return;
|
|
878
|
+
const safe = linkHref !== void 0 ? sanitizeHref(linkHref) : void 0;
|
|
879
|
+
const target = safe !== void 0 ? { href: safe } : linkAnchor !== void 0 ? { anchor: linkAnchor } : void 0;
|
|
880
|
+
if (target) links.push({
|
|
881
|
+
...target,
|
|
882
|
+
text: linkText.trim(),
|
|
883
|
+
rect: [
|
|
884
|
+
linkX0,
|
|
885
|
+
baselineY - linkDescent,
|
|
886
|
+
linkX1,
|
|
887
|
+
baselineY + linkAscent
|
|
888
|
+
],
|
|
889
|
+
...cmd.structId !== void 0 ? { structId: cmd.structId } : {}
|
|
890
|
+
});
|
|
891
|
+
linkHref = void 0;
|
|
892
|
+
linkAnchor = void 0;
|
|
893
|
+
linkText = "";
|
|
894
|
+
};
|
|
895
|
+
const trackLink = (href, anchor, text, x0, x1) => {
|
|
896
|
+
if (href !== linkHref || anchor !== linkAnchor) {
|
|
897
|
+
flushLink();
|
|
898
|
+
if (href !== void 0 || anchor !== void 0) {
|
|
899
|
+
linkHref = href;
|
|
900
|
+
linkAnchor = anchor;
|
|
901
|
+
linkX0 = x0;
|
|
902
|
+
}
|
|
903
|
+
}
|
|
904
|
+
if (href !== void 0 || anchor !== void 0) {
|
|
905
|
+
linkX1 = x1;
|
|
906
|
+
linkText += text;
|
|
907
|
+
}
|
|
908
|
+
};
|
|
909
|
+
const extraPerSpace = computeJustifyExtra(line);
|
|
910
|
+
const hasImageToken = line.tokens.some((t) => t.kind === "image");
|
|
911
|
+
const hasMathToken = line.tokens.some((t) => t.kind === "math");
|
|
912
|
+
const hasRtl = line.tokens.some((t) => t.bidiLevel % 2 === 1);
|
|
913
|
+
const hasTab = line.tokens.some((t) => t.kind === "text" && t.tab === true);
|
|
914
|
+
/** A text token carrying underline or strikethrough. */
|
|
915
|
+
const isDecorated = (tok) => tok.kind === "text" && (tok.resolvedRun.underline !== "none" || tok.resolvedRun.strike);
|
|
916
|
+
const showToken = (tok) => {
|
|
917
|
+
const text = tok.bidiLevel % 2 === 1 ? reverseByCodePoint(tok.text) : tok.text;
|
|
918
|
+
return tok.font.measure.showText(text);
|
|
919
|
+
};
|
|
920
|
+
if (line.tokens.some((t) => t.kind === "text" && t.resolvedRun.shadingColorHex)) {
|
|
921
|
+
if (inBT) {
|
|
922
|
+
out.push("ET");
|
|
923
|
+
inBT = false;
|
|
924
|
+
}
|
|
925
|
+
const shAscent = Math.max(lineFs, line.mathAscentPt ?? 0);
|
|
926
|
+
const shDescent = Math.max(lineFs * .2, line.mathDescentPt ?? 0);
|
|
927
|
+
out.push("q");
|
|
928
|
+
let sx = originX;
|
|
929
|
+
let painted = "";
|
|
930
|
+
for (const tok of line.tokens) {
|
|
931
|
+
const w = tok.widthPt + (tok.kind === "text" && tok.isSpace ? extraPerSpace : 0);
|
|
932
|
+
const hex = tok.kind === "text" ? tok.resolvedRun.shadingColorHex : void 0;
|
|
933
|
+
if (hex !== void 0) {
|
|
934
|
+
if (hex !== painted) {
|
|
935
|
+
if (painted !== "") out.push("f");
|
|
936
|
+
const [sr, sg, sb] = hexToRgb01(hex);
|
|
937
|
+
out.push(`${formatNumber(sr)} ${formatNumber(sg)} ${formatNumber(sb)} rg`);
|
|
938
|
+
painted = hex;
|
|
939
|
+
}
|
|
940
|
+
out.push(`${formatNumber(sx)} ${formatNumber(baselineY - shDescent)} ${formatNumber(w)} ${formatNumber(shAscent + shDescent)} re`);
|
|
941
|
+
}
|
|
942
|
+
sx += w;
|
|
943
|
+
}
|
|
944
|
+
if (painted !== "") out.push("f");
|
|
945
|
+
out.push("Q");
|
|
946
|
+
}
|
|
947
|
+
if (line.tokens.some((t) => t.kind === "text" && t.highlight === true)) {
|
|
948
|
+
if (inBT) {
|
|
949
|
+
out.push("ET");
|
|
950
|
+
inBT = false;
|
|
951
|
+
}
|
|
952
|
+
const hlAscent = Math.max(lineFs, line.mathAscentPt ?? 0);
|
|
953
|
+
const hlDescent = Math.max(lineFs * .2, line.mathDescentPt ?? 0);
|
|
954
|
+
const [hr, hg, hb] = hexToRgb01("fff3a3");
|
|
955
|
+
out.push("q");
|
|
956
|
+
out.push(`${formatNumber(hr)} ${formatNumber(hg)} ${formatNumber(hb)} rg`);
|
|
957
|
+
let hx = originX;
|
|
958
|
+
for (const tok of line.tokens) {
|
|
959
|
+
const w = tok.widthPt + (tok.kind === "text" && tok.isSpace ? extraPerSpace : 0);
|
|
960
|
+
if (tok.kind === "text" && tok.highlight === true) out.push(`${formatNumber(hx)} ${formatNumber(baselineY - hlDescent)} ${formatNumber(w)} ${formatNumber(hlAscent + hlDescent)} re`);
|
|
961
|
+
hx += w;
|
|
962
|
+
}
|
|
963
|
+
out.push("f");
|
|
964
|
+
out.push("Q");
|
|
965
|
+
}
|
|
966
|
+
if (line.tokens.some(isDecorated)) {
|
|
967
|
+
if (inBT) {
|
|
968
|
+
out.push("ET");
|
|
969
|
+
inBT = false;
|
|
970
|
+
}
|
|
971
|
+
out.push("q");
|
|
972
|
+
let dx = originX;
|
|
973
|
+
for (const tok of line.tokens) {
|
|
974
|
+
const w = tok.widthPt + (tok.kind === "text" && tok.isSpace ? extraPerSpace : 0);
|
|
975
|
+
if (isDecorated(tok)) {
|
|
976
|
+
const thickness = Math.max(.4, tok.fontSizePt * .06);
|
|
977
|
+
const paint = (hex) => {
|
|
978
|
+
const [r, g, b] = hexToRgb01(hex);
|
|
979
|
+
out.push(`${formatNumber(r)} ${formatNumber(g)} ${formatNumber(b)} rg`);
|
|
980
|
+
};
|
|
981
|
+
paint(tok.resolvedRun.colorHex);
|
|
982
|
+
if (tok.resolvedRun.underline !== "none") {
|
|
983
|
+
if (tok.resolvedRun.underlineColorHex) paint(tok.resolvedRun.underlineColorHex);
|
|
984
|
+
const style = tok.resolvedRun.underline;
|
|
985
|
+
const t = style === "thick" || style === "dottedHeavy" || style === "dashHeavy" ? thickness * 2 : thickness;
|
|
986
|
+
const y = baselineY - tok.fontSizePt * .12 - t;
|
|
987
|
+
const dashed = style === "dotted" || style === "dottedHeavy" ? [t, t * 2] : style === "dash" || style === "dashHeavy" ? [t * 4, t * 3] : void 0;
|
|
988
|
+
if (dashed) {
|
|
989
|
+
out.push(`${formatNumber(t)} w`);
|
|
990
|
+
out.push(`[${dashed.map((n) => formatNumber(n)).join(" ")}] 0 d`);
|
|
991
|
+
const [r, g, b] = hexToRgb01(tok.resolvedRun.underlineColorHex ?? tok.resolvedRun.colorHex);
|
|
992
|
+
out.push(`${formatNumber(r)} ${formatNumber(g)} ${formatNumber(b)} RG`);
|
|
993
|
+
out.push(`${formatNumber(dx)} ${formatNumber(y + t / 2)} m ${formatNumber(dx + w)} ${formatNumber(y + t / 2)} l S`);
|
|
994
|
+
out.push("[] 0 d");
|
|
995
|
+
} else {
|
|
996
|
+
out.push(`${formatNumber(dx)} ${formatNumber(y)} ${formatNumber(w)} ${formatNumber(t)} re f`);
|
|
997
|
+
if (style === "double") out.push(`${formatNumber(dx)} ${formatNumber(y - t * 2)} ${formatNumber(w)} ${formatNumber(t)} re f`);
|
|
998
|
+
}
|
|
999
|
+
if (tok.resolvedRun.underlineColorHex) paint(tok.resolvedRun.colorHex);
|
|
1000
|
+
}
|
|
1001
|
+
if (tok.resolvedRun.strike) {
|
|
1002
|
+
const y = baselineY + tok.fontSizePt * .26;
|
|
1003
|
+
out.push(`${formatNumber(dx)} ${formatNumber(y)} ${formatNumber(w)} ${formatNumber(thickness)} re f`);
|
|
1004
|
+
}
|
|
1005
|
+
}
|
|
1006
|
+
dx += w;
|
|
1007
|
+
}
|
|
1008
|
+
out.push("Q");
|
|
1009
|
+
}
|
|
1010
|
+
const hasRise = line.tokens.some((t) => t.kind === "text" && t.risePt !== void 0);
|
|
1011
|
+
const hasFauxItalic = line.tokens.some((t) => t.kind === "text" && t.synthetic?.italic === true);
|
|
1012
|
+
if (rotationDeg !== 0 && !hasImageToken && !hasMathToken) {
|
|
1013
|
+
if (!inBT) {
|
|
1014
|
+
out.push("BT");
|
|
1015
|
+
inBT = true;
|
|
1016
|
+
}
|
|
1017
|
+
const rad = rotationDeg * Math.PI / 180;
|
|
1018
|
+
const cos = formatNumber(Math.cos(rad));
|
|
1019
|
+
const sin = formatNumber(Math.sin(rad));
|
|
1020
|
+
out.push(`${cos} ${sin} ${formatNumber(-Math.sin(rad))} ${cos} ${formatNumber(originX)} ${formatNumber(baselineY)} Tm`);
|
|
1021
|
+
for (const tok of line.tokens) {
|
|
1022
|
+
if (tok.kind !== "text") continue;
|
|
1023
|
+
switchFontIfNeeded(tok);
|
|
1024
|
+
out.push(tok.font.measure.showText(tok.text));
|
|
1025
|
+
}
|
|
1026
|
+
} else if (extraPerSpace !== 0 || hasImageToken || hasMathToken || hasRtl || hasRise || hasFauxItalic || hasTab) {
|
|
1027
|
+
const order = hasRtl ? lineVisualOrder(line) : line.tokens.map((_, i) => i);
|
|
1028
|
+
let x = originX;
|
|
1029
|
+
for (const ti of order) {
|
|
1030
|
+
const tok = line.tokens[ti];
|
|
1031
|
+
if (tok.kind === "image") {
|
|
1032
|
+
flushLink();
|
|
1033
|
+
emitImageToken(tok, x, baselineY);
|
|
1034
|
+
x += tok.widthPt;
|
|
1035
|
+
continue;
|
|
1036
|
+
}
|
|
1037
|
+
if (tok.kind === "math") {
|
|
1038
|
+
flushLink();
|
|
1039
|
+
emitMathToken(tok, x, baselineY);
|
|
1040
|
+
x += tok.widthPt;
|
|
1041
|
+
continue;
|
|
1042
|
+
}
|
|
1043
|
+
if (!inBT) {
|
|
1044
|
+
out.push("BT");
|
|
1045
|
+
inBT = true;
|
|
1046
|
+
}
|
|
1047
|
+
switchFontIfNeeded(tok);
|
|
1048
|
+
const slant = tok.synthetic?.italic === true ? FAUX_ITALIC_SHEAR : 0;
|
|
1049
|
+
out.push(`1 0 ${formatNumber(slant)} 1 ${formatNumber(x)} ${formatNumber(baselineY + (tok.risePt ?? 0))} Tm`);
|
|
1050
|
+
out.push(showToken(tok));
|
|
1051
|
+
const tokenX0 = x;
|
|
1052
|
+
x += tok.widthPt;
|
|
1053
|
+
if (tok.isSpace) x += extraPerSpace;
|
|
1054
|
+
trackLink(tok.href, tok.anchor, tok.text, tokenX0, x);
|
|
1055
|
+
}
|
|
1056
|
+
flushLink();
|
|
1057
|
+
} else {
|
|
1058
|
+
if (!inBT) {
|
|
1059
|
+
out.push("BT");
|
|
1060
|
+
inBT = true;
|
|
1061
|
+
}
|
|
1062
|
+
out.push(`1 0 0 1 ${formatNumber(originX)} ${formatNumber(baselineY)} Tm`);
|
|
1063
|
+
let x = originX;
|
|
1064
|
+
for (const tok of line.tokens) {
|
|
1065
|
+
if (tok.kind !== "text") continue;
|
|
1066
|
+
switchFontIfNeeded(tok);
|
|
1067
|
+
out.push(tok.font.measure.showText(tok.text));
|
|
1068
|
+
trackLink(tok.href, tok.anchor, tok.text, x, x + tok.widthPt);
|
|
1069
|
+
x += tok.widthPt;
|
|
1070
|
+
}
|
|
1071
|
+
flushLink();
|
|
1072
|
+
}
|
|
1073
|
+
};
|
|
1074
|
+
const emitLinesPass = () => {
|
|
1075
|
+
if (lines.length === 0) return;
|
|
1076
|
+
if (tagging) for (const cmd of lines) {
|
|
1077
|
+
if (inBT) {
|
|
1078
|
+
out.push("ET");
|
|
1079
|
+
inBT = false;
|
|
1080
|
+
}
|
|
1081
|
+
const sid = cmd.structId;
|
|
1082
|
+
if (sid !== void 0) {
|
|
1083
|
+
const mcid = tagging.next++;
|
|
1084
|
+
tagging.assigned = true;
|
|
1085
|
+
tagging.record(sid, mcid);
|
|
1086
|
+
out.push(`/${tagging.tagFor(sid)} <</MCID ${mcid}>> BDC`);
|
|
1087
|
+
} else if (cmd.artifact === "pagination") out.push("/Artifact <</Type /Pagination>> BDC");
|
|
1088
|
+
else out.push("/Artifact BMC");
|
|
1089
|
+
emitClipped(cmd, emitOneLine);
|
|
1090
|
+
if (inBT) {
|
|
1091
|
+
out.push("ET");
|
|
1092
|
+
inBT = false;
|
|
1093
|
+
}
|
|
1094
|
+
out.push("EMC");
|
|
1095
|
+
}
|
|
1096
|
+
else {
|
|
1097
|
+
out.push("BT");
|
|
1098
|
+
inBT = true;
|
|
1099
|
+
for (const cmd of lines) emitClipped(cmd, emitOneLine);
|
|
1100
|
+
if (inBT) out.push("ET");
|
|
1101
|
+
}
|
|
1102
|
+
};
|
|
1103
|
+
const emitInOrder = (item) => {
|
|
1104
|
+
if (item.type === "shape") {
|
|
1105
|
+
const t = item.shape.transform;
|
|
1106
|
+
const fillAlpha = item.shape.fillAlpha;
|
|
1107
|
+
for (const op of emitVectorShape({
|
|
1108
|
+
...item.shape,
|
|
1109
|
+
transform: [
|
|
1110
|
+
t[0],
|
|
1111
|
+
-t[1],
|
|
1112
|
+
t[2],
|
|
1113
|
+
-t[3],
|
|
1114
|
+
t[4],
|
|
1115
|
+
H - t[5]
|
|
1116
|
+
]
|
|
1117
|
+
}, 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);
|
|
1118
|
+
return;
|
|
1119
|
+
}
|
|
1120
|
+
if (item.type === "image") {
|
|
1121
|
+
if (item.imageResourceName === "") return;
|
|
1122
|
+
out.push("q");
|
|
1123
|
+
if (item.clip) {
|
|
1124
|
+
const t = item.clip.transform;
|
|
1125
|
+
out.push(...emitClipPath(item.clip.paths, [
|
|
1126
|
+
t[0],
|
|
1127
|
+
-t[1],
|
|
1128
|
+
t[2],
|
|
1129
|
+
-t[3],
|
|
1130
|
+
t[4],
|
|
1131
|
+
H - t[5]
|
|
1132
|
+
]));
|
|
1133
|
+
}
|
|
1134
|
+
const state = item.alpha !== void 0 && item.alpha < 1 ? alphaStateNames?.get(Math.round(item.alpha * 1e3) / 1e3) : void 0;
|
|
1135
|
+
if (state !== void 0) out.push(`/${state} gs`);
|
|
1136
|
+
out.push(...paintImageBody(item, H - item.y - item.height, duotoneStateFor?.(item, H)));
|
|
1137
|
+
out.push(...washItems(item.wash, alphaStateNames));
|
|
1138
|
+
out.push("Q");
|
|
1139
|
+
return;
|
|
1140
|
+
}
|
|
1141
|
+
if (item.type === "fill") {
|
|
1142
|
+
const [r, g, b] = hexToRgb01(item.fillColorHex);
|
|
1143
|
+
out.push(`${formatNumber(r)} ${formatNumber(g)} ${formatNumber(b)} rg`, `${formatNumber(item.x)} ${formatNumber(H - item.y - item.height)} ${formatNumber(item.width)} ${formatNumber(item.height)} re`, "f");
|
|
1144
|
+
return;
|
|
1145
|
+
}
|
|
1146
|
+
if (item.type !== "line") return;
|
|
1147
|
+
emitClipped(item, emitOneLine);
|
|
1148
|
+
if (inBT) {
|
|
1149
|
+
out.push("ET");
|
|
1150
|
+
inBT = false;
|
|
1151
|
+
}
|
|
1152
|
+
};
|
|
1153
|
+
if (plan.behind.length > 0) {
|
|
1154
|
+
if (tagging) out.push("/Artifact BMC");
|
|
1155
|
+
for (const item of plan.behind) emitInOrder(item);
|
|
1156
|
+
if (tagging) out.push("EMC");
|
|
1157
|
+
}
|
|
533
1158
|
const fills = plan.fills;
|
|
534
1159
|
if (fills.length > 0) {
|
|
535
1160
|
if (tagging) out.push("/Artifact BMC");
|
|
536
1161
|
out.push("q");
|
|
537
|
-
let
|
|
1162
|
+
let lastFill = "";
|
|
538
1163
|
for (const f of fills) {
|
|
539
1164
|
const color = f.fillColorHex;
|
|
540
|
-
if (color !==
|
|
1165
|
+
if (color !== lastFill) {
|
|
541
1166
|
const [r, g, b] = hexToRgb01(color);
|
|
542
1167
|
out.push(`${formatNumber(r)} ${formatNumber(g)} ${formatNumber(b)} rg`);
|
|
543
|
-
|
|
1168
|
+
lastFill = color;
|
|
544
1169
|
}
|
|
545
1170
|
out.push(`${formatNumber(f.x)} ${formatNumber(H - f.y - f.height)} ${formatNumber(f.width)} ${formatNumber(f.height)} re`);
|
|
546
1171
|
out.push("f");
|
|
@@ -561,8 +1186,9 @@ function emitPageContent(page, tagging, gradientNames, alphaStateNames) {
|
|
|
561
1186
|
H - t[5]
|
|
562
1187
|
]));
|
|
563
1188
|
}
|
|
564
|
-
|
|
565
|
-
out.push(`/${
|
|
1189
|
+
const state = img.alpha !== void 0 && img.alpha < 1 ? alphaStateNames?.get(Math.round(img.alpha * 1e3) / 1e3) : void 0;
|
|
1190
|
+
if (state !== void 0) out.push(`/${state} gs`);
|
|
1191
|
+
out.push(...paintImageBody(img, H - img.y - img.height, duotoneStateFor?.(img, H)));
|
|
566
1192
|
out.push(...washItems(img.wash, alphaStateNames));
|
|
567
1193
|
out.push("Q");
|
|
568
1194
|
});
|
|
@@ -572,7 +1198,7 @@ function emitPageContent(page, tagging, gradientNames, alphaStateNames) {
|
|
|
572
1198
|
out.push("q");
|
|
573
1199
|
out.push("2 J");
|
|
574
1200
|
let lastWidth = -1;
|
|
575
|
-
let
|
|
1201
|
+
let lastStroke = "";
|
|
576
1202
|
let lastDash = "";
|
|
577
1203
|
for (const b of borders) {
|
|
578
1204
|
const width = b.borderSizePt;
|
|
@@ -587,10 +1213,10 @@ function emitPageContent(page, tagging, gradientNames, alphaStateNames) {
|
|
|
587
1213
|
out.push(`${formatNumber(strokeW)} w`);
|
|
588
1214
|
lastWidth = strokeW;
|
|
589
1215
|
}
|
|
590
|
-
if (color !==
|
|
1216
|
+
if (color !== lastStroke) {
|
|
591
1217
|
const [r, g, bl] = hexToRgb01(color);
|
|
592
1218
|
out.push(`${formatNumber(r)} ${formatNumber(g)} ${formatNumber(bl)} RG`);
|
|
593
|
-
|
|
1219
|
+
lastStroke = color;
|
|
594
1220
|
}
|
|
595
1221
|
const x = b.x;
|
|
596
1222
|
const y = H - b.y - b.height;
|
|
@@ -652,439 +1278,16 @@ function emitPageContent(page, tagging, gradientNames, alphaStateNames) {
|
|
|
652
1278
|
const shadowLayer = sh.shape.shadow ? shadowBlurLayers(sh.shape.shadow) : void 0;
|
|
653
1279
|
const alphaState = shadowLayer && shadowLayer.alpha < 1 ? alphaStateNames?.get(Math.round(shadowLayer.alpha * 1e3) / 1e3) : void 0;
|
|
654
1280
|
const fillAlpha = sh.shape.fillAlpha;
|
|
655
|
-
const fillAlphaState = fillAlpha !== void 0 && fillAlpha < 1 ? alphaStateNames?.get(Math.round(fillAlpha * 1e3) / 1e3) : void 0;
|
|
1281
|
+
const fillAlphaState = gradientMaskNames?.get(sh.shape) ?? (fillAlpha !== void 0 && fillAlpha < 1 ? alphaStateNames?.get(Math.round(fillAlpha * 1e3) / 1e3) : void 0);
|
|
656
1282
|
for (const op of emitVectorShape(shape, gradientNames?.get(sh.shape), alphaState, fillAlphaState)) out.push(op);
|
|
657
1283
|
});
|
|
658
|
-
const
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
let lastSize = -1;
|
|
664
|
-
let lastColor = "";
|
|
665
|
-
const switchFontIfNeeded = (tok) => {
|
|
666
|
-
const fontKey = tok.font.resourceName;
|
|
667
|
-
if (fontKey !== lastFont || tok.fontSizePt !== lastSize) {
|
|
668
|
-
out.push(`/${fontKey} ${formatNumber(tok.fontSizePt)} Tf`);
|
|
669
|
-
lastFont = fontKey;
|
|
670
|
-
lastSize = tok.fontSizePt;
|
|
671
|
-
}
|
|
672
|
-
const tc = tok.resolvedRun.letterSpacingPt ?? 0;
|
|
673
|
-
if (tc !== lastTc) {
|
|
674
|
-
out.push(`${formatNumber(tc)} Tc`);
|
|
675
|
-
lastTc = tc;
|
|
676
|
-
}
|
|
677
|
-
if (tok.resolvedRun.colorHex !== lastColor) {
|
|
678
|
-
const [r, g, b] = hexToRgb01(tok.resolvedRun.colorHex);
|
|
679
|
-
out.push(`${formatNumber(r)} ${formatNumber(g)} ${formatNumber(b)} rg`);
|
|
680
|
-
lastColor = tok.resolvedRun.colorHex;
|
|
681
|
-
}
|
|
682
|
-
};
|
|
683
|
-
const emitImageToken = (tok, x, baselineY) => {
|
|
684
|
-
const meta = tok.metafile;
|
|
685
|
-
if (meta) {
|
|
686
|
-
if (inBT) {
|
|
687
|
-
out.push("ET");
|
|
688
|
-
inBT = false;
|
|
689
|
-
}
|
|
690
|
-
const b = tok.drawBox;
|
|
691
|
-
const ox = x + (b?.dxPt ?? 0);
|
|
692
|
-
const oy = baselineY + (b?.dyPt ?? 0);
|
|
693
|
-
for (const sh of meta.shapes) for (const op of emitVectorShape({
|
|
694
|
-
...sh,
|
|
695
|
-
transform: [
|
|
696
|
-
1,
|
|
697
|
-
0,
|
|
698
|
-
0,
|
|
699
|
-
1,
|
|
700
|
-
ox,
|
|
701
|
-
oy
|
|
702
|
-
]
|
|
703
|
-
})) out.push(op);
|
|
704
|
-
for (const t of meta.texts) {
|
|
705
|
-
const first = t.line.tokens.find((k) => k.kind === "text");
|
|
706
|
-
if (!first) continue;
|
|
707
|
-
const [r, g, bl] = hexToRgb01(first.resolvedRun.colorHex);
|
|
708
|
-
out.push("BT");
|
|
709
|
-
out.push(`/${first.font.resourceName} ${formatNumber(first.fontSizePt)} Tf`);
|
|
710
|
-
out.push(`${formatNumber(r)} ${formatNumber(g)} ${formatNumber(bl)} rg`);
|
|
711
|
-
out.push(`1 0 0 1 ${formatNumber(ox + t.x)} ${formatNumber(oy + t.y)} Tm`);
|
|
712
|
-
out.push(first.font.measure.showText(first.text));
|
|
713
|
-
out.push("ET");
|
|
714
|
-
}
|
|
715
|
-
lastFont = "";
|
|
716
|
-
lastSize = -1;
|
|
717
|
-
lastColor = "";
|
|
718
|
-
return;
|
|
719
|
-
}
|
|
720
|
-
if (!tok.imageResourceName) return;
|
|
721
|
-
if (inBT) {
|
|
722
|
-
out.push("ET");
|
|
723
|
-
inBT = false;
|
|
724
|
-
}
|
|
725
|
-
const shdw = tok.shadow;
|
|
726
|
-
if (shdw) {
|
|
727
|
-
const bx = tok.drawBox;
|
|
728
|
-
const [shr, shg, shb] = hexToRgb01(shdw.colorHex);
|
|
729
|
-
const layers = shadowBlurLayers(shdw);
|
|
730
|
-
const state = layers.alpha < 1 ? alphaStateNames?.get(Math.round(layers.alpha * 1e3) / 1e3) : void 0;
|
|
731
|
-
const sx = x + (bx?.dxPt ?? 0) + shdw.dxPt;
|
|
732
|
-
const sy = baselineY + (bx?.dyPt ?? 0) - shdw.dyPt;
|
|
733
|
-
const sw = bx?.widthPt ?? tok.widthPt;
|
|
734
|
-
const sh = bx?.heightPt ?? tok.heightPt;
|
|
735
|
-
out.push("q");
|
|
736
|
-
if (state) out.push(`/${state} gs`);
|
|
737
|
-
out.push(`${formatNumber(shr)} ${formatNumber(shg)} ${formatNumber(shb)} rg`);
|
|
738
|
-
for (let i = 0; i < layers.count; i++) {
|
|
739
|
-
const grow = layers.count > 1 ? -shdw.blurPt / 2 + (i + .5) * shdw.blurPt / layers.count : 0;
|
|
740
|
-
out.push(`${formatNumber(sx - grow)} ${formatNumber(sy - grow)} ${formatNumber(Math.max(sw + 2 * grow, 0))} ${formatNumber(Math.max(sh + 2 * grow, 0))} re`);
|
|
741
|
-
out.push("f");
|
|
742
|
-
}
|
|
743
|
-
out.push("Q");
|
|
744
|
-
}
|
|
745
|
-
out.push("q");
|
|
746
|
-
const b = tok.drawBox;
|
|
747
|
-
out.push(...b ? placeImage(x + b.dxPt, baselineY + b.dyPt, b.widthPt, b.heightPt, tok.crop, tok.rotationDeg, tok.flipH, tok.flipV) : placeImage(x, baselineY, tok.widthPt, tok.heightPt, tok.crop, tok.rotationDeg, tok.flipH, tok.flipV));
|
|
748
|
-
out.push(`/${tok.imageResourceName} Do`);
|
|
749
|
-
out.push(...washItems(tok.wash, alphaStateNames));
|
|
750
|
-
out.push("Q");
|
|
751
|
-
const frame = tok.outline;
|
|
752
|
-
if (frame) {
|
|
753
|
-
const [fr, fg, fb] = hexToRgb01(frame.colorHex);
|
|
754
|
-
out.push("q");
|
|
755
|
-
out.push(`${formatNumber(frame.widthPt)} w`);
|
|
756
|
-
out.push(`${formatNumber(fr)} ${formatNumber(fg)} ${formatNumber(fb)} RG`);
|
|
757
|
-
out.push(`${formatNumber(x + (b?.dxPt ?? 0))} ${formatNumber(baselineY + (b?.dyPt ?? 0))} ${formatNumber(b?.widthPt ?? tok.widthPt)} ${formatNumber(b?.heightPt ?? tok.heightPt)} re`);
|
|
758
|
-
out.push("S");
|
|
759
|
-
out.push("Q");
|
|
760
|
-
}
|
|
761
|
-
lastFont = "";
|
|
762
|
-
lastSize = -1;
|
|
763
|
-
lastColor = "";
|
|
764
|
-
lastTc = 0;
|
|
765
|
-
};
|
|
766
|
-
const emitMathToken = (tok, originX, baselineY) => {
|
|
767
|
-
for (const it of tok.items) if (it.kind === "glyph") {
|
|
768
|
-
if (!inBT) {
|
|
769
|
-
out.push("BT");
|
|
770
|
-
inBT = true;
|
|
771
|
-
}
|
|
772
|
-
if (it.font.resourceName !== lastFont || it.sizePt !== lastSize) {
|
|
773
|
-
out.push(`/${it.font.resourceName} ${formatNumber(it.sizePt)} Tf`);
|
|
774
|
-
lastFont = it.font.resourceName;
|
|
775
|
-
lastSize = it.sizePt;
|
|
776
|
-
}
|
|
777
|
-
if (lastColor !== "000000") {
|
|
778
|
-
out.push("0 0 0 rg");
|
|
779
|
-
lastColor = "000000";
|
|
780
|
-
}
|
|
781
|
-
out.push(`1 0 0 1 ${formatNumber(originX + it.x)} ${formatNumber(baselineY + it.y)} Tm`);
|
|
782
|
-
out.push(it.font.measure.showText(it.text));
|
|
783
|
-
} else if (it.kind === "rule") {
|
|
784
|
-
if (inBT) {
|
|
785
|
-
out.push("ET");
|
|
786
|
-
inBT = false;
|
|
787
|
-
}
|
|
788
|
-
out.push("q");
|
|
789
|
-
out.push("0 0 0 rg");
|
|
790
|
-
out.push(`${formatNumber(originX + it.x)} ${formatNumber(baselineY + it.y)} ${formatNumber(it.w)} ${formatNumber(it.h)} re`);
|
|
791
|
-
out.push("f");
|
|
792
|
-
out.push("Q");
|
|
793
|
-
lastFont = "";
|
|
794
|
-
lastSize = -1;
|
|
795
|
-
lastColor = "";
|
|
796
|
-
} else {
|
|
797
|
-
if (inBT) {
|
|
798
|
-
out.push("ET");
|
|
799
|
-
inBT = false;
|
|
800
|
-
}
|
|
801
|
-
const shape = {
|
|
802
|
-
paths: [{ segments: it.segments }],
|
|
803
|
-
...it.fill ? { fillColorHex: "000000" } : {},
|
|
804
|
-
...it.strokeWidthPt !== void 0 ? { stroke: {
|
|
805
|
-
colorHex: "000000",
|
|
806
|
-
widthPt: it.strokeWidthPt
|
|
807
|
-
} } : {},
|
|
808
|
-
transform: [
|
|
809
|
-
1,
|
|
810
|
-
0,
|
|
811
|
-
0,
|
|
812
|
-
1,
|
|
813
|
-
originX,
|
|
814
|
-
baselineY
|
|
815
|
-
]
|
|
816
|
-
};
|
|
817
|
-
for (const op of emitVectorShape(shape)) out.push(op);
|
|
818
|
-
lastFont = "";
|
|
819
|
-
lastSize = -1;
|
|
820
|
-
lastColor = "";
|
|
821
|
-
}
|
|
822
|
-
};
|
|
823
|
-
const emitClipped = (cmd, body) => {
|
|
824
|
-
const clip = cmd.clip;
|
|
825
|
-
if (!clip) {
|
|
826
|
-
body(cmd);
|
|
827
|
-
return;
|
|
828
|
-
}
|
|
829
|
-
if (inBT) {
|
|
830
|
-
out.push("ET");
|
|
831
|
-
inBT = false;
|
|
832
|
-
}
|
|
833
|
-
out.push("q");
|
|
834
|
-
out.push(`${formatNumber(clip.x)} ${formatNumber(H - clip.y - clip.height)} ${formatNumber(clip.width)} ${formatNumber(clip.height)} re W n`);
|
|
835
|
-
lastFont = "";
|
|
836
|
-
lastSize = -1;
|
|
837
|
-
lastColor = "";
|
|
838
|
-
lastTc = 0;
|
|
839
|
-
out.push("BT");
|
|
840
|
-
inBT = true;
|
|
841
|
-
body(cmd);
|
|
842
|
-
if (inBT) {
|
|
843
|
-
out.push("ET");
|
|
844
|
-
inBT = false;
|
|
845
|
-
}
|
|
846
|
-
out.push("Q");
|
|
847
|
-
lastFont = "";
|
|
848
|
-
lastSize = -1;
|
|
849
|
-
lastColor = "";
|
|
850
|
-
lastTc = 0;
|
|
851
|
-
};
|
|
852
|
-
const emitOneLine = (cmd) => {
|
|
853
|
-
const line = cmd.line;
|
|
854
|
-
const originX = cmd.originX;
|
|
855
|
-
const baselineY = H - cmd.baselineY;
|
|
856
|
-
const rotationDeg = cmd.rotationDeg ?? 0;
|
|
857
|
-
const lineFs = line.maxFontSizePt || 12;
|
|
858
|
-
const linkAscent = Math.max(lineFs, line.mathAscentPt ?? 0);
|
|
859
|
-
const linkDescent = Math.max(lineFs * .2, line.mathDescentPt ?? 0);
|
|
860
|
-
let linkHref;
|
|
861
|
-
let linkAnchor;
|
|
862
|
-
let linkText = "";
|
|
863
|
-
let linkX0 = 0;
|
|
864
|
-
let linkX1 = 0;
|
|
865
|
-
const flushLink = () => {
|
|
866
|
-
if (linkHref === void 0 && linkAnchor === void 0) return;
|
|
867
|
-
const safe = linkHref !== void 0 ? sanitizeHref(linkHref) : void 0;
|
|
868
|
-
const target = safe !== void 0 ? { href: safe } : linkAnchor !== void 0 ? { anchor: linkAnchor } : void 0;
|
|
869
|
-
if (target) links.push({
|
|
870
|
-
...target,
|
|
871
|
-
text: linkText.trim(),
|
|
872
|
-
rect: [
|
|
873
|
-
linkX0,
|
|
874
|
-
baselineY - linkDescent,
|
|
875
|
-
linkX1,
|
|
876
|
-
baselineY + linkAscent
|
|
877
|
-
],
|
|
878
|
-
...cmd.structId !== void 0 ? { structId: cmd.structId } : {}
|
|
879
|
-
});
|
|
880
|
-
linkHref = void 0;
|
|
881
|
-
linkAnchor = void 0;
|
|
882
|
-
linkText = "";
|
|
883
|
-
};
|
|
884
|
-
const trackLink = (href, anchor, text, x0, x1) => {
|
|
885
|
-
if (href !== linkHref || anchor !== linkAnchor) {
|
|
886
|
-
flushLink();
|
|
887
|
-
if (href !== void 0 || anchor !== void 0) {
|
|
888
|
-
linkHref = href;
|
|
889
|
-
linkAnchor = anchor;
|
|
890
|
-
linkX0 = x0;
|
|
891
|
-
}
|
|
892
|
-
}
|
|
893
|
-
if (href !== void 0 || anchor !== void 0) {
|
|
894
|
-
linkX1 = x1;
|
|
895
|
-
linkText += text;
|
|
896
|
-
}
|
|
897
|
-
};
|
|
898
|
-
const extraPerSpace = computeJustifyExtra(line);
|
|
899
|
-
const hasImageToken = line.tokens.some((t) => t.kind === "image");
|
|
900
|
-
const hasMathToken = line.tokens.some((t) => t.kind === "math");
|
|
901
|
-
const hasRtl = line.tokens.some((t) => t.bidiLevel % 2 === 1);
|
|
902
|
-
const hasTab = line.tokens.some((t) => t.kind === "text" && t.tab === true);
|
|
903
|
-
/** A text token carrying underline or strikethrough. */
|
|
904
|
-
const isDecorated = (tok) => tok.kind === "text" && (tok.resolvedRun.underline !== "none" || tok.resolvedRun.strike);
|
|
905
|
-
const showToken = (tok) => {
|
|
906
|
-
const text = tok.bidiLevel % 2 === 1 ? reverseByCodePoint(tok.text) : tok.text;
|
|
907
|
-
return tok.font.measure.showText(text);
|
|
908
|
-
};
|
|
909
|
-
if (line.tokens.some((t) => t.kind === "text" && t.resolvedRun.shadingColorHex)) {
|
|
910
|
-
if (inBT) {
|
|
911
|
-
out.push("ET");
|
|
912
|
-
inBT = false;
|
|
913
|
-
}
|
|
914
|
-
const shAscent = Math.max(lineFs, line.mathAscentPt ?? 0);
|
|
915
|
-
const shDescent = Math.max(lineFs * .2, line.mathDescentPt ?? 0);
|
|
916
|
-
out.push("q");
|
|
917
|
-
let sx = originX;
|
|
918
|
-
let painted = "";
|
|
919
|
-
for (const tok of line.tokens) {
|
|
920
|
-
const w = tok.widthPt + (tok.kind === "text" && tok.isSpace ? extraPerSpace : 0);
|
|
921
|
-
const hex = tok.kind === "text" ? tok.resolvedRun.shadingColorHex : void 0;
|
|
922
|
-
if (hex !== void 0) {
|
|
923
|
-
if (hex !== painted) {
|
|
924
|
-
if (painted !== "") out.push("f");
|
|
925
|
-
const [sr, sg, sb] = hexToRgb01(hex);
|
|
926
|
-
out.push(`${formatNumber(sr)} ${formatNumber(sg)} ${formatNumber(sb)} rg`);
|
|
927
|
-
painted = hex;
|
|
928
|
-
}
|
|
929
|
-
out.push(`${formatNumber(sx)} ${formatNumber(baselineY - shDescent)} ${formatNumber(w)} ${formatNumber(shAscent + shDescent)} re`);
|
|
930
|
-
}
|
|
931
|
-
sx += w;
|
|
932
|
-
}
|
|
933
|
-
if (painted !== "") out.push("f");
|
|
934
|
-
out.push("Q");
|
|
935
|
-
}
|
|
936
|
-
if (line.tokens.some((t) => t.kind === "text" && t.highlight === true)) {
|
|
937
|
-
if (inBT) {
|
|
938
|
-
out.push("ET");
|
|
939
|
-
inBT = false;
|
|
940
|
-
}
|
|
941
|
-
const hlAscent = Math.max(lineFs, line.mathAscentPt ?? 0);
|
|
942
|
-
const hlDescent = Math.max(lineFs * .2, line.mathDescentPt ?? 0);
|
|
943
|
-
const [hr, hg, hb] = hexToRgb01("fff3a3");
|
|
944
|
-
out.push("q");
|
|
945
|
-
out.push(`${formatNumber(hr)} ${formatNumber(hg)} ${formatNumber(hb)} rg`);
|
|
946
|
-
let hx = originX;
|
|
947
|
-
for (const tok of line.tokens) {
|
|
948
|
-
const w = tok.widthPt + (tok.kind === "text" && tok.isSpace ? extraPerSpace : 0);
|
|
949
|
-
if (tok.kind === "text" && tok.highlight === true) out.push(`${formatNumber(hx)} ${formatNumber(baselineY - hlDescent)} ${formatNumber(w)} ${formatNumber(hlAscent + hlDescent)} re`);
|
|
950
|
-
hx += w;
|
|
951
|
-
}
|
|
952
|
-
out.push("f");
|
|
953
|
-
out.push("Q");
|
|
954
|
-
}
|
|
955
|
-
if (line.tokens.some(isDecorated)) {
|
|
956
|
-
if (inBT) {
|
|
957
|
-
out.push("ET");
|
|
958
|
-
inBT = false;
|
|
959
|
-
}
|
|
960
|
-
out.push("q");
|
|
961
|
-
let dx = originX;
|
|
962
|
-
for (const tok of line.tokens) {
|
|
963
|
-
const w = tok.widthPt + (tok.kind === "text" && tok.isSpace ? extraPerSpace : 0);
|
|
964
|
-
if (isDecorated(tok)) {
|
|
965
|
-
const thickness = Math.max(.4, tok.fontSizePt * .06);
|
|
966
|
-
const paint = (hex) => {
|
|
967
|
-
const [r, g, b] = hexToRgb01(hex);
|
|
968
|
-
out.push(`${formatNumber(r)} ${formatNumber(g)} ${formatNumber(b)} rg`);
|
|
969
|
-
};
|
|
970
|
-
paint(tok.resolvedRun.colorHex);
|
|
971
|
-
if (tok.resolvedRun.underline !== "none") {
|
|
972
|
-
if (tok.resolvedRun.underlineColorHex) paint(tok.resolvedRun.underlineColorHex);
|
|
973
|
-
const style = tok.resolvedRun.underline;
|
|
974
|
-
const t = style === "thick" || style === "dottedHeavy" || style === "dashHeavy" ? thickness * 2 : thickness;
|
|
975
|
-
const y = baselineY - tok.fontSizePt * .12 - t;
|
|
976
|
-
const dashed = style === "dotted" || style === "dottedHeavy" ? [t, t * 2] : style === "dash" || style === "dashHeavy" ? [t * 4, t * 3] : void 0;
|
|
977
|
-
if (dashed) {
|
|
978
|
-
out.push(`${formatNumber(t)} w`);
|
|
979
|
-
out.push(`[${dashed.map((n) => formatNumber(n)).join(" ")}] 0 d`);
|
|
980
|
-
const [r, g, b] = hexToRgb01(tok.resolvedRun.underlineColorHex ?? tok.resolvedRun.colorHex);
|
|
981
|
-
out.push(`${formatNumber(r)} ${formatNumber(g)} ${formatNumber(b)} RG`);
|
|
982
|
-
out.push(`${formatNumber(dx)} ${formatNumber(y + t / 2)} m ${formatNumber(dx + w)} ${formatNumber(y + t / 2)} l S`);
|
|
983
|
-
out.push("[] 0 d");
|
|
984
|
-
} else {
|
|
985
|
-
out.push(`${formatNumber(dx)} ${formatNumber(y)} ${formatNumber(w)} ${formatNumber(t)} re f`);
|
|
986
|
-
if (style === "double") out.push(`${formatNumber(dx)} ${formatNumber(y - t * 2)} ${formatNumber(w)} ${formatNumber(t)} re f`);
|
|
987
|
-
}
|
|
988
|
-
if (tok.resolvedRun.underlineColorHex) paint(tok.resolvedRun.colorHex);
|
|
989
|
-
}
|
|
990
|
-
if (tok.resolvedRun.strike) {
|
|
991
|
-
const y = baselineY + tok.fontSizePt * .26;
|
|
992
|
-
out.push(`${formatNumber(dx)} ${formatNumber(y)} ${formatNumber(w)} ${formatNumber(thickness)} re f`);
|
|
993
|
-
}
|
|
994
|
-
}
|
|
995
|
-
dx += w;
|
|
996
|
-
}
|
|
997
|
-
out.push("Q");
|
|
998
|
-
}
|
|
999
|
-
const hasRise = line.tokens.some((t) => t.kind === "text" && t.risePt !== void 0);
|
|
1000
|
-
if (rotationDeg !== 0 && !hasImageToken && !hasMathToken) {
|
|
1001
|
-
if (!inBT) {
|
|
1002
|
-
out.push("BT");
|
|
1003
|
-
inBT = true;
|
|
1004
|
-
}
|
|
1005
|
-
const rad = rotationDeg * Math.PI / 180;
|
|
1006
|
-
const cos = formatNumber(Math.cos(rad));
|
|
1007
|
-
const sin = formatNumber(Math.sin(rad));
|
|
1008
|
-
out.push(`${cos} ${sin} ${formatNumber(-Math.sin(rad))} ${cos} ${formatNumber(originX)} ${formatNumber(baselineY)} Tm`);
|
|
1009
|
-
for (const tok of line.tokens) {
|
|
1010
|
-
if (tok.kind !== "text") continue;
|
|
1011
|
-
switchFontIfNeeded(tok);
|
|
1012
|
-
out.push(tok.font.measure.showText(tok.text));
|
|
1013
|
-
}
|
|
1014
|
-
} else if (extraPerSpace !== 0 || hasImageToken || hasMathToken || hasRtl || hasRise || hasTab) {
|
|
1015
|
-
const order = hasRtl ? lineVisualOrder(line) : line.tokens.map((_, i) => i);
|
|
1016
|
-
let x = originX;
|
|
1017
|
-
for (const ti of order) {
|
|
1018
|
-
const tok = line.tokens[ti];
|
|
1019
|
-
if (tok.kind === "image") {
|
|
1020
|
-
flushLink();
|
|
1021
|
-
emitImageToken(tok, x, baselineY);
|
|
1022
|
-
x += tok.widthPt;
|
|
1023
|
-
continue;
|
|
1024
|
-
}
|
|
1025
|
-
if (tok.kind === "math") {
|
|
1026
|
-
flushLink();
|
|
1027
|
-
emitMathToken(tok, x, baselineY);
|
|
1028
|
-
x += tok.widthPt;
|
|
1029
|
-
continue;
|
|
1030
|
-
}
|
|
1031
|
-
if (!inBT) {
|
|
1032
|
-
out.push("BT");
|
|
1033
|
-
inBT = true;
|
|
1034
|
-
}
|
|
1035
|
-
switchFontIfNeeded(tok);
|
|
1036
|
-
out.push(`1 0 0 1 ${formatNumber(x)} ${formatNumber(baselineY + (tok.risePt ?? 0))} Tm`);
|
|
1037
|
-
out.push(showToken(tok));
|
|
1038
|
-
const tokenX0 = x;
|
|
1039
|
-
x += tok.widthPt;
|
|
1040
|
-
if (tok.isSpace) x += extraPerSpace;
|
|
1041
|
-
trackLink(tok.href, tok.anchor, tok.text, tokenX0, x);
|
|
1042
|
-
}
|
|
1043
|
-
flushLink();
|
|
1044
|
-
} else {
|
|
1045
|
-
if (!inBT) {
|
|
1046
|
-
out.push("BT");
|
|
1047
|
-
inBT = true;
|
|
1048
|
-
}
|
|
1049
|
-
out.push(`1 0 0 1 ${formatNumber(originX)} ${formatNumber(baselineY)} Tm`);
|
|
1050
|
-
let x = originX;
|
|
1051
|
-
for (const tok of line.tokens) {
|
|
1052
|
-
if (tok.kind !== "text") continue;
|
|
1053
|
-
switchFontIfNeeded(tok);
|
|
1054
|
-
out.push(tok.font.measure.showText(tok.text));
|
|
1055
|
-
trackLink(tok.href, tok.anchor, tok.text, x, x + tok.widthPt);
|
|
1056
|
-
x += tok.widthPt;
|
|
1057
|
-
}
|
|
1058
|
-
flushLink();
|
|
1059
|
-
}
|
|
1060
|
-
};
|
|
1061
|
-
if (tagging) for (const cmd of lines) {
|
|
1062
|
-
if (inBT) {
|
|
1063
|
-
out.push("ET");
|
|
1064
|
-
inBT = false;
|
|
1065
|
-
}
|
|
1066
|
-
const sid = cmd.structId;
|
|
1067
|
-
if (sid !== void 0) {
|
|
1068
|
-
const mcid = tagging.next++;
|
|
1069
|
-
tagging.assigned = true;
|
|
1070
|
-
tagging.record(sid, mcid);
|
|
1071
|
-
out.push(`/${tagging.tagFor(sid)} <</MCID ${mcid}>> BDC`);
|
|
1072
|
-
} else if (cmd.artifact === "pagination") out.push("/Artifact <</Type /Pagination>> BDC");
|
|
1073
|
-
else out.push("/Artifact BMC");
|
|
1074
|
-
emitClipped(cmd, emitOneLine);
|
|
1075
|
-
if (inBT) {
|
|
1076
|
-
out.push("ET");
|
|
1077
|
-
inBT = false;
|
|
1078
|
-
}
|
|
1079
|
-
out.push("EMC");
|
|
1080
|
-
}
|
|
1081
|
-
else {
|
|
1082
|
-
out.push("BT");
|
|
1083
|
-
inBT = true;
|
|
1084
|
-
for (const cmd of lines) emitClipped(cmd, emitOneLine);
|
|
1085
|
-
if (inBT) out.push("ET");
|
|
1086
|
-
}
|
|
1284
|
+
for (const run of plan.pictures) {
|
|
1285
|
+
if (run.length === 0) continue;
|
|
1286
|
+
if (tagging) out.push("/Artifact BMC");
|
|
1287
|
+
for (const item of run) emitInOrder(item);
|
|
1288
|
+
if (tagging) out.push("EMC");
|
|
1087
1289
|
}
|
|
1290
|
+
emitLinesPass();
|
|
1088
1291
|
return {
|
|
1089
1292
|
content: encoder.encode(out.join("\n")),
|
|
1090
1293
|
links
|