views:

511

answers:

2

Any help most appreciated, this is driving me insane. I'm doing exactly what I can find from google etc. and it's not working.

I'm having a lot of difficulty creating and writing BMP or PNG images in java. Either would do, I was going to go with BMP but I get an image which is correct in the lower section for what I want but the upper section is just a black block a lot of the time (not always).

With any other file format, including PNG, the resulting file is completely corrupted. Java says PNG, BMP and others are supported on my system according to the filetypessupported method.

If you're wondering what it's for, I'm trying to draw a representation of an area based on a robot's sensors.

And if you're wondering why I'm not using Graphics2d to draw a rectangle rather than doing it pixel by pixel, Graphics2d appears to be drawing rectangles that are bigger than what I ask for.

Here is my code for if I were to write a PNG (with a lot snipped out) and the bmp writing commented out:

private BufferedImage bufImage = null;
private ImageIO imageIO = null;
private int blobSize = 5;
private String pngPath = f.getAbsolutePath() + "test.png";
private java.io.File f = new java.io.File("");
private String bmpPath = f.getAbsolutePath() + "test.bmp";

Map(int sizeX, int sizeY){
    bufImage = new BufferedImage(sizeX, sizeY, BufferedImage.TYPE_INT_RGB);
    //set all pixels of bufImage to white
    for (int x = 0; x < sizeX; x++){
        for (int y = 0; y < sizeY; y++){
            bufImage.setRGB(x, y, Color.WHITE.getRGB());
        }
    }
    saveBMP();
}
public void addObstacle(int x, int y, int fiducial){        
    //invert y (y == 0 is upper left on bitmap)
    y = 1674 - y;

    //10*10 pixels
    for (int w = x; w < x + blobSize && w < sizeX && w >= 0 ; w++){
        for (int h = y; h < y + blobSize && h < sizeY && h >= 0; h++){
            try{
                bufImage.setRGB(w, h, Color.BLACK.getRGB());
                //System.out.println(h);
            }
            catch (ArrayIndexOutOfBoundsException e){
                System.out.println("x: " + w + " y: " + h);
            }
            //System.out.println(h);
        }
    }
    //bufImage.setRGB(x, y, Color.BLACK.getRGB());
    saveBMP();
}
public void saveBMP(){
    try {
        RenderedImage rendImage = bufImage;
        //ImageIO.write(rendImage, "bmp", new File(bmpPath));
        ImageIO.write(rendImage, "PNG", new File(pngPath));
        //ImageIO.write(rendImage, "jpeg", new File(jpegPath));
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}
+1  A: 

I don't see a problem with your approach, although I'm guessing at your calling code. Note that instead of setting pixels directly, you can draw into a buffered image. Here's a call to get(100, 100):

alt text

private BufferedImage get(int sizeX, int sizeY) {
    BufferedImage bufImage = new BufferedImage(
        sizeX, sizeY, BufferedImage.TYPE_INT_RGB);
    for (int x = 0; x < sizeX; x++) {
        for (int y = 0; y < sizeY; y++) {
            bufImage.setRGB(x, y, Color.RED.getRGB());
        }
    }
    Graphics2D g2d = bufImage.createGraphics();
    g2d.setColor(Color.green);
    g2d.fillRect(0, 0, sizeX / 2, sizeY / 2);
    g2d.fillRect(sizeX / 2, sizeY / 2, sizeX, sizeY);
    g2d.dispose();
    try {
        ImageIO.write(bufImage, "PNG", new File("test.png"));
    } catch (IOException ex) {
        ex.printStackTrace();
    }
    return bufImage;
}

Addendum: ImageIO.write(bufImage, "BMP", new File("test.bmp")); works too.

trashgod
+1  A: 

Maybe you could start with something that works and work from there?

Note that for better performances you should create a "compatible" BufferedImage:

GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration().createCompatibleImage(width,height,Transparency.TRANSLUCENT)

whose "ARGB" shall depend on your OS.

Here's a code that creates a 320x160 all white .png file based on your code.

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.image.RenderedImage;
import java.io.File;
import java.io.IOException;

public class SO {

    public static void main( final String[] args ) {
        final BufferedImage img = map( 320, 160 );
        savePNG( img, "/tmp/test.png" );
    }

    private static BufferedImage map( int sizeX, int sizeY ){
        final BufferedImage res = new BufferedImage( sizeX, sizeY, BufferedImage.TYPE_INT_RGB );
        //set all pixels of bufImage to white
        for (int x = 0; x < sizeX; x++){
            for (int y = 0; y < sizeY; y++){
                res.setRGB(x, y, Color.WHITE.getRGB() );
            }
        }
        return res;
    }

    private static void savePNG( final BufferedImage bi, final String path ){
        try {
            RenderedImage rendImage = bi;
            //ImageIO.write(rendImage, "bmp", new File(bmpPath));
            ImageIO.write(rendImage, "PNG", new File(path));
            //ImageIO.write(rendImage, "jpeg", new File(jpegPath));
        } catch ( IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

}

Note that setRGB(...) always work in ARGB so:

  res.setRGB(x, y, Color.WHITE.getRGB() );

and:

  res.setRGB(x, y, 0xFFFFFFFF );

are equivalent.

There are more efficient way to fill a solid background but knowing how to manipulate pixel ARGB components directly may come in handy once speed is needed.

Webinator