@libpdf/core 0.2.8 → 0.2.9

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/index.d.mts CHANGED
@@ -1633,6 +1633,11 @@ declare class Operator {
1633
1633
  * Create an operator with operands.
1634
1634
  */
1635
1635
  static of(op: Op, ...operands: Operand[]): Operator;
1636
+ /**
1637
+ * Write operator bytes directly into a shared ByteWriter.
1638
+ * Avoids intermediate allocations compared to toBytes().
1639
+ */
1640
+ writeTo(writer: ByteWriter): void;
1636
1641
  /**
1637
1642
  * Serialize to bytes for content stream output.
1638
1643
  * Format: "operand1 operand2 ... operator"
@@ -1644,7 +1649,9 @@ declare class Operator {
1644
1649
  */
1645
1650
  toString(): string;
1646
1651
  /**
1647
- * Get byte length when serialized (for pre-allocation).
1652
+ * Get byte length when serialized.
1653
+ *
1654
+ * Should be avoided in performance-critical paths, use {@link writeTo} instead.
1648
1655
  */
1649
1656
  byteLength(): number;
1650
1657
  }
package/dist/index.mjs CHANGED
@@ -11,7 +11,7 @@ import { createCMSECDSASignature } from "pkijs";
11
11
  import { base64 } from "@scure/base";
12
12
 
13
13
  //#region package.json
14
- var version = "0.2.8";
14
+ var version = "0.2.9";
15
15
 
16
16
  //#endregion
17
17
  //#region src/objects/pdf-array.ts
@@ -2083,7 +2083,6 @@ var PdfStream = class PdfStream extends PdfDict {
2083
2083
  *
2084
2084
  * This module provides type-safe creation and serialization of operators.
2085
2085
  */
2086
- const encoder$1 = new TextEncoder();
2087
2086
  const SPACE$1 = 32;
2088
2087
  /** All PDF content stream operator names */
2089
2088
  const Op = {
@@ -2173,18 +2172,24 @@ var Operator = class Operator {
2173
2172
  return new Operator(op, Object.freeze([...operands]));
2174
2173
  }
2175
2174
  /**
2175
+ * Write operator bytes directly into a shared ByteWriter.
2176
+ * Avoids intermediate allocations compared to toBytes().
2177
+ */
2178
+ writeTo(writer) {
2179
+ for (const operand of this.operands) {
2180
+ writeOperand(writer, operand);
2181
+ writer.writeByte(SPACE$1);
2182
+ }
2183
+ writer.writeAscii(this.op);
2184
+ }
2185
+ /**
2176
2186
  * Serialize to bytes for content stream output.
2177
2187
  * Format: "operand1 operand2 ... operator"
2178
2188
  */
2179
2189
  toBytes() {
2180
- if (this.operands.length === 0) return encoder$1.encode(this.op);
2181
- const parts = [];
2182
- for (const operand of this.operands) {
2183
- parts.push(serializeOperand(operand));
2184
- parts.push(new Uint8Array([SPACE$1]));
2185
- }
2186
- parts.push(encoder$1.encode(this.op));
2187
- return concatBytes(parts);
2190
+ const writer = new ByteWriter(void 0, { initialSize: 64 });
2191
+ this.writeTo(writer);
2192
+ return writer.toBytes();
2188
2193
  }
2189
2194
  /**
2190
2195
  * Serialize to PDF content stream syntax string.
@@ -2194,21 +2199,25 @@ var Operator = class Operator {
2194
2199
  return new TextDecoder().decode(this.toBytes());
2195
2200
  }
2196
2201
  /**
2197
- * Get byte length when serialized (for pre-allocation).
2202
+ * Get byte length when serialized.
2203
+ *
2204
+ * Should be avoided in performance-critical paths, use {@link writeTo} instead.
2198
2205
  */
2199
2206
  byteLength() {
2200
2207
  return this.toBytes().length;
2201
2208
  }
2202
2209
  };
2203
- /**
2204
- * Serialize an operand to bytes.
2205
- */
2206
- function serializeOperand(operand) {
2207
- if (typeof operand === "number") return encoder$1.encode(formatPdfNumber(operand));
2208
- if (typeof operand === "string") return encoder$1.encode(operand);
2209
- const writer = new ByteWriter();
2210
+ /** Write an operand directly into a ByteWriter. */
2211
+ function writeOperand(writer, operand) {
2212
+ if (typeof operand === "number") {
2213
+ writer.writeAscii(formatPdfNumber(operand));
2214
+ return;
2215
+ }
2216
+ if (typeof operand === "string") {
2217
+ writer.writeAscii(operand);
2218
+ return;
2219
+ }
2210
2220
  operand.toBytes(writer);
2211
- return writer.toBytes();
2212
2221
  }
2213
2222
 
2214
2223
  //#endregion
@@ -2230,7 +2239,7 @@ function isInlineImageOperation(op) {
2230
2239
  */
2231
2240
  const encoder = new TextEncoder();
2232
2241
  const SPACE = new Uint8Array([32]);
2233
- const NEWLINE = new Uint8Array([10]);
2242
+ const NEWLINE$1 = new Uint8Array([10]);
2234
2243
  /**
2235
2244
  * Serializes content stream operations to bytes.
2236
2245
  */
@@ -2244,7 +2253,7 @@ var ContentStreamSerializer = class ContentStreamSerializer {
2244
2253
  const parts = [];
2245
2254
  for (const op of operations) {
2246
2255
  parts.push(ContentStreamSerializer.serializeOperation(op));
2247
- parts.push(NEWLINE);
2256
+ parts.push(NEWLINE$1);
2248
2257
  }
2249
2258
  return concatBytes(parts);
2250
2259
  }
@@ -2268,15 +2277,15 @@ var ContentStreamSerializer = class ContentStreamSerializer {
2268
2277
  static serializeInlineImage(op) {
2269
2278
  const parts = [];
2270
2279
  parts.push(encoder.encode("BI"));
2271
- parts.push(NEWLINE);
2280
+ parts.push(NEWLINE$1);
2272
2281
  for (const [key$1, value] of op.params) {
2273
2282
  parts.push(encoder.encode(`/${key$1} `));
2274
2283
  parts.push(ContentStreamSerializer.serializeToken(value));
2275
- parts.push(NEWLINE);
2284
+ parts.push(NEWLINE$1);
2276
2285
  }
2277
2286
  parts.push(encoder.encode("ID "));
2278
2287
  parts.push(op.data);
2279
- parts.push(NEWLINE);
2288
+ parts.push(NEWLINE$1);
2280
2289
  parts.push(encoder.encode("EI"));
2281
2290
  return concatBytes(parts);
2282
2291
  }
@@ -22699,21 +22708,21 @@ function executeSvgPathString(options) {
22699
22708
 
22700
22709
  //#endregion
22701
22710
  //#region src/drawing/serialize.ts
22711
+ const NEWLINE = 10;
22702
22712
  /**
22703
22713
  * Serialize operators to bytes for content streams.
22704
22714
  *
22705
- * Uses Operator.toBytes() directly to avoid UTF-8 round-trip corruption
22706
- * of non-ASCII bytes in PdfString operands (e.g., WinAnsi-encoded text).
22715
+ * Uses Operator.writeTo() to write directly into a shared ByteWriter,
22716
+ * avoiding per-operator intermediate allocations.
22707
22717
  */
22708
22718
  function serializeOperators(ops) {
22709
22719
  if (ops.length === 0) return new Uint8Array(0);
22710
- const newline = new Uint8Array([10]);
22711
- const parts = [];
22720
+ const writer = new ByteWriter(void 0, { initialSize: ops.length * 24 });
22712
22721
  for (let i = 0; i < ops.length; i++) {
22713
- if (i > 0) parts.push(newline);
22714
- parts.push(ops[i].toBytes());
22722
+ if (i > 0) writer.writeByte(NEWLINE);
22723
+ ops[i].writeTo(writer);
22715
22724
  }
22716
- return concatBytes(parts);
22725
+ return writer.toBytes();
22717
22726
  }
22718
22727
 
22719
22728
  //#endregion
@@ -27898,7 +27907,7 @@ var PDFPage = class PDFPage {
27898
27907
  */
27899
27908
  addXObjectResource(ref) {
27900
27909
  const resources = this.getResources();
27901
- let xobjects = resources.get("XObject");
27910
+ let xobjects = resources.get("XObject", this.ctx.resolve.bind(this.ctx));
27902
27911
  if (!(xobjects instanceof PdfDict)) {
27903
27912
  xobjects = new PdfDict();
27904
27913
  resources.set("XObject", xobjects);
@@ -27933,7 +27942,7 @@ var PDFPage = class PDFPage {
27933
27942
  const cachedName = this._resourceCache.get(ref);
27934
27943
  if (cachedName) return cachedName;
27935
27944
  const resources = this.getResources();
27936
- let subdict = resources.get(resourceType);
27945
+ let subdict = resources.get(resourceType, this.ctx.resolve.bind(this.ctx));
27937
27946
  if (!(subdict instanceof PdfDict)) {
27938
27947
  subdict = new PdfDict();
27939
27948
  resources.set(resourceType, subdict);
@@ -39426,8 +39435,8 @@ function findBytesReverse(buffer, pattern) {
39426
39435
  * @throws {Error} if placeholders cannot be found
39427
39436
  */
39428
39437
  function findPlaceholders(buffer) {
39429
- const encoder$2 = new TextEncoder();
39430
- const byteRangeKey = encoder$2.encode("/ByteRange");
39438
+ const encoder$1 = new TextEncoder();
39439
+ const byteRangeKey = encoder$1.encode("/ByteRange");
39431
39440
  const byteRangeKeyPos = findBytesReverse(buffer, byteRangeKey);
39432
39441
  if (byteRangeKeyPos === -1) throw new Error("ByteRange placeholder not found in PDF");
39433
39442
  let byteRangeStart = byteRangeKeyPos + byteRangeKey.length;
@@ -39437,7 +39446,7 @@ function findPlaceholders(buffer) {
39437
39446
  while (byteRangeEnd < buffer.length && buffer[byteRangeEnd] !== 93) byteRangeEnd++;
39438
39447
  if (byteRangeEnd >= buffer.length) throw new Error("ByteRange ']' not found in PDF");
39439
39448
  const byteRangeLength = byteRangeEnd - byteRangeStart + 1;
39440
- const contentsKey = encoder$2.encode("/Contents");
39449
+ const contentsKey = encoder$1.encode("/Contents");
39441
39450
  const contentsKeyPos = findBytes(buffer, contentsKey, byteRangeKeyPos);
39442
39451
  if (contentsKeyPos === -1) throw new Error("Contents placeholder not found in PDF");
39443
39452
  let contentsStart = contentsKeyPos + contentsKey.length;