293
294 File spoolFile;
295
296 /**
297 * This string holds the PostScript operator to
298 * be used to fill a path. It can be changed
299 * by the <code>setFillMode</code> method.
300 */
301 private String mFillOpStr = WINDING_FILL_STR;
302
303 /**
304 * This string holds the PostScript operator to
305 * be used to clip to a path. It can be changed
306 * by the <code>setFillMode</code> method.
307 */
308 private String mClipOpStr = WINDING_CLIP_STR;
309
310 /**
311 * A stack that represents the PostScript gstate stack.
312 */
313 ArrayList mGStateStack = new ArrayList();
314
315 /**
316 * The x coordinate of the current pen position.
317 */
318 private float mPenX;
319
320 /**
321 * The y coordinate of the current pen position.
322 */
323 private float mPenY;
324
325 /**
326 * The x coordinate of the starting point of
327 * the current subpath.
328 */
329 private float mStartPathX;
330
331 /**
332 * The y coordinate of the starting point of
333 * the current subpath.
334 */
335 private float mStartPathY;
336
337 /**
338 * An optional mapping of fonts to PostScript names.
339 */
340 private static Properties mFontProps = null;
341
342 private static boolean isMac;
343
344 /* Class static initialiser block */
345 static {
346 //enable priviledges so initProps can access system properties,
347 // open the property file, etc.
348 java.security.AccessController.doPrivileged(
349 new java.security.PrivilegedAction() {
350 public Object run() {
351 mFontProps = initProps();
352 String osName = System.getProperty("os.name");
353 isMac = osName.startsWith("Mac");
354 return null;
355 }
356 });
357 }
358
359 /*
360 * Initialize PostScript font properties.
361 * Copied from PSPrintStream
362 */
363 private static Properties initProps() {
364 // search psfont.properties for fonts
365 // and create and initialize fontProps if it exist.
366
367 String jhome = System.getProperty("java.home");
368
369 if (jhome != null){
605
606 mPSStream.println("/"+SetFontName +" {");
607 mPSStream.println(" FL exch get exch scalefont");
608 mPSStream.println(" [1 0 0 -1 0 0] makefont setfont} BD");
609
610 mPSStream.println("%%EndProlog");
611
612 mPSStream.println("%%BeginSetup");
613 if (epsPrinter == null) {
614 // Set Page Size using first page's format.
615 PageFormat pageFormat = getPageable().getPageFormat(0);
616 double paperHeight = pageFormat.getPaper().getHeight();
617 double paperWidth = pageFormat.getPaper().getWidth();
618
619 /* PostScript printers can always generate uncollated copies.
620 */
621 mPSStream.print("<< /PageSize [" +
622 paperWidth + " "+ paperHeight+"]");
623
624 final PrintService pservice = getPrintService();
625 Boolean isPS = (Boolean)java.security.AccessController.doPrivileged(
626 new java.security.PrivilegedAction() {
627 public Object run() {
628 try {
629 Class psClass = Class.forName("sun.print.IPPPrintService");
630 if (psClass.isInstance(pservice)) {
631 Method isPSMethod = psClass.getMethod("isPostscript",
632 (Class[])null);
633 return (Boolean)isPSMethod.invoke(pservice, (Object[])null);
634 }
635 } catch (Throwable t) {
636 }
637 return Boolean.TRUE;
638 }
639 }
640 );
641 if (isPS) {
642 mPSStream.print(" /DeferredMediaSelection true");
643 }
644
645 mPSStream.print(" /ImagingBBox null /ManualFeed false");
646 mPSStream.print(isCollated() ? " /Collate true":"");
647 mPSStream.print(" /NumCopies " +getCopiesInt());
648
649 if (sidesAttr != Sides.ONE_SIDED) {
650 if (sidesAttr == Sides.TWO_SIDED_LONG_EDGE) {
651 mPSStream.print(" /Duplex true ");
652 } else if (sidesAttr == Sides.TWO_SIDED_SHORT_EDGE) {
653 mPSStream.print(" /Duplex true /Tumble true ");
654 }
655 }
656 mPSStream.println(" >> setpagedevice ");
657 }
658 mPSStream.println("%%EndSetup");
659 }
660
661 // Inner class to run "privileged" to open the printer output stream.
662
663 private class PrinterOpener implements java.security.PrivilegedAction {
664 PrinterException pex;
665 OutputStream result;
666
667 public Object run() {
668 try {
669
670 /* Write to a temporary file which will be spooled to
671 * the printer then deleted. In the case that the file
672 * is not removed for some reason, request that it is
673 * removed when the VM exits.
674 */
675 spoolFile = Files.createTempFile("javaprint", ".ps").toFile();
676 spoolFile.deleteOnExit();
677
678 result = new FileOutputStream(spoolFile);
679 return result;
680 } catch (IOException ex) {
681 // If there is an IOError we subvert it to a PrinterException.
682 pex = new PrinterIOException(ex);
683 }
684 return null;
685 }
686 }
687
688 // Inner class to run "privileged" to invoke the system print command
689
690 private class PrinterSpooler implements java.security.PrivilegedAction {
691 PrinterException pex;
692
693 private void handleProcessFailure(final Process failedProcess,
694 final String[] execCmd, final int result) throws IOException {
695 try (StringWriter sw = new StringWriter();
696 PrintWriter pw = new PrintWriter(sw)) {
697 pw.append("error=").append(Integer.toString(result));
698 pw.append(" running:");
699 for (String arg: execCmd) {
700 pw.append(" '").append(arg).append("'");
701 }
702 try (InputStream is = failedProcess.getErrorStream();
703 InputStreamReader isr = new InputStreamReader(is);
704 BufferedReader br = new BufferedReader(isr)) {
705 while (br.ready()) {
706 pw.println();
707 pw.append("\t\t").append(br.readLine());
708 }
709 } finally {
710 pw.flush();
736 } catch (IOException ex) {
737 pex = new PrinterIOException(ex);
738 } catch (InterruptedException ie) {
739 pex = new PrinterException(ie.toString());
740 } finally {
741 spoolFile.delete();
742 }
743 return null;
744 }
745 }
746
747
748 /**
749 * Invoked if the application cancelled the printjob.
750 */
751 protected void abortDoc() {
752 if (mPSStream != null && mDestType != RasterPrinterJob.STREAM) {
753 mPSStream.close();
754 }
755 java.security.AccessController.doPrivileged(
756 new java.security.PrivilegedAction() {
757
758 public Object run() {
759 if (spoolFile != null && spoolFile.exists()) {
760 spoolFile.delete();
761 }
762 return null;
763 }
764 });
765 }
766
767 /**
768 * Invoked by the RasterPrintJob super class
769 * this method is called after that last page
770 * has been imaged.
771 */
772 protected void endDoc() throws PrinterException {
773 if (mPSStream != null) {
774 mPSStream.println(EOF_COMMENT);
775 mPSStream.flush();
776 if (mDestType != RasterPrinterJob.STREAM) {
795 }
796 }
797 }
798
799 /**
800 * The RasterPrintJob super class calls this method
801 * at the start of each page.
802 */
803 protected void startPage(PageFormat pageFormat, Printable painter,
804 int index, boolean paperChanged)
805 throws PrinterException
806 {
807 double paperHeight = pageFormat.getPaper().getHeight();
808 double paperWidth = pageFormat.getPaper().getWidth();
809 int pageNumber = index + 1;
810
811 /* Place an initial gstate on to our gstate stack.
812 * It will have the default PostScript gstate
813 * attributes.
814 */
815 mGStateStack = new ArrayList();
816 mGStateStack.add(new GState());
817
818 mPSStream.println(PAGE_COMMENT + pageNumber + " " + pageNumber);
819
820 /* Check current page's pageFormat against the previous pageFormat,
821 */
822 if (index > 0 && paperChanged) {
823
824 mPSStream.print("<< /PageSize [" +
825 paperWidth + " " + paperHeight + "]");
826
827 final PrintService pservice = getPrintService();
828 Boolean isPS =
829 (Boolean)java.security.AccessController.doPrivileged(
830
831 new java.security.PrivilegedAction() {
832 public Object run() {
833 try {
834 Class psClass =
835 Class.forName("sun.print.IPPPrintService");
836 if (psClass.isInstance(pservice)) {
837 Method isPSMethod =
838 psClass.getMethod("isPostscript",
839 (Class[])null);
840 return (Boolean)
841 isPSMethod.invoke(pservice,
842 (Object[])null);
843 }
844 } catch (Throwable t) {
845 }
846 return Boolean.TRUE;
847 }
848 }
849 );
850
851 if (isPS) {
852 mPSStream.print(" /DeferredMediaSelection true");
853 }
854 mPSStream.println(" >> setpagedevice");
1703 /* Set the font if we have been asked to. It is
1704 * important that the font is set after the
1705 * transform in order to get the font size
1706 * correct.
1707 */
1708 // if (g != null) {
1709 // getGState().emitPSFont(g, mLastFont);
1710 // }
1711
1712 }
1713
1714 /**
1715 * Return the GState that is currently on top
1716 * of the GState stack. There should always be
1717 * a GState on top of the stack. If there isn't
1718 * then this method will throw an IndexOutOfBounds
1719 * exception.
1720 */
1721 private GState getGState() {
1722 int count = mGStateStack.size();
1723 return (GState) mGStateStack.get(count - 1);
1724 }
1725
1726 /**
1727 * Emit a PostScript gsave command and add a
1728 * new GState on to our stack which represents
1729 * the printer's gstate stack.
1730 */
1731 private void gsave() {
1732 GState oldGState = getGState();
1733 mGStateStack.add(new GState(oldGState));
1734 mPSStream.println(GSAVE_STR);
1735 }
1736
1737 /**
1738 * Emit a PostScript grestore command and remove
1739 * a GState from our stack which represents the
1740 * printer's gstate stack.
1741 */
1742 private void grestore() {
1743 int count = mGStateStack.size();
|
293
294 File spoolFile;
295
296 /**
297 * This string holds the PostScript operator to
298 * be used to fill a path. It can be changed
299 * by the <code>setFillMode</code> method.
300 */
301 private String mFillOpStr = WINDING_FILL_STR;
302
303 /**
304 * This string holds the PostScript operator to
305 * be used to clip to a path. It can be changed
306 * by the <code>setFillMode</code> method.
307 */
308 private String mClipOpStr = WINDING_CLIP_STR;
309
310 /**
311 * A stack that represents the PostScript gstate stack.
312 */
313 ArrayList<GState> mGStateStack = new ArrayList<>();
314
315 /**
316 * The x coordinate of the current pen position.
317 */
318 private float mPenX;
319
320 /**
321 * The y coordinate of the current pen position.
322 */
323 private float mPenY;
324
325 /**
326 * The x coordinate of the starting point of
327 * the current subpath.
328 */
329 private float mStartPathX;
330
331 /**
332 * The y coordinate of the starting point of
333 * the current subpath.
334 */
335 private float mStartPathY;
336
337 /**
338 * An optional mapping of fonts to PostScript names.
339 */
340 private static Properties mFontProps = null;
341
342 private static boolean isMac;
343
344 /* Class static initialiser block */
345 static {
346 //enable priviledges so initProps can access system properties,
347 // open the property file, etc.
348 java.security.AccessController.doPrivileged(
349 new java.security.PrivilegedAction<Object>() {
350 public Object run() {
351 mFontProps = initProps();
352 String osName = System.getProperty("os.name");
353 isMac = osName.startsWith("Mac");
354 return null;
355 }
356 });
357 }
358
359 /*
360 * Initialize PostScript font properties.
361 * Copied from PSPrintStream
362 */
363 private static Properties initProps() {
364 // search psfont.properties for fonts
365 // and create and initialize fontProps if it exist.
366
367 String jhome = System.getProperty("java.home");
368
369 if (jhome != null){
605
606 mPSStream.println("/"+SetFontName +" {");
607 mPSStream.println(" FL exch get exch scalefont");
608 mPSStream.println(" [1 0 0 -1 0 0] makefont setfont} BD");
609
610 mPSStream.println("%%EndProlog");
611
612 mPSStream.println("%%BeginSetup");
613 if (epsPrinter == null) {
614 // Set Page Size using first page's format.
615 PageFormat pageFormat = getPageable().getPageFormat(0);
616 double paperHeight = pageFormat.getPaper().getHeight();
617 double paperWidth = pageFormat.getPaper().getWidth();
618
619 /* PostScript printers can always generate uncollated copies.
620 */
621 mPSStream.print("<< /PageSize [" +
622 paperWidth + " "+ paperHeight+"]");
623
624 final PrintService pservice = getPrintService();
625 Boolean isPS = java.security.AccessController.doPrivileged(
626 new java.security.PrivilegedAction<Boolean>() {
627 public Boolean run() {
628 try {
629 Class<?> psClass = Class.forName("sun.print.IPPPrintService");
630 if (psClass.isInstance(pservice)) {
631 Method isPSMethod = psClass.getMethod("isPostscript",
632 (Class[])null);
633 return (Boolean)isPSMethod.invoke(pservice, (Object[])null);
634 }
635 } catch (Throwable t) {
636 }
637 return Boolean.TRUE;
638 }
639 }
640 );
641 if (isPS) {
642 mPSStream.print(" /DeferredMediaSelection true");
643 }
644
645 mPSStream.print(" /ImagingBBox null /ManualFeed false");
646 mPSStream.print(isCollated() ? " /Collate true":"");
647 mPSStream.print(" /NumCopies " +getCopiesInt());
648
649 if (sidesAttr != Sides.ONE_SIDED) {
650 if (sidesAttr == Sides.TWO_SIDED_LONG_EDGE) {
651 mPSStream.print(" /Duplex true ");
652 } else if (sidesAttr == Sides.TWO_SIDED_SHORT_EDGE) {
653 mPSStream.print(" /Duplex true /Tumble true ");
654 }
655 }
656 mPSStream.println(" >> setpagedevice ");
657 }
658 mPSStream.println("%%EndSetup");
659 }
660
661 // Inner class to run "privileged" to open the printer output stream.
662
663 private class PrinterOpener implements java.security.PrivilegedAction<OutputStream> {
664 PrinterException pex;
665 OutputStream result;
666
667 public OutputStream run() {
668 try {
669
670 /* Write to a temporary file which will be spooled to
671 * the printer then deleted. In the case that the file
672 * is not removed for some reason, request that it is
673 * removed when the VM exits.
674 */
675 spoolFile = Files.createTempFile("javaprint", ".ps").toFile();
676 spoolFile.deleteOnExit();
677
678 result = new FileOutputStream(spoolFile);
679 return result;
680 } catch (IOException ex) {
681 // If there is an IOError we subvert it to a PrinterException.
682 pex = new PrinterIOException(ex);
683 }
684 return null;
685 }
686 }
687
688 // Inner class to run "privileged" to invoke the system print command
689
690 private class PrinterSpooler implements java.security.PrivilegedAction<Object> {
691 PrinterException pex;
692
693 private void handleProcessFailure(final Process failedProcess,
694 final String[] execCmd, final int result) throws IOException {
695 try (StringWriter sw = new StringWriter();
696 PrintWriter pw = new PrintWriter(sw)) {
697 pw.append("error=").append(Integer.toString(result));
698 pw.append(" running:");
699 for (String arg: execCmd) {
700 pw.append(" '").append(arg).append("'");
701 }
702 try (InputStream is = failedProcess.getErrorStream();
703 InputStreamReader isr = new InputStreamReader(is);
704 BufferedReader br = new BufferedReader(isr)) {
705 while (br.ready()) {
706 pw.println();
707 pw.append("\t\t").append(br.readLine());
708 }
709 } finally {
710 pw.flush();
736 } catch (IOException ex) {
737 pex = new PrinterIOException(ex);
738 } catch (InterruptedException ie) {
739 pex = new PrinterException(ie.toString());
740 } finally {
741 spoolFile.delete();
742 }
743 return null;
744 }
745 }
746
747
748 /**
749 * Invoked if the application cancelled the printjob.
750 */
751 protected void abortDoc() {
752 if (mPSStream != null && mDestType != RasterPrinterJob.STREAM) {
753 mPSStream.close();
754 }
755 java.security.AccessController.doPrivileged(
756 new java.security.PrivilegedAction<Object>() {
757
758 public Object run() {
759 if (spoolFile != null && spoolFile.exists()) {
760 spoolFile.delete();
761 }
762 return null;
763 }
764 });
765 }
766
767 /**
768 * Invoked by the RasterPrintJob super class
769 * this method is called after that last page
770 * has been imaged.
771 */
772 protected void endDoc() throws PrinterException {
773 if (mPSStream != null) {
774 mPSStream.println(EOF_COMMENT);
775 mPSStream.flush();
776 if (mDestType != RasterPrinterJob.STREAM) {
795 }
796 }
797 }
798
799 /**
800 * The RasterPrintJob super class calls this method
801 * at the start of each page.
802 */
803 protected void startPage(PageFormat pageFormat, Printable painter,
804 int index, boolean paperChanged)
805 throws PrinterException
806 {
807 double paperHeight = pageFormat.getPaper().getHeight();
808 double paperWidth = pageFormat.getPaper().getWidth();
809 int pageNumber = index + 1;
810
811 /* Place an initial gstate on to our gstate stack.
812 * It will have the default PostScript gstate
813 * attributes.
814 */
815 mGStateStack = new ArrayList<>();
816 mGStateStack.add(new GState());
817
818 mPSStream.println(PAGE_COMMENT + pageNumber + " " + pageNumber);
819
820 /* Check current page's pageFormat against the previous pageFormat,
821 */
822 if (index > 0 && paperChanged) {
823
824 mPSStream.print("<< /PageSize [" +
825 paperWidth + " " + paperHeight + "]");
826
827 final PrintService pservice = getPrintService();
828 Boolean isPS = java.security.AccessController.doPrivileged(
829 new java.security.PrivilegedAction<Boolean>() {
830 public Boolean run() {
831 try {
832 Class<?> psClass =
833 Class.forName("sun.print.IPPPrintService");
834 if (psClass.isInstance(pservice)) {
835 Method isPSMethod =
836 psClass.getMethod("isPostscript",
837 (Class[])null);
838 return (Boolean)
839 isPSMethod.invoke(pservice,
840 (Object[])null);
841 }
842 } catch (Throwable t) {
843 }
844 return Boolean.TRUE;
845 }
846 }
847 );
848
849 if (isPS) {
850 mPSStream.print(" /DeferredMediaSelection true");
851 }
852 mPSStream.println(" >> setpagedevice");
1701 /* Set the font if we have been asked to. It is
1702 * important that the font is set after the
1703 * transform in order to get the font size
1704 * correct.
1705 */
1706 // if (g != null) {
1707 // getGState().emitPSFont(g, mLastFont);
1708 // }
1709
1710 }
1711
1712 /**
1713 * Return the GState that is currently on top
1714 * of the GState stack. There should always be
1715 * a GState on top of the stack. If there isn't
1716 * then this method will throw an IndexOutOfBounds
1717 * exception.
1718 */
1719 private GState getGState() {
1720 int count = mGStateStack.size();
1721 return mGStateStack.get(count - 1);
1722 }
1723
1724 /**
1725 * Emit a PostScript gsave command and add a
1726 * new GState on to our stack which represents
1727 * the printer's gstate stack.
1728 */
1729 private void gsave() {
1730 GState oldGState = getGState();
1731 mGStateStack.add(new GState(oldGState));
1732 mPSStream.println(GSAVE_STR);
1733 }
1734
1735 /**
1736 * Emit a PostScript grestore command and remove
1737 * a GState from our stack which represents the
1738 * printer's gstate stack.
1739 */
1740 private void grestore() {
1741 int count = mGStateStack.size();
|