1515 * This module provides type-safe creation and serialization of operators.
1616 */
1717
18- import { concatBytes } from "#src/helpers/buffer" ;
1918import { formatPdfNumber } from "#src/helpers/format" ;
2019import { ByteWriter } from "#src/io/byte-writer" ;
2120import type { PdfArray } from "#src/objects/pdf-array" ;
@@ -26,7 +25,6 @@ import type { PdfString } from "#src/objects/pdf-string";
2625/** Valid operand types */
2726export type Operand = number | string | PdfName | PdfString | PdfArray | PdfDict ;
2827
29- const encoder = new TextEncoder ( ) ;
3028const SPACE = 0x20 ;
3129
3230/** All PDF content stream operator names */
@@ -145,24 +143,27 @@ export class Operator {
145143 }
146144
147145 /**
148- * Serialize to bytes for content stream output .
149- * Format: "operand1 operand2 ... operator"
146+ * Write operator bytes directly into a shared ByteWriter .
147+ * Avoids intermediate allocations compared to toBytes().
150148 */
151- toBytes ( ) : Uint8Array {
152- if ( this . operands . length === 0 ) {
153- return encoder . encode ( this . op ) ;
154- }
155-
156- const parts : Uint8Array [ ] = [ ] ;
157-
149+ writeTo ( writer : ByteWriter ) : void {
158150 for ( const operand of this . operands ) {
159- parts . push ( serializeOperand ( operand ) ) ;
160- parts . push ( new Uint8Array ( [ SPACE ] ) ) ;
151+ writeOperand ( writer , operand ) ;
152+ writer . writeByte ( SPACE ) ;
161153 }
162154
163- parts . push ( encoder . encode ( this . op ) ) ;
155+ writer . writeAscii ( this . op ) ;
156+ }
157+
158+ /**
159+ * Serialize to bytes for content stream output.
160+ * Format: "operand1 operand2 ... operator"
161+ */
162+ toBytes ( ) : Uint8Array {
163+ const writer = new ByteWriter ( undefined , { initialSize : 64 } ) ;
164+ this . writeTo ( writer ) ;
164165
165- return concatBytes ( parts ) ;
166+ return writer . toBytes ( ) ;
166167 }
167168
168169 /**
@@ -174,29 +175,28 @@ export class Operator {
174175 }
175176
176177 /**
177- * Get byte length when serialized (for pre-allocation).
178+ * Get byte length when serialized.
179+ *
180+ * Should be avoided in performance-critical paths, use {@link writeTo} instead.
178181 */
179182 byteLength ( ) : number {
180183 return this . toBytes ( ) . length ;
181184 }
182185}
183186
184- /**
185- * Serialize an operand to bytes.
186- */
187- function serializeOperand ( operand : Operand ) : Uint8Array {
187+ /** Write an operand directly into a ByteWriter. */
188+ function writeOperand ( writer : ByteWriter , operand : Operand ) : void {
188189 if ( typeof operand === "number" ) {
189- return encoder . encode ( formatPdfNumber ( operand ) ) ;
190+ writer . writeAscii ( formatPdfNumber ( operand ) ) ;
191+ return ;
190192 }
191193
192194 if ( typeof operand === "string" ) {
193195 // Assume already formatted (e.g., "/FontName")
194- return encoder . encode ( operand ) ;
196+ writer . writeAscii ( operand ) ;
197+ return ;
195198 }
196199
197- // PdfName, PdfString, PdfArray, PdfDict all have toBytes()
198- const writer = new ByteWriter ( ) ;
200+ // PdfName, PdfString, PdfArray, PdfDict all have toBytes(writer)
199201 operand . toBytes ( writer ) ;
200-
201- return writer . toBytes ( ) ;
202202}
0 commit comments