Friday 15 April 2011

java - How to create BufferedImage for 32 bits per sample, 3 samples image data -



java - How to create BufferedImage for 32 bits per sample, 3 samples image data -

i trying create bufferedimage image info byte array. image rgb format 3 samples per pixel - r, g, , b , 32 bits per sample (for each sample, not 3 samples).

now want create bufferedimage byte array. have done:

colormodel cm = new componentcolormodel(colorspace.getinstance(colorspace.cs_srgb), new int[] {32, 32, 32}, false, false, transparency.opaque, databuffer.type_int); object temparray = arrayutils.tonbits(bitspersample, pixels, samplesperpixel*imagewidth, endian == ioutils.big_endian); writableraster raster = cm.createcompatiblewritableraster(imagewidth, imageheight); raster.setdataelements(0, 0, imagewidth, imageheight, temparray); bufferedimage bi = new bufferedimage(cm, raster, false, null);

the above code works 24 bits per sample rgb image not 32 bits per sample. generated image garbage shown on right of image. supposed left side of image.

note: image reader on machine can read image imagemagick. others show similar results garbage 1 right of next image.

the arrayutils.tonbits() translates byte array int array right endianess. i'm sure 1 right have cross checked other methods generate same int array.

i guess problem might arise fact using 32 bits int represent color contain negative values. looks need long info type, there no databuffer type long.

instances of componentcolormodel created transfer types databuffer.type_byte, databuffer.type_ushort, , databuffer.type_int have pixel sample values treated unsigned integral values.

the above quote java document componentcolormodel. means 32 bit sample treated unsigned integer value. problem somewhere else.

has body met similar problem , got workaround or may have done thing wrong here?

update2: "real" problem lies in fact when 32 bit sample used, algorithm componentcolormodel shift 1 left 0 times (1<<0) since shift on int within 0~31 inclusive. not expected value. solve problem (actually shift left 32 times), thing needs done alter 1 int long type 1l shown in prepare below.

update: reply haraldk , comments, have agreed problem coming java's componentcolormodel not handling 32 bit sample correctly. proposed prepare haraldk works case too. next version:

import java.awt.transparency; import java.awt.color.colorspace; import java.awt.image.componentcolormodel; import java.awt.image.databuffer; public class int32componentcolormodel extends componentcolormodel { // public int32componentcolormodel(colorspace cs, boolean alpha) { super(cs, alpha, false, alpha ? transparency.translucent : transparency.opaque, databuffer.type_int); } @override public float[] getnormalizedcomponents(object pixel, float[] normcomponents, int normoffset) { int numcomponents = getnumcomponents(); if (normcomponents == null || normcomponents.length < numcomponents + normoffset) { normcomponents = new float[numcomponents + normoffset]; } switch (transfertype) { case databuffer.type_int: int[] ipixel = (int[]) pixel; (int c = 0, nc = normoffset; c < numcomponents; c++, nc++) { normcomponents[nc] = ipixel[c] / ((float) ((1l << getcomponentsize(c)) - 1)); } break; default: // don't think can ever come far. in case!!! throw new unsupportedoperationexception("this method has not been implemented transfertype " + transfertype); } homecoming normcomponents; } }

update:

this seems known bug: componentcolormodel.getnormalizedcomponents() not handle 32-bit type_int, reported 10 (ten!) years ago, against java 5.

the upside, java partly open-sourced. can propose patch, , luck evaluated java 9 or so... :-p

the bug proposes next workaround:

subclass componentcolormodel , override getnormalizedcomponents() handle 32 bit per sample type_int info dividing incoming pixel value 'math.pow(2, 32) - 1' when dealing data, rather using erroneous bit shift. (using floating point value ok, since getnormalizedcomponents() converts floating point anyway).

my prepare little different, basic thought same (feel free optimize see fit :-)):

private static class typeintcomponentcolormodel extends componentcolormodel { public typeintcomponentcolormodel(final colorspace cs, final boolean alpha) { super(cs, alpha, false, alpha ? translucent : opaque, databuffer.type_int); } @override public float[] getnormalizedcomponents(object pixel, float[] normcomponents, int normoffset) { int numcomponents = getnumcomponents(); if (normcomponents == null) { normcomponents = new float[numcomponents + normoffset]; } switch (transfertype) { case databuffer.type_int: int[] ipixel = (int[]) pixel; (int c = 0, nc = normoffset; c < numcomponents; c++, nc++) { normcomponents[nc] = ((float) (ipixel[c] & 0xffffffffl)) / ((float) ((1l << getcomponentsize(c)) - 1)); } break; default: throw new unsupportedoperationexception("this method has not been implemented transfertype " + transfertype); } homecoming normcomponents; } }

consider below code. if run is, me displays black image, upper right quarter white overlayed black circle. if alter datatype type_ushort (uncomment transfertype line), displays half/half white , linear gradient black white, orange circle in middle (as should).

using colorconvertop convert standard type seems create no difference.

public class int32image { public static void main(string[] args) { // define dimensions , layout of image int w = 300; int h = 200; int transfertype = databuffer.type_int; // int transfertype = databuffer.type_ushort; colormodel colormodel = new componentcolormodel(colorspace.getinstance(colorspace.cs_srgb), false, false, transparency.opaque, transfertype); writableraster raster = colormodel.createcompatiblewritableraster(w, h); bufferedimage image = new bufferedimage(colormodel, raster, false, null); // start linear gradient if (raster.gettransfertype() == databuffer.type_int) { databufferint buffer = (databufferint) raster.getdatabuffer(); int[] info = buffer.getdata(); (int y = 0; y < h; y++) { int value = (int) (y * 0xffffffffl / h); (int x = 0; x < w; x++) { int offset = y * w * 3 + x * 3; data[offset] = value; data[offset + 1] = value; data[offset + 2] = value; } } } else if (raster.gettransfertype() == databuffer.type_ushort) { databufferushort buffer = (databufferushort) raster.getdatabuffer(); short[] info = buffer.getdata(); (int y = 0; y < h; y++) { short value = (short) (y * 0xffffl / h); (int x = 0; x < w; x++) { int offset = y * w * 3 + x * 3; data[offset] = value; data[offset + 1] = value; data[offset + 2] = value; } } } // paint (in color) graphics2d g = image.creategraphics(); g.setcolor(color.white); g.fillrect(0, 0, w / 2, h); g.setcolor(color.orange); g.filloval(100, 50, w - 200, h - 100); g.dispose(); system.out.println("image = " + image); // image = new colorconvertop(null).filter(image, new bufferedimage(image.getwidth(), image.getheight(), bufferedimage.type_int_argb)); jframe frame = new jframe(); frame.add(new jlabel(new imageicon(image))); frame.pack(); frame.setlocationrelativeto(null); frame.setvisible(true); } }

to me, seems suggest there's wrong colormodel using transfertype type_int. i'd happy wrong. ;-)

another thing try, scale values downwards 16 bit, utilize type_ushort raster , color model, , see if makes difference. bet will, i'm lazy try. ;-)

java image rgb bufferedimage 32-bit

No comments:

Post a Comment