mirror of
https://github.com/alam00000/bentopdf.git
synced 2026-08-17 21:25:47 +02:00
Add out of memory error handling for PDF to TIFF conversion
This commit is contained in:
@@ -400,7 +400,8 @@
|
||||
"noFile": "No File",
|
||||
"noFileExplanation": "Please upload a PDF file first.",
|
||||
"conversionSuccess": "PDF converted to TIFFs successfully!",
|
||||
"conversionError": "Failed to convert PDF to TIFF. The file might be corrupted."
|
||||
"conversionError": "Failed to convert PDF to TIFF. The file might be corrupted.",
|
||||
"conversionOutOfMemory": "The browser ran out of memory while converting. Try a lower DPI, or uncheck the multi-page TIFF option to convert pages one at a time."
|
||||
}
|
||||
},
|
||||
"pdfToCbz": {
|
||||
|
||||
@@ -36,6 +36,7 @@ async function getVips(): Promise<typeof Vips> {
|
||||
return fileName;
|
||||
},
|
||||
});
|
||||
vipsInstance.Cache.max(0);
|
||||
return vipsInstance;
|
||||
}
|
||||
|
||||
@@ -145,7 +146,11 @@ async function renderPageToRgba(
|
||||
}).promise;
|
||||
|
||||
const imageData = context.getImageData(0, 0, canvas.width, canvas.height);
|
||||
return { rgba: imageData.data, width: canvas.width, height: canvas.height };
|
||||
const { width, height } = canvas;
|
||||
page.cleanup();
|
||||
canvas.width = 0;
|
||||
canvas.height = 0;
|
||||
return { rgba: imageData.data, width, height };
|
||||
}
|
||||
|
||||
function encodePageToTiff(
|
||||
@@ -155,28 +160,33 @@ function encodePageToTiff(
|
||||
height: number,
|
||||
options: TiffOptions
|
||||
): Uint8Array {
|
||||
let image = vips.Image.newFromMemory(
|
||||
const intermediates: Vips.Image[] = [];
|
||||
const track = (img: Vips.Image): Vips.Image => {
|
||||
intermediates.push(img);
|
||||
return img;
|
||||
};
|
||||
|
||||
try {
|
||||
let image = track(
|
||||
vips.Image.newFromMemory(
|
||||
new Uint8Array(rgba.buffer, rgba.byteOffset, rgba.byteLength),
|
||||
width,
|
||||
height,
|
||||
4,
|
||||
vips.BandFormat.uchar
|
||||
)
|
||||
);
|
||||
|
||||
image = image.copy();
|
||||
image = track(image.copy());
|
||||
const pixelsPerMm = options.dpi / 25.4;
|
||||
image.setDouble('xres', pixelsPerMm);
|
||||
image.setDouble('yres', pixelsPerMm);
|
||||
|
||||
if (image.bands === 4) {
|
||||
image = track(image.flatten({ background: [255, 255, 255] }));
|
||||
}
|
||||
if (options.colorMode === 'greyscale' || options.colorMode === 'bw') {
|
||||
if (image.bands === 4) {
|
||||
image = image.flatten({ background: [255, 255, 255] });
|
||||
}
|
||||
image = image.colourspace(vips.Interpretation.b_w);
|
||||
} else {
|
||||
if (image.bands === 4) {
|
||||
image = image.flatten({ background: [255, 255, 255] });
|
||||
}
|
||||
image = track(image.colourspace(vips.Interpretation.b_w));
|
||||
}
|
||||
|
||||
const tiffOptions: Parameters<typeof image.tiffsaveBuffer>[0] = {
|
||||
@@ -198,9 +208,12 @@ function encodePageToTiff(
|
||||
tiffOptions.Q = 85;
|
||||
}
|
||||
|
||||
const buffer = image.tiffsaveBuffer(tiffOptions);
|
||||
image.delete();
|
||||
return buffer;
|
||||
return image.tiffsaveBuffer(tiffOptions);
|
||||
} finally {
|
||||
for (const img of intermediates) {
|
||||
if (!img.isDeleted()) img.delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function convert() {
|
||||
@@ -239,6 +252,7 @@ async function convert() {
|
||||
if (options.multiPage && pdf.numPages > 1) {
|
||||
const pages: Vips.Image[] = [];
|
||||
|
||||
try {
|
||||
for (let i = 1; i <= pdf.numPages; i++) {
|
||||
const page = await pdf.getPage(i);
|
||||
const { rgba, width, height } = await renderPageToRgba(
|
||||
@@ -246,26 +260,39 @@ async function convert() {
|
||||
options.dpi
|
||||
);
|
||||
|
||||
let img = vips.Image.newFromMemory(
|
||||
const intermediates: Vips.Image[] = [];
|
||||
const track = (image: Vips.Image): Vips.Image => {
|
||||
intermediates.push(image);
|
||||
return image;
|
||||
};
|
||||
|
||||
try {
|
||||
let img = track(
|
||||
vips.Image.newFromMemory(
|
||||
new Uint8Array(rgba.buffer, rgba.byteOffset, rgba.byteLength),
|
||||
width,
|
||||
height,
|
||||
4,
|
||||
vips.BandFormat.uchar
|
||||
)
|
||||
);
|
||||
|
||||
if (options.colorMode === 'greyscale' || options.colorMode === 'bw') {
|
||||
if (img.bands === 4) {
|
||||
img = img.flatten({ background: [255, 255, 255] });
|
||||
}
|
||||
img = img.colourspace(vips.Interpretation.b_w);
|
||||
} else {
|
||||
if (img.bands === 4) {
|
||||
img = img.flatten({ background: [255, 255, 255] });
|
||||
img = track(img.flatten({ background: [255, 255, 255] }));
|
||||
}
|
||||
if (
|
||||
options.colorMode === 'greyscale' ||
|
||||
options.colorMode === 'bw'
|
||||
) {
|
||||
img = track(img.colourspace(vips.Interpretation.b_w));
|
||||
}
|
||||
|
||||
pages.push(img);
|
||||
pages.push(img.copyMemory());
|
||||
} finally {
|
||||
for (const img of intermediates) {
|
||||
if (!img.isDeleted()) img.delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const firstPage = pages[0];
|
||||
@@ -274,6 +301,7 @@ async function convert() {
|
||||
joined = vips.Image.arrayjoin(pages, { across: 1 });
|
||||
}
|
||||
|
||||
try {
|
||||
const tiffOptions: Parameters<typeof joined.tiffsaveBuffer>[0] = {
|
||||
compression: options.compression as Vips.Enum,
|
||||
resunit: vips.ForeignTiffResunit.inch,
|
||||
@@ -295,13 +323,18 @@ async function convert() {
|
||||
}
|
||||
|
||||
const buffer = joined.tiffsaveBuffer(tiffOptions);
|
||||
const blob = new Blob([new Uint8Array(buffer)], { type: 'image/tiff' });
|
||||
const blob = new Blob([new Uint8Array(buffer)], {
|
||||
type: 'image/tiff',
|
||||
});
|
||||
downloadFile(blob, getCleanPdfFilename(files[0].name) + '.tiff');
|
||||
|
||||
joined.delete();
|
||||
} finally {
|
||||
if (joined !== firstPage && !joined.isDeleted()) joined.delete();
|
||||
}
|
||||
} finally {
|
||||
for (const p of pages) {
|
||||
if (!p.isDeleted()) p.delete();
|
||||
}
|
||||
}
|
||||
} else if (pdf.numPages === 1) {
|
||||
const page = await pdf.getPage(1);
|
||||
const { rgba, width, height } = await renderPageToRgba(page, options.dpi);
|
||||
@@ -334,7 +367,15 @@ async function convert() {
|
||||
);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
const message = e instanceof Error ? e.message : String(e);
|
||||
if (/memory/i.test(message)) {
|
||||
showAlert(
|
||||
t('common.error'),
|
||||
t('tools:pdfToTiff.alert.conversionOutOfMemory')
|
||||
);
|
||||
} else {
|
||||
showAlert(t('common.error'), t('tools:pdfToTiff.alert.conversionError'));
|
||||
}
|
||||
} finally {
|
||||
hideLoader();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user