react-pdf icon indicating copy to clipboard operation
react-pdf copied to clipboard

@react-pdf/png-js doesn't support Adam 7 interlacing

Open fluke opened this issue 6 years ago • 13 comments

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 />);

Image - Noninterlaced

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

Image - Adam 7 interlacing

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

fluke avatar Aug 04 '19 05:08 fluke

@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.

fluke avatar Aug 04 '19 05:08 fluke

jsPDF is able to render this image: https://jsfiddle.net/m6unowqe/

fluke avatar Aug 04 '19 05:08 fluke

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.

fluke avatar Aug 04 '19 13:08 fluke

@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.

fluke avatar Aug 05 '19 14:08 fluke

Any news of that issue ? THANKS!

derhyl avatar Jan 03 '20 12:01 derhyl

Just a little bump on this issue. Maybe it can be implemented in v2? I also experience this issue.

geerthoekzema avatar Apr 15 '20 09:04 geerthoekzema

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

earthnoob avatar Sep 03 '20 09:09 earthnoob

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?

johann1301s avatar Sep 23 '20 13:09 johann1301s

@diegomura Is it possible to replace png-js with something that supports more types of PNGs.

fluke avatar Oct 09 '20 12:10 fluke

I'm also facing this issue "Invalid Filter Algorithm : 209". Is there any workaround.

avneeshroks avatar Oct 27 '20 06:10 avneeshroks

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.

yafanasiev avatar Feb 19 '21 16:02 yafanasiev

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} />

denis-lukin avatar Apr 16 '21 11:04 denis-lukin

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

wojtekmaj avatar Feb 06 '24 23:02 wojtekmaj