001: /*
002: Copyright © 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 © 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.tools;
028:
029: import it.stefanochizzolini.clown.documents.Page;
030: import it.stefanochizzolini.clown.documents.contents.Contents;
031: import it.stefanochizzolini.clown.documents.contents.ContentScanner;
032: import it.stefanochizzolini.clown.documents.contents.composition.PrimitiveFilter;
033: import it.stefanochizzolini.clown.documents.contents.objects.RestoreGraphicsState;
034: import it.stefanochizzolini.clown.documents.contents.objects.SaveGraphicsState;
035: import it.stefanochizzolini.clown.files.File;
036: import it.stefanochizzolini.clown.objects.PdfArray;
037: import it.stefanochizzolini.clown.objects.PdfDataObject;
038: import it.stefanochizzolini.clown.objects.PdfDirectObject;
039: import it.stefanochizzolini.clown.objects.PdfName;
040: import it.stefanochizzolini.clown.objects.PdfReference;
041: import it.stefanochizzolini.clown.objects.PdfStream;
042:
043: /**
044: Tool for content insertion inside an existing page.
045: */
046: public class PageStamper {
047: // <class>
048: // <dynamic>
049: // <fields>
050: private Page page;
051:
052: private PrimitiveFilter background;
053: private PrimitiveFilter foreground;
054:
055: // </fields>
056:
057: // <constructors>
058: public PageStamper() {
059: this (null);
060: }
061:
062: public PageStamper(Page page) {
063: setPage(page);
064: }
065:
066: // </constructors>
067:
068: // <interface>
069: // <public>
070: public void flush() {
071: // Ensuring that there's room for the new content chunks inside the page's content stream...
072: /*
073: NOTE: This specialized stamper is optimized for content insertion without modifying
074: existing content representations, leveraging the peculiar feature of page structures
075: to express their content streams as arrays of data streams.
076: */
077: PdfArray streams;
078: {
079: PdfDirectObject contentsObject = page.getBaseDataObject()
080: .get(PdfName.Contents);
081: PdfDataObject contentsDataObject = File
082: .resolve(contentsObject);
083: // Single data stream?
084: if (contentsDataObject instanceof PdfStream) {
085: /*
086: NOTE: Content stream MUST be expressed as an array of data streams in order to host
087: background- and foreground-stamped contents.
088: */
089: streams = new PdfArray();
090: streams.add(contentsObject);
091: page.getBaseDataObject().put(PdfName.Contents, streams);
092:
093: page.update(); // Fundamental to override original page contents collection.
094: } else {
095: streams = (PdfArray) contentsDataObject;
096:
097: if (!File.update(contentsObject)) {
098: page.update();
099: } // Fundamental to override original page contents collection.
100: }
101: }
102:
103: // Background.
104: // Serialize the content!
105: background.flush();
106: // Insert the serialized content into the page's content stream!
107: streams.add(0, (PdfReference) background.getScanner()
108: .getContents().getBaseObject());
109:
110: // Foreground.
111: // Serialize the content!
112: foreground.flush();
113: // Append the serialized content into the page's content stream!
114: streams.add((PdfReference) foreground.getScanner()
115: .getContents().getBaseObject());
116: }
117:
118: public PrimitiveFilter getBackground() {
119: return background;
120: }
121:
122: public PrimitiveFilter getForeground() {
123: return foreground;
124: }
125:
126: public Page getPage() {
127: return page;
128: }
129:
130: public void setPage(Page page) {
131: this .page = page;
132: if (this .page == null) {
133: background = null;
134: foreground = null;
135: } else {
136: // Background.
137: background = createFilter();
138: // Open the background local state!
139: background.add(SaveGraphicsState.Value);
140: // Close the background local state!
141: background.add(RestoreGraphicsState.Value);
142: // Open the middleground local state!
143: background.add(SaveGraphicsState.Value);
144: // Move into the background!
145: background.getScanner().moveFirst();
146:
147: // Foregrond.
148: foreground = createFilter();
149: // Close the middleground local state!
150: foreground.add(RestoreGraphicsState.Value);
151: }
152: }
153:
154: // </public>
155:
156: // <private>
157: private PrimitiveFilter createFilter() {
158: PdfReference reference = page.getFile().register(
159: new PdfStream());
160:
161: return new PrimitiveFilter(new ContentScanner(new Contents(
162: reference, reference.getIndirectObject(), page)));
163: }
164: // </private>
165: // </interface>
166: // </dynamic>
167: // </class>
168: }
|