Search code examples
javabmpjavax.imageiojaiquantization

How to use ColorQuantizerDescriptor?


Following the idea of @PhiLho's answer to How to convert a BufferedImage to 8 bit?, I want to use ColorQuantizerDescriptor to convert a BufferedImage, imageType TYPE_INT_RGB, but RenderedOp#getColorModel() is throwing the following exception:

java.lang.IllegalArgumentException: The specified ColorModel is incompatible with the image SampleModel.
    at javax.media.jai.PlanarImage.setImageLayout(PlanarImage.java:541)
    at javax.media.jai.RenderedOp.createRendering(RenderedOp.java:878)
    at javax.media.jai.RenderedOp.getColorModel(RenderedOp.java:2253)

This is the code that I am attempting to use:

final RenderedOp medianCutQuantizerOp = ColorQuantizerDescriptor.create(rgbImage, ColorQuantizerDescriptor.MEDIANCUT, 256, null, null, null, null, null);
final BufferedImage bi = medianCutQuantizerOp.getAsBufferedImage(null, medianCutQuantizerOp.getColorModel());

How do I use ColorQuantizerDescriptor?


Solution

  • The following example has been modified from http://code.google.com/p/color-reduction-experiments/source/browse/trunk/it/geosolutions/mapproducers/MapProducersTest.java?r=2

    public class Main {
        public static void main(String[] args) throws Exception {
    
            BufferedImage original = ImageIO.read(new File("/Users/Nick/Desktop/with_flowers.jpg"));
             // 300 seems to be a good number
            final RenderedOp cqImage = ColorQuantizerDescriptor.create(
               original, ColorQuantizerDescriptor.OCTTREE,
               new Integer(255), new Integer(300), null, new Integer(2),
               new Integer(2), null);
    
            assert cqImage.getColorModel() instanceof IndexColorModel;
            final BufferedImage converted = cqImage.getAsBufferedImage();
            SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                    final JFrame f = new JFrame();
                    f.setTitle("Test");
                    f.getContentPane().add((new ScrollingImagePanel(converted, 300, 300)));
                    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    f.pack();
                    f.setVisible(true);
                }
            });
        }
    }
    

    Works for me:Using octree

    Edit: tried with your median cut and seems to work as well, though much slower.

    Using median cut