KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > fop > pdf > PDFDocument


1 /*
2  * $Id: PDFDocument.java,v 1.30.2.8 2003/03/05 18:58:15 pietsch Exp $
3  * ============================================================================
4  * The Apache Software License, Version 1.1
5  * ============================================================================
6  *
7  * Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without modifica-
10  * tion, are permitted provided that the following conditions are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright notice,
13  * this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright notice,
16  * this list of conditions and the following disclaimer in the documentation
17  * and/or other materials provided with the distribution.
18  *
19  * 3. The end-user documentation included with the redistribution, if any, must
20  * include the following acknowledgment: "This product includes software
21  * developed by the Apache Software Foundation (http://www.apache.org/)."
22  * Alternately, this acknowledgment may appear in the software itself, if
23  * and wherever such third-party acknowledgments normally appear.
24  *
25  * 4. The names "FOP" and "Apache Software Foundation" must not be used to
26  * endorse or promote products derived from this software without prior
27  * written permission. For written permission, please contact
28  * apache@apache.org.
29  *
30  * 5. Products derived from this software may not be called "Apache", nor may
31  * "Apache" appear in their name, without prior written permission of the
32  * Apache Software Foundation.
33  *
34  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
35  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
36  * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
37  * APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
38  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
39  * DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
40  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
41  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
42  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
43  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
44  * ============================================================================
45  *
46  * This software consists of voluntary contributions made by many individuals
47  * on behalf of the Apache Software Foundation and was originally created by
48  * James Tauber <jtauber@jtauber.com>. For more information on the Apache
49  * Software Foundation, please see <http://www.apache.org/>.
50  */

51 package org.apache.fop.pdf;
52
53 // images are the one place that FOP classes outside this package get
54
// referenced and I'd rather not do it
55
import org.apache.fop.image.FopImage;
56
57 import org.apache.fop.layout.LinkSet;
58 import org.apache.fop.datatypes.ColorSpace;
59
60 import org.apache.fop.render.pdf.CIDFont;
61 import org.apache.fop.render.pdf.fonts.LazyFont;
62
63 import org.apache.fop.datatypes.IDReferences;
64 import org.apache.fop.layout.Page;
65 import org.apache.fop.layout.FontMetric;
66 import org.apache.fop.layout.FontDescriptor;
67 // Java
68
import java.io.IOException JavaDoc;
69 import java.io.OutputStream JavaDoc;
70 import java.io.UnsupportedEncodingException JavaDoc;
71 import java.util.List JavaDoc;
72 import java.util.Map JavaDoc;
73 import java.awt.Rectangle JavaDoc;
74
75 /**
76  * class representing a PDF document.
77  *
78  * The document is built up by calling various methods and then finally
79  * output to given filehandle using output method.
80  *
81  * A PDF document consists of a series of numbered objects preceded by a
82  * header and followed by an xref table and trailer. The xref table
83  * allows for quick access to objects by listing their character
84  * positions within the document. For this reason the PDF document must
85  * keep track of the character position of each object. The document
86  * also keeps direct track of the /Root, /Info and /Resources objects.
87  *
88  * Modified by Mark Lillywhite, mark-fop@inomial.com. The changes
89  * involve: ability to output pages one-at-a-time in a streaming
90  * fashion (rather than storing them all for output at the end);
91  * ability to write the /Pages object after writing the rest
92  * of the document; ability to write to a stream and flush
93  * the object list; enhanced trailer output; cleanups.
94  *
95  * Modified by lmckenzi@ca.ibm.com
96  * Sometimes IDs are created, but not validated. This tracks
97  * the difference.
98  * Image support modified from work of BoBoGi.
99  * Font support based on work by Takayuki Takeuchi.
100  */

101 public class PDFDocument {
102     private static final Integer JavaDoc locationPlaceholder = new Integer JavaDoc(0);
103     /**
104      * the version of PDF supported
105      */

106     protected static final String JavaDoc pdfVersion = "1.3";
107
108     /**
109      * the current character position
110      */

111     protected int position = 0;
112
113     /**
114      * the character position of each object
115      */

116     protected List JavaDoc location = new java.util.ArrayList JavaDoc();
117
118     /** List of objects to write in the trailer */
119     private List JavaDoc trailerObjects = new java.util.ArrayList JavaDoc();
120
121     /**
122      * the counter for object numbering
123      */

124     protected int objectcount = 0;
125
126     /**
127      * the objects themselves
128      */

129     protected List JavaDoc objects = new java.util.ArrayList JavaDoc();
130
131     /**
132      * character position of xref table
133      */

134     protected int xref;
135
136     /**
137      * the /Root object
138      */

139     protected PDFRoot root;
140
141     /** The root outline object */
142     private PDFOutline outlineRoot = null;
143
144     /** The /Pages object (mark-fop@inomial.com) */
145     private PDFPages pages;
146
147     /**
148      * the /Info object
149      */

150     protected PDFInfo info;
151
152     /**
153      * the /Resources object
154      */

155     protected PDFResources resources;
156
157     /**
158      * the documents idReferences
159      */

160     protected IDReferences idReferences;
161
162     /**
163      * the documents encryption, if exists
164      */

165     protected PDFEncryption encryption;
166
167     /**
168      * the colorspace (0=RGB, 1=CMYK)
169      */

170     // protected int colorspace = 0;
171
protected ColorSpace colorspace = new ColorSpace(ColorSpace.DEVICE_RGB);
172
173     /**
174      * the counter for Pattern name numbering (e.g. 'Pattern1')
175      */

176     protected int patternCount = 0;
177
178     /**
179      * the counter for Shading name numbering
180      */

181     protected int shadingCount = 0;
182
183     /**
184      * the counter for XObject numbering
185      */

186     protected int xObjectCount = 0;
187
188     /**
189      * the XObjects
190      */

191     protected List JavaDoc xObjects = new java.util.ArrayList JavaDoc();
192
193     /**
194      * the XObjects Map.
195      * Should be modified (works only for image subtype)
196      */

197     protected Map JavaDoc xObjectsMap = new java.util.HashMap JavaDoc();
198
199     /**
200      * the objects themselves
201      */

202     protected List JavaDoc pendingLinks = null;
203
204     /**
205      * Encoding of the PDF
206      */

207     public static final String JavaDoc ENCODING = "ISO-8859-1";
208
209     /**
210      * creates an empty PDF document <p>
211      *
212      * The constructor creates a /Root and /Pages object to
213      * track the document but does not write these objects until
214      * the trailer is written. Note that the object ID of the
215      * pages object is determined now, and the xref table is
216      * updated later. This allows Pages to refer to their
217      * Parent before we write it out. This took me a long
218      * time to work out, and is so obvious now. Sigh.
219      * mark-fop@inomial.com. Maybe I should do a PDF course.
220      */

221     public PDFDocument() {
222
223         /* create the /Root, /Info and /Resources objects */
224         this.pages = makePages();
225
226         // Create the Root object
227
this.root = makeRoot(pages);
228
229         // Create the Resources object
230
this.resources = makeResources();
231
232         // Make the /Info record
233
this.info = makeInfo();
234     }
235
236     /**
237      * set the producer of the document
238      *
239      * @param producer string indicating application producing the PDF
240      */

241     public void setProducer(String JavaDoc producer) {
242         this.info.setProducer(producer);
243     }
244
245     /**
246      * set the encryption object
247      *
248      * @param ownerPassword The owner password for the pdf file
249      * @param userPassword The user password for the pdf file
250      * @param allowPrint Indicates whether the printing permission will be set
251      * @param allowCopyContent Indicates whether the content extracting permission will be set
252      * @param allowEditContent Indicates whether the edit content permission will be set
253      * @param allowEditAnnotations Indicates whether the edit annotations permission will be set
254      */

255     public void setEncryption(String JavaDoc ownerPassword, String JavaDoc userPassword,
256                               boolean allowPrint, boolean allowCopyContent,
257                               boolean allowEditContent, boolean allowEditAnnotations) {
258         this.encryption = new PDFEncryption(++this.objectcount);
259         this.encryption.setOwnerPassword(ownerPassword);
260         this.encryption.setUserPassword(userPassword);
261         this.encryption.setAllowPrint(allowPrint);
262         this.encryption.setAllowCopyContent(allowCopyContent);
263         this.encryption.setAllowEditContent(allowEditContent);
264         this.encryption.setAllowEditAnnotation(allowEditAnnotations);
265         this.encryption.init();
266         addTrailerObject(this.encryption);
267     }
268
269     /**
270      * Make a /Catalog (Root) object. This object is written in
271      * the trailer.
272      */

273     public PDFRoot makeRoot(PDFPages pages) {
274
275         /*
276         * Make a /Pages object. This object is written in the trailer.
277         */

278         PDFRoot pdfRoot = new PDFRoot(++this.objectcount, pages);
279         addTrailerObject(pdfRoot);
280         return pdfRoot;
281     }
282
283     /**
284      * Make a /Pages object. This object is written in the trailer.
285      */

286
287     public PDFPages makePages() {
288         PDFPages pdfPages = new PDFPages(++this.objectcount);
289         addTrailerObject(pdfPages);
290         return pdfPages;
291     }
292
293     /**
294      * Make a /Resources object. This object is written in the trailer.
295      */

296     public PDFResources makeResources() {
297         PDFResources pdfResources = new PDFResources(++this.objectcount);
298         addTrailerObject(pdfResources);
299         return pdfResources;
300     }
301
302     /**
303      * make an /Info object
304      *
305      * @param producer string indicating application producing the PDF
306      * @return the created /Info object
307      */

308     protected PDFInfo makeInfo() {
309
310         /*
311          * create a PDFInfo with the next object number and add to
312          * list of objects
313          */

314         PDFInfo pdfInfo = new PDFInfo(++this.objectcount);
315         // set the default producer
316
pdfInfo.setProducer(org.apache.fop.apps.Version.getVersion());
317         this.objects.add(pdfInfo);
318         return pdfInfo;
319     }
320
321     /**
322      * Make a Type 0 sampled function
323      *
324      * @param theDomain List objects of Double objects.
325      * This is the domain of the function.
326      * See page 264 of the PDF 1.3 Spec.
327      * @param theRange List objects of Double objects.
328      * This is the Range of the function.
329      * See page 264 of the PDF 1.3 Spec.
330      * @param theSize A List object of Integer objects.
331      * This is the number of samples in each input dimension.
332      * I can't imagine there being more or less than two input dimensions,
333      * so maybe this should be an array of length 2.
334      *
335      * See page 265 of the PDF 1.3 Spec.
336      * @param theBitsPerSample An int specifying the number of bits user to represent each sample value.
337      * Limited to 1,2,4,8,12,16,24 or 32.
338      * See page 265 of the 1.3 PDF Spec.
339      * @param theOrder The order of interpolation between samples. Default is 1 (one). Limited
340      * to 1 (one) or 3, which means linear or cubic-spline interpolation.
341      *
342      * This attribute is optional.
343      *
344      * See page 265 in the PDF 1.3 spec.
345      * @param theEncode List objects of Double objects.
346      * This is the linear mapping of input values intop the domain
347      * of the function's sample table. Default is hard to represent in
348      * ascii, but basically [0 (Size0 1) 0 (Size1 1)...].
349      * This attribute is optional.
350      *
351      * See page 265 in the PDF 1.3 spec.
352      * @param theDecode List objects of Double objects.
353      * This is a linear mapping of sample values into the range.
354      * The default is just the range.
355      *
356      * This attribute is optional.
357      * Read about it on page 265 of the PDF 1.3 spec.
358      * @param theFunctionDataStream The sample values that specify the function are provided in a stream.
359      *
360      * This is optional, but is almost always used.
361      *
362      * Page 265 of the PDF 1.3 spec has more.
363      * @param theFilter This is a List of String objects which are the various filters that
364      * have are to be applied to the stream to make sense of it. Order matters,
365      * so watch out.
366      *
367      * This is not documented in the Function section of the PDF 1.3 spec,
368      * it was deduced from samples that this is sometimes used, even if we may never
369      * use it in FOP. It is added for completeness sake.
370      * @param theNumber The object number of this PDF object.
371      * @param theFunctionType This is the type of function (0,2,3, or 4).
372      * It should be 0 as this is the constructor for sampled functions.
373      */

374     public PDFFunction makeFunction(int theFunctionType, List JavaDoc theDomain,
375                                     List JavaDoc theRange, List JavaDoc theSize,
376                                     int theBitsPerSample, int theOrder,
377                                     List JavaDoc theEncode, List JavaDoc theDecode,
378                                     StringBuffer JavaDoc theFunctionDataStream,
379                                     List JavaDoc theFilter) { // Type 0 function
380
PDFFunction function = new PDFFunction(++this.objectcount,
381                                                theFunctionType, theDomain,
382                                                theRange, theSize,
383                                                theBitsPerSample, theOrder,
384                                                theEncode, theDecode,
385                                                theFunctionDataStream,
386                                                theFilter);
387
388         this.objects.add(function);
389         return (function);
390     }
391
392     /**
393      * make a type Exponential interpolation function
394      * (for shading usually)
395      *
396      * @param theDomain List objects of Double objects.
397      * This is the domain of the function.
398      * See page 264 of the PDF 1.3 Spec.
399      * @param theRange List of Doubles that is the Range of the function.
400      * See page 264 of the PDF 1.3 Spec.
401      * @param theCZero This is a List of Double objects which defines the function result
402      * when x=0.
403      *
404      * This attribute is optional.
405      * It's described on page 268 of the PDF 1.3 spec.
406      * @param theCOne This is a List of Double objects which defines the function result
407      * when x=1.
408      *
409      * This attribute is optional.
410      * It's described on page 268 of the PDF 1.3 spec.
411      * @param theInterpolationExponentN This is the inerpolation exponent.
412      *
413      * This attribute is required.
414      * PDF Spec page 268
415      * @param theFunctionType The type of the function, which should be 2.
416      */

417     public PDFFunction makeFunction(int theFunctionType, List JavaDoc theDomain,
418                                     List JavaDoc theRange, List JavaDoc theCZero,
419                                     List JavaDoc theCOne,
420                                     double theInterpolationExponentN) { // type 2
421
PDFFunction function = new PDFFunction(++this.objectcount,
422                                                theFunctionType, theDomain,
423                                                theRange, theCZero, theCOne,
424                                                theInterpolationExponentN);
425
426         this.objects.add(function);
427         return (function);
428     }
429
430     /**
431      * Make a Type 3 Stitching function
432      *
433      * @param theDomain List objects of Double objects.
434      * This is the domain of the function.
435      * See page 264 of the PDF 1.3 Spec.
436      * @param theRange List objects of Double objects.
437      * This is the Range of the function.
438      * See page 264 of the PDF 1.3 Spec.
439      * @param theFunctions A List of the PDFFunction objects that the stitching function stitches.
440      *
441      * This attributed is required.
442      * It is described on page 269 of the PDF spec.
443      * @param theBounds This is a List of Doubles representing the numbers that,
444      * in conjunction with Domain define the intervals to which each function from
445      * the 'functions' object applies. It must be in order of increasing magnitude,
446      * and each must be within Domain.
447      *
448      * It basically sets how much of the gradient each function handles.
449      *
450      * This attributed is required.
451      * It's described on page 269 of the PDF 1.3 spec.
452      * @param theEncode List objects of Double objects.
453      * This is the linear mapping of input values intop the domain
454      * of the function's sample table. Default is hard to represent in
455      * ascii, but basically [0 (Size0 1) 0 (Size1 1)...].
456      * This attribute is required.
457      *
458      * See page 270 in the PDF 1.3 spec.
459      * @param theFunctionType This is the function type. It should be 3,
460      * for a stitching function.
461      */

462     public PDFFunction makeFunction(int theFunctionType, List JavaDoc theDomain,
463                                     List JavaDoc theRange, List JavaDoc theFunctions,
464                                     List JavaDoc theBounds,
465                                     List JavaDoc theEncode) { // Type 3
466

467         PDFFunction function = new PDFFunction(++this.objectcount,
468                                                theFunctionType, theDomain,
469                                                theRange, theFunctions,
470                                                theBounds, theEncode);
471
472         this.objects.add(function);
473         return (function);
474     }
475
476     /**
477      * make a postscript calculator function
478      *
479      * @param theNumber
480      * @param theFunctionType
481      * @param theDomain
482      * @param theRange
483      * @param theFunctionDataStream
484      */

485     public PDFFunction makeFunction(int theNumber, int theFunctionType,
486                                     List JavaDoc theDomain, List JavaDoc theRange,
487                                     StringBuffer JavaDoc theFunctionDataStream) { // Type 4
488
PDFFunction function = new PDFFunction(++this.objectcount,
489                                                theFunctionType, theDomain,
490                                                theRange,
491                                                theFunctionDataStream);
492
493         this.objects.add(function);
494         return (function);
495
496     }
497
498     /**
499      * make a function based shading object
500      *
501      * @param theShadingType The type of shading object, which should be 1 for function
502      * based shading.
503      * @param theColorSpace The colorspace is 'DeviceRGB' or something similar.
504      * @param theBackground An array of color components appropriate to the
505      * colorspace key specifying a single color value.
506      * This key is used by the f operator buy ignored by the sh operator.
507      * @param theBBox List of double's representing a rectangle
508      * in the coordinate space that is current at the
509      * time of shading is imaged. Temporary clipping
510      * boundary.
511      * @param theAntiAlias Whether or not to anti-alias.
512      * @param theDomain Optional List of Doubles specifying the domain.
513      * @param theMatrix List of Doubles specifying the matrix.
514      * If it's a pattern, then the matrix maps it to pattern space.
515      * If it's a shading, then it maps it to current user space.
516      * It's optional, the default is the identity matrix
517      * @param theFunction The PDF Function that maps an (x,y) location to a color
518      */

519     public PDFShading makeShading(int theShadingType,
520                                   ColorSpace theColorSpace,
521                                   List JavaDoc theBackground, List JavaDoc theBBox,
522                                   boolean theAntiAlias, List JavaDoc theDomain,
523                                   List JavaDoc theMatrix,
524                                   PDFFunction theFunction) { // make Shading of Type 1
525
String JavaDoc theShadingName = new String JavaDoc("Sh" + (++this.shadingCount));
526
527         PDFShading shading = new PDFShading(++this.objectcount,
528                                             theShadingName, theShadingType,
529                                             theColorSpace, theBackground,
530                                             theBBox, theAntiAlias, theDomain,
531                                             theMatrix, theFunction);
532         this.objects.add(shading);
533
534         // add this shading to resources
535
this.resources.addShading(shading);
536
537         return (shading);
538     }
539
540     /**
541      * Make an axial or radial shading object.
542      *
543      * @param theShadingType 2 or 3 for axial or radial shading
544      * @param theColorSpace "DeviceRGB" or similar.
545      * @param theBackground theBackground An array of color components appropriate to the
546      * colorspace key specifying a single color value.
547      * This key is used by the f operator buy ignored by the sh operator.
548      * @param theBBox List of double's representing a rectangle
549      * in the coordinate space that is current at the
550      * time of shading is imaged. Temporary clipping
551      * boundary.
552      * @param theAntiAlias Default is false
553      * @param theCoords List of four (type 2) or 6 (type 3) Double
554      * @param theDomain List of Doubles specifying the domain
555      * @param theFunction the Stitching (PDFfunction type 3) function, even if it's stitching a single function
556      * @param theExtend List of Booleans of whether to extend teh start and end colors past the start and end points
557      * The default is [false, false]
558      */

559     public PDFShading makeShading(int theShadingType,
560                                   ColorSpace theColorSpace,
561                                   List JavaDoc theBackground, List JavaDoc theBBox,
562                                   boolean theAntiAlias, List JavaDoc theCoords,
563                                   List JavaDoc theDomain, PDFFunction theFunction,
564                                   List JavaDoc theExtend) { // make Shading of Type 2 or 3
565
String JavaDoc theShadingName = new String JavaDoc("Sh" + (++this.shadingCount));
566
567         PDFShading shading = new PDFShading(++this.objectcount,
568                                             theShadingName, theShadingType,
569                                             theColorSpace, theBackground,
570                                             theBBox, theAntiAlias, theCoords,
571                                             theDomain, theFunction,
572                                             theExtend);
573
574         this.resources.addShading(shading);
575
576         this.objects.add(shading);
577         return (shading);
578     }
579
580     /**
581      * Make a free-form gouraud shaded triangle mesh, coons patch mesh, or tensor patch mesh
582      * shading object
583      *
584      * @param theShadingType 4, 6, or 7 depending on whether it's
585      * Free-form gouraud-shaded triangle meshes, coons patch meshes,
586      * or tensor product patch meshes, respectively.
587      * @param theColorSpace "DeviceRGB" or similar.
588      * @param theBackground theBackground An array of color components appropriate to the
589      * colorspace key specifying a single color value.
590      * This key is used by the f operator buy ignored by the sh operator.
591      * @param theBBox List of double's representing a rectangle
592      * in the coordinate space that is current at the
593      * time of shading is imaged. Temporary clipping
594      * boundary.
595      * @param theAntiAlias Default is false
596      * @param theBitsPerCoordinate 1,2,4,8,12,16,24 or 32.
597      * @param theBitsPerComponent 1,2,4,8,12, and 16
598      * @param theBitsPerFlag 2,4,8.
599      * @param theDecode List of Doubles see PDF 1.3 spec pages 303 to 312.
600      * @param theFunction the PDFFunction
601      */

602     public PDFShading makeShading(int theShadingType,
603                                   ColorSpace theColorSpace,
604                                   List JavaDoc theBackground, List JavaDoc theBBox,
605                                   boolean theAntiAlias,
606                                   int theBitsPerCoordinate,
607                                   int theBitsPerComponent,
608                                   int theBitsPerFlag, List JavaDoc theDecode,
609                                   PDFFunction theFunction) { // make Shading of type 4,6 or 7
610
String JavaDoc theShadingName = new String JavaDoc("Sh" + (++this.shadingCount));
611
612         PDFShading shading = new PDFShading(++this.objectcount,
613                                             theShadingName, theShadingType,
614                                             theColorSpace, theBackground,
615                                             theBBox, theAntiAlias,
616                                             theBitsPerCoordinate,
617                                             theBitsPerComponent,
618                                             theBitsPerFlag, theDecode,
619                                             theFunction);
620
621         this.resources.addShading(shading);
622
623         this.objects.add(shading);
624         return (shading);
625     }
626
627     /**
628      * make a Lattice-Form Gouraud mesh shading object
629      *
630      * @param theShadingType 5 for lattice-Form Gouraud shaded-triangle mesh
631      * without spaces. "Shading1" or "Sh1" are good examples.
632      * @param theColorSpace "DeviceRGB" or similar.
633      * @param theBackground theBackground An array of color components appropriate to the
634      * colorspace key specifying a single color value.
635      * This key is used by the f operator buy ignored by the sh operator.
636      * @param theBBox List of double's representing a rectangle
637      * in the coordinate space that is current at the
638      * time of shading is imaged. Temporary clipping
639      * boundary.
640      * @param theAntiAlias Default is false
641      * @param theBitsPerCoordinate 1,2,4,8,12,16, 24, or 32
642      * @param theBitsPerComponent 1,2,4,8,12,24,32
643      * @param theDecode List of Doubles. See page 305 in PDF 1.3 spec.
644      * @param theVerticesPerRow number of vertices in each "row" of the lattice.
645      * @param theFunction The PDFFunction that's mapped on to this shape
646      */

647     public PDFShading makeShading(int theShadingType,
648                                   ColorSpace theColorSpace,
649                                   List JavaDoc theBackground, List JavaDoc theBBox,
650                                   boolean theAntiAlias,
651                                   int theBitsPerCoordinate,
652                                   int theBitsPerComponent, List JavaDoc theDecode,
653                                   int theVerticesPerRow,
654                                   PDFFunction theFunction) { // make shading of Type 5
655
String JavaDoc theShadingName = new String JavaDoc("Sh" + (++this.shadingCount));
656
657         PDFShading shading = new PDFShading(++this.objectcount,
658                                             theShadingName, theShadingType,
659                                             theColorSpace, theBackground,
660                                             theBBox, theAntiAlias,
661                                             theBitsPerCoordinate,
662                                             theBitsPerComponent, theDecode,
663                                             theVerticesPerRow, theFunction);
664
665         this.resources.addShading(shading);
666
667         this.objects.add(shading);
668
669         return (shading);
670     }
671
672     /**
673      * Make a tiling pattern
674      *
675      * @param thePatternType the type of pattern, which is 1 for tiling.
676      * @param theResources the resources associated with this pattern
677      * @param thePaintType 1 or 2, colored or uncolored.
678      * @param theTilingType 1, 2, or 3, constant spacing, no distortion, or faster tiling
679      * @param theBBox List of Doubles: The pattern cell bounding box
680      * @param theXStep horizontal spacing
681      * @param theYStep vertical spacing
682      * @param theMatrix Optional List of Doubles transformation matrix
683      * @param theXUID Optional List of Integers that uniquely identify the pattern
684      * @param thePatternDataStream The stream of pattern data to be tiled.
685      */

686     public PDFPattern makePattern(int thePatternType, // 1
687
PDFResources theResources, int thePaintType, int theTilingType,
688                                   List JavaDoc theBBox, double theXStep, double theYStep, List JavaDoc theMatrix,
689                                   List JavaDoc theXUID, StringBuffer JavaDoc thePatternDataStream) {
690         String JavaDoc thePatternName = new String JavaDoc("Pa" + (++this.patternCount));
691         // int theNumber, String thePatternName,
692
// PDFResources theResources
693
PDFPattern pattern = new PDFPattern(++this.objectcount,
694                                             thePatternName, theResources, 1,
695                                             thePaintType, theTilingType,
696                                             theBBox, theXStep, theYStep,
697                                             theMatrix, theXUID,
698                                             thePatternDataStream);
699
700         this.resources.addPattern(pattern);
701         this.objects.add(pattern);
702
703         return (pattern);
704     }
705
706     /**
707      * Make a smooth shading pattern
708      *
709      * @param thePatternType the type of the pattern, which is 2, smooth shading
710      * @param theShading the PDF Shading object that comprises this pattern
711      * @param theXUID optional:the extended unique Identifier if used.
712      * @param theExtGState optional: the extended graphics state, if used.
713      * @param theMatrix Optional:List of Doubles that specify the matrix.
714      */

715     public PDFPattern makePattern(int thePatternType, PDFShading theShading,
716                                   List JavaDoc theXUID, StringBuffer JavaDoc theExtGState,
717                                   List JavaDoc theMatrix) {
718         String JavaDoc thePatternName = new String JavaDoc("Pa" + (++this.patternCount));
719
720         PDFPattern pattern = new PDFPattern(++this.objectcount,
721                                             thePatternName, 2, theShading,
722                                             theXUID, theExtGState, theMatrix);
723
724         this.resources.addPattern(pattern);
725         this.objects.add(pattern);
726
727         return (pattern);
728     }
729
730     public int getColorSpace() {
731         return (this.colorspace.getColorSpace());
732     }
733
734     public void setColorSpace(int theColorspace) {
735         this.colorspace.setColorSpace(theColorspace);
736         return;
737     }
738
739     public PDFPattern createGradient(boolean radial,
740                                      ColorSpace theColorspace,
741                                      List JavaDoc theColors, List JavaDoc theBounds,
742                                      List JavaDoc theCoords) {
743         PDFShading myShad;
744         PDFFunction myfunky;
745         PDFFunction myfunc;
746         List JavaDoc theCzero;
747         List JavaDoc theCone;
748         PDFPattern myPattern;
749         ColorSpace theColorSpace;
750         double interpolation = (double)1.000;
751         List JavaDoc theFunctions = new java.util.ArrayList JavaDoc();
752
753         int currentPosition;
754         int lastPosition = theColors.size() - 1;
755
756
757         // if 5 elements, the penultimate element is 3.
758
// do not go beyond that, because you always need
759
// to have a next color when creating the function.
760

761         for (currentPosition = 0; currentPosition < lastPosition;
762                 currentPosition++) { // for every consecutive color pair
763
PDFColor currentColor =
764                 (PDFColor)theColors.get(currentPosition);
765             PDFColor nextColor = (PDFColor)theColors.get(currentPosition
766                                  + 1);
767             // colorspace must be consistant
768
if (this.colorspace.getColorSpace()
769                     != currentColor.getColorSpace())
770                 currentColor.setColorSpace(this.colorspace.getColorSpace());
771
772             if (this.colorspace.getColorSpace() != nextColor.getColorSpace())
773                 nextColor.setColorSpace(this.colorspace.getColorSpace());
774
775             theCzero = currentColor.getVector();
776             theCone = nextColor.getVector();
777
778             myfunc = this.makeFunction(2, null, null, theCzero, theCone,
779                                        interpolation);
780
781             theFunctions.add(myfunc);
782
783         } // end of for every consecutive color pair
784

785         myfunky = this.makeFunction(3, null, null, theFunctions, theBounds,
786                                     null);
787
788         if (radial) {
789             if (theCoords.size() == 6) {
790                 myShad = this.makeShading(3, this.colorspace, null, null,
791                                           false, theCoords, null, myfunky,
792                                           null);
793             } else { // if the center x, center y, and radius specifiy
794
// the gradient, then assume the same center x, center y,
795
// and radius of zero for the other necessary component
796
List JavaDoc newCoords = new java.util.ArrayList JavaDoc();
797                 newCoords.add(theCoords.get(0));
798                 newCoords.add(theCoords.get(1));
799                 newCoords.add(theCoords.get(2));
800                 newCoords.add(theCoords.get(0));
801                 newCoords.add(theCoords.get(1));
802                 newCoords.add(new Double JavaDoc(0.0));
803
804                 myShad = this.makeShading(3, this.colorspace, null, null,
805                                           false, newCoords, null, myfunky,
806                                           null);
807
808             }
809         } else {
810             myShad = this.makeShading(2, this.colorspace, null, null, false,
811                                       theCoords, null, myfunky, null);
812
813         }
814
815         myPattern = this.makePattern(2, myShad, null, null, null);
816
817         return (myPattern);
818     }
819
820
821     /**
822      * make a /Encoding object
823      *
824      * @param encodingName character encoding scheme name
825      * @return the created /Encoding object
826      */

827     public PDFEncoding makeEncoding(String JavaDoc encodingName) {
828
829         /*
830          * create a PDFEncoding with the next object number and add to the
831          * list of objects
832          */

833         PDFEncoding encoding = new PDFEncoding(++this.objectcount,
834                                                encodingName);
835         this.objects.add(encoding);
836         return encoding;
837     }
838
839
840     public PDFICCStream makePDFICCStream() {
841         PDFICCStream iccStream = new PDFICCStream(++this.objectcount);
842         this.objects.add(iccStream);
843         return iccStream;
844     }
845
846     /**
847      * make a Type1 /Font object
848      *
849      * @param fontname internal name to use for this font (eg "F1")
850      * @param basefont name of the base font (eg "Helvetica")
851      * @param encoding character encoding scheme used by the font
852      * @param metrics additional information about the font
853      * @param descriptor additional information about the font
854      * @return the created /Font object
855      */

856     public PDFFont makeFont(String JavaDoc fontname, String JavaDoc basefont,
857                             String JavaDoc encoding, FontMetric metrics,
858                             FontDescriptor descriptor) {
859
860         /*
861          * create a PDFFont with the next object number and add to the
862          * list of objects
863          */

864         if (descriptor == null) {
865             PDFFont font = new PDFFont(++this.objectcount, fontname,
866                                        PDFFont.TYPE1, basefont, encoding);
867             this.objects.add(font);
868             return font;
869         } else {
870             byte subtype = PDFFont.TYPE1;
871             if (metrics instanceof org.apache.fop.render.pdf.Font)
872                 subtype =
873                     ((org.apache.fop.render.pdf.Font)metrics).getSubType();
874
875             PDFFontDescriptor pdfdesc = makeFontDescriptor(descriptor,
876                                         subtype);
877
878             PDFFontNonBase14 font = null;
879             if (subtype == PDFFont.TYPE0) {
880                 /*
881                  * Temporary commented out - customized CMaps
882                  * isn't needed until /ToUnicode support is added
883                  * PDFCMap cmap = new PDFCMap(++this.objectcount,
884                  * "fop-ucs-H",
885                  * new PDFCIDSystemInfo("Adobe",
886                  * "Identity",
887                  * 0));
888                  * cmap.addContents();
889                  * this.objects.add(cmap);
890                  */

891                 font =
892                     (PDFFontNonBase14)PDFFont.createFont(++this.objectcount,
893                                                          fontname, subtype,
894                                                          basefont,
895                                                          "Identity-H");
896             } else {
897
898                 font =
899                     (PDFFontNonBase14)PDFFont.createFont(++this.objectcount,
900                                                          fontname, subtype,
901                                                          basefont, encoding);
902             }
903             this.objects.add(font);
904
905             font.setDescriptor(pdfdesc);
906
907             if (subtype == PDFFont.TYPE0) {
908                 CIDFont cidMetrics;
909                 if(metrics instanceof LazyFont){
910                     cidMetrics = (CIDFont) ((LazyFont) metrics).getRealFont();
911                 }else{
912                     cidMetrics = (CIDFont)metrics;
913                 }
914                 PDFCIDSystemInfo sysInfo =
915                     new PDFCIDSystemInfo(cidMetrics.getRegistry(),
916                                          cidMetrics.getOrdering(),
917                                          cidMetrics.getSupplement());
918                 PDFCIDFont cidFont =
919                     new PDFCIDFont(++this.objectcount, basefont,
920                                    cidMetrics.getCidType(),
921                                    cidMetrics.getDefaultWidth(),
922                                    cidMetrics.getWidths(), sysInfo,
923                                    (PDFCIDFontDescriptor)pdfdesc);
924                 this.objects.add(cidFont);
925
926                 // ((PDFFontType0)font).setCMAP(cmap);
927

928                 ((PDFFontType0)font).setDescendantFonts(cidFont);
929             } else {
930                 font.setWidthMetrics(metrics.getFirstChar(),
931                                      metrics.getLastChar(),
932                                      makeArray(metrics.getWidths(1)));
933             }
934
935             return font;
936         }
937     }
938
939
940     /**
941      * make a /FontDescriptor object
942      */

943     public PDFFontDescriptor makeFontDescriptor(FontDescriptor desc,
944             byte subtype) {
945         PDFFontDescriptor font = null;
946
947         if (subtype == PDFFont.TYPE0) {
948             // CID Font
949
font = new PDFCIDFontDescriptor(++this.objectcount,
950                                             desc.fontName(),
951                                             desc.getFontBBox(),
952                                             // desc.getAscender(),
953
// desc.getDescender(),
954
desc.getCapHeight(), desc.getFlags(),
955                                             // new PDFRectangle(desc.getFontBBox()),
956
desc.getItalicAngle(), desc.getStemV(), null); // desc.getLang(),
957
// null);//desc.getPanose());
958
}
959         else {
960             // Create normal FontDescriptor
961
font = new PDFFontDescriptor(++this.objectcount, desc.fontName(),
962                                          desc.getAscender(),
963                                          desc.getDescender(),
964                                          desc.getCapHeight(),
965                                          desc.getFlags(),
966                                          new PDFRectangle(desc.getFontBBox()),
967                                          desc.getStemV(),
968                                          desc.getItalicAngle());
969         }
970         this.objects.add(font);
971
972         // Check if the font is embeddable
973
if (desc.isEmbeddable()) {
974             PDFStream stream = desc.getFontFile(this.objectcount + 1);
975             if (stream != null) {
976                 this.objectcount++;
977                 font.setFontFile(desc.getSubType(), stream);
978                 this.objects.add(stream);
979             }
980         }
981         return font;
982     }
983
984
985     /**
986      * make an Array object (ex. Widths array for a font)
987      */

988     public PDFArray makeArray(int[] values) {
989
990         PDFArray array = new PDFArray(++this.objectcount, values);
991         this.objects.add(array);
992         return array;
993     }
994
995
996     public int addImage(FopImage img) {
997         // check if already created
998
String JavaDoc url = img.getURL();
999         PDFXObject xObject = (PDFXObject)this.xObjectsMap.get(url);
1000        if (xObject != null)
1001            return xObject.getXNumber();
1002        // else, create a new one
1003
xObject = new PDFXObject(++this.objectcount, ++this.xObjectCount, img, this);
1004        this.objects.add(xObject);
1005        this.xObjects.add(xObject);
1006        this.xObjectsMap.put(url, xObject);
1007        return xObjectCount;
1008    }
1009
1010    /**
1011     * make a /Page object
1012     *
1013     * @param resources resources object to use
1014     * @param contents stream object with content
1015     * @param pagewidth width of the page in points
1016     * @param pageheight height of the page in points
1017     *
1018     * @return the created /Page object
1019     */

1020    public PDFPage makePage(PDFResources resources, PDFStream contents,
1021                            int pagewidth, int pageheight, Page currentPage) {
1022
1023        /*
1024         * create a PDFPage with the next object number, the given
1025         * resources, contents and dimensions
1026         */

1027        PDFPage page = new PDFPage(++this.objectcount, resources, contents,
1028                                   pagewidth, pageheight);
1029
1030        if(pendingLinks != null) {
1031            for(int i = 0; i< pendingLinks.size(); i++ ) {
1032                PendingLink pl = (PendingLink)pendingLinks.get(i);
1033                PDFGoTo gt = new PDFGoTo(++this.objectcount,
1034                                         page.referencePDF());
1035                gt.setDestination(pl.dest);
1036                addTrailerObject(gt);
1037                PDFInternalLink internalLink =
1038                                 new PDFInternalLink(gt.referencePDF());
1039                pl.link.setAction(internalLink);
1040            }
1041            pendingLinks = null;
1042        }
1043
1044        if (currentPage != null) {
1045            for(int i = 0; i< currentPage.getIDList().size(); i++ ) {
1046                String JavaDoc id = currentPage.getIDList().get(i).toString();
1047                idReferences.setInternalGoToPageReference(id,
1048                        page.referencePDF());
1049            }
1050        }
1051
1052        /* add it to the list of objects */
1053        this.objects.add(page);
1054
1055        /* add the page to the Root */
1056        this.root.addPage(page);
1057
1058        return page;
1059    }
1060
1061    /**
1062     * make a link object
1063     *
1064     * @param rect the clickable rectangle
1065     * @param destination the destination file
1066     * @param linkType the link type
1067     * @return the PDFLink object created
1068     */

1069    public PDFLink makeLink(Rectangle JavaDoc rect, String JavaDoc destination,
1070                            int linkType) {
1071
1072        PDFLink linkObject;
1073        PDFAction action;
1074        int index;
1075
1076        PDFLink link = new PDFLink(++this.objectcount, rect);
1077        this.objects.add(link);
1078
1079        if (linkType == LinkSet.EXTERNAL) {
1080            // check destination
1081
if (destination.endsWith(".pdf")) { // FileSpec
1082
PDFFileSpec fileSpec = new PDFFileSpec(++this.objectcount,
1083                                                       destination);
1084                this.objects.add(fileSpec);
1085                action = new PDFGoToRemote(++this.objectcount, fileSpec);
1086                this.objects.add(action);
1087                link.setAction(action);
1088             } else if ((index = destination.indexOf(".pdf#page=")) > 0) {
1089                 String JavaDoc file = destination.substring(0, index + 4);
1090                 int page = Integer.parseInt(destination.substring(index + 10));
1091                 PDFFileSpec fileSpec = new PDFFileSpec(++this.objectcount, file);
1092                 this.objects.add(fileSpec);
1093                 action = new PDFGoToRemote(++this.objectcount, fileSpec, page);
1094                 this.objects.add(action);
1095                 link.setAction(action);
1096             } else if ((index = destination.indexOf(".pdf#dest=")) > 0) {
1097                 String JavaDoc file = destination.substring(0, index + 4);
1098                 String JavaDoc dest = destination.substring(index + 10);
1099                 PDFFileSpec fileSpec = new PDFFileSpec(++this.objectcount, file);
1100                 this.objects.add(fileSpec);
1101                 action = new PDFGoToRemote(++this.objectcount, fileSpec, dest);
1102                 this.objects.add(action);
1103                 link.setAction(action);
1104            } else { // URI
1105
PDFUri uri = new PDFUri(destination);
1106                link.setAction(uri);
1107            }
1108        } else { // linkType is internal
1109
String JavaDoc goToReference = getGoToReference(destination);
1110            PDFInternalLink internalLink = new PDFInternalLink(goToReference);
1111            link.setAction(internalLink);
1112        }
1113        return link;
1114    }
1115
1116    private String JavaDoc getGoToReference(String JavaDoc destination) {
1117        String JavaDoc goToReference;
1118        if (idReferences.doesIDExist(destination)) {
1119            if (idReferences.doesGoToReferenceExist(destination)) {
1120                goToReference =
1121                    idReferences.getInternalLinkGoToReference(destination);
1122            } else { // assign Internal Link GoTo object
1123
goToReference =
1124                    idReferences.createInternalLinkGoTo(destination,
1125                                                        ++this.objectcount);
1126                addTrailerObject(idReferences.getPDFGoTo(destination));
1127            }
1128        } else { // id was not found, so create it
1129

1130            //next line by lmckenzi@ca.ibm.com
1131
//solves when IDNode made before IDReferences.createID called
1132
//idReferences.createNewId(destination);
1133

1134            idReferences.createUnvalidatedID(destination);
1135            idReferences.addToIdValidationList(destination);
1136            goToReference = idReferences.createInternalLinkGoTo(destination,
1137                            ++this.objectcount);
1138            addTrailerObject(idReferences.getPDFGoTo(destination));
1139        }
1140        return goToReference;
1141    }
1142
1143    public void addTrailerObject(PDFObject object) {
1144        this.trailerObjects.add(object);
1145    }
1146
1147    class PendingLink {
1148        PDFLink link;
1149        String JavaDoc dest;
1150    }
1151
1152    public PDFLink makeLinkCurrentPage(Rectangle JavaDoc rect, String JavaDoc dest) {
1153        PDFLink link = new PDFLink(++this.objectcount, rect);
1154        this.objects.add(link);
1155        PendingLink pl = new PendingLink();
1156        pl.link = link;
1157        pl.dest = dest;
1158        if(pendingLinks == null) {
1159            pendingLinks = new java.util.ArrayList JavaDoc();
1160        }
1161        pendingLinks.add(pl);
1162
1163        return link;
1164    }
1165
1166    public PDFLink makeLink(Rectangle JavaDoc rect, String JavaDoc page, String JavaDoc dest) {
1167        PDFLink link = new PDFLink(++this.objectcount, rect);
1168        this.objects.add(link);
1169
1170        PDFGoTo gt = new PDFGoTo(++this.objectcount, page);
1171        gt.setDestination(dest);
1172        addTrailerObject(gt);
1173        PDFInternalLink internalLink = new PDFInternalLink(gt.referencePDF());
1174        link.setAction(internalLink);
1175
1176        return link;
1177    }
1178
1179    /**
1180      Ensure there is room in the locations xref for the number of
1181      objects that have been created.
1182     */

1183    private void prepareLocations() {
1184        while(location.size() < objectcount)
1185            location.add(locationPlaceholder);
1186    }
1187
1188    /**
1189     * make a stream object
1190     *
1191     * @return the stream object created
1192     */

1193    public PDFStream makeStream() {
1194
1195        /*
1196         * create a PDFStream with the next object number and add it
1197         *
1198         * to the list of objects
1199         */

1200        PDFStream obj = new PDFStream(++this.objectcount);
1201        obj.addDefaultFilters();
1202        if (this.encryption != null) {
1203            obj.addFilter(this.encryption.makeFilter(obj.number,obj.generation));
1204        }
1205
1206        this.objects.add(obj);
1207        return obj;
1208    }
1209
1210
1211    /**
1212     * make an annotation list object
1213     *
1214     * @return the annotation list object created
1215     */

1216    public PDFAnnotList makeAnnotList() {
1217
1218        /*
1219         * create a PDFAnnotList with the next object number and add it
1220         * to the list of objects
1221         */

1222        PDFAnnotList obj = new PDFAnnotList(++this.objectcount);
1223        this.objects.add(obj);
1224        return obj;
1225    }
1226
1227    /**
1228     * Get the root Outlines object. This method does not write
1229     * the outline to the PDF document, it simply creates a
1230     * reference for later.
1231     */

1232    public PDFOutline getOutlineRoot() {
1233        if(outlineRoot != null)
1234            return outlineRoot;
1235
1236        outlineRoot = new PDFOutline(++this.objectcount, null, null);
1237        addTrailerObject(outlineRoot);
1238        root.setRootOutline(outlineRoot);
1239        return outlineRoot;
1240    }
1241
1242    /**
1243     * Make an outline object and add it to the given outline
1244     * @param parent parent PDFOutline object
1245     * @param label the title for the new outline object
1246     * @param action the PDFAction to reference
1247     */

1248    public PDFOutline makeOutline(PDFOutline parent, String JavaDoc label,
1249                                  String JavaDoc destination) {
1250        String JavaDoc goToRef = getGoToReference(destination);
1251
1252        PDFOutline obj = new PDFOutline(++this.objectcount, label, goToRef);
1253        //log.debug("created new outline object");
1254

1255        if (parent != null) {
1256            parent.addOutline(obj);
1257        }
1258        this.objects.add(obj);
1259        return obj;
1260
1261    }
1262
1263    /**
1264     * get the /Resources object for the document
1265     *
1266     * @return the /Resources object
1267     */

1268    public PDFResources getResources() {
1269        return this.resources;
1270    }
1271
1272    /**
1273     * write the entire document out
1274     *
1275     * @param writer the OutputStream to output the document to
1276     */

1277    public void output(OutputStream JavaDoc stream) throws IOException JavaDoc {
1278
1279        prepareLocations();
1280
1281        for (int i = 0; i < objects.size(); i++) {
1282            /* retrieve the object with the current number */
1283            PDFObject object = (PDFObject)objects.get(i);
1284
1285            /*
1286             * add the position of this object to the list of object
1287             * locations
1288             */

1289            location.set(object.getNumber() - 1,
1290                         new Integer JavaDoc(this.position));
1291
1292            /*
1293             * output the object and increment the character position
1294             * by the object's length
1295             */

1296            this.position += object.output(stream);
1297        }
1298
1299        this.objects.clear();
1300    }
1301
1302    /**
1303     * write the PDF header <P>
1304     *
1305     * This method must be called prior to formatting
1306     * and outputting AreaTrees.
1307     *
1308     * @param stream the OutputStream to write the header to
1309     * @return the number of bytes written
1310     */

1311    public void outputHeader(OutputStream JavaDoc stream)
1312    throws IOException JavaDoc {
1313        this.position=0;
1314
1315        byte[] pdf;
1316        try {
1317            pdf = ("%PDF-" + this.pdfVersion + "\n").getBytes(PDFDocument.ENCODING);
1318        } catch (UnsupportedEncodingException JavaDoc ue) {
1319            pdf = ("%PDF-" + this.pdfVersion + "\n").getBytes();
1320        }
1321        stream.write(pdf);
1322        this.position += pdf.length;
1323
1324        // output a binary comment as recommended by the PDF spec (3.4.1)
1325
byte[] bin = {
1326            (byte)'%', (byte)0xAA, (byte)0xAB, (byte)0xAC, (byte)0xAD,
1327            (byte)'\n'
1328        };
1329        stream.write(bin);
1330        this.position += bin.length;
1331
1332        this.resources.setXObjects(xObjects);
1333    }
1334
1335    /**
1336     * write the trailer
1337     *
1338     * @param stream the OutputStream to write the trailer to
1339     */

1340    public void outputTrailer(OutputStream JavaDoc stream)
1341    throws IOException JavaDoc {
1342        output(stream);
1343        for (int i = 0; i < trailerObjects.size(); i++) {
1344            PDFObject o = (PDFObject) trailerObjects.get(i);
1345            this.location.set(o.getNumber() - 1, new Integer JavaDoc(this.position));
1346            this.position += o.output(stream);
1347        }
1348        /* output the xref table and increment the character position
1349          by the table's length */

1350        this.position += outputXref(stream);
1351
1352        // Determine existance of encryption dictionary
1353
String JavaDoc encryptEntry = "";
1354        
1355        if (this.encryption != null) {
1356          encryptEntry =
1357            "/Encrypt " + this.encryption.number + " " + this.encryption.generation + " R\n"+
1358            "/ID[<"+this.encryption.getFileID(1)+"><"+this.encryption.getFileID(2)+">]\n";
1359        }
1360
1361        /* construct the trailer */
1362        String JavaDoc pdf =
1363            "trailer\n" +
1364            "<<\n" +
1365            "/Size " + (this.objectcount + 1) + "\n" +
1366            "/Root " + this.root.number + " " + this.root.generation + " R\n" +
1367            "/Info " + this.info.number + " " + this.info.generation + " R\n" +
1368            encryptEntry +
1369            ">>\n" +
1370            "startxref\n" +
1371            this.xref + "\n" +
1372            "%%EOF\n";
1373
1374        /* write the trailer */
1375        byte[] trailer;
1376        try {
1377            trailer = pdf.getBytes(PDFDocument.ENCODING);
1378        } catch (UnsupportedEncodingException JavaDoc ue) {
1379            trailer = pdf.getBytes();
1380        }
1381        stream.write(trailer);
1382    }
1383
1384    /**
1385     * write the xref table
1386     *
1387     * @param stream the OutputStream to write the xref table to
1388     * @return the number of characters written
1389     */

1390    private int outputXref(OutputStream JavaDoc stream) throws IOException JavaDoc {
1391
1392        /* remember position of xref table */
1393        this.xref = this.position;
1394
1395        /* construct initial part of xref */
1396        StringBuffer JavaDoc pdf = new StringBuffer JavaDoc("xref\n0 "
1397                                            + (this.objectcount + 1)
1398                                            + "\n0000000000 65535 f \n");
1399
1400        for (int i = 0; i< this.location.size(); i++ ) {
1401            String JavaDoc x = this.location.get(i).toString();
1402
1403            /* contruct xref entry for object */
1404            String JavaDoc padding = "0000000000";
1405            String JavaDoc loc = padding.substring(x.length()) + x;
1406
1407            /* append to xref table */
1408            pdf = pdf.append(loc + " 00000 n \n");
1409        }
1410
1411        /* write the xref table and return the character length */
1412        byte[] pdfBytes;
1413        try {
1414            pdfBytes = pdf.toString().getBytes(PDFDocument.ENCODING);
1415        } catch (UnsupportedEncodingException JavaDoc ue) {
1416            pdfBytes = pdf.toString().getBytes();
1417        }
1418        stream.write(pdfBytes);
1419        return pdfBytes.length;
1420    }
1421
1422    public void setIDReferences(IDReferences idReferences) {
1423        this.idReferences = idReferences;
1424    }
1425
1426    /**
1427     * Make a destination object and add it
1428     * @param label the title for the new destination object
1429     * @param dest the destination name to reference
1430     */

1431    public void addDestination(String JavaDoc destinationName, String JavaDoc internalDest) {
1432       if (!idReferences.doesIDExist(internalDest)) {
1433           idReferences.addToUnvalidatedIdList(internalDest);
1434       }
1435       PDFDestination obj = new PDFDestination(idReferences, destinationName, internalDest);
1436       root.getDestinations().add(obj);
1437    }
1438    
1439}
1440
Popular Tags