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.
@@ -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-BICQTKCZ.js";
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
- if (paragraphAlign === "justify") {
36426
- const chunks = groupSlotChunksByWhitespace(chars);
36427
- for (const chunk of chunks) {
36428
- const chunkText = chunk.map((c) => styles.allCaps ? c.char.toUpperCase() : c.char).join("");
36429
- if (chunkText.length === 0) continue;
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
- x: pxToPt$1(originX + chunk[0].left),
36432
- y: pxToPt$1(baselineY),
36433
- text: chunkText,
36434
- fontSize: fontSizePt,
36435
- color: styles.color ?? "#000000",
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
- } else {
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
- x: pxToPt$1(originX + chunk[0].left),
36450
- y: pxToPt$1(baselineY),
36451
- text: chunkText,
36452
- fontSize: fontSizePt,
36453
- color: styles.color ?? "#000000",
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 OasisPdfWriter {
37484
- constructor(fontResources = DEFAULT_PDF_FONT_RESOURCES) {
37485
- __publicField(this, "pages", []);
37486
- __publicField(this, "fontResources", /* @__PURE__ */ new Map());
37487
- __publicField(this, "unicodeFontStates", /* @__PURE__ */ new Map());
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(pageIndex, options) {
37528
- const page = this.pages[pageIndex];
37529
- if (!page || options.width <= 0 || options.height <= 0) {
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(pageIndex, options) {
37560
- const page = this.pages[pageIndex];
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(pageIndex, options) {
37585
- const page = this.pages[pageIndex];
37586
- if (!page || options.segments.length === 0) {
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(pageIndex) {
37636
- const page = this.pages[pageIndex];
37637
- if (page) {
37638
- page.commands.push("q");
37639
- }
37487
+ saveGraphicsState() {
37488
+ this.page.commands.push("q");
37640
37489
  }
37641
- restoreGraphicsState(pageIndex) {
37642
- const page = this.pages[pageIndex];
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(pageIndex, centerX, centerY, degrees) {
37651
- const page = this.pages[pageIndex];
37652
- if (!page || !degrees) {
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(pageIndex, x, y, width, height) {
37668
- const page = this.pages[pageIndex];
37669
- if (!page || width <= 0 || height <= 0) {
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(pageIndex, options) {
37679
- const page = this.pages[pageIndex];
37680
- if (!page || options.text.length === 0) {
37524
+ drawText(options) {
37525
+ if (options.text.length === 0) {
37681
37526
  return;
37682
37527
  }
37683
- const fontResourceName = resolveFontName(options);
37684
- this.usedFontResourceNames.add(fontResourceName);
37685
- const unicodeFont = this.unicodeFontStates.get(fontResourceName);
37686
- if (unicodeFont) {
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
- `<${encodePdfHexString(options.text)}> Tj`,
37552
+ showCommand,
37700
37553
  "ET"
37701
37554
  ].join("\n")
37702
37555
  );
37703
37556
  }
37704
- registerImageResource(resource) {
37705
- const resourceName = resource.resourceName ?? `Im${this.imageResources.size + 1}`;
37706
- if (!this.imageResources.has(resourceName)) {
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
- layoutUnicodeText(state, text) {
37771
- const cached = state.layoutCache.get(text);
37772
- if (cached) {
37773
- return cached;
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
- const run = state.font.layouter.layout(text);
37776
- state.layoutCache.set(text, run);
37777
- return run;
37631
+ return { glyphs, positions, advanceWidth };
37778
37632
  }
37779
- encodeUnicodeGlyphRun(state, run) {
37780
- return run.glyphs.map((glyph, index) => {
37781
- if (!state.usedGlyphs.has(glyph.id)) {
37782
- state.usedGlyphs.set(glyph.id, glyph);
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
- drawUnicodeText(page, state, options) {
37791
- const run = this.layoutUnicodeText(state, options.text);
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
- const textCommand = usesAdjustments ? `[${encoded.map((glyph) => {
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
- toArrayBuffer() {
37818
- const bytes = this.toUint8Array();
37819
- return Uint8Array.from(bytes).buffer;
37820
- }
37821
- toBlob() {
37822
- return new Blob([this.toArrayBuffer()], { type: "application/pdf" });
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 fontResourceXml = fontResourceEntries.map((font, index) => `/${font.resourceName} ${fontObjectIds[index]} 0 R`).join(" ");
37849
- const imageObjectIds = /* @__PURE__ */ new Map();
37850
- for (const image of this.imageResources.values()) {
37851
- imageObjectIds.set(
37852
- image.resourceName,
37853
- this.addImageObject(image, addObject)
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
- body += [
37908
- "trailer",
37909
- `<< /Size ${objects.length + 1} /Root ${catalogObjectId} 0 R >>`,
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
- addImageObject(resource, addObject) {
37918
- return addObject(
37919
- asciiHexImageStreamObjectBody(resource.data, [
37920
- "/Type /XObject",
37921
- "/Subtype /Image",
37922
- `/Width ${resource.width}`,
37923
- `/Height ${resource.height}`,
37924
- "/ColorSpace /DeviceRGB",
37925
- "/BitsPerComponent 8"
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);