0

I'm creating an image with a custom palette (in other words a custom colormodel):

 BufferedImage img = new BufferedImage(orgImg.getWidth(), orgImg.getHeight(),
      BufferedImage.TYPE_BYTE_INDEXED,
      cm);
 Graphics2D g2 = img.createGraphics();
    g2.drawImage(orgImg, 0, 0, null);
    g2.dispose();

Note that the "cm" variable is a my custom colormodel with a palette of 256 colors.

The "orgImg" variable is a full colored (24 big argb) image.

The above code results in a copy of "orgImg" with 256 colors using the palette defined in the colormodel.

This works nicely.

But java uses dithering to reduce colors. Is it possible to disable this dithering?

Note that i need to use my own palette so that the final images matches a specific color palette.

Tinus Tate
  • 2,237
  • 2
  • 12
  • 33

1 Answers1

2

When drawing an image into a Graphics2D object, various aspects of the rendering can be controlled using RenderingHints. You should be able to disable the dithering using the Graphics2D.setRenderingHint or setRenderingHints methods, passing the KEY_DITHERING and VALUE_DITHER_DISABLE value as parameters:

Graphics2D g2 = img.createGraphics();
// Disable dithering
g2.setRenderingHint(RenderingHint.KEY_DITHERING, RenderingHint.VALUE_DITHER_DISABLE);
g2.drawImage(orgImg, 0, 0, null);
g2.dispose();

See the Java2D tutorial for more info.

PS: Note that the methods/class are named "hint".

This may not be a problem any more, but in the past I've experienced that disabling the dither using the hint like above did not work. It's also not possible to specify the dithering algorithm to use, typically only a "ordered" or "diamond" pattern dithering is used.

I therefore implemented my own versions of various dithering algorithms for this use. See the CopyDither (which does a closest match lookup for each pixel, probably what you want here) and DiffusionDither (which implements a "Floyd-Steinberg" error diffusion dither). Both of the mentioned implementations rely on a fast reverse lookup of color values. Unfortunately, the default IndexColorModel doesn't do fast reverse lookups. So I implemented a special class for this case too, see the InverseColorMapIndexColorModel class.

Usage:

BufferedImage img = new BufferedImage(orgImg.getWidth(), orgImg.getHeight(), BufferedImage.TYPE_BYTE_INDEXED, cm);
CopyDither noDither = new CopyDither(new InverseColorMapIndexColorModel(cm)); // cm must be IndexColorModel
noDither.filter(orgImg, img);
Harald K
  • 26,314
  • 7
  • 65
  • 111
  • Using renderinghints doesn't work in this special case (in other/most cases it does work), the KEY_DITHERING is ignored. There are a few topics on the internet about this problem, but none come up with a solution which has good performance. Just give it a try. – Tinus Tate Oct 21 '17 at 12:53
  • 1
    I just saw you edited your question ;-) I'm going to take a look at your classes, they look good cause the use of rasters which is good for performance. I'll keep you up to date! – Tinus Tate Oct 21 '17 at 12:58
  • Cheers @haraldK , it took a little while to figure things out this morning, but after finding your maven dependencies everything went smooth. I used CopyDither with my color model and it generated a un-dithered version. And it is quite fast too, my hacky setRgb(getRgb) for every pixel is 50% slower. Thanks again! – Tinus Tate Oct 23 '17 at 10:49
  • 1
    @TinusTate Good stuff! It’s been a while since I wrote that code, so feel free to suggest improvements. – Harald K Oct 23 '17 at 10:53
  • I'm planning on looking through all you image related classes, i already seen a few interesting ones. They also illustrate nicely how to use some of the more advanced java image classes. Cheers for creating such useful library. – Tinus Tate Oct 23 '17 at 10:58