JDK-4352983 : Clipping of text when printing
  • Type: Bug
  • Component: client-libs
  • Sub-Component: javax.swing
  • Affected Version: 1.3.0,1.3.1,1.4.0,1.4.1,1.4.1_01
  • Priority: P4
  • Status: Resolved
  • Resolution: Fixed
  • OS:
    windows_98,windows_nt,windows_2000,windows_xp windows_98,windows_nt,windows_2000,windows_xp
  • CPU: x86
  • Submitted: 2000-07-13
  • Updated: 2003-12-15
  • Resolved: 2003-12-15
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 b32Fixed
Related Reports
Duplicate :  
Duplicate :  
Duplicate :  
Duplicate :  
Duplicate :  
Duplicate :  
Relates :  
Relates :  
Relates :  
Description
Name: sl110371			Date: 07/13/2000


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

It seems that JTextArea doesn't print to a printer properly.  When the JTextArea
is painted on the screen, everything looks fine.  When looking at the output
from a printer or printed file, the right side of the text area is clipped.
Below is some sample code to run:

// start sample code

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

public class ClippingBug extends JFrame implements Printable
{    
    JTextArea text;
    JLabel label;
    JPanel holder;

    public ClippingBug( )
    {
        RepaintManager.currentManager( this ).setDoubleBufferingEnabled(
            false );
        Font theFont = new Font( "SansSerif", Font.PLAIN, 8 );

        holder = new JPanel( new GridLayout( 1, 2 ) );
        text = new JTextArea( "The quick brown fox jumped over the lazy dog." +
            "All work and no play makes Jack a dull boy.  Dark is the " +
            "suede that mows like a harvest." );
        label = new JLabel( "This is to take up space." );
        label.setBorder( new LineBorder( Color.red ) );
        
        text.setLineWrap( true );
        text.setWrapStyleWord( true );
        text.setFont( theFont );

        holder.add( text );
        holder.add( label );

        getContentPane( ).setLayout( new GridLayout( 2, 1 ) );
        getContentPane( ).add( holder );
        pack( );
        setSize( 400, 400 );
        setVisible( true );
    }
	
    public int print( Graphics g2, PageFormat pf, int pageIndex )
    {
        if ( pageIndex > 1 )
        {
            return( Printable.NO_SUCH_PAGE );
        }
		
        Graphics2D g = (Graphics2D)g2;
        g.translate( pf.getImageableX( ), pf.getImageableY( ) );
		
        g.translate( holder.getX( ), holder.getY( ) );
        holder.paint( g );
        g.translate( -holder.getX( ), -holder.getY( ) );

        return( Printable.PAGE_EXISTS );
    }
	
    public void doPrint( )
    {
        PrinterJob pj = PrinterJob.getPrinterJob( );
	    
        pj.setPrintable( this );

        if( pj.printDialog( ) )
        {
            try
            {
                pj.print( );
            }
            catch( PrinterException ee )
            {
                System.out.println( ee );
            }
        }
    }
	
    public static void main( String args[] )
    {
        ClippingBug a = new ClippingBug( );
        a.doPrint( );
        System.exit( 0 );
    }
}

// end sample code

Running the code shows that the entire JTextArea is printed, but some of the
words are clipped on the right hand side.  By placing a border around the text
area, you can see that it isn't getting painted over by the JLabel filling in
the right hand side of the grid.  Changing the UI does not improve results.

This is a new problem that was introduced when 1.3 came out of Beta.  Similar
results have been observed using JEditorPane and JTextPane.  Also, creating your
own simple TextArea class by extending JComponent and writing a UI does not
solve the problem.  The custom component is still clipped on the right hand side
when printed, but not when it is painted to the screen.  Running the same code
on 1.3beta results in the entire JTextArea being printed, with no clipping on
the right hand side.
(Review ID: 107131) 
======================================================================
This bug is a java2D bug.
Size of a string painted on the screen differs from the size of a string painted on the printer device.

see evaluation section for PrintingBug.java example.

###@###.### 2001-11-08

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

EVALUATION ###@###.### 2001-10-03 What is the state of the bug? What progress has been made since 05/21/2001 ? ================================================== In fact this bug is a java2D bug. Size of a string painted on the screen differs from the size of a string painted on the printer device. ---- PrintingBug.java --------------------------------- import java.awt.*; import java.awt.print.*; import java.awt.geom.*; public class PrintingBug extends Frame implements Printable { int fontsNumber = 15; Font [] fonts = new Font[fontsNumber]; Rectangle2D [] stringBounds = null; String testString = "All work and no play makes Jack a dull boy."; public PrintingBug () { for (int i = 0; i < fontsNumber; i++) { fonts[i] = new Font( "SansSerif", Font.PLAIN, 5+i ); } } public int print( Graphics _g, PageFormat pf, int pageIndex ) { if ( pageIndex > 0 ) { return NO_SUCH_PAGE; } Graphics2D g = (Graphics2D) _g; g.translate( pf.getImageableX( ), pf.getImageableY( ) ); paint(g); return Printable.PAGE_EXISTS; } public void paint(Graphics g) { super.paint(g); if (stringBounds == null) { stringBounds = new Rectangle2D[fontsNumber]; for (int i = 0; i < fontsNumber; i++) { stringBounds[i] = g.getFontMetrics(fonts[i]).getStringBounds(testString,g); } } g.setColor(Color.black); Insets insets = getInsets(); g.translate(insets.left,insets.top); for (int i = 0; i < fontsNumber; i++) { g.translate(0,10); g.drawRect(0,0,(int)stringBounds[i].getWidth(),(int)stringBounds[i].getHeight()); g.translate(0,(int)stringBounds[i].getHeight()); g.setFont(fonts[i]); g.drawString(testString,0,0); System.out.println(g.getFontMetrics().getStringBounds(testString,g)); } } public void doPrint() { PrinterJob pj = PrinterJob.getPrinterJob( ); pj.setPrintable( this ); if( pj.printDialog( ) ) { try { pj.print( ); } catch( PrinterException ee ) { System.out.println( ee ); } } } public static void main(String[] args) { PrintingBug printingBug = new PrintingBug(); printingBug.setSize(400,600); printingBug.show(); printingBug.doPrint(); } } ---------------------------------------- The example calculates boundaries for sctrings painted on the screen and uses the same boundaries for strings painted on the printer device. You can see that sizes are not the same Changing category to classes_2D ###@###.### 2001-11-08 ======================================= This is a bug in Swing since Swing caches the font metrics from a screen context and then assumes they are valid in all contexts. This is incorrect and needs to be fixed in the code that makes this assumption. eg in the Swing implementation. The basic technical issue is that screen fonts at small point sizes are tweaked by the font vendors to look good at those sizes with the limited number of pixels available at screen resolution. At high reslutions such as obtained on printers this isn't scaling exactly with the graphics transform. This information is coming from the font in both cases. There has to be either a compensation for this or an accomodation of it. The usually accepted method is to measure text for the context in which its going to be displayed. In this case swing is measuring at screen resolution but displaying at printer resolution. ###@###.### 2002-02-16 ============================ The fix to Swing will involve the following: . Move all painting calls in Swing to SwingUtilities2. . In painting check if we're printing and if printing use TextLayout to layout the text just like it appeared on screen. . All calls to get the FontMetrics should get the FontMetrics from the Component. You shouldn't use the FontMetrics from the Graphics as that isn't what we layed the text out. Additionally this fix will consolidate some redundant painting code. ###@###.### 2003-11-24
24-11-2003

WORK AROUND In the print method of ClipingBug.java you can paint to offscreen image first and paint the image to graphics. BufferedImage image = new BufferedImage(holder.getWidth(),holder.getHeight(),BufferedImage.TYPE_INT_RGB); Graphics2D graphicsTmp = image.createGraphics(); graphicsTmp.translate( holder.getX( ), holder.getY( ) ); holder.paint( graphicsTmp ); g.drawImage(image,0,0,Color.white,null); ###@###.### 2001-11-08
08-11-2001