Source for gnu.java.awt.print.JavaPrinterGraphics

   1: /* JavaPrinterGraphics.java -- AWT printer rendering class.
   2:    Copyright (C) 2006  Free Software Foundation, Inc.
   3: 
   4: This file is part of GNU Classpath.
   5: 
   6: GNU Classpath is free software; you can redistribute it and/or modify
   7: it under the terms of the GNU General Public License as published by
   8: the Free Software Foundation; either version 2, or (at your option)
   9: any later version.
  10: 
  11: GNU Classpath is distributed in the hope that it will be useful, but
  12: WITHOUT ANY WARRANTY; without even the implied warranty of
  13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14: General Public License for more details.
  15: 
  16: You should have received a copy of the GNU General Public License
  17: along with GNU Classpath; see the file COPYING.  If not, write to the
  18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  19: 02110-1301 USA.
  20: 
  21: Linking this library statically or dynamically with other modules is
  22: making a combined work based on this library.  Thus, the terms and
  23: conditions of the GNU General Public License cover the whole
  24: combination.
  25: 
  26: As a special exception, the copyright holders of this library give you
  27: permission to link this library with independent modules to produce an
  28: executable, regardless of the license terms of these independent
  29: modules, and to copy and distribute the resulting executable under
  30: terms of your choice, provided that you also meet, for each linked
  31: independent module, the terms and conditions of the license of that
  32: module.  An independent module is a module which is not derived from
  33: or based on this library.  If you modify this library, you may extend
  34: this exception to your version of the library, but you are not
  35: obligated to do so.  If you do not wish to do so, delete this
  36: exception statement from your version. */
  37: 
  38: package gnu.java.awt.print;
  39: 
  40: import gnu.java.awt.peer.gtk.CairoSurface;
  41: 
  42: import java.awt.Color;
  43: import java.awt.Font;
  44: import java.awt.FontMetrics;
  45: import java.awt.Graphics;
  46: import java.awt.Image;
  47: import java.awt.Rectangle;
  48: import java.awt.Shape;
  49: import java.awt.geom.AffineTransform;
  50: import java.awt.image.ImageObserver;
  51: import java.awt.image.PixelGrabber;
  52: import java.awt.print.PageFormat;
  53: import java.awt.print.Pageable;
  54: import java.awt.print.Paper;
  55: import java.awt.print.Printable;
  56: import java.awt.print.PrinterException;
  57: import java.awt.print.PrinterGraphics;
  58: import java.awt.print.PrinterJob;
  59: import java.io.BufferedWriter;
  60: import java.io.File;
  61: import java.io.FileOutputStream;
  62: import java.io.IOException;
  63: import java.io.OutputStreamWriter;
  64: import java.io.PrintWriter;
  65: import java.text.AttributedCharacterIterator;
  66: 
  67: /**
  68:  * Graphics context to draw to PostScript.
  69:  *
  70:  * @author Sven de Marothy
  71:  */
  72: public class JavaPrinterGraphics extends Graphics implements PrinterGraphics
  73: {
  74: 
  75:   /**
  76:    * The used graphics context.
  77:    */
  78:   private Graphics g;
  79: 
  80:   /**
  81:    * The associated printer job.
  82:    */
  83:   private PrinterJob printerJob;
  84: 
  85:   /**
  86:    * Rendering resolution
  87:    */
  88:   private static final double DPI = 72.0;
  89: 
  90:   /**
  91:    * Rendered image size.
  92:    */
  93:   private int xSize, ySize;
  94: 
  95:   /**
  96:    * The image to render to.
  97:    */
  98:   private Image image;
  99: 
 100:   public JavaPrinterGraphics( PrinterJob printerJob )
 101:   {
 102:     this.printerJob = printerJob;
 103:   }
 104: 
 105:   /**
 106:    * Spool a document to PostScript.
 107:    * If Pageable is non-null, it will print that, otherwise it will use
 108:    * the supplied printable and pageFormat.
 109:    */
 110:   public SpooledDocument spoolPostScript(Printable printable,
 111:                                          PageFormat pageFormat,
 112:                                          Pageable pageable)
 113:     throws PrinterException
 114:   {
 115:     try
 116:       {
 117:         // spool to a temporary file
 118:         File temp = File.createTempFile("cpspool", ".ps");
 119:         temp.deleteOnExit();
 120: 
 121:         PrintWriter out = new PrintWriter
 122:           (new BufferedWriter
 123:             (new OutputStreamWriter
 124:              (new FileOutputStream(temp), "ISO8859_1"), 1000000));
 125: 
 126:         writePSHeader(out);
 127: 
 128:         if(pageable != null)
 129:           {
 130:             for(int index = 0; index < pageable.getNumberOfPages(); index++)
 131:               spoolPage(out, pageable.getPrintable(index),
 132:                         pageable.getPageFormat(index), index);
 133:           }
 134:         else
 135:           {
 136:             int index = 0;
 137:             while(spoolPage(out, printable, pageFormat, index++) ==
 138:                   Printable.PAGE_EXISTS)
 139:               ;
 140:           }
 141:          out.println("%%Trailer");
 142:          out.println("%%EOF");
 143:          out.close();
 144:          return new SpooledDocument( temp );
 145:        }
 146:     catch (IOException e)
 147:       {
 148:         PrinterException pe = new PrinterException();
 149:         pe.initCause(e);
 150:         throw pe;
 151:       }
 152:   }
 153: 
 154:   /**
 155:    * Spools a single page, returns NO_SUCH_PAGE unsuccessful,
 156:    * PAGE_EXISTS if it was.
 157:    */
 158:   public int spoolPage(PrintWriter out,
 159:                        Printable printable,
 160:                        PageFormat pageFormat,
 161:                        int index) throws IOException, PrinterException
 162:   {
 163:     initImage( pageFormat );
 164:     if(printable.print(this, pageFormat, index) == Printable.NO_SUCH_PAGE)
 165:       return Printable.NO_SUCH_PAGE;
 166:     g.dispose();
 167:     g = null;
 168:     writePage( out, pageFormat );
 169:     return Printable.PAGE_EXISTS;
 170:   }
 171: 
 172:   private void initImage(PageFormat pageFormat)
 173:   {
 174:     // Create a really big image and draw to that.
 175:     xSize = (int)(DPI*pageFormat.getWidth()/72.0);
 176:     ySize = (int)(DPI*pageFormat.getHeight()/72.0);
 177: 
 178:     // Swap X and Y sizes if it's a Landscape page.
 179:     if( pageFormat.getOrientation() != PageFormat.PORTRAIT )
 180:       {
 181:         int t = xSize;
 182:         xSize = ySize;
 183:         ySize = t;
 184:       }
 185: 
 186:     // FIXME: This should at least be BufferedImage.
 187:     // Fix once we have a working B.I.
 188:     // Graphics2D should also be supported of course.
 189:     image = CairoSurface.getBufferedImage(xSize, ySize);
 190: 
 191:     g = image.getGraphics();
 192:     setColor(Color.white);
 193:     fillRect(0, 0, xSize, ySize);
 194:     setColor(Color.black);
 195:   }
 196: 
 197:   private void writePSHeader(PrintWriter out)
 198:   {
 199:     out.println("%!PS-Adobe-3.0");
 200:     out.println("%%Title: "+printerJob.getJobName());
 201:     out.println("%%Creator: GNU Classpath ");
 202:     out.println("%%DocumentData: Clean8Bit");
 203: 
 204:     out.println("%%DocumentNeededResources: font Times-Roman Helvetica Courier");
 205:     //    out.println("%%Pages: "+);  // FIXME # pages.
 206:     out.println("%%EndComments");
 207: 
 208:     out.println("%%BeginProlog");
 209:     out.println("%%EndProlog");
 210:     out.println("%%BeginSetup");
 211: 
 212:     // FIXME: Paper name
 213:     // E.g. "A4" "Letter"
 214:     //    out.println("%%BeginFeature: *PageSize A4");
 215: 
 216:     out.println("%%EndFeature");
 217: 
 218:     out.println("%%EndSetup");
 219: 
 220:     //    out.println("%%Page: 1 1");
 221:   }
 222: 
 223:   private void writePage(PrintWriter out, PageFormat pageFormat)
 224:   {
 225:     out.println("%%BeginPageSetup");
 226: 
 227:     Paper p = pageFormat.getPaper();
 228:     double pWidth = p.getWidth();
 229:     double pHeight = p.getHeight();
 230: 
 231:     if( pageFormat.getOrientation() == PageFormat.PORTRAIT )
 232:       out.println( "%%Orientation: Portrait" );
 233:     else
 234:       {
 235:         out.println( "%%Orientation: Landscape" );
 236:         double t = pWidth;
 237:         pWidth = pHeight;
 238:         pHeight = t;
 239:       }
 240: 
 241:     out.println("gsave % first save");
 242: 
 243:     // 595x842; 612x792 respectively
 244:     out.println("<< /PageSize [" +pWidth + " "+pHeight+ "] >> setpagedevice");
 245: 
 246:     // invert the Y axis so that we get screen-like coordinates instead.
 247:     AffineTransform pageTransform = new AffineTransform();
 248:     if( pageFormat.getOrientation() == PageFormat.REVERSE_LANDSCAPE )
 249:       {
 250:         pageTransform.translate(pWidth, pHeight);
 251:         pageTransform.scale(-1.0, -1.0);
 252:       }
 253:     concatCTM(out, pageTransform);
 254:     out.println("%%EndPageSetup");
 255: 
 256:     out.println("gsave");
 257: 
 258: 
 259:     // Draw the image
 260:     out.println(xSize+" "+ySize+" 8 [1 0 0 -1 0 "+ySize+" ]");
 261:     out.println("{currentfile 3 string readhexstring pop} bind");
 262:     out.println("false 3 colorimage");
 263:     int[] pixels = new int[xSize * ySize];
 264:     PixelGrabber pg = new PixelGrabber(image, 0, 0, xSize, ySize, pixels, 0, xSize);
 265: 
 266:     try {
 267:       pg.grabPixels();
 268:     } catch (InterruptedException e) {
 269:       out.println("% Bug getting pixels!");
 270:     }
 271: 
 272:     int n = 0;
 273:     for (int j = 0; j < ySize; j++) {
 274:       for (int i = 0; i < xSize; i++) {
 275:         out.print( colorTripleHex(pixels[j * xSize + i]) );
 276:         if(((++n)%11) == 0) out.println();
 277:       }
 278:     }
 279: 
 280:     out.println();
 281:     out.println("%%EOF");
 282:     out.println("grestore");
 283:     out.println("showpage");
 284:   }
 285: 
 286:   /**
 287:    * Get a nonsperated hex RGB triple, e.g. FFFFFF = white
 288:    */
 289:   private String colorTripleHex(int num){
 290:     String s = "";
 291: 
 292:     try {
 293:       s = Integer.toHexString( ( num & 0x00FFFFFF ) );
 294:       if( s.length() < 6 )
 295:         {
 296:           s = "000000"+s;
 297:           return s.substring(s.length()-6);
 298:         }
 299:     } catch (Exception e){
 300:       s = "FFFFFF";
 301:     }
 302: 
 303:     return s;
 304:   }
 305: 
 306:   private void concatCTM(PrintWriter out, AffineTransform Tx){
 307:     double[] matrixElements = new double[6];
 308:     Tx.getMatrix(matrixElements);
 309: 
 310:     out.print("[ ");
 311:     for(int i=0;i<6;i++)
 312:       out.print(matrixElements[i]+" ");
 313:     out.println("] concat");
 314:   }
 315: 
 316:   //-----------------------------------------------------------------------------
 317:   /**
 318:    * PrinterGraphics method - Returns the printer job associated with this object.
 319:    */
 320:   public PrinterJob getPrinterJob()
 321:   {
 322:     return printerJob;
 323:   }
 324: 
 325:   /**
 326:    * The rest of the methods here are just pass-throughs to g.
 327:    */
 328:   public void clearRect(int x, int y, int width, int height)
 329:   {
 330:     g.clearRect(x, y, width, height);
 331:   }
 332: 
 333:   public void clipRect(int x, int y, int width, int height)
 334:   {
 335:     g.clipRect(x, y, width, height);
 336:   }
 337: 
 338:   public void copyArea(int x, int y, int width, int height, int dx, int dy)
 339:   {
 340:     g.copyArea(x, y, width, height, dx, dy);
 341:   }
 342: 
 343:   public Graphics create()
 344:   {
 345:     return g.create();
 346:   }
 347: 
 348:   public void dispose()
 349:   {
 350:   }
 351: 
 352:   public void drawArc(int x, int y, int width, int height, int startAngle,
 353:                       int arcAngle)
 354:   {
 355:     g.drawArc(x, y, width, height, startAngle, arcAngle);
 356:   }
 357: 
 358:   public boolean drawImage(Image img, int x, int y, Color bgcolor,
 359:                            ImageObserver observer)
 360:   {
 361:     return g.drawImage(img, x, y, bgcolor, observer);
 362:   }
 363: 
 364:   public boolean drawImage(Image img, int x, int y, ImageObserver observer)
 365:   {
 366:     return g.drawImage(img, x, y, observer);
 367:   }
 368: 
 369:   public boolean drawImage(Image img, int x, int y, int width, int height,
 370:                            Color bgcolor, ImageObserver observer)
 371:   {
 372:     return g.drawImage(img, x, y, width, height, bgcolor, observer);
 373:   }
 374: 
 375:   public boolean drawImage(Image img, int x, int y, int width, int height,
 376:                            ImageObserver observer)
 377:   {
 378:     return g.drawImage(img, x, y, width, height, observer);
 379:   }
 380: 
 381:   public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2,
 382:                            int sx1, int sy1, int sx2, int sy2, Color bgcolor,
 383:                            ImageObserver observer)
 384:   {
 385:     return g.drawImage(img, dx1,  dy1,  dx2,  dy2,
 386:                      sx1,  sy1,  sx2,  sy2, bgcolor, observer);
 387:   }
 388: 
 389:   public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2,
 390:                            int sx1, int sy1, int sx2, int sy2, ImageObserver observer)
 391:   {
 392:     return g.drawImage(img, dx1,  dy1,  dx2,  dy2,
 393:                      sx1,  sy1,  sx2,  sy2, observer);
 394:   }
 395: 
 396:   public void drawLine(int x1, int y1, int x2, int y2)
 397:   {
 398:     g.drawLine(x1, y1, x2, y2);
 399:   }
 400: 
 401:   public void drawOval(int x, int y, int width, int height)
 402:   {
 403:     g.drawOval(x, y, width, height);
 404:   }
 405: 
 406:   public void drawPolygon(int[] xPoints, int[] yPoints, int nPoints)
 407:   {
 408:     g.drawPolygon(xPoints, yPoints, nPoints);
 409:   }
 410: 
 411:   public void drawPolyline(int[] xPoints, int[] yPoints, int nPoints)
 412:   {
 413:     g.drawPolyline(xPoints, yPoints, nPoints);
 414:   }
 415: 
 416:   public void drawRoundRect(int x, int y, int width, int height,
 417:                             int arcWidth, int arcHeight)
 418:   {
 419:     g.drawRoundRect(x, y, width, height, arcWidth, arcHeight);
 420:   }
 421: 
 422:   public void drawString(AttributedCharacterIterator iterator, int x, int y)
 423:   {
 424:     g.drawString(iterator, x, y);
 425:   }
 426: 
 427:   public void drawString(String str, int x, int y)
 428:   {
 429:     g.drawString(str, x, y);
 430:   }
 431: 
 432:   public void fillArc(int x, int y, int width, int height,
 433:                       int startAngle, int arcAngle)
 434:   {
 435:     g.fillArc(x, y, width, height, startAngle, arcAngle);
 436:   }
 437: 
 438:   public void fillOval(int x, int y, int width, int height)
 439:   {
 440:     g.fillOval(x, y, width, height);
 441:   }
 442: 
 443:   public void fillPolygon(int[] xPoints, int[] yPoints, int nPoints)
 444:   {
 445:     g.fillPolygon(xPoints, yPoints, nPoints);
 446:   }
 447: 
 448:   public void fillRect(int x, int y, int width, int height)
 449:   {
 450:     g.fillRect(x, y, width, height);
 451:   }
 452: 
 453:   public void fillRoundRect(int x, int y, int width, int height,
 454:                             int arcWidth, int arcHeight)
 455:   {
 456:     g.fillRoundRect(x, y, width, height, arcWidth, arcHeight);
 457:   }
 458: 
 459:   public Shape getClip()
 460:   {
 461:     return g.getClip();
 462:   }
 463: 
 464:   public Rectangle getClipBounds()
 465:   {
 466:     return g.getClipBounds();
 467:   }
 468: 
 469:   public Color getColor()
 470:   {
 471:     return g.getColor();
 472:   }
 473: 
 474:   public Font getFont()
 475:   {
 476:     return g.getFont();
 477:   }
 478: 
 479:   public FontMetrics getFontMetrics(Font f)
 480:   {
 481:     return g.getFontMetrics(f);
 482:   }
 483: 
 484:   public void setClip(int x, int y, int width, int height)
 485:   {
 486:     g.setClip(x, y, width, height);
 487:   }
 488: 
 489:   public void setClip(Shape clip)
 490:   {
 491:     g.setClip(clip);
 492:   }
 493: 
 494:   public void setColor(Color c)
 495:   {
 496:     g.setColor(c);
 497:   }
 498: 
 499:   public void setFont(Font font)
 500:   {
 501:     g.setFont(font);
 502:   }
 503: 
 504:   public void setPaintMode()
 505:   {
 506:     g.setPaintMode();
 507:   }
 508: 
 509:   public void setXORMode(Color c1)
 510:   {
 511:     g.setXORMode(c1);
 512:   }
 513: 
 514:   public void translate(int x, int y)
 515:   {
 516:     g.translate(x, y);
 517:   }
 518: }