109 lines
3.0 KiB
TypeScript
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;
|
|
}
|