Reducing colors of an Image?

Posted on 2000-05-14
Last Modified: 2008-02-01
What is the simplest way to reduce an 32-bit Image object to 256 colors so it can be transformed into a gif with the Acme gifencoder?
Question by:marre111397
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
LVL 19

Expert Comment

by:Jim Cakalic
ID: 2809576
A tool I have used for some time on Unix is ImageMagick. Among many other capabilities, it will perform color reduction. Versions are available for most Unix systems and Linux as well as Windows (NT and 95), Macintosh, VMS, and OS/2. The package is free and can be downloaded (source and/or binary) from

Best regards,
Jim Cakalic

Author Comment

ID: 2809977
But I don't want to use an external software to convert my images. The 32-bit image is generated with Java and should then be converted to a gif with 256-colors...

Expert Comment

ID: 2810436
One possible solution based on image producers and consumers - there are others but this is perhaps the easiest to grasp at first.

This is some background on how it works...

Java's producer-consumer model makes it simple to create filters that provide many interesting image effects. Just to refresh your memory, an image producer provides the data for an image. An image consumer takes the image data and displays it. When you create an image from an URL, the data read from that URL serves as the image producer. When you create an image from an in-memory array, the MemoryImageSource is the image producer. To display an image, you connect an image producer to an image consumer and the image consumer displays the image. An image filter works like both a producer and a consumer. It acts like a consumer when it receives pixel data from the producer; then it acts like a producer when it sends the pixel data on to the consumer.

[In other words, a filter sits between a producer and a consumer and does something to the image when the producer passes it the data before the consumer gets the data to display it]

Have you tried using an RGBImageFilter? The following example is giving in the JDK docs:

FilteredImageSource is an implementation of the ImageProducer interface which takes an existing image and a filter object and uses them to produce image data for a new filtered version of the original image. Here is an example which filters an image by swapping the red and blue compents:

Image src = getImage("doc:///demo/images/duke/T1.gif");
ImageFilter colorfilter = new RedBlueSwapFilter();
Image img = createImage(new FilteredImageSource(src.getSource(), colorfilter));

where RedBlueSwapFilter is:

class RedBlueSwapFilter extends RGBImageFilter {
    public RedBlueSwapFilter() {
  // The filter's operation does not depend on the
  // pixel's location, so IndexColorModels can be
  // filtered directly.
      canFilterIndexColorModel = true;

    public int filterRGB(int x, int y, int rgb) {
      return ((rgb & 0xff00ff00)
           | ((rgb & 0xff0000) >> 16)
           | ((rgb & 0xff) << 16));

As you can see, the int RGB variable consists of 4 parts:

0x means use hex notation.
Then the next two digits are the Alpha (giving 256 possible intensities for the Alpha channel)
Then the next two are the Red value of the pixel (giving 256 possible intensities) and the next two are the Green and the final two are the Blue.

So you extract from the int rgb variable the parts of the colour you are interested in and process them separately. This is how the RedBlueSwapFilter works...

If you understand that then you are nearly there.

What you need is a filter that maps all the image colours down to only 256. This is done quite simply by making each colour map down from a complete possible range of 0 - FF in hex (which is 24 bit colour - 8 bits for each colour giving 16 million colours) down to only a possible 256 colours in total.

I'd give you the answer now, but to be honest I'm actually just going to lunch :) so I'll have a look at writing you a complete solution later.

I also get the feeling that you could do this by manipulating a colormodel object or perhaps there is a relevant BufferedImageOp available but I have not got time to look into this in any great detail at the moment.

This should you get you started anyway,

Let me know if you have any further questions...

NOTE: You could probably use an external program from within your Java app to process the file if it supports working from the command line. Just save your 32bit image, run the external program from with in java, wait for it to finish and then pick up the converted file but this is not particularly neat - it depends on how you are using the program.

PeopleSoft Has Never Been Easier

PeopleSoft Adoption Made Smooth & Simple!

On-The-Job Training Is made Intuitive & Easy With WalkMe's On-Screen Guidance Tool.  Claim Your Free WalkMe Account Now


Expert Comment

ID: 2810627

 I am seeing Your comments after a long time


Accepted Solution

Jod earned 50 total points
ID: 2810969
Hi. Yep, been very busy.

But I now have a database update running that will take a while so can spare some time...

The hardest question is, qhich colours to use and choose. What colours of RGB to map to.

Well, if you are using these gifs on the web, the answer is done for you. You must extract each part of the RGB values and map them to those shown on this page

because this is the safe palette that is used for most browsers.

There are only 216 colours in the pallete due to system variations, but you can be sure that if you map a gif to these colours then it will remain the same on most or all platforms.

So every red, green or blue value can be mapped to one of the following six values:

255, 204, 153, 102, 51 or 0.

Does not sound like many colours but then 6*6*6 = 216. Any more than this and you go over the 256 limit.

There is some more info here

So, extract each colour component:

RED = rgb & 0xff0000
GREEN = rgb & 0x00ff00
BLUE = rgb & 0x0000ff

Map it to the nearest relevant value above.

ff = 255 so ff becomes ff and so does eveything else above about 230.

I say about 230 as you may need to fiddle with the range boundaries to get the best results.

Then continue for all the remaining 5 ranges so that all values between 229 and 170 become 204 and so on through all the colours.

Try this filter in the above code:

class ColourReduceFilter extends RGBImageFilter {
    public ColourReduceFilter() {
      // The filter's operation does not depend on the
      // pixel's location, so IndexColorModels can be
      // filtered directly.
      canFilterIndexColorModel = true;

    public int filterRGB(int x, int y, int rgb) {
      return ( ( mapColour(rgb & 0xff000000) ) | // retain alpha transperency
               ( mapColour(rgb & 0xff0000) ) |
               ( mapColour(rgb & 0x00ff00) ) |
               ( mapColour(rgb & 0x0000ff) ) );

    public int mapColour (int c) {
      int mappedCol = 0;
      if (c > 230)
        mappedCol = 255;
      else if (c > 170)
        mappedCol = 204;
      else if (c > 127)
        mappedCol = 153;
      else if (c > 75)
        mappedCol = 102;
      else if (c > 20)
        mappedCol = 51;
        mappedCol = 0;

      return mappedCol;

I haven't compiled this so it may have some typos, but the general idea is sound.

Author Comment

ID: 2813241
I haven't actually tried this yet, but it looks reasonable. But I guess I this "color reduction algorithm" won't be high-quality, but it guess it will work for my application...

What I really wanted to know was whether Java had some standard-class that could do the color-reduction for me. Maybe with error-difussion or some other color-reduction-algorithm...

Expert Comment

ID: 2813828
I have could not see an off the shelf solution to do what you want in Java but you would think there was woudn't you.

I guess the problem is not simple and the theory of colour conversion quite complex so I'm not sure if there is an easier way though there are certainly other ways. The problem of quality in the reduced colour image is always an issue and a dithering algorithm may be far more accurate. The above will not dither the image at all - you would need to extend the code considerably to do this effectively.

For logos and business style graphics the above will be fine. For pictures and photographic material the quality will vary wildly.

Anyway, some Colour conversion theory is here, for example:

Not as straightforward as you might hope...

The code above is fairly basic but should do the job and it is pretty easy to do as well - only about twenty lines of code in total.

There is another even simpler way using a LookUpOp

      BufferedImage destImg = new BufferedImage(w,h,BufferedImage.TYPE_INT_RGB);

      byte reverse[] = new byte[256];
         for (int j=0; j<200; j++){

         ByteLookupTable blut=new ByteLookupTable(0, reverse);
         LookupOp lop = new LookupOp(blut, null);

This works by creatiung an array of 256 bytes each with the relevant colour value in for your new colour mapping. So the above example will copy sourceImg to destImg but reverse all the colours in the image by using a look up table of colours that is the wrong way round (goes from high to low instead of low to high).


Expert Comment

ID: 2813834
Perhaps look up the source of imagemagick from the link given above if you are feeling really brave and see what algorithms they use....

Featured Post

On Demand Webinar - Networking for the Cloud Era

This webinar discusses:
-Common barriers companies experience when moving to the cloud
-How SD-WAN changes the way we look at networks
-Best practices customers should employ moving forward with cloud migration
-What happens behind the scenes of SteelConnect’s one-click button

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Java contains several comparison operators (e.g., <, <=, >, >=, ==, !=) that allow you to compare primitive values. However, these operators cannot be used to compare the contents of objects. Interface Comparable is used to allow objects of a cl…
Java had always been an easily readable and understandable language.  Some relatively recent changes in the language seem to be changing this pretty fast, and anyone that had not seen any Java code for the last 5 years will possibly have issues unde…
This tutorial covers a step-by-step guide to install VisualVM launcher in eclipse.
This tutorial will introduce the viewer to VisualVM for the Java platform application. This video explains an example program and covers the Overview, Monitor, and Heap Dump tabs.
Suggested Courses

734 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question