位图图像变形了

时间:2014-10-09 04:21:53

标签: java arrays bitmap rgb

// load pixels into an image
        this.image = new BufferedImage(this.width,
                                       this.height, 
                                       BufferedImage.TYPE_INT_RGB);

        // get actual image data for easier pixel loading
        byte[] iData = new byte[this.size - 54];
        for(int i = 0; i < this.size - 54; i++) {
            iData[i] = this.data[i+54];
        }

        // start from bottom row
        for(int y = this.height-1; y >= 0; y--) {
            for(int x = 0; x < this.width; x++) {
                int index = (this.width*y + x) * 3;
                int b = iData[index];
                int g = iData[index+1];
                int r = iData[index+2];

                //System.out.format("R: %s\nG: %s\nB: %s\n\n", r, g, b);

                // merge rgb values to single int
                int rgb = ((r&0x0ff)<<16)|((g&0x0ff)<<8)|(b&0x0ff); 

                // build image from bottom up
                this.image.setRGB(x, this.height-1-y, rgb);
            }
        }

我正在从Bitmap读取RGB值。我的iData字节数组是正确的,因为我已经对十六进制编辑器进行了检查。但是,当我运行此循环时,我的输出图像会变形(见图片)。我试图解决这个问题需要花费数小时才能解决这个问题,为什么会发生这种情况呢?

输入图像是加拿大国旗。

输出图片:

warped canada flag

3 个答案:

答案 0 :(得分:0)

我没有考虑宽度上的零字节填充,公式为

WidthWithPadding = ceiling((w * colorDepth)/ 32)* 32.

答案 1 :(得分:0)

图像通常具有宽度,深度(每像素位数)和步幅。通常,步幅不仅仅是宽度*深度,而是填充一定量(通常用于将每行对齐到16位边界以获得内存访问)。

您的代码似乎没有考虑步幅或任何填充,这解释了您在浏览图像时的偏移。我很惊讶颜色没有被切换(建议填充与像素的大小相同),但那些未定义的值会导致黑色条纹穿过图像。

不应将(this.width*y + x) * 3乘以获取索引,而应使用(this.stride*y + x) * 3并使用适当的stride值。 BufferedImage class似乎无法以任何明显的方式提供,因此您需要计算或获取其他内容。

答案 2 :(得分:0)

正在发生的一般问题是你的代码将宽度(行之间的距离,以字节为单位)与宽度(一行中的字节数)混为一谈;在对齐的数据格式中,这些不一定是相同的。这样做的一般结果是得到你所看到的那种倾斜,因为第二行从第一行的最后一个字节开始,第三行从倒数第二个字节开始。第二行,依此类推。

您需要做的第一件事是计算数据的步幅,并将其用作行的倍增因子。这是一个简化的循环,它比在每个像素的基础上更有效:

int stride = (this.width + 3) & ~3; // rounds up to the nearest multiple of 4
for (int y = 0; y < this.height; y++) {
    int idx = y*stride;
    for (int x = 0; x < this.width; x++) {
        int b = iData[idx++];
        int g = iData[idx++];
        int a = iData[idx++];
        // etc.
    }
}

请注意,上面的舍入技巧((w + a - 1) & ~(a - 1))仅适用于二次幂值;舍入技巧的更一般形式是:

int stride = (width + stride - 1)/stride*stride;

虽然首先找到不是2的幂的对齐是非常罕见的。