oasis-editor 0.0.89 → 0.0.90
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/{OasisEditorApp-cKm4OFIF.js → OasisEditorApp-2b7y3aGj.js} +672 -476
- package/dist/assets/{importDocxWorker-DVDyiqYf.js → importDocxWorker-BN5o1geV.js} +1 -1
- package/dist/core/model/index.d.ts +1 -1
- package/dist/core/model/types/primitives.d.ts +2 -0
- package/dist/core/model/types/styles.d.ts +21 -1
- package/dist/export/pdf/OasisPdfWriter.d.ts +6 -102
- package/dist/export/pdf/draw/drawFragment.d.ts +2 -0
- package/dist/export/pdf/writer/PdfContentStream.d.ts +20 -0
- package/dist/export/pdf/writer/PdfDocumentSerializer.d.ts +5 -0
- package/dist/export/pdf/writer/PdfFontTable.d.ts +38 -0
- package/dist/export/pdf/writer/PdfImageTable.d.ts +12 -0
- package/dist/export/pdf/writer/pdfPrimitives.d.ts +20 -0
- package/dist/export/pdf/writer/pdfTypes.d.ts +107 -0
- package/dist/{index-BICQTKCZ.js → index-DcElQi6c.js} +285 -94
- package/dist/oasis-editor.js +1 -1
- package/dist/oasis-editor.umd.cjs +4 -4
- package/package.json +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
var __defProp = Object.defineProperty;
|
|
2
2
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3
3
|
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
4
|
-
import { v as visitRun, a as assertNever, c as createSignal, b as createEditorStateFromDocument, d as createInitialEditorState, S as STANDARD_FONT_SIZES_PT, f as fontSizePxToPt, p as probeLocalFontFamilies, e as createEditorParagraphFromRuns, i as isInlineObjectRun, g as createEditorStyledRun, h as getParagraphLength, j as getParagraphText, k as getActiveZone, l as getDocumentSections, m as getActiveSectionIndex, n as getParagraphs, o as normalizeSelection, q as positionToParagraphOffset, r as paragraphOffsetToPosition, s as clampPosition, t as findParagraphIndex, u as createCollapsedSelection, w as isSelectionCollapsed, x as parseFontSizePtToPx, y as formatFontSizePt, z as createEditorParagraph, A as getBlockParagraphs, B as findParagraphTableLocation, C as buildTableCellLayout, P as PT_PER_PX, D as createEditorTableCell, E as createEditorTableRow, F as createEditorTable, G as underlineStyleToCssDecorationStyle, H as resolveImageSrc, I as listKindForTag, J as isParagraphTag, K as collectInlineRuns, L as parseParagraphStyle, M as getRunImage, N as InlineShell, O as BalloonShell, Q as DocumentShell, R as createMemo, T as buildCanvasLayoutSnapshot, U as getCaretRectFromSnapshot, V as getParagraphRectFromSnapshot, W as createComponent, X as CaretOverlay, Y as Show, Z as createRenderEffect, _ as style, $ as setAttribute, a0 as setStyleProperty, a1 as memo, a2 as template, a3 as useI18n, a4 as createEffect, a5 as insert, a6 as use, a7 as addEventListener, a8 as Dialog, a9 as delegateEvents, aa as className, ab as For, ac as UNDERLINE_STYLE_OPTIONS, ad as Tabs, ae as onMount, af as onCleanup, ag as PluginUiHost, ah as OasisEditorEditor, ai as OasisBrandMark, aj as setPreciseFontPreference, ak as setWelcomeSeen, al as enablePreciseFontMode, am as TWIPS_PER_POINT, an as PX_PER_INCH, ao as TWIPS_PER_INCH, ap as resolveEffectiveParagraphStyle, aq as resolveEffectiveTextStyleForParagraph, ar as EMU_PER_PX, as as EMU_PER_PT, at as getRunFootnoteReference, au as getRunEndnoteReference, av as iterateFootnoteReferenceRuns, aw as iterateEndnoteReferenceRuns, ax as imageContentTypeDefaults, ay as getRunFieldChar, az as getRunFieldInstruction, aA as createEditorRun, aB as JSZip, aC as imageExtensionFromMime, aD as pxToPt$1, aE as resolveFloatingObjectRect, aF as getTextBoxFloatingGeometry, aG as getPresetPathSegments, aH as projectBlocksLayout, aI as buildListLabels, aJ as getImageFloatingGeometry, aK as textStyleToFontSizePt, aL as PX_PER_POINT, aM as DEFAULT_FONT_SIZE_PX, aN as isDoubleUnderlineStyle, aO as isWavyUnderlineStyle, aP as underlineStyleLineWidthPx, aQ as underlineStyleDashArray, aR as resolveListLabel, aS as getListLabelInset, aT as getAlignedListLabelInset, aU as getParagraphBorderInsets, aV as buildSegmentTable, aW as buildCanvasTableLayout, aX as resolveCanvasTableWidth, aY as resolveFloatingTableRect, aZ as normalizeFamily, a_ as ROBOTO_FONT_FILES, a$ as loadFontAsset, b0 as OFFICE_COMPAT_FONT_FAMILIES, b1 as buildSfnt, b2 as defaultFontDecoderRegistry, b3 as SfntFontProgram, b4 as collectPdfFontFamilies, b5 as projectDocumentLayout, b6 as getPageContentWidth, b7 as getPageHeaderZoneTop, b8 as getPageBodyTop, b9 as getPageColumnRects, ba as findFootnoteReference, bb as FOOTNOTE_MARKER_GUTTER_PX, bc as resolveImporterForFile, bd as getDocumentSectionsCanonical, be as getDocumentParagraphsCanonical, bf as getDocumentParagraphs, bg as getDocumentPageSettings, bh as getTableCellContentWidthForParagraph, bi as on, bj as debounce, bk as unwrap, bl as perfTimer, bm as getRunTextBox, bn as createEditorDocument, bo as resolveResizedDimensions, bp as resolveTextBoxRenderHeight, bq as getToolbarStyleState, br as getCachedCanvasImage, bs as measureParagraphMinContentWidthPx, bt as getEditableBlocksForZone, bu as findParagraphLocation, bv as createSectionBoundaryParagraph, bw as normalizePageSettings, bx as DEFAULT_EDITOR_PAGE_SETTINGS, by as markStart, bz as markEnd, bA as getParagraphEntries, bB as getParagraphById, bC as createEditorFootnote, bD as createFootnoteReferenceRun, bE as renumberFootnotes, bF as getFootnoteDisplayMarker, bG as getHeadingLevel, bH as preciseFontModeVersion, bI as isPreciseFontModeEnabled, bJ as resolveNamedTextStyle, bK as togglePreciseFontMode, bL as nextFontSizePt, bM as previousFontSizePt, bN as fontSizePtToPx, bO as createDefaultToolbarPreset, bP as MenuRegistry, bQ as createToolbarRegistry, bR as Editor, bS as resolveCommandRef, bT as commandRefName, bU as createOasisEditorClient, bV as createEditorZoom, bW as startLongTaskObserver, bX as installGlobalReport, bY as applyStoredPreciseFontPreference, bZ as getWelcomeSeen, b_ as isLocalFontAccessSupported, b$ as EDITOR_SCROLL_PADDING_PX, c0 as Toolbar, c1 as OasisEditorLoading, c2 as I18nProvider, c3 as createTranslator, c4 as createEditorLogger, c5 as registerDomStatsSurface } from "./index-
|
|
4
|
+
import { v as visitRun, a as assertNever, c as createSignal, b as createEditorStateFromDocument, d as createInitialEditorState, S as STANDARD_FONT_SIZES_PT, f as fontSizePxToPt, p as probeLocalFontFamilies, e as createEditorParagraphFromRuns, i as isInlineObjectRun, g as createEditorStyledRun, h as getParagraphLength, j as getParagraphText, k as getActiveZone, l as getDocumentSections, m as getActiveSectionIndex, n as getParagraphs, o as normalizeSelection, q as positionToParagraphOffset, r as paragraphOffsetToPosition, s as clampPosition, t as findParagraphIndex, u as createCollapsedSelection, w as isSelectionCollapsed, x as parseFontSizePtToPx, y as formatFontSizePt, z as createEditorParagraph, A as getBlockParagraphs, B as findParagraphTableLocation, C as buildTableCellLayout, P as PT_PER_PX, D as createEditorTableCell, E as createEditorTableRow, F as createEditorTable, G as underlineStyleToCssDecorationStyle, H as resolveImageSrc, I as listKindForTag, J as isParagraphTag, K as collectInlineRuns, L as parseParagraphStyle, M as getRunImage, N as InlineShell, O as BalloonShell, Q as DocumentShell, R as createMemo, T as buildCanvasLayoutSnapshot, U as getCaretRectFromSnapshot, V as getParagraphRectFromSnapshot, W as createComponent, X as CaretOverlay, Y as Show, Z as createRenderEffect, _ as style, $ as setAttribute, a0 as setStyleProperty, a1 as memo, a2 as template, a3 as useI18n, a4 as createEffect, a5 as insert, a6 as use, a7 as addEventListener, a8 as Dialog, a9 as delegateEvents, aa as className, ab as For, ac as UNDERLINE_STYLE_OPTIONS, ad as Tabs, ae as onMount, af as onCleanup, ag as PluginUiHost, ah as OasisEditorEditor, ai as OasisBrandMark, aj as setPreciseFontPreference, ak as setWelcomeSeen, al as enablePreciseFontMode, am as TWIPS_PER_POINT, an as PX_PER_INCH, ao as TWIPS_PER_INCH, ap as resolveEffectiveParagraphStyle, aq as resolveEffectiveTextStyleForParagraph, ar as EMU_PER_PX, as as EMU_PER_PT, at as getRunFootnoteReference, au as getRunEndnoteReference, av as iterateFootnoteReferenceRuns, aw as iterateEndnoteReferenceRuns, ax as imageContentTypeDefaults, ay as getRunFieldChar, az as getRunFieldInstruction, aA as createEditorRun, aB as JSZip, aC as imageExtensionFromMime, aD as pxToPt$1, aE as resolveFloatingObjectRect, aF as getTextBoxFloatingGeometry, aG as getPresetPathSegments, aH as projectBlocksLayout, aI as buildListLabels, aJ as getImageFloatingGeometry, aK as textStyleToFontSizePt, aL as PX_PER_POINT, aM as DEFAULT_FONT_SIZE_PX, aN as isDoubleUnderlineStyle, aO as isWavyUnderlineStyle, aP as underlineStyleLineWidthPx, aQ as underlineStyleDashArray, aR as resolveListLabel, aS as getListLabelInset, aT as getAlignedListLabelInset, aU as getParagraphBorderInsets, aV as buildSegmentTable, aW as buildCanvasTableLayout, aX as resolveCanvasTableWidth, aY as resolveFloatingTableRect, aZ as normalizeFamily, a_ as ROBOTO_FONT_FILES, a$ as loadFontAsset, b0 as OFFICE_COMPAT_FONT_FAMILIES, b1 as buildSfnt, b2 as defaultFontDecoderRegistry, b3 as SfntFontProgram, b4 as collectPdfFontFamilies, b5 as projectDocumentLayout, b6 as getPageContentWidth, b7 as getPageHeaderZoneTop, b8 as getPageBodyTop, b9 as getPageColumnRects, ba as findFootnoteReference, bb as FOOTNOTE_MARKER_GUTTER_PX, bc as resolveImporterForFile, bd as getDocumentSectionsCanonical, be as getDocumentParagraphsCanonical, bf as getDocumentParagraphs, bg as getDocumentPageSettings, bh as getTableCellContentWidthForParagraph, bi as on, bj as debounce, bk as unwrap, bl as perfTimer, bm as getRunTextBox, bn as createEditorDocument, bo as resolveResizedDimensions, bp as resolveTextBoxRenderHeight, bq as getToolbarStyleState, br as getCachedCanvasImage, bs as measureParagraphMinContentWidthPx, bt as getEditableBlocksForZone, bu as findParagraphLocation, bv as createSectionBoundaryParagraph, bw as normalizePageSettings, bx as DEFAULT_EDITOR_PAGE_SETTINGS, by as markStart, bz as markEnd, bA as getParagraphEntries, bB as getParagraphById, bC as createEditorFootnote, bD as createFootnoteReferenceRun, bE as renumberFootnotes, bF as getFootnoteDisplayMarker, bG as getHeadingLevel, bH as preciseFontModeVersion, bI as isPreciseFontModeEnabled, bJ as resolveNamedTextStyle, bK as togglePreciseFontMode, bL as nextFontSizePt, bM as previousFontSizePt, bN as fontSizePtToPx, bO as createDefaultToolbarPreset, bP as MenuRegistry, bQ as createToolbarRegistry, bR as Editor, bS as resolveCommandRef, bT as commandRefName, bU as createOasisEditorClient, bV as createEditorZoom, bW as startLongTaskObserver, bX as installGlobalReport, bY as applyStoredPreciseFontPreference, bZ as getWelcomeSeen, b_ as isLocalFontAccessSupported, b$ as EDITOR_SCROLL_PADDING_PX, c0 as Toolbar, c1 as OasisEditorLoading, c2 as I18nProvider, c3 as createTranslator, c4 as createEditorLogger, c5 as registerDomStatsSurface } from "./index-DcElQi6c.js";
|
|
5
5
|
function cloneStyle(style2) {
|
|
6
6
|
return style2 ? { ...style2 } : void 0;
|
|
7
7
|
}
|
|
@@ -33675,6 +33675,16 @@ function materializeRunStyle(run, paragraphStyleId, styles) {
|
|
|
33675
33675
|
noProof: effective.noProof,
|
|
33676
33676
|
webHidden: effective.webHidden,
|
|
33677
33677
|
specVanish: effective.specVanish,
|
|
33678
|
+
rtl: effective.rtl,
|
|
33679
|
+
complexScript: effective.complexScript,
|
|
33680
|
+
snapToGrid: effective.snapToGrid,
|
|
33681
|
+
fitText: effective.fitText,
|
|
33682
|
+
emphasisMark: effective.emphasisMark,
|
|
33683
|
+
textBorder: effective.textBorder,
|
|
33684
|
+
outline: effective.outline,
|
|
33685
|
+
shadow: effective.shadow,
|
|
33686
|
+
emboss: effective.emboss,
|
|
33687
|
+
imprint: effective.imprint,
|
|
33678
33688
|
textEffect: effective.textEffect,
|
|
33679
33689
|
characterScale: effective.characterScale,
|
|
33680
33690
|
characterSpacing: effective.characterSpacing,
|
|
@@ -33972,15 +33982,23 @@ function serializeRunProperties(styles) {
|
|
|
33972
33982
|
}
|
|
33973
33983
|
if (styles.strike) parts.push("<w:strike/>");
|
|
33974
33984
|
if (styles.doubleStrike) parts.push("<w:dstrike/>");
|
|
33985
|
+
if (styles.outline) parts.push("<w:outline/>");
|
|
33986
|
+
if (styles.shadow) parts.push("<w:shadow/>");
|
|
33987
|
+
if (styles.emboss) parts.push("<w:emboss/>");
|
|
33988
|
+
if (styles.imprint) parts.push("<w:imprint/>");
|
|
33975
33989
|
if (styles.smallCaps) parts.push("<w:smallCaps/>");
|
|
33976
33990
|
if (styles.allCaps) parts.push("<w:caps/>");
|
|
33977
33991
|
if (styles.hidden) parts.push("<w:vanish/>");
|
|
33978
33992
|
if (styles.noProof) parts.push("<w:noProof/>");
|
|
33979
33993
|
if (styles.webHidden) parts.push("<w:webHidden/>");
|
|
33980
33994
|
if (styles.specVanish) parts.push("<w:specVanish/>");
|
|
33995
|
+
if (styles.snapToGrid === false) parts.push('<w:snapToGrid w:val="0"/>');
|
|
33981
33996
|
if (styles.textEffect) {
|
|
33982
33997
|
parts.push(`<w:effect w:val="${escapeXml(styles.textEffect)}"/>`);
|
|
33983
33998
|
}
|
|
33999
|
+
if (styles.textBorder) {
|
|
34000
|
+
parts.push(`<w:bdr ${serializeDocxBorderAttrs(styles.textBorder)}`);
|
|
34001
|
+
}
|
|
33984
34002
|
if (styles.characterScale !== void 0 && styles.characterScale !== null && Number.isFinite(styles.characterScale)) {
|
|
33985
34003
|
parts.push(
|
|
33986
34004
|
`<w:w w:val="${Math.max(1, Math.round(styles.characterScale))}"/>`
|
|
@@ -34048,6 +34066,17 @@ function serializeRunProperties(styles) {
|
|
|
34048
34066
|
`<w:shd w:val="clear" w:color="auto" w:fill="${normalizeDocxColor(styles.shading, "FFFFFF")}"/>`
|
|
34049
34067
|
);
|
|
34050
34068
|
}
|
|
34069
|
+
if (styles.fitText !== void 0 && styles.fitText !== null && Number.isFinite(styles.fitText)) {
|
|
34070
|
+
const twips = pointsToSignedTwips(styles.fitText);
|
|
34071
|
+
if (twips !== null && twips > 0) {
|
|
34072
|
+
parts.push(`<w:fitText w:val="${twips}"/>`);
|
|
34073
|
+
}
|
|
34074
|
+
}
|
|
34075
|
+
if (styles.rtl) parts.push("<w:rtl/>");
|
|
34076
|
+
if (styles.complexScript) parts.push("<w:cs/>");
|
|
34077
|
+
if (styles.emphasisMark) {
|
|
34078
|
+
parts.push(`<w:em w:val="${escapeXml(styles.emphasisMark)}"/>`);
|
|
34079
|
+
}
|
|
34051
34080
|
if (styles.language) {
|
|
34052
34081
|
const attrs = [];
|
|
34053
34082
|
if (styles.language.value) {
|
|
@@ -36130,6 +36159,63 @@ function drawFragmentShading(writer, pageIndex, line, fragment, originX, originY
|
|
|
36130
36159
|
fill: styles.shading
|
|
36131
36160
|
});
|
|
36132
36161
|
}
|
|
36162
|
+
function drawFragmentBorder(writer, pageIndex, line, fragment, originX, originY, styles) {
|
|
36163
|
+
const border = styles.textBorder;
|
|
36164
|
+
if (!border || border.type === "none" || border.width <= 0) {
|
|
36165
|
+
return;
|
|
36166
|
+
}
|
|
36167
|
+
const bounds = resolveFragmentBounds(
|
|
36168
|
+
line,
|
|
36169
|
+
fragment,
|
|
36170
|
+
styles.fontSize ?? DEFAULT_FONT_SIZE_PX
|
|
36171
|
+
);
|
|
36172
|
+
if (!bounds) {
|
|
36173
|
+
return;
|
|
36174
|
+
}
|
|
36175
|
+
writer.drawRect(pageIndex, {
|
|
36176
|
+
x: pxToPt$1(originX + bounds.left),
|
|
36177
|
+
y: pxToPt$1(originY + line.top + 1),
|
|
36178
|
+
width: pxToPt$1(Math.max(0, bounds.right - bounds.left)),
|
|
36179
|
+
height: pxToPt$1(Math.max(2, line.height - 2)),
|
|
36180
|
+
stroke: border.color,
|
|
36181
|
+
lineWidth: pxToPt$1(Math.max(0.5, border.width * PX_PER_POINT))
|
|
36182
|
+
});
|
|
36183
|
+
}
|
|
36184
|
+
const PDF_EMPHASIS_GLYPH = {
|
|
36185
|
+
dot: "•",
|
|
36186
|
+
comma: "‚",
|
|
36187
|
+
circle: "○",
|
|
36188
|
+
underDot: "•"
|
|
36189
|
+
};
|
|
36190
|
+
function drawFragmentEmphasis(writer, pageIndex, line, fragment, originX, originY, styles) {
|
|
36191
|
+
const mark = styles.emphasisMark;
|
|
36192
|
+
if (!mark || mark === "none") {
|
|
36193
|
+
return;
|
|
36194
|
+
}
|
|
36195
|
+
const glyph = PDF_EMPHASIS_GLYPH[mark];
|
|
36196
|
+
if (!glyph) {
|
|
36197
|
+
return;
|
|
36198
|
+
}
|
|
36199
|
+
const slots = resolveFragmentSlots(line, fragment);
|
|
36200
|
+
const below = mark === "underDot";
|
|
36201
|
+
const size = Math.max(4, line.height * 0.35);
|
|
36202
|
+
const y = below ? originY + line.top + line.height + size : originY + line.top + size;
|
|
36203
|
+
for (let i = 0; i < slots.length; i += 1) {
|
|
36204
|
+
const slot = slots[i];
|
|
36205
|
+
if (slot.char === " " || slot.char === " " || slot.char === "\n") {
|
|
36206
|
+
continue;
|
|
36207
|
+
}
|
|
36208
|
+
const next = slots[i + 1];
|
|
36209
|
+
const centerX = next ? (slot.left + next.left) / 2 : slot.left + line.height * 0.25;
|
|
36210
|
+
writer.drawText(pageIndex, {
|
|
36211
|
+
x: pxToPt$1(originX + centerX - size * 0.25),
|
|
36212
|
+
y: pxToPt$1(y),
|
|
36213
|
+
text: glyph,
|
|
36214
|
+
fontSize: pxToPt$1(size),
|
|
36215
|
+
color: styles.color ?? "#000000"
|
|
36216
|
+
});
|
|
36217
|
+
}
|
|
36218
|
+
}
|
|
36133
36219
|
function drawFragmentDecoration(writer, pageIndex, line, fragment, originX, originY, styles, kind) {
|
|
36134
36220
|
const bounds = resolveFragmentBounds(
|
|
36135
36221
|
line,
|
|
@@ -36410,6 +36496,15 @@ async function drawFragmentText(writer, pageIndex, paragraph, line, fragment, do
|
|
|
36410
36496
|
originY,
|
|
36411
36497
|
styles
|
|
36412
36498
|
);
|
|
36499
|
+
drawFragmentBorder(
|
|
36500
|
+
writer,
|
|
36501
|
+
pageIndex,
|
|
36502
|
+
line,
|
|
36503
|
+
fragment,
|
|
36504
|
+
originX,
|
|
36505
|
+
originY,
|
|
36506
|
+
styles
|
|
36507
|
+
);
|
|
36413
36508
|
drawTabLeaders(
|
|
36414
36509
|
writer,
|
|
36415
36510
|
pageIndex,
|
|
@@ -36422,42 +36517,50 @@ async function drawFragmentText(writer, pageIndex, paragraph, line, fragment, do
|
|
|
36422
36517
|
styles.color ?? "#000000"
|
|
36423
36518
|
);
|
|
36424
36519
|
const paragraphAlign = resolveEffectiveParagraphStyle(paragraph.style, document2.styles).align ?? "left";
|
|
36425
|
-
|
|
36426
|
-
|
|
36427
|
-
|
|
36428
|
-
|
|
36429
|
-
|
|
36520
|
+
const baseTextOptions = {
|
|
36521
|
+
fontSize: fontSizePt,
|
|
36522
|
+
bold: styles.bold,
|
|
36523
|
+
italic: styles.italic,
|
|
36524
|
+
fontResourceName: fontFace.writerResourceName,
|
|
36525
|
+
characterSpacing: styles.characterSpacing ?? 0,
|
|
36526
|
+
horizontalScale: styles.characterScale ?? 100
|
|
36527
|
+
};
|
|
36528
|
+
const mainColor = styles.color ?? "#000000";
|
|
36529
|
+
const offsetPt = pxToPt$1(1);
|
|
36530
|
+
const emitChunk = (leftPx, text2) => {
|
|
36531
|
+
if (styles.emboss || styles.imprint) {
|
|
36532
|
+
const dir = styles.imprint ? 1 : -1;
|
|
36430
36533
|
writer.drawText(pageIndex, {
|
|
36431
|
-
|
|
36432
|
-
|
|
36433
|
-
|
|
36434
|
-
|
|
36435
|
-
color:
|
|
36436
|
-
bold: styles.bold,
|
|
36437
|
-
italic: styles.italic,
|
|
36438
|
-
fontResourceName: fontFace.writerResourceName,
|
|
36439
|
-
characterSpacing: styles.characterSpacing ?? 0,
|
|
36440
|
-
horizontalScale: styles.characterScale ?? 100
|
|
36534
|
+
...baseTextOptions,
|
|
36535
|
+
x: pxToPt$1(leftPx) + offsetPt * dir,
|
|
36536
|
+
y: pxToPt$1(baselineY) + offsetPt * dir,
|
|
36537
|
+
text: text2,
|
|
36538
|
+
color: "#BFBFBF"
|
|
36441
36539
|
});
|
|
36442
36540
|
}
|
|
36443
|
-
|
|
36444
|
-
const chunks = groupSlotChunksByOffsetGaps(chars);
|
|
36445
|
-
for (const chunk of chunks) {
|
|
36446
|
-
const chunkText = chunk.map((c) => styles.allCaps ? c.char.toUpperCase() : c.char).join("");
|
|
36447
|
-
if (chunkText.length === 0) continue;
|
|
36541
|
+
if (styles.shadow) {
|
|
36448
36542
|
writer.drawText(pageIndex, {
|
|
36449
|
-
|
|
36450
|
-
|
|
36451
|
-
|
|
36452
|
-
|
|
36453
|
-
color:
|
|
36454
|
-
bold: styles.bold,
|
|
36455
|
-
italic: styles.italic,
|
|
36456
|
-
fontResourceName: fontFace.writerResourceName,
|
|
36457
|
-
characterSpacing: styles.characterSpacing ?? 0,
|
|
36458
|
-
horizontalScale: styles.characterScale ?? 100
|
|
36543
|
+
...baseTextOptions,
|
|
36544
|
+
x: pxToPt$1(leftPx) + offsetPt,
|
|
36545
|
+
y: pxToPt$1(baselineY) + offsetPt,
|
|
36546
|
+
text: text2,
|
|
36547
|
+
color: "#808080"
|
|
36459
36548
|
});
|
|
36460
36549
|
}
|
|
36550
|
+
writer.drawText(pageIndex, {
|
|
36551
|
+
...baseTextOptions,
|
|
36552
|
+
x: pxToPt$1(leftPx),
|
|
36553
|
+
y: pxToPt$1(baselineY),
|
|
36554
|
+
text: text2,
|
|
36555
|
+
color: mainColor,
|
|
36556
|
+
renderMode: styles.outline ? 1 : 0
|
|
36557
|
+
});
|
|
36558
|
+
};
|
|
36559
|
+
const chunks = paragraphAlign === "justify" ? groupSlotChunksByWhitespace(chars) : groupSlotChunksByOffsetGaps(chars);
|
|
36560
|
+
for (const chunk of chunks) {
|
|
36561
|
+
const chunkText = chunk.map((c) => styles.allCaps ? c.char.toUpperCase() : c.char).join("");
|
|
36562
|
+
if (chunkText.length === 0) continue;
|
|
36563
|
+
emitChunk(originX + chunk[0].left, chunkText);
|
|
36461
36564
|
}
|
|
36462
36565
|
if (styles.underline) {
|
|
36463
36566
|
drawFragmentDecoration(
|
|
@@ -36495,6 +36598,17 @@ async function drawFragmentText(writer, pageIndex, paragraph, line, fragment, do
|
|
|
36495
36598
|
"doubleStrike"
|
|
36496
36599
|
);
|
|
36497
36600
|
}
|
|
36601
|
+
if (styles.emphasisMark) {
|
|
36602
|
+
drawFragmentEmphasis(
|
|
36603
|
+
writer,
|
|
36604
|
+
pageIndex,
|
|
36605
|
+
line,
|
|
36606
|
+
fragment,
|
|
36607
|
+
originX,
|
|
36608
|
+
originY,
|
|
36609
|
+
styles
|
|
36610
|
+
);
|
|
36611
|
+
}
|
|
36498
36612
|
}
|
|
36499
36613
|
function getListOrdinals(document2) {
|
|
36500
36614
|
return buildListLabels(document2);
|
|
@@ -37066,227 +37180,6 @@ class PdfFontRegistry {
|
|
|
37066
37180
|
return matchedFamilies;
|
|
37067
37181
|
}
|
|
37068
37182
|
}
|
|
37069
|
-
class SimpleTextLayouter {
|
|
37070
|
-
constructor(font) {
|
|
37071
|
-
this.font = font;
|
|
37072
|
-
}
|
|
37073
|
-
layout(text) {
|
|
37074
|
-
const glyphs = [];
|
|
37075
|
-
const positions = [];
|
|
37076
|
-
let advanceWidth = 0;
|
|
37077
|
-
for (const char of text) {
|
|
37078
|
-
const codePoint = char.codePointAt(0) ?? 65533;
|
|
37079
|
-
const glyphId = this.font.glyphForCodePoint(codePoint);
|
|
37080
|
-
const glyphAdvance = this.font.advanceWidthForGlyph(glyphId);
|
|
37081
|
-
glyphs.push({
|
|
37082
|
-
id: glyphId,
|
|
37083
|
-
codePoints: glyphId === 0 ? [65533] : [codePoint],
|
|
37084
|
-
advanceWidth: glyphAdvance
|
|
37085
|
-
});
|
|
37086
|
-
positions.push({ xAdvance: glyphAdvance });
|
|
37087
|
-
advanceWidth += glyphAdvance;
|
|
37088
|
-
}
|
|
37089
|
-
return { glyphs, positions, advanceWidth };
|
|
37090
|
-
}
|
|
37091
|
-
}
|
|
37092
|
-
function view(bytes) {
|
|
37093
|
-
return new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
37094
|
-
}
|
|
37095
|
-
function u16(bytes, offset) {
|
|
37096
|
-
return view(bytes).getUint16(offset);
|
|
37097
|
-
}
|
|
37098
|
-
function i16(bytes, offset) {
|
|
37099
|
-
return view(bytes).getInt16(offset);
|
|
37100
|
-
}
|
|
37101
|
-
function writeU16(target, offset, value) {
|
|
37102
|
-
view(target).setUint16(offset, value, false);
|
|
37103
|
-
}
|
|
37104
|
-
function writeU32(target, offset, value) {
|
|
37105
|
-
view(target).setUint32(offset, value, false);
|
|
37106
|
-
}
|
|
37107
|
-
function pad4(length) {
|
|
37108
|
-
return length + 3 & -4;
|
|
37109
|
-
}
|
|
37110
|
-
function concat(chunks) {
|
|
37111
|
-
const total = chunks.reduce((sum, chunk) => sum + pad4(chunk.byteLength), 0);
|
|
37112
|
-
const result = new Uint8Array(total);
|
|
37113
|
-
let offset = 0;
|
|
37114
|
-
for (const chunk of chunks) {
|
|
37115
|
-
result.set(chunk, offset);
|
|
37116
|
-
offset += pad4(chunk.byteLength);
|
|
37117
|
-
}
|
|
37118
|
-
return result;
|
|
37119
|
-
}
|
|
37120
|
-
function readLoca(loca, indexToLocFormat) {
|
|
37121
|
-
const offsets = [];
|
|
37122
|
-
const table = view(loca);
|
|
37123
|
-
if (indexToLocFormat === 0) {
|
|
37124
|
-
for (let offset = 0; offset + 1 < loca.byteLength; offset += 2) {
|
|
37125
|
-
offsets.push(table.getUint16(offset) * 2);
|
|
37126
|
-
}
|
|
37127
|
-
} else {
|
|
37128
|
-
for (let offset = 0; offset + 3 < loca.byteLength; offset += 4) {
|
|
37129
|
-
offsets.push(table.getUint32(offset));
|
|
37130
|
-
}
|
|
37131
|
-
}
|
|
37132
|
-
return offsets;
|
|
37133
|
-
}
|
|
37134
|
-
function glyphRange(offsets, glyphId) {
|
|
37135
|
-
const start = offsets[glyphId];
|
|
37136
|
-
const end = offsets[glyphId + 1];
|
|
37137
|
-
return start === void 0 || end === void 0 ? null : { start, end };
|
|
37138
|
-
}
|
|
37139
|
-
function collectCompositeGlyphs(glyph, addGlyph) {
|
|
37140
|
-
if (glyph.byteLength < 10 || i16(glyph, 0) >= 0) {
|
|
37141
|
-
return;
|
|
37142
|
-
}
|
|
37143
|
-
let offset = 10;
|
|
37144
|
-
let flags = 0;
|
|
37145
|
-
do {
|
|
37146
|
-
if (offset + 4 > glyph.byteLength) return;
|
|
37147
|
-
flags = u16(glyph, offset);
|
|
37148
|
-
addGlyph(u16(glyph, offset + 2));
|
|
37149
|
-
offset += 4;
|
|
37150
|
-
offset += flags & 1 ? 4 : 2;
|
|
37151
|
-
if (flags & 8) offset += 2;
|
|
37152
|
-
else if (flags & 64) offset += 4;
|
|
37153
|
-
else if (flags & 128) offset += 8;
|
|
37154
|
-
} while (flags & 32);
|
|
37155
|
-
}
|
|
37156
|
-
function subsetClosure(font, initialGlyphs) {
|
|
37157
|
-
const glyf = font.getRawTableData("glyf");
|
|
37158
|
-
const loca = font.getRawTableData("loca");
|
|
37159
|
-
const head = font.getRawTableData("head");
|
|
37160
|
-
if (!glyf || !loca || !head) {
|
|
37161
|
-
return Array.from(/* @__PURE__ */ new Set([0, ...initialGlyphs])).sort((a, b) => a - b);
|
|
37162
|
-
}
|
|
37163
|
-
const offsets = readLoca(loca, u16(head, 50));
|
|
37164
|
-
const used = /* @__PURE__ */ new Set([0, ...initialGlyphs]);
|
|
37165
|
-
const stack = Array.from(used);
|
|
37166
|
-
while (stack.length > 0) {
|
|
37167
|
-
const glyphId = stack.pop();
|
|
37168
|
-
const range = glyphRange(offsets, glyphId);
|
|
37169
|
-
if (!range || range.end <= range.start || range.end > glyf.byteLength) {
|
|
37170
|
-
continue;
|
|
37171
|
-
}
|
|
37172
|
-
const glyph = glyf.slice(range.start, range.end);
|
|
37173
|
-
collectCompositeGlyphs(glyph, (componentId) => {
|
|
37174
|
-
if (!used.has(componentId)) {
|
|
37175
|
-
used.add(componentId);
|
|
37176
|
-
stack.push(componentId);
|
|
37177
|
-
}
|
|
37178
|
-
});
|
|
37179
|
-
}
|
|
37180
|
-
return Array.from(used).sort((a, b) => a - b);
|
|
37181
|
-
}
|
|
37182
|
-
function buildLoca(offsets) {
|
|
37183
|
-
const loca = new Uint8Array(offsets.length * 4);
|
|
37184
|
-
offsets.forEach((offset, index) => writeU32(loca, index * 4, offset));
|
|
37185
|
-
return loca;
|
|
37186
|
-
}
|
|
37187
|
-
function buildHmtx(font, maxGlyphId) {
|
|
37188
|
-
const hmtx = new Uint8Array((maxGlyphId + 1) * 4);
|
|
37189
|
-
for (let glyphId = 0; glyphId <= maxGlyphId; glyphId += 1) {
|
|
37190
|
-
writeU16(hmtx, glyphId * 4, font.advanceWidthForGlyph(glyphId));
|
|
37191
|
-
writeU16(hmtx, glyphId * 4 + 2, 0);
|
|
37192
|
-
}
|
|
37193
|
-
return hmtx;
|
|
37194
|
-
}
|
|
37195
|
-
function buildSubsetTables(font, glyphIds) {
|
|
37196
|
-
const glyf = font.getRawTableData("glyf");
|
|
37197
|
-
const loca = font.getRawTableData("loca");
|
|
37198
|
-
const head = font.getRawTableData("head");
|
|
37199
|
-
const hhea = font.getRawTableData("hhea");
|
|
37200
|
-
const maxp = font.getRawTableData("maxp");
|
|
37201
|
-
const cmap = font.getRawTableData("cmap");
|
|
37202
|
-
if (!glyf || !loca || !head || !hhea || !maxp || !cmap) {
|
|
37203
|
-
throw new Error("Missing required TrueType tables for subsetting");
|
|
37204
|
-
}
|
|
37205
|
-
const maxGlyphId = Math.max(0, ...glyphIds);
|
|
37206
|
-
const used = new Set(glyphIds);
|
|
37207
|
-
const sourceOffsets = readLoca(loca, u16(head, 50));
|
|
37208
|
-
const locaOffsets = [];
|
|
37209
|
-
const glyfChunks = [];
|
|
37210
|
-
let glyfOffset = 0;
|
|
37211
|
-
for (let glyphId = 0; glyphId <= maxGlyphId; glyphId += 1) {
|
|
37212
|
-
locaOffsets.push(glyfOffset);
|
|
37213
|
-
const range = glyphRange(sourceOffsets, glyphId);
|
|
37214
|
-
if (used.has(glyphId) && range && range.end > range.start) {
|
|
37215
|
-
const glyph = glyf.slice(range.start, range.end);
|
|
37216
|
-
glyfChunks.push(glyph);
|
|
37217
|
-
glyfOffset += pad4(glyph.byteLength);
|
|
37218
|
-
}
|
|
37219
|
-
}
|
|
37220
|
-
locaOffsets.push(glyfOffset);
|
|
37221
|
-
const newHead = head.slice();
|
|
37222
|
-
writeU32(newHead, 8, 0);
|
|
37223
|
-
writeU16(newHead, 50, 1);
|
|
37224
|
-
const newHhea = hhea.slice();
|
|
37225
|
-
writeU16(newHhea, 34, maxGlyphId + 1);
|
|
37226
|
-
const newMaxp = maxp.slice();
|
|
37227
|
-
writeU16(newMaxp, 4, maxGlyphId + 1);
|
|
37228
|
-
const tables = {
|
|
37229
|
-
cmap,
|
|
37230
|
-
head: newHead,
|
|
37231
|
-
hhea: newHhea,
|
|
37232
|
-
hmtx: buildHmtx(font, maxGlyphId),
|
|
37233
|
-
loca: buildLoca(locaOffsets),
|
|
37234
|
-
maxp: newMaxp,
|
|
37235
|
-
glyf: concat(glyfChunks)
|
|
37236
|
-
};
|
|
37237
|
-
for (const tag of ["OS/2", "name", "post"]) {
|
|
37238
|
-
const table = font.getRawTableData(tag);
|
|
37239
|
-
if (table) tables[tag] = table;
|
|
37240
|
-
}
|
|
37241
|
-
return tables;
|
|
37242
|
-
}
|
|
37243
|
-
class TrueTypePdfFontSubsetter {
|
|
37244
|
-
createSubset(font, glyphs) {
|
|
37245
|
-
const unicodeByGlyph = /* @__PURE__ */ new Map();
|
|
37246
|
-
const initialGlyphs = [];
|
|
37247
|
-
for (const glyph of glyphs) {
|
|
37248
|
-
initialGlyphs.push(glyph.id);
|
|
37249
|
-
if (!unicodeByGlyph.has(glyph.id)) {
|
|
37250
|
-
unicodeByGlyph.set(glyph.id, glyph.codePoints);
|
|
37251
|
-
}
|
|
37252
|
-
}
|
|
37253
|
-
const glyphIds = subsetClosure(font, initialGlyphs);
|
|
37254
|
-
const tables = buildSubsetTables(font, glyphIds);
|
|
37255
|
-
const fontFile = buildSfnt(
|
|
37256
|
-
65536,
|
|
37257
|
-
new Map(
|
|
37258
|
-
Object.entries(tables).map(([tag, data]) => [
|
|
37259
|
-
tag.charCodeAt(0) << 24 | tag.charCodeAt(1) << 16 | tag.charCodeAt(2) << 8 | tag.charCodeAt(3),
|
|
37260
|
-
data
|
|
37261
|
-
])
|
|
37262
|
-
)
|
|
37263
|
-
).ttf;
|
|
37264
|
-
const maxGlyphId = Math.max(0, ...glyphIds);
|
|
37265
|
-
const widths = [];
|
|
37266
|
-
const unicode = [];
|
|
37267
|
-
for (let glyphId = 0; glyphId <= maxGlyphId; glyphId += 1) {
|
|
37268
|
-
widths[glyphId] = font.advanceWidthForGlyph(glyphId) / font.unitsPerEm * 1e3;
|
|
37269
|
-
unicode[glyphId] = unicodeByGlyph.get(glyphId) ?? [0];
|
|
37270
|
-
}
|
|
37271
|
-
return {
|
|
37272
|
-
fontFile,
|
|
37273
|
-
widths,
|
|
37274
|
-
unicode,
|
|
37275
|
-
encodeGlyph: (glyphId) => glyphId
|
|
37276
|
-
};
|
|
37277
|
-
}
|
|
37278
|
-
}
|
|
37279
|
-
function parseEmbeddedFontSync(sourceBytes) {
|
|
37280
|
-
const sfntBytes = defaultFontDecoderRegistry.decodeSync(sourceBytes);
|
|
37281
|
-
return SfntFontProgram.parse(sfntBytes);
|
|
37282
|
-
}
|
|
37283
|
-
function createPdfEmbeddableFont(program) {
|
|
37284
|
-
return {
|
|
37285
|
-
program,
|
|
37286
|
-
layouter: new SimpleTextLayouter(program),
|
|
37287
|
-
subsetter: new TrueTypePdfFontSubsetter()
|
|
37288
|
-
};
|
|
37289
|
-
}
|
|
37290
37183
|
const PDF_HEADER = "%PDF-1.4\n% Oasis PDF\n";
|
|
37291
37184
|
const DEFAULT_PDF_FONT_RESOURCES = [
|
|
37292
37185
|
{ kind: "base14", resourceName: "F1", baseFont: "Helvetica" },
|
|
@@ -37480,53 +37373,15 @@ function textMarkerComment(value) {
|
|
|
37480
37373
|
);
|
|
37481
37374
|
return `% OasisText ${encodePdfUtf16Hex(codePoints)}`;
|
|
37482
37375
|
}
|
|
37483
|
-
class
|
|
37484
|
-
constructor(
|
|
37485
|
-
|
|
37486
|
-
|
|
37487
|
-
|
|
37488
|
-
__publicField(this, "usedFontResourceNames", /* @__PURE__ */ new Set());
|
|
37489
|
-
__publicField(this, "imageResources", /* @__PURE__ */ new Map());
|
|
37490
|
-
for (const resource of fontResources) {
|
|
37491
|
-
this.registerFontResource(resource);
|
|
37492
|
-
}
|
|
37493
|
-
}
|
|
37494
|
-
registerFontResource(resource) {
|
|
37495
|
-
this.fontResources.set(resource.resourceName, resource);
|
|
37496
|
-
if (resource.kind === "unicode" && !this.unicodeFontStates.has(resource.resourceName)) {
|
|
37497
|
-
const font = createPdfEmbeddableFont(
|
|
37498
|
-
parseEmbeddedFontSync(resource.fontData)
|
|
37499
|
-
);
|
|
37500
|
-
const scale = 1e3 / font.program.unitsPerEm;
|
|
37501
|
-
const notdef = {
|
|
37502
|
-
id: 0,
|
|
37503
|
-
codePoints: [0],
|
|
37504
|
-
advanceWidth: font.program.advanceWidthForGlyph(0)
|
|
37505
|
-
};
|
|
37506
|
-
this.unicodeFontStates.set(resource.resourceName, {
|
|
37507
|
-
resource,
|
|
37508
|
-
font,
|
|
37509
|
-
usedGlyphs: /* @__PURE__ */ new Map([[0, notdef]]),
|
|
37510
|
-
scale,
|
|
37511
|
-
layoutCache: /* @__PURE__ */ new Map()
|
|
37512
|
-
});
|
|
37513
|
-
}
|
|
37514
|
-
}
|
|
37515
|
-
addPage(size) {
|
|
37516
|
-
this.pages.push({
|
|
37517
|
-
width: Math.max(1, size.width),
|
|
37518
|
-
height: Math.max(1, size.height),
|
|
37519
|
-
commands: [],
|
|
37520
|
-
imageResourceNames: /* @__PURE__ */ new Set()
|
|
37521
|
-
});
|
|
37522
|
-
return this.pages.length - 1;
|
|
37523
|
-
}
|
|
37524
|
-
getPageCount() {
|
|
37525
|
-
return this.pages.length;
|
|
37376
|
+
class PdfContentStream {
|
|
37377
|
+
constructor(page, fonts, images) {
|
|
37378
|
+
this.page = page;
|
|
37379
|
+
this.fonts = fonts;
|
|
37380
|
+
this.images = images;
|
|
37526
37381
|
}
|
|
37527
|
-
drawRect(
|
|
37528
|
-
const page = this.
|
|
37529
|
-
if (
|
|
37382
|
+
drawRect(options) {
|
|
37383
|
+
const page = this.page;
|
|
37384
|
+
if (options.width <= 0 || options.height <= 0) {
|
|
37530
37385
|
return;
|
|
37531
37386
|
}
|
|
37532
37387
|
const commands = ["q"];
|
|
@@ -37556,11 +37411,8 @@ class OasisPdfWriter {
|
|
|
37556
37411
|
commands.push("Q");
|
|
37557
37412
|
page.commands.push(commands.join("\n"));
|
|
37558
37413
|
}
|
|
37559
|
-
drawLine(
|
|
37560
|
-
const page = this.
|
|
37561
|
-
if (!page) {
|
|
37562
|
-
return;
|
|
37563
|
-
}
|
|
37414
|
+
drawLine(options) {
|
|
37415
|
+
const page = this.page;
|
|
37564
37416
|
const dashCommand = options.dashArray && options.dashArray.length > 0 ? `[${options.dashArray.map((value) => formatNumber(value)).join(" ")}] 0 d` : null;
|
|
37565
37417
|
const commands = [
|
|
37566
37418
|
"q",
|
|
@@ -37581,9 +37433,9 @@ class OasisPdfWriter {
|
|
|
37581
37433
|
// Fills/strokes an arbitrary path. Segment coordinates are in points with a
|
|
37582
37434
|
// top-left origin (callers convert px→pt, like drawRect/drawLine); the y axis
|
|
37583
37435
|
// is flipped here to the PDF bottom-left origin.
|
|
37584
|
-
drawPath(
|
|
37585
|
-
const page = this.
|
|
37586
|
-
if (
|
|
37436
|
+
drawPath(options) {
|
|
37437
|
+
const page = this.page;
|
|
37438
|
+
if (options.segments.length === 0) {
|
|
37587
37439
|
return;
|
|
37588
37440
|
}
|
|
37589
37441
|
if (!options.fill && !options.stroke) {
|
|
@@ -37632,24 +37484,18 @@ class OasisPdfWriter {
|
|
|
37632
37484
|
}
|
|
37633
37485
|
// Saves the graphics state (`q`). Pair with restoreGraphicsState. Any draw
|
|
37634
37486
|
// commands emitted in between inherit the current transform/clip.
|
|
37635
|
-
saveGraphicsState(
|
|
37636
|
-
|
|
37637
|
-
if (page) {
|
|
37638
|
-
page.commands.push("q");
|
|
37639
|
-
}
|
|
37487
|
+
saveGraphicsState() {
|
|
37488
|
+
this.page.commands.push("q");
|
|
37640
37489
|
}
|
|
37641
|
-
restoreGraphicsState(
|
|
37642
|
-
|
|
37643
|
-
if (page) {
|
|
37644
|
-
page.commands.push("Q");
|
|
37645
|
-
}
|
|
37490
|
+
restoreGraphicsState() {
|
|
37491
|
+
this.page.commands.push("Q");
|
|
37646
37492
|
}
|
|
37647
37493
|
// Concatenates a clockwise rotation (in degrees, matching the canvas/editor
|
|
37648
37494
|
// convention) about a top-left-origin point onto the current CTM. Must sit
|
|
37649
37495
|
// inside a saveGraphicsState/restoreGraphicsState pair.
|
|
37650
|
-
rotateAbout(
|
|
37651
|
-
const page = this.
|
|
37652
|
-
if (!
|
|
37496
|
+
rotateAbout(centerX, centerY, degrees) {
|
|
37497
|
+
const page = this.page;
|
|
37498
|
+
if (!degrees) {
|
|
37653
37499
|
return;
|
|
37654
37500
|
}
|
|
37655
37501
|
const cyf = page.height - centerY;
|
|
@@ -37664,9 +37510,9 @@ class OasisPdfWriter {
|
|
|
37664
37510
|
}
|
|
37665
37511
|
// Intersects the clip path with a rectangle (top-left origin). Must sit inside
|
|
37666
37512
|
// a saveGraphicsState/restoreGraphicsState pair so the clip can be undone.
|
|
37667
|
-
clipRect(
|
|
37668
|
-
const page = this.
|
|
37669
|
-
if (
|
|
37513
|
+
clipRect(x, y, width, height) {
|
|
37514
|
+
const page = this.page;
|
|
37515
|
+
if (width <= 0 || height <= 0) {
|
|
37670
37516
|
return;
|
|
37671
37517
|
}
|
|
37672
37518
|
page.commands.push(
|
|
@@ -37675,48 +37521,42 @@ class OasisPdfWriter {
|
|
|
37675
37521
|
"n"
|
|
37676
37522
|
);
|
|
37677
37523
|
}
|
|
37678
|
-
drawText(
|
|
37679
|
-
|
|
37680
|
-
if (!page || options.text.length === 0) {
|
|
37524
|
+
drawText(options) {
|
|
37525
|
+
if (options.text.length === 0) {
|
|
37681
37526
|
return;
|
|
37682
37527
|
}
|
|
37683
|
-
const fontResourceName =
|
|
37684
|
-
this.
|
|
37685
|
-
const
|
|
37686
|
-
if (
|
|
37687
|
-
this.drawUnicodeText(page, unicodeFont, options);
|
|
37528
|
+
const fontResourceName = this.fonts.resolveAndMarkFontName(options);
|
|
37529
|
+
const unicodeState = this.fonts.getUnicodeState(fontResourceName);
|
|
37530
|
+
const showCommand = unicodeState ? this.fonts.buildUnicodeShowCommand(unicodeState, options.text) : `<${encodePdfHexString(options.text)}> Tj`;
|
|
37531
|
+
if (showCommand === null) {
|
|
37688
37532
|
return;
|
|
37689
37533
|
}
|
|
37534
|
+
this.emitTextBlock(fontResourceName, showCommand, options);
|
|
37535
|
+
}
|
|
37536
|
+
emitTextBlock(fontResourceName, showCommand, options) {
|
|
37537
|
+
const page = this.page;
|
|
37690
37538
|
page.commands.push(
|
|
37691
37539
|
[
|
|
37692
37540
|
textMarkerComment(options.text),
|
|
37693
37541
|
"BT",
|
|
37694
37542
|
colorCommand(options.color, "rg", [0, 0, 0]),
|
|
37695
37543
|
`/${fontResourceName} ${formatNumber(options.fontSize ?? 12)} Tf`,
|
|
37544
|
+
...options.renderMode && options.renderMode !== 0 ? [
|
|
37545
|
+
colorCommand(options.color, "RG", [0, 0, 0]),
|
|
37546
|
+
`${formatNumber(Math.max(0.3, (options.fontSize ?? 12) * 0.03))} w`,
|
|
37547
|
+
`${options.renderMode} Tr`
|
|
37548
|
+
] : [],
|
|
37696
37549
|
...options.horizontalScale && options.horizontalScale > 0 && options.horizontalScale !== 100 ? [`${formatNumber(options.horizontalScale)} Tz`] : [],
|
|
37697
37550
|
...options.characterSpacing && options.characterSpacing !== 0 ? [`${formatNumber(options.characterSpacing)} Tc`] : [],
|
|
37698
37551
|
`${formatNumber(options.x)} ${formatNumber(page.height - options.y)} Td`,
|
|
37699
|
-
|
|
37552
|
+
showCommand,
|
|
37700
37553
|
"ET"
|
|
37701
37554
|
].join("\n")
|
|
37702
37555
|
);
|
|
37703
37556
|
}
|
|
37704
|
-
|
|
37705
|
-
const
|
|
37706
|
-
if (!this.
|
|
37707
|
-
this.imageResources.set(resourceName, {
|
|
37708
|
-
resourceName,
|
|
37709
|
-
width: Math.max(1, Math.round(resource.width)),
|
|
37710
|
-
height: Math.max(1, Math.round(resource.height)),
|
|
37711
|
-
data: resource.data,
|
|
37712
|
-
filter: resource.filter
|
|
37713
|
-
});
|
|
37714
|
-
}
|
|
37715
|
-
return resourceName;
|
|
37716
|
-
}
|
|
37717
|
-
drawImage(pageIndex, options) {
|
|
37718
|
-
const page = this.pages[pageIndex];
|
|
37719
|
-
if (!page || options.width <= 0 || options.height <= 0 || !this.imageResources.has(options.resourceName)) {
|
|
37557
|
+
drawImage(options) {
|
|
37558
|
+
const page = this.page;
|
|
37559
|
+
if (options.width <= 0 || options.height <= 0 || !this.images.has(options.resourceName)) {
|
|
37720
37560
|
return;
|
|
37721
37561
|
}
|
|
37722
37562
|
page.imageResourceNames.add(options.resourceName);
|
|
@@ -37767,72 +37607,292 @@ class OasisPdfWriter {
|
|
|
37767
37607
|
].join("\n")
|
|
37768
37608
|
);
|
|
37769
37609
|
}
|
|
37770
|
-
|
|
37771
|
-
|
|
37772
|
-
|
|
37773
|
-
|
|
37610
|
+
}
|
|
37611
|
+
class SimpleTextLayouter {
|
|
37612
|
+
constructor(font) {
|
|
37613
|
+
this.font = font;
|
|
37614
|
+
}
|
|
37615
|
+
layout(text) {
|
|
37616
|
+
const glyphs = [];
|
|
37617
|
+
const positions = [];
|
|
37618
|
+
let advanceWidth = 0;
|
|
37619
|
+
for (const char of text) {
|
|
37620
|
+
const codePoint = char.codePointAt(0) ?? 65533;
|
|
37621
|
+
const glyphId = this.font.glyphForCodePoint(codePoint);
|
|
37622
|
+
const glyphAdvance = this.font.advanceWidthForGlyph(glyphId);
|
|
37623
|
+
glyphs.push({
|
|
37624
|
+
id: glyphId,
|
|
37625
|
+
codePoints: glyphId === 0 ? [65533] : [codePoint],
|
|
37626
|
+
advanceWidth: glyphAdvance
|
|
37627
|
+
});
|
|
37628
|
+
positions.push({ xAdvance: glyphAdvance });
|
|
37629
|
+
advanceWidth += glyphAdvance;
|
|
37774
37630
|
}
|
|
37775
|
-
|
|
37776
|
-
state.layoutCache.set(text, run);
|
|
37777
|
-
return run;
|
|
37631
|
+
return { glyphs, positions, advanceWidth };
|
|
37778
37632
|
}
|
|
37779
|
-
|
|
37780
|
-
|
|
37781
|
-
|
|
37782
|
-
|
|
37633
|
+
}
|
|
37634
|
+
function view(bytes) {
|
|
37635
|
+
return new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
37636
|
+
}
|
|
37637
|
+
function u16(bytes, offset) {
|
|
37638
|
+
return view(bytes).getUint16(offset);
|
|
37639
|
+
}
|
|
37640
|
+
function i16(bytes, offset) {
|
|
37641
|
+
return view(bytes).getInt16(offset);
|
|
37642
|
+
}
|
|
37643
|
+
function writeU16(target, offset, value) {
|
|
37644
|
+
view(target).setUint16(offset, value, false);
|
|
37645
|
+
}
|
|
37646
|
+
function writeU32(target, offset, value) {
|
|
37647
|
+
view(target).setUint32(offset, value, false);
|
|
37648
|
+
}
|
|
37649
|
+
function pad4(length) {
|
|
37650
|
+
return length + 3 & -4;
|
|
37651
|
+
}
|
|
37652
|
+
function concat(chunks) {
|
|
37653
|
+
const total = chunks.reduce((sum, chunk) => sum + pad4(chunk.byteLength), 0);
|
|
37654
|
+
const result = new Uint8Array(total);
|
|
37655
|
+
let offset = 0;
|
|
37656
|
+
for (const chunk of chunks) {
|
|
37657
|
+
result.set(chunk, offset);
|
|
37658
|
+
offset += pad4(chunk.byteLength);
|
|
37659
|
+
}
|
|
37660
|
+
return result;
|
|
37661
|
+
}
|
|
37662
|
+
function readLoca(loca, indexToLocFormat) {
|
|
37663
|
+
const offsets = [];
|
|
37664
|
+
const table = view(loca);
|
|
37665
|
+
if (indexToLocFormat === 0) {
|
|
37666
|
+
for (let offset = 0; offset + 1 < loca.byteLength; offset += 2) {
|
|
37667
|
+
offsets.push(table.getUint16(offset) * 2);
|
|
37668
|
+
}
|
|
37669
|
+
} else {
|
|
37670
|
+
for (let offset = 0; offset + 3 < loca.byteLength; offset += 4) {
|
|
37671
|
+
offsets.push(table.getUint32(offset));
|
|
37672
|
+
}
|
|
37673
|
+
}
|
|
37674
|
+
return offsets;
|
|
37675
|
+
}
|
|
37676
|
+
function glyphRange(offsets, glyphId) {
|
|
37677
|
+
const start = offsets[glyphId];
|
|
37678
|
+
const end = offsets[glyphId + 1];
|
|
37679
|
+
return start === void 0 || end === void 0 ? null : { start, end };
|
|
37680
|
+
}
|
|
37681
|
+
function collectCompositeGlyphs(glyph, addGlyph) {
|
|
37682
|
+
if (glyph.byteLength < 10 || i16(glyph, 0) >= 0) {
|
|
37683
|
+
return;
|
|
37684
|
+
}
|
|
37685
|
+
let offset = 10;
|
|
37686
|
+
let flags = 0;
|
|
37687
|
+
do {
|
|
37688
|
+
if (offset + 4 > glyph.byteLength) return;
|
|
37689
|
+
flags = u16(glyph, offset);
|
|
37690
|
+
addGlyph(u16(glyph, offset + 2));
|
|
37691
|
+
offset += 4;
|
|
37692
|
+
offset += flags & 1 ? 4 : 2;
|
|
37693
|
+
if (flags & 8) offset += 2;
|
|
37694
|
+
else if (flags & 64) offset += 4;
|
|
37695
|
+
else if (flags & 128) offset += 8;
|
|
37696
|
+
} while (flags & 32);
|
|
37697
|
+
}
|
|
37698
|
+
function subsetClosure(font, initialGlyphs) {
|
|
37699
|
+
const glyf = font.getRawTableData("glyf");
|
|
37700
|
+
const loca = font.getRawTableData("loca");
|
|
37701
|
+
const head = font.getRawTableData("head");
|
|
37702
|
+
if (!glyf || !loca || !head) {
|
|
37703
|
+
return Array.from(/* @__PURE__ */ new Set([0, ...initialGlyphs])).sort((a, b) => a - b);
|
|
37704
|
+
}
|
|
37705
|
+
const offsets = readLoca(loca, u16(head, 50));
|
|
37706
|
+
const used = /* @__PURE__ */ new Set([0, ...initialGlyphs]);
|
|
37707
|
+
const stack = Array.from(used);
|
|
37708
|
+
while (stack.length > 0) {
|
|
37709
|
+
const glyphId = stack.pop();
|
|
37710
|
+
const range = glyphRange(offsets, glyphId);
|
|
37711
|
+
if (!range || range.end <= range.start || range.end > glyf.byteLength) {
|
|
37712
|
+
continue;
|
|
37713
|
+
}
|
|
37714
|
+
const glyph = glyf.slice(range.start, range.end);
|
|
37715
|
+
collectCompositeGlyphs(glyph, (componentId) => {
|
|
37716
|
+
if (!used.has(componentId)) {
|
|
37717
|
+
used.add(componentId);
|
|
37718
|
+
stack.push(componentId);
|
|
37783
37719
|
}
|
|
37784
|
-
const position = run.positions[index];
|
|
37785
|
-
const nominalWidth = glyph.advanceWidth * state.scale;
|
|
37786
|
-
const desiredAdvance = ((position == null ? void 0 : position.xAdvance) ?? glyph.advanceWidth) * state.scale;
|
|
37787
|
-
return { glyphId: glyph.id, nominalWidth, desiredAdvance };
|
|
37788
37720
|
});
|
|
37789
37721
|
}
|
|
37790
|
-
|
|
37791
|
-
|
|
37722
|
+
return Array.from(used).sort((a, b) => a - b);
|
|
37723
|
+
}
|
|
37724
|
+
function buildLoca(offsets) {
|
|
37725
|
+
const loca = new Uint8Array(offsets.length * 4);
|
|
37726
|
+
offsets.forEach((offset, index) => writeU32(loca, index * 4, offset));
|
|
37727
|
+
return loca;
|
|
37728
|
+
}
|
|
37729
|
+
function buildHmtx(font, maxGlyphId) {
|
|
37730
|
+
const hmtx = new Uint8Array((maxGlyphId + 1) * 4);
|
|
37731
|
+
for (let glyphId = 0; glyphId <= maxGlyphId; glyphId += 1) {
|
|
37732
|
+
writeU16(hmtx, glyphId * 4, font.advanceWidthForGlyph(glyphId));
|
|
37733
|
+
writeU16(hmtx, glyphId * 4 + 2, 0);
|
|
37734
|
+
}
|
|
37735
|
+
return hmtx;
|
|
37736
|
+
}
|
|
37737
|
+
function buildSubsetTables(font, glyphIds) {
|
|
37738
|
+
const glyf = font.getRawTableData("glyf");
|
|
37739
|
+
const loca = font.getRawTableData("loca");
|
|
37740
|
+
const head = font.getRawTableData("head");
|
|
37741
|
+
const hhea = font.getRawTableData("hhea");
|
|
37742
|
+
const maxp = font.getRawTableData("maxp");
|
|
37743
|
+
const cmap = font.getRawTableData("cmap");
|
|
37744
|
+
if (!glyf || !loca || !head || !hhea || !maxp || !cmap) {
|
|
37745
|
+
throw new Error("Missing required TrueType tables for subsetting");
|
|
37746
|
+
}
|
|
37747
|
+
const maxGlyphId = Math.max(0, ...glyphIds);
|
|
37748
|
+
const used = new Set(glyphIds);
|
|
37749
|
+
const sourceOffsets = readLoca(loca, u16(head, 50));
|
|
37750
|
+
const locaOffsets = [];
|
|
37751
|
+
const glyfChunks = [];
|
|
37752
|
+
let glyfOffset = 0;
|
|
37753
|
+
for (let glyphId = 0; glyphId <= maxGlyphId; glyphId += 1) {
|
|
37754
|
+
locaOffsets.push(glyfOffset);
|
|
37755
|
+
const range = glyphRange(sourceOffsets, glyphId);
|
|
37756
|
+
if (used.has(glyphId) && range && range.end > range.start) {
|
|
37757
|
+
const glyph = glyf.slice(range.start, range.end);
|
|
37758
|
+
glyfChunks.push(glyph);
|
|
37759
|
+
glyfOffset += pad4(glyph.byteLength);
|
|
37760
|
+
}
|
|
37761
|
+
}
|
|
37762
|
+
locaOffsets.push(glyfOffset);
|
|
37763
|
+
const newHead = head.slice();
|
|
37764
|
+
writeU32(newHead, 8, 0);
|
|
37765
|
+
writeU16(newHead, 50, 1);
|
|
37766
|
+
const newHhea = hhea.slice();
|
|
37767
|
+
writeU16(newHhea, 34, maxGlyphId + 1);
|
|
37768
|
+
const newMaxp = maxp.slice();
|
|
37769
|
+
writeU16(newMaxp, 4, maxGlyphId + 1);
|
|
37770
|
+
const tables = {
|
|
37771
|
+
cmap,
|
|
37772
|
+
head: newHead,
|
|
37773
|
+
hhea: newHhea,
|
|
37774
|
+
hmtx: buildHmtx(font, maxGlyphId),
|
|
37775
|
+
loca: buildLoca(locaOffsets),
|
|
37776
|
+
maxp: newMaxp,
|
|
37777
|
+
glyf: concat(glyfChunks)
|
|
37778
|
+
};
|
|
37779
|
+
for (const tag of ["OS/2", "name", "post"]) {
|
|
37780
|
+
const table = font.getRawTableData(tag);
|
|
37781
|
+
if (table) tables[tag] = table;
|
|
37782
|
+
}
|
|
37783
|
+
return tables;
|
|
37784
|
+
}
|
|
37785
|
+
class TrueTypePdfFontSubsetter {
|
|
37786
|
+
createSubset(font, glyphs) {
|
|
37787
|
+
const unicodeByGlyph = /* @__PURE__ */ new Map();
|
|
37788
|
+
const initialGlyphs = [];
|
|
37789
|
+
for (const glyph of glyphs) {
|
|
37790
|
+
initialGlyphs.push(glyph.id);
|
|
37791
|
+
if (!unicodeByGlyph.has(glyph.id)) {
|
|
37792
|
+
unicodeByGlyph.set(glyph.id, glyph.codePoints);
|
|
37793
|
+
}
|
|
37794
|
+
}
|
|
37795
|
+
const glyphIds = subsetClosure(font, initialGlyphs);
|
|
37796
|
+
const tables = buildSubsetTables(font, glyphIds);
|
|
37797
|
+
const fontFile = buildSfnt(
|
|
37798
|
+
65536,
|
|
37799
|
+
new Map(
|
|
37800
|
+
Object.entries(tables).map(([tag, data]) => [
|
|
37801
|
+
tag.charCodeAt(0) << 24 | tag.charCodeAt(1) << 16 | tag.charCodeAt(2) << 8 | tag.charCodeAt(3),
|
|
37802
|
+
data
|
|
37803
|
+
])
|
|
37804
|
+
)
|
|
37805
|
+
).ttf;
|
|
37806
|
+
const maxGlyphId = Math.max(0, ...glyphIds);
|
|
37807
|
+
const widths = [];
|
|
37808
|
+
const unicode = [];
|
|
37809
|
+
for (let glyphId = 0; glyphId <= maxGlyphId; glyphId += 1) {
|
|
37810
|
+
widths[glyphId] = font.advanceWidthForGlyph(glyphId) / font.unitsPerEm * 1e3;
|
|
37811
|
+
unicode[glyphId] = unicodeByGlyph.get(glyphId) ?? [0];
|
|
37812
|
+
}
|
|
37813
|
+
return {
|
|
37814
|
+
fontFile,
|
|
37815
|
+
widths,
|
|
37816
|
+
unicode,
|
|
37817
|
+
encodeGlyph: (glyphId) => glyphId
|
|
37818
|
+
};
|
|
37819
|
+
}
|
|
37820
|
+
}
|
|
37821
|
+
function parseEmbeddedFontSync(sourceBytes) {
|
|
37822
|
+
const sfntBytes = defaultFontDecoderRegistry.decodeSync(sourceBytes);
|
|
37823
|
+
return SfntFontProgram.parse(sfntBytes);
|
|
37824
|
+
}
|
|
37825
|
+
function createPdfEmbeddableFont(program) {
|
|
37826
|
+
return {
|
|
37827
|
+
program,
|
|
37828
|
+
layouter: new SimpleTextLayouter(program),
|
|
37829
|
+
subsetter: new TrueTypePdfFontSubsetter()
|
|
37830
|
+
};
|
|
37831
|
+
}
|
|
37832
|
+
class PdfFontTable {
|
|
37833
|
+
constructor(fontResources) {
|
|
37834
|
+
__publicField(this, "fontResources", /* @__PURE__ */ new Map());
|
|
37835
|
+
__publicField(this, "unicodeFontStates", /* @__PURE__ */ new Map());
|
|
37836
|
+
__publicField(this, "usedFontResourceNames", /* @__PURE__ */ new Set());
|
|
37837
|
+
for (const resource of fontResources) {
|
|
37838
|
+
this.registerFontResource(resource);
|
|
37839
|
+
}
|
|
37840
|
+
}
|
|
37841
|
+
registerFontResource(resource) {
|
|
37842
|
+
this.fontResources.set(resource.resourceName, resource);
|
|
37843
|
+
if (resource.kind === "unicode" && !this.unicodeFontStates.has(resource.resourceName)) {
|
|
37844
|
+
const font = createPdfEmbeddableFont(
|
|
37845
|
+
parseEmbeddedFontSync(resource.fontData)
|
|
37846
|
+
);
|
|
37847
|
+
const scale = 1e3 / font.program.unitsPerEm;
|
|
37848
|
+
const notdef = {
|
|
37849
|
+
id: 0,
|
|
37850
|
+
codePoints: [0],
|
|
37851
|
+
advanceWidth: font.program.advanceWidthForGlyph(0)
|
|
37852
|
+
};
|
|
37853
|
+
this.unicodeFontStates.set(resource.resourceName, {
|
|
37854
|
+
resource,
|
|
37855
|
+
font,
|
|
37856
|
+
usedGlyphs: /* @__PURE__ */ new Map([[0, notdef]]),
|
|
37857
|
+
scale,
|
|
37858
|
+
layoutCache: /* @__PURE__ */ new Map()
|
|
37859
|
+
});
|
|
37860
|
+
}
|
|
37861
|
+
}
|
|
37862
|
+
/** Resolves the font resource a run uses and marks it as referenced. */
|
|
37863
|
+
resolveAndMarkFontName(options) {
|
|
37864
|
+
const fontResourceName = resolveFontName(options);
|
|
37865
|
+
this.usedFontResourceNames.add(fontResourceName);
|
|
37866
|
+
return fontResourceName;
|
|
37867
|
+
}
|
|
37868
|
+
getUnicodeState(resourceName) {
|
|
37869
|
+
return this.unicodeFontStates.get(resourceName);
|
|
37870
|
+
}
|
|
37871
|
+
/**
|
|
37872
|
+
* Builds the glyph-show operator (`<...> Tj` or `[...] TJ`) for an embedded
|
|
37873
|
+
* Unicode run, recording the glyphs used for subsetting. Returns `null` when
|
|
37874
|
+
* the run produced no glyphs so the caller can skip emission entirely.
|
|
37875
|
+
*/
|
|
37876
|
+
buildUnicodeShowCommand(state, text) {
|
|
37877
|
+
const run = this.layoutUnicodeText(state, text);
|
|
37792
37878
|
const encoded = this.encodeUnicodeGlyphRun(state, run);
|
|
37793
37879
|
if (encoded.length === 0) {
|
|
37794
|
-
return;
|
|
37880
|
+
return null;
|
|
37795
37881
|
}
|
|
37796
37882
|
const usesAdjustments = encoded.some(
|
|
37797
37883
|
(glyph) => Math.abs(glyph.nominalWidth - glyph.desiredAdvance) > 0.01
|
|
37798
37884
|
);
|
|
37799
|
-
|
|
37885
|
+
return usesAdjustments ? `[${encoded.map((glyph) => {
|
|
37800
37886
|
const adjustment = glyph.nominalWidth - glyph.desiredAdvance;
|
|
37801
37887
|
return adjustment === 0 ? `<${encodeGlyphHex(glyph.glyphId)}>` : `<${encodeGlyphHex(glyph.glyphId)}> ${formatNumber(adjustment)}`;
|
|
37802
37888
|
}).join(" ")}] TJ` : `<${encoded.map((glyph) => encodeGlyphHex(glyph.glyphId)).join("")}> Tj`;
|
|
37803
|
-
page.commands.push(
|
|
37804
|
-
[
|
|
37805
|
-
textMarkerComment(options.text),
|
|
37806
|
-
"BT",
|
|
37807
|
-
colorCommand(options.color, "rg", [0, 0, 0]),
|
|
37808
|
-
`/${state.resource.resourceName} ${formatNumber(options.fontSize ?? 12)} Tf`,
|
|
37809
|
-
...options.horizontalScale && options.horizontalScale > 0 && options.horizontalScale !== 100 ? [`${formatNumber(options.horizontalScale)} Tz`] : [],
|
|
37810
|
-
...options.characterSpacing && options.characterSpacing !== 0 ? [`${formatNumber(options.characterSpacing)} Tc`] : [],
|
|
37811
|
-
`${formatNumber(options.x)} ${formatNumber(page.height - options.y)} Td`,
|
|
37812
|
-
textCommand,
|
|
37813
|
-
"ET"
|
|
37814
|
-
].join("\n")
|
|
37815
|
-
);
|
|
37816
37889
|
}
|
|
37817
|
-
|
|
37818
|
-
|
|
37819
|
-
|
|
37820
|
-
|
|
37821
|
-
|
|
37822
|
-
|
|
37823
|
-
}
|
|
37824
|
-
toUint8Array() {
|
|
37825
|
-
if (this.pages.length === 0) {
|
|
37826
|
-
this.addPage({ width: 612, height: 792 });
|
|
37827
|
-
}
|
|
37828
|
-
const objects = [];
|
|
37829
|
-
const addObject = (body2) => {
|
|
37830
|
-
const id = objects.length + 1;
|
|
37831
|
-
objects.push({ id, body: body2 });
|
|
37832
|
-
return id;
|
|
37833
|
-
};
|
|
37834
|
-
const catalogObjectId = addObject("");
|
|
37835
|
-
const pagesObjectId = addObject("");
|
|
37890
|
+
/**
|
|
37891
|
+
* Emits the font objects (base-14 dictionaries and embedded Unicode font
|
|
37892
|
+
* programs) for every referenced resource and returns the `/Font` resource
|
|
37893
|
+
* dictionary XML for page objects.
|
|
37894
|
+
*/
|
|
37895
|
+
buildFontObjects(addObject) {
|
|
37836
37896
|
const fontResourceEntries = Array.from(this.fontResources.values()).filter(
|
|
37837
37897
|
(resource) => resource.kind === "base14" || this.usedFontResourceNames.has(resource.resourceName)
|
|
37838
37898
|
);
|
|
@@ -37845,86 +37905,28 @@ class OasisPdfWriter {
|
|
|
37845
37905
|
}
|
|
37846
37906
|
return addObject(fontResourceObjectBody(font));
|
|
37847
37907
|
});
|
|
37848
|
-
const
|
|
37849
|
-
|
|
37850
|
-
|
|
37851
|
-
|
|
37852
|
-
|
|
37853
|
-
|
|
37854
|
-
|
|
37855
|
-
}
|
|
37856
|
-
const pageObjectIds = [];
|
|
37857
|
-
for (const page of this.pages) {
|
|
37858
|
-
const stream = `${page.commands.join("\n")}
|
|
37859
|
-
`;
|
|
37860
|
-
const contentObjectId = addObject(
|
|
37861
|
-
`<< /Length ${byteLength(stream)} >>
|
|
37862
|
-
stream
|
|
37863
|
-
${stream}endstream`
|
|
37864
|
-
);
|
|
37865
|
-
const imageResourceXml = Array.from(page.imageResourceNames).map((resourceName) => {
|
|
37866
|
-
const objectId = imageObjectIds.get(resourceName);
|
|
37867
|
-
return objectId ? `/${resourceName} ${objectId} 0 R` : "";
|
|
37868
|
-
}).filter(Boolean).join(" ");
|
|
37869
|
-
const xObjectResourceXml = imageResourceXml ? ` /XObject << ${imageResourceXml} >>` : "";
|
|
37870
|
-
const pageObjectId = addObject(
|
|
37871
|
-
[
|
|
37872
|
-
"<< /Type /Page",
|
|
37873
|
-
`/Parent ${pagesObjectId} 0 R`,
|
|
37874
|
-
`/MediaBox [0 0 ${formatNumber(page.width)} ${formatNumber(page.height)}]`,
|
|
37875
|
-
`/Resources << /Font << ${fontResourceXml} >>${xObjectResourceXml} >>`,
|
|
37876
|
-
`/Contents ${contentObjectId} 0 R`,
|
|
37877
|
-
">>"
|
|
37878
|
-
].join("\n")
|
|
37879
|
-
);
|
|
37880
|
-
pageObjectIds.push(pageObjectId);
|
|
37881
|
-
}
|
|
37882
|
-
objects[catalogObjectId - 1].body = `<< /Type /Catalog /Pages ${pagesObjectId} 0 R >>`;
|
|
37883
|
-
objects[pagesObjectId - 1].body = [
|
|
37884
|
-
"<< /Type /Pages",
|
|
37885
|
-
`/Kids [${pageObjectIds.map((id) => `${id} 0 R`).join(" ")}]`,
|
|
37886
|
-
`/Count ${pageObjectIds.length}`,
|
|
37887
|
-
">>"
|
|
37888
|
-
].join("\n");
|
|
37889
|
-
let body = PDF_HEADER;
|
|
37890
|
-
const offsets = [0];
|
|
37891
|
-
for (const object of objects) {
|
|
37892
|
-
offsets[object.id] = byteLength(body);
|
|
37893
|
-
body += `${object.id} 0 obj
|
|
37894
|
-
${object.body}
|
|
37895
|
-
endobj
|
|
37896
|
-
`;
|
|
37897
|
-
}
|
|
37898
|
-
const xrefOffset = byteLength(body);
|
|
37899
|
-
body += `xref
|
|
37900
|
-
0 ${objects.length + 1}
|
|
37901
|
-
`;
|
|
37902
|
-
body += "0000000000 65535 f \n";
|
|
37903
|
-
for (const object of objects) {
|
|
37904
|
-
body += `${String(offsets[object.id] ?? 0).padStart(10, "0")} 00000 n
|
|
37905
|
-
`;
|
|
37908
|
+
const resourceXml = fontResourceEntries.map((font, index) => `/${font.resourceName} ${fontObjectIds[index]} 0 R`).join(" ");
|
|
37909
|
+
return { resourceXml };
|
|
37910
|
+
}
|
|
37911
|
+
layoutUnicodeText(state, text) {
|
|
37912
|
+
const cached = state.layoutCache.get(text);
|
|
37913
|
+
if (cached) {
|
|
37914
|
+
return cached;
|
|
37906
37915
|
}
|
|
37907
|
-
|
|
37908
|
-
|
|
37909
|
-
|
|
37910
|
-
"startxref",
|
|
37911
|
-
String(xrefOffset),
|
|
37912
|
-
"%%EOF",
|
|
37913
|
-
""
|
|
37914
|
-
].join("\n");
|
|
37915
|
-
return new TextEncoder().encode(body);
|
|
37916
|
+
const run = state.font.layouter.layout(text);
|
|
37917
|
+
state.layoutCache.set(text, run);
|
|
37918
|
+
return run;
|
|
37916
37919
|
}
|
|
37917
|
-
|
|
37918
|
-
return
|
|
37919
|
-
|
|
37920
|
-
|
|
37921
|
-
|
|
37922
|
-
|
|
37923
|
-
|
|
37924
|
-
|
|
37925
|
-
|
|
37926
|
-
|
|
37927
|
-
);
|
|
37920
|
+
encodeUnicodeGlyphRun(state, run) {
|
|
37921
|
+
return run.glyphs.map((glyph, index) => {
|
|
37922
|
+
if (!state.usedGlyphs.has(glyph.id)) {
|
|
37923
|
+
state.usedGlyphs.set(glyph.id, glyph);
|
|
37924
|
+
}
|
|
37925
|
+
const position = run.positions[index];
|
|
37926
|
+
const nominalWidth = glyph.advanceWidth * state.scale;
|
|
37927
|
+
const desiredAdvance = ((position == null ? void 0 : position.xAdvance) ?? glyph.advanceWidth) * state.scale;
|
|
37928
|
+
return { glyphId: glyph.id, nominalWidth, desiredAdvance };
|
|
37929
|
+
});
|
|
37928
37930
|
}
|
|
37929
37931
|
addUnicodeFontObjects(state, addObject) {
|
|
37930
37932
|
const subset = state.font.subsetter.createSubset(
|
|
@@ -38002,6 +38004,200 @@ endobj
|
|
|
38002
38004
|
);
|
|
38003
38005
|
}
|
|
38004
38006
|
}
|
|
38007
|
+
class PdfImageTable {
|
|
38008
|
+
constructor() {
|
|
38009
|
+
__publicField(this, "imageResources", /* @__PURE__ */ new Map());
|
|
38010
|
+
}
|
|
38011
|
+
registerImageResource(resource) {
|
|
38012
|
+
const resourceName = resource.resourceName ?? `Im${this.imageResources.size + 1}`;
|
|
38013
|
+
if (!this.imageResources.has(resourceName)) {
|
|
38014
|
+
this.imageResources.set(resourceName, {
|
|
38015
|
+
resourceName,
|
|
38016
|
+
width: Math.max(1, Math.round(resource.width)),
|
|
38017
|
+
height: Math.max(1, Math.round(resource.height)),
|
|
38018
|
+
data: resource.data,
|
|
38019
|
+
filter: resource.filter
|
|
38020
|
+
});
|
|
38021
|
+
}
|
|
38022
|
+
return resourceName;
|
|
38023
|
+
}
|
|
38024
|
+
has(resourceName) {
|
|
38025
|
+
return this.imageResources.has(resourceName);
|
|
38026
|
+
}
|
|
38027
|
+
/** Emits each registered image object, keyed by resource name for page maps. */
|
|
38028
|
+
buildImageObjects(addObject) {
|
|
38029
|
+
const imageObjectIds = /* @__PURE__ */ new Map();
|
|
38030
|
+
for (const image of this.imageResources.values()) {
|
|
38031
|
+
imageObjectIds.set(
|
|
38032
|
+
image.resourceName,
|
|
38033
|
+
this.addImageObject(image, addObject)
|
|
38034
|
+
);
|
|
38035
|
+
}
|
|
38036
|
+
return imageObjectIds;
|
|
38037
|
+
}
|
|
38038
|
+
addImageObject(resource, addObject) {
|
|
38039
|
+
return addObject(
|
|
38040
|
+
asciiHexImageStreamObjectBody(resource.data, [
|
|
38041
|
+
"/Type /XObject",
|
|
38042
|
+
"/Subtype /Image",
|
|
38043
|
+
`/Width ${resource.width}`,
|
|
38044
|
+
`/Height ${resource.height}`,
|
|
38045
|
+
"/ColorSpace /DeviceRGB",
|
|
38046
|
+
"/BitsPerComponent 8"
|
|
38047
|
+
])
|
|
38048
|
+
);
|
|
38049
|
+
}
|
|
38050
|
+
}
|
|
38051
|
+
function serializePdfDocument(pages, fonts, images) {
|
|
38052
|
+
const objects = [];
|
|
38053
|
+
const addObject = (body2) => {
|
|
38054
|
+
const id = objects.length + 1;
|
|
38055
|
+
objects.push({ id, body: body2 });
|
|
38056
|
+
return id;
|
|
38057
|
+
};
|
|
38058
|
+
const catalogObjectId = addObject("");
|
|
38059
|
+
const pagesObjectId = addObject("");
|
|
38060
|
+
const { resourceXml: fontResourceXml } = fonts.buildFontObjects(addObject);
|
|
38061
|
+
const imageObjectIds = images.buildImageObjects(addObject);
|
|
38062
|
+
const pageObjectIds = [];
|
|
38063
|
+
for (const page of pages) {
|
|
38064
|
+
const stream = `${page.commands.join("\n")}
|
|
38065
|
+
`;
|
|
38066
|
+
const contentObjectId = addObject(
|
|
38067
|
+
`<< /Length ${byteLength(stream)} >>
|
|
38068
|
+
stream
|
|
38069
|
+
${stream}endstream`
|
|
38070
|
+
);
|
|
38071
|
+
const imageResourceXml = Array.from(page.imageResourceNames).map((resourceName) => {
|
|
38072
|
+
const objectId = imageObjectIds.get(resourceName);
|
|
38073
|
+
return objectId ? `/${resourceName} ${objectId} 0 R` : "";
|
|
38074
|
+
}).filter(Boolean).join(" ");
|
|
38075
|
+
const xObjectResourceXml = imageResourceXml ? ` /XObject << ${imageResourceXml} >>` : "";
|
|
38076
|
+
const pageObjectId = addObject(
|
|
38077
|
+
[
|
|
38078
|
+
"<< /Type /Page",
|
|
38079
|
+
`/Parent ${pagesObjectId} 0 R`,
|
|
38080
|
+
`/MediaBox [0 0 ${formatNumber(page.width)} ${formatNumber(page.height)}]`,
|
|
38081
|
+
`/Resources << /Font << ${fontResourceXml} >>${xObjectResourceXml} >>`,
|
|
38082
|
+
`/Contents ${contentObjectId} 0 R`,
|
|
38083
|
+
">>"
|
|
38084
|
+
].join("\n")
|
|
38085
|
+
);
|
|
38086
|
+
pageObjectIds.push(pageObjectId);
|
|
38087
|
+
}
|
|
38088
|
+
objects[catalogObjectId - 1].body = `<< /Type /Catalog /Pages ${pagesObjectId} 0 R >>`;
|
|
38089
|
+
objects[pagesObjectId - 1].body = [
|
|
38090
|
+
"<< /Type /Pages",
|
|
38091
|
+
`/Kids [${pageObjectIds.map((id) => `${id} 0 R`).join(" ")}]`,
|
|
38092
|
+
`/Count ${pageObjectIds.length}`,
|
|
38093
|
+
">>"
|
|
38094
|
+
].join("\n");
|
|
38095
|
+
let body = PDF_HEADER;
|
|
38096
|
+
const offsets = [0];
|
|
38097
|
+
for (const object of objects) {
|
|
38098
|
+
offsets[object.id] = byteLength(body);
|
|
38099
|
+
body += `${object.id} 0 obj
|
|
38100
|
+
${object.body}
|
|
38101
|
+
endobj
|
|
38102
|
+
`;
|
|
38103
|
+
}
|
|
38104
|
+
const xrefOffset = byteLength(body);
|
|
38105
|
+
body += `xref
|
|
38106
|
+
0 ${objects.length + 1}
|
|
38107
|
+
`;
|
|
38108
|
+
body += "0000000000 65535 f \n";
|
|
38109
|
+
for (const object of objects) {
|
|
38110
|
+
body += `${String(offsets[object.id] ?? 0).padStart(10, "0")} 00000 n
|
|
38111
|
+
`;
|
|
38112
|
+
}
|
|
38113
|
+
body += [
|
|
38114
|
+
"trailer",
|
|
38115
|
+
`<< /Size ${objects.length + 1} /Root ${catalogObjectId} 0 R >>`,
|
|
38116
|
+
"startxref",
|
|
38117
|
+
String(xrefOffset),
|
|
38118
|
+
"%%EOF",
|
|
38119
|
+
""
|
|
38120
|
+
].join("\n");
|
|
38121
|
+
return new TextEncoder().encode(body);
|
|
38122
|
+
}
|
|
38123
|
+
class OasisPdfWriter {
|
|
38124
|
+
constructor(fontResources = DEFAULT_PDF_FONT_RESOURCES) {
|
|
38125
|
+
__publicField(this, "pages", []);
|
|
38126
|
+
__publicField(this, "streams", []);
|
|
38127
|
+
__publicField(this, "fonts");
|
|
38128
|
+
__publicField(this, "images", new PdfImageTable());
|
|
38129
|
+
this.fonts = new PdfFontTable(fontResources);
|
|
38130
|
+
}
|
|
38131
|
+
registerFontResource(resource) {
|
|
38132
|
+
this.fonts.registerFontResource(resource);
|
|
38133
|
+
}
|
|
38134
|
+
addPage(size) {
|
|
38135
|
+
const page = {
|
|
38136
|
+
width: Math.max(1, size.width),
|
|
38137
|
+
height: Math.max(1, size.height),
|
|
38138
|
+
commands: [],
|
|
38139
|
+
imageResourceNames: /* @__PURE__ */ new Set()
|
|
38140
|
+
};
|
|
38141
|
+
this.pages.push(page);
|
|
38142
|
+
this.streams.push(new PdfContentStream(page, this.fonts, this.images));
|
|
38143
|
+
return this.pages.length - 1;
|
|
38144
|
+
}
|
|
38145
|
+
getPageCount() {
|
|
38146
|
+
return this.pages.length;
|
|
38147
|
+
}
|
|
38148
|
+
drawRect(pageIndex, options) {
|
|
38149
|
+
var _a;
|
|
38150
|
+
(_a = this.streams[pageIndex]) == null ? void 0 : _a.drawRect(options);
|
|
38151
|
+
}
|
|
38152
|
+
drawLine(pageIndex, options) {
|
|
38153
|
+
var _a;
|
|
38154
|
+
(_a = this.streams[pageIndex]) == null ? void 0 : _a.drawLine(options);
|
|
38155
|
+
}
|
|
38156
|
+
drawPath(pageIndex, options) {
|
|
38157
|
+
var _a;
|
|
38158
|
+
(_a = this.streams[pageIndex]) == null ? void 0 : _a.drawPath(options);
|
|
38159
|
+
}
|
|
38160
|
+
saveGraphicsState(pageIndex) {
|
|
38161
|
+
var _a;
|
|
38162
|
+
(_a = this.streams[pageIndex]) == null ? void 0 : _a.saveGraphicsState();
|
|
38163
|
+
}
|
|
38164
|
+
restoreGraphicsState(pageIndex) {
|
|
38165
|
+
var _a;
|
|
38166
|
+
(_a = this.streams[pageIndex]) == null ? void 0 : _a.restoreGraphicsState();
|
|
38167
|
+
}
|
|
38168
|
+
rotateAbout(pageIndex, centerX, centerY, degrees) {
|
|
38169
|
+
var _a;
|
|
38170
|
+
(_a = this.streams[pageIndex]) == null ? void 0 : _a.rotateAbout(centerX, centerY, degrees);
|
|
38171
|
+
}
|
|
38172
|
+
clipRect(pageIndex, x, y, width, height) {
|
|
38173
|
+
var _a;
|
|
38174
|
+
(_a = this.streams[pageIndex]) == null ? void 0 : _a.clipRect(x, y, width, height);
|
|
38175
|
+
}
|
|
38176
|
+
drawText(pageIndex, options) {
|
|
38177
|
+
var _a;
|
|
38178
|
+
(_a = this.streams[pageIndex]) == null ? void 0 : _a.drawText(options);
|
|
38179
|
+
}
|
|
38180
|
+
registerImageResource(resource) {
|
|
38181
|
+
return this.images.registerImageResource(resource);
|
|
38182
|
+
}
|
|
38183
|
+
drawImage(pageIndex, options) {
|
|
38184
|
+
var _a;
|
|
38185
|
+
(_a = this.streams[pageIndex]) == null ? void 0 : _a.drawImage(options);
|
|
38186
|
+
}
|
|
38187
|
+
toArrayBuffer() {
|
|
38188
|
+
const bytes = this.toUint8Array();
|
|
38189
|
+
return Uint8Array.from(bytes).buffer;
|
|
38190
|
+
}
|
|
38191
|
+
toBlob() {
|
|
38192
|
+
return new Blob([this.toArrayBuffer()], { type: "application/pdf" });
|
|
38193
|
+
}
|
|
38194
|
+
toUint8Array() {
|
|
38195
|
+
if (this.pages.length === 0) {
|
|
38196
|
+
this.addPage({ width: 612, height: 792 });
|
|
38197
|
+
}
|
|
38198
|
+
return serializePdfDocument(this.pages, this.fonts, this.images);
|
|
38199
|
+
}
|
|
38200
|
+
}
|
|
38005
38201
|
const FOOTNOTE_BLOCK_GAP_PX = 2;
|
|
38006
38202
|
async function exportEditorDocumentToPdf(document2) {
|
|
38007
38203
|
document2 = renumberImageCaptionsInDocument(document2);
|