0
votes

So I've finally written code to detect all the correct RGB values for my bitmap, and store them.

BufferedImage image = new BufferedImage(adjWidth, 
                                        this.height, 
                                        BufferedImage.TYPE_3BYTE_BGR);

// start from bottom row
for(int i = this.height-1; i >= 0; i--) {
    for(int j = 0; j < adjWidth-2; j += 3) {
        int index = adjWidth*i + j;
        int b = iData[index];
        int g = iData[index+1];
        int r = iData[index+2];
        int rgb = ((r&0x0ff)<<16)|((g&0x0ff)<<8)|(b&0x0ff); // merge rgb values to single int
        /*
        System.out.printf("\nRow: %s\nColumn: %s\nRed: %s\n"
                            + "Green: %s\nBlue: %s\n", i, j, 
                            (rgb>>16)&0x0ff, (rgb>>8)&0x0ff, (rgb)&0x0ff);
        System.out.println("Color value: " + rgb);
        */
        // build image from bottom up
        image.setRGB(j, this.height-i-1, rgb);
    }
}

iData is a byte[] read from the file. I know my RGB values are correct after debugging their values, and also comparing them against a hex editor. AdjWidth is the width including padding.

However, my image is outputting with vertical black bands all along the image. I know the image is partially correct when I compare it to the source image, albeit it being a little distorted, but I think all of that sources from this problem. I suspect this is because j is being incremented by 3, so when I set the pixel value, it skips those pixels. How can I avoid this, and create the correct image?

Input bmp: Input

Output bmp: Output

edit I'm doing this as an exercise, by the way.

1
why don't you use ImageIO.read()?UniversE
I'm doing this as an exercise.Tetramputechture
are you sure, the source image is in bgr 24bit format? And why is your target BufferedImage in 3BYTE_BGR and not INT_RGB or INT_ARGB?UniversE
Yes I am, because I've read the header correctly. Because I thought bitmaps stored their pixels in 3 byte BGR format? Nevertheless, changing the format to INT_RGB changes nothing.Tetramputechture
"I know java has native bmp support." Actually no, Java has no BMP support.icza

1 Answers

2
votes

It may lack a bit of code and further explaination, but: You have an array containing 3 values for each pixel. So you are incrementing with j+=3 in the inner loop. However, the output image should only receive one pixel for each triple of values.

So you could probably either use

image.setRGB(j/3, this.height-i-1, rgb);

or let the loop run over the size of the output image, and multiply the coordinates with 3 when accessing the array, roughly like this:

for(int j = 0; j < adjWidth-2; j++) {
    int index = (adjWidth*i + j) * 3;
    int b = iData[index];
    int g = iData[index+1];
    int r = iData[index+2];
    ...
    image.setRGB(j, this.height-i-1, rgb);
}

EDIT: Although it's a bit pointless to create an array and fill it with pixels, just in order to create an image that is filled with the same data: This program fills the bgr array with BGR pixel values that are supposed to extend from black to blue horizontally, and from black to green vertically. This array is then used to create an image, which shows exactly these gradients. Maybe this example will help anyhow.

import java.awt.image.BufferedImage;

import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;

public class ImagePixelsTest {
    public static void main(String[] args) {

        int w = 256;
        int h = 256;
        byte bgr[] = new byte[w * h * 3];
        for (int y = 0; y < h; y++) {
            for (int x = 0; x < w; x++) {
                int index = (y * w + x) * 3;
                bgr[index + 0] = (byte) x;
                bgr[index + 1] = (byte) y;
                bgr[index + 2] = 0;
            }
        }

        final BufferedImage image = createImage(w, h, bgr);
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                JFrame f = new JFrame();
                f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                f.getContentPane().add(new JLabel(new ImageIcon(image)));
                f.pack();
                f.setLocationRelativeTo(null);
                f.setVisible(true);
            }
        });
    }

    private static BufferedImage createImage(int w, int h, byte bgr[]) {
        BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_3BYTE_BGR);

        for (int y = h - 1; y >= 0; y--) {
            for (int x = 0; x < w; x++) {
                int index = (y * w + x) * 3;
                int b = bgr[index + 0];
                int g = bgr[index + 1];
                int r = bgr[index + 2];
                int rgb = ((r & 0x0ff) << 16) | ((g & 0x0ff) << 8) | (b & 0x0ff);
                image.setRGB(x, y, rgb);
            }
        }
        return image;
    }

}