99 import sun.font.FontUtilities;
100
101 import java.nio.charset.*;
102 import java.nio.CharBuffer;
103 import java.nio.ByteBuffer;
104 import java.nio.file.Files;
105
106 //REMIND: Remove use of this class when IPPPrintService is moved to share directory.
107 import java.lang.reflect.Method;
108
109 /**
110 * A class which initiates and executes a PostScript printer job.
111 *
112 * @author Richard Blanchard
113 */
114 public class PSPrinterJob extends RasterPrinterJob {
115
116 /* Class Constants */
117
118 /**
119 * Passed to the <code>setFillMode</code>
120 * method this value forces fills to be
121 * done using the even-odd fill rule.
122 */
123 protected static final int FILL_EVEN_ODD = 1;
124
125 /**
126 * Passed to the <code>setFillMode</code>
127 * method this value forces fills to be
128 * done using the non-zero winding rule.
129 */
130 protected static final int FILL_WINDING = 2;
131
132 /* PostScript has a 64K maximum on its strings.
133 */
134 private static final int MAX_PSSTR = (1024 * 64 - 1);
135
136 private static final int RED_MASK = 0x00ff0000;
137 private static final int GREEN_MASK = 0x0000ff00;
138 private static final int BLUE_MASK = 0x000000ff;
139
140 private static final int RED_SHIFT = 16;
141 private static final int GREEN_SHIFT = 8;
142 private static final int BLUE_SHIFT = 0;
143
144 private static final int LOWNIBBLE_MASK = 0x0000000f;
145 private static final int HINIBBLE_MASK = 0x000000f0;
146 private static final int HINIBBLE_SHIFT = 4;
277 private EPSPrinter epsPrinter = null;
278
279 /**
280 * The metrics for the font currently set.
281 */
282 FontMetrics mCurMetrics;
283
284 /**
285 * The output stream to which the generated PostScript
286 * is written.
287 */
288 PrintStream mPSStream;
289
290 /* The temporary file to which we spool before sending to the printer */
291
292 File spoolFile;
293
294 /**
295 * This string holds the PostScript operator to
296 * be used to fill a path. It can be changed
297 * by the <code>setFillMode</code> method.
298 */
299 private String mFillOpStr = WINDING_FILL_STR;
300
301 /**
302 * This string holds the PostScript operator to
303 * be used to clip to a path. It can be changed
304 * by the <code>setFillMode</code> method.
305 */
306 private String mClipOpStr = WINDING_CLIP_STR;
307
308 /**
309 * A stack that represents the PostScript gstate stack.
310 */
311 ArrayList<GState> mGStateStack = new ArrayList<>();
312
313 /**
314 * The x coordinate of the current pen position.
315 */
316 private float mPenX;
317
318 /**
319 * The y coordinate of the current pen position.
320 */
321 private float mPenY;
322
323 /**
324 * The x coordinate of the starting point of
859 mPSStream.println(" >> setpagedevice");
860 }
861 mPSStream.println(PAGE_SAVE);
862 mPSStream.println(paperHeight + getCoordPrep());
863 }
864
865 /**
866 * The RastePrintJob super class calls this method
867 * at the end of each page.
868 */
869 protected void endPage(PageFormat format, Printable painter,
870 int index)
871 throws PrinterException
872 {
873 mPSStream.println(PAGE_RESTORE);
874 mPSStream.println(SHOWPAGE);
875 }
876
877 /**
878 * Convert the 24 bit BGR image buffer represented by
879 * <code>image</code> to PostScript. The image is drawn at
880 * <code>(destX, destY)</code> in device coordinates.
881 * The image is scaled into a square of size
882 * specified by <code>destWidth</code> and
883 * <code>destHeight</code>. The portion of the
884 * source image copied into that square is specified
885 * by <code>srcX</code>, <code>srcY</code>,
886 * <code>srcWidth</code>, and srcHeight.
887 */
888 protected void drawImageBGR(byte[] bgrData,
889 float destX, float destY,
890 float destWidth, float destHeight,
891 float srcX, float srcY,
892 float srcWidth, float srcHeight,
893 int srcBitMapWidth, int srcBitMapHeight) {
894
895 /* We draw images at device resolution so we probably need
896 * to change the current PostScript transform.
897 */
898 setTransform(new AffineTransform());
899 prepDrawing();
900
901 int intSrcWidth = (int) srcWidth;
902 int intSrcHeight = (int) srcHeight;
903
904 mPSStream.println(IMAGE_SAVE);
905
906 /* Create a PS string big enough to hold a row of pixels.
1009 byte[] rgbData = new byte[width*3];
1010
1011 try {
1012 for(int i = 0; i < height; i++) {
1013 index = swapBGRtoRGB(bgrData, index, rgbData);
1014 byte[] encodedData = rlEncode(rgbData);
1015 byte[] asciiData = ascii85Encode(encodedData);
1016 mPSStream.write(asciiData);
1017 mPSStream.println("");
1018 }
1019
1020 } catch (IOException e) {
1021 throw new PrinterIOException(e);
1022 }
1023
1024 mPSStream.println(IMAGE_RESTORE);
1025 }
1026
1027 /**
1028 * Examine the metrics captured by the
1029 * <code>PeekGraphics</code> instance and
1030 * if capable of directly converting this
1031 * print job to the printer's control language
1032 * or the native OS's graphics primitives, then
1033 * return a <code>PSPathGraphics</code> to perform
1034 * that conversion. If there is not an object
1035 * capable of the conversion then return
1036 * <code>null</code>. Returning <code>null</code>
1037 * causes the print job to be rasterized.
1038 */
1039
1040 protected Graphics2D createPathGraphics(PeekGraphics peekGraphics,
1041 PrinterJob printerJob,
1042 Printable painter,
1043 PageFormat pageFormat,
1044 int pageIndex) {
1045
1046 PSPathGraphics pathGraphics;
1047 PeekMetrics metrics = peekGraphics.getMetrics();
1048
1049 /* If the application has drawn anything that
1050 * out PathGraphics class can not handle then
1051 * return a null PathGraphics.
1052 */
1053 if (forcePDL == false && (forceRaster == true
1054 || metrics.hasNonSolidColors()
1055 || metrics.hasCompositing())) {
1056
1332 // mPSStream.println("% Font[" + mLastFont.getName() + ", " +
1333 // FontConfiguration.getStyleString(mLastFont.getStyle()) + ", "
1334 // + mLastFont.getSize2D() + "]");
1335 getGState().emitPSFont(psFonts[i], mLastFont.getSize2D());
1336
1337 // out String
1338 mPSStream.println(nativeStr.toString() + " " +
1339 desiredWidth + " " + x + " " + y + " " +
1340 DrawStringName);
1341 x += desiredWidth;
1342 }
1343 } else {
1344 didText = false;
1345 }
1346 }
1347
1348 return didText;
1349 }
1350 /**
1351 * Set the current path rule to be either
1352 * <code>FILL_EVEN_ODD</code> (using the
1353 * even-odd file rule) or <code>FILL_WINDING</code>
1354 * (using the non-zero winding rule.)
1355 */
1356 protected void setFillMode(int fillRule) {
1357
1358 switch (fillRule) {
1359
1360 case FILL_EVEN_ODD:
1361 mFillOpStr = EVEN_ODD_FILL_STR;
1362 mClipOpStr = EVEN_ODD_CLIP_STR;
1363 break;
1364
1365 case FILL_WINDING:
1366 mFillOpStr = WINDING_FILL_STR;
1367 mClipOpStr = WINDING_CLIP_STR;
1368 break;
1369
1370 default:
1371 throw new IllegalArgumentException();
1372 }
1373
1374 }
1375
1376 /**
1377 * Set the printer's current color to be that
1378 * defined by <code>color</code>
1379 */
1380 protected void setColor(Color color) {
1381 mLastColor = color;
1382 }
1383
1384 /**
1385 * Fill the current path using the current fill mode
1386 * and color.
1387 */
1388 protected void fillPath() {
1389
1390 mPSStream.println(mFillOpStr);
1391 }
1392
1393 /**
1394 * Called to mark the start of a new path.
1395 */
1396 protected void beginPath() {
1397
1398 prepDrawing();
1401 mPenX = 0;
1402 mPenY = 0;
1403 }
1404
1405 /**
1406 * Close the current subpath by appending a straight
1407 * line from the current point to the subpath's
1408 * starting point.
1409 */
1410 protected void closeSubpath() {
1411
1412 mPSStream.println(CLOSEPATH_STR);
1413
1414 mPenX = mStartPathX;
1415 mPenY = mStartPathY;
1416 }
1417
1418
1419 /**
1420 * Generate PostScript to move the current pen
1421 * position to <code>(x, y)</code>.
1422 */
1423 protected void moveTo(float x, float y) {
1424
1425 mPSStream.println(trunc(x) + " " + trunc(y) + MOVETO_STR);
1426
1427 /* moveto marks the start of a new subpath
1428 * and we need to remember that starting
1429 * position so that we know where the
1430 * pen returns to with a close path.
1431 */
1432 mStartPathX = x;
1433 mStartPathY = y;
1434
1435 mPenX = x;
1436 mPenY = y;
1437 }
1438 /**
1439 * Generate PostScript to draw a line from the
1440 * current pen position to <code>(x, y)</code>.
1441 */
1442 protected void lineTo(float x, float y) {
1443
1444 mPSStream.println(trunc(x) + " " + trunc(y) + LINETO_STR);
1445
1446 mPenX = x;
1447 mPenY = y;
1448 }
1449
1450 /**
1451 * Add to the current path a bezier curve formed
1452 * by the current pen position and the method parameters
1453 * which are two control points and an ending
1454 * point.
1455 */
1456 protected void bezierTo(float control1x, float control1y,
1457 float control2x, float control2y,
1458 float endX, float endY) {
1459
1460 // mPSStream.println(control1x + " " + control1y
1844 */
1845 } else {
1846 mPSStream.println(rgb[0] + " "
1847 + rgb[1] + " "
1848 + rgb[2] + " "
1849 + SETRGBCOLOR_STR);
1850 }
1851
1852 mColor = color;
1853
1854 }
1855 }
1856
1857 void emitPSFont(int psFontIndex, float fontSize) {
1858 mPSStream.println(fontSize + " " +
1859 psFontIndex + " " + SetFontName);
1860 }
1861 }
1862
1863 /**
1864 * Given a Java2D <code>PathIterator</code> instance,
1865 * this method translates that into a PostScript path..
1866 */
1867 void convertToPSPath(PathIterator pathIter) {
1868
1869 float[] segment = new float[6];
1870 int segmentType;
1871
1872 /* Map the PathIterator's fill rule into the PostScript
1873 * fill rule.
1874 */
1875 int fillRule;
1876 if (pathIter.getWindingRule() == PathIterator.WIND_EVEN_ODD) {
1877 fillRule = FILL_EVEN_ODD;
1878 } else {
1879 fillRule = FILL_WINDING;
1880 }
1881
1882 beginPath();
1883
1884 setFillMode(fillRule);
1909 segment[2], segment[3]);
1910 break;
1911
1912 case PathIterator.SEG_CUBICTO:
1913 bezierTo(segment[0], segment[1],
1914 segment[2], segment[3],
1915 segment[4], segment[5]);
1916 break;
1917
1918 case PathIterator.SEG_CLOSE:
1919 closeSubpath();
1920 break;
1921 }
1922
1923
1924 pathIter.next();
1925 }
1926 }
1927
1928 /*
1929 * Fill the path defined by <code>pathIter</code>
1930 * with the specified color.
1931 * The path is provided in current user space.
1932 */
1933 protected void deviceFill(PathIterator pathIter, Color color,
1934 AffineTransform tx, Shape clip) {
1935
1936 setTransform(tx);
1937 setClip(clip);
1938 setColor(color);
1939 convertToPSPath(pathIter);
1940 /* Specify the path to fill as the clip, this ensures that only
1941 * pixels which are inside the path will be filled, which is
1942 * what the Java 2D APIs specify
1943 */
1944 mPSStream.println(GSAVE_STR);
1945 selectClipPath();
1946 fillPath();
1947 mPSStream.println(GRESTORE_STR + " " + NEWPATH_STR);
1948 }
1949
|
99 import sun.font.FontUtilities;
100
101 import java.nio.charset.*;
102 import java.nio.CharBuffer;
103 import java.nio.ByteBuffer;
104 import java.nio.file.Files;
105
106 //REMIND: Remove use of this class when IPPPrintService is moved to share directory.
107 import java.lang.reflect.Method;
108
109 /**
110 * A class which initiates and executes a PostScript printer job.
111 *
112 * @author Richard Blanchard
113 */
114 public class PSPrinterJob extends RasterPrinterJob {
115
116 /* Class Constants */
117
118 /**
119 * Passed to the {@code setFillMode}
120 * method this value forces fills to be
121 * done using the even-odd fill rule.
122 */
123 protected static final int FILL_EVEN_ODD = 1;
124
125 /**
126 * Passed to the {@code setFillMode}
127 * method this value forces fills to be
128 * done using the non-zero winding rule.
129 */
130 protected static final int FILL_WINDING = 2;
131
132 /* PostScript has a 64K maximum on its strings.
133 */
134 private static final int MAX_PSSTR = (1024 * 64 - 1);
135
136 private static final int RED_MASK = 0x00ff0000;
137 private static final int GREEN_MASK = 0x0000ff00;
138 private static final int BLUE_MASK = 0x000000ff;
139
140 private static final int RED_SHIFT = 16;
141 private static final int GREEN_SHIFT = 8;
142 private static final int BLUE_SHIFT = 0;
143
144 private static final int LOWNIBBLE_MASK = 0x0000000f;
145 private static final int HINIBBLE_MASK = 0x000000f0;
146 private static final int HINIBBLE_SHIFT = 4;
277 private EPSPrinter epsPrinter = null;
278
279 /**
280 * The metrics for the font currently set.
281 */
282 FontMetrics mCurMetrics;
283
284 /**
285 * The output stream to which the generated PostScript
286 * is written.
287 */
288 PrintStream mPSStream;
289
290 /* The temporary file to which we spool before sending to the printer */
291
292 File spoolFile;
293
294 /**
295 * This string holds the PostScript operator to
296 * be used to fill a path. It can be changed
297 * by the {@code setFillMode} method.
298 */
299 private String mFillOpStr = WINDING_FILL_STR;
300
301 /**
302 * This string holds the PostScript operator to
303 * be used to clip to a path. It can be changed
304 * by the {@code setFillMode} method.
305 */
306 private String mClipOpStr = WINDING_CLIP_STR;
307
308 /**
309 * A stack that represents the PostScript gstate stack.
310 */
311 ArrayList<GState> mGStateStack = new ArrayList<>();
312
313 /**
314 * The x coordinate of the current pen position.
315 */
316 private float mPenX;
317
318 /**
319 * The y coordinate of the current pen position.
320 */
321 private float mPenY;
322
323 /**
324 * The x coordinate of the starting point of
859 mPSStream.println(" >> setpagedevice");
860 }
861 mPSStream.println(PAGE_SAVE);
862 mPSStream.println(paperHeight + getCoordPrep());
863 }
864
865 /**
866 * The RastePrintJob super class calls this method
867 * at the end of each page.
868 */
869 protected void endPage(PageFormat format, Printable painter,
870 int index)
871 throws PrinterException
872 {
873 mPSStream.println(PAGE_RESTORE);
874 mPSStream.println(SHOWPAGE);
875 }
876
877 /**
878 * Convert the 24 bit BGR image buffer represented by
879 * {@code image} to PostScript. The image is drawn at
880 * {@code (destX, destY)} in device coordinates.
881 * The image is scaled into a square of size
882 * specified by {@code destWidth} and
883 * {@code destHeight}. The portion of the
884 * source image copied into that square is specified
885 * by {@code srcX}, {@code srcY},
886 * {@code srcWidth}, and srcHeight.
887 */
888 protected void drawImageBGR(byte[] bgrData,
889 float destX, float destY,
890 float destWidth, float destHeight,
891 float srcX, float srcY,
892 float srcWidth, float srcHeight,
893 int srcBitMapWidth, int srcBitMapHeight) {
894
895 /* We draw images at device resolution so we probably need
896 * to change the current PostScript transform.
897 */
898 setTransform(new AffineTransform());
899 prepDrawing();
900
901 int intSrcWidth = (int) srcWidth;
902 int intSrcHeight = (int) srcHeight;
903
904 mPSStream.println(IMAGE_SAVE);
905
906 /* Create a PS string big enough to hold a row of pixels.
1009 byte[] rgbData = new byte[width*3];
1010
1011 try {
1012 for(int i = 0; i < height; i++) {
1013 index = swapBGRtoRGB(bgrData, index, rgbData);
1014 byte[] encodedData = rlEncode(rgbData);
1015 byte[] asciiData = ascii85Encode(encodedData);
1016 mPSStream.write(asciiData);
1017 mPSStream.println("");
1018 }
1019
1020 } catch (IOException e) {
1021 throw new PrinterIOException(e);
1022 }
1023
1024 mPSStream.println(IMAGE_RESTORE);
1025 }
1026
1027 /**
1028 * Examine the metrics captured by the
1029 * {@code PeekGraphics} instance and
1030 * if capable of directly converting this
1031 * print job to the printer's control language
1032 * or the native OS's graphics primitives, then
1033 * return a {@code PSPathGraphics} to perform
1034 * that conversion. If there is not an object
1035 * capable of the conversion then return
1036 * {@code null}. Returning {@code null}
1037 * causes the print job to be rasterized.
1038 */
1039
1040 protected Graphics2D createPathGraphics(PeekGraphics peekGraphics,
1041 PrinterJob printerJob,
1042 Printable painter,
1043 PageFormat pageFormat,
1044 int pageIndex) {
1045
1046 PSPathGraphics pathGraphics;
1047 PeekMetrics metrics = peekGraphics.getMetrics();
1048
1049 /* If the application has drawn anything that
1050 * out PathGraphics class can not handle then
1051 * return a null PathGraphics.
1052 */
1053 if (forcePDL == false && (forceRaster == true
1054 || metrics.hasNonSolidColors()
1055 || metrics.hasCompositing())) {
1056
1332 // mPSStream.println("% Font[" + mLastFont.getName() + ", " +
1333 // FontConfiguration.getStyleString(mLastFont.getStyle()) + ", "
1334 // + mLastFont.getSize2D() + "]");
1335 getGState().emitPSFont(psFonts[i], mLastFont.getSize2D());
1336
1337 // out String
1338 mPSStream.println(nativeStr.toString() + " " +
1339 desiredWidth + " " + x + " " + y + " " +
1340 DrawStringName);
1341 x += desiredWidth;
1342 }
1343 } else {
1344 didText = false;
1345 }
1346 }
1347
1348 return didText;
1349 }
1350 /**
1351 * Set the current path rule to be either
1352 * {@code FILL_EVEN_ODD} (using the
1353 * even-odd file rule) or {@code FILL_WINDING}
1354 * (using the non-zero winding rule.)
1355 */
1356 protected void setFillMode(int fillRule) {
1357
1358 switch (fillRule) {
1359
1360 case FILL_EVEN_ODD:
1361 mFillOpStr = EVEN_ODD_FILL_STR;
1362 mClipOpStr = EVEN_ODD_CLIP_STR;
1363 break;
1364
1365 case FILL_WINDING:
1366 mFillOpStr = WINDING_FILL_STR;
1367 mClipOpStr = WINDING_CLIP_STR;
1368 break;
1369
1370 default:
1371 throw new IllegalArgumentException();
1372 }
1373
1374 }
1375
1376 /**
1377 * Set the printer's current color to be that
1378 * defined by {@code color}
1379 */
1380 protected void setColor(Color color) {
1381 mLastColor = color;
1382 }
1383
1384 /**
1385 * Fill the current path using the current fill mode
1386 * and color.
1387 */
1388 protected void fillPath() {
1389
1390 mPSStream.println(mFillOpStr);
1391 }
1392
1393 /**
1394 * Called to mark the start of a new path.
1395 */
1396 protected void beginPath() {
1397
1398 prepDrawing();
1401 mPenX = 0;
1402 mPenY = 0;
1403 }
1404
1405 /**
1406 * Close the current subpath by appending a straight
1407 * line from the current point to the subpath's
1408 * starting point.
1409 */
1410 protected void closeSubpath() {
1411
1412 mPSStream.println(CLOSEPATH_STR);
1413
1414 mPenX = mStartPathX;
1415 mPenY = mStartPathY;
1416 }
1417
1418
1419 /**
1420 * Generate PostScript to move the current pen
1421 * position to {@code (x, y)}.
1422 */
1423 protected void moveTo(float x, float y) {
1424
1425 mPSStream.println(trunc(x) + " " + trunc(y) + MOVETO_STR);
1426
1427 /* moveto marks the start of a new subpath
1428 * and we need to remember that starting
1429 * position so that we know where the
1430 * pen returns to with a close path.
1431 */
1432 mStartPathX = x;
1433 mStartPathY = y;
1434
1435 mPenX = x;
1436 mPenY = y;
1437 }
1438 /**
1439 * Generate PostScript to draw a line from the
1440 * current pen position to {@code (x, y)}.
1441 */
1442 protected void lineTo(float x, float y) {
1443
1444 mPSStream.println(trunc(x) + " " + trunc(y) + LINETO_STR);
1445
1446 mPenX = x;
1447 mPenY = y;
1448 }
1449
1450 /**
1451 * Add to the current path a bezier curve formed
1452 * by the current pen position and the method parameters
1453 * which are two control points and an ending
1454 * point.
1455 */
1456 protected void bezierTo(float control1x, float control1y,
1457 float control2x, float control2y,
1458 float endX, float endY) {
1459
1460 // mPSStream.println(control1x + " " + control1y
1844 */
1845 } else {
1846 mPSStream.println(rgb[0] + " "
1847 + rgb[1] + " "
1848 + rgb[2] + " "
1849 + SETRGBCOLOR_STR);
1850 }
1851
1852 mColor = color;
1853
1854 }
1855 }
1856
1857 void emitPSFont(int psFontIndex, float fontSize) {
1858 mPSStream.println(fontSize + " " +
1859 psFontIndex + " " + SetFontName);
1860 }
1861 }
1862
1863 /**
1864 * Given a Java2D {@code PathIterator} instance,
1865 * this method translates that into a PostScript path..
1866 */
1867 void convertToPSPath(PathIterator pathIter) {
1868
1869 float[] segment = new float[6];
1870 int segmentType;
1871
1872 /* Map the PathIterator's fill rule into the PostScript
1873 * fill rule.
1874 */
1875 int fillRule;
1876 if (pathIter.getWindingRule() == PathIterator.WIND_EVEN_ODD) {
1877 fillRule = FILL_EVEN_ODD;
1878 } else {
1879 fillRule = FILL_WINDING;
1880 }
1881
1882 beginPath();
1883
1884 setFillMode(fillRule);
1909 segment[2], segment[3]);
1910 break;
1911
1912 case PathIterator.SEG_CUBICTO:
1913 bezierTo(segment[0], segment[1],
1914 segment[2], segment[3],
1915 segment[4], segment[5]);
1916 break;
1917
1918 case PathIterator.SEG_CLOSE:
1919 closeSubpath();
1920 break;
1921 }
1922
1923
1924 pathIter.next();
1925 }
1926 }
1927
1928 /*
1929 * Fill the path defined by {@code pathIter}
1930 * with the specified color.
1931 * The path is provided in current user space.
1932 */
1933 protected void deviceFill(PathIterator pathIter, Color color,
1934 AffineTransform tx, Shape clip) {
1935
1936 setTransform(tx);
1937 setClip(clip);
1938 setColor(color);
1939 convertToPSPath(pathIter);
1940 /* Specify the path to fill as the clip, this ensures that only
1941 * pixels which are inside the path will be filled, which is
1942 * what the Java 2D APIs specify
1943 */
1944 mPSStream.println(GSAVE_STR);
1945 selectClipPath();
1946 fillPath();
1947 mPSStream.println(GRESTORE_STR + " " + NEWPATH_STR);
1948 }
1949
|