【问题标题】:Java ImageIO PNG Encoding Incorrectly?Java ImageIO PNG编码不正确?
【发布时间】:2014-01-29 09:49:20
【问题描述】:

我一直在尝试使用 Java 以 PNG 图像格式对一些数据(表示为字节值 0-255 的数组)进行编码。使用 JavaScript 中的 HTML canvas 元素 getImageData() 方法读取数据(类似于:http://blog.nihilogic.dk/2008/05/compression-using-canvas-and-png.html)。

但是,输出数据并不总是与输入相同。某些值似乎与输入不同。它似乎可以编码为 1 像素高的图像,并且仅对于具有多行的图像是不正确的。我认为这可能是由于对 PNG 图像进行逐行过滤造成的,但我真的不知道。

似乎每个不正确的值只有 1 或 2 个错误。

这是 Java 代码,但我想知道它是否也可能是 ImageIO api 的问题,尤其是它的 PNG 编码器?

public static File encodeInPng(byte[] data, String filename) throws java.io.IOException{
    int width = (int)Math.ceil(Math.sqrt(data.length));
    int height = (int)Math.ceil((double)data.length/width);

    BufferedImage bufImg = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY);

    int x = 0, y = 0;
    for (byte b : data) {
        bufImg.getRaster().setPixel(x, y, new int[]{b&0xFF});
        x++;
        if (x == width) {
            x = 0;
            y ++;
        }
    }

    File f = new File(filename);
    ImageIO.write(bufImg, "png", f);

    return f;
}

编辑:该问题仅出现在特定大小(大约 50 kB,或可能为 256x256px)的 PNG 文件中。

【问题讨论】:

  • 嗯,我认为您真的不想标记 JavaScript。已删除。
  • y = 0; 似乎是一个错误。也许你的意思是x = 0;
  • 你是对的,虽然原始代码是正确的(我在发布时更改了一些 var 名称以提高可读性)。
  • 你确定width * height 在这种情况下总是 == data.length 吗?您是否总是创建data 数组以适应方形图像(2x2、3x3、..、NxN)?否则你计算widthheight的代码是错误的。
  • @haraldK:图像大小宽度高度应始终> = datasize,看来OP选择了一个正方形是为了方便。除非Math.sqrt 做了一些*真的 讨厌的四舍五入平方根,否则计算似乎是正确的。然而!即使图像大小关闭,它也不会显示 OP 报告的内容。所有太小的图像尺寸都应该在最后显示一些数据丢失。

标签: java png javax.imageio


【解决方案1】:

尺寸的计算相当丑陋,代码的某些部分可能会稍微更有效和更简洁——下面会进行一些改进。但是您的代码似乎基本正确,并且对我有用。你能举一个“输出数据与输入不同”的例子吗?

public static File encodeInPng(byte[] data, String filename) 
         throws java.io.IOException {
    int width = (int) Math.ceil(Math.sqrt(data.length));
    int height = data.length / width;
    BufferedImage bufImg = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY);
    int[] pix = new int[1];
    int pos = 0;
    for( int y = 0; y < height; y++ ) {
        for( int x = 0; x < width; x++ ) {
            pix[0] = data[pos++] & 0xFF;
            bufImg.getRaster().setPixel(x, y, pix);
        }
    }
    File f = new File(filename);
    ImageIO.write(bufImg, "png", f);
    return f;
}

【讨论】:

  • 计算height = (data.length+width-1) / width 是否(稍微)更安全?然后你确定目标缓冲区足够大。目前,如果data.length % width &gt; 0,你会错过一整行,不是吗?但是,是的,我想看看带有简单消息编码的 PNG。
【解决方案2】:

好的,所以我发现问题只发生在大于 256x256 的图像上。我做了一些研究,发现了人们在 Chrome 中遇到的现有(尽管不同)问题(使用 canvas 元素和这个大小的图像)。所以我尝试使用Firefox,没有错误!

Chrome 的画布元素似乎远非完美。

[使用 Chrome 版本 32.0.1700.77]

编辑:另外,设置 chrome://flags“禁用加速的 2D 画布”使其在 Chrome 中工作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-12-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-06
    相关资源
    最近更新 更多