@pdfme/pdf-lib 6.1.13-dev.22 → 6.1.13-dev.24

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.
@@ -18,6 +18,7 @@ declare class CustomFontEmbedder {
18
18
  readonly fontFeatures: TypeFeatures | undefined;
19
19
  protected baseFontName: string;
20
20
  protected glyphCache: Cache<Glyph[]>;
21
+ private readonly shapedGlyphsById;
21
22
  protected constructor(font: Font, fontData: Uint8Array, customName?: string, fontFeatures?: TypeFeatures);
22
23
  /**
23
24
  * Encode the JavaScript string into this font. (JavaScript encodes strings in
@@ -25,6 +26,19 @@ declare class CustomFontEmbedder {
25
26
  */
26
27
  encodeText(text: string): PDFHexString;
27
28
  widthOfTextAtSize(text: string, size: number): number;
29
+ /**
30
+ * Layout `text` as one or more fontkit runs. Thai/Lao spans are shaped
31
+ * separately so GSUB mark variants are selected even when Latin/CJK leads.
32
+ * A script tag is never passed — each run has one strong script, so fontkit
33
+ * auto-detection matches the script we would have specified.
34
+ */
35
+ protected layoutGlyphs(text: string): Glyph[];
36
+ /**
37
+ * GSUB can emit glyphs that are not in `font.characterSet` (e.g. Sarabun
38
+ * tone gid 736). Retain those objects so `computeWidths()` and
39
+ * `embedUnicodeCmap()` include them when the full font is embedded.
40
+ */
41
+ protected registerShapedGlyphs(glyphs: Glyph[]): void;
28
42
  heightOfFontAtSize(size: number, options?: {
29
43
  descender?: boolean;
30
44
  }): number;
@@ -12,6 +12,7 @@ declare class CustomFontSubsetEmbedder extends CustomFontEmbedder {
12
12
  private readonly glyphs;
13
13
  private readonly glyphIdMap;
14
14
  private constructor();
15
+ protected registerShapedGlyphs(_glyphs: Glyph[]): void;
15
16
  encodeText(text: string): PDFHexString;
16
17
  protected isCFF(): boolean;
17
18
  protected glyphId(glyph?: Glyph): number;
package/dist/index.js CHANGED
@@ -815,6 +815,45 @@ var pdfDocEncodingDecode = (bytes) => {
815
815
  return String.fromCodePoint(...codePoints);
816
816
  };
817
817
  //#endregion
818
+ //#region src/utils/scriptRuns.ts
819
+ var MARK_CRITICAL_SCRIPTS = [{
820
+ name: "thai",
821
+ test: /\p{Script=Thai}/u
822
+ }, {
823
+ name: "lao",
824
+ test: /\p{Script=Lao}/u
825
+ }];
826
+ var MARK_CRITICAL_ANY = /[\p{Script=Thai}\p{Script=Lao}]/u;
827
+ var NEUTRAL = /[\p{Script=Common}\p{Script=Inherited}]/u;
828
+ var classifyCodePoint = (ch) => {
829
+ if (NEUTRAL.test(ch)) return null;
830
+ for (const { name, test } of MARK_CRITICAL_SCRIPTS) if (test.test(ch)) return name;
831
+ return "default";
832
+ };
833
+ /**
834
+ * Split `text` into shaping runs at Thai/Lao script boundaries.
835
+ * Concatenating the result always reproduces the input.
836
+ */
837
+ var splitTextIntoShapingRuns = (text) => {
838
+ if (text.length === 0) return [];
839
+ if (!MARK_CRITICAL_ANY.test(text)) return [text];
840
+ const runs = [];
841
+ let current = "";
842
+ let currentClass = null;
843
+ for (const ch of text) {
844
+ const cls = classifyCodePoint(ch);
845
+ if (!(cls === null || currentClass === null || currentClass === cls) && current.length > 0) {
846
+ runs.push(current);
847
+ current = "";
848
+ currentClass = null;
849
+ }
850
+ current += ch;
851
+ if (cls !== null) currentClass = cls;
852
+ }
853
+ if (current.length > 0) runs.push(current);
854
+ return runs;
855
+ };
856
+ //#endregion
818
857
  //#region \0@oxc-project+runtime@0.147.0/helpers/esm/typeof.js
819
858
  function _typeof(o) {
820
859
  "@babel/helpers - typeof";
@@ -3314,12 +3353,15 @@ var CustomFontEmbedder = class CustomFontEmbedder {
3314
3353
  _defineProperty(this, "fontFeatures", void 0);
3315
3354
  _defineProperty(this, "baseFontName", void 0);
3316
3355
  _defineProperty(this, "glyphCache", void 0);
3356
+ _defineProperty(this, "shapedGlyphsById", void 0);
3317
3357
  _defineProperty(this, "allGlyphsInFontSortedById", () => {
3318
- const glyphs = Array(this.font.characterSet.length);
3319
- for (let idx = 0, len = glyphs.length; idx < len; idx++) {
3358
+ const glyphs = Array(this.font.characterSet.length + this.shapedGlyphsById.size);
3359
+ for (let idx = 0, len = this.font.characterSet.length; idx < len; idx++) {
3320
3360
  const codePoint = this.font.characterSet[idx];
3321
3361
  glyphs[idx] = this.font.glyphForCodePoint(codePoint);
3322
3362
  }
3363
+ let extraIdx = this.font.characterSet.length;
3364
+ for (const glyph of this.shapedGlyphsById.values()) glyphs[extraIdx++] = glyph;
3323
3365
  return sortedUniq(glyphs.sort(byAscendingId), (g) => g.id);
3324
3366
  });
3325
3367
  this.font = font;
@@ -3329,6 +3371,7 @@ var CustomFontEmbedder = class CustomFontEmbedder {
3329
3371
  this.customName = customName;
3330
3372
  this.fontFeatures = fontFeatures;
3331
3373
  this.baseFontName = "";
3374
+ this.shapedGlyphsById = /* @__PURE__ */ new Map();
3332
3375
  this.glyphCache = Cache.populatedBy(this.allGlyphsInFontSortedById);
3333
3376
  }
3334
3377
  /**
@@ -3336,18 +3379,54 @@ var CustomFontEmbedder = class CustomFontEmbedder {
3336
3379
  * Unicode, but embedded fonts use their own custom encodings)
3337
3380
  */
3338
3381
  encodeText(text) {
3339
- const { glyphs } = this.font.layout(text, this.fontFeatures);
3382
+ const glyphs = this.layoutGlyphs(text);
3340
3383
  const hexCodes = Array(glyphs.length);
3341
3384
  for (let idx = 0, len = glyphs.length; idx < len; idx++) hexCodes[idx] = toHexStringOfMinLength(glyphs[idx].id, 4);
3342
3385
  return PDFHexString.of(hexCodes.join(""));
3343
3386
  }
3344
3387
  widthOfTextAtSize(text, size) {
3345
- const { glyphs } = this.font.layout(text, this.fontFeatures);
3388
+ const glyphs = this.layoutGlyphs(text);
3346
3389
  let totalWidth = 0;
3347
3390
  for (let idx = 0, len = glyphs.length; idx < len; idx++) totalWidth += glyphs[idx].advanceWidth * this.scale;
3348
3391
  const scale = size / 1e3;
3349
3392
  return totalWidth * scale;
3350
3393
  }
3394
+ /**
3395
+ * Layout `text` as one or more fontkit runs. Thai/Lao spans are shaped
3396
+ * separately so GSUB mark variants are selected even when Latin/CJK leads.
3397
+ * A script tag is never passed — each run has one strong script, so fontkit
3398
+ * auto-detection matches the script we would have specified.
3399
+ */
3400
+ layoutGlyphs(text) {
3401
+ const runs = splitTextIntoShapingRuns(text);
3402
+ let glyphs;
3403
+ if (runs.length <= 1) glyphs = this.font.layout(runs[0] ?? "", this.fontFeatures).glyphs;
3404
+ else {
3405
+ glyphs = [];
3406
+ for (const run of runs) {
3407
+ const runGlyphs = this.font.layout(run, this.fontFeatures).glyphs;
3408
+ for (let idx = 0, len = runGlyphs.length; idx < len; idx++) glyphs.push(runGlyphs[idx]);
3409
+ }
3410
+ }
3411
+ this.registerShapedGlyphs(glyphs);
3412
+ return glyphs;
3413
+ }
3414
+ /**
3415
+ * GSUB can emit glyphs that are not in `font.characterSet` (e.g. Sarabun
3416
+ * tone gid 736). Retain those objects so `computeWidths()` and
3417
+ * `embedUnicodeCmap()` include them when the full font is embedded.
3418
+ */
3419
+ registerShapedGlyphs(glyphs) {
3420
+ let added = false;
3421
+ for (let idx = 0, len = glyphs.length; idx < len; idx++) {
3422
+ const glyph = glyphs[idx];
3423
+ if (!this.shapedGlyphsById.has(glyph.id)) {
3424
+ this.shapedGlyphsById.set(glyph.id, glyph);
3425
+ added = true;
3426
+ }
3427
+ }
3428
+ if (added) this.glyphCache.invalidate();
3429
+ }
3351
3430
  heightOfFontAtSize(size, options = {}) {
3352
3431
  const { descender = true } = options;
3353
3432
  const { ascent, descent, bbox } = this.font;
@@ -3484,8 +3563,9 @@ var CustomFontSubsetEmbedder = class CustomFontSubsetEmbedder extends CustomFont
3484
3563
  this.glyphCache = Cache.populatedBy(() => this.glyphs);
3485
3564
  this.glyphIdMap = /* @__PURE__ */ new Map();
3486
3565
  }
3566
+ registerShapedGlyphs(_glyphs) {}
3487
3567
  encodeText(text) {
3488
- const { glyphs } = this.font.layout(text, this.fontFeatures);
3568
+ const glyphs = this.layoutGlyphs(text);
3489
3569
  const hexCodes = Array(glyphs.length);
3490
3570
  for (let idx = 0, len = glyphs.length; idx < len; idx++) {
3491
3571
  const glyph = glyphs[idx];
@@ -19117,6 +19197,6 @@ var PDFButton = class extends PDFField {
19117
19197
  _PDFButton = PDFButton;
19118
19198
  _defineProperty(PDFButton, "of", (acroPushButton, ref, doc) => new _PDFButton(acroPushButton, ref, doc));
19119
19199
  //#endregion
19120
- export { AFRelationship, AcroButtonFlags, AcroChoiceFlags, AcroFieldFlags, AcroTextFlags, AnnotationFlags, AppearanceCharacteristics, BlendMode, Cache, CharCodes, ColorTypes, CombedTextLayoutError, CorruptPageTreeError, CustomFontEmbedder, CustomFontSubsetEmbedder, DecompressionBombError, Duplex, EncryptedPDFError, ExceededMaxLengthError, FieldAlreadyExistsError, FieldExistsAsNonTerminalError, FileEmbedder, FillRule, FontkitNotRegisteredError, ForeignPageError, ImageAlignment, IndexOutOfBoundsError, InvalidAcroFieldValueError, InvalidFieldNamePartError, InvalidMaxLengthError, InvalidPDFDateStringError, InvalidTargetIndexError, JpegEmbedder, LineCapStyle, LineJoinStyle, MethodNotImplementedError, MissingCatalogError, MissingDAEntryError, MissingKeywordError, MissingOnValueCheckError, MissingPDFHeaderError, MissingPageContentsEmbeddingError, MissingTfOperatorError, MultiSelectValueError, NextByteAssertionError, NoSuchFieldError, NonFullScreenPageMode, NumberParsingError, PDFAcroButton, PDFAcroCheckBox, PDFAcroChoice, PDFAcroComboBox, PDFAcroField, PDFAcroForm, PDFAcroListBox, PDFAcroNonTerminal, PDFAcroPushButton, PDFAcroRadioButton, PDFAcroSignature, PDFAcroTerminal, PDFAcroText, PDFAnnotation, PDFArray, PDFArrayIsNotRectangleError, PDFBool, PDFButton, PDFCatalog, PDFCheckBox, PDFContentStream, PDFContext, PDFCrossRefSection, PDFCrossRefStream, PDFDict, PDFDocument, PDFDropdown, PDFEmbeddedPage, PDFField, PDFFlateStream, PDFFont, PDFForm, PDFHeader, PDFHexString, PDFImage, PDFInvalidObject, PDFInvalidObjectParsingError, PDFJavaScript, PDFName, PDFNull_default as PDFNull, PDFNumber, PDFObject, PDFObjectCopier, PDFObjectParser, PDFObjectParsingError, PDFObjectStream, PDFObjectStreamParser, PDFOperator, PDFOperatorNames, PDFOptionList, PDFPage, PDFPageEmbedder, PDFPageLeaf, PDFPageTree, PDFParser, PDFParsingError, PDFRadioGroup, PDFRawStream, PDFRef, PDFSignature, PDFStream, PDFStreamParsingError, PDFStreamWriter, PDFString, PDFTextField, PDFTrailer, PDFTrailerDict, PDFWidgetAnnotation, PDFWriter, PDFXRefStreamParser, PageEmbeddingMismatchedContextError, PageSizes, ParseSpeeds, PngEmbedder, PrintScaling, PrivateConstructorError, ReadingDirection, RemovePageFromEmptyDocumentError, ReparseError, RichTextFieldReadError, RotationTypes, StalledParserError, StandardFontEmbedder, StandardFontValues, StandardFonts, TextAlignment, TextRenderingMode, UnbalancedParenthesisError, UnexpectedFieldTypeError, UnexpectedObjectTypeError, UnrecognizedStreamTypeError, UnsupportedEncodingError, ViewerPreferences, addRandomSuffix, adjustDimsForRotation, appendBezierCurve, appendQuadraticCurve, arrayAsString, asNumber, asPDFName, asPDFNumber, assertEachIs, assertInteger, assertIs, assertIsOneOf, assertIsOneOfOrUndefined, assertIsSubset, assertMultiple, assertOrUndefined, assertPositive, assertRange, assertRangeOrUndefined, backtick, beginMarkedContent, beginText, breakTextIntoLines, byAscendingId, bytesFor, canBeConvertedToUint8Array, charAtIndex, charFromCode, charFromHexCode, charSplit, cleanText, clip, clipEvenOdd, closePath, cmyk, colorString, colorToComponents, componentsToColor, concatTransformationMatrix, copyStringIntoBuffer, createPDFAcroField, createPDFAcroFields, createTypeErrorMsg, createValueErrorMsg, decodeFromBase64, decodeFromBase64DataUri, decodePDFRawStream, defaultButtonAppearanceProvider, defaultCheckBoxAppearanceProvider, defaultDropdownAppearanceProvider, defaultOptionListAppearanceProvider, defaultRadioGroupAppearanceProvider, defaultTextFieldAppearanceProvider, degrees, degreesToRadians, drawButton, drawCheckBox, drawCheckMark, drawEllipse, drawEllipsePath, drawImage, drawLine, drawLinesOfText, drawObject, drawOptionList, drawPage, drawRadioButton, drawRectangle, drawSvgPath, drawText, drawTextField, drawTextLines, encodeToBase64, endMarkedContent, endPath, endText, error, escapeRegExp, escapedNewlineChars, fill, fillAndStroke, fillEvenOdd, findLastMatch, getType, grayscale, hasSurrogates, hasUtf16BOM, highSurrogate, isArrayEqual, isNewlineChar, isStandardFont, isType, isWithinBMP, last, layoutCombedText, layoutMultilineText, layoutSinglelineText, lineSplit, lineTo, lowSurrogate, mergeIntoTypedArray, mergeLines, mergeUint8Arrays, moveText, moveTo, newlineChars, nextLine, normalizeAppearance, numberToString, padStart, parseDate, pdfDocEncodingDecode, pluckIndices, popGraphicsState, pushGraphicsState, radians, radiansToDegrees, range, rectangle, rectanglesAreEqual, reduceRotation, restoreDashPattern, reverseArray, rgb, rotateAndSkewTextDegreesAndTranslate, rotateAndSkewTextRadiansAndTranslate, rotateDegrees, rotateInPlace, rotateRadians, rotateRectangle, scale, setCharacterSpacing, setCharacterSqueeze, setDashPattern, setFillingCmykColor, setFillingColor, setFillingGrayscaleColor, setFillingRgbColor, setFontAndSize, setGraphicsState, setLineCap, setLineHeight, setLineJoin, setLineWidth, setStrokingCmykColor, setStrokingColor, setStrokingGrayscaleColor, setStrokingRgbColor, setTextMatrix, setTextRenderingMode, setTextRise, setWordSpacing, showText, singleQuote, sizeInBytes, skewDegrees, skewRadians, sortedUniq, square, stringAsByteArray, stroke, sum, toCharCode, toCodePoint, toDegrees, toHexString, toHexStringOfMinLength, toRadians, toUint8Array, translate, typedArrayFor, utf16Decode, utf16Encode, utf8Encode, values, waitForTick };
19200
+ export { AFRelationship, AcroButtonFlags, AcroChoiceFlags, AcroFieldFlags, AcroTextFlags, AnnotationFlags, AppearanceCharacteristics, BlendMode, Cache, CharCodes, ColorTypes, CombedTextLayoutError, CorruptPageTreeError, CustomFontEmbedder, CustomFontSubsetEmbedder, DecompressionBombError, Duplex, EncryptedPDFError, ExceededMaxLengthError, FieldAlreadyExistsError, FieldExistsAsNonTerminalError, FileEmbedder, FillRule, FontkitNotRegisteredError, ForeignPageError, ImageAlignment, IndexOutOfBoundsError, InvalidAcroFieldValueError, InvalidFieldNamePartError, InvalidMaxLengthError, InvalidPDFDateStringError, InvalidTargetIndexError, JpegEmbedder, LineCapStyle, LineJoinStyle, MethodNotImplementedError, MissingCatalogError, MissingDAEntryError, MissingKeywordError, MissingOnValueCheckError, MissingPDFHeaderError, MissingPageContentsEmbeddingError, MissingTfOperatorError, MultiSelectValueError, NextByteAssertionError, NoSuchFieldError, NonFullScreenPageMode, NumberParsingError, PDFAcroButton, PDFAcroCheckBox, PDFAcroChoice, PDFAcroComboBox, PDFAcroField, PDFAcroForm, PDFAcroListBox, PDFAcroNonTerminal, PDFAcroPushButton, PDFAcroRadioButton, PDFAcroSignature, PDFAcroTerminal, PDFAcroText, PDFAnnotation, PDFArray, PDFArrayIsNotRectangleError, PDFBool, PDFButton, PDFCatalog, PDFCheckBox, PDFContentStream, PDFContext, PDFCrossRefSection, PDFCrossRefStream, PDFDict, PDFDocument, PDFDropdown, PDFEmbeddedPage, PDFField, PDFFlateStream, PDFFont, PDFForm, PDFHeader, PDFHexString, PDFImage, PDFInvalidObject, PDFInvalidObjectParsingError, PDFJavaScript, PDFName, PDFNull_default as PDFNull, PDFNumber, PDFObject, PDFObjectCopier, PDFObjectParser, PDFObjectParsingError, PDFObjectStream, PDFObjectStreamParser, PDFOperator, PDFOperatorNames, PDFOptionList, PDFPage, PDFPageEmbedder, PDFPageLeaf, PDFPageTree, PDFParser, PDFParsingError, PDFRadioGroup, PDFRawStream, PDFRef, PDFSignature, PDFStream, PDFStreamParsingError, PDFStreamWriter, PDFString, PDFTextField, PDFTrailer, PDFTrailerDict, PDFWidgetAnnotation, PDFWriter, PDFXRefStreamParser, PageEmbeddingMismatchedContextError, PageSizes, ParseSpeeds, PngEmbedder, PrintScaling, PrivateConstructorError, ReadingDirection, RemovePageFromEmptyDocumentError, ReparseError, RichTextFieldReadError, RotationTypes, StalledParserError, StandardFontEmbedder, StandardFontValues, StandardFonts, TextAlignment, TextRenderingMode, UnbalancedParenthesisError, UnexpectedFieldTypeError, UnexpectedObjectTypeError, UnrecognizedStreamTypeError, UnsupportedEncodingError, ViewerPreferences, addRandomSuffix, adjustDimsForRotation, appendBezierCurve, appendQuadraticCurve, arrayAsString, asNumber, asPDFName, asPDFNumber, assertEachIs, assertInteger, assertIs, assertIsOneOf, assertIsOneOfOrUndefined, assertIsSubset, assertMultiple, assertOrUndefined, assertPositive, assertRange, assertRangeOrUndefined, backtick, beginMarkedContent, beginText, breakTextIntoLines, byAscendingId, bytesFor, canBeConvertedToUint8Array, charAtIndex, charFromCode, charFromHexCode, charSplit, cleanText, clip, clipEvenOdd, closePath, cmyk, colorString, colorToComponents, componentsToColor, concatTransformationMatrix, copyStringIntoBuffer, createPDFAcroField, createPDFAcroFields, createTypeErrorMsg, createValueErrorMsg, decodeFromBase64, decodeFromBase64DataUri, decodePDFRawStream, defaultButtonAppearanceProvider, defaultCheckBoxAppearanceProvider, defaultDropdownAppearanceProvider, defaultOptionListAppearanceProvider, defaultRadioGroupAppearanceProvider, defaultTextFieldAppearanceProvider, degrees, degreesToRadians, drawButton, drawCheckBox, drawCheckMark, drawEllipse, drawEllipsePath, drawImage, drawLine, drawLinesOfText, drawObject, drawOptionList, drawPage, drawRadioButton, drawRectangle, drawSvgPath, drawText, drawTextField, drawTextLines, encodeToBase64, endMarkedContent, endPath, endText, error, escapeRegExp, escapedNewlineChars, fill, fillAndStroke, fillEvenOdd, findLastMatch, getType, grayscale, hasSurrogates, hasUtf16BOM, highSurrogate, isArrayEqual, isNewlineChar, isStandardFont, isType, isWithinBMP, last, layoutCombedText, layoutMultilineText, layoutSinglelineText, lineSplit, lineTo, lowSurrogate, mergeIntoTypedArray, mergeLines, mergeUint8Arrays, moveText, moveTo, newlineChars, nextLine, normalizeAppearance, numberToString, padStart, parseDate, pdfDocEncodingDecode, pluckIndices, popGraphicsState, pushGraphicsState, radians, radiansToDegrees, range, rectangle, rectanglesAreEqual, reduceRotation, restoreDashPattern, reverseArray, rgb, rotateAndSkewTextDegreesAndTranslate, rotateAndSkewTextRadiansAndTranslate, rotateDegrees, rotateInPlace, rotateRadians, rotateRectangle, scale, setCharacterSpacing, setCharacterSqueeze, setDashPattern, setFillingCmykColor, setFillingColor, setFillingGrayscaleColor, setFillingRgbColor, setFontAndSize, setGraphicsState, setLineCap, setLineHeight, setLineJoin, setLineWidth, setStrokingCmykColor, setStrokingColor, setStrokingGrayscaleColor, setStrokingRgbColor, setTextMatrix, setTextRenderingMode, setTextRise, setWordSpacing, showText, singleQuote, sizeInBytes, skewDegrees, skewRadians, sortedUniq, splitTextIntoShapingRuns, square, stringAsByteArray, stroke, sum, toCharCode, toCodePoint, toDegrees, toHexString, toHexStringOfMinLength, toRadians, toUint8Array, translate, typedArrayFor, utf16Decode, utf16Encode, utf8Encode, values, waitForTick };
19121
19201
 
19122
19202
  //# sourceMappingURL=index.js.map