Skip to main content

[JAVA2D] color depth

7 replies [Last post]
Anonymous

Is there a way to query the color depth (bits per pixel) from a BufferedImage?

I found a 3rd party helper class to do this
(http://www.geocities.com/marcoschmidt.geo/image-info.html), but I was hoping
there was something built into the JDK that I could use.

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.
Jim Graham

Hi David,

The short "guess" answer for your problem is that I imagine that doing a
getColorModel() on one of your screen components will help you make this
determination, but the fact that you have to check this screen depth
concerns me for the following reasons:

Robot always returns a 24-bit image regardless of screen depth. If there
is an issue with color depth, it is not in the image that we give you from
that API.

It sounds like this GIF encoder package you found does some funny work
under the covers to process the pixels and ends up using a system
ColorModel when it doesn't need to. It doesn't have to have native code to
have this dependency, it could make use of Component.getColorModel() and
end up with such a dependency, though it is still pretty much unnecessary.
In the new age (JDK 1.2 and later) of BufferedImage objects any reasonable
encoder would work directly with the color depth that is given to it. You
might want to look for another encoder.

I might also recommend using PNG instead of GIF for this reason. The GIF
format is restricted to at most 256 colors and so all of your great
snapshots of your rich 24-bit color depth screens will end up getting
dithered when reduced to 256 colors for writing as a GIF file. PNG
supports 24-bit images so no color reduction will be needed for your screen
snapshots to write out an image.

JPEG also writes out full color images, but uses a "lossy" compression that
doesn't work well for text, line art, or GUI images. PNG is a better
choice because it uses non-lossy compression, though JPEG at a very low
compression factor could look much better than a dithered GIF image.

Finally, we supply both PNG and JPEG encoders built into the JDK as of 1.4
in the javax.imageio package. No need to download an external package to
write out images...

...jim

--On Thursday, October 21, 2004 2:50 PM -0400 "Rosenstrauch, David"
wrote:

>> Hi David,
>>
>> you can use
>> BufferedImage bi = ...;
>> ColorModel cm = bi.getColorModel();
>> int bpp = cm.getPixelSize();
>>
>> Thank you,
>> Dmitri
>
>
> Hmmm. That did work (thanks!), but it looks that's not actually what I'm
> looking for after all. Let me clarify my problem a little bit then.
>
> One of our developers wrote some code to do a screen scrape: generate a
> BufferedImage using the java.awt.Robot. We then try to save that to a GIF
> using an encoder class we found. But we ran into a problem: the GIF
> encoding worked on some people's machines and failed on others. Turns
> out that the deciding factor was whether the user's PC is set to 16-bit
> color or to a higher setting. Writing the GIF would succeed on 16-bit
> boxes, but fail for 24- or 32-bit: we'd get an exception thrown from the
> encoder indicating that the image contained more than 255 colors (which I
> assume is a limit for the GIF format).
>
> Now I'm able to successfully work around the problem whenever I get that
> exception by converting the image to 16 bit (by creating a new buffered
> image BufferedImage.TYPE_USHORT_565_RGB). But I'd like to make this more
> efficient. I don't want to have to get halfway through encoding the image
> before I get that "> 255 colors" exception and then have to go and re-do
> the encoding using the converted image. I'd much rather find a way to
> query up front as to whether the original image is not encodable as a GIF
> due to too many colors and, if so, then do the conversion and in this way
> I would only ever have to do the encoding once.
>
> Although the getPixelSize() method you mentioned does show the difference
> between the pixel sizes of the original and the converted images (24 bit
> as opposed to 16), that's not a sufficient query to use for this purpose.
> On a machine with 16-bit color (where I'm able to encode the image fine
> without any exceptions thrown) getPixelSize() still reports the original
> image at 24 bits, even though it will encode to GIF just fine.
>
> So I guess the problem is not just determining the pixel size, but rather
> how many colors are actually in use by the image. Anyone know of a
> technique I can use to do that?
>
> Thanks,
>
> 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".

Rosenstrauch, David

> Hi David,

Hi Jim. Thanks very much for the response and helpful suggestions.

> It sounds like this GIF encoder package you found does some
> funny work
> under the covers to process the pixels and ends up using a system
> ColorModel when it doesn't need to. It doesn't have to have
> native code to
> have this dependency, it could make use of
> Component.getColorModel() and
> end up with such a dependency, though it is still pretty much
> unnecessary.
> In the new age (JDK 1.2 and later) of BufferedImage objects
> any reasonable
> encoder would work directly with the color depth that is
> given to it. You
> might want to look for another encoder.

It's certainly possible that the encoder's a bit lame. Someone else chose
this encoder prior to my arrival. It looks like it scans the image and builds
a list of all the colors used in it. From its Javadocs: "GIFEncoder will
convert the image to indexed color upon construction. This will take some
time, depending on the size of the image ...". I'll definitely keep in mind
the possibility of switching to a better encoder at some point, but for now I
think I need to just focus on getting this bug fixed.

> I might also recommend using PNG instead of GIF for this
> reason. The GIF
> format is restricted to at most 256 colors and so all of your great
> snapshots of your rich 24-bit color depth screens will end up getting
> dithered when reduced to 256 colors for writing as a GIF file. PNG
> supports 24-bit images so no color reduction will be needed
> for your screen
> snapshots to write out an image.

I wish I could use PNG. We use GIF and JPG as our standards system-wide,
though, so unfortunately I'm stuck with those. I have to have support export
to either of these 2 formats, since it's chosen by the user at run-time. JPEG
is obviously not a problem, as you indicated, but I have to support GIF too.

I've also had some discussions off-list with Dmitri about this situation too.
(Who was also very helpful, I might add.)

I think I'm just going to wind up doing this for now:

private static BufferedImage colorDepthReduce(BufferedImage img) {
BufferedImage colorDepthReducedImg =
new BufferedImage(img.getWidth(), img.getHeight(),
BufferedImage.TYPE_USHORT_565_RGB);
Graphics2D g2d = (Graphics2D)colorDepthReducedImg.getGraphics();
g2d.setComposite(AlphaComposite.Src);
g2d.drawImage(img, 0, 0, null);
return colorDepthReducedImg;
}

Seems to solve the problem. Dmitri suggested that I use
BufferedImage.TYPE_BYTE_INDEXED instead, but that seemed to generate a poorer
quality image.

Thanks very much for the help!

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".

Anonymous

Hi David,

> I think I'm just going to wind up doing this for now:
>
> private static BufferedImage
> ge colorDepthReduce(BufferedImage img) {
> BufferedImage colorDepthReducedImg =
> new
> new BufferedImage(img.getWidth(),
> mage(img.getWidth(), img.getHeight(),
> BufferedImage.TYPE_USHORT_565_RGB);
> Graphics2D g2d =
> cs2D g2d =
> (Graphics2D)colorDepthReducedImg.getGraphics();
> g2d.setComposite(AlphaComposite.Src);
> g2d.drawImage(img, 0, 0, null);
> return colorDepthReducedImg;
> }
>
> Seems to solve the problem. Dmitri suggested that I
> use
> BufferedImage.TYPE_BYTE_INDEXED instead, but that
> seemed to generate a poorer
> quality image.
>

Thrown by the used GIF encoder exception ("the image contained more than 255 colors") means that this encoder doesn't include any quantizer (special class(-es) for reducing number of unique colors down to 256 (8 color bit depth) or less).

The above code reduces an image's palette to 16 bit depth - NOT TO 8 bit depth. And if this code has resolved your bug then it only means you are lucky to receive less than 256 unique colors after such reduction. But you should know that it'll not be always true.

You can solve your problem in two ways:

1) Use BufferedImage.TYPE_BYTE_INDEXED instead - not good way because in this case the default (not optimized to the exact palette) 8 bit depth ColorModel is used and as a result you receive bad quality images;

2) Use the GIF encoder with the embedded quantizer or quantize images by yourself using one of the existing quantizers. You can find the list of available GIF encoders here: http://www.geocities.com/marcoschmidt.geo/java-image-coding.html and find the list and even quality measurements and benchmark testing of the most popular java-based quantizers on our site's page: http://www.gif4j.com/gif4j_java_quantizer_quality_benchmarking.jsp

Regards, Alex
Gif4J Software

Rosenstrauch, David

> i guess your encoder should be 100% java otherwise it
> may use native library that rely on the colordepth the machine
> can handle...

Yeah, it's all Java.

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".

Rosenstrauch, David

> Hi David,
>
> you can use
> BufferedImage bi = ...;
> ColorModel cm = bi.getColorModel();
> int bpp = cm.getPixelSize();
>
> Thank you,
> Dmitri

Hmmm. That did work (thanks!), but it looks that's not actually what I'm
looking for after all. Let me clarify my problem a little bit then.

One of our developers wrote some code to do a screen scrape: generate a
BufferedImage using the java.awt.Robot. We then try to save that to a GIF
using an encoder class we found. But we ran into a problem: the GIF encoding
worked on some people's machines and failed on others. Turns out that the
deciding factor was whether the user's PC is set to 16-bit color or to a
higher setting. Writing the GIF would succeed on 16-bit boxes, but fail for
24- or 32-bit: we'd get an exception thrown from the encoder indicating that
the image contained more than 255 colors (which I assume is a limit for the
GIF format).

Now I'm able to successfully work around the problem whenever I get that
exception by converting the image to 16 bit (by creating a new buffered image
BufferedImage.TYPE_USHORT_565_RGB). But I'd like to make this more efficient.
I don't want to have to get halfway through encoding the image before I get
that "> 255 colors" exception and then have to go and re-do the encoding using
the converted image. I'd much rather find a way to query up front as to
whether the original image is not encodable as a GIF due to too many colors
and, if so, then do the conversion and in this way I would only ever have to
do the encoding once.

Although the getPixelSize() method you mentioned does show the difference
between the pixel sizes of the original and the converted images (24 bit as
opposed to 16), that's not a sufficient query to use for this purpose. On a
machine with 16-bit color (where I'm able to encode the image fine without any
exceptions thrown) getPixelSize() still reports the original image at 24 bits,
even though it will encode to GIF just fine.

So I guess the problem is not just determining the pixel size, but rather how
many colors are actually in use by the image. Anyone know of a technique I
can use to do that?

Thanks,

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".

Auguste Genovesio

i guess your encoder should be 100% java otherwise it
may use native library that rely on the colordepth the machine
can handle...

----- Original Message -----
From: "Rosenstrauch, David"
To:
Sent: Thursday, October 21, 2004 8:50 PM
Subject: Re: [JAVA2D] color depth

>> Hi David,
>>
>> you can use
>> BufferedImage bi = ...;
>> ColorModel cm = bi.getColorModel();
>> int bpp = cm.getPixelSize();
>>
>> Thank you,
>> Dmitri
>
>
> Hmmm. That did work (thanks!), but it looks that's not actually what I'm
> looking for after all. Let me clarify my problem a little bit then.
>
> One of our developers wrote some code to do a screen scrape: generate a
> BufferedImage using the java.awt.Robot. We then try to save that to a GIF
> using an encoder class we found. But we ran into a problem: the GIF
> encoding
> worked on some people's machines and failed on others. Turns out that the
> deciding factor was whether the user's PC is set to 16-bit color or to a
> higher setting. Writing the GIF would succeed on 16-bit boxes, but fail
> for
> 24- or 32-bit: we'd get an exception thrown from the encoder indicating
> that
> the image contained more than 255 colors (which I assume is a limit for
> the
> GIF format).
>
> Now I'm able to successfully work around the problem whenever I get that
> exception by converting the image to 16 bit (by creating a new buffered
> image
> BufferedImage.TYPE_USHORT_565_RGB). But I'd like to make this more
> efficient.
> I don't want to have to get halfway through encoding the image before I
> get
> that "> 255 colors" exception and then have to go and re-do the encoding
> using
> the converted image. I'd much rather find a way to query up front as to
> whether the original image is not encodable as a GIF due to too many
> colors
> and, if so, then do the conversion and in this way I would only ever have
> to
> do the encoding once.
>
> Although the getPixelSize() method you mentioned does show the difference
> between the pixel sizes of the original and the converted images (24 bit
> as
> opposed to 16), that's not a sufficient query to use for this purpose. On
> a
> machine with 16-bit color (where I'm able to encode the image fine without
> any
> exceptions thrown) getPixelSize() still reports the original image at 24
> bits,
> even though it will encode to GIF just fine.
>
> So I guess the problem is not just determining the pixel size, but rather
> how
> many colors are actually in use by the image. Anyone know of a technique
> I
> can use to do that?
>
> Thanks,
>
> 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".

Dmitri Trembovetski

Hi David,

you can use
BufferedImage bi = ...;
ColorModel cm = bi.getColorModel();
int bpp = cm.getPixelSize();

Thank you,
Dmitri

On Thu, Oct 21, 2004 at 05:39:47PM +0100, Rosenstrauch, David wrote:
> Is there a way to query the color depth (bits per pixel) from a BufferedImage?
>
> I found a 3rd party helper class to do this
> (http://www.geocities.com/marcoschmidt.geo/image-info.html), but I was hoping
> there was something built into the JDK that I could use.
>
> 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".