annotate at/ofai/music/util/PSPrinter.java @ 5:bcb4c9697967 tip

Add README and CITATION files
author Chris Cannam
date Tue, 03 Dec 2013 12:58:05 +0000
parents 4c3f5bc01c97
children
rev   line source
Chris@2 1 /*
Chris@2 2 Copyright (C) 2001, 2006 by Simon Dixon
Chris@2 3
Chris@2 4 This program is free software; you can redistribute it and/or modify
Chris@2 5 it under the terms of the GNU General Public License as published by
Chris@2 6 the Free Software Foundation; either version 2 of the License, or
Chris@2 7 (at your option) any later version.
Chris@2 8
Chris@2 9 This program is distributed in the hope that it will be useful,
Chris@2 10 but WITHOUT ANY WARRANTY; without even the implied warranty of
Chris@2 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Chris@2 12 GNU General Public License for more details.
Chris@2 13
Chris@2 14 You should have received a copy of the GNU General Public License along
Chris@2 15 with this program (the file gpl.txt); if not, download it from
Chris@2 16 http://www.gnu.org/licenses/gpl.txt or write to the
Chris@2 17 Free Software Foundation, Inc.,
Chris@2 18 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Chris@2 19 */
Chris@2 20
Chris@2 21 package at.ofai.music.util;
Chris@2 22
Chris@2 23 import java.awt.Component;
Chris@2 24 import java.awt.Graphics;
Chris@2 25 import java.awt.Graphics2D;
Chris@2 26 import java.awt.geom.AffineTransform;
Chris@2 27 import java.awt.print.PageFormat;
Chris@2 28 import java.awt.print.Printable;
Chris@2 29 import java.awt.print.PrinterException;
Chris@2 30 import java.awt.print.PrinterJob;
Chris@2 31
Chris@2 32 import at.ofai.music.util.Format;
Chris@2 33
Chris@2 34 /** A utility class for converting graphical user interface components to
Chris@2 35 * PostScript, which can be sent directly to a printer or printed to a file.
Chris@2 36 * This gives much higher quality illustrations for articles
Chris@2 37 * than if a screenshot is used, since scaling should not reduce quality.
Chris@2 38 * The only requirement is that the component to be printed has a
Chris@2 39 * <code>paint(Graphics)</code> method.
Chris@2 40 * <p>There are some bugs in this code which require manual editing of
Chris@2 41 * the PostScript file. First, there doesn't seem to be any way to include
Chris@2 42 * the bounding box, although it is possible to calculate it. Second, the
Chris@2 43 * cliprect produced in the PostScript output is wrong.
Chris@2 44 * (Check: has this been fixed in more recent Java versions?
Chris@2 45 * Apparently not, as of 1.5.0, but if scaling is not performed, the cliprect
Chris@2 46 * is OK and the bounding box correct.)
Chris@2 47 * See {@link PSPrinter#print(Graphics, PageFormat, int)}
Chris@2 48 */
Chris@2 49 public class PSPrinter implements Printable {
Chris@2 50
Chris@2 51 /** the component to be converted */
Chris@2 52 Component component;
Chris@2 53 /** the desired graphical resolution in pixels per inch */
Chris@2 54 int resolution; // can't work out how to ask the system
Chris@2 55
Chris@2 56 /** Print a GUI component to a PostScript printer or file.
Chris@2 57 * The 2 forms of this method are the normal ways of accessing this class.
Chris@2 58 * This form has problems printing some components. It is recommended to
Chris@2 59 * use the other version.
Chris@2 60 * @param c the component to be rendered in PostScript
Chris@2 61 * @param r the resolution of the printer in pixels per inch
Chris@2 62 */
Chris@2 63 public static void print(Component c, int r) {
Chris@2 64 new PSPrinter(c, r).doPrint();
Chris@2 65 }
Chris@2 66
Chris@2 67 /** Print a GUI component to a PostScript printer or file.
Chris@2 68 * The 2 forms of this method are the normal ways of accessing this class.
Chris@2 69 * If no resolution is given, the picture is not scaled, and the cliprect
Chris@2 70 * is then correct. This is the recommended version to use.
Chris@2 71 * @param c the component to be rendered in PostScript
Chris@2 72 */
Chris@2 73 public static void print(Component c) {
Chris@2 74 new PSPrinter(c, -1).doPrint();
Chris@2 75 }
Chris@2 76
Chris@2 77 /** Constructs a PSPrinter for a given graphical component and resolution.
Chris@2 78 * @param c the component to be rendered in PostScript
Chris@2 79 * @param res the resolution of the printer in pixels per inch; set res to
Chris@2 80 * -1 for no scaling (avoids the apparently buggy cliprect)
Chris@2 81 */
Chris@2 82 public PSPrinter(Component c, int res) {
Chris@2 83 component = c;
Chris@2 84 resolution = res;
Chris@2 85 } // constructor
Chris@2 86
Chris@2 87 /** Produces a print dialog and executes the requested print job.
Chris@2 88 * The print job performs its task by callback of the
Chris@2 89 * {@link PSPrinter#print(Graphics, PageFormat, int)} method.
Chris@2 90 */
Chris@2 91 public void doPrint() {
Chris@2 92 PrinterJob printJob = PrinterJob.getPrinterJob();
Chris@2 93 printJob.setPrintable(this); // tell it where the rendering code is
Chris@2 94 if (printJob.printDialog()) {
Chris@2 95 try {
Chris@2 96 printJob.print();
Chris@2 97 } catch (Exception ex) {
Chris@2 98 ex.printStackTrace();
Chris@2 99 }
Chris@2 100 }
Chris@2 101 } // doPrint()
Chris@2 102
Chris@2 103 /** The callback method for performing the printing / Postscript conversion.
Chris@2 104 * The resulting PostScript file requires some post-editing.
Chris@2 105 * In particular, there are two problems to be dealt with:
Chris@2 106 * <p>1) The file has no bounding box. This method prints the correct
Chris@2 107 * bounding box to stardard output, and it must then be cut and pasted
Chris@2 108 * into the PostScript file. (There must be a better way!)
Chris@2 109 * <p>2) The cliprect is wrong (but only if the resolution is specified).
Chris@2 110 * This is solved by using resolution = -1 or by deleting the lines
Chris@2 111 * in the PostScript file from <code>newpath</code> to <code>clip</code>.
Chris@2 112 * (I don't know if this causes problems for components that try to draw
Chris@2 113 * outside of their area.)
Chris@2 114 * @param g the graphics object used for painting
Chris@2 115 * @param f the requested page format (e.g. A4)
Chris@2 116 * @param pg the page number (must be 0, or we report an error)
Chris@2 117 * @return the error status; if the page is successfully rendered,
Chris@2 118 * Printable.PAGE_EXISTS is returned, otherwise if a page number greater
Chris@2 119 * than 0 is requested, Printable.NO_SUCH_PAGE is returned
Chris@2 120 * @throws PrinterException thrown when the print job is terminated
Chris@2 121 */
Chris@2 122 public int print(Graphics g, PageFormat f, int pg) throws PrinterException {
Chris@2 123 if (pg >= 1)
Chris@2 124 return Printable.NO_SUCH_PAGE;
Chris@2 125 Graphics2D g2 = (Graphics2D) g;
Chris@2 126 double wd = component.getWidth();
Chris@2 127 double ht = component.getHeight();
Chris@2 128 double imwd = f.getImageableWidth();
Chris@2 129 double imht = f.getImageableHeight();
Chris@2 130 double corr = resolution / 72.0;
Chris@2 131 double scaleFactor = corr * Math.min(imwd / wd, imht / ht);
Chris@2 132 double xmin = f.getImageableX();
Chris@2 133 double ymin = f.getImageableY();
Chris@2 134 AffineTransform scale = new AffineTransform(scaleFactor, 0,
Chris@2 135 0, scaleFactor,
Chris@2 136 corr * xmin, corr * ymin);
Chris@2 137 Format.setGroupingUsed(false);
Chris@2 138 double pgHt = f.getHeight();
Chris@2 139 if (resolution > 0) {
Chris@2 140 g2.setTransform(scale);
Chris@2 141 System.out.println("%%BoundingBox: " +
Chris@2 142 Format.d(xmin, 0) + " " +
Chris@2 143 Format.d(pgHt - ymin - ht * scaleFactor / corr, 0) + " " +
Chris@2 144 Format.d(xmin + wd * scaleFactor / corr, 0) + " " +
Chris@2 145 Format.d(pgHt - ymin, 0));
Chris@2 146 } else {
Chris@2 147 g2.setClip(0, 0, (int)wd, (int)ht);
Chris@2 148 System.out.println("%%BoundingBox: " +
Chris@2 149 Format.d(0, 0) + " " +
Chris@2 150 Format.d(pgHt - ht, 0) + " " +
Chris@2 151 Format.d(wd, 0) + " " +
Chris@2 152 Format.d(pgHt, 0));
Chris@2 153 }
Chris@2 154
Chris@2 155 // System.out.println(f.getWidth() + " " + f.getHeight() + " " +
Chris@2 156 // f.getImageableX() + " " + f.getImageableY() + " " +
Chris@2 157 // f.getImageableWidth() + " " + f.getImageableHeight());
Chris@2 158 // Letter = 8.5x11" 612x792pt DEFAULT
Chris@2 159 // A4 = 210x297mm 595x842pt
Chris@2 160
Chris@2 161 // AffineTransform scale = new AffineTransform(2.5, 0, 0, 2.5, 200, 1000);
Chris@2 162 // g2.setTransform(scale); // The figures need some fiddling.
Chris@2 163 // In particular, the PostScript file has:
Chris@2 164 // 1) no bounding box (add manually)
Chris@2 165 // 2) wrong cliprect (delete lines from
Chris@2 166 // "newpath" to "clip")
Chris@2 167 component.printAll(g2);
Chris@2 168 return Printable.PAGE_EXISTS;
Chris@2 169 } // print()
Chris@2 170
Chris@2 171 } // class PSPrinter