Skip to main content

[JAVA2D] Color depth question

4 replies [Last post]
Anonymous

I have a strange situation happening. Perhaps someone can help me make head
or tails of it?

I'm loading up a GIF image (i.e., 8-bit/256 color), then creating an offscreen
BufferedImage (initially with TYPE_INT_ARGB, but I've tried others as I'll
explain later). I then proceed to paint a white background onto it, paint the
GIF onto it, paint some black text over it, and trying to write it out again
as a GIF, using a GIF encoder utility. The GIF encoder, however is throwing
an exception re: > 256 colors.

I'm able to avoid this problem by creating an image of TYPE_BYTE_INDEXED, but
the quality of the image suffers as a result (it looks "grainy", for lack of a
better word).

I realize that what's happening is that there's a 32-bit image being produced,
and that it's rendering with > 256 colors, and so that's why I'm having this
problem. But I can't understand why it's rendering with > 256 colors. As the
initial image was a GIF, it was only using an 8-bit set of colors, and the
only other colors I'm using are black and white, both of which I believe are
already being used elsewhere in the image. So I can't see how I'd be using
more colors than the original image.

Anyone have any idea what might be happening here and how to work around it?
I'll use the grainy output image if I have to, but I'd prefer not to if I can
avoid it.

(BTW, I do know about PNG, JPEG, etc., but unfortunately I'm stuck with GIF
format for reasons outside of my control.)

TIA,

DR

==============================================================================
This message is for the sole use of the intended recipient. If you received
this message in error please delete it and notify us. If this message was
misdirected, CSFB does not waive any confidentiality or privilege. CSFB
retains and monitors electronic communications sent through its network.
Instructions transmitted over this system are not binding on CSFB until they
are confirmed by us. Message transmission is not guaranteed to be secure.
==============================================================================

===========================================================================
To unsubscribe, send email to listserv@java.sun.com and include in the body
of the message "signoff JAVA2D-INTEREST". For general help, send email to
listserv@java.sun.com and include in the body of the message "help".

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
Anonymous

The source GIF image has indexed palette with up to 256 colors. When you paint decoded GIF on the white background and some black text over it then the source palette is extended by at least 2 colors: black and white (if these colors aren't present at the palette yet) and you receive 258 colors palette. But if anti-aliasing mode is on then a new palette will contain considerably more than 258 colors.
The most proper advice is to quantize the result image to reduce colors' number down to 256. There are some open-source quantizers and you can find them with google.
But if you need to manipulate GIF images in a complicated manner then we suggest to try our Gif4J PRO library (http://www.gif4j.com/java-gif-imaging-gif4j-pro-library.htm). With Gif4J PRO your issue can be resolved with just some code lines.

Rosenstrauch, David

Hi Jim. Thanks for the response.

> Hi David,
>
> Where are you getting the IndexColorModel for your TYPE_BYTE_INDEXED
> image? If you use:
>
> new BufferedImage(w, h, TYPE_BYTE_INDEXED);
>
> then you get the default palette with a set of colors that may not
> match the original GIF image's color palette. As a result, trying
> to do any kind of manipulation with the image will result in color
> approximations.

That is what I was initially doing.

> There is another constructor where you can specify your own palette
> in a custom IndexColorModel:
>
> new BufferedImage(w, h, TYPE_BYTE_INDEXED, icm);
>
> If you can retrieve the IndexColorModel from the original GIF
> then you might have better luck constructing a matching BYTE_INDEXED
> image using this constructor. This is probably easier done if you
> use the Image I/O framework since it returns a BufferedImage which
> will let you get the ColorModel directly. If you use any of the
> various "getImage(file)" or "createImage(file)" methods on Toolkit
> and Component then you will get back a somewhat "opaque" file which
> doesn't let you query its ColorModel very easily.

Yes, that occurred to me yesterday too, and I tried to switch it over to use
the method you described, but still seemed to have the problem. As I
indicated yesterday, I render a white background, the original image, and some
overlaid black text onto a new BufferedImage, and then shuffle that new
BufferedImage off to the GifEncoder. If I try to create that buffered image
using TYPE_USHORT_565_RGB I get the "too many colors" error, and if I try it
with TYPE_BYTE_INDEXED then I get a grainy image. Somehow even with your
suggested changes I'm exceeding the color limit, but I'm not sure how.

Hmmm - one possibility comes to mind, but it's a remote one: I think that the
original image might be using transparency instead of white. So perhaps the
original is already using 255 colors, and the addition of the white color
(and/or the black text color) is pushing it over the edge? Like I said,
though, seems like a pretty remote possibility.

> That answer explains why your previous technique might have gone
> wrong, but it also points out another solution that is potentially
> much easier. Use Image I/O to load the GIF and you will get back
> a BufferedImage. You should then be able to render directly into
> that BufferedImage without having to make a copy.

Hmmm. That's an interesting idea. I'll have to give that some thought.

> If you want to create many different annoted versions
> of the image then you might get better perfomance by creating copies
> to modify rather than reloading and re-decoding the image every
> time, but you will need to take the issues I raised above into
> account when doing that...
>
> ...jim

Yes, I'd have to do it that way, since I'm re-using the image over and over
and so can't be messing up the original. I'll have to see if this is
feasible.

So far our solution has been to add PNG capability in addition to GIF. The
GIF output won't be as good as the PNG, but since I believe that some people
require it I have to support it. Kludgey state of affairs, though, so it'd be
good if I can find a way to address this.

Thanks very much for the suggestions. I'll let you know how it goes.

DR

==============================================================================
This message is for the sole use of the intended recipient. If you received
this message in error please delete it and notify us. If this message was
misdirected, CSFB does not waive any confidentiality or privilege. CSFB
retains and monitors electronic communications sent through its network.
Instructions transmitted over this system are not binding on CSFB until they
are confirmed by us. Message transmission is not guaranteed to be secure.
==============================================================================

===========================================================================
To unsubscribe, send email to listserv@java.sun.com and include in the body
of the message "signoff JAVA2D-INTEREST". For general help, send email to
listserv@java.sun.com and include in the body of the message "help".

Seth Tager

Is it possible that text antialiasing is turned on? (It might be on by
default) If so, when you paint black text over the image you will wind
up with many more colors (shades of gray) at the edges of the text.
That would easily bump up the number of colors to greater than 255.

Seth

On Wed, 16 Feb 2005 20:17:04 -0000, Rosenstrauch, David
wrote:
> Hi Jim. Thanks for the response.
>
>
> > Hi David,
> >
> > Where are you getting the IndexColorModel for your TYPE_BYTE_INDEXED
> > image? If you use:
> >
> > new BufferedImage(w, h, TYPE_BYTE_INDEXED);
> >
> > then you get the default palette with a set of colors that may not
> > match the original GIF image's color palette. As a result, trying
> > to do any kind of manipulation with the image will result in color
> > approximations.
>
> That is what I was initially doing.
>
>
> > There is another constructor where you can specify your own palette
> > in a custom IndexColorModel:
> >
> > new BufferedImage(w, h, TYPE_BYTE_INDEXED, icm);
> >
> > If you can retrieve the IndexColorModel from the original GIF
> > then you might have better luck constructing a matching BYTE_INDEXED
> > image using this constructor. This is probably easier done if you
> > use the Image I/O framework since it returns a BufferedImage which
> > will let you get the ColorModel directly. If you use any of the
> > various "getImage(file)" or "createImage(file)" methods on Toolkit
> > and Component then you will get back a somewhat "opaque" file which
> > doesn't let you query its ColorModel very easily.
>
> Yes, that occurred to me yesterday too, and I tried to switch it over to use
> the method you described, but still seemed to have the problem. As I
> indicated yesterday, I render a white background, the original image, and some
> overlaid black text onto a new BufferedImage, and then shuffle that new
> BufferedImage off to the GifEncoder. If I try to create that buffered image
> using TYPE_USHORT_565_RGB I get the "too many colors" error, and if I try it
> with TYPE_BYTE_INDEXED then I get a grainy image. Somehow even with your
> suggested changes I'm exceeding the color limit, but I'm not sure how.
>
> Hmmm - one possibility comes to mind, but it's a remote one: I think that the
> original image might be using transparency instead of white. So perhaps the
> original is already using 255 colors, and the addition of the white color
> (and/or the black text color) is pushing it over the edge? Like I said,
> though, seems like a pretty remote possibility.
>
>
> > That answer explains why your previous technique might have gone
> > wrong, but it also points out another solution that is potentially
> > much easier. Use Image I/O to load the GIF and you will get back
> > a BufferedImage. You should then be able to render directly into
> > that BufferedImage without having to make a copy.
>
> Hmmm. That's an interesting idea. I'll have to give that some thought.
>
>
> > If you want to create many different annoted versions
> > of the image then you might get better perfomance by creating copies
> > to modify rather than reloading and re-decoding the image every
> > time, but you will need to take the issues I raised above into
> > account when doing that...
> >
> > ...jim
>
> Yes, I'd have to do it that way, since I'm re-using the image over and over
> and so can't be messing up the original. I'll have to see if this is
> feasible.
>
> So far our solution has been to add PNG capability in addition to GIF. The
> GIF output won't be as good as the PNG, but since I believe that some people
> require it I have to support it. Kludgey state of affairs, though, so it'd be
> good if I can find a way to address this.
>
> Thanks very much for the suggestions. I'll let you know how it goes.
>
> DR
>
> ==============================================================================
> This message is for the sole use of the intended recipient. If you received
> this message in error please delete it and notify us. If this message was
> misdirected, CSFB does not waive any confidentiality or privilege. CSFB
> retains and monitors electronic communications sent through its network.
> Instructions transmitted over this system are not binding on CSFB until they
> are confirmed by us. Message transmission is not guaranteed to be secure.
> ==============================================================================
>
> ===========================================================================
> To unsubscribe, send email to listserv@java.sun.com and include in the body
> of the message "signoff JAVA2D-INTEREST". For general help, send email to
> listserv@java.sun.com and include in the body of the message "help".
>

===========================================================================
To unsubscribe, send email to listserv@java.sun.com and include in the body
of the message "signoff JAVA2D-INTEREST". For general help, send email to
listserv@java.sun.com and include in the body of the message "help".

Jim Graham

Hi David,

Where are you getting the IndexColorModel for your TYPE_BYTE_INDEXED
image? If you use:

new BufferedImage(w, h, TYPE_BYTE_INDEXED);

then you get the default palette with a set of colors that may not
match the original GIF image's color palette. As a result, trying
to do any kind of manipulation with the image will result in color
approximations.

There is another constructor where you can specify your own palette
in a custom IndexColorModel:

new BufferedImage(w, h, TYPE_BYTE_INDEXED, icm);

If you can retrieve the IndexColorModel from the original GIF
then you might have better luck constructing a matching BYTE_INDEXED
image using this constructor. This is probably easier done if you
use the Image I/O framework since it returns a BufferedImage which
will let you get the ColorModel directly. If you use any of the
various "getImage(file)" or "createImage(file)" methods on Toolkit
and Component then you will get back a somewhat "opaque" file which
doesn't let you query its ColorModel very easily.

That answer explains why your previous technique might have gone
wrong, but it also points out another solution that is potentially
much easier. Use Image I/O to load the GIF and you will get back
a BufferedImage. You should then be able to render directly into
that BufferedImage without having to make a copy. You will have
to load it all over again if you do this more than once to a given
GIF image. If you want to create many different annoted versions
of the image then you might get better perfomance by creating copies
to modify rather than reloading and re-decoding the image every
time, but you will need to take the issues I raised above into
account when doing that...

...jim

--On 02/14/05 09:23:47 PM +0000 Rosenstrauch, David wrote:
> I have a strange situation happening. Perhaps someone can help me
> make head or tails of it?
>
> I'm loading up a GIF image (i.e., 8-bit/256 color), then creating an
> offscreen BufferedImage (initially with TYPE_INT_ARGB, but I've tried
> others as I'll explain later). I then proceed to paint a white
> background onto it, paint the GIF onto it, paint some black text over
> it, and trying to write it out again as a GIF, using a GIF encoder
> utility. The GIF encoder, however is throwing an exception re: > 256
> colors.
>
> I'm able to avoid this problem by creating an image of
> TYPE_BYTE_INDEXED, but the quality of the image suffers as a result
> (it looks "grainy", for lack of a better word).
>
> I realize that what's happening is that there's a 32-bit image being
> produced, and that it's rendering with > 256 colors, and so that's
> why I'm having this problem. But I can't understand why it's
> rendering with > 256 colors. As the initial image was a GIF, it was
> only using an 8-bit set of colors, and the only other colors I'm
> using are black and white, both of which I believe are already being
> used elsewhere in the image. So I can't see how I'd be using more
> colors than the original image.
>
> Anyone have any idea what might be happening here and how to work
> around it? I'll use the grainy output image if I have to, but I'd
> prefer not to if I can avoid it.
>
> (BTW, I do know about PNG, JPEG, etc., but unfortunately I'm stuck
> with GIF format for reasons outside of my control.)
>
> TIA,
>
> DR
>
>
> =====================================================================
> ========= This message is for the sole use of the intended recipient.
> If you received this message in error please delete it and notify us.
> If this message was misdirected, CSFB does not waive any
> confidentiality or privilege. CSFB retains and monitors electronic
> communications sent through its network. Instructions transmitted
> over this system are not binding on CSFB until they are confirmed by
> us. Message transmission is not guaranteed to be secure.
> =====================================================================
> =========
>
> =====================================================================
> ====== To unsubscribe, send email to listserv@java.sun.com and
> include in the body of the message "signoff JAVA2D-INTEREST". For
> general help, send email to listserv@java.sun.com and include in the
> body of the message "help".

===========================================================================
To unsubscribe, send email to listserv@java.sun.com and include in the body
of the message "signoff JAVA2D-INTEREST". For general help, send email to
listserv@java.sun.com and include in the body of the message "help".