mirror of
https://github.com/Stirling-Tools/Stirling-PDF.git
synced 2025-08-26 14:19:24 +00:00
Refactor thumbnail generation code
This commit is contained in:
parent
01a1629aeb
commit
0eee52dedf
@ -224,6 +224,25 @@ function drawLargeLockIcon(ctx: CanvasRenderingContext2D, centerX: number, cente
|
|||||||
ctx.fillRect(keyholeX - 2, keyholeY, 4, 8);
|
ctx.fillRect(keyholeX - 2, keyholeY, 4, 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate standard PDF thumbnail by rendering first page
|
||||||
|
*/
|
||||||
|
async function generateStandardPDFThumbnail(pdf: any, scale: number): Promise<string> {
|
||||||
|
const page = await pdf.getPage(1);
|
||||||
|
const viewport = page.getViewport({ scale });
|
||||||
|
const canvas = document.createElement("canvas");
|
||||||
|
canvas.width = viewport.width;
|
||||||
|
canvas.height = viewport.height;
|
||||||
|
const context = canvas.getContext("2d");
|
||||||
|
|
||||||
|
if (!context) {
|
||||||
|
throw new Error('Could not get canvas context');
|
||||||
|
}
|
||||||
|
|
||||||
|
await page.render({ canvasContext: context, viewport }).promise;
|
||||||
|
return canvas.toDataURL();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Draw extension badge
|
* Draw extension badge
|
||||||
*/
|
*/
|
||||||
@ -281,98 +300,65 @@ export async function generateThumbnailForFile(file: File): Promise<string | und
|
|||||||
console.log('Generating thumbnail for', file.name);
|
console.log('Generating thumbnail for', file.name);
|
||||||
const scale = calculateScaleFromFileSize(file.size);
|
const scale = calculateScaleFromFileSize(file.size);
|
||||||
console.log(`Using scale ${scale} for ${file.name} (${(file.size / 1024 / 1024).toFixed(1)}MB)`);
|
console.log(`Using scale ${scale} for ${file.name} (${(file.size / 1024 / 1024).toFixed(1)}MB)`);
|
||||||
try {
|
|
||||||
// Only read first 2MB for thumbnail generation to save memory
|
// Only read first 2MB for thumbnail generation to save memory
|
||||||
const chunkSize = 2 * 1024 * 1024; // 2MB
|
const chunkSize = 2 * 1024 * 1024; // 2MB
|
||||||
const chunk = file.slice(0, Math.min(chunkSize, file.size));
|
const chunk = file.slice(0, Math.min(chunkSize, file.size));
|
||||||
const arrayBuffer = await chunk.arrayBuffer();
|
const arrayBuffer = await chunk.arrayBuffer();
|
||||||
|
|
||||||
|
let thumbnail: string;
|
||||||
|
try {
|
||||||
const pdf = await getDocument({
|
const pdf = await getDocument({
|
||||||
data: arrayBuffer,
|
data: arrayBuffer,
|
||||||
disableAutoFetch: true,
|
disableAutoFetch: true,
|
||||||
disableStream: true
|
disableStream: true
|
||||||
}).promise;
|
}).promise;
|
||||||
|
|
||||||
// Check if PDF is encrypted
|
thumbnail = await generateStandardPDFThumbnail(pdf, scale);
|
||||||
if ((pdf as any).isEncrypted) {
|
|
||||||
console.log('PDF is encrypted, generating encrypted thumbnail:', file.name);
|
|
||||||
pdf.destroy();
|
|
||||||
return generateEncryptedPDFThumbnail(file);
|
|
||||||
}
|
|
||||||
|
|
||||||
const page = await pdf.getPage(1);
|
|
||||||
const viewport = page.getViewport({ scale }); // Dynamic scale based on file size
|
|
||||||
const canvas = document.createElement("canvas");
|
|
||||||
canvas.width = viewport.width;
|
|
||||||
canvas.height = viewport.height;
|
|
||||||
const context = canvas.getContext("2d");
|
|
||||||
|
|
||||||
if (!context) {
|
|
||||||
throw new Error('Could not get canvas context');
|
|
||||||
}
|
|
||||||
|
|
||||||
await page.render({ canvasContext: context, viewport }).promise;
|
|
||||||
const thumbnail = canvas.toDataURL();
|
|
||||||
|
|
||||||
// Immediately clean up memory after thumbnail generation
|
// Immediately clean up memory after thumbnail generation
|
||||||
pdf.destroy();
|
pdf.destroy();
|
||||||
console.log('Thumbnail generated and PDF destroyed for', file.name);
|
|
||||||
|
|
||||||
return thumbnail;
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error instanceof Error) {
|
if (error instanceof Error) {
|
||||||
// Check if error indicates encrypted PDF
|
// Check if PDF is encrypted
|
||||||
const errorMessage = error.message.toLowerCase();
|
if (error.name === "PasswordException") {
|
||||||
if (errorMessage.includes('password') || errorMessage.includes('encrypted')) {
|
thumbnail = generateEncryptedPDFThumbnail(file);
|
||||||
console.log('PDF appears to be encrypted based on error, generating encrypted thumbnail:', file.name);
|
|
||||||
return generateEncryptedPDFThumbnail(file);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (error.name === 'InvalidPDFException') {
|
} else if (error.name === 'InvalidPDFException') {
|
||||||
console.warn(`PDF structure issue for ${file.name} - using fallback thumbnail`);
|
console.warn(`PDF structure issue for ${file.name} - using fallback thumbnail`);
|
||||||
// Return a placeholder or try with full file instead of chunk
|
// Return a placeholder or try with full file instead of chunk
|
||||||
try {
|
|
||||||
const fullArrayBuffer = await file.arrayBuffer();
|
const fullArrayBuffer = await file.arrayBuffer();
|
||||||
|
try {
|
||||||
const pdf = await getDocument({
|
const pdf = await getDocument({
|
||||||
data: fullArrayBuffer,
|
data: fullArrayBuffer,
|
||||||
disableAutoFetch: true,
|
disableAutoFetch: true,
|
||||||
disableStream: true,
|
disableStream: true,
|
||||||
verbosity: 0 // Reduce PDF.js warnings
|
verbosity: 0 // Reduce PDF.js warnings
|
||||||
}).promise;
|
}).promise;
|
||||||
|
thumbnail = await generateStandardPDFThumbnail(pdf, scale);
|
||||||
// Check if PDF is encrypted in fallback too
|
|
||||||
if ((pdf as any).isEncrypted) {
|
|
||||||
console.log('PDF is encrypted in fallback, generating encrypted thumbnail:', file.name);
|
|
||||||
pdf.destroy();
|
pdf.destroy();
|
||||||
return generateEncryptedPDFThumbnail(file);
|
|
||||||
}
|
|
||||||
|
|
||||||
const page = await pdf.getPage(1);
|
|
||||||
const viewport = page.getViewport({ scale });
|
|
||||||
const canvas = document.createElement("canvas");
|
|
||||||
canvas.width = viewport.width;
|
|
||||||
canvas.height = viewport.height;
|
|
||||||
const context = canvas.getContext("2d");
|
|
||||||
|
|
||||||
if (!context) {
|
|
||||||
throw new Error('Could not get canvas context');
|
|
||||||
}
|
|
||||||
|
|
||||||
await page.render({ canvasContext: context, viewport }).promise;
|
|
||||||
const thumbnail = canvas.toDataURL();
|
|
||||||
|
|
||||||
pdf.destroy();
|
|
||||||
return thumbnail;
|
|
||||||
} catch (fallbackError) {
|
} catch (fallbackError) {
|
||||||
|
if (fallbackError instanceof Error) {
|
||||||
|
// Check if PDF is encrypted
|
||||||
|
if (fallbackError.name === "PasswordException") {
|
||||||
|
thumbnail = generateEncryptedPDFThumbnail(file);
|
||||||
|
} else {
|
||||||
console.warn('Fallback thumbnail generation also failed for', file.name, fallbackError);
|
console.warn('Fallback thumbnail generation also failed for', file.name, fallbackError);
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
console.warn('Failed to generate thumbnail for', file.name, error);
|
throw fallbackError; // Re-throw non-Error exceptions
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.warn('Unknown error thrown. Failed to generate thumbnail for', file.name, error);
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
console.warn('Unknown error generating thumbnail for', file.name, error);
|
throw error; // Re-throw non-Error exceptions
|
||||||
return undefined;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return thumbnail;
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user