KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > it > stefanochizzolini > clown > documents > Page


1 /*
2   Copyright 2006,2007 Stefano Chizzolini. http://clown.stefanochizzolini.it
3
4   Contributors:
5     * Stefano Chizzolini (original code developer, info@stefanochizzolini.it):
6       contributed code is Copyright 2006,2007 by Stefano Chizzolini.
7
8   This file should be part of the source code distribution of "PDF Clown library"
9   (the Program): see the accompanying README files for more info.
10
11   This Program is free software; you can redistribute it and/or modify it under
12   the terms of the GNU General Public License as published by the Free Software
13   Foundation; either version 2 of the License, or (at your option) any later version.
14
15   This Program is distributed in the hope that it will be useful, but WITHOUT ANY
16   WARRANTY, either expressed or implied; without even the implied warranty of
17   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the License for more details.
18
19   You should have received a copy of the GNU General Public License along with this
20   Program (see README files); if not, go to the GNU website (http://www.gnu.org/).
21
22   Redistribution and use, with or without modification, are permitted provided that such
23   redistributions retain the above copyright notice, license and disclaimer, along with
24   this list of conditions.
25 */

26
27 package it.stefanochizzolini.clown.documents;
28
29 import it.stefanochizzolini.clown.documents.contents.ContentStreams;
30 import it.stefanochizzolini.clown.documents.contents.IContentStreamContext;
31 import it.stefanochizzolini.clown.documents.contents.Resources;
32 import it.stefanochizzolini.clown.files.File;
33 import it.stefanochizzolini.clown.objects.IPdfNumber;
34 import it.stefanochizzolini.clown.objects.PdfArray;
35 import it.stefanochizzolini.clown.objects.PdfDictionary;
36 import it.stefanochizzolini.clown.objects.PdfDirectObject;
37 import it.stefanochizzolini.clown.objects.PdfInteger;
38 import it.stefanochizzolini.clown.objects.PdfName;
39 import it.stefanochizzolini.clown.objects.PdfObjectWrapper;
40 import it.stefanochizzolini.clown.objects.PdfReference;
41 import it.stefanochizzolini.clown.util.NotImplementedException;
42
43 import java.util.Map JavaDoc;
44
45 /**
46   Document page [PDF:1.6:3.6.2].
47 */

48 public class Page
49   extends PdfObjectWrapper<PdfDictionary>
50   implements IContentStreamContext
51 {
52   /*
53     NOTE: Inheritable attributes are NOT early-collected, as they are NOT part
54     of the explicit representation of a page. They are retrieved everytime
55     clients call.
56   */

57   // <class>
58
// <static>
59
// <interface>
60
// <public>
61
public static Page wrap(
62     PdfReference reference
63     )
64   {return new Page(reference);}
65   // </public>
66
// </interface>
67
// </static>
68

69   // <dynamic>
70
// <constructors>
71
public Page(
72     Document context
73     )
74   {
75     super(
76       context.getFile(),
77       new PdfDictionary(
78         new PdfName[]
79         {
80           PdfName.Type,
81           PdfName.MediaBox,
82           PdfName.Contents,
83           PdfName.Resources
84         },
85         new PdfDirectObject[]
86         {
87           PdfName.Page,
88           context.ensureMediaBox(),
89           new PdfArray(),
90           context.getResources().getBaseObject()
91         }
92         )
93       );
94   }
95
96   /**
97     <h3>Remarks</h3>
98     <p>For internal use only.</p>
99   */

100   public Page(
101     PdfDirectObject baseObject
102     )
103   {
104     super(
105       baseObject,
106       null // NO container. NOTE: this is a simplification (the spec [PDF:1.6] doesn't apparently prescribe the use of an indirect object for page dictionary, whilst the general practice is as such. If an exception occur, you'll need to specify the proper container).
107
);
108   }
109   // </constructors>
110

111   // <interface>
112
// <public>
113
public Object JavaDoc clone(
114     Document context
115     )
116   {
117     /*
118       NOTE: We cannot just delegate the cloning to the base object, as it would
119       involve some unwanted objects like those in 'Parent' and 'Annots' entries that may
120       cause infinite loops (due to circular references) and may include exceeding contents
121       (due to copy propagations to the whole page-tree which this page belongs to).
122       TODO: 'Annots' entry must be finely treated to include any non-circular reference.
123     */

124     // TODO:IMPL deal with inheritable attributes!!!
125

126     File contextFile = context.getFile();
127     PdfDictionary clone = new PdfDictionary(getBaseDataObject().size());
128     for(
129       Map.Entry JavaDoc<PdfName,PdfDirectObject> entry : getBaseDataObject().entrySet()
130       )
131     {
132       PdfName key = entry.getKey();
133       // Is the entry unwanted?
134
if(key.equals(PdfName.Parent)
135         || key.equals(PdfName.Annots))
136         continue;
137
138       // Insert the clone of the entry into the clone of the page dictionary!
139
clone.put(
140         key,
141         (PdfDirectObject)entry.getValue().clone(contextFile)
142         );
143     }
144
145     return new Page(
146       contextFile.getIndirectObjects().add(clone).getReference()
147       );
148   }
149
150   /**
151     Gets the content streams associated to the page.
152   */

153   public ContentStreams getContents(
154     )
155   {
156     return new ContentStreams(
157       getBaseDataObject().get(PdfName.Contents),
158       this
159       );
160   }
161
162   public double getHeight(
163     )
164   {
165     return ((IPdfNumber)
166       ((PdfArray)
167         File.resolve(
168           ensureEntry(PdfName.MediaBox)
169           )
170         ).get(3)
171       ).getNumberValue();
172   }
173
174   public void setHeight(
175     double value
176     )
177   {
178     throw new NotImplementedException("When page height is about to be modified, you need to verify that the change will affect just the mediaBox of this page; so, if such a mediaBox is implicit (inherited), it MUST be cloned and explicitly assigned to this page in order to apply customizations.");
179   }
180
181   /**
182     Gets the index of the page.
183     <h3>Remarks</h3>
184     <p>The page index is not an explicit datum, therefore it needs to be
185     inferred from the position of the page object inside the page tree,
186     requiring a significant amount of computation: invoke it sparingly!</p>
187   */

188   public int getIndex(
189     )
190   {
191     /*
192       NOTE: We'll scan sequentially each page-tree level above this page object
193       collecting page counts. At each level we'll scan the kids array from the
194       lower-indexed item to the ancestor of this page object at that level.
195     */

196     PdfReference ancestorKidReference = (PdfReference)getBaseObject();
197     PdfReference parentReference = (PdfReference)getBaseDataObject().get(PdfName.Parent);
198     PdfDictionary parent = (PdfDictionary)File.resolve(parentReference);
199     PdfArray kids = (PdfArray)File.resolve(parent.get(PdfName.Kids));
200     int index = 0;
201     for(
202       int i = 0;
203       true;
204       i++
205       )
206     {
207       PdfReference kidReference = (PdfReference)kids.get(i);
208       // Is the current-level counting complete?
209
// NOTE: It's complete when it reaches the ancestor at the current level.
210
if(kidReference.equals(ancestorKidReference)) // Ancestor node.
211
{
212         // Does the current level correspond to the page-tree root node?
213
if(!parent.containsKey(PdfName.Parent))
214         {
215           // We reached the top: counting's finished.
216
return index;
217         }
218         // Set the ancestor at the next level!
219
ancestorKidReference = parentReference;
220         // Move up one level!
221
parentReference = (PdfReference)parent.get(PdfName.Parent);
222         parent = (PdfDictionary)File.resolve(parentReference);
223         kids = (PdfArray)File.resolve(parent.get(PdfName.Kids));
224         i = -1;
225       }
226       else // Intermediate node.
227
{
228         PdfDictionary kid = (PdfDictionary)File.resolve(kidReference);
229         if(kid.get(PdfName.Type).equals(PdfName.Page))
230           index++;
231         else
232           index += ((PdfInteger)kid.get(PdfName.Count)).getValue();
233       }
234     }
235   }
236
237   /**
238     Gets the next page.
239     <h3>Remarks</h3>
240     <p>Relative positions are not explicit data, so they need a substantial
241     amount of computation: invoke it sparingly!</p>
242   */

243   public Page getNext(
244     )
245   {return getPage(+1);}
246
247   /**
248     Gets the previous page.
249     <h3>Remarks</h3>
250     <p>Relative positions are not explicit data, so they need a substantial amount of
251     computation: invoke it sparingly!</p>
252   */

253   public Page getPrevious(
254     )
255   {return getPage(-1);}
256
257   /**
258     Gets a page at a position relative to this one.
259     <h3>Remarks</h3>
260     <p>Relative positions are not explicit data, so they need a substantial amount of
261     computation and should be used sparingly.</p>
262   */

263   public Page getPage(
264     int offset
265     )
266   {
267     if(offset == 0)
268       return this;
269     /*TODO:IMPL This is NOT good: it's needed an optimized algorithm in order to
270     avoid double scans (Index evaluation + page search): we need that index and
271     search be evaluated incrementally together! It should get the
272     pdfreference of the sought page and then use Page.wrap(PdfReference)!!!*/

273     return getDocument().getPages().get(getIndex() + offset);
274   }
275
276   /**
277     Gets the resources associated to the page.
278   */

279   public Resources getResources(
280     )
281   {
282     return new Resources(
283       ensureEntry(PdfName.Resources),
284       ((PdfReference)getBaseObject()).getIndirectObject()
285       );
286   }
287
288   public double getWidth(
289     )
290   {
291     return ((IPdfNumber)
292       ((PdfArray)
293         File.resolve(
294           ensureEntry(PdfName.MediaBox)
295           )
296         ).get(2)
297       ).getNumberValue();
298   }
299
300   public void setWidth(
301     double value
302     )
303   {
304     throw new NotImplementedException("When page width is about to be modified, you need to verify that the change will affect just the mediaBox of this page; so, if such a mediaBox is implicit (inherited), it MUST be cloned and explicitly assigned to this page in order to apply customizations.");
305   }
306   // </public>
307

308   // <protected>
309
protected PdfDirectObject ensureEntry(
310     PdfName key
311     )
312   {
313     PdfDirectObject entry = getBaseDataObject().get(key);
314     if(entry == null)
315       throw new NotImplementedException("When an entry (" + key + ") is implicit, it MUST be retrieve as inherited attribute from upstream nodes (move upwards through the Parent attribute nodes!).");
316
317     return entry;
318   }
319   // </protected>
320

321   // <internal>
322
// <IContentStreamContext>
323
/**
324     <h3>Remarks</h3>
325     <p>For internal use only.</p>
326   */

327   public PdfArray getContextBox(
328     )
329   {
330     return (PdfArray)File.resolve(ensureEntry(PdfName.MediaBox));
331   }
332
333   /**
334     <h3>Remarks</h3>
335     <p>For internal use only.</p>
336   */

337   public PdfDictionary getContextResources(
338     )
339   {
340     return (PdfDictionary)File.resolve(ensureEntry(PdfName.Resources));
341   }
342   // </IContentStreamContext>
343
// </internal>
344
// </interface>
345
// </dynamic>
346
// </class>
347
}
Popular Tags