diff --git a/README.md b/README.md index 7dd6491..4ac2026 100644 --- a/README.md +++ b/README.md @@ -51,7 +51,7 @@ async main() { }); // Save the PNG image to the output folder - await fs.writeFile(`output/${page.number}.png`, image.data); + await fs.writeFile(`output/${page.number}.png`, Buffer.from(image.data)); } // Do not forget to destroy the document and the library diff --git a/docs/docs/02-render-pdf.md b/docs/docs/02-render-pdf.md index ee133e2..f9a2463 100644 --- a/docs/docs/02-render-pdf.md +++ b/docs/docs/02-render-pdf.md @@ -106,7 +106,7 @@ console.log(image.data); // Bitmap image data as a buffer #### render: custom render function -You can also pass a custom render function as the `render` option. It should be a function that accepts a `RenderPageOptions` object and returns a `Promise` object. You can use it to render to any image format: +You can also pass a custom render function as the `render` option. It should be a function that accepts a `RenderPageOptions` object and returns a `Promise` object. You can use it to render to any image format: ```typescript import sharp from 'sharp'; @@ -114,7 +114,7 @@ import { type PDFiumPageRenderOptions } from '@hyzyla/pdfium'; const image = await page.render({ scale: 3, - render: async (options: PDFiumPageRenderOptions): Promise => { + render: async (options: PDFiumPageRenderOptions): Promise => { return await sharp(options.data, { raw: { width: options.width, @@ -170,7 +170,7 @@ async main() { }); // Save the PNG image to the output folder - await fs.writeFile(`output/${page.number}.png`, image.data); + await fs.writeFile(`output/${page.number}.png`, Buffer.from(image.data)); } // Do not forget to destroy the document and the library diff --git a/docs/docs/03-extract-images-from-page.md b/docs/docs/03-extract-images-from-page.md index 069f8cd..10624fc 100644 --- a/docs/docs/03-extract-images-from-page.md +++ b/docs/docs/03-extract-images-from-page.md @@ -22,7 +22,7 @@ for (const page of document.pages()) { }); // Save the PNG image to the output folder - await fs.writeFile(`output/${index}.png`, image.data); + await fs.writeFile(`output/${index}.png`, Buffer.from(image.data)); index++; } @@ -44,7 +44,7 @@ const page = document.getPage(0); const object = page.getObject(0); const image = await object.render({ - render: async (options: PDFiumPageRenderOptions): Promise => { + render: async (options: PDFiumPageRenderOptions): Promise => { return await sharp(options.data, { raw: { width: options.width, diff --git a/src/objects.ts b/src/objects.ts index 9bdbb83..92ff4e0 100644 --- a/src/objects.ts +++ b/src/objects.ts @@ -1,7 +1,7 @@ import type * as t from "./vendor/pdfium"; import { BYTES_PER_PIXEL, FPDFBitmap, FPDFPageObjectType } from "./constants"; -import { convertBitmapToImage } from "./utils"; +import { convertBitmapToImage, readUInt16LE } from "./utils"; import type { PDFiumImageObjectRaw, PDFiumImageObjectRender, @@ -93,7 +93,7 @@ export class PDFiumImageObject extends PDFiumObjectBase { throw new Error("Failed to get bitmap buffer."); } - const oData = Buffer.from(this.module.HEAPU8.slice(bufferPtr, bufferPtr + bufferSize)); + const oData = this.module.HEAPU8.slice(bufferPtr, bufferPtr + bufferSize); this.module.wasmExports.free(bufferPtr); // Width and height of the image in pixels will be written to these pointers as 16-bit integers (2 bytes each): @@ -106,12 +106,12 @@ export class PDFiumImageObject extends PDFiumObjectBase { throw new Error("Failed to get image size."); } - const widthBuffer = Buffer.from(this.module.HEAPU8.slice(widthPtr, widthPtr + 2)); - const heightBuffer = Buffer.from(this.module.HEAPU8.slice(heightPtr, heightPtr + 2)); + const widthBuffer = this.module.HEAPU8.slice(widthPtr, widthPtr + 2); + const heightBuffer = this.module.HEAPU8.slice(heightPtr, heightPtr + 2); this.module.wasmExports.free(sizePtr); - const width = widthBuffer.readUInt16LE(); - const height = heightBuffer.readUInt16LE(); + const width = readUInt16LE(widthBuffer) + const height = readUInt16LE(heightBuffer) const filtersCount = this.module._FPDFImageObj_GetImageFilterCount(this.objectIdx); const filters: string[] = []; @@ -121,8 +121,9 @@ export class PDFiumImageObject extends PDFiumObjectBase { if (!this.module._FPDFImageObj_GetImageFilter(this.objectIdx, i, filterPtr, filterSize)) { throw new Error("Failed to get image filter."); } - const filterBuffer = Buffer.from(this.module.HEAPU8.slice(filterPtr, filterPtr + filterSize - 1)); - const filter = filterBuffer.toString("utf8").trim(); + const filterBuffer = this.module.HEAPU8.slice(filterPtr, filterPtr + filterSize - 1); + const filter = (new TextDecoder().decode(filterBuffer)).trim(); + this.module.wasmExports.free(filterPtr); filters.push(filter); } @@ -178,7 +179,9 @@ export class PDFiumImageObject extends PDFiumObjectBase { const tBPP = BYTES_PER_PIXEL; // Create a new buffer for the target image and fill it with white color - const tData = Buffer.alloc(width * height * tBPP, 255); + const tData = new Uint8Array(width * height * tBPP); + // Fill the buffer with transparent white color + tData.fill(255); // Iterate over the rows of the original and target images for (let rowIndex = 0; rowIndex < height; rowIndex++) { diff --git a/src/objects.types.ts b/src/objects.types.ts index 119b29a..2d7acb7 100644 --- a/src/objects.types.ts +++ b/src/objects.types.ts @@ -9,12 +9,12 @@ export type PDFiumImageObjectRenderParams = { export type PDFiumImageObjectRender = { width: number; height: number; - data: Buffer; + data: Uint8Array; }; export type PDFiumImageObjectRaw = { width: number; height: number; - data: Buffer; + data: Uint8Array; filters: string[]; }; diff --git a/src/page.ts b/src/page.ts index a6167eb..7228178 100644 --- a/src/page.ts +++ b/src/page.ts @@ -89,7 +89,7 @@ export class PDFiumPage { this.module._FPDFBitmap_Destroy(bitmap); this.module._FPDF_ClosePage(this.pageIdx); - const data = Buffer.from(this.module.HEAPU8.subarray(ptr, ptr + buffSize)); + const data = this.module.HEAPU8.subarray(ptr, ptr + buffSize); this.module.wasmExports.free(ptr); const image = await this.convertBitmapToImage({ @@ -112,7 +112,7 @@ export class PDFiumPage { options: { render: PDFiumRenderFunction; } & PDFiumRenderOptions, - ): Promise { + ): Promise { return await convertBitmapToImage(options); } diff --git a/src/page.types.ts b/src/page.types.ts index 0f8b06b..948c97c 100644 --- a/src/page.types.ts +++ b/src/page.types.ts @@ -3,18 +3,18 @@ import type { PDFiumRenderFunction, PDFiumRenderOptions } from "./types"; export type PDFiumPageRenderFunction = PDFiumRenderFunction; export type PDFiumPageRenderOptions = PDFiumRenderOptions; -export type PDFiumPageRenderCallback = (options: PDFiumPageRenderOptions) => Promise; +export type PDFiumPageRenderCallback = (options: PDFiumPageRenderOptions) => Promise; export type PDFiumPageRenderParams = { render: PDFiumPageRenderFunction; } & ( - | { + | { scale: number; } - | { + | { width: number; height: number; } -); + ); export type PDFiumPageSize = { width: number; @@ -26,5 +26,5 @@ export type PDFiumPageRender = { height: number; originalHeight: number; originalWidth: number; - data: Buffer; + data: Uint8Array; }; diff --git a/src/renderer/sharp.ts b/src/renderer/sharp.ts index 559e6af..18ed7a5 100644 --- a/src/renderer/sharp.ts +++ b/src/renderer/sharp.ts @@ -1,6 +1,6 @@ import type { PDFiumRenderOptions } from "../types"; -export async function renderBySharp(options: PDFiumRenderOptions): Promise { +export async function renderBySharp(options: PDFiumRenderOptions): Promise { const { default: sharp } = await import("sharp"); return await sharp(options.data, { raw: { diff --git a/src/types.ts b/src/types.ts index c58b488..f6ddf22 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,9 +1,9 @@ export type PDFiumRenderOptions = { width: number; height: number; - data: Buffer; + data: Uint8Array; }; -export type PDFiumRenderCallback = (options: PDFiumRenderOptions) => Promise; +export type PDFiumRenderCallback = (options: PDFiumRenderOptions) => Promise; export type PDFiumRenderFunction = "sharp" | "bitmap" | PDFiumRenderCallback; diff --git a/src/utils.ts b/src/utils.ts index 2f4e74f..a8940cf 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -5,7 +5,7 @@ export async function convertBitmapToImage( options: { render: PDFiumRenderFunction; } & PDFiumRenderOptions, -): Promise { +): Promise { switch (options.render) { case "sharp": return await renderBySharp(options); @@ -15,3 +15,8 @@ export async function convertBitmapToImage( return await options.render(options); } } + + +export function readUInt16LE(buffer: Uint8Array, offset = 0): number { + return buffer[offset] | (buffer[offset + 1] << 8); +} \ No newline at end of file diff --git a/test/index.test.ts b/test/index.test.ts index 94ae0a0..e31d06c 100644 --- a/test/index.test.ts +++ b/test/index.test.ts @@ -151,14 +151,14 @@ describe("PDFium", () => { const result = await document.getPage(0).render({ scale: 1, render: async (options) => { - expect(options.data).toBeInstanceOf(Buffer); + expect(options.data).toBeInstanceOf(Uint8Array); expect(options.height).toBe(A4_SIZE.height); expect(options.width).toBe(A4_SIZE.width); - return Buffer.from("test"); + return new TextEncoder().encode("test"); }, }); expect(result).toEqual({ - data: Buffer.from("test"), + data: new TextEncoder().encode("test"), height: A4_SIZE.height, width: A4_SIZE.width, originalHeight: A4_SIZE.height, @@ -256,6 +256,7 @@ describe("PDFium", () => { const { data: image } = await imageObj.render({ render: "sharp", }); + expect(image).toBeInstanceOf(Uint8Array); expect(image).toMatchImageSnapshot(); } }