/jdk/src/share/classes/sun/print/PSPrinterJob.java
Java | 2210 lines | 1309 code | 307 blank | 594 comment | 255 complexity | 5774c67d37b8a6cfb2789f7442ced070 MD5 | raw file
Possible License(s): LGPL-3.0, GPL-2.0, BSD-3-Clause-No-Nuclear-License-2014, BSD-3-Clause
Large files files are truncated, but you can click here to view the full file
- /*
- * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
- package sun.print;
- import java.awt.Color;
- import java.awt.Component;
- import java.awt.Font;
- import java.awt.FontMetrics;
- import java.awt.GraphicsEnvironment;
- import java.awt.Graphics;
- import java.awt.Graphics2D;
- import java.awt.HeadlessException;
- import java.awt.Rectangle;
- import java.awt.Shape;
- import java.awt.image.BufferedImage;
- import java.awt.font.FontRenderContext;
- import java.awt.geom.AffineTransform;
- import java.awt.geom.PathIterator;
- import java.awt.geom.Rectangle2D;
- import java.awt.image.BufferedImage;
- import java.awt.print.Pageable;
- import java.awt.print.PageFormat;
- import java.awt.print.Paper;
- import java.awt.print.Printable;
- import java.awt.print.PrinterException;
- import java.awt.print.PrinterIOException;
- import java.awt.print.PrinterJob;
- import javax.print.DocFlavor;
- import javax.print.PrintService;
- import javax.print.StreamPrintService;
- import javax.print.attribute.HashPrintRequestAttributeSet;
- import javax.print.attribute.PrintRequestAttributeSet;
- import javax.print.attribute.standard.Chromaticity;
- import javax.print.attribute.standard.Copies;
- import javax.print.attribute.standard.Destination;
- import javax.print.attribute.standard.JobName;
- import javax.print.attribute.standard.Sides;
- import java.io.BufferedInputStream;
- import java.io.BufferedOutputStream;
- import java.io.CharConversionException;
- import java.io.File;
- import java.io.InputStream;
- import java.io.IOException;
- import java.io.FileInputStream;
- import java.io.FileOutputStream;
- import java.io.OutputStream;
- import java.io.PrintStream;
- import java.util.ArrayList;
- import java.util.Enumeration;
- import java.util.Locale;
- import java.util.Properties;
- import sun.awt.CharsetString;
- import sun.awt.FontConfiguration;
- import sun.awt.FontDescriptor;
- import sun.awt.PlatformFont;
- import sun.awt.SunToolkit;
- import java.nio.charset.*;
- import java.nio.CharBuffer;
- import java.nio.ByteBuffer;
- //REMIND: Remove use of this class when IPPPrintService is moved to share directory.
- import java.lang.reflect.Method;
- /**
- * A class which initiates and executes a PostScript printer job.
- *
- * @author Richard Blanchard
- */
- public class PSPrinterJob extends RasterPrinterJob {
- /* Class Constants */
- /**
- * Passed to the <code>setFillMode</code>
- * method this value forces fills to be
- * done using the even-odd fill rule.
- */
- protected static final int FILL_EVEN_ODD = 1;
- /**
- * Passed to the <code>setFillMode</code>
- * method this value forces fills to be
- * done using the non-zero winding rule.
- */
- protected static final int FILL_WINDING = 2;
- /* PostScript has a 64K maximum on its strings.
- */
- private static final int MAX_PSSTR = (1024 * 64 - 1);
- private static final int RED_MASK = 0x00ff0000;
- private static final int GREEN_MASK = 0x0000ff00;
- private static final int BLUE_MASK = 0x000000ff;
- private static final int RED_SHIFT = 16;
- private static final int GREEN_SHIFT = 8;
- private static final int BLUE_SHIFT = 0;
- private static final int LOWNIBBLE_MASK = 0x0000000f;
- private static final int HINIBBLE_MASK = 0x000000f0;
- private static final int HINIBBLE_SHIFT = 4;
- private static final byte hexDigits[] = {
- (byte)'0', (byte)'1', (byte)'2', (byte)'3',
- (byte)'4', (byte)'5', (byte)'6', (byte)'7',
- (byte)'8', (byte)'9', (byte)'A', (byte)'B',
- (byte)'C', (byte)'D', (byte)'E', (byte)'F'
- };
- private static final int PS_XRES = 300;
- private static final int PS_YRES = 300;
- private static final String ADOBE_PS_STR = "%!PS-Adobe-3.0";
- private static final String EOF_COMMENT = "%%EOF";
- private static final String PAGE_COMMENT = "%%Page: ";
- private static final String READIMAGEPROC = "/imStr 0 def /imageSrc " +
- "{currentfile /ASCII85Decode filter /RunLengthDecode filter " +
- " imStr readstring pop } def";
- private static final String COPIES = "/#copies exch def";
- private static final String PAGE_SAVE = "/pgSave save def";
- private static final String PAGE_RESTORE = "pgSave restore";
- private static final String SHOWPAGE = "showpage";
- private static final String IMAGE_SAVE = "/imSave save def";
- private static final String IMAGE_STR = " string /imStr exch def";
- private static final String IMAGE_RESTORE = "imSave restore";
- private static final String COORD_PREP = " 0 exch translate "
- + "1 -1 scale"
- + "[72 " + PS_XRES + " div "
- + "0 0 "
- + "72 " + PS_YRES + " div "
- + "0 0]concat";
- private static final String SetFontName = "F";
- private static final String DrawStringName = "S";
- /**
- * The PostScript invocation to fill a path using the
- * even-odd rule. (eofill)
- */
- private static final String EVEN_ODD_FILL_STR = "EF";
- /**
- * The PostScript invocation to fill a path using the
- * non-zero winding rule. (fill)
- */
- private static final String WINDING_FILL_STR = "WF";
- /**
- * The PostScript to set the clip to be the current path
- * using the even odd rule. (eoclip)
- */
- private static final String EVEN_ODD_CLIP_STR = "EC";
- /**
- * The PostScript to set the clip to be the current path
- * using the non-zero winding rule. (clip)
- */
- private static final String WINDING_CLIP_STR = "WC";
- /**
- * Expecting two numbers on the PostScript stack, this
- * invocation moves the current pen position. (moveto)
- */
- private static final String MOVETO_STR = " M";
- /**
- * Expecting two numbers on the PostScript stack, this
- * invocation draws a PS line from the current pen
- * position to the point on the stack. (lineto)
- */
- private static final String LINETO_STR = " L";
- /**
- * This PostScript operator takes two control points
- * and an ending point and using the current pen
- * position as a starting point adds a bezier
- * curve to the current path. (curveto)
- */
- private static final String CURVETO_STR = " C";
- /**
- * The PostScript to pop a state off of the printer's
- * gstate stack. (grestore)
- */
- private static final String GRESTORE_STR = "R";
- /**
- * The PostScript to push a state on to the printer's
- * gstate stack. (gsave)
- */
- private static final String GSAVE_STR = "G";
- /**
- * Make the current PostScript path an empty path. (newpath)
- */
- private static final String NEWPATH_STR = "N";
- /**
- * Close the current subpath by generating a line segment
- * from the current position to the start of the subpath. (closepath)
- */
- private static final String CLOSEPATH_STR = "P";
- /**
- * Use the three numbers on top of the PS operator
- * stack to set the rgb color. (setrgbcolor)
- */
- private static final String SETRGBCOLOR_STR = " SC";
- /**
- * Use the top number on the stack to set the printer's
- * current gray value. (setgray)
- */
- private static final String SETGRAY_STR = " SG";
- /* Instance Variables */
- private int mDestType;
- private String mDestination = "lp";
- private boolean mNoJobSheet = false;
- private String mOptions;
- private Font mLastFont;
- private Color mLastColor;
- private Shape mLastClip;
- private AffineTransform mLastTransform;
- /* non-null if printing EPS for Java Plugin */
- private EPSPrinter epsPrinter = null;
- /**
- * The metrics for the font currently set.
- */
- FontMetrics mCurMetrics;
- /**
- * The output stream to which the generated PostScript
- * is written.
- */
- PrintStream mPSStream;
- /* The temporary file to which we spool before sending to the printer */
- File spoolFile;
- /**
- * This string holds the PostScript operator to
- * be used to fill a path. It can be changed
- * by the <code>setFillMode</code> method.
- */
- private String mFillOpStr = WINDING_FILL_STR;
- /**
- * This string holds the PostScript operator to
- * be used to clip to a path. It can be changed
- * by the <code>setFillMode</code> method.
- */
- private String mClipOpStr = WINDING_CLIP_STR;
- /**
- * A stack that represents the PostScript gstate stack.
- */
- ArrayList mGStateStack = new ArrayList();
- /**
- * The x coordinate of the current pen position.
- */
- private float mPenX;
- /**
- * The y coordinate of the current pen position.
- */
- private float mPenY;
- /**
- * The x coordinate of the starting point of
- * the current subpath.
- */
- private float mStartPathX;
- /**
- * The y coordinate of the starting point of
- * the current subpath.
- */
- private float mStartPathY;
- /**
- * An optional mapping of fonts to PostScript names.
- */
- private static Properties mFontProps = null;
- /* Class static initialiser block */
- static {
- //enable priviledges so initProps can access system properties,
- // open the property file, etc.
- java.security.AccessController.doPrivileged(
- new java.security.PrivilegedAction() {
- public Object run() {
- mFontProps = initProps();
- return null;
- }
- });
- }
- /*
- * Initialize PostScript font properties.
- * Copied from PSPrintStream
- */
- private static Properties initProps() {
- // search psfont.properties for fonts
- // and create and initialize fontProps if it exist.
- String jhome = System.getProperty("java.home");
- if (jhome != null){
- String ulocale = SunToolkit.getStartupLocale().getLanguage();
- try {
- File f = new File(jhome + File.separator +
- "lib" + File.separator +
- "psfontj2d.properties." + ulocale);
- if (!f.canRead()){
- f = new File(jhome + File.separator +
- "lib" + File.separator +
- "psfont.properties." + ulocale);
- if (!f.canRead()){
- f = new File(jhome + File.separator + "lib" +
- File.separator + "psfontj2d.properties");
- if (!f.canRead()){
- f = new File(jhome + File.separator + "lib" +
- File.separator + "psfont.properties");
- if (!f.canRead()){
- return (Properties)null;
- }
- }
- }
- }
- // Load property file
- InputStream in =
- new BufferedInputStream(new FileInputStream(f.getPath()));
- Properties props = new Properties();
- props.load(in);
- in.close();
- return props;
- } catch (Exception e){
- return (Properties)null;
- }
- }
- return (Properties)null;
- }
- /* Constructors */
- public PSPrinterJob()
- {
- }
- /* Instance Methods */
- /**
- * Presents the user a dialog for changing properties of the
- * print job interactively.
- * @returns false if the user cancels the dialog and
- * true otherwise.
- * @exception HeadlessException if GraphicsEnvironment.isHeadless()
- * returns true.
- * @see java.awt.GraphicsEnvironment#isHeadless
- */
- public boolean printDialog() throws HeadlessException {
- if (GraphicsEnvironment.isHeadless()) {
- throw new HeadlessException();
- }
- if (attributes == null) {
- attributes = new HashPrintRequestAttributeSet();
- }
- attributes.add(new Copies(getCopies()));
- attributes.add(new JobName(getJobName(), null));
- boolean doPrint = false;
- DialogTypeSelection dts =
- (DialogTypeSelection)attributes.get(DialogTypeSelection.class);
- if (dts == DialogTypeSelection.NATIVE) {
- // Remove DialogTypeSelection.NATIVE to prevent infinite loop in
- // RasterPrinterJob.
- attributes.remove(DialogTypeSelection.class);
- doPrint = printDialog(attributes);
- // restore attribute
- attributes.add(DialogTypeSelection.NATIVE);
- } else {
- doPrint = printDialog(attributes);
- }
- if (doPrint) {
- JobName jobName = (JobName)attributes.get(JobName.class);
- if (jobName != null) {
- setJobName(jobName.getValue());
- }
- Copies copies = (Copies)attributes.get(Copies.class);
- if (copies != null) {
- setCopies(copies.getValue());
- }
- Destination dest = (Destination)attributes.get(Destination.class);
- if (dest != null) {
- try {
- mDestType = RasterPrinterJob.FILE;
- mDestination = (new File(dest.getURI())).getPath();
- } catch (Exception e) {
- mDestination = "out.ps";
- }
- } else {
- mDestType = RasterPrinterJob.PRINTER;
- PrintService pServ = getPrintService();
- if (pServ != null) {
- mDestination = pServ.getName();
- }
- }
- }
- return doPrint;
- }
- /**
- * Invoked by the RasterPrinterJob super class
- * this method is called to mark the start of a
- * document.
- */
- protected void startDoc() throws PrinterException {
- // A security check has been performed in the
- // java.awt.print.printerJob.getPrinterJob method.
- // We use an inner class to execute the privilged open operations.
- // Note that we only open a file if it has been nominated by
- // the end-user in a dialog that we ouselves put up.
- OutputStream output;
- if (epsPrinter == null) {
- if (getPrintService() instanceof PSStreamPrintService) {
- StreamPrintService sps = (StreamPrintService)getPrintService();
- mDestType = RasterPrinterJob.STREAM;
- if (sps.isDisposed()) {
- throw new PrinterException("service is disposed");
- }
- output = sps.getOutputStream();
- if (output == null) {
- throw new PrinterException("Null output stream");
- }
- } else {
- /* REMIND: This needs to be more maintainable */
- mNoJobSheet = super.noJobSheet;
- if (super.destinationAttr != null) {
- mDestType = RasterPrinterJob.FILE;
- mDestination = super.destinationAttr;
- }
- if (mDestType == RasterPrinterJob.FILE) {
- try {
- spoolFile = new File(mDestination);
- output = new FileOutputStream(spoolFile);
- } catch (IOException ex) {
- throw new PrinterIOException(ex);
- }
- } else {
- PrinterOpener po = new PrinterOpener();
- java.security.AccessController.doPrivileged(po);
- if (po.pex != null) {
- throw po.pex;
- }
- output = po.result;
- }
- }
- mPSStream = new PrintStream(new BufferedOutputStream(output));
- mPSStream.println(ADOBE_PS_STR);
- }
- mPSStream.println("%%BeginProlog");
- mPSStream.println(READIMAGEPROC);
- mPSStream.println("/BD {bind def} bind def");
- mPSStream.println("/D {def} BD");
- mPSStream.println("/C {curveto} BD");
- mPSStream.println("/L {lineto} BD");
- mPSStream.println("/M {moveto} BD");
- mPSStream.println("/R {grestore} BD");
- mPSStream.println("/G {gsave} BD");
- mPSStream.println("/N {newpath} BD");
- mPSStream.println("/P {closepath} BD");
- mPSStream.println("/EC {eoclip} BD");
- mPSStream.println("/WC {clip} BD");
- mPSStream.println("/EF {eofill} BD");
- mPSStream.println("/WF {fill} BD");
- mPSStream.println("/SG {setgray} BD");
- mPSStream.println("/SC {setrgbcolor} BD");
- mPSStream.println("/ISOF {");
- mPSStream.println(" dup findfont dup length 1 add dict begin {");
- mPSStream.println(" 1 index /FID eq {pop pop} {D} ifelse");
- mPSStream.println(" } forall /Encoding ISOLatin1Encoding D");
- mPSStream.println(" currentdict end definefont");
- mPSStream.println("} BD");
- mPSStream.println("/NZ {dup 1 lt {pop 1} if} BD");
- /* The following procedure takes args: string, x, y, desiredWidth.
- * It calculates using stringwidth the width of the string in the
- * current font and subtracts it from the desiredWidth and divides
- * this by stringLen-1. This gives us a per-glyph adjustment in
- * the spacing needed (either +ve or -ve) to make the string
- * print at the desiredWidth. The ashow procedure call takes this
- * per-glyph adjustment as an argument. This is necessary for WYSIWYG
- */
- mPSStream.println("/"+DrawStringName +" {");
- mPSStream.println(" moveto 1 index stringwidth pop NZ sub");
- mPSStream.println(" 1 index length 1 sub NZ div 0");
- mPSStream.println(" 3 2 roll ashow newpath} BD");
- mPSStream.println("/FL [");
- if (mFontProps == null){
- mPSStream.println(" /Helvetica ISOF");
- mPSStream.println(" /Helvetica-Bold ISOF");
- mPSStream.println(" /Helvetica-Oblique ISOF");
- mPSStream.println(" /Helvetica-BoldOblique ISOF");
- mPSStream.println(" /Times-Roman ISOF");
- mPSStream.println(" /Times-Bold ISOF");
- mPSStream.println(" /Times-Italic ISOF");
- mPSStream.println(" /Times-BoldItalic ISOF");
- mPSStream.println(" /Courier ISOF");
- mPSStream.println(" /Courier-Bold ISOF");
- mPSStream.println(" /Courier-Oblique ISOF");
- mPSStream.println(" /Courier-BoldOblique ISOF");
- } else {
- int cnt = Integer.parseInt(mFontProps.getProperty("font.num", "9"));
- for (int i = 0; i < cnt; i++){
- mPSStream.println(" /" + mFontProps.getProperty
- ("font." + String.valueOf(i), "Courier ISOF"));
- }
- }
- mPSStream.println("] D");
- mPSStream.println("/"+SetFontName +" {");
- mPSStream.println(" FL exch get exch scalefont");
- mPSStream.println(" [1 0 0 -1 0 0] makefont setfont} BD");
- mPSStream.println("%%EndProlog");
- mPSStream.println("%%BeginSetup");
- if (epsPrinter == null) {
- // Set Page Size using first page's format.
- PageFormat pageFormat = getPageable().getPageFormat(0);
- double paperHeight = pageFormat.getPaper().getHeight();
- double paperWidth = pageFormat.getPaper().getWidth();
- /* PostScript printers can always generate uncollated copies.
- */
- mPSStream.print("<< /PageSize [" +
- paperWidth + " "+ paperHeight+"]");
- final PrintService pservice = getPrintService();
- Boolean isPS = (Boolean)java.security.AccessController.doPrivileged(
- new java.security.PrivilegedAction() {
- public Object run() {
- try {
- Class psClass = Class.forName("sun.print.IPPPrintService");
- if (psClass.isInstance(pservice)) {
- Method isPSMethod = psClass.getMethod("isPostscript",
- (Class[])null);
- return (Boolean)isPSMethod.invoke(pservice, (Object[])null);
- }
- } catch (Throwable t) {
- }
- return Boolean.TRUE;
- }
- }
- );
- if (isPS) {
- mPSStream.print(" /DeferredMediaSelection true");
- }
- mPSStream.print(" /ImagingBBox null /ManualFeed false");
- mPSStream.print(isCollated() ? " /Collate true":"");
- mPSStream.print(" /NumCopies " +getCopiesInt());
- if (sidesAttr != Sides.ONE_SIDED) {
- if (sidesAttr == Sides.TWO_SIDED_LONG_EDGE) {
- mPSStream.print(" /Duplex true ");
- } else if (sidesAttr == Sides.TWO_SIDED_SHORT_EDGE) {
- mPSStream.print(" /Duplex true /Tumble true ");
- }
- }
- mPSStream.println(" >> setpagedevice ");
- }
- mPSStream.println("%%EndSetup");
- }
- // Inner class to run "privileged" to open the printer output stream.
- private class PrinterOpener implements java.security.PrivilegedAction {
- PrinterException pex;
- OutputStream result;
- public Object run() {
- try {
- /* Write to a temporary file which will be spooled to
- * the printer then deleted. In the case that the file
- * is not removed for some reason, request that it is
- * removed when the VM exits.
- */
- spoolFile = sun.misc.IOUtils.createTempFile("javaprint", ".ps", null);
- spoolFile.deleteOnExit();
- result = new FileOutputStream(spoolFile);
- return result;
- } catch (IOException ex) {
- // If there is an IOError we subvert it to a PrinterException.
- pex = new PrinterIOException(ex);
- }
- return null;
- }
- }
- // Inner class to run "privileged" to invoke the system print command
- private class PrinterSpooler implements java.security.PrivilegedAction {
- PrinterException pex;
- public Object run() {
- try {
- /**
- * Spool to the printer.
- */
- if (spoolFile == null || !spoolFile.exists()) {
- pex = new PrinterException("No spool file");
- return null;
- }
- String fileName = spoolFile.getAbsolutePath();
- String execCmd[] = printExecCmd(mDestination, mOptions,
- mNoJobSheet, getJobNameInt(),
- 1, fileName);
- Process process = Runtime.getRuntime().exec(execCmd);
- process.waitFor();
- spoolFile.delete();
- } catch (IOException ex) {
- pex = new PrinterIOException(ex);
- } catch (InterruptedException ie) {
- pex = new PrinterException(ie.toString());
- }
- return null;
- }
- }
- /**
- * Invoked if the application cancelled the printjob.
- */
- protected void abortDoc() {
- if (mPSStream != null && mDestType != RasterPrinterJob.STREAM) {
- mPSStream.close();
- }
- java.security.AccessController.doPrivileged(
- new java.security.PrivilegedAction() {
- public Object run() {
- if (spoolFile != null && spoolFile.exists()) {
- spoolFile.delete();
- }
- return null;
- }
- });
- }
- /**
- * Invoked by the RasterPrintJob super class
- * this method is called after that last page
- * has been imaged.
- */
- protected void endDoc() throws PrinterException {
- if (mPSStream != null) {
- mPSStream.println(EOF_COMMENT);
- mPSStream.flush();
- if (mDestType != RasterPrinterJob.STREAM) {
- mPSStream.close();
- }
- }
- if (mDestType == RasterPrinterJob.PRINTER) {
- if (getPrintService() != null) {
- mDestination = getPrintService().getName();
- }
- PrinterSpooler spooler = new PrinterSpooler();
- java.security.AccessController.doPrivileged(spooler);
- if (spooler.pex != null) {
- throw spooler.pex;
- }
- }
- }
- /**
- * The RasterPrintJob super class calls this method
- * at the start of each page.
- */
- protected void startPage(PageFormat pageFormat, Printable painter,
- int index, boolean paperChanged)
- throws PrinterException
- {
- double paperHeight = pageFormat.getPaper().getHeight();
- double paperWidth = pageFormat.getPaper().getWidth();
- int pageNumber = index + 1;
- /* Place an initial gstate on to our gstate stack.
- * It will have the default PostScript gstate
- * attributes.
- */
- mGStateStack = new ArrayList();
- mGStateStack.add(new GState());
- mPSStream.println(PAGE_COMMENT + pageNumber + " " + pageNumber);
- /* Check current page's pageFormat against the previous pageFormat,
- */
- if (index > 0 && paperChanged) {
- mPSStream.print("<< /PageSize [" +
- paperWidth + " " + paperHeight + "]");
- final PrintService pservice = getPrintService();
- Boolean isPS =
- (Boolean)java.security.AccessController.doPrivileged(
- new java.security.PrivilegedAction() {
- public Object run() {
- try {
- Class psClass =
- Class.forName("sun.print.IPPPrintService");
- if (psClass.isInstance(pservice)) {
- Method isPSMethod =
- psClass.getMethod("isPostscript",
- (Class[])null);
- return (Boolean)
- isPSMethod.invoke(pservice,
- (Object[])null);
- }
- } catch (Throwable t) {
- }
- return Boolean.TRUE;
- }
- }
- );
- if (isPS) {
- mPSStream.print(" /DeferredMediaSelection true");
- }
- mPSStream.println(" >> setpagedevice");
- }
- mPSStream.println(PAGE_SAVE);
- mPSStream.println(paperHeight + COORD_PREP);
- }
- /**
- * The RastePrintJob super class calls this method
- * at the end of each page.
- */
- protected void endPage(PageFormat format, Printable painter,
- int index)
- throws PrinterException
- {
- mPSStream.println(PAGE_RESTORE);
- mPSStream.println(SHOWPAGE);
- }
- /**
- * Convert the 24 bit BGR image buffer represented by
- * <code>image</code> to PostScript. The image is drawn at
- * <code>(destX, destY)</code> in device coordinates.
- * The image is scaled into a square of size
- * specified by <code>destWidth</code> and
- * <code>destHeight</code>. The portion of the
- * source image copied into that square is specified
- * by <code>srcX</code>, <code>srcY</code>,
- * <code>srcWidth</code>, and srcHeight.
- */
- protected void drawImageBGR(byte[] bgrData,
- float destX, float destY,
- float destWidth, float destHeight,
- float srcX, float srcY,
- float srcWidth, float srcHeight,
- int srcBitMapWidth, int srcBitMapHeight) {
- /* We draw images at device resolution so we probably need
- * to change the current PostScript transform.
- */
- setTransform(new AffineTransform());
- prepDrawing();
- int intSrcWidth = (int) srcWidth;
- int intSrcHeight = (int) srcHeight;
- mPSStream.println(IMAGE_SAVE);
- /* Create a PS string big enough to hold a row of pixels.
- */
- int psBytesPerRow = 3 * (int) intSrcWidth;
- while (psBytesPerRow > MAX_PSSTR) {
- psBytesPerRow /= 2;
- }
- mPSStream.println(psBytesPerRow + IMAGE_STR);
- /* Scale and translate the unit image.
- */
- mPSStream.println("[" + destWidth + " 0 "
- + "0 " + destHeight
- + " " + destX + " " + destY
- +"]concat");
- /* Color Image invocation.
- */
- mPSStream.println(intSrcWidth + " " + intSrcHeight + " " + 8 + "["
- + intSrcWidth + " 0 "
- + "0 " + intSrcHeight
- + " 0 " + 0 + "]"
- + "/imageSrc load false 3 colorimage");
- /* Image data.
- */
- int index = 0;
- byte[] rgbData = new byte[intSrcWidth * 3];
- try {
- /* Skip the parts of the image that are not part
- * of the source rectangle.
- */
- index = (int) srcY * srcBitMapWidth;
- for(int i = 0; i < intSrcHeight; i++) {
- /* Skip the left part of the image that is not
- * part of the source rectangle.
- */
- index += (int) srcX;
- index = swapBGRtoRGB(bgrData, index, rgbData);
- byte[] encodedData = rlEncode(rgbData);
- byte[] asciiData = ascii85Encode(encodedData);
- mPSStream.write(asciiData);
- mPSStream.println("");
- }
- /*
- * If there is an IOError we subvert it to a PrinterException.
- * Fix: There has got to be a better way, maybe define
- * a PrinterIOException and then throw that?
- */
- } catch (IOException e) {
- //throw new PrinterException(e.toString());
- }
- mPSStream.println(IMAGE_RESTORE);
- }
- /**
- * Prints the contents of the array of ints, 'data'
- * to the current page. The band is placed at the
- * location (x, y) in device coordinates on the
- * page. The width and height of the band is
- * specified by the caller. Currently the data
- * is 24 bits per pixel in BGR format.
- */
- protected void printBand(byte[] bgrData, int x, int y,
- int width, int height)
- throws PrinterException
- {
- mPSStream.println(IMAGE_SAVE);
- /* Create a PS string big enough to hold a row of pixels.
- */
- int psBytesPerRow = 3 * width;
- while (psBytesPerRow > MAX_PSSTR) {
- psBytesPerRow /= 2;
- }
- mPSStream.println(psBytesPerRow + IMAGE_STR);
- /* Scale and translate the unit image.
- */
- mPSStream.println("[" + width + " 0 "
- + "0 " + height
- + " " + x + " " + y
- +"]concat");
- /* Color Image invocation.
- */
- mPSStream.println(width + " " + height + " " + 8 + "["
- + width + " 0 "
- + "0 " + -height
- + " 0 " + height + "]"
- + "/imageSrc load false 3 colorimage");
- /* Image data.
- */
- int index = 0;
- byte[] rgbData = new byte[width*3];
- try {
- for(int i = 0; i < height; i++) {
- index = swapBGRtoRGB(bgrData, index, rgbData);
- byte[] encodedData = rlEncode(rgbData);
- byte[] asciiData = ascii85Encode(encodedData);
- mPSStream.write(asciiData);
- mPSStream.println("");
- }
- } catch (IOException e) {
- throw new PrinterIOException(e);
- }
- mPSStream.println(IMAGE_RESTORE);
- }
- /**
- * Examine the metrics captured by the
- * <code>PeekGraphics</code> instance and
- * if capable of directly converting this
- * print job to the printer's control language
- * or the native OS's graphics primitives, then
- * return a <code>PSPathGraphics</code> to perform
- * that conversion. If there is not an object
- * capable of the conversion then return
- * <code>null</code>. Returning <code>null</code>
- * causes the print job to be rasterized.
- */
- protected Graphics2D createPathGraphics(PeekGraphics peekGraphics,
- PrinterJob printerJob,
- Printable painter,
- PageFormat pageFormat,
- int pageIndex) {
- PSPathGraphics pathGraphics;
- PeekMetrics metrics = peekGraphics.getMetrics();
- /* If the application has drawn anything that
- * out PathGraphics class can not handle then
- * return a null PathGraphics.
- */
- if (forcePDL == false && (forceRaster == true
- || metrics.hasNonSolidColors()
- || metrics.hasCompositing())) {
- pathGraphics = null;
- } else {
- BufferedImage bufferedImage = new BufferedImage(8, 8,
- BufferedImage.TYPE_INT_RGB);
- Graphics2D bufferedGraphics = bufferedImage.createGraphics();
- boolean canRedraw = peekGraphics.getAWTDrawingOnly() == false;
- pathGraphics = new PSPathGraphics(bufferedGraphics, printerJob,
- painter, pageFormat, pageIndex,
- canRedraw);
- }
- return pathGraphics;
- }
- /**
- * Intersect the gstate's current path with the
- * current clip and make the result the new clip.
- */
- protected void selectClipPath() {
- mPSStream.println(mClipOpStr);
- }
- protected void setClip(Shape clip) {
- mLastClip = clip;
- }
- protected void setTransform(AffineTransform transform) {
- mLastTransform = transform;
- }
- /**
- * Set the current PostScript font.
- * Taken from outFont in PSPrintStream.
- */
- protected boolean setFont(Font font) {
- mLastFont = font;
- return true;
- }
- /**
- * Given an array of CharsetStrings that make up a run
- * of text, this routine converts each CharsetString to
- * an index into our PostScript font list. If one or more
- * CharsetStrings can not be represented by a PostScript
- * font, then this routine will return a null array.
- */
- private int[] getPSFontIndexArray(Font font, CharsetString[] charSet) {
- int[] psFont = null;
- if (mFontProps != null) {
- psFont = new int[charSet.length];
- }
- for (int i = 0; i < charSet.length && psFont != null; i++){
- /* Get the encoding of the run of text.
- */
- CharsetString cs = charSet[i];
- CharsetEncoder fontCS = cs.fontDescriptor.encoder;
- String charsetName = cs.fontDescriptor.getFontCharsetName();
- /*
- * sun.awt.Symbol perhaps should return "symbol" for encoding.
- * Similarly X11Dingbats should return "dingbats"
- * Forced to check for win32 & x/unix names for these converters.
- */
- if ("Symbol".equals(charsetName)) {
- charsetName = "symbol";
- } else if ("WingDings".equals(charsetName) ||
- "X11Dingbats".equals(charsetName)) {
- charsetName = "dingbats";
- } else {
- charsetName = makeCharsetName(charsetName, cs.charsetChars);
- }
- int styleMask = font.getStyle() |
- sun.font.FontManager.getFont2D(font).getStyle();
- String style = FontConfiguration.getStyleString(styleMask);
- /* First we map the font name through the properties file.
- * This mapping provides alias names for fonts, for example,
- * "timesroman" is mapped to "serif".
- */
- String fontName = font.getFamily().toLowerCase(Locale.ENGLISH);
- fontName = fontName.replace(' ', '_');
- String name = mFontProps.getProperty(fontName, "");
- /* Now map the alias name, character set name, and style
- * to a PostScript name.
- */
- String psName =
- mFontProps.getProperty(name + "." + charsetName + "." + style,
- null);
- if (psName != null) {
- /* Get the PostScript font index for the PostScript font.
- */
- try {
- psFont[i] =
- Integer.parseInt(mFontProps.getProperty(psName));
- /* If there is no PostScript font for this font name,
- * then we want to termintate the loop and the method
- * indicating our failure. Setting the array to null
- * is used to indicate these failures.
- */
- } catch(NumberFormatException e){
- psFont = null;
- }
- /* There was no PostScript name for the font, character set,
- * and style so give up.
- */
- } else {
- psFont = null;
- }
- }
- return psFont;
- }
- private static String escapeParens(String str) {
- if (str.indexOf('(') == -1 && str.indexOf(')') == -1 ) {
- return str;
- } else {
- int count = 0;
- int pos = 0;
- while ((pos = str.indexOf('(', pos)) != -1) {
- count++;
- pos++;
- }
- pos = 0;
- while ((pos = str.indexOf(')', pos)) != -1) {
- count++;
- pos++;
- }
- char []inArr = str.toCharArray();
- char []outArr = new char[inArr.length+count];
- pos = 0;
- for (int i=0;i<inArr.length;i++) {
- if (inArr[i] == '(' || inArr[i] == ')') {
- outArr[pos++] = '\\';
- }
- outArr[pos++] = inArr[i];
- }
- return new String(outArr);
- }
- }
- /* return of 0 means unsupported. Other return indicates the number
- * of distinct PS fonts needed to draw this text. This saves us
- * doing this processing one extra time.
- */
- protected int platformFontCount(Font font, String str) {
- if (mFontProps == null) {
- return 0;
- }
- CharsetString[] acs =
- ((PlatformFont)(font.getPeer())).makeMultiCharsetString(str,false);
- if (acs == null) {
- /* AWT can't convert all chars so use 2D path */
- return 0;
- }
- int[] psFonts = getPSFontIndexArray(font, acs);
- return (psFonts == null) ? 0 : psFonts.length;
- }
- protected boolean textOut(Graphics g, String str, float x, float y,
- Font mLastFont, FontRenderContext frc,
- float width) {
- boolean didText = true;
- if (mFontProps == null) {
- return false;
- } else {
- prepDrawing();
- /* On-screen drawString renders most control chars as the missing
- * glyph and have the non-zero advance of that glyph.
- * Exceptions are \t, \n and \r which are considered zero-width.
- * Postscript handles control chars mostly as a missing glyph.
- * But we use 'ashow' specifying a width for the string which
- * assumes zero-width for those three exceptions, and Postscript
- * tries to squeeze the extra char in, with the result that the
- * glyphs look compressed or even overlap.
- * So exclude those control chars from the string sent to PS.
- */
- str = removeControlChars(str);
- if (str.length() == 0) {
- return true;
- }
- CharsetString[] acs =
- ((PlatformFont)
- (mLastFont.getPeer())).makeMultiCharsetString(str, false);
- if (acs == null) {
- /* AWT can't convert all chars so use 2D path */
- return false;
- }
- /* Get an array of indices into our PostScript name
- * table. If all of the runs can not be converted
- * to PostScript fonts then null is returned and
- * we'll want to fall back to printing the text
- * as shapes.
- */
- int[] psFonts = getPSFontIndexArray(mLastFont, acs);
- if (psFonts != null) {
- for (int i = 0; i < acs.length; i++){
- CharsetString cs = acs[i];
- CharsetEncoder fontCS = cs.fontDescriptor.encoder;
- StringBuffer nativeStr = new StringBuffer();
- byte[] strSeg = new byte[cs.length * 2];
- int len = 0;
- try {
- ByteBuffer bb = ByteBuffer.wrap(strSeg);
- fontCS.encode(CharBuffer.wrap(cs.charsetChars,
- cs.offset,
- cs.length),
- bb, true);
- bb.flip();
- len = bb.limit();
- } catch(IllegalStateException xx){
- continue;
- } catch(CoderMalfunctionError xx){
- continue;
- }
- /* The width to fit to may either be specified,
- * or calculated. Specifying by the caller is only
- * valid if the text does not need to be decomposed
- * into multiple calls.
- */
- float desiredWidth;
- if (acs.length == 1 && width != 0f) {
- desiredWidth = width;
- } else {
- Rectangle2D r2d =
- mLastFont.getStringBounds(cs.charsetChars,
- cs.offset,
- cs.offset+cs.length,
- frc);
- desiredWidth = (float)r2d.getWidth();
- }
- /* unprintable chars had width of 0, causing a PS error
- */
- if (desiredWidth == 0) {
- return didText;
- }
- nativeStr.append('<');
- for (int j = 0; j < len; j++){
- byte b = strSeg[j];
- // to avoid encoding conversion with println()
- String hexS = Integer.toHexString(b);
- int length = hexS.length();
- if (length > 2) {
- hexS = hexS.substring(length - 2, length);
- } else if (length == 1) {
- hexS = "0" + hexS;
- } else if (length == 0) {
- hexS = "00";
- }
- nativeStr.append(hexS);
- }
- nativeStr.append('>');
- /* This comment costs too much in output file size */
- // mPSStream.println("% Font[" + mLastFont.getName() + ", " +
- // FontConfiguration.getStyleString(mLastFont.getStyle()) + ", "
- // + mLastFont.getSize2D() + "]");
- getGState().emitPSFont(psFonts[i], mLastFont.getSize2D());
- // out String
- mPSStream.println(nativeStr.toString() + " " +
- desiredWidth + " " + x + " " + y + " " +
- DrawStringName);
- x += desiredWidth;
- }
- } else {
- didText = false;
- }
- }
- return didText;
- }
- /**
- * Set the current path rule to be either
- * <code>FILL_EVEN_ODD</code> (using the
- * even-odd file rule) or <code>FILL_WINDING</code>
- * (using the non-zero winding rule.)
- */
- protected void setFillMode(int fillRule) {
- switch (fillRule) {
- case FILL_EVEN_ODD:
- mFillOpStr = EVEN_ODD_FILL_STR;
- mClipOpStr = EVEN_ODD_CLIP_STR;
- break;
- case FILL_WINDING:
- mFillOpStr = WINDING_FILL_STR;
- mClipOpStr = WINDING_CLIP_STR;
- break;
- default:
- throw new IllegalArgumentException();
- }
- }
- /**
- * Set the printer's current color to be that
- * defined by <code>color</code>
- */
- protected void setColor(Color color) {
- mLastColor = color;
- }
- /**
- * Fill the current path using the current fill mode
- * and color.
- */
- protected void fillPath() {
- mPSStream.println(mFillOpStr);
- }
- /**
- * Called to mark the start of a new path.
- */
- protected void beginPath() {
- prepDrawing();
- mPSStream.println(NEWPATH_STR);
- mPenX = 0;
- mPenY = 0;
- }
- /**
- * Close the current subpath by appending a straight
- * line from the current point to the subpath's
- * starting point.
- */
- protected void closeSubpath() {
- mPSStream.println(CLOSEPATH_STR);
- mPenX = mStartPathX;
- mPenY = mStartPathY;
- }
- /**
- * Generate PostScript to move the current pen
- * position to <code>(x, y)</code>.
- */
- protected void moveTo(float x, float y) {
- mPSStream.println(trunc(x) + " " + trunc(y) + MOVETO_STR);
- /* moveto marks the start of a new subpath
- * and we need to remember that starting
- * position so that we know where the
- * pen returns to with a close path.
- */
- mStartPathX = x;
- mStartPathY = y;
- mPenX = x;
- mPenY = y;
- }
- /**
- * Generate PostScript to draw a line from the
- * current pen position to <code>(x, y)</code>.
- */
- protected void lineTo(float x, float y) {
- mPSStream.println(trunc(x) + " " + trunc(y) + LINETO_STR);
- mPenX = x;
- mPenY = y;
- }
- /**
- * Add to the current path a bezier curve formed
- * by the current pen position and the method parameters
- * which are two control points and an ending
- * point.
- */
- protected void bezierTo(float control1x, float control1y,
- float control2x, float control2y,
- float endX, float endY) {
- // mPSStream.println(control1x + " " + control1y
- // + " " + control2x + " " + control2y
- // + " " + endX + " " + endY
- // + CURVETO_STR);
- mPSStream.println(trunc(control1x) + " " + trunc(control1y)
- + " " + trunc(control2x) + " " + trunc(control2y)
- + " " + trunc(endX) + " " + trunc(endY)
- + CURVETO_STR);
- mPenX = endX;
- mPenY = endY;
- }
- String trunc(float f) {
- float af = Math.abs(f);
- if (af >= 1f && af <=1000f) {
- f = Math.round(f*1000)/1000f;
- }
- return Float.toString(f);
- }
- /**
- * Return the x coordinate of the pen in the
- * current path.
- */
- protected float getPenX() {
- return mPenX;
- }
- /**
- * Return the y coordinate of the pen in the
- * current path.
- */
- protected f…
Large files files are truncated, but you can click here to view the full file