Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java printing: creating a PageFormat with minimum acceptable margin

Tags:

java

printing

I'm trying to get the PageFormat correct when I print. Below is an example program that shows my dilemma: I get a different result when I use printJob.setPrintable(printable) than when I use printJob.setPageable(book) when I create a Book object using the default PageFormat from the Print job.

When I run it, and click "Print", then "Print using Book", I see this console output:

doPrint(false)
printing on 612.000000x792.000000 paper, imageable area=588.960000x768.960000
printing on 612.000000x792.000000 paper, imageable area=588.960000x768.960000
printing on 612.000000x792.000000 paper, imageable area=588.960000x768.960000
doPrint(true)
printing on 612.000000x792.000000 paper, imageable area=468.000000x648.000000
printing on 612.000000x792.000000 paper, imageable area=468.000000x648.000000

What gives? The default page format when using Book sucks and uses 1" margin on each side of the page; the "real" page format only needs about 1/6" margin on each side.

example program here:

package com.example.printing;

import java.awt.BasicStroke;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.geom.Rectangle2D;
import java.awt.print.Book;
import java.awt.print.PageFormat;
import java.awt.print.Paper;
import java.awt.print.Printable;
import java.awt.print.PrinterException;
import java.awt.print.PrinterJob;

import javax.swing.AbstractAction;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class PrintRectangles extends JFrame 
{
    static final int Nrectangles = 3;

    static class RectangleThingy extends JPanel implements Printable
    {
        @Override public int print(Graphics graphics, 
                PageFormat pageFormat, 
                int pageIndex)
            throws PrinterException 
        {
            describePageFormat(pageFormat);
            if (pageIndex > 0) {
                return(NO_SUCH_PAGE);
            } 
            else {
                Graphics2D g2d = (Graphics2D)graphics;
                g2d.translate(pageFormat.getImageableX(), 
                        pageFormat.getImageableY());
                double w = pageFormat.getImageableWidth();
                double h = pageFormat.getImageableHeight();
                final int N = (Nrectangles - 1) / 2;
                final double spacing = 7.2; // 1/10 inch 
                g2d.setStroke(new BasicStroke(0.1f));
                for (int i = -N; i <= N; ++i)
                {
                    double dx = i*spacing;
                    Rectangle2D r = new Rectangle2D.Double(
                            dx, dx, w-2*dx, h-2*dx
                            );
                    g2d.draw(r);
                }
                Rectangle2D rthick = new Rectangle2D.Double(
                        0, 0, w, h
                        );
                g2d.setStroke(new BasicStroke(1.0f));
                g2d.draw(rthick);
                return(PAGE_EXISTS);
            }
        }

        private void describePageFormat(PageFormat pageFormat) {
            System.out.println(String.format("printing on %fx%f paper, imageable area=%fx%f",
                    pageFormat.getWidth(),
                    pageFormat.getHeight(),
                    pageFormat.getImageableWidth(),
                    pageFormat.getImageableHeight()
                    ));

        }
    }

    static private class PrintPreviewPanel extends JPanel
    {
        final private Printable p;
        final private PageFormat pageFormat;
        public PrintPreviewPanel(Printable p, PageFormat pf)
        {
            this.p = p;
            this.pageFormat = pf;
        }
        @Override public Dimension getPreferredSize() {
            return new Dimension((int)this.pageFormat.getWidth(), 
                    (int)this.pageFormat.getHeight());
        }
        @Override protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            try {
                p.print(g, this.pageFormat, 0);
            } catch (PrinterException e) {
                e.printStackTrace();
            }
        }       
    }

    public PrintRectangles(String title) {
        super(title);
        JPanel panel = new JPanel();
        setContentPane(panel);
        panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
        JButton printButton = new JButton("Print");
        JButton printUsingBookButton = new JButton("Print using Book");
        JButton printPreviewButton = new JButton("Print preview");
        panel.add(printButton);
        panel.add(printUsingBookButton);
        panel.add(printPreviewButton);
        printButton.addActionListener(new AbstractAction("print") {
            @Override public void actionPerformed(ActionEvent e) {
                doPrint(false);
            }           
        });
        printUsingBookButton.addActionListener(new AbstractAction("printUsingBook") {
            @Override public void actionPerformed(ActionEvent e) {
                doPrint(true);
            }           
        });
        printPreviewButton.addActionListener(new AbstractAction("printPreview") {
            @Override public void actionPerformed(ActionEvent e) {
                doPrintPreview();
            }           
        });
    }

    protected void doPrint(boolean useBook) {
        RectangleThingy rectangleThingy = new RectangleThingy();
        System.out.println("doPrint("+useBook+")");
        try
        {
            PrinterJob printJob = PrinterJob.getPrinterJob();
            PageFormat pageFormat = printJob.getPageFormat(null);
            if (useBook)
            {
                Book book = new Book();
                book.append(rectangleThingy, pageFormat);               
                printJob.setPageable(book);
            }
            else
            {
                printJob.setPrintable(rectangleThingy);             
            }
            if (printJob.printDialog())
                printJob.print();
        } 
        catch(PrinterException pe) {
            System.out.println("Error printing: " + pe);
        }
    }

    protected void doPrintPreview() {
        RectangleThingy rt = new RectangleThingy();
        JFrame frame = new JFrame("print preview");

        // hack for now -- how do we get this from the printer?
        Paper paper = new Paper();
        double dotsperinch = 72;
        double margin = 0.125*dotsperinch;
        double w = 8.5*dotsperinch;
        double h = 11*dotsperinch;
        paper.setImageableArea(margin, margin, w-2*margin, h-2*margin);
        paper.setSize(w, h);
        PageFormat pfmt = new PageFormat();
        pfmt.setPaper(paper);
        frame.setContentPane(new PrintPreviewPanel(rt, pfmt));
        frame.pack();
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        new PrintRectangles("PrintRectangles").start();
    }

    private void start() {
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        pack();
        setVisible(true);
    }
}
like image 275
Jason S Avatar asked May 04 '12 19:05

Jason S


1 Answers

Hmm. After trying a number of fruitless efforts, it looks like setting a page to zero margin and then calling PrinterJob.validatePage() seems to be the only way I can get a valid minimum-margin PageFormat:

static private PageFormat getMinimumMarginPageFormat(PrinterJob printJob) {
    PageFormat pf0 = printJob.defaultPage();
    PageFormat pf1 = (PageFormat) pf0.clone();
    Paper p = pf0.getPaper();
    p.setImageableArea(0, 0,pf0.getWidth(), pf0.getHeight());
    pf1.setPaper(p);
    PageFormat pf2 = printJob.validatePage(pf1);
    return pf2;     
}

and then I can change doPrint() to:

protected void doPrint(boolean useBook) {
    RectangleThingy rectangleThingy = new RectangleThingy();
    System.out.println("doPrint("+useBook+")");
    try
    {
        PrinterJob printJob = PrinterJob.getPrinterJob();
        if (useBook)
        {
            Book book = new Book();
            book.append(rectangleThingy, getMinimumMarginPageFormat(printJob));
            printJob.setPageable(book);
        }
        else
        {
            printJob.setPrintable(rectangleThingy);        
        }
        if (printJob.printDialog())
            printJob.print();
    } 
    catch(PrinterException pe) {
        System.out.println("Error printing: " + pe);
    }
}
like image 113
Jason S Avatar answered Nov 07 '22 05:11

Jason S