Mac Safari

时间:2017-04-20 17:46:10

标签: macos safari png photoshop zopfli

我们网站上的图片不会在Safari中显示给某些Mac用户,他们会报告看不到图像或黑色图像。这是一个例子:

http://s3-eu-west-2.amazonaws.com/bp18.boxcleverpress.com/Boxclever_logo_chartreuse.png

我发现的是:

  • 在PC上显示图像
  • 在某些Mac上显示图像(我有一个较旧的可以)
  • iPhone和iPad上的图像显示
  • 图片为PNG
  • 我用pngtastic
  • 优化了图像
  • 将图像复制到Mac并使用Adobe Photoshop打开时,会出现错误:文件格式模块无法解析文件
  • 当我尝试在Windows上的Photoshop Elements中打开一个pngtastic优化文件时,我也会收到该错误
  • 当我尝试在Windows上的Photoshop中打开优化文件时,我收到错误IDAT:错误的数据检查

我将用未经优化的图像替换优化的图像,但我不确定这个问题是否与pngtastic或Adobe图像库或其他内容有关。

2 个答案:

答案 0 :(得分:2)

问题在于Zopfli.java,包含在pngtastic中。

它使用此Java代码计算Adler-32校验和:

/**
 * Calculates the adler32 checksum of the data
 */
private static int adler32(byte[] data) {
    int s1 = 1;
    int s2 = 1 >> 16;
    int i = 0;
    while (i < data.length) {
        int tick = Math.min(data.length, i + 1024);
        while (i < tick) {
            s1 += data[i++];
            s2 += s1;
        }
        s1 %= 65521;
        s2 %= 65521;
    }

    return (s2 << 16) | s1;
}

但是,Java中的bytealways signed,因此它可能会为某些数据输入返回错误的校验和值。此外,ints1的裸s2声明会导致进一步的复杂化。

使用(我的C版本)相同的代码,data明确声明为signed chars1s2同为signed int,我得到了错误的校验和FFFF9180 - 正好是损坏的PNG中的那个。

如果我更改声明以使用unsigned charunsigned int,则会再次返回正确的校验和1BCD6EB2

zopfli中Adler-32校验和的original C code始终使用unsigned类型,因此只是Java实现受此影响。

答案 1 :(得分:1)

问题似乎是由于我使用pngtastic优化的PNG中使用了zopfli压缩。解决方法是使用不同的pngtastic压缩选项,然后在Photoshop中可以读取PNG。

使用不同的压缩算法将导致更少的优化。

我不确定为什么zopfli压缩是一个问题,可能是我的代码中存在错误(尽管只有zopli选项被更改时相同的代码才能正常工作),pngtastic,或者MacOS和Adobe不支持zopfli。

@ usr2564301做了一些调查,看来我示例图片中压缩数据的Adler-32校验和不正确。 usr2564301还测试了pngtastic代码并发现它产生了正确的校验和。问题可能在于我如何处理pngtastic中的字节流。

下面的代码使用pngtastic执行PNG优化(com.googlecode.pngtastic.core)

public static final String OPT_ZOPFLI = "zopfli";
public static final String OPT_DEFAULT = "default";
public static final String OPT_IMAGEOPTIM = "imageoptim";

private String optimization = OPT_ZOPFLI;

public void optimizePng(File infile, String out) {

     final InputStream in;
     try {
         in = new BufferedInputStream(new FileInputStream(infile));
         final PngImage image = new PngImage(in);

         // optimize
         final PngOptimizer optimizer = new PngOptimizer();

         optimizer.setCompressor(optimization, 1);
         final PngImage optimizedImage = optimizer.optimize(image, false, 9);

         // export the optimized image to a new file
         final ByteArrayOutputStream optimizedBytes = new ByteArrayOutputStream();
         optimizedImage.writeDataOutputStream(optimizedBytes);
         optimizedImage.export(out, optimizedBytes.toByteArray());

       } catch (FileNotFoundException e) {
         e.printStackTrace();
     } catch (IOException e) {
         e.printStackTrace();
     }
 }