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:      out.println("%%Trailer");
 141:      out.println("%%EOF");
 142:      out.close();
 143:      return new SpooledDocument( temp );
 144:        } 
 145:     catch (IOException e) 
 146:       {
 147:     PrinterException pe = new PrinterException();
 148:     pe.initCause(e);
 149:     throw pe;
 150:       }
 151:   }
 152: 
 153:   /**
 154:    * Spools a single page, returns NO_SUCH_PAGE unsuccessful,
 155:    * PAGE_EXISTS if it was.
 156:    */
 157:   public int spoolPage(PrintWriter out,
 158:                Printable printable, 
 159:                PageFormat pageFormat, 
 160:                int index) throws IOException, PrinterException
 161:   {
 162:     initImage( pageFormat );
 163:     if(printable.print(this, pageFormat, index) == Printable.NO_SUCH_PAGE)
 164:       return Printable.NO_SUCH_PAGE;
 165:     g.dispose();
 166:     g = null;
 167:     writePage( out, pageFormat );
 168:     return Printable.PAGE_EXISTS;
 169:   }
 170:   
 171:   private void initImage(PageFormat pageFormat)
 172:   {
 173:     // Create a really big image and draw to that.
 174:     xSize = (int)(DPI*pageFormat.getWidth()/72.0);
 175:     ySize = (int)(DPI*pageFormat.getHeight()/72.0);
 176:     
 177:     // Swap X and Y sizes if it's a Landscape page.
 178:     if( pageFormat.getOrientation() != PageFormat.PORTRAIT )
 179:       {
 180:     int t = xSize;
 181:     xSize = ySize;
 182:     ySize = t;
 183:       }
 184: 
 185:     // FIXME: This should at least be BufferedImage. 
 186:     // Fix once we have a working B.I.
 187:     // Graphics2D should also be supported of course.
 188:     image = CairoSurface.getBufferedImage(xSize, ySize);
 189: 
 190:     g = image.getGraphics();
 191:     setColor(Color.white);
 192:     fillRect(0, 0, xSize, ySize);
 193:     setColor(Color.black);
 194:   }
 195: 
 196:   private void writePSHeader(PrintWriter out)
 197:   {
 198:     out.println("%!PS-Adobe-3.0");      
 199:     out.println("%%Title: "+printerJob.getJobName());
 200:     out.println("%%Creator: GNU Classpath ");
 201:     out.println("%%DocumentData: Clean8Bit");
 202: 
 203:     out.println("%%DocumentNeededResources: font Times-Roman Helvetica Courier");
 204:     //    out.println("%%Pages: "+);  // FIXME # pages.
 205:     out.println("%%EndComments");
 206:     
 207:     out.println("%%BeginProlog");
 208:     out.println("%%EndProlog");
 209:     out.println("%%BeginSetup");
 210:     
 211:     // FIXME: Paper name
 212:     // E.g. "A4" "Letter"
 213:     //    out.println("%%BeginFeature: *PageSize A4");
 214:     
 215:     out.println("%%EndFeature");
 216: 
 217:     out.println("%%EndSetup");
 218:     
 219:     //    out.println("%%Page: 1 1");
 220:   }
 221: 
 222:   private void writePage(PrintWriter out, PageFormat pageFormat)
 223:   {
 224:     out.println("%%BeginPageSetup");
 225: 
 226:     Paper p = pageFormat.getPaper();
 227:     double pWidth = p.getWidth();
 228:     double pHeight = p.getHeight();
 229: 
 230:     if( pageFormat.getOrientation() == PageFormat.PORTRAIT )
 231:       out.println( "%%Orientation: Portrait" );
 232:     else
 233:       {
 234:     out.println( "%%Orientation: Landscape" );
 235:     double t = pWidth;
 236:     pWidth = pHeight;
 237:     pHeight = t;
 238:       }
 239:       
 240:     out.println("gsave % first save");
 241:     
 242:     // 595x842; 612x792 respectively
 243:     out.println("<< /PageSize [" +pWidth + " "+pHeight+ "] >> setpagedevice");
 244: 
 245:     // invert the Y axis so that we get screen-like coordinates instead.
 246:     AffineTransform pageTransform = new AffineTransform();
 247:     if( pageFormat.getOrientation() == PageFormat.REVERSE_LANDSCAPE )
 248:       {
 249:     pageTransform.translate(pWidth, pHeight);
 250:     pageTransform.scale(-1.0, -1.0);
 251:       }
 252:     concatCTM(out, pageTransform);
 253:     out.println("%%EndPageSetup");
 254: 
 255:     out.println("gsave");
 256: 
 257: 
 258:     // Draw the image
 259:     out.println(xSize+" "+ySize+" 8 [1 0 0 -1 0 "+ySize+" ]"); 
 260:     out.println("{currentfile 3 string readhexstring pop} bind");
 261:     out.println("false 3 colorimage");
 262:     int[] pixels = new int[xSize * ySize];
 263:     PixelGrabber pg = new PixelGrabber(image, 0, 0, xSize, ySize, pixels, 0, xSize);
 264: 
 265:     try {
 266:       pg.grabPixels();
 267:     } catch (InterruptedException e) {
 268:       out.println("% Bug getting pixels!");
 269:     }
 270: 
 271:     int n = 0;
 272:     for (int j = 0; j < ySize; j++) {
 273:       for (int i = 0; i < xSize; i++) {
 274:     out.print( colorTripleHex(pixels[j * xSize + i]) );
 275:     if(((++n)%11) == 0) out.println();
 276:       }
 277:     }
 278:     
 279:     out.println();
 280:     out.println("%%EOF");
 281:     out.println("grestore");
 282:     out.println("showpage");
 283:   }
 284:   
 285:   /**
 286:    * Get a nonsperated hex RGB triple, e.g. FFFFFF = white 
 287:    */
 288:   private String colorTripleHex(int num){
 289:     String s = "";
 290: 
 291:     try {
 292:       s = Integer.toHexString( ( num & 0x00FFFFFF ) );
 293:       if( s.length() < 6 )
 294:     {
 295:       s = "000000"+s;
 296:       return s.substring(s.length()-6);
 297:     }
 298:     } catch (Exception e){
 299:       s = "FFFFFF";
 300:     }
 301: 
 302:     return s;
 303:   }
 304: 
 305:   private void concatCTM(PrintWriter out, AffineTransform Tx){
 306:     double[] matrixElements = new double[6];
 307:     Tx.getMatrix(matrixElements);
 308:     
 309:     out.print("[ ");
 310:     for(int i=0;i<6;i++)
 311:       out.print(matrixElements[i]+" ");
 312:     out.println("] concat");
 313:   }
 314: 
 315:   //-----------------------------------------------------------------------------
 316:   /**
 317:    * PrinterGraphics method - Returns the printer job associated with this object.
 318:    */
 319:   public PrinterJob getPrinterJob()
 320:   {
 321:     return printerJob;
 322:   }
 323: 
 324:   /**
 325:    * The rest of the methods here are just pass-throughs to g.
 326:    */
 327:   public void clearRect(int x, int y, int width, int height)
 328:   {
 329:     g.clearRect(x, y, width, height);
 330:   }
 331: 
 332:   public void clipRect(int x, int y, int width, int height)
 333:   {
 334:     g.clipRect(x, y, width, height);
 335:   }
 336: 
 337:   public void copyArea(int x, int y, int width, int height, int dx, int dy)
 338:   {
 339:     g.copyArea(x, y, width, height, dx, dy);
 340:   }
 341: 
 342:   public Graphics create()
 343:   {
 344:     return g.create();
 345:   }
 346: 
 347:   public void dispose()
 348:   {
 349:   }
 350: 
 351:   public void drawArc(int x, int y, int width, int height, int startAngle, 
 352:               int arcAngle)
 353:   {
 354:     g.drawArc(x, y, width, height, startAngle, arcAngle);
 355:   }
 356: 
 357:   public boolean drawImage(Image img, int x, int y, Color bgcolor, 
 358:                ImageObserver observer)
 359:   {
 360:     return g.drawImage(img, x, y, bgcolor, observer);
 361:   }
 362: 
 363:   public boolean drawImage(Image img, int x, int y, ImageObserver observer)
 364:   {
 365:     return g.drawImage(img, x, y, observer);
 366:   }
 367: 
 368:   public boolean drawImage(Image img, int x, int y, int width, int height, 
 369:                Color bgcolor, ImageObserver observer)
 370:   {
 371:     return g.drawImage(img, x, y, width, height, bgcolor, observer);
 372:   }
 373: 
 374:   public boolean drawImage(Image img, int x, int y, int width, int height, 
 375:                ImageObserver observer)
 376:   {
 377:     return g.drawImage(img, x, y, width, height, observer);
 378:   }
 379: 
 380:   public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, 
 381:                int sx1, int sy1, int sx2, int sy2, Color bgcolor, 
 382:                ImageObserver observer)
 383:   {
 384:     return g.drawImage(img, dx1,  dy1,  dx2,  dy2,  
 385:              sx1,  sy1,  sx2,  sy2, bgcolor, observer);
 386:   }
 387: 
 388:   public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, 
 389:                int sx1, int sy1, int sx2, int sy2, ImageObserver observer)
 390:   {
 391:     return g.drawImage(img, dx1,  dy1,  dx2,  dy2,  
 392:              sx1,  sy1,  sx2,  sy2, observer);
 393:   }
 394: 
 395:   public void drawLine(int x1, int y1, int x2, int y2)
 396:   {
 397:     g.drawLine(x1, y1, x2, y2);
 398:   }
 399: 
 400:   public void drawOval(int x, int y, int width, int height)
 401:   {
 402:     g.drawOval(x, y, width, height);
 403:   }
 404: 
 405:   public void drawPolygon(int[] xPoints, int[] yPoints, int nPoints)
 406:   {
 407:     g.drawPolygon(xPoints, yPoints, nPoints);
 408:   }
 409: 
 410:   public void drawPolyline(int[] xPoints, int[] yPoints, int nPoints)
 411:   {
 412:     g.drawPolyline(xPoints, yPoints, nPoints);
 413:   }
 414: 
 415:   public void drawRoundRect(int x, int y, int width, int height, 
 416:                 int arcWidth, int arcHeight)
 417:   {
 418:     g.drawRoundRect(x, y, width, height, arcWidth, arcHeight);
 419:   }
 420: 
 421:   public void drawString(AttributedCharacterIterator iterator, int x, int y)
 422:   {
 423:     g.drawString(iterator, x, y);
 424:   }
 425: 
 426:   public void drawString(String str, int x, int y)
 427:   {
 428:     g.drawString(str, x, y);
 429:   }
 430: 
 431:   public void fillArc(int x, int y, int width, int height, 
 432:               int startAngle, int arcAngle)
 433:   {
 434:     g.fillArc(x, y, width, height, startAngle, arcAngle);
 435:   }
 436: 
 437:   public void fillOval(int x, int y, int width, int height)
 438:   {
 439:     g.fillOval(x, y, width, height);
 440:   }
 441: 
 442:   public void fillPolygon(int[] xPoints, int[] yPoints, int nPoints)
 443:   {
 444:     g.fillPolygon(xPoints, yPoints, nPoints);
 445:   }
 446: 
 447:   public void fillRect(int x, int y, int width, int height)
 448:   {
 449:     g.fillRect(x, y, width, height);
 450:   }
 451: 
 452:   public void fillRoundRect(int x, int y, int width, int height, 
 453:                 int arcWidth, int arcHeight)
 454:   {
 455:     g.fillRoundRect(x, y, width, height, arcWidth, arcHeight);
 456:   }
 457: 
 458:   public Shape getClip()
 459:   {
 460:     return g.getClip();
 461:   }
 462: 
 463:   public Rectangle getClipBounds()
 464:   {
 465:     return g.getClipBounds();
 466:   }
 467: 
 468:   public Color getColor()
 469:   {
 470:     return g.getColor();
 471:   }
 472: 
 473:   public Font getFont()
 474:   {
 475:     return g.getFont();
 476:   }
 477: 
 478:   public FontMetrics getFontMetrics(Font f)
 479:   {
 480:     return g.getFontMetrics(f);
 481:   }
 482: 
 483:   public void setClip(int x, int y, int width, int height)
 484:   {
 485:     g.setClip(x, y, width, height);
 486:   }
 487: 
 488:   public void setClip(Shape clip)
 489:   {
 490:     g.setClip(clip);
 491:   }
 492: 
 493:   public void setColor(Color c)
 494:   {
 495:     g.setColor(c);
 496:   }
 497: 
 498:   public void setFont(Font font)
 499:   {
 500:     g.setFont(font);
 501:   }
 502: 
 503:   public void setPaintMode()
 504:   {
 505:     g.setPaintMode();
 506:   }
 507: 
 508:   public void setXORMode(Color c1)
 509:   {
 510:     g.setXORMode(c1);
 511:   }
 512: 
 513:   public void translate(int x, int y)
 514:   {
 515:     g.translate(x, y);
 516:   }
 517: }