001: /*
002: * Copyright (c) 2007, intarsys consulting GmbH
003: *
004: * Redistribution and use in source and binary forms, with or without
005: * modification, are permitted provided that the following conditions are met:
006: *
007: * - Redistributions of source code must retain the above copyright notice,
008: * this list of conditions and the following disclaimer.
009: *
010: * - Redistributions in binary form must reproduce the above copyright notice,
011: * this list of conditions and the following disclaimer in the documentation
012: * and/or other materials provided with the distribution.
013: *
014: * - Neither the name of intarsys nor the names of its contributors may be used
015: * to endorse or promote products derived from this software without specific
016: * prior written permission.
017: *
018: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
019: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
020: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
021: * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
022: * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
023: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
024: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
025: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
026: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
027: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
028: * POSSIBILITY OF SUCH DAMAGE.
029: */
030: package de.intarsys.pdf.pd;
031:
032: import java.awt.geom.Rectangle2D;
033:
034: import de.intarsys.pdf.cds.CDSMatrix;
035: import de.intarsys.pdf.cds.CDSRectangle;
036: import de.intarsys.pdf.content.CSContent;
037: import de.intarsys.pdf.content.CSOperation;
038: import de.intarsys.pdf.content.IContentStreamProvider;
039: import de.intarsys.pdf.cos.COSArray;
040: import de.intarsys.pdf.cos.COSBasedObject;
041: import de.intarsys.pdf.cos.COSDictionary;
042: import de.intarsys.pdf.cos.COSInteger;
043: import de.intarsys.pdf.cos.COSName;
044: import de.intarsys.pdf.cos.COSObject;
045: import de.intarsys.pdf.cos.COSStream;
046:
047: /**
048: * A form object. A form object specifies a reusable graphical object (not an
049: * AcroForm).
050: */
051: public class PDForm extends PDXObject implements IContentStreamProvider {
052: /**
053: * The meta class implementation
054: */
055: public static class MetaClass extends PDXObject.MetaClass {
056: protected MetaClass(Class instanceClass) {
057: super (instanceClass);
058: }
059:
060: protected COSBasedObject doCreateCOSBasedObject(COSObject object) {
061: return new PDForm(object);
062: }
063: }
064:
065: /** The meta class instance */
066: public static final MetaClass META = new MetaClass(MetaClass.class
067: .getDeclaringClass());
068:
069: //
070: public static final COSName CN_Subtype_Form = COSName
071: .constant("Form"); //$NON-NLS-1$
072:
073: public static final COSName DK_BBox = COSName.constant("BBox"); //$NON-NLS-1$
074:
075: public static final COSName DK_Matrix = COSName.constant("Matrix"); //$NON-NLS-1$
076:
077: public static final COSName DK_PieceInfo = COSName
078: .constant("PieceInfo"); //$NON-NLS-1$
079:
080: public static final COSName DK_FormType = COSName
081: .constant("FormType"); //$NON-NLS-1$
082:
083: public static final COSName DK_OPI = COSName.constant("OPI"); //$NON-NLS-1$
084:
085: public static final COSName DK_PS = COSName.constant("PS"); //$NON-NLS-1$
086:
087: public static final COSName DK_Subtype2 = COSName
088: .constant("Subtype2"); //$NON-NLS-1$
089:
090: public static final COSName DK_Group = COSName.constant("Group"); //$NON-NLS-1$
091:
092: /**
093: * Cached content of the form.
094: *
095: * <p>
096: * Requesting the content is frequent and expensive.
097: * </p>
098: */
099: private CSContent cachedContent;
100:
101: /** Cached transformed rectangle. */
102: private Rectangle2D cachedTransformedBBox;
103:
104: /**
105: * Create the receiver class from an already defined {@link COSStream}.
106: * NEVER use the constructor directly.
107: *
108: * @param object
109: * the PDDocument containing the new object
110: */
111: protected PDForm(COSObject object) {
112: super (object);
113: }
114:
115: public void setApplicationData(COSName name, PDApplicationData data) {
116: COSDictionary pid = cosGetPieceInfo();
117: if (pid == null) {
118: pid = COSDictionary.create();
119: cosSetPieceInfo(pid);
120: }
121: pid.put(name, data.cosGetDict());
122: }
123:
124: public PDApplicationData getApplicationData(COSName name) {
125: COSDictionary pid = cosGetPieceInfo();
126: if (pid == null) {
127: return null;
128: }
129: COSDictionary pi = pid.get(name).asDictionary();
130: if (pi == null) {
131: return null;
132: }
133: return (PDApplicationData) PDApplicationData.META
134: .createFromCos(pi);
135: }
136:
137: /**
138: * Set the bounding box of the receiver.
139: *
140: * @param rect
141: * The new bounding box of the receiver.
142: */
143: public void setBoundingBox(CDSRectangle rect) {
144: setFieldObject(DK_BBox, rect);
145: }
146:
147: /**
148: * The bounding box of the receiver form.
149: *
150: * @return The bounding box of the receiver form.
151: */
152: public CDSRectangle getBoundingBox() {
153: COSArray array = cosGetField(DK_BBox).asArray();
154: if (array == null) {
155: return null;
156: }
157: return CDSRectangle.createFromCOS(array);
158: }
159:
160: public CSContent getContentStream() {
161: if (cachedContent == null) {
162: cachedContent = CSContent.createFromCos(cosGetStream());
163: }
164: return cachedContent;
165: }
166:
167: public void setContentStream(CSContent content) {
168: setBytes(content.toByteArray());
169: }
170:
171: public boolean isForm() {
172: return true;
173: }
174:
175: /**
176: * Set the new variable content of the stream.
177: *
178: * @param content
179: * The new variable content of the stream.
180: */
181: public void setMarkedContent(byte[] content) {
182: CSContent contentStream;
183: byte[] bytes = getBytes();
184: if (bytes == null) {
185: bytes = new byte[0];
186: }
187: contentStream = CSContent.createFromBytes(bytes);
188: contentStream.setMarkedContent(CSOperation.OPERAND_Tx, content);
189: setBytes(contentStream.toByteArray());
190: }
191:
192: /**
193: * Set the matrix of the receiver.
194: *
195: * @param matrix
196: * The new matrix of the receiver.
197: */
198: public void setMatrix(CDSMatrix matrix) {
199: setFieldObject(DK_Matrix, matrix);
200: }
201:
202: /**
203: * The form matrix of the receiver form.
204: *
205: * @return The form matrix of the receiver form.
206: */
207: public CDSMatrix getMatrix() {
208: return CDSMatrix
209: .createFromCOS(cosGetField(DK_Matrix).asArray());
210: }
211:
212: /**
213: * The resource dictionary of the receiver form. This method can return null
214: * if no resource dictionary is available.
215: *
216: * @return The resource dictionary of the receiver form.
217: */
218: public PDResources getResources() {
219: COSDictionary r = cosGetField(DK_Resources).asDictionary();
220: return (PDResources) PDResources.META.createFromCos(r);
221: }
222:
223: public void setResources(PDResources resources) {
224: setFieldObject(DK_Resources, resources);
225: }
226:
227: /*
228: * (non-Javadoc)
229: *
230: * @see de.intarsys.pdf.pd.PDObject#cosGetExpectedSubtype()
231: */
232: protected COSName cosGetExpectedSubtype() {
233: return CN_Subtype_Form;
234: }
235:
236: /**
237: * Compute a box according to the PDF specification that completely
238: * encompasses the transformed bounding box of the form.
239: *
240: * @return a box according to the PDF specification that completely
241: * encompasses the transformed bounding box of the form.
242: */
243: public Rectangle2D getTransformedBBox() {
244: if (cachedTransformedBBox == null) {
245: Rectangle2D.Float bbox = (Rectangle2D.Float) getBoundingBox()
246: .toRectangle();
247: CDSMatrix matrix = getMatrix();
248:
249: // transform all corners and lookup extremes
250: float minX;
251: float minY;
252: float maxX;
253: float maxY;
254: float[] vec;
255: vec = new float[] { bbox.x, bbox.y, bbox.x + bbox.width,
256: bbox.y, bbox.x + bbox.width, bbox.y + bbox.height,
257: bbox.x, bbox.y + bbox.height };
258: float[] tvec = vec;
259: if (matrix != null) {
260: tvec = matrix.transform(vec);
261: }
262: minX = tvec[0];
263: minY = tvec[1];
264: maxX = tvec[0];
265: maxY = tvec[1];
266: minX = Math.min(minX, tvec[2]);
267: minY = Math.min(minY, tvec[3]);
268: maxX = Math.max(maxX, tvec[2]);
269: maxY = Math.max(maxY, tvec[3]);
270: minX = Math.min(minX, tvec[4]);
271: minY = Math.min(minY, tvec[5]);
272: maxX = Math.max(maxX, tvec[4]);
273: maxY = Math.max(maxY, tvec[5]);
274: minX = Math.min(minX, tvec[6]);
275: minY = Math.min(minY, tvec[7]);
276: maxX = Math.max(maxX, tvec[6]);
277: maxY = Math.max(maxY, tvec[7]);
278: //
279: cachedTransformedBBox = new Rectangle2D.Float(minX, minY,
280: maxX - minX, maxY - minY);
281: }
282: return cachedTransformedBBox;
283: }
284:
285: /**
286: * Add new marked content to the stream.
287: *
288: * @param content
289: * The new variable content of the stream.
290: */
291: public void addMarkedContent(byte[] content) {
292: CSContent contentStream;
293: byte[] bytes = getBytes();
294: if (bytes == null) {
295: bytes = new byte[0];
296: }
297: contentStream = CSContent.createFromBytes(bytes);
298: contentStream.addMarkedContent(CSOperation.OPERAND_Tx, content);
299: setBytes(contentStream.toByteArray());
300: }
301:
302: /**
303: * The piece info dictionary of the document.
304: *
305: * @return The piece info dictionary of the document.
306: */
307: public COSDictionary cosGetPieceInfo() {
308: return cosGetField(DK_PieceInfo).asDictionary();
309: }
310:
311: /**
312: * Set the piece info dictionary of the document.
313: *
314: * @param dict
315: * The piece info dictionary of the document.
316: *
317: * @return The /PieceInfo entry previously associated with this.
318: */
319: public COSDictionary cosSetPieceInfo(COSDictionary dict) {
320: if (dict != null) {
321: dict.beIndirect();
322: }
323: return cosSetField(DK_PieceInfo, dict).asDictionary();
324: }
325:
326: public void invalidateCaches() {
327: super .invalidateCaches();
328: cachedContent = null;
329: cachedTransformedBBox = null;
330: }
331:
332: /*
333: * (non-Javadoc)
334: *
335: * @see de.intarsys.pdf.pd.PDObject#initializeFromScratch()
336: */
337: protected void initializeFromScratch() {
338: super .initializeFromScratch();
339: setBoundingBox(new CDSRectangle());
340: setMatrix(new CDSMatrix());
341: cosSetField(DK_Resources, COSDictionary.create());
342: cosSetField(DK_FormType, COSInteger.create(1));
343: setBytes(new byte[0]);
344: }
345: }
|