Skip to content

Commit

Permalink
[PDF] convert JPEG non compatible with jsPDF by ourselves (#837)
Browse files Browse the repository at this point in the history
* [jsPdf] workaround for non compatibles JPEG

Closes #797
  • Loading branch information
MikeZeDev authored Nov 2, 2024
1 parent ca7b2a2 commit f7dd351
Showing 1 changed file with 30 additions and 2 deletions.
32 changes: 30 additions & 2 deletions web/src/engine/exporters/PortableDocumentFormatExporter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,43 @@ export class PortableDocumentFormatExporter extends MangaExporter {
try {
const { width, height } = bitmap;
// Conversion of unsupported images via jsPDF is slow and produces a large PDF => Using own implementation of image conversion
const blob = pdfImageFormats.includes(data.type) ? data : await ConvertBitmap(bitmap, 'image/jpeg', 0.95);
return { width, height, data: new Uint8Array(await blob.arrayBuffer()) };
let buffer = new Uint8Array(await data.arrayBuffer());
buffer = await this.CheckImageCompatibility(data.type, buffer) ? buffer : new Uint8Array(await (await ConvertBitmap(bitmap, 'image/jpeg', 0.95)).arrayBuffer());
return { width, height, data: buffer };
} finally {
bitmap.close();
}
}, Priority.Normal));
return Promise.all(promises);
}

private async CheckImageCompatibility(mimetype: string, buffer: Uint8Array): Promise<boolean> {
return mimetype === 'image/jpeg' ? this.IsCompatibleJPEG(buffer) : pdfImageFormats.includes(mimetype);
}

/**
* Test if JPEG data is compatible with JsPDF "headers check"
* @param imageData - Image buffer as Uint8Array
* @returns
*/
private async IsCompatibleJPEG(imageData: Uint8Array): Promise<boolean> {
const jsPdfJpegHeaders =
[[0xff, 0xd8, 0xff, 0xe0, undefined, undefined, 0x4a, 0x46, 0x49, 0x46, 0x00], //JFIF
[0xff, 0xd8, 0xff, 0xe1, undefined, undefined, 0x45, 0x78, 0x69, 0x66, 0x00, 0x00], //Exif
[0xff, 0xd8, 0xff, 0xdb], //JPEG RAW
[0xff, 0xd8, 0xff, 0xee] //EXIF RAW
];

return jsPdfJpegHeaders.some(jpegPattern => {
for (let index = 0; index < jpegPattern.length; index++) {
if (jpegPattern[index] !== undefined && jpegPattern[index] !== imageData[index]) {
return false;
}
}
return true;
});
}

public async Export(sourceFileList: Map<number, string>, targetDirectory: FileSystemDirectoryHandle, targetBaseName: string): Promise<void> {
const pdf = new jsPDF({ unit: 'px' });
pdf.deletePage(1);
Expand Down

0 comments on commit f7dd351

Please sign in to comment.