Java Solaris Communities Sun Store Join SDN My Profile Why Join?
 
Bug Database
Bug Detail
Quick Lists
Top 25 Bugs
Top 25 RFE's
Recently Closed Bugs
Printable Page Printable Page


Bug Database
Bug ID: 6488219
Votes 9
Synopsis Uneven character spacing when printing JTextComponent
Category java:classes_2d
Reported Against
Release Fixed 7(b08), 6u10(b26) (Bug ID:2162850)
State 10-Fix Delivered, Verified, bug
Priority: 4-Low
Related Bugs
Submit Date 31-OCT-2006
Description
FULL PRODUCT VERSION :
java version "1.6.0-beta2"
Java(TM) SE Runtime Environment (build 1.6.0-beta2-b86)
Java HotSpot(TM) Client VM (build 1.6.0-beta2-b86, mixed mode, sharing)

ADDITIONAL OS VERSION INFORMATION :
 customer  Windows XP [Version 5.1.2600]

A DESCRIPTION OF THE PROBLEM :
Printing text using JTextArea and JTextPane results in noticably uneven spacing between characters, as though the wrong kerning information is being used.  Some letters have too much space after them, resulting in noticable gaps with the following letters.  Other letters have too little space after them, resulting in their touching the letters that follow them.

The problem only occurs in printed output, the screen display looks fine.

The problem occurs for JTextComponent subclasses but not when printing the same strings using drawString.

This was not a problem under JDK 1.4 but appeared starting with JDK 1.5 and continues in JDK 1.6.  In JDK 1.5 some more serious character spacing problems were fixed (see Bug Parade 4724061 and 4352983), but perhaps that solution introduced this new problem.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Build and run the program provided below under JDK 1.4, JDK 1.5 and JDK 1.6.  Carefully compare the spacing after the letters "m", "v", and "s" in the 1.4 output versus the 1.5 and 1.6 outputs.


EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Spacing should be consistent, as in the 1.4 output
ACTUAL -
Spacing is uneven, as in the 1.5 and 1.6 outputs.  For example, there is too much space following "m" and "s" and too little space after "v".


REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import java.awt.*;
import javax.swing.*;
import java.awt.print.*;

class Test implements Printable {
    static JTextArea area;

    static public void main(String args[]) {
        area = new JTextArea();
        area.setEditable(false);
        area.setText("marvelous suspicious solving");

        JFrame frame = new JFrame("Printing test");
        frame.getContentPane().add(area);
        frame.setSize(300,200);
        frame.setVisible(true);

        PrinterJob job = PrinterJob.getPrinterJob();
        job.setPrintable(new Test(), job.defaultPage());
        if (job.printDialog()) {
            try { job.print(); }
            catch (Exception e) { }
        }
        System.exit(0);
    }

    public int print(Graphics g, PageFormat pf, int pageIndex) throws PrinterException {
        if (pageIndex >= 1) return Printable.NO_SUCH_PAGE;
        Graphics2D g2d = (Graphics2D)g;
        g2d.translate((int)pf.getImageableX(), (int)pf.getImageableY());
        g2d.setClip(0, 0, (int)pf.getImageableWidth(), (int)pf.getImageableHeight());
        try { area.print(g2d); }
        catch (Exception e) { }
        return Printable.PAGE_EXISTS;
    }

}


---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
Revert to JDK 1.4

or

Print using drawString

Release Regression From : 1.4.2_12
The above release value was the last known release where this 
bug was not reproducible. Since then there has been a regression.
Posted Date : 2006-10-31 10:56:49.0
Work Around
N/A
Evaluation
yes the fix for 4352983 introduces this.
The printer size character shapes and advances are different so
if they are spaced 'naturally' they do not fit the same width they
did on screen, and if they are spaced as per screen metrics they
do not look naturally spaced and sometimes abut.

A variant of the submitter's program below can be run
on 1.4 and 1.5 and shows that prior to 1.5 the space occupied
by the text did not match the component. That often lead to
clipped text.

import java.awt.*;
import javax.swing.*;
import java.awt.print.*;

class Test1 implements Printable {
    static JLabel label;
    static JFrame frame;

    static public void main(String args[]) {
        label = new JLabel();
        label.setFont(new Font("Dialog", Font.PLAIN, 12));
        label.setText("marvelous suspicious solving");

        frame = new JFrame("Printing test");
        frame.getContentPane().add(label);
        frame.pack();
        frame.setVisible(true);

        PrinterJob job = PrinterJob.getPrinterJob();
        job.setPrintable(new Test1(), job.defaultPage());
        if (job.printDialog()) {
            try { job.print(); }
            catch (Exception e) { }
        }
        //System.exit(0);
    }

    public int print(Graphics g, PageFormat pf, int pageIndex) throws PrinterException {
        if (pageIndex >= 1) return Printable.NO_SUCH_PAGE;
        Graphics2D g2d = (Graphics2D)g;
        g2d.translate((int)pf.getImageableX(), (int)pf.getImageableY());
        g2d.setClip(0, 0, (int)pf.getImageableWidth(), (int)pf.getImageableHeight());
        try { frame.printAll(g2d); }
        catch (Exception e) { }
        return Printable.PAGE_EXISTS;
    }

}

For printing swingtext components in JDK6 there is a new API
javax.swing.JTextComponent.print(..) which layout for printing.
It can return a printable or can be used even more simply

import javax.swing.*;
import java.awt.print.*;

class Test2 {

    static public void main(String args[]) {
        JTextArea area = new JTextArea();
        area.setEditable(false);
        area.setText("marvelous suspicious solving");

        JFrame frame = new JFrame("Printing test");
        frame.getContentPane().add(area);
        frame.setSize(300,200);
        frame.setVisible(true);
        try {
          area.print();
        } catch (PrinterException e) {
        }
    }
}

This doesn't help existing code, but pre-existing code has problems either way
- prior to 1.5 : text clipped or too short
- in 1.5 and later : uneven spacing.

Its not clear what to do to improve matters. It needs some thought.
Making it into a screen resolution screen dump would fix the spacing
because screen resolution characters would be used but they'd be
grossly pixellated and so would everything else.

Essentially it needs a better way to distribute the white space
within a target width that is conscious of the true advance widths
of the characters at device resolution so as to minimise the
obviousness of this problem.
But white space isn't going to help as much in cursive scripts
such as Arabic and Indic.
Posted Date : 2006-11-01 19:30:59.0

The following seems to help (subjectively) enough to make it implementing
as a solution.

1. Use the printer graphics FontRenderContext to create a TextLayout laid out
for the printer. The reason is that it will contain per-character (or per-glyph)
advances that match those of the characters at screen resolution.

2. Use the screen FontRenderContext to measure the overall desired advance
of the string at screen-resolution.

3. Using the TextLayout from (1) and the screen width from (2), call
TextLayout. getJustifiedLayout(screenWidth) to return a new TextLayout
which is spaced better because it knows the true advances of each character.

Caveat: this can never be perfect when trying to fit printer resolution
text to a screen width.
Posted Date : 2006-12-07 19:14:17.0
Comments
  
  Include a link with my name & email   

Submitted On 01-DEC-2006
mamabile
I think the issue started occurring in Java 1.5 Update 4 and onwards.

I have no problems with using the Java 1.5 Update 3 or earlier Java 1.4 versions.


Submitted On 01-AUG-2007
raj_mur
Is there any place I can get this portion of the fixed code. Can I build my rt.jar till Sun releases this version.
BTW what is the ETA for 7(b08)  is it JDK 1.7 Beta 8 ??


Submitted On 12-NOV-2007
The above work around will not work for me and I can't wait until JDK 1.7 to have this fixed.  Can this be fixed in JDK 1.5 or 1.6?



PLEASE NOTE: JDK6 is formerly known as Project Mustang