United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
JDK-4352983 : Clipping of text when printing

Details
Type:
Bug
Submit Date:
2000-07-13
Status:
Resolved
Updated Date:
2003-12-15
Project Name:
JDK
Resolved Date:
2003-12-15
Component:
client-libs
OS:
windows_98,windows_nt,windows_2000,windows_xp
Sub-Component:
javax.swing
CPU:
x86
Priority:
P4
Resolution:
Fixed
Affected Versions:
1.3.0,1.3.1,1.4.0,1.4.1,1.4.1_01
Fixed Versions:
5.0 (b32)

Related Reports
Duplicate:
Duplicate:
Duplicate:
Duplicate:
Duplicate:
Duplicate:
Relates:
Relates:
Relates:

Sub Tasks

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


                                     
2004-06-14
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
                                     
2003-11-24
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
                                     
2001-11-08



Hardware and Software, Engineered to Work Together