001: /*
002: Copyright © 2006,2007 Stefano Chizzolini. http://clown.stefanochizzolini.it
003:
004: Contributors:
005: * Stefano Chizzolini (original code developer, http://www.stefanochizzolini.it):
006: contributed code is Copyright © 2006,2007 by Stefano Chizzolini.
007:
008: This file should be part of the source code distribution of "PDF Clown library"
009: (the Program): see the accompanying README files for more info.
010:
011: This Program is free software; you can redistribute it and/or modify it under
012: the terms of the GNU General Public License as published by the Free Software
013: Foundation; either version 2 of the License, or (at your option) any later version.
014:
015: This Program is distributed in the hope that it will be useful, but WITHOUT ANY
016: WARRANTY, either expressed or implied; without even the implied warranty of
017: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the License for more details.
018:
019: You should have received a copy of the GNU General Public License along with this
020: Program (see README files); if not, go to the GNU website (http://www.gnu.org/).
021:
022: Redistribution and use, with or without modification, are permitted provided that such
023: redistributions retain the above copyright notice, license and disclaimer, along with
024: this list of conditions.
025: */
026:
027: package it.stefanochizzolini.clown.documents;
028:
029: import it.stefanochizzolini.clown.documents.contents.Resources;
030: import it.stefanochizzolini.clown.documents.interaction.ViewerPreferences;
031: import it.stefanochizzolini.clown.documents.interaction.navigation.document.Bookmarks;
032: import it.stefanochizzolini.clown.documents.interchange.metadata.Information;
033: import it.stefanochizzolini.clown.files.File;
034: import it.stefanochizzolini.clown.objects.IPdfNumber;
035: import it.stefanochizzolini.clown.objects.PdfArray;
036: import it.stefanochizzolini.clown.objects.PdfDictionary;
037: import it.stefanochizzolini.clown.objects.PdfDirectObject;
038: import it.stefanochizzolini.clown.objects.PdfInteger;
039: import it.stefanochizzolini.clown.objects.PdfName;
040: import it.stefanochizzolini.clown.objects.PdfObjectWrapper;
041: import it.stefanochizzolini.clown.objects.PdfReal;
042: import it.stefanochizzolini.clown.objects.PdfRectangle;
043: import it.stefanochizzolini.clown.objects.PdfReference;
044: import it.stefanochizzolini.clown.util.NotImplementedException;
045:
046: import java.awt.Dimension;
047: import java.awt.geom.Dimension2D;
048: import java.util.ArrayList;
049: import java.util.Collection;
050:
051: /**
052: PDF document [PDF:1.6:3.6.1].
053: @version 0.0.4, 07/19/07
054: */
055: public class Document extends PdfObjectWrapper<PdfDictionary> {
056: // <class>
057: // <dynamic>
058: // <fields>
059: /**
060: <h3>Remarks</h3>
061: <p>For internal use only.</p>
062: */
063: public java.util.Hashtable<PdfReference, Object> cache = new java.util.Hashtable<PdfReference, Object>();
064:
065: // </fields>
066:
067: // <constructors>
068: /**
069: <h3>Remarks</h3>
070: <p>For internal use only.</p>
071: */
072: public Document(File context) {
073: super (context, new PdfDictionary(
074: new PdfName[] { PdfName.Type },
075: new PdfDirectObject[] { PdfName.Catalog }) // Document catalog [PDF:1.6:3.6.1].
076: );
077:
078: /*
079: NOTE: Here is just the minimal initialization.
080: Any further customization is upon client's responsibility.
081: */
082: // Link the document to the file!
083: // NOTE: Attach a catalog reference to the file trailer.
084: context.getTrailer().put(PdfName.Root, getBaseObject());
085:
086: // Initialize the pages collection (page-tree root node)!
087: /*
088: NOTE: The page-tree root node is required [PDF:1.6:3.6.1].
089: */
090: setPages(new Pages(this ));
091: }
092:
093: /**
094: <h3>Remarks</h3>
095: <p>For internal use only.</p>
096: */
097: public Document(PdfDirectObject baseObject // Catalog.
098: ) {
099: super (baseObject, null // NO container (catalog MUST be an indirect object [PDF:1.6:3.4.4]).
100: );
101: }
102:
103: // </constructors>
104:
105: // <interface>
106: // <public>
107: @Override
108: public Document clone(Document context) {
109: throw new NotImplementedException();
110: }
111:
112: /**
113: Clones the object within this document context.
114: */
115: public Object contextualize(PdfObjectWrapper<?> object) {
116: if (object.getFile() == getFile())
117: return object;
118:
119: return object.clone(this );
120: }
121:
122: /**
123: Clones the collection's objects within this document context.
124: */
125: public Collection<? extends PdfObjectWrapper<?>> contextualize(
126: Collection<? extends PdfObjectWrapper<?>> objects) {
127: ArrayList<PdfObjectWrapper<?>> contextualizedObjects = new ArrayList<PdfObjectWrapper<?>>(
128: objects.size());
129: for (PdfObjectWrapper<?> object : objects) {
130: contextualizedObjects
131: .add((PdfObjectWrapper<?>) contextualize(object));
132: }
133:
134: return contextualizedObjects;
135: }
136:
137: /**
138: Drops the object from this document context.
139: */
140: public void decontextualize(PdfObjectWrapper<?> object) {
141: if (object.getFile() != getFile())
142: return;
143:
144: object.delete();
145: }
146:
147: /**
148: Drops the collection's objects from this document context.
149: */
150: public void decontextualize(
151: Collection<? extends PdfObjectWrapper<?>> objects) {
152: for (PdfObjectWrapper<?> object : objects) {
153: decontextualize(object);
154: }
155: }
156:
157: /**
158: Gets the bookmark collection [PDF:1.6:8.2.2].
159: */
160: public Bookmarks getBookmarks() {
161: PdfDirectObject bookmarks = getBaseDataObject().get(
162: PdfName.Outlines);
163: if (bookmarks == null)
164: return null;
165:
166: return new Bookmarks(bookmarks);
167: }
168:
169: /**
170: Gets the document information dictionary [PDF:1.6:10.2.1].
171: */
172: public Information getInformation() {
173: PdfDirectObject informationObject = getFile().getTrailer().get(
174: PdfName.Info);
175: if (informationObject == null)
176: return null;
177:
178: return new Information(informationObject);
179: }
180:
181: /**
182: Gets the name dictionary [PDF:1.6:3.6.3].
183: @since 0.0.4
184: @version 0.0.4
185: */
186: public Names getNames() {
187: PdfDirectObject namesObject = getBaseDataObject().get(
188: PdfName.Names);
189: if (namesObject == null)
190: return null;
191:
192: return new Names(namesObject, ((PdfReference) getBaseObject())
193: .getIndirectObject());
194: }
195:
196: /**
197: Gets the page layout to be used when the document is opened.
198: */
199: public PageLayoutEnum getPageLayout() {
200: PdfName value = (PdfName) getBaseDataObject().get(
201: PdfName.PageLayout);
202: if (value.equals(PdfName.OneColumn))
203: return PageLayoutEnum.OneColumn;
204: else if (value.equals(PdfName.TwoColumnLeft))
205: return PageLayoutEnum.TwoColumns;
206: else
207: return PageLayoutEnum.SinglePage;
208: }
209:
210: /**
211: Gets the page mode, that is how the document should be displayed when is opened.
212: */
213: public PageModeEnum getPageMode() {
214: PdfName value = (PdfName) getBaseDataObject().get(
215: PdfName.PageMode);
216: if (value.equals(PdfName.UseOutlines))
217: return PageModeEnum.Outlines;
218: else if (value.equals(PdfName.UseThumbs))
219: return PageModeEnum.Thumbnails;
220: else if (value.equals(PdfName.FullScreen))
221: return PageModeEnum.FullScreen;
222: else
223: return PageModeEnum.Simple;
224: }
225:
226: /**
227: Gets the page collection [PDF:1.6:3.6.2].
228: */
229: public Pages getPages() {
230: return new Pages(getBaseDataObject().get(PdfName.Pages)); // NOTE: Required.
231: }
232:
233: /**
234: Gets the default page size [PDF:1.6:3.6.2].
235: */
236: public Dimension2D getPageSize() {
237: /*
238: NOTE: Due to the contract,
239: we cannot force the existence of the default media box at document level.
240: */
241: PdfArray box = getMediaBox();
242: if (box == null)
243: return null;
244:
245: return new Dimension((int) ((IPdfNumber) box.get(2))
246: .getNumberValue(), (int) ((IPdfNumber) box.get(3))
247: .getNumberValue());
248: }
249:
250: /**
251: Gets the default resource collection [PDF:1.6:3.6.2].
252: <h3>Remarks</h3>
253: <p>The default resource collection is used as last resort by every page that doesn't reference one
254: explicitly (and doesn't reference an intermediate one implicitly).</p>
255: */
256: public Resources getResources() {
257: PdfReference pages = (PdfReference) getBaseDataObject().get(
258: PdfName.Pages);
259: PdfDirectObject resources = ((PdfDictionary) File
260: .resolve(pages)).get(PdfName.Resources);
261: if (resources == null)
262: return null;
263:
264: return new Resources(resources, pages.getIndirectObject());
265: }
266:
267: /**
268: Gets the document size, that is the maximum page dimensions across the whole document.
269: */
270: public Dimension2D getSize() {
271: int height = 0, width = 0;
272: for (Page page : getPages()) {
273: Dimension2D pageSize = page.getSize();
274: if (pageSize == null)
275: continue;
276:
277: height = Math.max(height, (int) pageSize.getHeight());
278: width = Math.max(width, (int) pageSize.getWidth());
279: }
280: return new Dimension(width, height);
281: }
282:
283: /**
284: Gets the way the document is to be presented [PDF:1.6:8.1].
285: */
286: public ViewerPreferences getViewerPreferences() {
287: PdfDirectObject viewerPreferences = getBaseDataObject().get(
288: PdfName.ViewerPreferences);
289: if (viewerPreferences == null)
290: return null;
291:
292: return new ViewerPreferences(viewerPreferences,
293: ((PdfReference) getBaseObject()).getIndirectObject());
294: }
295:
296: /**
297: Sets the bookmark collection.
298: @see #getBookmarks()
299: */
300: public void setBookmarks(Bookmarks value) {
301: getBaseDataObject()
302: .put(PdfName.Outlines, value.getBaseObject());
303: }
304:
305: /**
306: Sets the document information dictionary.
307: @see #getInformation()
308: */
309: public void setInformation(Information value) {
310: getFile().getTrailer().put(PdfName.Info, value.getBaseObject());
311: }
312:
313: /**
314: Sets the name dictionary.
315: @since 0.0.4 06/01/07
316: @version 0.0.4
317: @see #getNames()
318: */
319: public void setNames(Names value) {
320: getBaseDataObject().put(PdfName.Names, value.getBaseObject());
321: }
322:
323: /**
324: Sets the page layout to be used when the document is opened.
325: @see #getPageLayout()
326: */
327: public void setPageLayout(PageLayoutEnum value) {
328: switch (value) {
329: case SinglePage:
330: getBaseDataObject().put(PdfName.PageLayout,
331: PdfName.SinglePage);
332: break;
333: case OneColumn:
334: getBaseDataObject().put(PdfName.PageLayout,
335: PdfName.OneColumn);
336: break;
337: case TwoColumns:
338: getBaseDataObject().put(PdfName.PageLayout,
339: PdfName.TwoColumnLeft);
340: break;
341: }
342: }
343:
344: /**
345: Sets the page mode, that is how the document should be displayed when is opened.
346: @see #getPageMode()
347: */
348: public void setPageMode(PageModeEnum value) {
349: switch (value) {
350: case Simple:
351: getBaseDataObject().put(PdfName.PageMode, PdfName.UseNone);
352: break;
353: case Outlines:
354: getBaseDataObject().put(PdfName.PageMode,
355: PdfName.UseOutlines);
356: break;
357: case Thumbnails:
358: getBaseDataObject()
359: .put(PdfName.PageMode, PdfName.UseThumbs);
360: break;
361: case FullScreen:
362: getBaseDataObject().put(PdfName.PageMode,
363: PdfName.FullScreen);
364: break;
365: }
366: }
367:
368: /**
369: Sets the page collection.
370: @see #getPages()
371: */
372: public void setPages(Pages value) {
373: getBaseDataObject().put(PdfName.Pages, value.getBaseObject());
374: }
375:
376: /**
377: Sets the default page size.
378: @see #getPageSize()
379: */
380: public void setPageSize(Dimension2D value) {
381: PdfArray mediaBox = getMediaBox();
382: if (mediaBox == null) {
383: // Create default media box!
384: mediaBox = new PdfRectangle(0, 0, 0, 0);
385: // Assign the media box to the document!
386: ((PdfDictionary) File.resolve(getBaseDataObject().get(
387: PdfName.Pages))).put(PdfName.MediaBox, mediaBox);
388: }
389:
390: mediaBox.set(2, new PdfReal(value.getWidth()));
391: mediaBox.set(3, new PdfReal(value.getHeight()));
392: }
393:
394: /**
395: Sets the default resource collection.
396: @see #getResources()
397: */
398: public void setResources(Resources value) {
399: PdfReference pages = (PdfReference) getBaseDataObject().get(
400: PdfName.Pages);
401: ((PdfDictionary) File.resolve(pages)).put(PdfName.Resources,
402: value.getBaseObject());
403: value.setContainer(pages.getIndirectObject()); // Resources object could be directly inside a container.
404: }
405:
406: /**
407: Sets the way the document is to be presented.
408: @see #getViewerPreferences()
409: */
410: public void setViewerPreferences(ViewerPreferences value) {
411: getBaseDataObject().put(PdfName.ViewerPreferences,
412: value.getBaseObject());
413: value.setContainer(((PdfReference) getBaseObject())
414: .getIndirectObject()); // ViewerPreferences object could be directly inside a container.
415: }
416:
417: // </public>
418:
419: // <private>
420: /**
421: Gets the default media box.
422: */
423: private PdfArray getMediaBox() {
424: /*
425: NOTE: Document media box MUST be associated with the page-tree root node
426: in order to be inheritable by all the pages.
427: */
428: return (PdfArray) File.resolve(((PdfDictionary) File
429: .resolve(getBaseDataObject().get(PdfName.Pages)))
430: .get(PdfName.MediaBox));
431: }
432: // </private>
433: // </interface>
434: // </dynamic>
435: // </class>
436: }
|