United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
Bug ID: JDK-6800846 REGRESSION: Printing quality degraded with Java 6 compared to 5.0
JDK-6800846 : REGRESSION: Printing quality degraded with Java 6 compared to 5.0

Details
Type:
Bug
Submit Date:
2009-02-03
Status:
Closed
Updated Date:
2011-03-07
Project Name:
JDK
Resolved Date:
2011-03-07
Component:
client-libs
OS:
solaris_2.5.1
Sub-Component:
2d
CPU:
sparc
Priority:
P3
Resolution:
Fixed
Affected Versions:
6
Fixed Versions:

Related Reports
Backport:
Relates:

Sub Tasks

Description
OPERATING SYSTEM
----------------
Windows XP

FULL JDK VERSION
----------------
Any Java 6 SDK after pre-GA build 1.6.0-b92

DESCRIPTION
-----------
Direct printing quality with Java 6 is severely degraded, under certain circumstances, compared to Java 5.0. We have provided a testcase demonstrating this.

With the help of JLE (David Korbel) we have narrowed this problem down to a regression caused by the fix for CR 6444688 in 1.6.0-b92:

------- WPathGraphics.java -------
955a956,961
>                      * Since a subimage can be created by calling
>                      * BufferedImage.getSubImage() that condition needs to
>                      * be accounted for too. This implies inspecting the
>                      * data buffer. In the end too many cases are not able
>                      * to take advantage of this option until we can teach
>                      * the native code to properly navigate the data buffer.
966a973
>                      * Until all of this is resolved newImage is always true.
968,977c975
<                     int txType = rotTransform.getType();
<                     boolean newImage =
<                         (txType != AffineTransform.TYPE_IDENTITY &&
<                          txType != AffineTransform.TYPE_TRANSLATION) ||
<                         dibType != img.getType() ||
<                         icm != null && icm != img.getColorModel() ||
<                         srcX != 0 || srcY != 0 ||
<                         srcWidth != img.getWidth(null) ||
<                         srcHeight != img.getHeight(null);
<
---
>                     boolean newImage = true;

It seems that explicitly setting the boolean newImage to true is the root cause of the issue. If we change the code to always set the boolean to false, or reinstate the original code, the problem disappears. However, this will re-introduce the problem reported in 6444688. In summary, the fix for 6444688 needs to be reworked.

Release Regression From : 6
The above release value was the last known release where this 
bug was not reproducible. Since then there has been a regression.

                                    

Comments
WORK AROUND

Print via a buffered image or using off-screen graphics.
                                     
2009-02-03
EVALUATION

The bug isn't in printing. Its in image code that is used by printing.

The application prepares an image and draws it to the printer.
The image is a 1 bit image in BYTE_BINARY BufferedImage,
with an indexed colormodel where we have color index 0 == WHITE,
and color index 1 = BLACK.

The printing implementation re-draws that into its own copy
of the image using the same size, image type and colormodel
as the original.

This should be a simple blit but it replicates many of the
black pixels on the scan line. The same doesn't happen if the
indexed color model reverses the order of the colours.

The problem is demonstrated by this test program which simply
creates a small image and then re-draws it. The results differ
based on the colour table.

I believe we are tripping over a > 10 year old bug in the color cube initialisation
in dither.c that is used to look up a pixel given an RGB value.

This is used for each pixel in the inner loop for this indexed color model.
Because of the way the color cube is initialised, for RGB=0x0 it assigns pixel value 255.
This is nonsense since there are only pixel values 0 and 1.
The loop however takes that value and ors it into the output, and depending
on where in the output byte we are corruption is variable.

I think the cause of the problem is that the code pays no attention to the cmap_len
parameter (in this case 2) and assumes 256.
ie it grabs the rgb value from cmap[255-i] which could be garbage.
When a color map is in increasing order of pixel and RGB value this bug isn't
likely to be observed since entries in the cube that are already assigned are not overwritten
but reverse order will hit this case. 

Here's a simple test case which creates two GIF files, in good.gif a single pixel
is drawn. In bad.gif its replicated.

import java.awt.*;
import java.awt.color.*;
import java.awt.image.*;
import static java.awt.image.BufferedImage.*;
import java.io.*;
import javax.imageio.*;

public class DrawBB {

  public static void main(String args[]) throws IOException {
    int w = 100, h = 30;
    byte[] arr = {(byte)0xff, (byte)0x0};
    IndexColorModel newCM = new IndexColorModel(1, 2, arr, arr, arr);
    BufferedImage orig = new BufferedImage(w, h, TYPE_BYTE_BINARY, newCM);
    Graphics2D g2d = orig.createGraphics();
    g2d.setColor(Color.white);
    g2d.fillRect(0, 0,w,h);
    g2d.setColor(Color.black);
    g2d.drawLine(10, 20, 10, 20); // draw a single pixel.
    g2d.dispose();

    BufferedImage good = new BufferedImage(w, h, TYPE_BYTE_BINARY);
    g2d = good.createGraphics();
    g2d.drawImage(orig, 0, 0, null);
    g2d.dispose();
    ImageIO.write(good, "gif", new File("good.gif"));

    IndexColorModel origCM = (IndexColorModel)orig.getColorModel();
    BufferedImage bad = new BufferedImage(w, h, TYPE_BYTE_BINARY,origCM);
    g2d = bad.createGraphics();
    g2d.drawImage(orig, 0, 0, null);
    g2d.dispose();
    ImageIO.write(bad, "gif", new File("bad.gif"));
  }


}
                                     
2009-02-06
SUGGESTED FIX

http://sa.sfbay.sun.com/projects/java2d_data/7/6800846.0
                                     
2009-02-06



Hardware and Software, Engineered to Work Together