Images from our website do not display in Safari for some Mac users and they report seeing either no image or a black image. Here is an example:
http://s3-eu-west-2.amazonaws.com/bp18.boxcleverpress.com/Boxclever_logo_chartreuse.png
What I have discovered is:
- Images display on PC
- Images display on SOME Macs (I have an older one that is OK)
- Images display on iPhones and iPads
- Images are PNG
- I have optimised the images with pngtastic
- When images are copied to the Mac and opened with Adobe Photoshop they give the error: the file format module cannot parse the file
- When I tried to open a pngtastic optimised file in Photoshop Elements on Windows I also get that error
- When I tried to open the optimised file in Photoshop on Windows I get the error IDAT: incorrect data check
I will replace the optimised images with unoptimised ones but I am not sure if this problem is with pngtastic or Adobe image libraries or something else.
2
Answers
The problem appears to be due to the use of the zopfli compression in the PNGs that I optimised using pngtastic. The workaround is to use a different pngtastic compression option and the PNGs are then readable in Photoshop.
Using a different compression algorithm will result in less optimisation.
I am not sure why the zopfli compression is a problem, it could be that there is a fault in my code (although the same code works fine when only the zopli option is changed), in pngtastic, or that MacOS and Adobe don't support zopfli.
@usr2564301 has done some investigation and it appears the Adler-32 checksum on the compressed data in my example image is incorrect. usr2564301 has also tested the pngtastic code and found it to produce the correct checksum. The problem might be in how I handle the bytestream out of pngtastic.
The code below performs the PNG optimisation using pngtastic (com.googlecode.pngtastic.core)
The problem lies in
Zopfli.java
, included by pngtastic.It uses this Java code to calculate the Adler-32 checksum:
However,
byte
s in Java are always signed, and so it may return a wrong checksum value for some data inputs. Also, the bareint
declarations fors1
ands2
cause further complications.With (my C version of) the same code and
data
explicitly declared assigned char
and boths1
ands2
assigned int
, I get a wrong checksumFFFF9180
– exactly the one in your damaged PNG.If I change the declaration to use
unsigned char
andunsigned int
, it returns the correct checksum1BCD6EB2
again.The original C code for the Adler-32 checksum in zopfli uses
unsigned
types throughout, so it’s just the Java implementation that suffers from this.