Files
pdf-tools/src/pdf/pdfThumbnailService.ts
2025-11-26 18:02:58 +01:00

109 lines
3.0 KiB
TypeScript

import * as pdfjsLib from 'pdfjs-dist';
import pdfjsWorker from 'pdfjs-dist/build/pdf.worker?worker&url';
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(pdfjsLib as any).GlobalWorkerOptions.workerSrc = pdfjsWorker;
type RotationsMap = Record<number, number>;
export async function generateThumbnails(
arrayBuffer: ArrayBuffer,
maxHeight = 150
): Promise<string[]> {
return generateThumbnailsInternal(arrayBuffer, {}, maxHeight);
}
export async function generateThumbnailsWithRotations(
arrayBuffer: ArrayBuffer,
rotations: RotationsMap,
maxHeight = 150
): Promise<string[]> {
return generateThumbnailsInternal(arrayBuffer, rotations, maxHeight);
}
async function generateThumbnailsInternal(
arrayBuffer: ArrayBuffer,
rotations: RotationsMap,
maxHeight: number
): Promise<string[]> {
const loadingTask = pdfjsLib.getDocument({ data: arrayBuffer });
const pdf = await loadingTask.promise;
const thumbs: string[] = [];
for (let pageNum = 1; pageNum <= pdf.numPages; pageNum++) {
const page = await pdf.getPage(pageNum);
const viewport = page.getViewport({ scale: 1 });
const scale = maxHeight / viewport.height;
const scaledViewport = page.getViewport({ scale });
const baseCanvas = document.createElement('canvas');
const baseCtx = baseCanvas.getContext('2d');
if (!baseCtx) {
thumbs.push('');
continue;
}
baseCanvas.width = scaledViewport.width;
baseCanvas.height = scaledViewport.height;
const renderTask = page.render({
canvasContext: baseCtx,
viewport: scaledViewport,
});
await renderTask.promise;
const originalIndex = pageNum - 1;
const rotationDegRaw = rotations[originalIndex] ?? 0;
const rotationDeg = ((rotationDegRaw % 360) + 360) % 360;
if (rotationDeg === 0) {
thumbs.push(baseCanvas.toDataURL('image/png'));
continue;
}
const rotatedCanvas = document.createElement('canvas');
const rotatedCtx = rotatedCanvas.getContext('2d');
if (!rotatedCtx) {
thumbs.push(baseCanvas.toDataURL('image/png'));
continue;
}
const rad = (rotationDeg * Math.PI) / 180;
if (rotationDeg === 90 || rotationDeg === 270) {
rotatedCanvas.width = baseCanvas.height;
rotatedCanvas.height = baseCanvas.width;
} else {
rotatedCanvas.width = baseCanvas.width;
rotatedCanvas.height = baseCanvas.height;
}
rotatedCtx.save();
switch (rotationDeg) {
case 90:
rotatedCtx.translate(rotatedCanvas.width, 0);
rotatedCtx.rotate(rad);
break;
case 180:
rotatedCtx.translate(rotatedCanvas.width, rotatedCanvas.height);
rotatedCtx.rotate(rad);
break;
case 270:
rotatedCtx.translate(0, rotatedCanvas.height);
rotatedCtx.rotate(rad);
break;
default:
break;
}
rotatedCtx.drawImage(baseCanvas, 0, 0);
rotatedCtx.restore();
thumbs.push(rotatedCanvas.toDataURL('image/png'));
}
return thumbs;
}