Details
-
Bug
-
Status: Resolved
-
Major
-
Resolution: Fixed
-
2.3
-
None
-
None
Description
TL;NR
When using palette-based transparency via tRNS chunk in PNG images, the generated PDFs are broken.
palette-based with transparency.
8.5.2. Palette-Based with Transparency
"The PNG spec forbids the use of a full alpha channel with palette-based images, but it does allow `cheap alpha` via the transparency chunk, tRNS [...] In effect, it transforms the palette from an RGB lookup table to an RGBA table [...] a single PNG transparency entry should come first"
http://www.libpng.org/pub/png/book/chapter08.html#png.ch08.div.5.2
general PDF encoding strategy
Option 1:
most libraries just undo the palettization and use a full color image + mask.
https://forums.adobe.com/message/6148131#6148131
Option 2:
SMask would be simpler since you could leave the palette in place
https://forums.adobe.com/message/6148557#6148557
what does FOP do
It creates a chroma-key mask:
/Type /XObject /ColorSpace [/Indexed /DeviceRGB 255 <D9DB ...>] /Mask [182 182 151 151 158 158]
Acrobat Reader even fails to read those files while PDF viewers embedded into Chrome/Firefox read the file, but show visual glitches:
https://github.com/apache/fop/pull/49 fixes the Acrobat Reader error.
FOP doesn't implement Option 1 yet. None of the ImageLoaders is prepared to do that:
https://wiki.apache.org/xmlgraphics-fop/HowTo/ImageLoaderRawPNG
In fact the following results in missing Option 2:
public void setup(PDFDocument doc) { RenderedImage ri = getImage().getRenderedImage(); // code deleted Raster raster = GraphicsUtil.getAlphaRaster(ri); if (raster != null) { AlphaRasterImage alphaImage = new AlphaRasterImage("Mask:" + getKey(), raster); this.softMask = doc.addImage(null, alphaImage).makeReference(); }
In the above code raster will be null and therefore FOP fails to initialize a softMask. GraphicsUtil.getAlphaRaster() calls internally ColorModel.getAlphaRaster(), which returns null:
If this is an IndexColorModel which has alpha in the lookup table, this method will return null since there is no spatially discrete alpha channel.
https://docs.oracle.com/javase/8/docs/api/index.html?java/awt/image/ColorModel.html
The softMask Issue is fixed by:
https://github.com/apache/fop/pull/50
As a result an image such as is rendered with a transparency gradient instead of
This code will then add the chroma key mask to the image:
protected void populateXObjectDictionaryForIndexColorModel(PDFDictionary dict, IndexColorModel icm) { // code deleted Integer index = getIndexOfFirstTransparentColorInPalette(icm); if (index != null) { PDFArray mask = new PDFArray(dict); mask.add(index); mask.add(index); dict.put("Mask", mask); } }
why care to support?
Libraries such as pngquant optimize images for web usage and low footprint and can not be used directly with Apache FOP as source images:
"pngquant: Lossy PNG optimizer, reducing a PNG image down to an 8 bit color palette with dithering. It will build indexed-color PNG's with alpha transparency colors conveyed in the tRNS chunk."
https://imagemagick.org/Usage/formats/#png_non-im
sample data
$ identify -verbose sample_image_palette_tRNS.png Format: PNG (Portable Network Graphics) Type: PaletteAlpha png:IHDR.color_type : 3 (Indexed) png:tRNS : chunk was found
Attachments
Attachments
Issue Links
- relates to
-
FOP-2512 java.lang.NullPointerException: Parameter alpha must not be null
- Closed