pdf-lib
Version:
Create and modify PDF files with JavaScript
102 lines (87 loc) • 3.1 kB
text/typescript
import PDFName from 'src/core/objects/PDFName';
import PDFNumber from 'src/core/objects/PDFNumber';
import PDFObject from 'src/core/objects/PDFObject';
import PDFRef from 'src/core/objects/PDFRef';
import PDFContext from 'src/core/PDFContext';
import PDFFlateStream from 'src/core/structures/PDFFlateStream';
import CharCodes from 'src/core/syntax/CharCodes';
import { copyStringIntoBuffer, last } from 'src/utils';
export type IndirectObject = [PDFRef, PDFObject];
class PDFObjectStream extends PDFFlateStream {
static withContextAndObjects = (
context: PDFContext,
objects: IndirectObject[],
encode = true,
) => new PDFObjectStream(context, objects, encode);
private readonly objects: IndirectObject[];
private readonly offsets: [number, number][];
private readonly offsetsString: string;
private constructor(
context: PDFContext,
objects: IndirectObject[],
encode = true,
) {
super(context.obj({}), encode);
this.objects = objects;
this.offsets = this.computeObjectOffsets();
this.offsetsString = this.computeOffsetsString();
this.dict.set(PDFName.of('Type'), PDFName.of('ObjStm'));
this.dict.set(PDFName.of('N'), PDFNumber.of(this.objects.length));
this.dict.set(PDFName.of('First'), PDFNumber.of(this.offsetsString.length));
}
getObjectsCount(): number {
return this.objects.length;
}
clone(context?: PDFContext): PDFObjectStream {
return PDFObjectStream.withContextAndObjects(
context || this.dict.context,
this.objects.slice(),
this.encode,
);
}
getContentsString(): string {
let value = this.offsetsString;
for (let idx = 0, len = this.objects.length; idx < len; idx++) {
const [, object] = this.objects[idx];
value += `${object}\n`;
}
return value;
}
getUnencodedContents(): Uint8Array {
const buffer = new Uint8Array(this.getUnencodedContentsSize());
let offset = copyStringIntoBuffer(this.offsetsString, buffer, 0);
for (let idx = 0, len = this.objects.length; idx < len; idx++) {
const [, object] = this.objects[idx];
offset += object.copyBytesInto(buffer, offset);
buffer[offset++] = CharCodes.Newline;
}
return buffer;
}
getUnencodedContentsSize(): number {
return (
this.offsetsString.length +
last(this.offsets)[1] +
last(this.objects)[1].sizeInBytes() +
1
);
}
private computeOffsetsString(): string {
let offsetsString = '';
for (let idx = 0, len = this.offsets.length; idx < len; idx++) {
const [objectNumber, offset] = this.offsets[idx];
offsetsString += `${objectNumber} ${offset} `;
}
return offsetsString;
}
private computeObjectOffsets(): [number, number][] {
let offset = 0;
const offsets = new Array(this.objects.length);
for (let idx = 0, len = this.objects.length; idx < len; idx++) {
const [ref, object] = this.objects[idx];
offsets[idx] = [ref.objectNumber, offset];
offset += object.sizeInBytes() + 1; // '\n'
}
return offsets;
}
}
export default PDFObjectStream;