0
votes

My program prints A6 size pages, however, I often use larger paper. In that situation, I would like to print a border around the A6 virtual page to help me trim the paper. But I want a solution that works if I ever use actual A6 paper.

I am running on macOS.

I configure the pageDialog() with the desired page size (3.75 x 6.75 inches) and a full size imageable area. The validated returned PageFormat matches that size and imageable area.

However, when my Printable is called, the PageFormat is different: the paper size is 3.875 x 7.5 inches, the imagable area is 3.375 x 6.55 inches, with a left margin of .25 inch and a top margin of .2 inch. I can understand the top margin, because the actual printing on 8.5 x 11 inch paper is at the top of the paper. The left margin is not obvious, because the actual printing is centered horizontally. (The printer apparently knows the paper width, but perhaps the software does not know what the printer will do?)

I draw the border:

double paperWidth = 3.75 * 72;
double paperHeight = 6.75 * 72;
g.draw(new Rectangle2D.Double(2, 2, paperWidth - 2, paperHeight - 2));

(The 2 is a fudge factor.)

All I get is a thin line at the bottom, but nothing at the sides. (I don't care about the top.) That makes sense if the imageable area is causing clipping.

I have tried altering the imageable area and clip region, but nothing changes.

pageFormat.getPaper().setImageableArea(0, 0, paperWidth, paperHeight);
g = (Graphics2D) g.create();
g.setClip(0, 0, (int) paperWidth, (int) paperHeight);
g.draw(new Rectangle2D.Double(2, 2, paperWidth - 2, paperHeight - 2));
g.dispose();
1

1 Answers

0
votes

As to why your code's not working, I can't say, as there isn't enough of it to be sure. One thing which seems to be obvious is, you're ignoring the page margins when you paint, which is going to be an issue. Also, you can't change the PageFormat during a printing process, as this information has already been used to produce the physical print job (to the printer).

The following example basically assumes that the desired target of the output page is A6, if the page is not the right size, it will print a border around an area which represents a A6 page.

The example is far from complete, as I don't take into consideration what will happen if the page is smaller, only larger, something for you to nut out.

The example defaults the page to A4 with a very small margin (0.1 cm), but the concept should remain the same for a default page

Example

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
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 java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;

public class Test {

    public static PaperSize A6_PAPER = new PaperSize(toPPI(4.1), toPPI(5.8));
    public static PaperSize A4_PAPER = new PaperSize(toPPI(8.27), toPPI(11.69));

    public static void main(String[] args) throws IOException {
        BufferedImage background = ImageIO.read(new File("/Users/shanew/Downloads/1512455_10152727077279377_24129534228312133_n.jpg"));
        PrinterJob pj = PrinterJob.getPrinterJob();
        if (pj.printDialog()) {
            PageFormat pf = pj.defaultPage();
            Paper paper = pf.getPaper();

            double width = A4_PAPER.getWidth();            
            double height = A4_PAPER.getHeight();
            paper.setSize(width, height);
            paper.setImageableArea(
                    fromCMToPPI(0.1),
                    fromCMToPPI(0.1),
                    width - fromCMToPPI(0.1),
                    height - fromCMToPPI(0.1));
            pf.setOrientation(PageFormat.PORTRAIT);
            pf.setPaper(paper);
            PageFormat validatePage = pj.validatePage(pf);
            pj.setPrintable(new FancyOutput(background), validatePage);
            try {
                pj.print();
            } catch (PrinterException ex) {
                ex.printStackTrace();
            }
        }
    }

    public static class FancyOutput implements Printable {

        protected static final Rectangle2D BORDER = new Rectangle2D.Double(0, 0, A6_PAPER.getWidth() - 1, A6_PAPER.getHeight() - 1);

        private BufferedImage background;

        public FancyOutput(BufferedImage background) {
            this.background = background;
        }

        @Override
        public int print(Graphics g, PageFormat pf, int page) throws PrinterException {
            Graphics2D g2d = (Graphics2D) g.create();
            if (page != 0) {
                return NO_SUCH_PAGE;
            }
            double width = pf.getImageableWidth();
            double height = pf.getImageableHeight();

            double x = pf.getImageableX();
            double y = pf.getImageableY();

            if (width != A6_PAPER.getWidth() || height != A6_PAPER.getHeight()) {
                x = x + ((width - A6_PAPER.getWidth()) / 2);
                y = y + ((height - A6_PAPER.getHeight()) / 2);

                System.out.println(x + "x" + y);
            }

            g2d.translate((int) x,
                    (int) y);
            Shape oldClip = g2d.getClip();
            g2d.setClip(BORDER);
            g2d.drawImage(background, 0, 0, null);

            g2d.setClip(oldClip);
            if (width != A6_PAPER.getWidth() || height != A6_PAPER.getHeight()) {
                g2d.setColor(Color.RED);
                g2d.draw(BORDER);
            }

            g2d.dispose();

            return PAGE_EXISTS;
        }

    }

    public static class PaperSize {

        private double width;
        private double height;

        public PaperSize(double width, double height) {
            this.width = width;
            this.height = height;
        }

        public double getWidth() {
            return width;
        }

        public double getHeight() {
            return height;
        }
    }

    protected static double fromCMToPPI(double cm) {
        return toPPI(cm * 0.393700787);
    }

    protected static double toPPI(double inch) {
        return inch * 72d;
    }
}