I am printing a Swing component that contains text. The Swing component renders the text just fine on the screen, but, when I print it (to a .tif file), the characters are all smashed together. Why is this?
Run this code to see what I mean:
import javax.swing.*;
import javax.swing.text.MutableAttributeSet;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyledDocument;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.print.PageFormat;
import java.awt.print.Printable;
import java.awt.print.PrinterException;
import java.awt.print.PrinterJob;
public final class PrintingDemo2 implements Printable {
private final JTextPane textPane;
private static final String WORDS = "GOOD MORNING\u00AE AMERICA";
private static final String TEXT = WORDS + '\n' + WORDS + '\n' + WORDS + '\n' + WORDS + '\n' + WORDS + '\n' + WORDS;
public static void main(String[] args) {
new PrintingDemo2();
}
public PrintingDemo2() {
textPane = new JTextPane();
textPane.setText(TEXT);
final StyledDocument document = textPane.getStyledDocument();
String[] fontFamilies = new String[]{"Tahoma", "SimSum", "MS Mincho", "Batang", "Arial", "Times New Roman"};
for (int i = 0; i < fontFamilies.length; i++) {
final MutableAttributeSet attributeSet = new SimpleAttributeSet();
StyleConstants.setFontFamily(attributeSet, fontFamilies[i]);
StyleConstants.setFontSize(attributeSet, 14);
document.setParagraphAttributes(i * 22, 21, attributeSet, true);
}
final AbstractButton printContextButton = new JButton("Print Context");
printContextButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
final PrinterJob job = PrinterJob.getPrinterJob();
job.setPrintable(PrintingDemo2.this);
try {
job.print();
} catch (PrinterException ex) {
throw new RuntimeException("Printing Failed.", ex);
}
}
});
final JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final Container contentPane = frame.getContentPane();
contentPane.setLayout(new BoxLayout(contentPane, BoxLayout.Y_AXIS));
contentPane.add(printContextButton);
contentPane.add(new JScrollPane(textPane));
frame.setSize(400, 200);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
frame.setVisible(true);
}
});
}
public int print(Graphics graphics, PageFormat pageFormat, int pageIndex) throws PrinterException {
if (pageIndex >= 1) return Printable.NO_SUCH_PAGE;
RepaintManager mgr = RepaintManager.currentManager(textPane);
mgr.setDoubleBufferingEnabled(false);
final Graphics2D graphics2D = (Graphics2D) graphics;
graphics2D.translate(pageFormat.getImageableX(), pageFormat.getImageableY());
textPane.paint(graphics);
mgr.setDoubleBufferingEnabled(true);
return Printable.PAGE_EXISTS;
}
}
You could try rasterizing it (painting it to a BufferedImage at 300dpi) and then printing that image. Hacky, and bad for performance (huge rasterized file sent to printer instead of vector data), but at least you won’t have font problems.
To rasterize it, create a BufferedImage that is 4.17x (300/72) the size of your on-screen panel and scale its graphics object be the same abount, and then paint the panel onto the buffered image’s Graphics2D object.
Disclaimer: this isn’t elegant and I know it. If someone knows how to convince every make and model of printer to receive fonts from a Java printing process, please chime in!