first commit
This commit is contained in:
108
src/pdf/pdfThumbnailService.ts
Normal file
108
src/pdf/pdfThumbnailService.ts
Normal file
@@ -0,0 +1,108 @@
|
||||
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;
|
||||
}
|
||||
Reference in New Issue
Block a user