|
Java example source code file (PSPrinterJob.java)
The PSPrinterJob.java Java example source code
/*
* Copyright (c) 1998, 2013, 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.PrintServiceAttributeSet;
import javax.print.attribute.standard.PrinterName;
import javax.print.attribute.standard.Chromaticity;
import javax.print.attribute.standard.Copies;
import javax.print.attribute.standard.Destination;
import javax.print.attribute.standard.DialogTypeSelection;
import javax.print.attribute.standard.JobName;
import javax.print.attribute.standard.Sides;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.CharConversionException;
import java.io.File;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.IOException;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.io.StringWriter;
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 sun.font.FontManagerFactory;
import sun.font.FontUtilities;
import java.nio.charset.*;
import java.nio.CharBuffer;
import java.nio.ByteBuffer;
import java.nio.file.Files;
//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
* 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
* 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 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 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;
private static boolean isMac;
/* 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();
String osName = System.getProperty("os.name");
isMac = osName.startsWith("Mac");
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();
if (isMac) {
PrintServiceAttributeSet psaSet = pServ.getAttributes() ;
if (psaSet != null) {
mDestination = psaSet.get(PrinterName.class).toString();
}
}
}
}
}
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 = Files.createTempFile("javaprint", ".ps").toFile();
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;
private void handleProcessFailure(final Process failedProcess,
final String[] execCmd, final int result) throws IOException {
try (StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw)) {
pw.append("error=").append(Integer.toString(result));
pw.append(" running:");
for (String arg: execCmd) {
pw.append(" '").append(arg).append("'");
}
try (InputStream is = failedProcess.getErrorStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr)) {
while (br.ready()) {
pw.println();
pw.append("\t\t").append(br.readLine());
}
} finally {
pw.flush();
throw new IOException(sw.toString());
}
}
}
public Object run() {
if (spoolFile == null || !spoolFile.exists()) {
pex = new PrinterException("No spool file");
return null;
}
try {
/**
* Spool to the printer.
*/
String fileName = spoolFile.getAbsolutePath();
String execCmd[] = printExecCmd(mDestination, mOptions,
mNoJobSheet, getJobNameInt(),
1, fileName);
Process process = Runtime.getRuntime().exec(execCmd);
process.waitFor();
final int result = process.exitValue();
if (0 != result) {
handleProcessFailure(process, execCmd, result);
}
} catch (IOException ex) {
pex = new PrinterIOException(ex);
} catch (InterruptedException ie) {
pex = new PrinterException(ie.toString());
} finally {
spoolFile.delete();
}
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) {
PrintService pServ = getPrintService();
if (pServ != null) {
mDestination = pServ.getName();
if (isMac) {
PrintServiceAttributeSet psaSet = pServ.getAttributes();
if (psaSet != null) {
mDestination = psaSet.get(PrinterName.class).toString() ;
}
}
}
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 to PostScript. The image is drawn at
* <code>(destX, destY) in device coordinates.
* The image is scaled into a square of size
* specified by <code>destWidth and
* <code>destHeight. The portion of the
* source image copied into that square is specified
* by <code>srcX,
Other Java examples (source code examples)Here is a short list of links related to this Java PSPrinterJob.java source code file: |
| ... this post is sponsored by my books ... | |
#1 New Release! |
FP Best Seller |
Copyright 1998-2024 Alvin Alexander, alvinalexander.com
All Rights Reserved.
A percentage of advertising revenue from
pages under the /java/jwarehouse
URI on this website is
paid back to open source projects.