deno.land / x / skia_canvas@0.5.8 / src / pdfdocument.ts
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153import { CanvasRenderingContext2D } from "./context2d.ts";import ffi, { cstr, getBuffer } from "./ffi.ts";
const { sk_pdf_begin_page, sk_pdf_destroy, sk_pdf_new, sk_pdf_get_buffer, sk_pdf_write_file, sk_pdf_end_page, sk_data_free,} = ffi;
const PDF_DOCUMENT_FINALIZER = new FinalizationRegistry( (ptr: Deno.PointerValue) => { sk_pdf_destroy(ptr); },);
const SK_DATA_FINALIZER = new FinalizationRegistry( (ptr: Deno.PointerValue) => { sk_data_free(ptr); },);
export interface PdfMetadata { title?: string; author?: string; subject?: string; keywords?: string; creator?: string; producer?: string; creation?: Date; modified?: Date; pdfa?: boolean; encodingQuality?: number;}
export interface Rect { x: number; y: number; w: number; h: number;}
const DATE_TIME_SIZE = 2 + 2 + 1 + 1 + 1 + 1 + 1 + 1;
const OUT_SIZE = new Uint32Array(1);const OUT_SIZE_PTR = new Uint8Array(OUT_SIZE.buffer);const OUT_DATA = new BigUint64Array(1);const OUT_DATA_PTR = new Uint8Array(OUT_DATA.buffer);
function dateToSkTime(date: Date) { const buffer = new Uint8Array(DATE_TIME_SIZE); const view = new DataView(buffer.buffer); view.setUint16(2, date.getUTCFullYear(), true); view.setUint8(4, date.getUTCMonth() + 1); view.setUint8(5, date.getUTCDay()); return buffer;}
export class PdfRenderingContext2D extends CanvasRenderingContext2D { // @ts-expect-error typescript error declare canvas!: PdfDocument;
constructor( canvas: PdfDocument, ptr: Deno.PointerValue, public width: number, public height: number, ) { // deno-lint-ignore no-explicit-any super(canvas as any, ptr); }}
const _ptr = Symbol("[[ptr]]");
/** * Create a new PDF document to draw using Canvas 2D API. */export class PdfDocument { [_ptr]: Deno.PointerValue;
constructor(options: PdfMetadata = {}) { this[_ptr] = sk_pdf_new( cstr(options.title ?? ""), cstr(options.author ?? ""), cstr(options.subject ?? ""), cstr(options.keywords ?? ""), cstr(options.creator ?? ""), cstr(options.producer ?? ""), options.creation ? dateToSkTime(options.creation) : new Uint8Array(DATE_TIME_SIZE), options.modified ? dateToSkTime(options.modified) : new Uint8Array(DATE_TIME_SIZE), options.pdfa ?? false, options.encodingQuality ?? 0, ); PDF_DOCUMENT_FINALIZER.register(this, this[_ptr]); }
/** * Creates a new page and returns a 2D rendering context for drawing on it. * The context extends CanvasRenderingContext2D so it has same API. * * You must not use the context after calling endPage. */ newPage(w: number, h: number, contentRect?: Rect): PdfRenderingContext2D { const ptr = sk_pdf_begin_page( this[_ptr], w, h, ...(contentRect ? [contentRect.x, contentRect.y, contentRect.w, contentRect.h] : [0, 0, w, h]) as [number, number, number, number], ); if (!ptr) { throw new Error("Failed to create new page"); } return new PdfRenderingContext2D(this, ptr, w, h); }
/** Writes the page into internal stream and destroys */ endPage() { sk_pdf_end_page(this[_ptr]); }
/** Saves PDF to the file and closes the stream. Changes cannot be made to PDF after this. */ save(path: string) { if (!sk_pdf_write_file(this[_ptr], cstr(path))) { throw new Error("Failed to save PDF"); } }
/** Encodes the PDF into a buffer and closes the stream. Changes cannot be made to PDF after this. */ encode(): Uint8Array { const skdata = sk_pdf_get_buffer(this[_ptr], OUT_DATA_PTR, OUT_SIZE_PTR); if (!skdata) { throw new Error("Failed to encode PDF"); } const size = OUT_SIZE[0]; const ptr = OUT_DATA[0]; const buffer = new Uint8Array( getBuffer(Deno.UnsafePointer.create(ptr), 0, size), ); SK_DATA_FINALIZER.register(buffer, skdata); return buffer; }}
Version Info