简体   繁体   中英

Manipulating pixels in binary bitmap image with DataBufferByte

I'm having trouble accessing individual pixels in a BufferedImage. My image is binary, as in black or white only. This means that each byte of the image contains 8 pixels (1 bit per pixel).

To make sure that I'm indexing the image correctly, I wrote a quick test to set all the pixels to 1 (black):

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"));
    }
}

The input image, stripes.bmp looks like: stripes.bmp

And the output is: stripes_out.bmp

I expected the image to come out all black, but there are a few rows at the bottom that weren't modified. Apparently, I'm not reaching the end of the byte buffer.

Investigating further, it looks like there are some extra bytes in the array.

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

Unfortunately, these 543 extra bytes aren't simply at the beginning, because skipping the first 543 bytes leaves a few rows unmodified at the beginning of the image.

What am I missing? How can I index the individual pixels correctly?

Each image row in the byte buffer array is byte-aligned. That means the "real" bit width of each row needs to be a multiple of 8. In your image, each row is thus rounded up to 816 bits. I assume the last 6 bits in each row are discarded.

    816 * 723 / 8 = 73746

So just round your width up to the nearest multiple of 8 and use that in your inner loop:

    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;
        }
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM