PhilterPaper / Perl-PDF-Builder

Extended version of the popular PDF::API2 Perl-based PDF library for creating, reading, and modifying PDF documents
https://www.catskilltech.com/FreeSW/product/PDF%2DBuilder/title/PDF%3A%3ABuilder/freeSW_full
Other
6 stars 7 forks source link

[RT 124349] Slow RGBA PNG processing performance #85

Closed PhilterPaper closed 6 years ago

PhilterPaper commented 6 years ago

Subject: | Slow RGBA PNG processing performance Date: | Wed, 7 Feb 2018 10:34:55 +0000 To: | bug-PDF-API2 [...] rt.cpan.org From: | Dusan Vuckovic <dusan.vuckovic [...] otrs.com>

Hello,

I'm having performance issues with RGBA PNG files, when they are processed by the image_png() method.

I'm supplying two screenshot files as a reproduction sample: one is plain RGB, the other one has an alpha channel as well.

$ file screenshot-rgb.png screenshot-rgb.png: PNG image data, 2400 x 1800, 8-bit/color RGB, non-interlaced $ time perl -e 'use PDF::API2; PDF::API2->new()->image_png("screenshot-rgb.png")' real 0m0.174s user 0m0.140s sys 0m0.022s $ file screenshot-rgba.png screenshot-rgba.png: PNG image data, 2400 x 1800, 8-bit/color RGBA, non-interlaced $time perl -e 'use PDF::API2; PDF::API2->new()->image_png("screenshot-rgba.png")' real 0m40.619s user 0m40.412s sys 0m0.134s

The difference in time needed to process both files is staggering. Is there any possibility to speed this up? The difference in file size is less than 30kB.

Distribution: PDF-API2-2.033 Perl version: 5.18.2 OS: Mac OS 10.13.3 (Darwin Kernel Version 17.4.0)

Thank you for your help! Regards, Dusan screenshot-rgb screenshot-rgba

PhilterPaper commented 6 years ago

Sat Jun 02 17:51:45 2018 steve [...] deefs.net - Correspondence added

I'm sure it's possible. The relevant code is in PDF/API2/Resource/XObject/Image/PNG.pm, which implements its own PNG parser. For anyone who'd like to take this on, here are a couple possible solutions:

1) Parsing could be delegated to another pure-Perl module where PNGs are the main focus (if one exists -- there are a bunch of modules in the Image::PNG namespace), or you can try profiling the code to see if there are any obvious optimizations that could be made.

2) The code could be modified to check to see if libpng (or a Perl module that relies on it) is present, and use that instead, if it exists. I don't want to add a non-Perl dependency requirement, but it's fine to use one if it's there.

-- Steve

On Wed Feb 07 05:42:16 2018, dusan.vuckovic@otrs.com wrote: Show quoted text # Sat Jun 02 17:51:46 2018 The RT System itself - Status changed from 'new' to 'open' # Sat Jun 02 17:52:03 2018 steve [...] deefs.net - Severity Wishlist added

PhilterPaper commented 6 years ago

If users are experiencing such slowdowns on anything but a few edge cases, I would call it a bug rather than an enhancement ("wishlist") item. The current PNG code should certainly be examined to see if there are any reasonable fixes that could be made, and optionally make use of libpng or other such libraries if they offer a big improvement. Taking over 200 times as long when the "A" channel is used (transparency) is ridiculous, and hopefully there's a glaring error in there that could be fixed.

PhilterPaper commented 6 years ago

I have just added changes to PDF::Builder to make use of Image::PNG::Libpng (a wrapper around the libpng.a library) if it is installed. The functionality given is:

  1. noticeable speedup of the specified cases (more than 4 times faster in the RGBA sample)
  2. 16bps RGB, RGBA, gray, and gray+Alpha now usable
  3. interlaced PNG images can be handled

Image::PNG::Libpng is not required -- the old PNG library is still offered (without the new functionality). Users may specify that the old PNG library be used instead of the new one (PNG_IPL), if desired, in the same manner as TIFF with Graphics::TIFF.

I am still looking for a library or better Perl code to split out the Alpha channel from the RGB or Gray channel, in order to speed it up even more. Currently the code uses the vec() call to do this. I have tried several other things, including pack(..., unpack(...)), which was quite a bit slower. If anyone has suggestions on how to do this, I would welcome them. In the mean time, I'll close this ticket.