使用DataBufferByte处理二进制位图图像中的像素

时间:2013-08-15 20:26:09

标签: java image

我无法访问BufferedImage中的单个像素。我的图像是二进制的,只有黑色或白色。这意味着图像的每个字节包含8个像素(每像素1位)。

为了确保我正确索引图像,我写了一个快速测试,将所有像素设置为1(黑色):

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;
import java.io.File;

public class ImageTest {
    public static void main(String... args) throws Exception {
        File input = new File("stripes.bmp");
        final BufferedImage image = ImageIO.read(input);
        System.out.println(image);

        byte[] byte_buffer = ((DataBufferByte) image.getRaster().getDataBuffer()).getData();

        final int width = image.getWidth(), height = image.getHeight();

        for (int j = 0; j < height; j++) {
            for (int i = 0; i < width; i++) {
                int byte_index = (i + j * width) / 8;
                int bit_index = (i + j * width) % 8;
                byte_buffer[byte_index] |= 1 << bit_index;
            }
        }

        ImageIO.write(image, "bmp", new File("stripes_out.bmp"));
    }
}

输入图像,stripes.bmp看起来像: stripes.bmp

输出是: stripes_out.bmp

我希望图像全黑,但底部有几行未修改。显然,我没有到达字节缓冲区的末尾。

进一步研究,看起来数组中有一些额外的字节。

width = 810, height = 723
-> width * height / 8 = 73203
byte_buffer.length = 73746

不幸的是,这些543个额外字节不仅仅是在开头,因为跳过前543个字节会在图像开头不加修改几行。

我错过了什么?如何正确索引各个像素?

1 个答案:

答案 0 :(得分:3)

字节缓冲区数组中的每个图像行都是字节对齐的。这意味着每行的“实际”位宽需要是8的倍数。在图像中,每行向上舍入为816位。我假设每行中的最后6位被丢弃。

    816 * 723 / 8 = 73746

因此,只需将宽度调整到最接近的8的倍数,然后在内循环中使用它:

    final int width = image.getWidth(),
              height = image.getHeight(),
              rowBitWidth = ((width + 7) / 8) * 8;

    for (int j = 0; j < height; j++) {
        for (int i = 0; i < width; i++) {
            int byte_index = (i + j * rowBitWidth) / 8;
            int bit_index = (i + j * rowBitWidth) % 8;
            byte_buffer[byte_index] |= 1 << bit_index;
        }
    }