PSPrinterJob.java revision 4944
481N/A * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved. 481N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 481N/A * This code is free software; you can redistribute it and/or modify it 481N/A * under the terms of the GNU General Public License version 2 only, as 481N/A * published by the Free Software Foundation. Oracle designates this 481N/A * particular file as subject to the "Classpath" exception as provided 481N/A * by Oracle in the LICENSE file that accompanied this code. 481N/A * This code is distributed in the hope that it will be useful, but WITHOUT 481N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 481N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 481N/A * version 2 for more details (a copy is included in the LICENSE file that 481N/A * accompanied this code). 481N/A * You should have received a copy of the GNU General Public License version 481N/A * 2 along with this work; if not, write to the Free Software Foundation, 481N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 481N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 481N/A * or visit www.oracle.com if you need additional information or have any //REMIND: Remove use of this class when IPPPrintService is moved to share directory. * A class which initiates and executes a PostScript printer job. * @author Richard Blanchard * Passed to the <code>setFillMode</code> * method this value forces fills to be * done using the even-odd fill rule. * Passed to the <code>setFillMode</code> * method this value forces fills to be * done using the non-zero winding rule. /* 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 BLUE_MASK =
0x000000ff;
(
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;
"{currentfile /ASCII85Decode filter /RunLengthDecode filter " +
" imStr readstring pop } def";
* The PostScript invocation to fill a path using the * even-odd rule. (eofill) * The PostScript invocation to fill a path using the * non-zero winding rule. (fill) * The PostScript to set the clip to be the current path * using the even odd rule. (eoclip) * The PostScript to set the clip to be the current path * using the non-zero winding rule. (clip) * Expecting two numbers on the PostScript stack, this * invocation moves the current pen position. (moveto) * 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) * 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) * The PostScript to pop a state off of the printer's * gstate stack. (grestore) * The PostScript to push a state on to the printer's * Make the current PostScript path an empty path. (newpath) * Close the current subpath by generating a line segment * from the current position to the start of the subpath. (closepath) * Use the three numbers on top of the PS operator * stack to set the rgb color. (setrgbcolor) * Use the top number on the stack to set the printer's * current gray value. (setgray) /* non-null if printing EPS for Java Plugin */ * The metrics for the font currently set. * The output stream to which the generated PostScript /* The temporary file to which we spool before sending to the printer */ * This string holds the PostScript operator to * be used to fill a path. It can be changed * by the <code>setFillMode</code> method. * This string holds the PostScript operator to * be used to clip to a path. It can be changed * by the <code>setFillMode</code> method. * A stack that represents the PostScript gstate stack. * The x coordinate of the current pen position. * The y coordinate of the current pen position. * The x coordinate of the starting point of * The y coordinate of the starting point of * An optional mapping of fonts to PostScript names. /* Class static initialiser block */ //enable priviledges so initProps can access system properties, // open the property file, etc. * Initialize PostScript font properties. * Copied from PSPrintStream // and create and initialize fontProps if it exist. * Presents the user a dialog for changing properties of the * print job interactively. * @returns false if the user cancels the dialog and * @exception HeadlessException if GraphicsEnvironment.isHeadless() * @see java.awt.GraphicsEnvironment#isHeadless // Remove DialogTypeSelection.NATIVE to prevent infinite loop in * Invoked by the RasterPrinterJob super class * this method is called to mark the start of a // 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. /* REMIND: This needs to be more maintainable */ /* 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 for (
int i =
0; i <
cnt; i++){
// Set Page Size using first page's format. /* PostScript printers can always generate uncollated copies. // Inner class to run "privileged" to open the printer output stream. /* 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. // If there is an IOError we subvert it to a PrinterException. // Inner class to run "privileged" to invoke the system print command * Invoked if the application cancelled the printjob. * Invoked by the RasterPrintJob super class * this method is called after that last page * The RasterPrintJob super class calls this method * at the start of each page. /* Place an initial gstate on to our gstate stack. * It will have the default PostScript gstate /* Check current page's pageFormat against the previous pageFormat, * The RastePrintJob super class calls this method * at the end of each page. * 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. /* We draw images at device resolution so we probably need * to change the current PostScript transform. /* Create a PS string big enough to hold a row of pixels. /* Scale and translate the unit image. /* Color Image invocation. +
"/imageSrc load false 3 colorimage");
/* Skip the parts of the image that are not part * of the source rectangle. /* Skip the left part of the image that is not * part of the source rectangle. * 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? //throw new PrinterException(e.toString()); * 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. /* Create a PS string big enough to hold a row of pixels. /* Scale and translate the unit image. /* Color Image invocation. +
"/imageSrc load false 3 colorimage");
for(
int i =
0; i <
height; i++) {
* 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. /* If the application has drawn anything that * out PathGraphics class can not handle then * return a null PathGraphics. * Intersect the gstate's current path with the * current clip and make the result the new clip. * Set the current PostScript font. * Taken from outFont in PSPrintStream. * 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. /* Get the encoding of the run of text. * 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. /* First we map the font name through the properties file. * This mapping provides alias names for fonts, for example, * "timesroman" is mapped to "serif". /* Now map the alias name, character set name, and style /* Get the PostScript font index for the PostScript font. /* 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. /* There was no PostScript name for the font, character set, /* 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. /* AWT can't convert all chars so use 2D path */ /* 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. /* AWT can't convert all chars so use 2D path */ /* 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 /* 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 /* unprintable chars had width of 0, causing a PS error for (
int j =
0; j <
len; j++){
// to avoid encoding conversion with println() /* This comment costs too much in output file size */ // mPSStream.println("% Font[" + mLastFont.getName() + ", " + // FontConfiguration.getStyleString(mLastFont.getStyle()) + ", " // + mLastFont.getSize2D() + "]"); * 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.) * Set the printer's current color to be that * defined by <code>color</code> * Fill the current path using the current fill mode * Called to mark the start of a new path. * Close the current subpath by appending a straight * line from the current point to the subpath's * Generate PostScript to move the current pen * position to <code>(x, y)</code>. protected void moveTo(
float x,
float y) {
/* 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. * Generate PostScript to draw a line from the * current pen position to <code>(x, y)</code>. protected void lineTo(
float x,
float 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 // mPSStream.println(control1x + " " + control1y // + " " + control2x + " " + control2y // + " " + endX + " " + endY if (
af >=
1f &&
af <=
1000f) {
* Return the x coordinate of the pen in the * Return the y coordinate of the pen in the * Return the x resolution of the coordinates * Return the y resolution of the coordinates * For PostScript the origin is in the upper-left of the * paper not at the imageable area corner. * For PostScript the origin is in the upper-left of the * paper not at the imageable area corner. * Returns how many times each page in the book * should be consecutively printed by PrintJob. * If the printer makes copies itself then this * method should return 1. int ncomps =
2;
// minimum number of print args execCmd[n++] =
"-c";
// make a copy of the spool file * Currently CharToByteConverter.getCharacterEncoding() return values are * not fixed yet. These are used as the part of the key of * psfont.propeties. When those name are fixed this routine can // same as latin 1 if all chars < 256 // same as latin 1 if all chars < 128 /* Pop gstates until we can set the needed clip * and transform or until we are at the outer most /* Set the color. This can push the color to the * outer most gsave which is often a good thing. /* We do not want to change the outermost * transform or clip so if we are at the * outer clip the generate a gsave. /* Set the font if we have been asked to. It is * important that the font is set after the * transform in order to get the font size // getGState().emitPSFont(g, mLastFont); * Return the GState that is currently on top * of the GState stack. There should always be * a GState on top of the stack. If there isn't * then this method will throw an IndexOutOfBounds * Emit a PostScript gsave command and add a * new GState on to our stack which represents * the printer's gstate stack. * Emit a PostScript grestore command and remove * a GState from our stack which represents the * printer's gstate stack. * Return true if the current GState is the * outermost GState and therefore should not * A stack of GStates is maintained to model the printer's * gstate stack. Each GState holds information about * the current graphics attributes. /* The clip is a shape and has reset the winding rule state */ double[]
matrix =
new double[
6];
/* If the color is a gray value then use /* It's not gray so use setrgbcolor. * Given a Java2D <code>PathIterator</code> instance, * this method translates that into a PostScript path.. /* Map the PathIterator's fill rule into the PostScript /* Convert the quad path to a bezier. * Fill the path defined by <code>pathIter</code> * with the specified color. * The path is provided in current user space. /* Specify the path to fill as the clip, this ensures that only * pixels which are inside the path will be filled, which is * what the Java 2D APIs specify * Run length encode byte array in a form suitable for decoding * by the PS Level 2 filter RunLengthDecode. * Array data to encode is inArr. Encoded data is written to outArr * outArr must be long enough to hold the encoded data but this * can't be known ahead of time. * A safe assumption is to use double the length of the input array. * This is then copied into a new array of the correct length which * Encoding is a lead byte followed by data bytes. * Lead byte of 0->127 indicates leadByte + 1 distinct bytes follow * Lead byte of 129->255 indicates 257 - leadByte is the number of times * the following byte is repeated in the source. * 128 is a special lead byte indicating end of data (EOD) and is * written as the final byte of the returned encoded data. runLen++;
// count run of same value continue;
// back to top of while loop. // if reach here have a run of different values, or at the end. runLen++;
// count run of different values /* written acc. to Adobe Spec. "Filtered Files: ASCIIEncode Filter", * "PS Language Reference Manual, 2nd edition: Section 3.13" ((
long)((
inArr[i++]&
0xff))<<
16) +
((
long)((
inArr[i++]&
0xff))<<
8) +
((
long)(
inArr[i++]&
0xff));
// input not a multiple of 4 bytes, write partial output. int n =
inArr.
length - i;
// n bytes remain to be written for (
int b =
0; b < n+
1 ; b++) {
/* The original intention was to insert a newline after every 78 bytes. * This was mainly intended for legibility but I decided against this * partially because of the (small) amount of extra space, and * partially because for line breaks either would have to hardwire * ascii 10 (newline) or calculate space in bytes to allocate for * the platform's newline byte sequence. Also need to be careful * about where its inserted: * Ascii 85 decoder ignores white space except for one special case: * you must ensure you do not split the EOD marker across lines. * PluginPrinter generates EPSF wrapped with a header and trailer * comment. This conforms to the new requirements of Mozilla 1.7 * and FireFox 1.5 and later. Earlier versions of these browsers * did not support plugin printing in the general sense (not just Java). * A notable limitation of these browsers is that they handle plugins * which would span page boundaries by scaling plugin content to fit on a * single page. This means white space is left at the bottom of the * previous page and its impossible to print these cases as they appear on * the web page. This is contrast to how the same browsers behave on * Windows where it renders as on-screen. * Cases where the content fits on a single page do work fine, and they * are the majority of cases. * The scaling that the browser specifies to make the plugin content fit * when it is larger than a single page can hold is non-uniform. It * scales the axis in which the content is too large just enough to * ensure it fits. For content which is extremely long this could lead * to noticeable distortion. However that is probably rare enough that * its not worth compensating for that here, but we can revisit that if * needed, and compensate by making the scale for the other axis the * This is called from the Java Plug-in to print an Applet's * contents as EPS to a postscript stream provided by the browser. * @param applet the applet component to print. * @param stream the print stream provided by the plug-in * @param x the x location of the applet panel in the browser window * @param y the y location of the applet panel in the browser window * @param w the width of the applet panel in the browser window * @param h the width of the applet panel in the browser window int x,
int y,
int w,
int h) {
// "aware" client code can detect that its been passed a // PrinterGraphics and could theoretically print // differently. I think this is more likely useful than * This class can take an application-client supplied printable object * and send the result to a stream. * The application does not need to send any postscript to this stream * unless it needs to specify a translation etc. * It assumes that its importing application obeys all the conventions * for importation of EPS. See Appendix H - Encapsulated Postscript File * Format - of the Adobe Postscript Language Reference Manual, 2nd edition. * This class could be used as the basis for exposing the ability to * generate EPSF from 2D graphics as a StreamPrintService. * In that case a MediaPrintableArea attribute could be used to * communicate the bounding box. int x,
int y,
int wid,
int hgt) {
// construct a PageFormat with zero margins representing the // exact bounds of the applet. ie construct a theoretical // paper which happens to exactly match applet panel size.