// write EOD marker. outArr[olen++]='~'; outArr[olen++]='>'; /* 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. */ byte[] retArr = new byte[olen]; System.arraycopy(outArr, 0, retArr, 0, olen); return retArr; } /** * 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 * same. */ public static class PluginPrinter implements Printable { private EPSPrinter epsPrinter; private Component applet; private PrintStream stream; private String epsTitle; private int bx, by, bw, bh; private int width, height; /** * 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 */ public PluginPrinter(Component applet, PrintStream stream, int x, int y, int w, int h) { this.applet = applet; this.epsTitle = "Java Plugin Applet"; this.stream = stream; bx = x; by = y; bw = w; bh = h; width = applet.size().width; height = applet.size().height; epsPrinter = new EPSPrinter(this, epsTitle, stream, 0, 0, width, height); } public void printPluginPSHeader() { stream.println("%%BeginDocument: JavaPluginApplet"); } public void printPluginApplet() { try { epsPrinter.print(); } catch (PrinterException e) { } } public void printPluginPSTrailer() { stream.println("%%EndDocument: JavaPluginApplet"); stream.flush(); } public void printAll() { printPluginPSHeader(); printPluginApplet(); printPluginPSTrailer(); } public int print(Graphics g, PageFormat pf, int pgIndex) { if (pgIndex > 0) { return Printable.NO_SUCH_PAGE; } else { // "aware" client code can detect that its been passed a // PrinterGraphics and could theoretically print // differently. I think this is more likely useful than // a problem. applet.printAll(g); return Printable.PAGE_EXISTS; } } } /* * 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. */ public static class EPSPrinter implements Pageable { private PageFormat pf; private PSPrinterJob job; private int llx, lly, urx, ury; private Printable printable; private PrintStream stream; private String epsTitle; public EPSPrinter(Printable printable, String title, PrintStream stream, int x, int y, int wid, int hgt) { this.printable = printable; this.epsTitle = title; this.stream = stream; llx = x; lly = y; urx = llx+wid; ury = lly+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. Paper p = new Paper(); p.setSize((double)wid, (double)hgt); p.setImageableArea(0.0,0.0, (double)wid, (double)hgt); pf = new PageFormat(); pf.setPaper(p); } public void print() throws PrinterException { stream.println("%!PS-Adobe-3.0 EPSF-3.0"); stream.println("%%BoundingBox: " + llx + " " + lly + " " + urx + " " + ury); stream.println("%%Title: " + epsTitle); stream.println("%%Creator: Java Printing"); stream.println("%%CreationDate: " + new java.util.Date()); stream.println("%%EndComments"); stream.println("/pluginSave save def"); stream.println("mark"); // for restoring stack state on return job = new PSPrinterJob(); job.epsPrinter = this; // modifies the behaviour of PSPrinterJob job.mPSStream = stream; job.mDestType = RasterPrinterJob.STREAM; // prevents closure job.startDoc(); try { job.printPage(this, 0); } catch (Throwable t) { if (t instanceof PrinterException) { throw (PrinterException)t; } else { throw new PrinterException(t.toString()); } } finally { stream.println("cleartomark"); // restore stack state stream.println("pluginSave restore"); job.endDoc(); } stream.flush(); } public int getNumberOfPages() { return 1; } public PageFormat getPageFormat(int pgIndex) { if (pgIndex > 0) { throw new IndexOutOfBoundsException("pgIndex"); } else { return pf; } } public Printable getPrintable(int pgIndex) { if (pgIndex > 0) { throw new IndexOutOfBoundsException("pgIndex"); } else { return printable; } } }}Lines 2001–2213 of 2213. Previous lines
// write EOD marker. outArr[olen++]='~'; outArr[olen++]='>'; /* 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. */ byte[] retArr = new byte[olen]; System.arraycopy(outArr, 0, retArr, 0, olen); return retArr; } /** * 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 * same. */ public static class PluginPrinter implements Printable { private EPSPrinter epsPrinter; private Component applet; private PrintStream stream; private String epsTitle; private int bx, by, bw, bh; private int width, height; /** * 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 */ public PluginPrinter(Component applet, PrintStream stream, int x, int y, int w, int h) { this.applet = applet; this.epsTitle = "Java Plugin Applet"; this.stream = stream; bx = x; by = y; bw = w; bh = h; width = applet.size().width; height = applet.size().height; epsPrinter = new EPSPrinter(this, epsTitle, stream, 0, 0, width, height); } public void printPluginPSHeader() { stream.println("%%BeginDocument: JavaPluginApplet"); } public void printPluginApplet() { try { epsPrinter.print(); } catch (PrinterException e) { } } public void printPluginPSTrailer() { stream.println("%%EndDocument: JavaPluginApplet"); stream.flush(); } public void printAll() { printPluginPSHeader(); printPluginApplet(); printPluginPSTrailer(); } public int print(Graphics g, PageFormat pf, int pgIndex) { if (pgIndex > 0) { return Printable.NO_SUCH_PAGE; } else { // "aware" client code can detect that its been passed a // PrinterGraphics and could theoretically print // differently. I think this is more likely useful than // a problem. applet.printAll(g); return Printable.PAGE_EXISTS; } } } /* * 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. */ public static class EPSPrinter implements Pageable { private PageFormat pf; private PSPrinterJob job; private int llx, lly, urx, ury; private Printable printable; private PrintStream stream; private String epsTitle; public EPSPrinter(Printable printable, String title, PrintStream stream, int x, int y, int wid, int hgt) { this.printable = printable; this.epsTitle = title; this.stream = stream; llx = x; lly = y; urx = llx+wid; ury = lly+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. Paper p = new Paper(); p.setSize((double)wid, (double)hgt); p.setImageableArea(0.0,0.0, (double)wid, (double)hgt); pf = new PageFormat(); pf.setPaper(p); } public void print() throws PrinterException { stream.println("%!PS-Adobe-3.0 EPSF-3.0"); stream.println("%%BoundingBox: " + llx + " " + lly + " " + urx + " " + ury); stream.println("%%Title: " + epsTitle); stream.println("%%Creator: Java Printing"); stream.println("%%CreationDate: " + new java.util.Date()); stream.println("%%EndComments"); stream.println("/pluginSave save def"); stream.println("mark"); // for restoring stack state on return job = new PSPrinterJob(); job.epsPrinter = this; // modifies the behaviour of PSPrinterJob job.mPSStream = stream; job.mDestType = RasterPrinterJob.STREAM; // prevents closure job.startDoc(); try { job.printPage(this, 0); } catch (Throwable t) { if (t instanceof PrinterException) { throw (PrinterException)t; } else { throw new PrinterException(t.toString()); } } finally { stream.println("cleartomark"); // restore stack state stream.println("pluginSave restore"); job.endDoc(); } stream.flush(); } public int getNumberOfPages() { return 1; } public PageFormat getPageFormat(int pgIndex) { if (pgIndex > 0) { throw new IndexOutOfBoundsException("pgIndex"); } else { return pf; } } public Printable getPrintable(int pgIndex) { if (pgIndex > 0) { throw new IndexOutOfBoundsException("pgIndex"); } else { return printable; } } } }