@react-pdf/png-js doesn't support Adam 7 interlacing
Describe the bug
Using PNGs with Adam 7 interlacing throws the error Invalid filter which we've seen before in #391
To Reproduce I'm attaching an interlaced and non interlaced image. Using the interlaced image throws the above error.
const InterlacedPngPdf = () => (
<Document>
<Page>
<Image
src="https://i.imgur.com/wNI68lf.png"
/>
</Page>
</Document>
);
ReactPDF.render(<InterlacedPngPdf />);

Exif data:
ExifTool Version Number : 11.60 File Name : BikeaidSG logo - photopea.png Directory : . File Size : 11 kB File Modification Date/Time : 2019:08:04 09:31:45+05:30 File Access Date/Time : 2019:08:04 10:19:10+05:30 File Inode Change Date/Time : 2019:08:04 09:31:53+05:30 File Permissions : rw-r--r-- File Type : PNG File Type Extension : png MIME Type : image/png Image Width : 1280 Image Height : 720 Bit Depth : 8 Color Type : Palette Compression : Deflate/Inflate Filter : Adaptive Interlace : Noninterlaced SRGB Rendering : Relative Colorimetric Pixels Per Unit X : 3780 Pixels Per Unit Y : 3780 Pixel Units : meters Palette : (Binary data 132 bytes, use -b option to extract) Image Size : 1280x720 Megapixels : 0.922

Exif data:
ExifTool Version Number : 11.60 File Name : BikeaidSG logo.png Directory : . File Size : 17 kB File Modification Date/Time : 2019:08:04 09:31:05+05:30 File Access Date/Time : 2019:08:04 10:19:53+05:30 File Inode Change Date/Time : 2019:08:04 09:31:10+05:30 File Permissions : rw-r--r-- File Type : PNG File Type Extension : png MIME Type : image/png Image Width : 1280 Image Height : 720 Bit Depth : 8 Color Type : Palette Compression : Deflate/Inflate Filter : Adaptive Interlace : Adam7 Interlace SRGB Rendering : Perceptual Gamma : 2.2 Palette : (Binary data 219 bytes, use -b option to extract) Transparency : (Binary data 73 bytes, use -b option to extract) Pixels Per Unit X : 3779 Pixels Per Unit Y : 3779 Pixel Units : meters Image Size : 1280x720 Megapixels : 0.922
Expected behavior The PNG should render.
Desktop (please complete the following information):
- OS: [e.g. MacOS, Windows] MacOS
- Browser [e.g. chrome, safari] chrome
- React-pdf version [e.g. v1.1.0] 1.6.2
@diegomura For reference this is how jsPDF handled the issue: Issue - https://github.com/MrRio/jsPDF/issues/1452 Pull request - https://github.com/MrRio/jsPDF/pull/1455/files Latest version of png.js from jsPDF - https://github.com/MrRio/jsPDF/blob/master/src/libs/png.js
It requires a change to png-js to support interlaced files. We would need to update @react-pdf/png-js with these changes.
jsPDF is able to render this image: https://jsfiddle.net/m6unowqe/
I think it's best to replace png-js with another decoder like https://github.com/photopea/UPNG.js or https://github.com/lukeapage/pngjs.
@diegomura Is it possible for us to replace png-js here and @react-pdf/pdfkit with UPNG? I've created a PR to switch out png-js.
Any news of that issue ? THANKS!
Just a little bump on this issue. Maybe it can be implemented in v2? I also experience this issue.
I am also getting error "Invalid filter algorithm: 208" when trying to load a PNG from server as URL. I'm on v1.6.11
Is it possible to catch this error somehow? I tried:
try {
ReactPDF.render(<TestArticleImage url={url} />, '/dev/null');
} catch (error) {
console.warn(error);
}
But it does not seem to capture the error. Any ideas?
@diegomura Is it possible to replace png-js with something that supports more types of PNGs.
I'm also facing this issue "Invalid Filter Algorithm : 209". Is there any workaround.
Same here. We worked around it by converting the source image to plain non-interlaced PNG using sharp:
const convertedImage = await sharp(rawImage.data).toFormat('png').toBuffer()
It would be nice to update the underlying library tho.
If someone still doesn't know what to do, you can try this:
const convertImgToBase64URL = (url, outputFormat) =>
new Promise((resolve, reject) => {
const img = new Image();
img.crossOrigin = 'Anonymous';
img.onerror = (e) => {
reject(e);
};
img.onload = function () {
let canvas = document.createElement('CANVAS');
const ctx = canvas.getContext('2d');
let dataURL;
canvas.height = img.height;
canvas.width = img.width;
ctx.drawImage(img, 0, 0, img.width, img.height);
dataURL = canvas.toDataURL(outputFormat);
canvas = null;
resolve({ dataURL });
};
img.src = url;
});
const imageBase64 = convertImgToBase64URL('/assets/images/your_image.png');
after that just use this for image rendering:
<Image src={imageBase64.dataURL} />
It appears replacing @react-pdf/png-js with pngjs would solve this. It would also probably be a better idea from maintainability point of view.
https://npmtrends.com/@react-pdf/png-js-vs-png-js-vs-pngjs