7 Replies Latest reply: Jul 10, 2009 2:47 PM by 807588 RSS

    How do I specify 16bit R5G6B5 pixels when creating a BufferedImage?

    807588
      Hello All,

      I'm trying to load raster data from an image file and it may contain different bit depths. I'm loading this data into a BufferedImage using the constructor

      BufferedImage(ColorModel cm, WritableRaster raster, boolean isRasterPremultiplied, Hashtable<?,?> properties)

      I'm trying to figure out how to specify the exact way the pixels are stored, but I'm having a really hard time. It seems that I would want to put this information in the ColorModel, but I can't find anything to specify that. The WritableRaster is another place I looked, but when I create that, it also doesn't ask for (or I don't know how to provide) the specific color info. I have a file that stores it's pixel data in 16 bits, but the colors are separated out by Red (5bits) Green(6bits) Blue(5bits). I have the hex color masks for the color, but I don't know how to use them without first creating a BufferedImage, then using a PixelGrabber or other such process for editing the pixels after the fact. I'd like to be able to specify the the info when I create the image. Can anybody help me?

      Thank you!
        • 1. Re: How do I specify 16bit R5G6B5 pixels when creating a BufferedImage?
          807588
          Hi Quasi_Stomach,

          After you've load your picture in the [*BufferedImage*|http://java.sun.com/javase/6/docs/api/java/awt/image/BufferedImage.html] , just create a new BufferedImage instance using the BufferedImage(int width, int height, int imageType) constructor (use the BufferedImage.TYPE_USHORT_565_RGB as imageType parameter). Then, you will have to proceed using the methods getRGB/setRGB.

          Also, when you build your first instance of BufferedImage, just use the [*ImageIO*|http://java.sun.com/javase/6/docs/api/javax/imageio/ImageIO.html] API if you're working with an image file.

          Simply :
          BufferedImage buffer = ImageIO.read(new File(C:\\Temp\\myPicture.jpg));
          Edited by: Chicon on Jul 9, 2009 8:44 PM

          Edited by: Chicon on Jul 9, 2009 8:53 PM
          • 2. Re: How do I specify 16bit R5G6B5 pixels when creating a BufferedImage?
            807588
            ColorModel cm = new DirectColorModel(15, 0xF800, 0x7E0, 0x1F);
            Double check those masks.
            • 3. Re: How do I specify 16bit R5G6B5 pixels when creating a BufferedImage?
              807588
              Wow! I can't believe I missed the DirectColorModel. I was trying to use a ComponentColorModel. Thanks so much!
              Now I've run into another problem. Should I not be using an InterleavedRaster via

              Raster.createInterleavedRaster(DataBuffer dataBuffer, int w, int h, int scanlineStride, int pixelStride, int[] bandOffsets, Point location)?

              I can't figure out what the bandOffsets means, and it doesn't seem to work with this new ColorModel. Can you help me out again?
              • 4. Re: How do I specify 16bit R5G6B5 pixels when creating a BufferedImage?
                807588
                I suspect you need to use createPackedRaster since your pixel data is packed into shorts, not?
                • 5. Re: How do I specify 16bit R5G6B5 pixels when creating a BufferedImage?
                  807588
                  Well, Thank you very much. I've switched to using createPackedRaster, but I'm having trouble understanding the different sample models used by the two different methods. One uses a SinglePixelPackedSampleModel, while the other uses a MultiPixelPackedSampleModel. It seems that the SinglePixelPackedSampleModel makes the most sense, since there is only 1 pixel per "bit depth", such that if I say it is 16 bits, those 16 bits only contain 1 pixel. Am I looking at this wrong?

                  If I use the SinglePixelPackedSampleModel, I'm required to provide a scanlineStride and bandMask array. Do you know what these mean?

                  If I use the MultiPixelPackedSampleModel, I get an error message that says "MultiPixelPackedSampleModel does not allow pixels to span data element boundaries" Is this happening because I've told it my data is 16bits and my data is in a byte[]? Do I need to convert it to a short[]? I would hope not to, since I don't want to have to traverse the array anymore than I absolutely have to.

                  Thanks again!
                  • 6. Re: How do I specify 16bit R5G6B5 pixels when creating a BufferedImage?
                    807588
                    Quasi_Stomach wrote:
                    If I use the SinglePixelPackedSampleModel, I'm required to provide a scanlineStride and bandMask array. Do you know what these mean?
                    I think you're referring to this constructor:
                    public SinglePixelPackedSampleModel(int dataType, int w, int h, int scanlineStride, int[] bitMasks)
                    Ultimately, the data is going to be stored in a one dimensional array, say a short[]. The SampleModel knows how to access the data elements for the pixel in row r column c, for example.

                    Suppose I have a short[] where each short represents a pixel packed as 565_RGB. Bit masks are needed to extract the red, green and blue components from a short. These masks are:
                    int[] bitMasks = {0xF800, 0x7E0, 0x1F}; 
                    Write those out in binary and you'll see.

                    Second, an image is two-dimensional but a DataBuffer is one-dimensional -- basically a short[] in our case. How is the image folded in? Row by row. If you ran through the data in the short[] you would see row 0 of the image, then row 1, row 2, etc... But sometimes there's padding in there. It may be advantageous (because of video hardware) for the image width to be a power of 2: 2, 4, 8, 16, 32... and if the width isn't there may be padding (zeroes) in the short[] that guarantee that each row's data starts at an offset that is a multiple of a power of two. For example, you may have an image with width 200 that's padded out to 256, and the rows start at offsets [0], [256], [512], ...

                    This larger width, 256, is the scanlineStride. Chances are, if you don't know about a specific scanlineStride, it's going to be the same as the width.

                    Edit: All this being said, I can't remember the last time I needed to directly create or manipulate a SampleModel. Are you sure you need to go this low level? Perhaps you need to step back and describe the big picture. There may be another approach that's much easier to do what ever it is you are trying to do.
                    • 7. Re: How do I specify 16bit R5G6B5 pixels when creating a BufferedImage?
                      807588
                      Thanks so much. I got my DDS file reader working just as I wanted, (I still need to de-compress compressed images, but that's another issue entirely). I didn't know how to read these images without using bloated libraries, so that's why I was building this simple reader myself. As far as I know, I needed to get the data into the format of a BufferedImage, since that's the only way I could find to easily convert it to multiple other formats which is my ultimate goal. If you happen to have info on converting raw pixel bytes (or shorts, or ints) directly to other file formats, I may look into doing that instead, but at least I can now convert (uncompressed) DDS files to jpg or other formats. Thanks again!