United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
Bug ID: JDK-4480930 Java 2D printing : TextLayout prints as filled shapes.
JDK-4480930 : Java 2D printing : TextLayout prints as filled shapes.

Details
Type:
Bug
Submit Date:
2001-07-17
Status:
Resolved
Updated Date:
2003-12-08
Project Name:
JDK
Resolved Date:
2003-12-08
Component:
client-libs
OS:
windows_nt,windows_2000
Sub-Component:
2d
CPU:
x86
Priority:
P3
Resolution:
Fixed
Affected Versions:
1.4.0
Fixed Versions:
5.0 (b31)

Related Reports
Duplicate:

Sub Tasks

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
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
=========================
                                     
2001-07-17
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
============================
                                     
2001-07-17
CONVERTED DATA

BugTraq+ Release Management Values

COMMIT TO FIX:
tiger-beta

FIXED IN:
tiger-beta

INTEGRATED IN:
tiger-b31
tiger-beta


                                     
2004-06-14



Hardware and Software, Engineered to Work Together