Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java App on Mac OS X not printing fonts correctly

I recently found out that a badge printing program I wrote that has been working fine for years on windows doesn't print correctly on MAC OS X. I am using Arial truetype font. The program seems to display a basic font, without proper scaling. I am using intellij and jdk1.7.0_15. The font appears correctly on the screen, but not when I print to a printer or pdf. When I list the fonts that are available to the program on the console using GraphicsEnvironment.getAvailableFontFamilyNames, Arial is listed as one of them. When I load the font from a font file directly, it works correctly. I've been chasing my tail on this for over a day, any suggestions would be appreciated. Here is the code that demonstrates my problem...

/**
 *  DisplayPage.java
 */
import java.awt.*;
import java.awt.print.*;

public class DisplayPage extends ApplicationFrame {

    public static void main(String[] args) {
        // Create app and display draw page
        DisplayPage f = new DisplayPage();
        f.setTitle("PaintingAndStroking v1.0");
        f.setSize(850, 1100);
        f.center();
        f.setVisible(true);

        // Generate print job to print page
        PrinterJob pj = PrinterJob.getPrinterJob();
        pj.setPrintable(new PrintPage());
        boolean doPrint = pj.printDialog();
        if (doPrint) {
            try {
                pj.print();
            } catch (PrinterException e) {
                System.out.println(e);
            }
        }
    }

    /**
     * This is called by the windows event processor
     * @param g java.awt.Graphics context for display
     */
    public void paint(Graphics g) {
        super.paint(g);
        Graphics2D g2d = (Graphics2D)g;
        DrawPage.draw(g2d);
    }

}

/**
 *  ApplicationFrame.java
 */
import java.awt.*;
import java.awt.event.*;

public class ApplicationFrame extends Frame {

    public ApplicationFrame() { this("ApplicationFrame v1.0"); }

    public ApplicationFrame(String title) {
        super(title);
        setSize(850, 1100);
        center();

        addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                dispose();
                System.exit(0);
            }
        });
    }

    public void center() {
        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
        Dimension frameSize = getSize();
        int x = (screenSize.width - frameSize.width) / 2;
        int y = (screenSize.height - frameSize.height) / 2;
        setLocation(x, y);
    }

}

/**
 * PrintPage.java
 */
import java.awt.*;
import java.awt.print.*;

public class PrintPage
        implements Printable {

    public int print(Graphics g, PageFormat pf, int page)
            throws PrinterException {

        // We have only one page
        if (page > 0) {
            return NO_SUCH_PAGE;
        }

        // Create Graphics2D context
        Graphics2D g2d = (Graphics2D)g;

        // Draw page
        DrawPage.draw(g2d);

        // Verify page exists
        return PAGE_EXISTS;
    }

}

/**
 * DrawPage.java
 */
import java.awt.*;

public class DrawPage {

    static public void draw(Graphics2D g2d) {
        GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
        Font[] fonts = ge.getAllFonts();
        String[] fontFamilies = ge.getAvailableFontFamilyNames();
        for (int i=0; i<fontFamilies.length; i++) {
            System.out.println(fontFamilies[i]);
        }

        double x = 15, y = 50, w = 70, h = 70;
        GradientPaint gp = new GradientPaint(75, 75, Color.white,
                95, 95, Color.gray, true);

        // Fill with a gradient
        g2d.setPaint(gp);

        // Stroke with a solid color.
        g2d.setPaint(Color.black);
        g2d.setStroke(new BasicStroke(8));

        // Stroke with a gradient.
        g2d.setPaint(gp);

        // Draw text string
        String text = new String("This is a test...");
        g2d.setPaint(Color.black);
        g2d.setStroke(new BasicStroke(8));
        Font font = new Font("Arial", Font.PLAIN, 36);
        g2d.setFont(font);
        g2d.drawString("This is a test of Arial 36", 50, 100);

        font = new Font("Arial", Font.PLAIN, 72);
        g2d.setFont(font);
        g2d.drawString("This is a test of Arial 72", 50, 200);

    }
}
like image 995
tslykhouse Avatar asked Oct 21 '22 14:10

tslykhouse


2 Answers

I wrote a blog post about this called Printing is Broken on Mac OS X with Java 7 which includes everything I found, including the cause, the bug reports, as well as our workaround for now. The short version is that it looks like a bug in either Apple's Mac OS or Java 7, and as of this writing it's still not fixed.

like image 123
Stephane Grenier Avatar answered Oct 27 '22 18:10

Stephane Grenier


There is a workaround available for this issue. The font rendering problems are due to a bug with the implementation of Graphics.drawString().

Two approaches to avoiding this:

  1. You can replace your calls to Graphics.drawString(... ) with a call like this

    • Graphics.drawGlyphVector(Graphics.getFont().createGlyphVector(Graphics.getFontRenderingContext(), String.toCharArray()))
  2. You can supply your own implementation of Graphics2D which overrides the drawString() methods and performs the above conversion and delegates to drawGlyphVector()

Using drawGlyphVector() will cause the text to be rendered by Java's AWT code, rather than the native OS's rendering, so there may be some visual artifacts and reduced performance. But it's much better than the current situation.

like image 37
user456837 Avatar answered Oct 27 '22 16:10

user456837