java - BufferedImage bytes have a different byte order, when running from Eclipse and the command line -


i trying convert bufferedimage's byte[] 32-bit rgba 24-bit rgb. according this answer fastest way byte[] image is:

byte[] pixels = ((databufferbyte) bufferedimage.getraster().getdatabuffer()).getdata(); 

so iterate on bytes assuming order r g b , every 4 bytes, write first 3 in output byte[] (i.e. ignoring alpha value).

this works fine when run eclipse , bytes converted correctly. when run same program command line same bytes returned opposite byte order!

the test image use test 5x5 black image top-left corner different having rgba color [aa cc ee ff]: test image 5x5

and zoomed-in version conveniency:

zoomed-in test image

my folder structure is:

- src/     - test.png   - test/       - testbufferedimage.java   

the sscce following:

package test;  import java.awt.image.bufferedimage; import java.awt.image.databufferbyte; import java.io.ioexception; import java.io.inputstream;  import javax.imageio.imageio;  public class testbufferedimage {    private static void log(string s) {     system.out.println(s);   }    private static string tobytestring(byte b) {     // perform bitwise , convenience while printing.      // otherwise integer.tohexstring() interprets values integers , negative byte 0xff printed "ffffffff"     return integer.tohexstring(b & 0xff);   }    /**    * @param args    * @throws ioexception     */   public static void main(string[] args) throws ioexception {      inputstream stream = testbufferedimage.class.getclassloader().getresourceasstream("test.png");     bufferedimage image = imageio.read(stream);     stream.close();     log("image loaded succesfully, width=" + image.getwidth() + " height=" + image.getheight());      log("converting 32-bit 24-bit...");     databufferbyte buffer = (databufferbyte)image.getraster().getdatabuffer();      byte[] input = buffer.getdata();     byte[] output = convertto24bit(input);     log("converted total of " + input.length + " bytes " + output.length + " bytes");   }    private static byte[] convertto24bit(byte[] input) {     int datalength = input.length;     byte[] converteddata = new byte[ datalength * 3 / 4 ];      (int = 0, j = 0; < datalength; i+=4, j+=3) {       convertintbytetobyte(input, i, converteddata, j);     }     return converteddata;   }    private static void convertintbytetobyte(byte[] src, int srcindex, byte[] out, int outindex) {     byte r = src[srcindex];     byte g = src[srcindex+1];     byte b = src[srcindex+2];     byte = src[srcindex+3];      out[outindex] = r;     out[outindex+1] = g;      out[outindex+2] = b;       log("i=" + srcindex          + " converting [" + tobytestring(r) + ", " + tobytestring(g)          + ", " + tobytestring(b) + ", " + tobytestring(a) + "] --> ["         + tobytestring(out[outindex]) + ", " + tobytestring(out[outindex+1])         + ", " + tobytestring(out[outindex+2]) + "]"         );   }  } 

output when run eclipse (version: juno service release 2 build id: 20130225-0426):

image loaded succesfully, width=5 height=5 converting 32-bit 24-bit... i=0 converting [aa, cc, ee, ff] --> [aa, cc, ee]   // <-- bytes have correct order i=4 converting [0, 0, 0, ff] --> [0, 0, 0] i=8 converting [0, 0, 0, ff] --> [0, 0, 0] ..... i=96 converting [0, 0, 0, ff] --> [0, 0, 0] converted total of 100 bytes 75 bytes 

output when run command line (windows vista) java test.testbufferedimage:

image loaded succesfully, width=5 height=5 converting 32-bit 24-bit... i=0 converting [ff, ee, cc, aa] --> [ff, ee, cc]    // <-- bytes returned different byte order! i=4 converting [ff, 0, 0, 0] --> [ff, 0, 0] i=8 converting [ff, 0, 0, 0] --> [ff, 0, 0] ..... i=96 converting [ff, 0, 0, 0] --> [ff, 0, 0] converted total of 100 bytes 75 bytes 

so has encountered similar issue and/or can explain going on? why byte order different when running inside eclipse?

before answering own question really, really, thank @joni , @haraldk pointed me right direction. knowledge internals of bufferedimage, colormodel, samplemodel , not great have helped me out.

so here happened:

first of different behaviour caused different jres. log statement printing java version revealed eclipse prints 1.6.0_16-b01 while command line prints 1.6.0_31-b05. apparently implementation of image loading (this pngimagereader class) has changed between versions , suspect did during this change.

still though both versions use same colormodel , samplemodel couldn't understand change (it seemed real code-breaker me) have investigated further.

the important change between 2 versions of pngimagereader in iterator<imagetypespecifier> getimagetypes() method decides available compatible formats can used create new image:

version 1.6.0_16-b01:

... case png_color_rgb_alpha:     // component r, g, b, (non-premultiplied)     rgb = colorspace.getinstance(colorspace.cs_srgb);     bandoffsets = new int[4];     bandoffsets[0] = 0;     bandoffsets[1] = 1;     bandoffsets[2] = 2;     bandoffsets[3] = 3;      l.add(imagetypespecifier.createinterleaved(rgb,                                                bandoffsets,                                                datatype,                                                true,                                                false));     break; 

version 1.6.0_31-b05:

... case png_color_rgb_alpha:     if (bitdepth == 8) {         // standard types of buffered images         // wich can used destination         l.add(imagetypespecifier.createfrombufferedimagetype(                                            bufferedimage.type_4byte_abgr));          l.add(imagetypespecifier.createfrombufferedimagetype(                                            bufferedimage.type_int_argb));     }      // component r, g, b, (non-premultiplied)     rgb = colorspace.getinstance(colorspace.cs_srgb);     bandoffsets = new int[4];     bandoffsets[0] = 0;     bandoffsets[1] = 1;     bandoffsets[2] = 2;     bandoffsets[3] = 3;      l.add(imagetypespecifier.createinterleaved(rgb,                                                bandoffsets,                                                datatype,                                                true,                                                false));     break; 

so in newer version, new imagetypespecifiers png loader compatible image internal representation bufferedimage.type_4byte_abgr , since first type in list, loader goes ahead , uses that. why bands color channels (and bytes) reversed.

realizing above, hit me not bug nor code breaker thought. reason because using byte[] pixels = ((databufferbyte) bufferedimage.getraster().getdatabuffer()).getdata(); bytes hacking way internal data structures (i.e. ignoring samplemodel) of image. nothing in contract of imagereader guarantees order of bytes. free change internal data stuctures if wants (this point of encapsulation right?). way correctly configure imagereader if desire else default behaviour default imagereadparam , configure it. pass reader using reader.read(imageindex, param);

since want reader return specific format image bytes should this:

log("java version: " + system.getproperty("java.runtime.version"));  // reader imagereader ir = imageio.getimagereadersbyformatname("png").next();  // default param     imagereadparam p = ir.getdefaultreadparam(); p.setdestinationtype(     // define image type return if supported     imagetypespecifier.createinterleaved(         colorspace.getinstance(colorspace.cs_srgb),          new int[] {0, 1, 2, 3},    // <-- order of color bands return bytes in desired order         databuffer.type_byte,         true, false)         );  inputstream stream = testbufferedimage.class.getclassloader().getresourceasstream("test.png");  imageinputstream imagestream = imageio.createimageinputstream(stream); ir.setinput(imagestream); bufferedimage image = ir.read(0, p);  

now both versions return order of bytes in same rgba form i.e. output different color print in both cases:

... i=0 converting [aa, cc, ee, ff] --> [aa, cc, ee]  ... 

Comments

Popular posts from this blog

image - ClassNotFoundException when add a prebuilt apk into system.img in android -

I need to import mysql 5.1 to 5.5? -

Java, Hibernate, MySQL - store UTC date-time -