From 8604cc90b7fb188ba43457eced2886d07ac5e248 Mon Sep 17 00:00:00 2001 From: Kyle Hensel Date: Thu, 8 Aug 2024 09:22:16 +1000 Subject: [PATCH] Added a new method to read a specific page number --- CHANGELOG.md | 4 + README.md | 4 + package-lock.json | 4 +- package.json | 108 +++++++++--------- src/index.ts | 35 +++--- ...can-read-a-specific-page-number-1-snap.png | Bin 0 -> 6197 bytes tests/jsdom.test.ts | 5 + 7 files changed, 90 insertions(+), 70 deletions(-) create mode 100644 tests/__image_snapshots__/jsdom-test-ts-multipage-pdf-can-read-a-specific-page-number-1-snap.png diff --git a/CHANGELOG.md b/CHANGELOG.md index 2cfd5e0..362f423 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## 4.1.0 (2024-08-07) + +- Added a new method to read a specific page number + ## 4.0.0 (2024-06-08) - 💥 BREAKING CHANGE: Drop support for node v16. The minimum version is now v18 diff --git a/README.md b/README.md index ddc01bb..e642468 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,10 @@ async function main() { await fs.writeFile(`page${counter}.png`, image); counter++; } + + + // you can also read a specific page number: + const page12buffer = await document.getPage(12) } main(); ``` diff --git a/package-lock.json b/package-lock.json index 375b86c..78655ef 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "pdf-to-img", - "version": "4.0.0", + "version": "4.1.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "pdf-to-img", - "version": "4.0.0", + "version": "4.1.0", "license": "MIT", "dependencies": { "canvas": "2.11.2", diff --git a/package.json b/package.json index 7c894af..7b34956 100644 --- a/package.json +++ b/package.json @@ -1,54 +1,54 @@ -{ - "name": "pdf-to-img", - "version": "4.0.0", - "author": "Kyle Hensel", - "description": "📃📸 Converts PDFs to images in nodejs", - "exports": "./dist/index.js", - "types": "dist/index.d.ts", - "type": "module", - "license": "MIT", - "files": [ - "dist" - ], - "keywords": [ - "pdf", - "pdfjs", - "pdf-to-img", - "pdf-to-png", - "vitest", - "jest" - ], - "repository": "https://github.com/k-yle/pdf-to-img", - "scripts": { - "build": "tsc && rm -rf dist && mv temp/src dist && rm -rf temp", - "lint": "eslint --ignore-path .gitignore .", - "test": "vitest --pool=forks", - "trypublish": "npm publish --provenance || true" - }, - "bin": { - "pdf2img": "./bin/cli.mjs" - }, - "engines": { - "node": ">=18" - }, - "engineStrict": true, - "dependencies": { - "canvas": "2.11.2", - "pdfjs-dist": "4.2.67" - }, - "devDependencies": { - "@rushstack/eslint-patch": "^1.5.1", - "@types/jest-image-snapshot": "^6.2.1", - "@types/node": "^20.8.6", - "@types/pdfjs-dist": "2.10.377", - "@vitest/coverage-v8": "^1.6.0", - "eslint": "^8.50.0", - "eslint-config-kyle": "^14.12.3", - "jest-image-snapshot": "^6.2.0", - "typescript": "^5.2.2", - "vitest": "^1.6.0" - }, - "prettier": { - "trailingComma": "es5" - } -} +{ + "name": "pdf-to-img", + "version": "4.1.0", + "author": "Kyle Hensel", + "description": "📃📸 Converts PDFs to images in nodejs", + "exports": "./dist/index.js", + "types": "dist/index.d.ts", + "type": "module", + "license": "MIT", + "files": [ + "dist" + ], + "keywords": [ + "pdf", + "pdfjs", + "pdf-to-img", + "pdf-to-png", + "vitest", + "jest" + ], + "repository": "https://github.com/k-yle/pdf-to-img", + "scripts": { + "build": "tsc && rm -rf dist && mv temp/src dist && rm -rf temp", + "lint": "eslint --ignore-path .gitignore .", + "test": "vitest --pool=forks", + "trypublish": "npm publish --provenance || true" + }, + "bin": { + "pdf2img": "./bin/cli.mjs" + }, + "engines": { + "node": ">=18" + }, + "engineStrict": true, + "dependencies": { + "canvas": "2.11.2", + "pdfjs-dist": "4.2.67" + }, + "devDependencies": { + "@rushstack/eslint-patch": "^1.5.1", + "@types/jest-image-snapshot": "^6.2.1", + "@types/node": "^20.8.6", + "@types/pdfjs-dist": "2.10.377", + "@vitest/coverage-v8": "^1.6.0", + "eslint": "^8.50.0", + "eslint-config-kyle": "^14.12.3", + "jest-image-snapshot": "^6.2.0", + "typescript": "^5.2.2", + "vitest": "^1.6.0" + }, + "prettier": { + "trailingComma": "es5" + } +} diff --git a/src/index.ts b/src/index.ts index e813338..7a29739 100644 --- a/src/index.ts +++ b/src/index.ts @@ -73,6 +73,7 @@ export async function pdf( ): Promise<{ length: number; metadata: PdfMetadata; + getPage(pageNumber: number): Promise; [Symbol.asyncIterator](): AsyncIterator; }> { const data = await parseInput(input); @@ -91,30 +92,36 @@ export async function pdf( const metadata = await pdfDocument.getMetadata(); + async function getPage(pageNumber: number) { + const page = await pdfDocument.getPage(pageNumber); + + const viewport = page.getViewport({ scale: options.scale ?? 1 }); + + const { canvas, context } = canvasFactory.create( + viewport.width, + viewport.height + ); + + await page.render({ + canvasContext: context, + viewport, + }).promise; + + return canvas.toBuffer(); + } + return { length: pdfDocument.numPages, metadata: sanitize(metadata.info), + getPage, [Symbol.asyncIterator]() { return { pg: 0, async next(this: { pg: number }) { if (this.pg < pdfDocument.numPages) { this.pg += 1; - const page = await pdfDocument.getPage(this.pg); - - const viewport = page.getViewport({ scale: options.scale ?? 1 }); - - const { canvas, context } = canvasFactory.create( - viewport.width, - viewport.height - ); - - await page.render({ - canvasContext: context, - viewport, - }).promise; - return { done: false, value: canvas.toBuffer() }; + return { done: false, value: await getPage(this.pg) }; } return { done: true, value: undefined }; }, diff --git a/tests/__image_snapshots__/jsdom-test-ts-multipage-pdf-can-read-a-specific-page-number-1-snap.png b/tests/__image_snapshots__/jsdom-test-ts-multipage-pdf-can-read-a-specific-page-number-1-snap.png new file mode 100644 index 0000000000000000000000000000000000000000..d2966e0731d167a72c5a73ff59d9d9f69d395daf GIT binary patch literal 6197 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 { expect(page).toMatchImageSnapshot(); } }); + + it("can read a specific page number", async () => { + const document = await pdf("./tests/multipage.pdf"); + expect(await document.getPage(2)).toMatchImageSnapshot(); + }); }); describe("test-pattern.pdf", () => {