PNG - Is it possible to reduce the palette using Java 2D?
Asked Answered
P

2

7

If I have a PNG image opened as a BufferedImage, is it possible to reduce the palette in the PNG image so that there is less colour (less bits per pixel / colour depth)?

For example, if you look at Colour depth in Wikipedia, I would like to use 16 colours in my PNG image (3rd image down the right hand side).

If it's not possible with Java 2D, is there a library out there that will allow me to do this effectively?

Philips answered 26/7, 2011 at 15:20 Comment(2)
https://mcmap.net/q/1479295/-color-reduction-in-javaRhythm
Take a look at options provided to PNGImageWriter in code here: forums.oracle.com/forums/thread.jspa?messageID=5386868Type
T
10

I think Martijn Courteaux was right:

comparison

Here is example implementation:

import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.awt.image.IndexColorModel;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;

public class ImagingTest2 {
    public static void main(String[] args) throws IOException {
        BufferedImage src = ImageIO.read(new File("in.png")); // 71 kb

        // here goes custom palette
        IndexColorModel cm = new IndexColorModel(
                3, // 3 bits can store up to 8 colors
                6, // here I use only 6
                //          RED  GREEN1 GREEN2  BLUE  WHITE BLACK              
                new byte[]{-100,     0,     0,    0,    -1,     0},
                new byte[]{   0,  -100,    60,    0,    -1,     0},
                new byte[]{   0,     0,     0, -100,    -1,     0});

        // draw source image on new one, with custom palette
        BufferedImage img = new BufferedImage(
                src.getWidth(), src.getHeight(), // match source
                BufferedImage.TYPE_BYTE_INDEXED, // required to work
                cm); // custom color model (i.e. palette)
        Graphics2D g2 = img.createGraphics();
        g2.drawImage(src, 0, 0, null);
        g2.dispose();

        // output
        ImageIO.write(img, "png", new File("out.png"));   // 2,5 kb
    } 
}
Type answered 26/7, 2011 at 21:32 Comment(4)
The reduced image looks terrible. I think 16 colors (evenly distributed) would be quite better than your 6 ones. (But still +1.)Fenelia
Thanks, 16 colors would break the indentation and introduce scrollbars. :DType
This works a charm! Can you just explain why you have the indexes labelled // RED GREEN1 GREEN2 BLUE WHITE BLACK Why do you have 'GREEN1' and 'GREEN2'? ThanksPhilips
Oh, yes. I just wanted to see wheter or not it picks up the palette. If yes than the resulting picture would have two shades of green and one shade of any other color. It's hard to see, but it really has.Type
B
3

Create a new BufferedImage with the lower palette and use createGraphic() to acquire a Graphics2D object. Draw the original image on the graphics. dispose() the graphics and here you are.

BufferedImage img = new BufferedImage(orig.getWidth(), orig.getHeight(),
                                      BufferedImage.TYPE_USHORT_555_RGB);
Banjermasin answered 26/7, 2011 at 16:4 Comment(2)
How to define the palette colours?Mahlstick
You certainly didn't deserve the downvote. I provided my answer to prove it.Type

© 2022 - 2024 — McMap. All rights reserved.