United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
Bug ID: 6357416 Dithering occurs in 8 bit images even when rendering hints should disable it
6357416 : Dithering occurs in 8 bit images even when rendering hints should disable it

Details
Type:
Bug
Submit Date:
2005-11-30
Status:
Open
Updated Date:
2012-01-16
Project Name:
JDK
Resolved Date:
Component:
client-libs
OS:
windows_2000
Sub-Component:
2d
CPU:
x86
Priority:
P5
Resolution:
Unresolved
Affected Versions:
1.4.2
Targeted Versions:

Related Reports

Sub Tasks

Description
FULL PRODUCT VERSION :
java version "1.4.2_03"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.2_03-b02)
Java HotSpot(TM) Client VM (build 1.4.2_03-b02, mixed mode)

ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows 2000 [Version 5.00.2195]
(Also occurs on Solaris)

A DESCRIPTION OF THE PROBLEM :
I have an application used to render maps that draws graphics into a BufferedImage that uses an 8 bit indexed color model. Rendering hints are used to enable anti-aliasing and to disable dithering.

In J2SE 1.3.1_06, everything worked correctly, and the generated maps contained solid colors.

In J2SE 1.4.1 and 1.4.2, polygons are filled with dithered colors for most of the colors in the palette used.

  Interestingly, if anti-aliasing is disabled, no dithering occurs.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run the attached sample code using J2SE 1.3.1_06 and J2SE 1.4.2_03, and observe the differences.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The sample code draws a set of squares in various colors. They are all colors that exist in the indexed color model, and so all of them should be rendered as solid (not dithered) colors.
ACTUAL -
A large number of the squares are rendered using a dithering pattern.

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------

package sandbox;

import java.awt.*;
import java.awt.image.*;


public class ImageDitheringProblem extends Frame
{
    public static int[] COLORS = new int[]{
        0xFFFFFF, 0xC0C0C0, 0x808080, 0x000000,
        0xFF0000, 0xFFFF00, 0x00FF00, 0x00FFFF,
        0x0000FF, 0xFF00FF, 0x800000, 0x808000,
        0x008000, 0x008080, 0x000080, 0x800080,
        0x500000, 0x700000, 0x900000, 0xC00000,
        0xE00000, 0xFF0000, 0xFF2020, 0xFF4040,
        0xFF5050, 0xFF6060, 0xFF8080, 0xFF9090,
        0xFFA0A0, 0xFFB0B0, 0xFFD0D0, 0x501400,
            
        0x701C00, 0x902400, 0xA02800, 0xC03000,
        0xE03800, 0xFF4000, 0xFF5820, 0xFF7040,
        0xFF7C50, 0xFF9470, 0xFFA080, 0xFFB8A0,
        0xFFC4B0, 0xFFDCD0, 0x502800, 0x603000,
        0x804000, 0xA05000, 0xB05800, 0xD06800,
        0xE07000, 0xFF8000, 0xFF9830, 0xFFA850,
        0xFFB060, 0xFFC080, 0xFFD0A0, 0xFFD8B0,
        0xFFE8D0, 0x503C00, 0x604800, 0x806000,
            
        0x906C00, 0xA07800, 0xC09000, 0xD09C00,
        0xF0B400, 0xFFC000, 0xFFD040, 0xFFD860,
        0xFFDC70, 0xFFE490, 0xFFECB0, 0xFFF4D0,
        0x505000, 0x606000, 0x707000, 0x909000,
        0xA0A000, 0xB0B000, 0xC0C000, 0xF4F400,
        0xF0F000, 0xFFFF00, 0xFFFF40, 0xFFFF70,
        0xFFFF90, 0xFFFFB0, 0xFFFFD0, 0x305000,
        0x3A6000, 0x4D8000, 0x569000, 0x60A000,
            
        0x73C000, 0x7DD000, 0x90F000, 0x9AFF00,
        0xB3FF40, 0xC0FF60, 0xCDFF80, 0xD3FF90,
        0xE0FFB0, 0xEDFFD0, 0x005000, 0x006000,
        0x008000, 0x00A000, 0x00B000, 0x00D000,
        0x00E000, 0x00FF00, 0x50FF50, 0x60FF60,
        0x70FF70, 0x90FF90, 0xA0FFA0, 0xB0FFB0,
        0xD0FFD0, 0x005028, 0x006030, 0x008040,
        0x00A050, 0x00B058, 0x00D068, 0x00F470,
            
        0x00FF80, 0x50FFA8, 0x60FFB0, 0x70FFB8,
        0x90FFC8, 0xA0FFD0, 0xB0FFD8, 0xD0FFE8,
        0x005050, 0x006060, 0x008080, 0x009090,
        0x00A0A0, 0x00C0C0, 0x00D0D0, 0x00F0F0,
        0x00FFFF, 0x50FFFF, 0x70FFFF, 0x80FFFF,
        0xA0FFFF, 0xB0FFFF, 0xD0FFFF, 0x003550,
        0x004B70, 0x006090, 0x006BA0, 0x0080C0,
        0x0095E0, 0x00ABFF, 0x40C0FF, 0x50C5FF,
            
        0x60CBFF, 0x80D5FF, 0x90DBFF, 0xA0E0FF,
        0xB0E5FF, 0xD0F0FF, 0x001B50, 0x002570,
        0x001C90, 0x0040C0, 0x004BE0, 0x0055FF,
        0x3075FF, 0x4080FF, 0x508BFF, 0x70A0FF,
        0x80ABFF, 0x90B5FF, 0xA0C0FF, 0xC0D5FF,
        0xD0E0FF, 0x000050, 0x000080, 0x0000A0,
        0x0000D0, 0x0000FF, 0x2020FF, 0x1C1CFF,
        0x5050FF, 0x6060FF, 0x7070FF, 0x8080FF,
            
        0x9090FF, 0xA0A0FF, 0xC0C0FF, 0xD0D0FF,
        0x280050, 0x380070, 0x480090, 0x6000C0,
        0x7000E0, 0x8000FF, 0x9020FF, 0xA040FF,
        0xA850FF, 0xB060FF, 0xC080FF, 0xC890FF,
        0xD0A0FF, 0xD8B0FF, 0xE8D0FF, 0x500050,
        0x700070, 0x900090, 0xA000A0, 0xC000C0,
        0xE000E0, 0xFF00FF, 0xFF20FF, 0xFF40FF,
        0xFF50FF, 0xFF70FF, 0xFF80FF, 0xFFA0FF,
            
        0xFFB0FF, 0xFFD0FF, 0x500028, 0x700060,
        0x900048, 0xC00060, 0xE00070, 0xFF008A,
        0xFF2090, 0xFF40A0, 0xFF50A8, 0xFF60B0,
        0xFF80C0, 0xFF90C8, 0xFFA0D0, 0xFFB0D8,
        0xFFD0E8, 0x000000, 0x101010, 0x202020,
        0x303030, 0x404040, 0x505050, 0x606060,
        0x707070, 0x909090, 0xA0A0A0, 0xB0B0B0,
        0xC0C0C0, 0xD0D0D0, 0xE0E0E0, 0xF0F0F0};

    
    public static void main(String [] args)
    {
        Frame f = new ImageDitheringProblem();
        f.setSize(640, 480);
        f.setVisible(true);
    }

    public void paint(Graphics g)
    {
        int width = getSize().width;
        int height = getSize().height;
        
        // Create an IndexColorModel for the custom palette
        IndexColorModel colorModel = new IndexColorModel(8, COLORS.length,
            COLORS, 0, false, -1, DataBuffer.TYPE_BYTE);
        
        // Create a BufferedImage that uses the custom color model
        BufferedImage image = new BufferedImage(width,
            height, BufferedImage.TYPE_BYTE_INDEXED,
            colorModel);
        
        // Create a graphics object to render to
        Graphics2D graphics = image.createGraphics();

        // Disable dithering
        graphics.setRenderingHint(RenderingHints.KEY_DITHERING,
            RenderingHints.VALUE_DITHER_DISABLE);
       
        // Enable anti-aliasing
        graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
            RenderingHints.VALUE_ANTIALIAS_ON);
        
        // Draw a series of squares in different colors
        int colorIndex = 0;
        for(int xOffset = 0; xOffset < width - 50; xOffset += 50)
        {
            for(int yOffset = 0; yOffset < height - 50; yOffset += 50)
            {
                if(colorIndex < COLORS.length)
                {
                    Color color = new Color(COLORS[colorIndex++]);
                    graphics.setColor(color);
                    graphics.fillRect(xOffset, yOffset, 50, 50);
                }
            }
        }
        graphics.dispose();
        
        // Display the image
        g.drawImage(image, 0, 0, null);
    }
}
---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
Disabling anti-aliasing seems to disable the dithering effect. However this is not really an acceptable workaround because graphics within the image then (obviously) take on a jagged appearance.

                                    

Comments
EVALUATION

There are a couple of problems here that should be addressed:

- When doing AA rendering, when the coverage of a given pixel is
100% we should simply store the best approximation of the requested
color rather than treat it as an imaging operation and doing dithering.

- Our color approximation code in the rendering loops should take the
dithering hint into account.

The first problem (simplifying the color stores when coverage is 100%)
can be solved in a couple of ways.

Currently we only define an "any alpha mode" rendering loop for ByteIndexed
destinations and the macros which generate those generalized loops do not
have the optimization to just store the color if the coverage is 100% because
they deal with quite a lot of calculations which could make the resulting
color not exactly the original.  If we add a more specific "src mode" rendering
loop for ByteIndexed then those more specific macros do generate the optimized
code to just store the pixel in which case the solid colors should clear up,
but only for the SRC mode and the SRC_OVER mode with an opaque color.  Those
modes end up being the bulk of the situations where this optimization can help
so that should cover the important cases.

We could also add the optimization code to the "any alpha mode" macros which
would make those already long macros even longer.  This may improve their
performance if they run into that case a lot, but it could also make their
performance worse if the code becomes complex enough to foil the code
optimizers.  Further investigation and benchmarking is needed there.

The second problem (honoring the hint) would require a major change to the
way that rendering loops are chosen and used.  That does need to be done
eventually, but one of the above two changes could make this change unnecessary
for most developers.
                                     
2006-06-21



Hardware and Software, Engineered to Work Together