JDK-4480930 : Java 2D printing : TextLayout prints as filled shapes.
  • Type: Bug
  • Component: client-libs
  • Sub-Component: 2d
  • Affected Version: 1.4.0
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • OS: windows_nt,windows_2000
  • CPU: x86
  • Submitted: 2001-07-17
  • Updated: 2003-12-08
  • Resolved: 2003-12-08
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other
5.0 b31Fixed
Related Reports
Duplicate :  
Description

Name: bsC130419			Date: 07/17/2001


java version "1.4.0-beta"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.0-beta-b65)
Java HotSpot(TM) Client VM (build 1.4.0-beta-b65, mixed mode)

When I use java.awt.font.TextLayout to render text on my printer, the quality
of the text is bad as compared to when using java.awt.Graphics.drawString.  The
following code illustrates the problem.  I have seen the same behavior on JDK
1.3.1 and 1.4 beta.  Interestingly, JDK 1.2.2 has bad print quality in both
cases.

I am printing from Windows 2000 to a HP OfficeJet T45.

Note that this bug effects the print quality of JEditorPane/JTextPane when i18n
is enabled, because javax.swing.text.GlyphPainter2 uses TextLayout.

public class TextLayoutTest {
    private static java.awt.Component canvas = new Canvas();

    public static void main( String args[]) {
	try {
	    java.awt.Frame frame = new java.awt.Frame("TextLayoutTest");
	    frame.setLayout( new java.awt.BorderLayout());
	    frame.addWindowListener( new java.awt.event.WindowAdapter() {
		    public void windowClosing( java.awt.event.WindowEvent
event) {
			System.exit(0);
		    }
		});
	    frame.add( canvas, java.awt.BorderLayout.CENTER);
	    javax.swing.JButton printButton = new javax.swing.JButton("print");
	    printButton.addActionListener( new java.awt.event.ActionListener() {
		    public void actionPerformed( java.awt.event.ActionEvent e) {
			try {
			    java.awt.print.PrinterJob printerJob =
java.awt.print.PrinterJob.getPrinterJob();
			    java.awt.print.Book book = new java.awt.print.Book
();
			    book.append( new PrintableAdapter( canvas),
printerJob.defaultPage());
			    printerJob.setPageable( book);
			    if( printerJob.printDialog()) {
				printerJob.print();
			    }
			}
			catch( Throwable ex) {
			    ex.printStackTrace();
			}
		    }
		});
	    frame.add( printButton, java.awt.BorderLayout.SOUTH);
	    frame.pack();
	    frame.setVisible( true);
	}
	catch( Exception ex) {
	    ex.printStackTrace();
	}
    }

    /**
     * The drawing surface.
     */
    static class Canvas extends java.awt.Component {

	/**
	 * Restrict our size to our preferred size.
	 */
	public java.awt.Dimension getPreferredSize() {
	    java.awt.Dimension dim = new java.awt.Dimension( 200, 150);
	    return dim;
	}
	public java.awt.Dimension getMaximumSize() {
	    return getPreferredSize();
	}
	public java.awt.Dimension getMinimumSize() {
	    return getPreferredSize();
	}

	/**
	 * The goodies are here.
	 */
	public void paint( java.awt.Graphics graphicsArg) {
	    java.awt.Graphics2D graphics = (java.awt.Graphics2D)graphicsArg;

	    graphics.setColor( java.awt.Color.black);
	    String text = "The Java language provides special support for the
string concatentation operator";
	    java.awt.Font font = new java.awt.Font("serif",
java.awt.Font.PLAIN, 6);
	    graphics.setFont( font);
	    graphics.drawString( text, 0, 50);
	    java.text.AttributedString string = new java.text.AttributedString(
text);
	    string.addAttribute( java.awt.font.TextAttribute.FONT, font);
	    java.text.AttributedCharacterIterator iterator = string.getIterator
();
	    java.awt.font.LineBreakMeasurer measurer = new
java.awt.font.LineBreakMeasurer( iterator, graphics.getFontRenderContext());
	    float y = 100;
	    while( measurer.getPosition() < iterator.getEndIndex()) {
		java.awt.font.TextLayout layout = measurer.nextLayout( getWidth
());
		y += layout.getAscent();
		layout.draw( graphics, 0, y);
		y += layout.getDescent() + layout.getLeading();
	    }
	}

    };

    /**
     * Adapter for printing AWT components.
     */
    static class PrintableAdapter implements java.awt.print.Printable {
	private java.awt.Component component;
	public PrintableAdapter( java.awt.Component componentArg) {
	    component = componentArg;
	}
	public int print( java.awt.Graphics graphicsArg,
java.awt.print.PageFormat pageFormat, int pageIndex) throws
java.awt.print.PrinterException {
	    java.awt.Graphics2D graphics = (java.awt.Graphics2D)graphicsArg;
	    graphics.translate( pageFormat.getImageableX(),
pageFormat.getImageableY());
	    graphics.setClip( 0, 0, (int)pageFormat.getImageableWidth(), (int)
pageFormat.getImageableHeight());
	    component.print( graphics);
	    return PAGE_EXISTS;
	}
    }
}
(Review ID: 128220) 
======================================================================

Comments
CONVERTED DATA BugTraq+ Release Management Values COMMIT TO FIX: tiger-beta FIXED IN: tiger-beta INTEGRATED IN: tiger-b31 tiger-beta
14-06-2004

EVALUATION The stated problem is not unexpected since TextLayout always prints as stroked and filled shapes whereas drawString usually uses GDI text APIs TextLayout prints as shapes becauses it uses GlyphVectors and these print as shapes in part because a GV can have complex behaviours such as per-glyph transforms that don't easily map directly to GDI text APIs For some of the more basic cases 1.4 beta 2 (aka beta refresh) should fix this as TextLayout has had optimisations added to use drawString. However many "normal" operations on TextLayout such as querying the ascent to determine where to draw the text will tickle the shape case again as TextLayout will bypass its optimisations irrevocably. Also it appears that the way in which TextLayouts are obtained from the AttributedString in this example have already tickled this problem and to see the benefit I needed to construct a TextLayout directly. Whilst the optimisations in TextLayout will be improved in the future it should also be possible to do more in the printing code to identify the GlyphVector cases which can be turned into GDI text calls (or Postscript text primitives on Solaris/Linux) Many more TextLayout usages in printing will then benefit from this. It should be noted that for this to make an observable difference you are going to have to be selecting a printer which has internal printer fonts which correspond to the ones you are using for rendering. I found the quality of the text displayed in each of these cases to be identical and very acceptable until I picked a particularly intricate font (Marigold) which my HP 5000 PS printer had as an internal font and which was also available to Java code as a TrueType font installed on my system. In this case the printer font was distinguishable as being less "bold". phil.race@eng 2001-07-17 ======================== TextLayout now (JDK 1.5) prints most non-CTL strings using printer fonts ###@###.### 2003-11-26 ============================
17-07-2001

WORK AROUND Name: bsC130419 Date: 07/17/2001 None found yet. ====================================================================== Use 1.4 beta 2 (refresh) or later. phil.race@eng 2001-07-17 =========================
17-07-2001