Source Code Cross Referenced for PDFRenderer.java in  » PDF » PDF-Renderer » com » sun » pdfview » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » PDF » PDF Renderer » com.sun.pdfview 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         * $Id: PDFRenderer.java,v 1.3 2007/12/20 18:17:41 rbair Exp $
003:         *
004:         * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle,
005:         * Santa Clara, California 95054, U.S.A. All rights reserved.
006:         *
007:         * This library is free software; you can redistribute it and/or
008:         * modify it under the terms of the GNU Lesser General Public
009:         * License as published by the Free Software Foundation; either
010:         * version 2.1 of the License, or (at your option) any later version.
011:         * 
012:         * This library is distributed in the hope that it will be useful,
013:         * but WITHOUT ANY WARRANTY; without even the implied warranty of
014:         * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
015:         * Lesser General Public License for more details.
016:         * 
017:         * You should have received a copy of the GNU Lesser General Public
018:         * License along with this library; if not, write to the Free Software
019:         * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
020:         */
021:
022:        package com.sun.pdfview;
023:
024:        import java.awt.AlphaComposite;
025:        import java.awt.BasicStroke;
026:        import java.awt.Color;
027:        import java.awt.Graphics2D;
028:        import java.awt.Image;
029:        import java.awt.Rectangle;
030:        import java.awt.RenderingHints;
031:        import java.awt.Shape;
032:        import java.awt.geom.AffineTransform;
033:        import java.awt.geom.GeneralPath;
034:        import java.awt.geom.Rectangle2D;
035:        import java.awt.image.BufferedImage;
036:        import java.awt.image.ImageObserver;
037:        import java.lang.ref.WeakReference;
038:        import java.util.ArrayList;
039:        import java.util.Iterator;
040:        import java.util.List;
041:        import java.util.Stack;
042:
043:        /**
044:         * This class turns a set of PDF Commands from a PDF page into an image.  It
045:         * encapsulates the state of drawing in terms of stroke, fill, transform,
046:         * etc., as well as pushing and popping these states.
047:         *
048:         * When the run method is called, this class goes through all remaining commands
049:         * in the PDF Page and draws them to its buffered image.  It then updates any
050:         * ImageConsumers with the drawn data.
051:         */
052:        public class PDFRenderer extends BaseWatchable implements  Runnable {
053:            /** the page we were generate from */
054:            private PDFPage page;
055:
056:            /** where we are in the page's command list */
057:            private int currentCommand;
058:
059:            /** a weak reference to the image we render into.  For the image
060:             * to remain available, some other code must retain a strong reference to it.
061:             */
062:            private WeakReference imageRef;
063:
064:            /** the graphics object for use within an iteration.  Note this must be
065:             * set to null at the end of each iteration, or the image will not be 
066:             * collected
067:             */
068:            private Graphics2D g;
069:
070:            /** the current graphics state */
071:            private GraphicsState state;
072:
073:            /** the stack of push()ed graphics states */
074:            private Stack stack;
075:
076:            /** the total region of this image that has been written to */
077:            private Rectangle2D globalDirtyRegion;
078:
079:            /** the image observers that will be updated when this image changes */
080:            private List observers;
081:
082:            /** the last shape we drew (to check for overlaps) */
083:            private GeneralPath lastShape;
084:
085:            /** the info about the image, if we need to recreate it */
086:            private ImageInfo imageinfo;
087:
088:            /** the next time the image should be notified about updates */
089:            private long then = 0;
090:
091:            /** the sum of all the individual dirty regions since the last update */
092:            private Rectangle2D unupdatedRegion;
093:
094:            /** how long (in milliseconds) to wait between image updates */
095:            public static final long UPDATE_DURATION = 200;
096:
097:            public static final float NOPHASE = -1000;
098:            public static final float NOWIDTH = -1000;
099:            public static final float NOLIMIT = -1000;
100:            public static final int NOCAP = -1000;
101:            public static final float[] NODASH = null;
102:            public static final int NOJOIN = -1000;
103:
104:            /**
105:             * create a new PDFGraphics state
106:             * @param page the current page
107:             * @param imageinfo the paramters of the image to render
108:             */
109:            public PDFRenderer(PDFPage page, ImageInfo imageinfo,
110:                    BufferedImage bi) {
111:                super ();
112:
113:                this .page = page;
114:                this .imageinfo = imageinfo;
115:                this .imageRef = new WeakReference(bi);
116:
117:                // initialize the list of observers
118:                observers = new ArrayList();
119:            }
120:
121:            /**
122:             * create a new PDFGraphics state, given a Graphics2D. This version
123:             * will <b>not</b> create an image, and you will get a NullPointerException
124:             * if you attempt to call getImage().
125:             * @param page the current page
126:             * @param g the Graphics2D object to use for drawing
127:             * @param imgbounds the bounds of the image into which to fit the page
128:             * @param clip the portion of the page to draw, in page space, or null
129:             * if the whole page should be drawn
130:             * @param bgColor the color to draw the background of the image, or
131:             * null for no color (0 alpha value)
132:             */
133:            public PDFRenderer(PDFPage page, Graphics2D g, Rectangle imgbounds,
134:                    Rectangle2D clip, Color bgColor) {
135:                super ();
136:
137:                this .page = page;
138:                this .g = g;
139:                this .imageinfo = new ImageInfo(imgbounds.width,
140:                        imgbounds.height, clip);
141:                g.translate(imgbounds.x, imgbounds.y);
142:                //	System.out.println("Translating by "+imgbounds.x+","+imgbounds.y);
143:
144:                // initialize the list of observers
145:                observers = new ArrayList();
146:            }
147:
148:            /**
149:             * Set up the graphics transform to match the clip region
150:             * to the image size.
151:             */
152:            private void setupRendering(Graphics2D g) {
153:                g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
154:                        RenderingHints.VALUE_ANTIALIAS_ON);
155:                g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
156:                        RenderingHints.VALUE_INTERPOLATION_BICUBIC);
157:                g.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION,
158:                        RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
159:
160:                if (imageinfo.bgColor != null) {
161:                    g.setColor(imageinfo.bgColor);
162:                    g.fillRect(0, 0, imageinfo.width, imageinfo.height);
163:                }
164:
165:                g.setColor(Color.BLACK);
166:
167:                // set the initial clip and transform on the graphics 
168:                AffineTransform at = getInitialTransform();
169:                g.transform(at);
170:
171:                // set up the initial graphics state
172:                state = new GraphicsState();
173:                state.cliprgn = null;
174:                state.stroke = new BasicStroke();
175:                state.strokePaint = PDFPaint.getColorPaint(Color.black);
176:                state.fillPaint = state.strokePaint;
177:                state.fillAlpha = AlphaComposite
178:                        .getInstance(AlphaComposite.SRC);
179:                state.strokeAlpha = AlphaComposite
180:                        .getInstance(AlphaComposite.SRC);
181:                state.xform = g.getTransform();
182:
183:                // initialize the stack
184:                stack = new Stack();
185:
186:                // initialize the current command
187:                currentCommand = 0;
188:            }
189:
190:            /**
191:             * push the current graphics state onto the stack.  Continue working
192:             * with the current object; calling pop() restores the state of this
193:             * object to its state when push() was called.
194:             */
195:            public void push() {
196:                state.cliprgn = g.getClip();
197:                stack.push(state);
198:
199:                state = (GraphicsState) state.clone();
200:            }
201:
202:            /**
203:             * restore the state of this object to what it was when the previous
204:             * push() was called.
205:             */
206:            public void pop() {
207:                state = (GraphicsState) stack.pop();
208:
209:                setTransform(state.xform);
210:                setClip(state.cliprgn);
211:            }
212:
213:            /**
214:             * draw an outline using the current stroke and draw paint
215:             * @param s the path to stroke
216:             * @return a Rectangle2D to which the current region being
217:             * drawn will be added.  May also be null, in which case no dirty
218:             * region will be recorded.
219:             */
220:            public Rectangle2D stroke(GeneralPath s) {
221:                g.setComposite(state.strokeAlpha);
222:                s = new GeneralPath(state.stroke.createStrokedShape(s));
223:                return state.strokePaint.fill(this , g, s);
224:            }
225:
226:            /**
227:             * draw an outline.
228:             * @param p the path to draw
229:             * @param bs the stroke with which to draw the path
230:             */
231:            public void draw(GeneralPath p, BasicStroke bs) {
232:                g.setComposite(state.fillAlpha);
233:                g.setPaint(state.fillPaint.getPaint());
234:                g.setStroke(bs);
235:                g.draw(p);
236:            }
237:
238:            /**
239:             * fill an outline using the current fill paint
240:             * @param s the path to fill
241:             */
242:            public Rectangle2D fill(GeneralPath s) {
243:                g.setComposite(state.fillAlpha);
244:                return state.fillPaint.fill(this , g, s);
245:            }
246:
247:            /**
248:             * draw an image.
249:             * @param image the image to draw
250:             */
251:            public Rectangle2D drawImage(PDFImage image) {
252:                AffineTransform at = new AffineTransform(1f / image.getWidth(),
253:                        0, 0, -1f / image.getHeight(), 0, 1);
254:
255:                BufferedImage bi = image.getImage();
256:                if (image.isImageMask()) {
257:                    bi = getMaskedImage(bi);
258:                }
259:
260:                /*
261:                javax.swing.JFrame frame = new javax.swing.JFrame("Original Image");
262:                frame.getContentPane().add(new javax.swing.JLabel(new javax.swing.ImageIcon(bi)));
263:                frame.pack();
264:                frame.show();
265:                 */
266:
267:                g.setComposite(AlphaComposite
268:                        .getInstance(AlphaComposite.SRC_OVER));
269:                if (!g.drawImage(bi, at, null)) {
270:                    System.out.println("Image not completed!");
271:                }
272:
273:                // get the total transform that was executed
274:                AffineTransform bt = new AffineTransform(g.getTransform());
275:                bt.concatenate(at);
276:
277:                double minx = bi.getMinX();
278:                double miny = bi.getMinY();
279:
280:                double[] points = new double[] { minx, miny,
281:                        minx + bi.getWidth(), miny + bi.getHeight() };
282:                bt.transform(points, 0, points, 0, 2);
283:
284:                return new Rectangle2D.Double(points[0], points[1], points[2]
285:                        - points[0], points[3] - points[1]);
286:
287:            }
288:
289:            /**
290:             * add the path to the current clip.  The new clip will be the intersection
291:             * of the old clip and given path.
292:             */
293:            public void clip(GeneralPath s) {
294:                g.clip(s);
295:            }
296:
297:            /**
298:             * set the clip to be the given shape.  The current clip is not taken
299:             * into account.
300:             */
301:            private void setClip(Shape s) {
302:                state.cliprgn = s;
303:                g.setClip(null);
304:                g.clip(s);
305:            }
306:
307:            /**
308:             * get the current affinetransform
309:             */
310:            public AffineTransform getTransform() {
311:                return state.xform;
312:            }
313:
314:            /**
315:             * concatenate the given transform with the current transform
316:             */
317:            public void transform(AffineTransform at) {
318:                state.xform.concatenate(at);
319:                g.setTransform(state.xform);
320:            }
321:
322:            /**
323:             * replace the current transform with the given one.
324:             */
325:            public void setTransform(AffineTransform at) {
326:                state.xform = at;
327:                g.setTransform(state.xform);
328:            }
329:
330:            /**
331:             * get the initial transform from page space to Java space
332:             */
333:            public AffineTransform getInitialTransform() {
334:                return page.getInitialTransform(imageinfo.width,
335:                        imageinfo.height, imageinfo.clip);
336:            }
337:
338:            /**
339:             * Set some or all aspects of the current stroke.
340:             * @param w the width of the stroke, or NOWIDTH to leave it unchanged
341:             * @param cap the end cap style, or NOCAP to leave it unchanged
342:             * @param join the join style, or NOJOIN to leave it unchanged
343:             * @param limit the miter limit, or NOLIMIT to leave it unchanged
344:             * @param phase the phase of the dash array, or NOPHASE to leave it
345:             * unchanged
346:             * @param ary the dash array, or null to leave it unchanged.  phase
347:             * and ary must both be valid, or phase must be NOPHASE while ary is null.
348:             */
349:            public void setStrokeParts(float w, int cap, int join, float limit,
350:                    float[] ary, float phase) {
351:                if (w == NOWIDTH) {
352:                    w = state.stroke.getLineWidth();
353:                }
354:                if (cap == NOCAP) {
355:                    cap = state.stroke.getEndCap();
356:                }
357:                if (join == NOJOIN) {
358:                    join = state.stroke.getLineJoin();
359:                }
360:                if (limit == NOLIMIT) {
361:                    limit = state.stroke.getMiterLimit();
362:                }
363:                if (phase == NOPHASE) {
364:                    ary = state.stroke.getDashArray();
365:                    phase = state.stroke.getDashPhase();
366:                }
367:                if (ary != null && ary.length == 0) {
368:                    ary = null;
369:                }
370:                if (phase == NOPHASE) {
371:                    state.stroke = new BasicStroke(w, cap, join, limit);
372:                } else {
373:                    state.stroke = new BasicStroke(w, cap, join, limit, ary,
374:                            phase);
375:                }
376:            }
377:
378:            /**
379:             * get the current stroke as a BasicStroke
380:             */
381:            public BasicStroke getStroke() {
382:                return state.stroke;
383:            }
384:
385:            /**
386:             * set the current stroke as a BasicStroke
387:             */
388:            public void setStroke(BasicStroke bs) {
389:                state.stroke = bs;
390:            }
391:
392:            /**
393:             * set the stroke color
394:             */
395:            public void setStrokePaint(PDFPaint paint) {
396:                state.strokePaint = paint;
397:            }
398:
399:            /**
400:             * set the fill color
401:             */
402:            public void setFillPaint(PDFPaint paint) {
403:                state.fillPaint = paint;
404:            }
405:
406:            /**
407:             * set the stroke alpha 
408:             */
409:            public void setStrokeAlpha(float alpha) {
410:                state.strokeAlpha = AlphaComposite.getInstance(
411:                        AlphaComposite.SRC_OVER, alpha);
412:            }
413:
414:            /**
415:             * set the stroke alpha 
416:             */
417:            public void setFillAlpha(float alpha) {
418:                state.fillAlpha = AlphaComposite.getInstance(
419:                        AlphaComposite.SRC_OVER, alpha);
420:            }
421:
422:            /**
423:             * Add an image observer
424:             */
425:            public void addObserver(ImageObserver observer) {
426:                if (observer == null) {
427:                    return;
428:                }
429:
430:                // update the new observer to the current state
431:                Image i = (Image) imageRef.get();
432:                if (rendererFinished()) {
433:                    // if we're finished, just send a finished notification, don't
434:                    // add to the list of observers
435:                    // System.out.println("Late notify");
436:                    observer.imageUpdate(i, ImageObserver.ALLBITS, 0, 0,
437:                            imageinfo.width, imageinfo.height);
438:                    return;
439:                } else {
440:                    // if we're not yet finished, add to the list of observers and
441:                    // notify of the current dirty region
442:                    synchronized (observers) {
443:                        observers.add(observer);
444:                    }
445:
446:                    if (globalDirtyRegion != null) {
447:                        observer.imageUpdate(i, ImageObserver.SOMEBITS,
448:                                (int) globalDirtyRegion.getMinX(),
449:                                (int) globalDirtyRegion.getMinY(),
450:                                (int) globalDirtyRegion.getWidth(),
451:                                (int) globalDirtyRegion.getHeight());
452:                    }
453:                }
454:            }
455:
456:            /**
457:             * Remove an image observer
458:             */
459:            public void removeObserver(ImageObserver observer) {
460:                synchronized (observers) {
461:                    observers.remove(observer);
462:                }
463:            }
464:
465:            /** 
466:             * Set the last shape drawn
467:             */
468:            public void setLastShape(GeneralPath shape) {
469:                this .lastShape = shape;
470:            }
471:
472:            /**
473:             * Get the last shape drawn
474:             */
475:            public GeneralPath getLastShape() {
476:                return lastShape;
477:            }
478:
479:            /**
480:             * Setup rendering.  Called before iteration begins
481:             */
482:            @Override
483:            public void setup() {
484:                Graphics2D graphics = null;
485:
486:                if (imageRef != null) {
487:                    BufferedImage bi = (BufferedImage) imageRef.get();
488:                    if (bi != null) {
489:                        graphics = bi.createGraphics();
490:                    }
491:                } else {
492:                    graphics = g;
493:                }
494:
495:                if (graphics != null) {
496:                    setupRendering(graphics);
497:                }
498:            }
499:
500:            /**
501:             * Draws the next command in the PDFPage to the buffered image.
502:             * The image will be notified about changes no less than every
503:             * UPDATE_DURATION milliseconds.
504:             *
505:             * @return <ul><li>Watchable.RUNNING when there are commands to be processed
506:             *             <li>Watchable.NEEDS_DATA when there are no commands to be
507:             *                 processed, but the page is not yet complete
508:             *             <li>Watchable.COMPLETED when the page is done and all
509:             *                 the commands have been processed
510:             *             <li>Watchable.STOPPED if the image we are rendering into
511:             *                 has gone away
512:             *         </ul> 
513:             */
514:            public int iterate() throws Exception {
515:                // make sure we have a page to render
516:                if (page == null) {
517:                    return Watchable.COMPLETED;
518:                }
519:
520:                // check if this renderer is based on a weak reference to a graphics
521:                // object.  If it is, and the graphics is no longer valid, then just quit
522:                BufferedImage bi = null;
523:                if (imageRef != null) {
524:                    bi = (BufferedImage) imageRef.get();
525:                    if (bi == null) {
526:                        System.out.println("Image went away.  Stopping");
527:                        return Watchable.STOPPED;
528:                    }
529:
530:                    g = (Graphics2D) bi.createGraphics();
531:                }
532:
533:                // check if there are any commands to parse.  If there aren't,
534:                // just return, but check if we'return really finished or not
535:                if (currentCommand >= page.getCommandCount()) {
536:                    if (page.isFinished()) {
537:                        return Watchable.COMPLETED;
538:                    } else {
539:                        return Watchable.NEEDS_DATA;
540:                    }
541:                }
542:
543:                // find the current command
544:                PDFCmd cmd = page.getCommand(currentCommand++);
545:                if (cmd == null) {
546:                    // uh oh.  Synchronization problem!
547:                    throw new PDFParseException("Command not found!");
548:                }
549:
550:                // execute the command
551:                Rectangle2D dirtyRegion = cmd.execute(this );
552:
553:                // append to the global dirty region
554:                globalDirtyRegion = addDirtyRegion(dirtyRegion,
555:                        globalDirtyRegion);
556:                unupdatedRegion = addDirtyRegion(dirtyRegion, unupdatedRegion);
557:
558:                long now = System.currentTimeMillis();
559:                if (now > then || rendererFinished()) {
560:                    // now tell any observers, so they can repaint
561:                    notifyObservers(bi, unupdatedRegion);
562:                    unupdatedRegion = null;
563:                    then = now + UPDATE_DURATION;
564:                }
565:
566:                // if we are based on a reference to a graphics, don't hold on to it
567:                // since that will prevent the image from being collected.
568:                if (imageRef != null) {
569:                    g = null;
570:                }
571:
572:                // if we need to stop, it will be caught at the start of the next
573:                // iteration.
574:                return Watchable.RUNNING;
575:            }
576:
577:            /**
578:             * Called when iteration has stopped
579:             */
580:            @Override
581:            public void cleanup() {
582:                page = null;
583:                state = null;
584:                stack = null;
585:                globalDirtyRegion = null;
586:                lastShape = null;
587:
588:                observers.clear();
589:
590:                // keep around the image ref and image info for use in
591:                // late addObserver() call
592:            }
593:
594:            /**
595:             * Append a rectangle to the total dirty region of this shape
596:             */
597:            private Rectangle2D addDirtyRegion(Rectangle2D region,
598:                    Rectangle2D glob) {
599:                if (region == null) {
600:                    return glob;
601:                } else if (glob == null) {
602:                    return region;
603:                } else {
604:                    Rectangle2D.union(glob, region, glob);
605:                    return glob;
606:                }
607:            }
608:
609:            /**
610:             * Determine if we are finished
611:             */
612:            private boolean rendererFinished() {
613:                if (page == null) {
614:                    return true;
615:                }
616:
617:                return (page.isFinished() && currentCommand == page
618:                        .getCommandCount());
619:            }
620:
621:            /**
622:             * Notify the observer that a region of the image has changed
623:             */
624:            private void notifyObservers(BufferedImage bi, Rectangle2D region) {
625:                if (bi == null) {
626:                    return;
627:                }
628:
629:                int startx, starty, width, height;
630:                int flags = 0;
631:
632:                // don't do anything if nothing is there or no one is listening
633:                if ((region == null && !rendererFinished())
634:                        || observers == null || observers.size() == 0) {
635:                    return;
636:                }
637:
638:                if (region != null) {
639:                    // get the image data for the total dirty region
640:                    startx = (int) Math.floor(region.getMinX());
641:                    starty = (int) Math.floor(region.getMinY());
642:                    width = (int) Math.ceil(region.getWidth());
643:                    height = (int) Math.ceil(region.getHeight());
644:
645:                    // sometimes width or height is negative.  Grrr...
646:                    if (width < 0) {
647:                        startx += width;
648:                        width = -width;
649:                    }
650:                    if (height < 0) {
651:                        starty += height;
652:                        height = -height;
653:                    }
654:
655:                    flags = 0;
656:                } else {
657:                    startx = 0;
658:                    starty = 0;
659:                    width = imageinfo.width;
660:                    height = imageinfo.height;
661:                }
662:                if (rendererFinished()) {
663:                    flags |= ImageObserver.ALLBITS;
664:                    // forget about the Graphics -- allows the image to be
665:                    // garbage collected.
666:                    g = null;
667:                } else {
668:                    flags |= ImageObserver.SOMEBITS;
669:                }
670:
671:                synchronized (observers) {
672:                    for (Iterator i = observers.iterator(); i.hasNext();) {
673:                        ImageObserver observer = (ImageObserver) i.next();
674:
675:                        boolean result = observer.imageUpdate(bi, flags,
676:                                startx, starty, width, height);
677:
678:                        // if result is false, the observer no longer wants to 
679:                        // be notified of changes
680:                        if (!result) {
681:                            i.remove();
682:                        }
683:                    }
684:                }
685:            }
686:
687:            /**
688:             * Convert an image mask into an image by painting over any pixels
689:             * that have a value in the image with the current paint
690:             */
691:            private BufferedImage getMaskedImage(BufferedImage bi) {
692:                // get the color of the current paint
693:                Color col = (Color) state.fillPaint.getPaint();
694:
695:                // format as 8 bits each of ARGB
696:                int paintColor = col.getAlpha() << 24;
697:                paintColor |= col.getRed() << 16;
698:                paintColor |= col.getGreen() << 8;
699:                paintColor |= col.getBlue();
700:
701:                // transparent (alpha = 1)
702:                int noColor = 0;
703:
704:                // get the coordinates of the source image
705:                int startX = bi.getMinX();
706:                int startY = bi.getMinY();
707:                int width = bi.getWidth();
708:                int height = bi.getHeight();
709:
710:                // create a destion image of the same size
711:                BufferedImage dstImage = new BufferedImage(width, height,
712:                        BufferedImage.TYPE_INT_ARGB);
713:
714:                // copy the pixels row by row
715:                for (int i = 0; i < height; i++) {
716:                    int[] srcPixels = new int[width];
717:                    int[] dstPixels = new int[srcPixels.length];
718:
719:                    // read a row of pixels from the source
720:                    bi.getRGB(startX, startY + i, width, 1, srcPixels, 0,
721:                            height);
722:
723:                    // figure out which ones should get painted
724:                    for (int j = 0; j < srcPixels.length; j++) {
725:                        if (srcPixels[j] == 0xff000000) {
726:                            dstPixels[j] = paintColor;
727:                        } else {
728:                            dstPixels[j] = noColor;
729:                        }
730:                    }
731:
732:                    // write the destination image
733:                    dstImage.setRGB(startX, startY + i, width, 1, dstPixels, 0,
734:                            height);
735:                }
736:
737:                return dstImage;
738:            }
739:
740:            class GraphicsState implements  Cloneable {
741:                /** the clip region */
742:                Shape cliprgn;
743:
744:                /** the current stroke */
745:                BasicStroke stroke;
746:
747:                /** the current paint for drawing strokes */
748:                PDFPaint strokePaint;
749:
750:                /** the current paint for filling shapes */
751:                PDFPaint fillPaint;
752:
753:                /** the current compositing alpha for stroking */
754:                AlphaComposite strokeAlpha;
755:
756:                /** the current compositing alpha for filling */
757:                AlphaComposite fillAlpha;
758:
759:                /** the current transform */
760:                AffineTransform xform;
761:
762:                /** Clone this Graphics state.
763:                 *
764:                 * Note that cliprgn is not cloned.  It must be set manually from
765:                 * the current graphics object's clip
766:                 */
767:                @Override
768:                public Object clone() {
769:                    GraphicsState cState = new GraphicsState();
770:                    cState.cliprgn = null;
771:
772:                    // copy immutable fields
773:                    cState.strokePaint = strokePaint;
774:                    cState.fillPaint = fillPaint;
775:                    cState.strokeAlpha = strokeAlpha;
776:                    cState.fillAlpha = fillAlpha;
777:
778:                    // clone mutable fields
779:                    cState.stroke = new BasicStroke(stroke.getLineWidth(),
780:                            stroke.getEndCap(), stroke.getLineJoin(), stroke
781:                                    .getMiterLimit(), stroke.getDashArray(),
782:                            stroke.getDashPhase());
783:                    cState.xform = (AffineTransform) xform.clone();
784:
785:                    return cState;
786:                }
787:            }
788:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.