【问题标题】:Bitmap image coming out warped位图图像变形
【发布时间】:2014-10-09 04:21:53
【问题描述】:
// 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);
            }
        }

我正在从位图中读取 RGB 值。我的 iData 字节数组是正确的,因为我已经对照十六进制编辑器对其进行了检查。但是,当我运行这个循环时,我的输出图像会变形(见图)。为了解决这个问题,我已经绞尽脑汁好几个小时了,为什么会这样?

输入图像是加拿大国旗。

输出图像:

【问题讨论】:

  • 您的输入文件是否有 4 字节对齐的行?某些格式会在每行的末尾添加填充,以使每行的长度为 4 字节的倍数。
  • 因为你可能没有考虑到这一点。
  • @Tetramputechture 这意味着你需要使用不同的值来乘以y。
  • 你没事,我已经解决了。这一切都源于我认为我不需要调整后的宽度,所以我将它从循环中删除,但我的调试方法不正确,所以我没有看到结果。谢谢,伙计们。

标签: java arrays bitmap rgb


【解决方案1】:

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

WidthWithPadding = 天花板((w*colorDepth)/32)*32.

【讨论】:

    【解决方案2】:

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

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

    而不是乘以(this.width*y + x) * 3 来获得您的索引,您应该使用(this.stride*y + x) * 3 和适当的步幅值。 BufferedImage class 似乎没有以任何明显的方式提供,因此您需要计算或获取它。

    【讨论】:

      【解决方案3】:

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

      您需要做的第一件事是计算数据的步长,并将其用作行的乘法因子。这是一个简化的循环,它也比逐像素相乘更有效:

      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) &amp; ~(a - 1)) 仅适用于二次幂值;舍入技巧的更一般形式是:

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-24
        • 2021-10-30
        • 1970-01-01
        • 2017-09-15
        • 2020-01-15
        相关资源
        最近更新 更多