@mkholt/pdf-thumbnail
v2.1.0
Published
Create PDF thumbnails server and client side, with React hook support
Readme
PDF Thumbnail Library
Overview
The PDF Thumbnail Library is a tool to generate thumbnails from PDF documents. It is designed to be simple and efficient, making it easy to integrate into your projects.
The library exposes methods to directly generate the thumbnail into a data url string, or a Buffer.
Installation
NPM:
npm install @mkholt/pdf-thumbnailYarn:
yarn add @mkholt/pdf-thumbnailIf you are running in Node.js, @napi-rs/canvas is needed for rendering:
NPM:
npm install @napi-rs/canvasYarn:
yarn add @napi-rs/canvasThis is not needed for browser-only usage, where the native canvas is used automatically.
Usage
Embedded client-side as thumbnail images
import { useThumbnails, FileData } from '@mkholt/pdf-thumbnail'
export type Data = FileData & { name: string }
export type ThumbnailsProps = {
files: Data[]
}
export const Thumbnails = ({ files }: ThumbnailsProps) => {
const { thumbnails, isLoading, error } = useThumbnails(files)
if (isLoading) return <div>Loading thumbnails...</div>
if (error) return <div>Error: {error.message}</div>
return (
<div>
{thumbnails.map(td => (
<a key={td.file} href={`/files/${td.file}`} target="_blank">
<img src={td.thumbData} alt={td.name} />
</a>
))}
</div>
)
}Embedded server-side by building images using node
import { PageContext } from "vike/types";
import { createThumbnails } from "@mkholt/pdf-thumbnail";
export type Data = Awaited<ReturnType<typeof data>>
export async function data(pageContext: PageContext) {
const { id } = pageContext.routeParams
const pageData = await import(`../../../data/${id}.mdx`) as MDXDocument<InfoPage>
const thumbnails = await createThumbnails(pageData.config.links ?? [], { prefix: 'public/files/' })
return {
pageId: id,
pageConfig: unit.config,
thumbnails
}
}
Features
- Generate thumbnails from PDF documents
- Easy to use API
- Supports outputting directly to a data URL or Buffer
- Structured error results with error details
- Customizable scale and page selection
- Concurrency control for batch operations
- Progress callback for batch operations
- AbortSignal support for cancellation
- React hook with loading/error state
Security Considerations
This library processes file paths and URLs as provided. When using it with untrusted input, be aware of:
- Path traversal: File paths are passed directly to
fs.readFilein Node.js. Never pass unsanitized user input as a file path. - SSRF: URLs are fetched with
fetch(). If user input controls the URL, an attacker could reach internal services. Validate or restrict URLs before passing them to this library. - Resource limits: There are no built-in limits on PDF file size or rendered image dimensions. Use the
concurrencyoption to limit parallel processing, and validate file sizes before processing untrusted PDFs.
API
createThumbnail(file, options?)
Creates a thumbnail for a single PDF file. Returns a StringThumbnail or BufferThumbnail on success, an ErrorThumbnail on failure, or undefined if the operation was aborted.
const thumb = await createThumbnail("path/to/file.pdf", {
output: "string", // "string" (default) or "buffer"
scale: 1, // Scale factor (default: 1)
page: 1, // Page number (default: 1)
signal: abortController.signal, // Optional AbortSignal
logLevel: "error", // "silent" | "error" | "debug"
});
if (!thumb) {
// Operation was aborted
} else if (thumb.thumbType === "error") {
console.error("Failed:", thumb.thumbData);
} else {
// thumb.thumbData is a base64 data URL or Buffer
}createThumbnails(files, options?)
Creates thumbnails for multiple files. The returned array includes both successful thumbnails and ErrorThumbnail results for files that failed. Aborted files are excluded from the results.
const thumbs = await createThumbnails(files, {
prefix: "public/", // Prefix for file paths
scale: 0.5, // Scale factor
page: 1, // Page number
concurrency: 4, // Max parallel operations (default: Infinity)
signal: abortController.signal,
onProgress: (completed, total) => {
console.log(`Progress: ${completed}/${total}`);
}
});
// Separate successes from errors
const successes = thumbs.filter(t => t.thumbType !== "error");
const errors = thumbs.filter(t => t.thumbType === "error");useThumbnails(files, options?) (React Hook)
React hook for client-side thumbnail generation.
const { thumbnails, isLoading, error } = useThumbnails(files, {
prefix: "/api/files/",
scale: 1,
page: 1,
});Migration from v2 to v3
Breaking Change: Canvas peer dependency
The canvas (node-canvas) peer dependency has been replaced with @napi-rs/canvas. This eliminates the need for node-gyp and native build tools.
# Remove the old dependency
npm uninstall canvas
# Install the new one
npm install @napi-rs/canvasBreaking Change: Error handling
createThumbnail now returns an ErrorThumbnail (with thumbType: "error" and the error message in thumbData) instead of undefined when a file fails to process. undefined is now reserved exclusively for aborted operations.
// v2 — errors returned undefined
const thumb = await createThumbnail("file.pdf");
if (!thumb) {
// Could be an error or an abort — no way to tell
}
// v3 — errors are structured
const thumb = await createThumbnail("file.pdf");
if (!thumb) {
// Aborted
} else if (thumb.thumbType === "error") {
console.error(thumb.thumbData); // Error message
}createThumbnails now includes ErrorThumbnail results in the returned array instead of silently dropping failed files. If you previously relied on the array only containing successes, filter by thumbType:
const results = await createThumbnails(files);
const successes = results.filter(t => t.thumbType !== "error");Node.js version
The minimum Node.js version is now 18 (was ^18.12.0 || >=20.9.0). The restrictive version range from v2 was due to node-canvas binary availability and no longer applies.
Migration from v1 to v2
Breaking Change: useThumbnails return type
In v1, useThumbnails returned an array of thumbnails directly:
// v1
const thumbnails = useThumbnails(files);In v2, it returns an object with thumbnails, isLoading, and error:
// v2
const { thumbnails, isLoading, error } = useThumbnails(files);Contributing
Contributions are welcome! Please open a PR for suggestions.
License
This project is licensed under the MIT License. See the LICENSE file for details.
