Search code examples
javaimagebufferedimagepixel

Convert 2D pixel array into BufferedImage


I used the accepted answer's code from this SO question. Now, I want to convert in back to a BufferedImage (preferably not with setRGB()). I've tried this:

private BufferedImage createImage(int[][] pixelData, BufferedImage outputImage){
    final int[] outputImagePixelData = ((DataBufferInt) outputImage.getRaster().getDataBuffer()).getData();
    System.arraycopy(pixelData, 0, outputImagePixelData, 0, pixelData.length);
    return outputImage;
}

but it doesn't work because it takes a 1D array as a parameter, not a 2D array.


Solution

  • If your outputImage has already the good type and format, then you can simply do a 2D to 1D conversion using loops (assuming your array encoding is [nbRows][RowLength]):

    private BufferedImage createImage(int[][] pixelData, BufferedImage outputImage)
        {
        int[] outputImagePixelData = ((DataBufferInt) outputImage.getRaster().getDataBuffer()).getData() ;
    
        final int width = outputImage.getWidth() ;
        final int height = outputImage.getHeight() ;
    
        for (int y=0, pos=0 ; y < height ; y++)
            for (int x=0 ; x < width ; x++, pos++)
                outputImagePixelData[pos] = pixelData[y][x] ;
    
        return outputImage;
        }
    

    But, the type INT is not really well defined in the BufferedImage. By default, you have TYPE_INT_RGB and TYPE_INT_ARGB, which concatenates the R, G, B, A values of a pixel encoding with a single INT. If you want to create a gray level BufferedImage of type INT with a single channel, then you should do:

    private BufferedImage createImage(int[][] pixelData)
        {
        final int width = pixelData[0].length ;
        final int height = pixelData.length ;
        // First I create a BufferedImage with a DataBufferInt, with the appropriate dimensions and number of channels/bands/colors
        ColorSpace myColorSpace = new FloatCS(ColorSpace.TYPE_GRAY, channel) ;
        int[] bits = new int[]{32} ;
        ColorModel myColorModel = new ComponentColorModel(myColorSpace,bits,false,false,ColorModel.OPAQUE,DataBuffer.TYPE_INT) ;
        BufferedImage outputImage = new BufferedImage(myColorModel, myColorModel.createCompatibleWritableRaster(width, height), false, null) ;
    
        int[] outputImagePixelData = ((DataBufferInt) outputImage.getRaster().getDataBuffer()).getData() ;
    
        for (int y=0, pos=0 ; y < height ; y++)
            for (int x=0 ; x < width ; x++, pos++)
                outputImagePixelData[pos] = pixelData[y][x] ;
    
        return outputImage ;
        }
    

    With FloatCS being the ColorSpace class. You have to create you own ColorSpace class when you want specific ColorSpace like Lab, HLS, etc.

    public class FloatCS extends ColorSpace
    {
    
    private static final long serialVersionUID = -7713114653902159981L;
    
    private ColorSpace rgb = ColorSpace.getInstance(ColorSpace.CS_sRGB) ;
    
    public FloatCS(int type, int channel)
        {
        super(type, channel) ;
        }
    
    
    @Override
    public float[] fromCIEXYZ(float[] pixel)
        {
        return fromRGB(rgb.fromCIEXYZ(pixel)) ;
        }
    
    @Override
    public float[] fromRGB(float[] RGB)
        {   
        return RGB ;
        }
    
    @Override
    public float[] toCIEXYZ(float[] pixel)
        {
        return rgb.toCIEXYZ(toRGB(pixel)) ;
        }
    
    @Override
    public float[] toRGB(float[] nRGB)
        {
        return nRGB ;
        }
    }