KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > pdfbox > pdmodel > PDPage


1 /**
2  * Copyright (c) 2003-2006, www.pdfbox.org
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  * this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright notice,
11  * this list of conditions and the following disclaimer in the documentation
12  * and/or other materials provided with the distribution.
13  * 3. Neither the name of pdfbox; nor the names of its
14  * contributors may be used to endorse or promote products derived from this
15  * software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
24  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  * http://www.pdfbox.org
29  *
30  */

31 package org.pdfbox.pdmodel;
32
33 import org.pdfbox.cos.COSArray;
34 import org.pdfbox.cos.COSBase;
35 import org.pdfbox.cos.COSDictionary;
36 import org.pdfbox.cos.COSInteger;
37 import org.pdfbox.cos.COSName;
38 import org.pdfbox.cos.COSNumber;
39 import org.pdfbox.cos.COSStream;
40
41 import org.pdfbox.pdfviewer.PageDrawer;
42 import org.pdfbox.pdmodel.common.COSArrayList;
43 import org.pdfbox.pdmodel.common.COSObjectable;
44 import org.pdfbox.pdmodel.common.PDMetadata;
45 import org.pdfbox.pdmodel.common.PDRectangle;
46 import org.pdfbox.pdmodel.common.PDStream;
47 import org.pdfbox.pdmodel.interactive.action.PDPageAdditionalActions;
48 import org.pdfbox.pdmodel.interactive.annotation.PDAnnotation;
49 import org.pdfbox.pdmodel.interactive.pagenavigation.PDThreadBead;
50
51 import java.awt.Color JavaDoc;
52 import java.awt.Dimension JavaDoc;
53 import java.awt.Graphics JavaDoc;
54 import java.awt.Graphics2D JavaDoc;
55 import java.awt.image.BufferedImage JavaDoc;
56 import java.awt.print.PageFormat JavaDoc;
57 import java.awt.print.Printable JavaDoc;
58 import java.awt.print.PrinterException JavaDoc;
59 import java.awt.print.PrinterIOException JavaDoc;
60 import java.io.IOException JavaDoc;
61
62 import java.util.ArrayList JavaDoc;
63 import java.util.Calendar JavaDoc;
64 import java.util.GregorianCalendar JavaDoc;
65 import java.util.List JavaDoc;
66
67 /**
68  * This represents a single page in a PDF document.
69  *
70  * @author <a HREF="mailto:ben@benlitchfield.com">Ben Litchfield</a>
71  * @version $Revision: 1.28 $
72  */

73 public class PDPage implements COSObjectable, Printable JavaDoc
74 {
75     private COSDictionary page;
76     
77     /**
78      * A page size of LETTER or 8.5x11.
79      */

80     public static final PDRectangle PAGE_SIZE_LETTER = new PDRectangle( 612, 792 );
81     
82
83     /**
84      * Creates a new instance of PDPage with a size of 8.5x11.
85      */

86     public PDPage()
87     {
88         page = new COSDictionary();
89         page.setItem( COSName.TYPE, COSName.PAGE );
90         setMediaBox( PAGE_SIZE_LETTER );
91     }
92
93     /**
94      * Creates a new instance of PDPage.
95      *
96      * @param pageDic The existing page dictionary.
97      */

98     public PDPage( COSDictionary pageDic )
99     {
100         page = pageDic;
101     }
102
103     /**
104      * Convert this standard java object to a COS object.
105      *
106      * @return The cos object that matches this Java object.
107      */

108     public COSBase getCOSObject()
109     {
110         return page;
111     }
112
113     /**
114      * This will get the underlying dictionary that this class acts on.
115      *
116      * @return The underlying dictionary for this class.
117      */

118     public COSDictionary getCOSDictionary()
119     {
120         return page;
121     }
122
123
124     /**
125      * This is the parent page node. The parent is a required element of the
126      * page. This will be null until this page is added to the document.
127      *
128      * @return The parent to this page.
129      */

130     public PDPageNode getParent()
131     {
132         PDPageNode parent = null;
133         COSDictionary parentDic = (COSDictionary)page.getDictionaryObject( "Parent", "P" );
134         if( parentDic != null )
135         {
136             parent = new PDPageNode( parentDic );
137         }
138         return parent;
139     }
140
141     /**
142      * This will set the parent of this page.
143      *
144      * @param parent The parent to this page node.
145      */

146     public void setParent( PDPageNode parent )
147     {
148         page.setItem( COSName.PARENT, parent.getDictionary() );
149     }
150
151     /**
152      * This will update the last modified time for the page object.
153      */

154     public void updateLastModified()
155     {
156         page.setDate( "LastModified", new GregorianCalendar JavaDoc() );
157     }
158
159     /**
160      * This will get the date that the content stream was last modified. This
161      * may return null.
162      *
163      * @return The date the content stream was last modified.
164      *
165      * @throws IOException If there is an error accessing the date information.
166      */

167     public Calendar JavaDoc getLastModified() throws IOException JavaDoc
168     {
169         return page.getDate( "LastModified" );
170     }
171
172     /**
173      * This will get the resources at this page and not look up the hierarchy.
174      * This attribute is inheritable, and findResources() should probably used.
175      * This will return null if no resources are available at this level.
176      *
177      * @return The resources at this level in the hierarchy.
178      */

179     public PDResources getResources()
180     {
181         PDResources retval = null;
182         COSDictionary resources = (COSDictionary)page.getDictionaryObject( COSName.RESOURCES );
183         if( resources != null )
184         {
185             retval = new PDResources( resources );
186         }
187         return retval;
188     }
189
190     /**
191      * This will find the resources for this page by looking up the hierarchy until
192      * it finds them.
193      *
194      * @return The resources at this level in the hierarchy.
195      */

196     public PDResources findResources()
197     {
198         PDResources retval = getResources();
199         PDPageNode parent = getParent();
200         if( retval == null && parent != null )
201         {
202             retval = parent.findResources();
203         }
204         return retval;
205     }
206
207     /**
208      * This will set the resources for this page.
209      *
210      * @param resources The new resources for this page.
211      */

212     public void setResources( PDResources resources )
213     {
214         page.setItem( COSName.RESOURCES, resources );
215     }
216
217     /**
218      * A rectangle, expressed
219      * in default user space units, defining the boundaries of the physical
220      * medium on which the page is intended to be displayed or printed
221      *
222      * This will get the MediaBox at this page and not look up the hierarchy.
223      * This attribute is inheritable, and findMediaBox() should probably used.
224      * This will return null if no MediaBox are available at this level.
225      *
226      * @return The MediaBox at this level in the hierarchy.
227      */

228     public PDRectangle getMediaBox()
229     {
230         PDRectangle retval = null;
231         COSArray array = (COSArray)page.getDictionaryObject( COSName.MEDIA_BOX );
232         if( array != null )
233         {
234             retval = new PDRectangle( array );
235         }
236         return retval;
237     }
238
239     /**
240      * This will find the MediaBox for this page by looking up the hierarchy until
241      * it finds them.
242      *
243      * @return The MediaBox at this level in the hierarchy.
244      */

245     public PDRectangle findMediaBox()
246     {
247         PDRectangle retval = getMediaBox();
248         PDPageNode parent = getParent();
249         if( retval == null && parent != null )
250         {
251             retval = parent.findMediaBox();
252         }
253         return retval;
254     }
255
256     /**
257      * This will set the mediaBox for this page.
258      *
259      * @param mediaBox The new mediaBox for this page.
260      */

261     public void setMediaBox( PDRectangle mediaBox )
262     {
263         if( mediaBox == null )
264         {
265             page.removeItem( COSName.MEDIA_BOX );
266         }
267         else
268         {
269             page.setItem( COSName.MEDIA_BOX, mediaBox.getCOSArray() );
270         }
271     }
272
273     /**
274      * A rectangle, expressed in default user space units,
275      * defining the visible region of default user space. When the page is displayed
276      * or printed, its contents are to be clipped (cropped) to this rectangle
277      * and then imposed on the output medium in some implementationdefined
278      * manner
279      *
280      * This will get the CropBox at this page and not look up the hierarchy.
281      * This attribute is inheritable, and findCropBox() should probably used.
282      * This will return null if no CropBox is available at this level.
283      *
284      * @return The CropBox at this level in the hierarchy.
285      */

286     public PDRectangle getCropBox()
287     {
288         PDRectangle retval = null;
289         COSArray array = (COSArray)page.getDictionaryObject( COSName.CROP_BOX);
290         if( array != null )
291         {
292             retval = new PDRectangle( array );
293         }
294         return retval;
295     }
296
297     /**
298      * This will find the CropBox for this page by looking up the hierarchy until
299      * it finds them.
300      *
301      * @return The CropBox at this level in the hierarchy.
302      */

303     public PDRectangle findCropBox()
304     {
305         PDRectangle retval = getCropBox();
306         PDPageNode parent = getParent();
307         if( retval == null && parent != null )
308         {
309             retval = findParentCropBox( parent );
310         }
311
312         //default value for cropbox is the media box
313
if( retval == null )
314         {
315             retval = findMediaBox();
316         }
317         return retval;
318     }
319
320     /**
321      * This will search for a crop box in the parent and return null if it is not
322      * found. It will NOT default to the media box if it cannot be found.
323      *
324      * @param node The node
325      */

326     private PDRectangle findParentCropBox( PDPageNode node )
327     {
328         PDRectangle rect = node.getCropBox();
329         PDPageNode parent = node.getParent();
330         if( rect == null && parent != null )
331         {
332             rect = findParentCropBox( parent );
333         }
334         return rect;
335     }
336
337     /**
338      * This will set the CropBox for this page.
339      *
340      * @param cropBox The new CropBox for this page.
341      */

342     public void setCropBox( PDRectangle cropBox )
343     {
344         if( cropBox == null )
345         {
346             page.removeItem( COSName.CROP_BOX );
347         }
348         else
349         {
350             page.setItem( COSName.CROP_BOX, cropBox.getCOSArray() );
351         }
352     }
353
354     /**
355      * A rectangle, expressed in default user space units, defining
356      * the region to which the contents of the page should be clipped
357      * when output in a production environment. The default is the CropBox.
358      *
359      * @return The BleedBox attribute.
360      */

361     public PDRectangle getBleedBox()
362     {
363         PDRectangle retval = null;
364         COSArray array = (COSArray)page.getDictionaryObject( COSName.BLEED_BOX );
365         if( array != null )
366         {
367             retval = new PDRectangle( array );
368         }
369         else
370         {
371             retval = findCropBox();
372         }
373         return retval;
374     }
375
376     /**
377      * This will set the BleedBox for this page.
378      *
379      * @param bleedBox The new BleedBox for this page.
380      */

381     public void setBleedBox( PDRectangle bleedBox )
382     {
383         if( bleedBox == null )
384         {
385             page.removeItem( COSName.BLEED_BOX );
386         }
387         else
388         {
389             page.setItem( COSName.BLEED_BOX, bleedBox.getCOSArray() );
390         }
391     }
392
393     /**
394      * A rectangle, expressed in default user space units, defining
395      * the intended dimensions of the finished page after trimming.
396      * The default is the CropBox.
397      *
398      * @return The TrimBox attribute.
399      */

400     public PDRectangle getTrimBox()
401     {
402         PDRectangle retval = null;
403         COSArray array = (COSArray)page.getDictionaryObject( COSName.TRIM_BOX );
404         if( array != null )
405         {
406             retval = new PDRectangle( array );
407         }
408         else
409         {
410             retval = findCropBox();
411         }
412         return retval;
413     }
414
415     /**
416      * This will set the TrimBox for this page.
417      *
418      * @param trimBox The new TrimBox for this page.
419      */

420     public void setTrimBox( PDRectangle trimBox )
421     {
422         if( trimBox == null )
423         {
424             page.removeItem( COSName.TRIM_BOX );
425         }
426         else
427         {
428             page.setItem( COSName.TRIM_BOX, trimBox.getCOSArray() );
429         }
430     }
431
432     /**
433      * A rectangle, expressed in default user space units, defining
434      * the extent of the page's meaningful content (including potential
435      * white space) as intended by the page's creator The default isthe CropBox.
436      *
437      * @return The ArtBox attribute.
438      */

439     public PDRectangle getArtBox()
440     {
441         PDRectangle retval = null;
442         COSArray array = (COSArray)page.getDictionaryObject( COSName.ART_BOX );
443         if( array != null )
444         {
445             retval = new PDRectangle( array );
446         }
447         else
448         {
449             retval = findCropBox();
450         }
451         return retval;
452     }
453
454     /**
455      * This will set the ArtBox for this page.
456      *
457      * @param artBox The new ArtBox for this page.
458      */

459     public void setArtBox( PDRectangle artBox )
460     {
461         if( artBox == null )
462         {
463             page.removeItem( COSName.ART_BOX );
464         }
465         else
466         {
467             page.setItem( COSName.ART_BOX, artBox.getCOSArray() );
468         }
469     }
470
471
472     //todo BoxColorInfo
473
//todo Contents
474

475     /**
476      * A value representing the rotation. This will be null if not set at this level
477      * The number of degrees by which the page should
478      * be rotated clockwise when displayed or printed. The value must be a multiple
479      * of 90.
480      *
481      * This will get the rotation at this page and not look up the hierarchy.
482      * This attribute is inheritable, and findRotation() should probably used.
483      * This will return null if no rotation is available at this level.
484      *
485      * @return The rotation at this level in the hierarchy.
486      */

487     public Integer JavaDoc getRotation()
488     {
489         Integer JavaDoc retval = null;
490         COSNumber value = (COSNumber)page.getDictionaryObject( COSName.ROTATE );
491         if( value != null )
492         {
493             retval = new Integer JavaDoc( value.intValue() );
494         }
495         return retval;
496     }
497
498     /**
499      * This will find the rotation for this page by looking up the hierarchy until
500      * it finds them.
501      *
502      * @return The rotation at this level in the hierarchy.
503      */

504     public int findRotation()
505     {
506         int retval = 0;
507         Integer JavaDoc rotation = getRotation();
508         if( rotation != null )
509         {
510             retval = rotation.intValue();
511         }
512         else
513         {
514             PDPageNode parent = getParent();
515             if( parent != null )
516             {
517                 retval = parent.findRotation();
518             }
519         }
520
521         return retval;
522     }
523
524     /**
525      * This will set the rotation for this page.
526      *
527      * @param rotation The new rotation for this page.
528      */

529     public void setRotation( int rotation )
530     {
531         page.setItem( COSName.ROTATE, new COSInteger( rotation ) );
532     }
533
534     /**
535      * This will get the contents of the PDF Page, in the case that the contents
536      * of the page is an array then then the entire array of streams will be
537      * be wrapped and appear as a single stream.
538      *
539      * @return The page content stream.
540      *
541      * @throws IOException If there is an error obtaining the stream.
542      */

543     public PDStream getContents() throws IOException JavaDoc
544     {
545         return PDStream.createFromCOS( page.getDictionaryObject( COSName.CONTENTS ) );
546     }
547
548     /**
549      * This will set the contents of this page.
550      *
551      * @param contents The new contents of the page.
552      */

553     public void setContents( PDStream contents )
554     {
555         page.setItem( COSName.CONTENTS, contents );
556     }
557     
558     /**
559      * This will get a list of PDThreadBead objects, which are article threads in the
560      * document. This will return an empty list of there are no thread beads.
561      *
562      * @return A list of article threads on this page.
563      */

564     public List getThreadBeads()
565     {
566         COSArray beads = (COSArray)page.getDictionaryObject( COSName.B );
567         if( beads == null )
568         {
569             beads = new COSArray();
570         }
571         List pdObjects = new ArrayList();
572         for( int i=0; i<beads.size(); i++)
573         {
574             COSDictionary beadDic = (COSDictionary)beads.getObject( i );
575             PDThreadBead bead = null;
576             //in some cases the bead is null
577
if( beadDic != null )
578             {
579                 bead = new PDThreadBead( beadDic );
580             }
581             pdObjects.add( bead );
582         }
583         return new COSArrayList(pdObjects, beads);
584         
585     }
586     
587     /**
588      * This will set the list of thread beads.
589      *
590      * @param beads A list of PDThreadBead objects or null.
591      */

592     public void setThreadBeads( List beads )
593     {
594         page.setItem( COSName.B, COSArrayList.converterToCOSArray( beads ) );
595     }
596     
597     /**
598      * Get the metadata that is part of the document catalog. This will
599      * return null if there is no meta data for this object.
600      *
601      * @return The metadata for this object.
602      */

603     public PDMetadata getMetadata()
604     {
605         PDMetadata retval = null;
606         COSStream stream = (COSStream)page.getDictionaryObject( COSName.METADATA );
607         if( stream != null )
608         {
609             retval = new PDMetadata( stream );
610         }
611         return retval;
612     }
613     
614     /**
615      * Set the metadata for this object. This can be null.
616      *
617      * @param meta The meta data for this object.
618      */

619     public void setMetadata( PDMetadata meta )
620     {
621         page.setItem( COSName.METADATA, meta );
622     }
623     
624     /**
625      * Convert this page to an output image.
626      *
627      * @return A graphical representation of this page.
628      *
629      * @throws IOException If there is an error drawing to the image.
630      */

631     public BufferedImage JavaDoc convertToImage() throws IOException JavaDoc
632     {
633         int scaling = 2;
634         int rotation = findRotation();
635         PDRectangle mBox = findMediaBox();
636         int width = (int)(mBox.getWidth());//*2);
637
int height = (int)(mBox.getHeight());//*2);
638
if( rotation == 90 || rotation == 270 )
639         {
640             int tmp = width;
641             width = height;
642             height = tmp;
643         }
644         Dimension JavaDoc pageDimension = new Dimension JavaDoc( width, height );
645         
646         //note we are doing twice as many pixels because
647
//the default size is not really good resolution,
648
//so create an image that is twice the size
649
//and let the client scale it down.
650
BufferedImage JavaDoc retval =
651             new BufferedImage JavaDoc( width*scaling, height*scaling, BufferedImage.TYPE_BYTE_INDEXED );
652         Graphics2D JavaDoc graphics = (Graphics2D JavaDoc)retval.getGraphics();
653         graphics.setColor( Color.WHITE );
654         graphics.fillRect(0,0,width*scaling, height*scaling);
655         graphics.scale( scaling, scaling );
656         PageDrawer drawer = new PageDrawer();
657         drawer.drawPage( graphics, this, pageDimension );
658         
659         
660         return retval;
661     }
662     
663     /**
664      * Get the page actions.
665      *
666      * @return The Actions for this Page
667      */

668     public PDPageAdditionalActions getActions()
669     {
670         COSDictionary addAct = (COSDictionary) page.getDictionaryObject(COSName.AA);
671         if (addAct == null)
672         {
673             addAct = new COSDictionary();
674             page.setItem(COSName.AA, addAct);
675         }
676         return new PDPageAdditionalActions(addAct);
677     }
678     
679     /**
680      * Set the page actions.
681      *
682      * @param actions The actions for the page.
683      */

684     public void setActions( PDPageAdditionalActions actions )
685     {
686         page.setItem( COSName.AA, actions );
687     }
688     
689     /**
690      * This will return a list of the Annotations for this page.
691      *
692      * @return List of the PDAnnotation objects.
693      *
694      * @throws IOException If there is an error while creating the annotations.
695      */

696     public List getAnnotations() throws IOException JavaDoc
697     {
698         COSArrayList retval = null;
699         COSArray annots = (COSArray)page.getDictionaryObject(COSName.ANNOTS);
700         if (annots == null)
701         {
702             annots = new COSArray();
703             page.setItem(COSName.ANNOTS, annots);
704             retval = new COSArrayList(new ArrayList(), annots);
705         }
706         else
707         {
708             List actuals = new ArrayList();
709         
710             for (int i=0; i < annots.size(); i++)
711             {
712                 COSBase item = annots.getObject(i);
713                 actuals.add( PDAnnotation.createAnnotation( item ) );
714             }
715             retval = new COSArrayList(actuals, annots);
716         }
717         return retval;
718     }
719     
720     /**
721      * This will set the list of annotations.
722      *
723      * @param annots The new list of annotations.
724      */

725     public void setAnnotations( List annots )
726     {
727         page.setItem( COSName.ANNOTS, COSArrayList.converterToCOSArray( annots ) );
728     }
729     
730     /**
731      * {@inheritDoc}
732      */

733     public int print(Graphics JavaDoc graphics, PageFormat JavaDoc pageFormat, int pageIndex)
734         throws PrinterException JavaDoc
735     {
736         int retval = Printable.PAGE_EXISTS;
737         try
738         {
739             PageDrawer drawer = new PageDrawer();
740             PDRectangle pageSize = findMediaBox();
741             drawer.drawPage( graphics, this, pageSize.createDimension() );
742         }
743         catch( IOException JavaDoc io )
744         {
745             throw new PrinterIOException JavaDoc( io );
746         }
747         return retval;
748     }
749     
750     /**
751      * {@inheritDoc}
752      */

753     public boolean equals( Object JavaDoc other )
754     {
755         return other instanceof PDPage && ((PDPage)other).getCOSObject() == this.getCOSObject();
756     }
757     
758     /**
759      * {@inheritDoc}
760      */

761     public int hashCode()
762     {
763         return this.getCOSDictionary().hashCode();
764     }
765 }
Popular Tags