Painting with Graphics2D and an IndexColorModel...

M

Michael C. Gilson

Hi all. I've searched high and low for a resolution to this problem,
but to no avail... thus I turn to you, gurus, for a helping
hand.........

The application I'm writing is meant to retrieve data from a database
( which happens to be of bacterial DNA sequences ) and then to display
this data as an image. These images are very large, sometimes on the
order of 500,000x200 pixels; and up to 20 of them need to be displayed
at once. To create these images, I construct a BufferedImage object
of type BufferedImage.TYPE_INT_RGB, and then use this image's
Graphics2D object to paint the "content." This works great, but it's
quite pricey with memory.
It turns out that these images only require 14 different colors in
their palette, so I would like to use a more compact ColorModel to
reduce the memory required by each image. Specifically, I'd like to
create an IndexColorModel with my custom palette. I have yet to find
on the web or in Sun's API docs an adequate description of how to use
a Graphics2D object to paint into an indexed-color image. There are
plenty of examples on how to create an image with a custom color map,
but in each of these cases the image is created from a pixel array,
rather than from explicit calls to a Graphics2D object associated with
the image. For my purposes, setting pixel values directly would be an
overwhelming task; I require the convenience methods of Graphics2D to
handle some geometry stuff that would be a NIGHTMARE to do by hand in
pixel arrays.
I do believe I am correctly constructing the IndexColorModel object.
As I understand it, you create the color bands like so:

byte[] r = new byte[numColors];
byte[] g = new byte[numColors];
byte[] b = new byte[numColors];

r[index] = (byte) // red component for "index" goes here
g[index] = (byte) // green component for "index" goes here
b[index] = (byte) // blue component for "index" goes here

And you repeat this for each color/index in your palette.

Here's where things go wrong for me. After I create a BufferedImage
with a ColorModel like the one described above, I use
BufferedImage.createGraphics() to get a handle on the Graphics2D
object so that I may begin painting in my image. I would normally
call:

Graphics.setColor( new Color(*explicit r,g,b values go here*) )

to set the Paint, but in an indexed-color image I need to specify an
index into a color map rather than the explicit red/green/blue values
of the desired color. I tried the following to access the colors in
my color map:

Graphics.setColor( new Color(index,index,index) )

But this almost never yields the actual color that is mapped to the
index.
What am I doing wrong? Is it at all possible to use a Graphics
object to paint into a paletted image? If not, how can one
"interactively" create an image of this sort, without resorting to raw
pixel manipulation?
I would greatly appreciate any advice, suggestions, or working code
samples that might steer me in the right direction.

Thank you all for your time,
Michael C. Gilson
University of Wisconsin - Madison
 
J

Jezuch

U¿ytkownik Michael C. Gilson napisa³:
What am I doing wrong? Is it at all possible to use a Graphics
object to paint into a paletted image? If not, how can one
"interactively" create an image of this sort, without resorting to raw
pixel manipulation?

Just paint like you would do with TYPE_INT. The ColorModel will handle
conversion from Color to index for you. That's the point of abstraction,
don't you think? :)
 
M

Marco Schmidt

fup2 comp.lang.java.gui

[...]
Here's where things go wrong for me. After I create a BufferedImage
with a ColorModel like the one described above, I use
BufferedImage.createGraphics() to get a handle on the Graphics2D
object so that I may begin painting in my image. I would normally
call:

Graphics.setColor( new Color(*explicit r,g,b values go here*) )

to set the Paint, but in an indexed-color image I need to specify an
index into a color map rather than the explicit red/green/blue values
of the desired color. I tried the following to access the colors in
my color map:

Graphics.setColor( new Color(index,index,index) )

But this almost never yields the actual color that is mapped to the
index.

Can't you keep the RGB values for each index and then use the new
Color version where you specify the RGB values? I'd hope that then the
correct underlying index is used.

Regards,
Marco
 
M

Michael C. Gilson

Jezuch said:
U¿ytkownik Michael C. Gilson napisa³:

Just paint like you would do with TYPE_INT. The ColorModel will handle
conversion from Color to index for you. That's the point of abstraction,
don't you think? :)

I tried that, believe me. But here is the problem: java does the
color conversion for you, which is not good. It gets "close" with
most of the colors, but it is WAY OFF with some of the others.

My assumption is that when you create the BufferedImage of
TYPE_BYTE_INDEXED, but you don't specify a custom ColorModel object,
java just goes ahead and creates a generic, 256 (or whatever size)
color map.

There are two problems with this: 1) I only need to use 14 colors, not
256 or whatever java comes up with. 2) These 14 colors need to be the
exact RGB colors that I specify, not some "approximated" color that
java mapped my actual RGB color to.

In conclusion, I _could_ just paint into a TYPE_BYTE_INDEXED just like
I would into a TYPE_INT_RGB. But I need the PRECISE colors, not
Java's GUESSED colors; so I must specify the color map myself, don't
you think? ;-)
 
K

Ken DeLong

If you are going to construct a BufferedImage with an IndexColorModel
that has a palette of 14 colors, the pixel samples in the image array
must have integral values between 0 and 13. The G2 will look at the
pixel value (say, 5), and look up that color in the IndexColorModel.

I've done this with an image that consists of an array of bytes. The
bytes range from 0 to 255, and I don't wish to normalize them, so I
created an IndexColorModel with 256 colors. I take the original array
of bytes, wrap it in a DataBuffer, wrap that in an InterleavedRaster,
and finally stuff the Raster and the ColorModel into a BufferedImage.
In my paintComponent() method, I just say
g2.paintImage(bi, 0, 0, width, height, null);
No need to set the color on the g2 or anything. The entire set of
code is about 6 lines long.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,743
Messages
2,569,478
Members
44,899
Latest member
RodneyMcAu

Latest Threads

Top