KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > fop > render > pcl > PCLGraphics2D


1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements. See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */

17
18 /* $Id$ */
19
20 package org.apache.fop.render.pcl;
21
22 import java.awt.BasicStroke JavaDoc;
23 import java.awt.Color JavaDoc;
24 import java.awt.Dimension JavaDoc;
25 import java.awt.Graphics JavaDoc;
26 import java.awt.Graphics2D JavaDoc;
27 import java.awt.GraphicsConfiguration JavaDoc;
28 import java.awt.GraphicsEnvironment JavaDoc;
29 import java.awt.Image JavaDoc;
30 import java.awt.Paint JavaDoc;
31 import java.awt.Shape JavaDoc;
32 import java.awt.Stroke JavaDoc;
33 import java.awt.font.FontRenderContext JavaDoc;
34 import java.awt.font.GlyphVector JavaDoc;
35 import java.awt.geom.AffineTransform JavaDoc;
36 import java.awt.geom.PathIterator JavaDoc;
37 import java.awt.geom.Point2D JavaDoc;
38 import java.awt.image.BufferedImage JavaDoc;
39 import java.awt.image.ImageObserver JavaDoc;
40 import java.awt.image.RenderedImage JavaDoc;
41 import java.awt.image.renderable.RenderableImage JavaDoc;
42 import java.io.IOException JavaDoc;
43 import java.text.AttributedCharacterIterator JavaDoc;
44
45 import org.apache.fop.util.UnitConv;
46 import org.apache.xmlgraphics.java2d.AbstractGraphics2D;
47 import org.apache.xmlgraphics.java2d.GraphicContext;
48
49 /**
50  * Graphics2D implementation implementing PCL and HP GL/2.
51  * Note: This class cannot be used stand-alone to create full PCL documents.
52  */

53 public class PCLGraphics2D extends AbstractGraphics2D {
54
55     /** The PCL generator */
56     protected PCLGenerator gen;
57     
58     private boolean failOnUnsupportedFeature = true;
59     private boolean clippingDisabled = false;
60     
61     /**
62      * Create a new PCLGraphics2D.
63      * @param gen the PCL Generator to paint with
64      */

65     public PCLGraphics2D(PCLGenerator gen) {
66         super(true);
67         this.gen = gen;
68     }
69
70     /**
71      * Copy constructor
72      * @param g parent PCLGraphics2D
73      */

74     public PCLGraphics2D(PCLGraphics2D g) {
75         super(true);
76         this.gen = g.gen;
77     }
78
79     /** @see java.awt.Graphics#create() */
80     public Graphics JavaDoc create() {
81         PCLGraphics2D copy = new PCLGraphics2D(this);
82         copy.setGraphicContext((GraphicContext)getGraphicContext().clone());
83         return copy;
84     }
85
86     /** @see java.awt.Graphics#dispose() */
87     public void dispose() {
88         this.gen = null;
89     }
90
91     /**
92      * Sets the GraphicContext
93      * @param c GraphicContext to use
94      */

95     public void setGraphicContext(GraphicContext c) {
96         this.gc = c;
97     }
98
99     /**
100      * Allows to disable all clipping operations.
101      * @param value true if clipping should be disabled.
102      */

103     public void setClippingDisabled(boolean value) {
104         this.clippingDisabled = value;
105     }
106     
107     /**
108      * Central handler for IOExceptions for this class.
109      * @param ioe IOException to handle
110      */

111     public void handleIOException(IOException JavaDoc ioe) {
112         //TODO Surely, there's a better way to do this.
113
ioe.printStackTrace();
114     }
115
116     /**
117      * Raises an UnsupportedOperationException if this instance is configured to do so and an
118      * unsupported feature has been requested. Clients can make use of this to fall back to
119      * a more compatible way of painting a PCL graphic.
120      * @param msg the error message to be displayed
121      */

122     protected void handleUnsupportedFeature(String JavaDoc msg) {
123         if (this.failOnUnsupportedFeature) {
124             throw new UnsupportedOperationException JavaDoc(msg);
125         }
126     }
127     
128     /** @see java.awt.Graphics2D#getDeviceConfiguration() */
129     public GraphicsConfiguration JavaDoc getDeviceConfiguration() {
130         return GraphicsEnvironment.getLocalGraphicsEnvironment().
131                 getDefaultScreenDevice().getDefaultConfiguration();
132     }
133
134     /**
135      * Applies a new Stroke object.
136      * @param stroke Stroke object to use
137      * @throws IOException In case of an I/O problem
138      */

139     protected void applyStroke(Stroke JavaDoc stroke) throws IOException JavaDoc {
140         if (stroke instanceof BasicStroke JavaDoc) {
141             BasicStroke JavaDoc bs = (BasicStroke JavaDoc)stroke;
142
143             float[] da = bs.getDashArray();
144             if (da != null) {
145                 
146                 gen.writeText("UL1,");
147                 int len = Math.min(20, da.length);
148                 float patternLen = 0.0f;
149                 for (int idx = 0; idx < len; idx++) {
150                     patternLen += da[idx];
151                 }
152                 if (len == 1) {
153                     patternLen *= 2;
154                 }
155                 for (int idx = 0; idx < len; idx++) {
156                     float perc = da[idx] * 100 / patternLen;
157                     gen.writeText(gen.formatDouble2(perc));
158                     if (idx < da.length - 1) {
159                         gen.writeText(",");
160                     }
161                 }
162                 if (len == 1) {
163                     gen.writeText("," + gen.formatDouble2(da[0] * 100 / patternLen ));
164                     
165                 }
166                 gen.writeText(";");
167                 /* TODO Dash phase NYI
168                 float offset = bs.getDashPhase();
169                 gen.writeln(gen.formatDouble4(offset) + " setdash");
170                 */

171                 Point2D JavaDoc ptLen = new Point2D.Double JavaDoc(patternLen, 0);
172                 //interpret as absolute length
173
getTransform().deltaTransform(ptLen, ptLen);
174                 double transLen = UnitConv.pt2mm(ptLen.distance(0, 0));
175                 gen.writeText("LT1," + gen.formatDouble4(transLen) + ",1;");
176             } else {
177                 gen.writeText("LT;");
178             }
179
180             gen.writeText("LA1"); //line cap
181
int ec = bs.getEndCap();
182             switch (ec) {
183             case BasicStroke.CAP_BUTT:
184                 gen.writeText(",1");
185                 break;
186             case BasicStroke.CAP_ROUND:
187                 gen.writeText(",4");
188                 break;
189             case BasicStroke.CAP_SQUARE:
190                 gen.writeText(",2");
191                 break;
192             default: System.err.println("Unsupported line cap: " + ec);
193             }
194
195             gen.writeText(",2"); //line join
196
int lj = bs.getLineJoin();
197             switch (lj) {
198             case BasicStroke.JOIN_MITER:
199                 gen.writeText(",1");
200                 break;
201             case BasicStroke.JOIN_ROUND:
202                 gen.writeText(",4");
203                 break;
204             case BasicStroke.JOIN_BEVEL:
205                 gen.writeText(",5");
206                 break;
207             default: System.err.println("Unsupported line join: " + lj);
208             }
209
210             float ml = bs.getMiterLimit();
211             gen.writeText(",3" + gen.formatDouble4(ml));
212             
213             float lw = bs.getLineWidth();
214             Point2D JavaDoc ptSrc = new Point2D.Double JavaDoc(lw, 0);
215             //Pen widths are set as absolute metric values (WU0;)
216
Point2D JavaDoc ptDest = getTransform().deltaTransform(ptSrc, null);
217             double transDist = UnitConv.pt2mm(ptDest.distance(0, 0));
218             //System.out.println("--" + ptDest.distance(0, 0) + " " + transDist);
219
gen.writeText(";PW" + gen.formatDouble4(transDist) + ";");
220             
221         } else {
222             handleUnsupportedFeature("Unsupported Stroke: " + stroke.getClass().getName());
223         }
224     }
225
226     /**
227      * Applies a new Paint object.
228      * @param paint Paint object to use
229      * @throws IOException In case of an I/O problem
230      */

231     protected void applyPaint(Paint JavaDoc paint) throws IOException JavaDoc {
232         if (paint instanceof Color JavaDoc) {
233             Color JavaDoc col = (Color JavaDoc)paint;
234             int shade = gen.convertToPCLShade(col);
235             gen.writeText("TR0;FT10," + shade + ";");
236         } else {
237             handleUnsupportedFeature("Unsupported Paint: " + paint.getClass().getName());
238         }
239     }
240
241     private void writeClip(Shape JavaDoc imclip) throws IOException JavaDoc {
242         if (clippingDisabled) {
243             return;
244         }
245         if (imclip == null) {
246             //gen.writeText("IW;");
247
} else {
248             handleUnsupportedFeature("Clipping is not supported. Shape: " + imclip);
249             /* This is an attempt to clip using the "InputWindow" (IW) but this only allows to
250              * clip a rectangular area. Force falling back to bitmap mode for now.
251             Rectangle2D bounds = imclip.getBounds2D();
252             Point2D p1 = new Point2D.Double(bounds.getX(), bounds.getY());
253             Point2D p2 = new Point2D.Double(
254                     bounds.getX() + bounds.getWidth(), bounds.getY() + bounds.getHeight());
255             getTransform().transform(p1, p1);
256             getTransform().transform(p2, p2);
257             gen.writeText("IW" + gen.formatDouble4(p1.getX())
258                     + "," + gen.formatDouble4(p2.getY())
259                     + "," + gen.formatDouble4(p2.getX())
260                     + "," + gen.formatDouble4(p1.getY()) + ";");
261             */

262         }
263     }
264
265     /** @see java.awt.Graphics2D#draw(java.awt.Shape) */
266     public void draw(Shape JavaDoc s) {
267         try {
268             AffineTransform JavaDoc trans = getTransform();
269     
270             Shape JavaDoc imclip = getClip();
271             writeClip(imclip);
272     
273             if (!Color.black.equals(getColor())) {
274                 //TODO PCL 5 doesn't support colored pens, PCL5c has a pen color (PC) command
275
handleUnsupportedFeature("Only black is supported as stroke color: " + getColor());
276             }
277             applyStroke(getStroke());
278     
279             PathIterator JavaDoc iter = s.getPathIterator(trans);
280             processPathIteratorStroke(iter);
281             writeClip(null);
282         } catch (IOException JavaDoc ioe) {
283             handleIOException(ioe);
284         }
285     }
286
287     /** @see java.awt.Graphics2D#fill(java.awt.Shape) */
288     public void fill(Shape JavaDoc s) {
289         try {
290             AffineTransform JavaDoc trans = getTransform();
291             Shape JavaDoc imclip = getClip();
292             writeClip(imclip);
293             
294             applyPaint(getPaint());
295
296             PathIterator JavaDoc iter = s.getPathIterator(trans);
297             processPathIteratorFill(iter);
298             writeClip(null);
299         } catch (IOException JavaDoc ioe) {
300             handleIOException(ioe);
301         }
302     }
303
304     /**
305      * Processes a path iterator generating the nexessary painting operations.
306      * @param iter PathIterator to process
307      * @throws IOException In case of an I/O problem.
308      */

309     public void processPathIteratorStroke(PathIterator JavaDoc iter) throws IOException JavaDoc {
310         gen.writeText("\n");
311         double[] vals = new double[6];
312         boolean penDown = false;
313         double x = 0;
314         double y = 0;
315         StringBuffer JavaDoc sb = new StringBuffer JavaDoc(256);
316         penUp(sb);
317         while (!iter.isDone()) {
318             int type = iter.currentSegment(vals);
319             if (type == PathIterator.SEG_CLOSE) {
320                 gen.writeText("PM;");
321                 gen.writeText(sb.toString());
322                 gen.writeText("PM2;EP;");
323                 sb.setLength(0);
324                 iter.next();
325                 continue;
326             } else if (type == PathIterator.SEG_MOVETO) {
327                 gen.writeText(sb.toString());
328                 sb.setLength(0);
329                 if (penDown) {
330                     penUp(sb);
331                     penDown = false;
332                 }
333             } else {
334                 if (!penDown) {
335                     penDown(sb);
336                     penDown = true;
337                 }
338             }
339             switch (type) {
340             case PathIterator.SEG_CLOSE:
341                 break;
342             case PathIterator.SEG_MOVETO:
343                 x = vals[0];
344                 y = vals[1];
345                 plotAbsolute(x, y, sb);
346                 gen.writeText(sb.toString());
347                 sb.setLength(0);
348                 break;
349             case PathIterator.SEG_LINETO:
350                 x = vals[0];
351                 y = vals[1];
352                 plotAbsolute(x, y, sb);
353                 break;
354             case PathIterator.SEG_CUBICTO:
355                 x = vals[4];
356                 y = vals[5];
357                 bezierAbsolute(vals[0], vals[1], vals[2], vals[3], x, y, sb);
358                 break;
359             case PathIterator.SEG_QUADTO:
360                 double originX = x;
361                 double originY = y;
362                 x = vals[2];
363                 y = vals[3];
364                 quadraticBezierAbsolute(originX, originY, vals[0], vals[1], x, y, sb);
365                 break;
366             default:
367                 break;
368             }
369             iter.next();
370         }
371         sb.append("\n");
372         gen.writeText(sb.toString());
373     }
374     
375     /**
376      * Processes a path iterator generating the nexessary painting operations.
377      * @param iter PathIterator to process
378      * @throws IOException In case of an I/O problem.
379      */

380     public void processPathIteratorFill(PathIterator JavaDoc iter) throws IOException JavaDoc {
381         gen.writeText("\n");
382         double[] vals = new double[6];
383         boolean penDown = false;
384         double x = 0;
385         double y = 0;
386         boolean pendingPM0 = true;
387         StringBuffer JavaDoc sb = new StringBuffer JavaDoc(256);
388         penUp(sb);
389         while (!iter.isDone()) {
390             int type = iter.currentSegment(vals);
391             if (type == PathIterator.SEG_CLOSE) {
392                 sb.append("PM1;");
393                 iter.next();
394                 continue;
395             } else if (type == PathIterator.SEG_MOVETO) {
396                 if (penDown) {
397                     penUp(sb);
398                     penDown = false;
399                 }
400             } else {
401                 if (!penDown) {
402                     penDown(sb);
403                     penDown = true;
404                 }
405             }
406             switch (type) {
407             case PathIterator.SEG_MOVETO:
408                 x = vals[0];
409                 y = vals[1];
410                 plotAbsolute(x, y, sb);
411                 break;
412             case PathIterator.SEG_LINETO:
413                 x = vals[0];
414                 y = vals[1];
415                 plotAbsolute(x, y, sb);
416                 break;
417             case PathIterator.SEG_CUBICTO:
418                 x = vals[4];
419                 y = vals[5];
420                 bezierAbsolute(vals[0], vals[1], vals[2], vals[3], x, y, sb);
421                 break;
422             case PathIterator.SEG_QUADTO:
423                 double originX = x;
424                 double originY = y;
425                 x = vals[2];
426                 y = vals[3];
427                 quadraticBezierAbsolute(originX, originY, vals[0], vals[1], x, y, sb);
428                 break;
429             default:
430                 throw new IllegalStateException JavaDoc("Must not get here");
431             }
432             if (pendingPM0) {
433                 pendingPM0 = false;
434                 sb.append("PM;");
435             }
436             iter.next();
437         }
438         sb.append("PM2;");
439         fillPolygon(iter.getWindingRule(), sb);
440         sb.append("\n");
441         gen.writeText(sb.toString());
442     }
443     
444     private void fillPolygon(int windingRule, StringBuffer JavaDoc sb) {
445         int fillMethod = (windingRule == PathIterator.WIND_EVEN_ODD ? 0 : 1);
446         sb.append("FP").append(fillMethod).append(";");
447     }
448
449     private void plotAbsolute(double x, double y, StringBuffer JavaDoc sb) {
450         sb.append("PA").append(gen.formatDouble4(x));
451         sb.append(",").append(gen.formatDouble4(y)).append(";");
452     }
453
454     private void bezierAbsolute(double x1, double y1, double x2, double y2, double x3, double y3,
455             StringBuffer JavaDoc sb) {
456         sb.append("BZ").append(gen.formatDouble4(x1));
457         sb.append(",").append(gen.formatDouble4(y1));
458         sb.append(",").append(gen.formatDouble4(x2));
459         sb.append(",").append(gen.formatDouble4(y2));
460         sb.append(",").append(gen.formatDouble4(x3));
461         sb.append(",").append(gen.formatDouble4(y3)).append(";");
462     }
463
464     private void quadraticBezierAbsolute(double originX, double originY,
465             double x1, double y1, double x2, double y2, StringBuffer JavaDoc sb) {
466         //Quadratic Bezier curve can be mapped to a normal bezier curve
467
//See http://pfaedit.sourceforge.net/bezier.html
468
double nx1 = originX + (2.0 / 3.0) * (x1 - originX);
469         double ny1 = originY + (2.0 / 3.0) * (y1 - originY);
470         
471         double nx2 = nx1 + (1.0 / 3.0) * (x2 - originX);
472         double ny2 = ny1 + (1.0 / 3.0) * (y2 - originY);
473         
474         bezierAbsolute(nx1, ny1, nx2, ny2, x2, y2, sb);
475     }
476
477     private void penDown(StringBuffer JavaDoc sb) {
478         sb.append("PD;");
479     }
480
481     private void penUp(StringBuffer JavaDoc sb) {
482         sb.append("PU;");
483     }
484
485     /** @see java.awt.Graphics2D#drawString(java.lang.String, float, float) */
486     public void drawString(String JavaDoc s, float x, float y) {
487         java.awt.Font JavaDoc awtFont = getFont();
488         FontRenderContext JavaDoc frc = getFontRenderContext();
489         GlyphVector JavaDoc gv = awtFont.createGlyphVector(frc, s);
490         Shape JavaDoc glyphOutline = gv.getOutline(x, y);
491         fill(glyphOutline);
492     }
493
494     /** @see java.awt.Graphics2D#drawString(java.text.AttributedCharacterIterator, float, float) */
495     public void drawString(AttributedCharacterIterator JavaDoc iterator, float x,
496             float y) {
497         // TODO Auto-generated method stub
498
handleUnsupportedFeature("drawString NYI");
499     }
500
501     /**
502      * @see java.awt.Graphics2D#drawRenderedImage(java.awt.image.RenderedImage,
503      * java.awt.geom.AffineTransform)
504      */

505     public void drawRenderedImage(RenderedImage JavaDoc img, AffineTransform JavaDoc xform) {
506         handleUnsupportedFeature("Bitmap images are not supported");
507     }
508
509     /**
510      * @see java.awt.Graphics2D#drawRenderableImage(java.awt.image.renderable.RenderableImage,
511      * java.awt.geom.AffineTransform)
512      */

513     public void drawRenderableImage(RenderableImage JavaDoc img, AffineTransform JavaDoc xform) {
514         handleUnsupportedFeature("Bitmap images are not supported");
515     }
516
517     /**
518      * @see java.awt.Graphics#drawImage(java.awt.Image, int, int, int, int,
519      * java.awt.image.ImageObserver)
520      */

521     public boolean drawImage(Image JavaDoc img, int x, int y, int width, int height,
522             ImageObserver JavaDoc observer) {
523         handleUnsupportedFeature("Bitmap images are not supported");
524         return false;
525     }
526
527     /**
528      * @see java.awt.Graphics#drawImage(java.awt.Image, int, int, java.awt.image.ImageObserver)
529      */

530     public boolean drawImage(Image JavaDoc img, int x, int y, ImageObserver JavaDoc observer) {
531         handleUnsupportedFeature("Bitmap images are not supported");
532         return false;
533         /*
534          * First attempt disabled.
535          * Reasons: Lack of transparency control, positioning and rotation issues
536         final int width = img.getWidth(observer);
537         final int height = img.getHeight(observer);
538         if (width == -1 || height == -1) {
539             return false;
540         }
541
542         Dimension size = new Dimension(width, height);
543         BufferedImage buf = buildBufferedImage(size);
544
545         java.awt.Graphics2D g = buf.createGraphics();
546         try {
547             g.setComposite(AlphaComposite.SrcOver);
548             g.setBackground(new Color(255, 255, 255));
549             g.setPaint(new Color(255, 255, 255));
550             g.fillRect(0, 0, width, height);
551             g.clip(new Rectangle(0, 0, buf.getWidth(), buf.getHeight()));
552
553             if (!g.drawImage(img, 0, 0, observer)) {
554                 return false;
555             }
556         } finally {
557             g.dispose();
558         }
559
560         try {
561             AffineTransform at = getTransform();
562             gen.enterPCLMode(false);
563             //Shape imclip = getClip(); Clipping is not available in PCL
564             Point2D p1 = new Point2D.Double(x, y);
565             at.transform(p1, p1);
566             pclContext.getTransform().transform(p1, p1);
567             gen.setCursorPos(p1.getX(), p1.getY());
568             gen.paintBitmap(buf, 72);
569             gen.enterHPGL2Mode(false);
570         } catch (IOException ioe) {
571             handleIOException(ioe);
572         }
573
574         return true;*/

575     }
576
577     /** @see java.awt.Graphics#copyArea(int, int, int, int, int, int) */
578     public void copyArea(int x, int y, int width, int height, int dx, int dy) {
579         // TODO Auto-generated method stub
580
handleUnsupportedFeature("copyArea NYI");
581     }
582
583     /** @see java.awt.Graphics#setXORMode(java.awt.Color) */
584     public void setXORMode(Color JavaDoc c1) {
585         // TODO Auto-generated method stub
586
handleUnsupportedFeature("setXORMode NYI");
587     }
588
589     /**
590      * Used to create proper font metrics
591      */

592     private Graphics2D JavaDoc fmg;
593
594     {
595         BufferedImage JavaDoc bi = new BufferedImage JavaDoc(1, 1,
596                                              BufferedImage.TYPE_INT_ARGB);
597
598         fmg = bi.createGraphics();
599     }
600
601     /**
602      * Creates a buffered image.
603      * @param size dimensions of the image to be created
604      * @return the buffered image
605      */

606     protected BufferedImage JavaDoc buildBufferedImage(Dimension JavaDoc size) {
607         return new BufferedImage JavaDoc(size.width, size.height,
608                                  BufferedImage.TYPE_BYTE_GRAY);
609     }
610     
611     /** @see java.awt.Graphics#getFontMetrics(java.awt.Font) */
612     public java.awt.FontMetrics JavaDoc getFontMetrics(java.awt.Font JavaDoc f) {
613         return fmg.getFontMetrics(f);
614     }
615
616 }
617
Popular Tags