KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements. See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */

17
18 /* $Id: PDFFactory.java 454725 2006-10-10 13:00:05Z bdelacretaz $ */
19
20 package org.apache.fop.pdf;
21
22 // Java
23
import java.awt.geom.Rectangle2D JavaDoc;
24 import java.io.FileNotFoundException JavaDoc;
25 import java.io.IOException JavaDoc;
26 import java.io.InputStream JavaDoc;
27 import java.net.MalformedURLException JavaDoc;
28 import java.util.BitSet JavaDoc;
29 import java.util.Iterator JavaDoc;
30 import java.util.List JavaDoc;
31 import java.util.Map JavaDoc;
32 import javax.xml.transform.Source JavaDoc;
33 import javax.xml.transform.stream.StreamSource JavaDoc;
34
35 // Apache libs
36
import org.apache.commons.io.IOUtils;
37 import org.apache.commons.io.output.ByteArrayOutputStream;
38 import org.apache.commons.logging.Log;
39 import org.apache.commons.logging.LogFactory;
40
41 // FOP
42
import org.apache.fop.fonts.CIDFont;
43 import org.apache.fop.fonts.CustomFont;
44 import org.apache.fop.fonts.Typeface;
45 import org.apache.fop.fonts.FontDescriptor;
46 import org.apache.fop.fonts.FontMetrics;
47 import org.apache.fop.fonts.FontType;
48 import org.apache.fop.fonts.LazyFont;
49 import org.apache.fop.fonts.MultiByteFont;
50 import org.apache.fop.fonts.truetype.FontFileReader;
51 import org.apache.fop.fonts.truetype.TTFSubSetFile;
52 import org.apache.fop.fonts.type1.PFBData;
53 import org.apache.fop.fonts.type1.PFBParser;
54 import org.apache.xmlgraphics.xmp.Metadata;
55
56 /**
57  * This class provides method to create and register PDF objects.
58  */

59 public class PDFFactory {
60
61     private PDFDocument document;
62
63     private Log log = LogFactory.getLog(PDFFactory.class);
64
65     /**
66      * Creates a new PDFFactory.
67      * @param document the parent PDFDocument needed to register the generated
68      * objects
69      */

70     public PDFFactory(PDFDocument document) {
71         this.document = document;
72     }
73
74     /**
75      * Returns the parent PDFDocument associated with this factory.
76      * @return PDFDocument the parent PDFDocument
77      */

78     public final PDFDocument getDocument() {
79         return this.document;
80     }
81
82     /* ========================= structure objects ========================= */
83
84     /**
85      * Make a /Catalog (Root) object. This object is written in
86      * the trailer.
87      *
88      * @param pages the pages pdf object that the root points to
89      * @return the new pdf root object for this document
90      */

91     public PDFRoot makeRoot(PDFPages pages) {
92         //Make a /Pages object. This object is written in the trailer.
93
PDFRoot pdfRoot = new PDFRoot(++this.document.objectcount, pages);
94         pdfRoot.setDocument(getDocument());
95         getDocument().addTrailerObject(pdfRoot);
96         return pdfRoot;
97     }
98
99     /**
100      * Make a /Pages object. This object is written in the trailer.
101      *
102      * @return a new PDF Pages object for adding pages to
103      */

104     public PDFPages makePages() {
105         PDFPages pdfPages = new PDFPages(++(this.document.objectcount));
106         pdfPages.setDocument(getDocument());
107         getDocument().addTrailerObject(pdfPages);
108         return pdfPages;
109     }
110
111     /**
112      * Make a /Resources object. This object is written in the trailer.
113      *
114      * @return a new PDF resources object
115      */

116     public PDFResources makeResources() {
117         PDFResources pdfResources = new PDFResources(++this.document.objectcount);
118         pdfResources.setDocument(getDocument());
119         getDocument().addTrailerObject(pdfResources);
120         return pdfResources;
121     }
122
123     /**
124      * make an /Info object
125      *
126      * @param prod string indicating application producing the PDF
127      * @return the created /Info object
128      */

129     protected PDFInfo makeInfo(String JavaDoc prod) {
130
131         /*
132          * create a PDFInfo with the next object number and add to
133          * list of objects
134          */

135         PDFInfo pdfInfo = new PDFInfo();
136         // set the default producer
137
pdfInfo.setProducer(prod);
138         getDocument().registerObject(pdfInfo);
139         return pdfInfo;
140     }
141
142     /**
143      * Make a Metadata object.
144      * @param doc the DOM Document containing the XMP metadata.
145      * @param readOnly true if the metadata packet should be marked read-only
146      * @return the newly created Metadata object
147      */

148     public PDFMetadata makeMetadata(Metadata meta, boolean readOnly) {
149         PDFMetadata pdfMetadata = new PDFMetadata(meta, readOnly);
150         getDocument().registerObject(pdfMetadata);
151         return pdfMetadata;
152     }
153
154     /**
155      * Make a OutputIntent dictionary.
156      * @return the newly created OutputIntent dictionary
157      */

158     public PDFOutputIntent makeOutputIntent() {
159         PDFOutputIntent outputIntent = new PDFOutputIntent();
160         getDocument().registerObject(outputIntent);
161         return outputIntent;
162     }
163
164     /**
165      * Make a /Page object. The page is assigned an object number immediately
166      * so references can already be made. The page must be added to the
167      * PDFDocument later using addObject().
168      *
169      * @param resources resources object to use
170      * @param pageWidth width of the page in points
171      * @param pageHeight height of the page in points
172      * @param pageIndex index of the page (zero-based)
173      *
174      * @return the created /Page object
175      */

176     public PDFPage makePage(PDFResources resources,
177                             int pageWidth, int pageHeight, int pageIndex) {
178
179         /*
180          * create a PDFPage with the next object number, the given
181          * resources, contents and dimensions
182          */

183         PDFPage page = new PDFPage(resources,
184                                    pageWidth, pageHeight, pageIndex);
185
186         getDocument().assignObjectNumber(page);
187         getDocument().getPages().addPage(page);
188         return page;
189     }
190
191     /**
192      * Make a /Page object. The page is assigned an object number immediately
193      * so references can already be made. The page must be added to the
194      * PDFDocument later using addObject().
195      *
196      * @param resources resources object to use
197      * @param pageWidth width of the page in points
198      * @param pageHeight height of the page in points
199      *
200      * @return the created /Page object
201      */

202     public PDFPage makePage(PDFResources resources,
203                             int pageWidth, int pageHeight) {
204         return makePage(resources, pageWidth, pageHeight, -1);
205     }
206
207     /* ========================= functions ================================= */
208
209     /**
210      * Make a Type 0 sampled function
211      *
212      * @param theDomain List objects of Double objects.
213      * This is the domain of the function.
214      * See page 264 of the PDF 1.3 Spec.
215      * @param theRange List objects of Double objects.
216      * This is the Range of the function.
217      * See page 264 of the PDF 1.3 Spec.
218      * @param theSize A List object of Integer objects.
219      * This is the number of samples in each input dimension.
220      * I can't imagine there being more or less than two input dimensions,
221      * so maybe this should be an array of length 2.
222      *
223      * See page 265 of the PDF 1.3 Spec.
224      * @param theBitsPerSample An int specifying the number of bits user
225      * to represent each sample value.
226      * Limited to 1,2,4,8,12,16,24 or 32.
227      * See page 265 of the 1.3 PDF Spec.
228      * @param theOrder The order of interpolation between samples.
229      * Default is 1 (one). Limited
230      * to 1 (one) or 3, which means linear or cubic-spline interpolation.
231      *
232      * This attribute is optional.
233      *
234      * See page 265 in the PDF 1.3 spec.
235      * @param theEncode List objects of Double objects.
236      * This is the linear mapping of input values intop the domain
237      * of the function's sample table. Default is hard to represent in
238      * ascii, but basically [0 (Size0 1) 0 (Size1 1)...].
239      * This attribute is optional.
240      *
241      * See page 265 in the PDF 1.3 spec.
242      * @param theDecode List objects of Double objects.
243      * This is a linear mapping of sample values into the range.
244      * The default is just the range.
245      *
246      * This attribute is optional.
247      * Read about it on page 265 of the PDF 1.3 spec.
248      * @param theFunctionDataStream The sample values that specify
249      * the function are provided in a stream.
250      *
251      * This is optional, but is almost always used.
252      *
253      * Page 265 of the PDF 1.3 spec has more.
254      * @param theFilter This is a vector of String objects which
255      * are the various filters that have are to be
256      * applied to the stream to make sense of it.
257      * Order matters, so watch out.
258      *
259      * This is not documented in the Function section of the PDF 1.3 spec,
260      * it was deduced from samples that this is sometimes used, even if we may never
261      * use it in FOP. It is added for completeness sake.
262      * @param theFunctionType This is the type of function (0,2,3, or 4).
263      * It should be 0 as this is the constructor for sampled functions.
264      * @return the PDF function that was created
265      */

266     public PDFFunction makeFunction(int theFunctionType, List JavaDoc theDomain,
267                                     List JavaDoc theRange, List JavaDoc theSize,
268                                     int theBitsPerSample, int theOrder,
269                                     List JavaDoc theEncode, List JavaDoc theDecode,
270                                     StringBuffer JavaDoc theFunctionDataStream,
271                                     List JavaDoc theFilter) {
272         // Type 0 function
273
PDFFunction function = new PDFFunction(theFunctionType, theDomain,
274                                                theRange, theSize,
275                                                theBitsPerSample, theOrder,
276                                                theEncode, theDecode,
277                                                theFunctionDataStream,
278                                                theFilter);
279
280         PDFFunction oldfunc = getDocument().findFunction(function);
281         if (oldfunc == null) {
282             getDocument().registerObject(function);
283         } else {
284             function = oldfunc;
285         }
286         return (function);
287     }
288
289     /**
290      * make a type Exponential interpolation function
291      * (for shading usually)
292      *
293      * @param theDomain List objects of Double objects.
294      * This is the domain of the function.
295      * See page 264 of the PDF 1.3 Spec.
296      * @param theRange List of Doubles that is the Range of the function.
297      * See page 264 of the PDF 1.3 Spec.
298      * @param theCZero This is a vector of Double objects which defines the function result
299      * when x=0.
300      *
301      * This attribute is optional.
302      * It's described on page 268 of the PDF 1.3 spec.
303      * @param theCOne This is a vector of Double objects which defines the function result
304      * when x=1.
305      *
306      * This attribute is optional.
307      * It's described on page 268 of the PDF 1.3 spec.
308      * @param theInterpolationExponentN This is the inerpolation exponent.
309      *
310      * This attribute is required.
311      * PDF Spec page 268
312      * @param theFunctionType The type of the function, which should be 2.
313      * @return the PDF function that was created
314      */

315     public PDFFunction makeFunction(int theFunctionType, List JavaDoc theDomain,
316                                     List JavaDoc theRange, List JavaDoc theCZero,
317                                     List JavaDoc theCOne,
318                                     double theInterpolationExponentN) { // type 2
319
PDFFunction function = new PDFFunction(theFunctionType, theDomain,
320                                                theRange, theCZero, theCOne,
321                                                theInterpolationExponentN);
322         PDFFunction oldfunc = getDocument().findFunction(function);
323         if (oldfunc == null) {
324             getDocument().registerObject(function);
325         } else {
326             function = oldfunc;
327         }
328         return (function);
329     }
330
331     /**
332      * Make a Type 3 Stitching function
333      *
334      * @param theDomain List objects of Double objects.
335      * This is the domain of the function.
336      * See page 264 of the PDF 1.3 Spec.
337      * @param theRange List objects of Double objects.
338      * This is the Range of the function.
339      * See page 264 of the PDF 1.3 Spec.
340      * @param theFunctions An List of the PDFFunction objects
341      * that the stitching function stitches.
342      *
343      * This attributed is required.
344      * It is described on page 269 of the PDF spec.
345      * @param theBounds This is a vector of Doubles representing
346      * the numbers that, in conjunction with Domain
347      * define the intervals to which each function from
348      * the 'functions' object applies. It must be in
349      * order of increasing magnitude, and each must be
350      * within Domain.
351      *
352      * It basically sets how much of the gradient each function handles.
353      *
354      * This attributed is required.
355      * It's described on page 269 of the PDF 1.3 spec.
356      * @param theEncode List objects of Double objects.
357      * This is the linear mapping of input values intop the domain
358      * of the function's sample table. Default is hard to represent in
359      * ascii, but basically [0 (Size0 1) 0 (Size1 1)...].
360      * This attribute is required.
361      *
362      * See page 270 in the PDF 1.3 spec.
363      * @param theFunctionType This is the function type. It should be 3,
364      * for a stitching function.
365      * @return the PDF function that was created
366      */

367     public PDFFunction makeFunction(int theFunctionType, List JavaDoc theDomain,
368                                     List JavaDoc theRange, List JavaDoc theFunctions,
369                                     List JavaDoc theBounds,
370                                     List JavaDoc theEncode) {
371         // Type 3
372

373         PDFFunction function = new PDFFunction(theFunctionType, theDomain,
374                                                theRange, theFunctions,
375                                                theBounds, theEncode);
376
377         PDFFunction oldfunc = getDocument().findFunction(function);
378         if (oldfunc == null) {
379             getDocument().registerObject(function);
380         } else {
381             function = oldfunc;
382         }
383         return (function);
384     }
385
386     /**
387      * make a postscript calculator function
388      *
389      * @param theNumber the PDF object number
390      * @param theFunctionType the type of function to make
391      * @param theDomain the domain values
392      * @param theRange the range values of the function
393      * @param theFunctionDataStream a string containing the pdf drawing
394      * @return the PDF function that was created
395      */

396     public PDFFunction makeFunction(int theNumber, int theFunctionType,
397                                     List JavaDoc theDomain, List JavaDoc theRange,
398                                     StringBuffer JavaDoc theFunctionDataStream) {
399         // Type 4
400
PDFFunction function = new PDFFunction(theFunctionType, theDomain,
401                                                theRange,
402                                                theFunctionDataStream);
403
404         PDFFunction oldfunc = getDocument().findFunction(function);
405         if (oldfunc == null) {
406             getDocument().registerObject(function);
407         } else {
408             function = oldfunc;
409         }
410         return (function);
411
412     }
413
414     /* ========================= shadings ================================== */
415
416     /**
417      * make a function based shading object
418      *
419      * @param res the PDF resource context to add the shading, may be null
420      * @param theShadingType The type of shading object, which should be 1 for function
421      * based shading.
422      * @param theColorSpace The colorspace is 'DeviceRGB' or something similar.
423      * @param theBackground An array of color components appropriate to the
424      * colorspace key specifying a single color value.
425      * This key is used by the f operator buy ignored by the sh operator.
426      * @param theBBox List of double's representing a rectangle
427      * in the coordinate space that is current at the
428      * time of shading is imaged. Temporary clipping
429      * boundary.
430      * @param theAntiAlias Whether or not to anti-alias.
431      * @param theDomain Optional vector of Doubles specifying the domain.
432      * @param theMatrix List of Doubles specifying the matrix.
433      * If it's a pattern, then the matrix maps it to pattern space.
434      * If it's a shading, then it maps it to current user space.
435      * It's optional, the default is the identity matrix
436      * @param theFunction The PDF Function that maps an (x,y) location to a color
437      * @return the PDF shading that was created
438      */

439     public PDFShading makeShading(PDFResourceContext res, int theShadingType,
440                                   PDFDeviceColorSpace theColorSpace,
441                                   List JavaDoc theBackground, List JavaDoc theBBox,
442                                   boolean theAntiAlias, List JavaDoc theDomain,
443                                   List JavaDoc theMatrix,
444                                   PDFFunction theFunction) {
445         // make Shading of Type 1
446
PDFShading shading = new PDFShading(theShadingType,
447                                             theColorSpace, theBackground,
448                                             theBBox, theAntiAlias, theDomain,
449                                             theMatrix, theFunction);
450
451         PDFShading oldshad = getDocument().findShading(shading);
452         if (oldshad == null) {
453             getDocument().registerObject(shading);
454         } else {
455             shading = oldshad;
456         }
457
458         // add this shading to resources
459
if (res != null) {
460             res.getPDFResources().addShading(shading);
461         } else {
462             getDocument().getResources().addShading(shading);
463         }
464
465         return (shading);
466     }
467
468     /**
469      * Make an axial or radial shading object.
470      *
471      * @param res the PDF resource context to add the shading, may be null
472      * @param theShadingType 2 or 3 for axial or radial shading
473      * @param theColorSpace "DeviceRGB" or similar.
474      * @param theBackground theBackground An array of color components appropriate to the
475      * colorspace key specifying a single color value.
476      * This key is used by the f operator buy ignored by the sh operator.
477      * @param theBBox List of double's representing a rectangle
478      * in the coordinate space that is current at the
479      * time of shading is imaged. Temporary clipping
480      * boundary.
481      * @param theAntiAlias Default is false
482      * @param theCoords List of four (type 2) or 6 (type 3) Double
483      * @param theDomain List of Doubles specifying the domain
484      * @param theFunction the Stitching (PDFfunction type 3) function,
485      * even if it's stitching a single function
486      * @param theExtend List of Booleans of whether to extend the
487      * start and end colors past the start and end points
488      * The default is [false, false]
489      * @return the PDF shading that was created
490      */

491     public PDFShading makeShading(PDFResourceContext res, int theShadingType,
492                                   PDFDeviceColorSpace theColorSpace,
493                                   List JavaDoc theBackground, List JavaDoc theBBox,
494                                   boolean theAntiAlias, List JavaDoc theCoords,
495                                   List JavaDoc theDomain, PDFFunction theFunction,
496                                   List JavaDoc theExtend) {
497         // make Shading of Type 2 or 3
498
PDFShading shading = new PDFShading(theShadingType,
499                                             theColorSpace, theBackground,
500                                             theBBox, theAntiAlias, theCoords,
501                                             theDomain, theFunction,
502                                             theExtend);
503
504         PDFShading oldshad = getDocument().findShading(shading);
505         if (oldshad == null) {
506             getDocument().registerObject(shading);
507         } else {
508             shading = oldshad;
509         }
510
511         if (res != null) {
512             res.getPDFResources().addShading(shading);
513         } else {
514             getDocument().getResources().addShading(shading);
515         }
516
517         return (shading);
518     }
519
520     /**
521      * Make a free-form gouraud shaded triangle mesh, coons patch mesh, or tensor patch mesh
522      * shading object
523      *
524      * @param res the PDF resource context to add the shading, may be null
525      * @param theShadingType 4, 6, or 7 depending on whether it's
526      * Free-form gouraud-shaded triangle meshes, coons patch meshes,
527      * or tensor product patch meshes, respectively.
528      * @param theColorSpace "DeviceRGB" or similar.
529      * @param theBackground theBackground An array of color components appropriate to the
530      * colorspace key specifying a single color value.
531      * This key is used by the f operator buy ignored by the sh operator.
532      * @param theBBox List of double's representing a rectangle
533      * in the coordinate space that is current at the
534      * time of shading is imaged. Temporary clipping
535      * boundary.
536      * @param theAntiAlias Default is false
537      * @param theBitsPerCoordinate 1,2,4,8,12,16,24 or 32.
538      * @param theBitsPerComponent 1,2,4,8,12, and 16
539      * @param theBitsPerFlag 2,4,8.
540      * @param theDecode List of Doubles see PDF 1.3 spec pages 303 to 312.
541      * @param theFunction the PDFFunction
542      * @return the PDF shading that was created
543      */

544     public PDFShading makeShading(PDFResourceContext res, int theShadingType,
545                                   PDFDeviceColorSpace theColorSpace,
546                                   List JavaDoc theBackground, List JavaDoc theBBox,
547                                   boolean theAntiAlias,
548                                   int theBitsPerCoordinate,
549                                   int theBitsPerComponent,
550                                   int theBitsPerFlag, List JavaDoc theDecode,
551                                   PDFFunction theFunction) {
552         // make Shading of type 4,6 or 7
553
PDFShading shading = new PDFShading(theShadingType,
554                                             theColorSpace, theBackground,
555                                             theBBox, theAntiAlias,
556                                             theBitsPerCoordinate,
557                                             theBitsPerComponent,
558                                             theBitsPerFlag, theDecode,
559                                             theFunction);
560
561         PDFShading oldshad = getDocument().findShading(shading);
562         if (oldshad == null) {
563             getDocument().registerObject(shading);
564         } else {
565             shading = oldshad;
566         }
567
568         if (res != null) {
569             res.getPDFResources().addShading(shading);
570         } else {
571             getDocument().getResources().addShading(shading);
572         }
573
574         return (shading);
575     }
576
577     /**
578      * make a Lattice-Form Gouraud mesh shading object
579      *
580      * @param res the PDF resource context to add the shading, may be null
581      * @param theShadingType 5 for lattice-Form Gouraud shaded-triangle mesh
582      * without spaces. "Shading1" or "Sh1" are good examples.
583      * @param theColorSpace "DeviceRGB" or similar.
584      * @param theBackground theBackground An array of color components appropriate to the
585      * colorspace key specifying a single color value.
586      * This key is used by the f operator buy ignored by the sh operator.
587      * @param theBBox List of double's representing a rectangle
588      * in the coordinate space that is current at the
589      * time of shading is imaged. Temporary clipping
590      * boundary.
591      * @param theAntiAlias Default is false
592      * @param theBitsPerCoordinate 1,2,4,8,12,16, 24, or 32
593      * @param theBitsPerComponent 1,2,4,8,12,24,32
594      * @param theDecode List of Doubles. See page 305 in PDF 1.3 spec.
595      * @param theVerticesPerRow number of vertices in each "row" of the lattice.
596      * @param theFunction The PDFFunction that's mapped on to this shape
597      * @return the PDF shading that was created
598      */

599     public PDFShading makeShading(PDFResourceContext res, int theShadingType,
600                                   PDFDeviceColorSpace theColorSpace,
601                                   List JavaDoc theBackground, List JavaDoc theBBox,
602                                   boolean theAntiAlias,
603                                   int theBitsPerCoordinate,
604                                   int theBitsPerComponent, List JavaDoc theDecode,
605                                   int theVerticesPerRow,
606                                   PDFFunction theFunction) {
607         // make shading of Type 5
608
PDFShading shading = new PDFShading(theShadingType,
609                                             theColorSpace, theBackground,
610                                             theBBox, theAntiAlias,
611                                             theBitsPerCoordinate,
612                                             theBitsPerComponent, theDecode,
613                                             theVerticesPerRow, theFunction);
614
615         PDFShading oldshad = getDocument().findShading(shading);
616         if (oldshad == null) {
617             getDocument().registerObject(shading);
618         } else {
619             shading = oldshad;
620         }
621
622         if (res != null) {
623             res.getPDFResources().addShading(shading);
624         } else {
625             getDocument().getResources().addShading(shading);
626         }
627
628         return (shading);
629     }
630
631     /* ========================= patterns ================================== */
632
633     /**
634      * Make a tiling pattern
635      *
636      * @param res the PDF resource context to add the shading, may be null
637      * @param thePatternType the type of pattern, which is 1 for tiling.
638      * @param theResources the resources associated with this pattern
639      * @param thePaintType 1 or 2, colored or uncolored.
640      * @param theTilingType 1, 2, or 3, constant spacing, no distortion, or faster tiling
641      * @param theBBox List of Doubles: The pattern cell bounding box
642      * @param theXStep horizontal spacing
643      * @param theYStep vertical spacing
644      * @param theMatrix Optional List of Doubles transformation matrix
645      * @param theXUID Optional vector of Integers that uniquely identify the pattern
646      * @param thePatternDataStream The stream of pattern data to be tiled.
647      * @return the PDF pattern that was created
648      */

649     public PDFPattern makePattern(PDFResourceContext res, int thePatternType, // 1
650
PDFResources theResources, int thePaintType, int theTilingType,
651                                   List JavaDoc theBBox, double theXStep,
652                                   double theYStep, List JavaDoc theMatrix,
653                                   List JavaDoc theXUID, StringBuffer JavaDoc thePatternDataStream) {
654         // PDFResources theResources
655
PDFPattern pattern = new PDFPattern(theResources, 1,
656                                             thePaintType, theTilingType,
657                                             theBBox, theXStep, theYStep,
658                                             theMatrix, theXUID,
659                                             thePatternDataStream);
660
661         PDFPattern oldpatt = getDocument().findPattern(pattern);
662         if (oldpatt == null) {
663             getDocument().registerObject(pattern);
664         } else {
665             pattern = oldpatt;
666         }
667
668         if (res != null) {
669             res.getPDFResources().addPattern(pattern);
670         } else {
671             getDocument().getResources().addPattern(pattern);
672         }
673
674         return (pattern);
675     }
676
677     /**
678      * Make a smooth shading pattern
679      *
680      * @param res the PDF resource context to add the shading, may be null
681      * @param thePatternType the type of the pattern, which is 2, smooth shading
682      * @param theShading the PDF Shading object that comprises this pattern
683      * @param theXUID optional:the extended unique Identifier if used.
684      * @param theExtGState optional: the extended graphics state, if used.
685      * @param theMatrix Optional:List of Doubles that specify the matrix.
686      * @return the PDF pattern that was created
687      */

688     public PDFPattern makePattern(PDFResourceContext res,
689                                   int thePatternType, PDFShading theShading,
690                                   List JavaDoc theXUID, StringBuffer JavaDoc theExtGState,
691                                   List JavaDoc theMatrix) {
692         PDFPattern pattern = new PDFPattern(2, theShading,
693                                             theXUID, theExtGState, theMatrix);
694
695         PDFPattern oldpatt = getDocument().findPattern(pattern);
696         if (oldpatt == null) {
697             getDocument().registerObject(pattern);
698         } else {
699             pattern = oldpatt;
700         }
701
702         if (res != null) {
703             res.getPDFResources().addPattern(pattern);
704         } else {
705             getDocument().getResources().addPattern(pattern);
706         }
707
708         return (pattern);
709     }
710
711     /**
712      * Make a gradient
713      *
714      * @param res the PDF resource context to add the shading, may be null
715      * @param radial if true a radial gradient will be created
716      * @param theColorspace the colorspace of the gradient
717      * @param theColors the list of colors for the gradient
718      * @param theBounds the list of bounds associated with the colors
719      * @param theCoords the coordinates for the gradient
720      * @return the PDF pattern that was created
721      */

722     public PDFPattern makeGradient(PDFResourceContext res, boolean radial,
723                                    PDFDeviceColorSpace theColorspace,
724                                    List JavaDoc theColors, List JavaDoc theBounds,
725                                    List JavaDoc theCoords, List JavaDoc theMatrix) {
726         PDFShading myShad;
727         PDFFunction myfunky;
728         PDFFunction myfunc;
729         List JavaDoc theCzero;
730         List JavaDoc theCone;
731         PDFPattern myPattern;
732         //PDFColorSpace theColorSpace;
733
double interpolation = (double)1.000;
734         List JavaDoc theFunctions = new java.util.ArrayList JavaDoc();
735
736         int currentPosition;
737         int lastPosition = theColors.size() - 1;
738
739
740         // if 5 elements, the penultimate element is 3.
741
// do not go beyond that, because you always need
742
// to have a next color when creating the function.
743

744         for (currentPosition = 0; currentPosition < lastPosition;
745                 currentPosition++) { // for every consecutive color pair
746
PDFColor currentColor =
747                 (PDFColor)theColors.get(currentPosition);
748             PDFColor nextColor = (PDFColor)theColors.get(currentPosition
749                                  + 1);
750             // colorspace must be consistant
751
if (getDocument().getColorSpace()
752                     != currentColor.getColorSpace()) {
753                 currentColor.setColorSpace(
754                     getDocument().getColorSpace());
755             }
756
757             if (getDocument().getColorSpace()
758                     != nextColor.getColorSpace()) {
759                 nextColor.setColorSpace(
760                     getDocument().getColorSpace());
761             }
762
763             theCzero = currentColor.getVector();
764             theCone = nextColor.getVector();
765
766             myfunc = makeFunction(2, null, null, theCzero, theCone,
767                                        interpolation);
768
769             theFunctions.add(myfunc);
770
771         } // end of for every consecutive color pair
772

773         myfunky = makeFunction(3, null, null, theFunctions, theBounds,
774                                     null);
775
776         if (radial) {
777             if (theCoords.size() == 6) {
778                 myShad = makeShading(res, 3, getDocument().getPDFColorSpace(),
779                                      null, null,
780                                      false, theCoords, null, myfunky,
781                                      null);
782             } else { // if the center x, center y, and radius specifiy
783
// the gradient, then assume the same center x, center y,
784
// and radius of zero for the other necessary component
785
List JavaDoc newCoords = new java.util.ArrayList JavaDoc();
786                 newCoords.add(theCoords.get(0));
787                 newCoords.add(theCoords.get(1));
788                 newCoords.add(theCoords.get(2));
789                 newCoords.add(theCoords.get(0));
790                 newCoords.add(theCoords.get(1));
791                 newCoords.add(new Double JavaDoc(0.0));
792
793                 myShad = makeShading(res, 3, getDocument().getPDFColorSpace(),
794                                      null, null,
795                                      false, newCoords, null, myfunky,
796                                      null);
797
798             }
799         } else {
800             myShad = makeShading(res, 2, getDocument().getPDFColorSpace(),
801                                  null, null,
802                                  false, theCoords, null, myfunky,
803                                  null);
804
805         }
806
807         myPattern = makePattern(res, 2, myShad, null, null, theMatrix);
808
809         return (myPattern);
810     }
811
812     /* ========================= links ===================================== */
813
814     /**
815      * Make an internal link.
816      *
817      * @param rect the hotspot position in absolute coordinates
818      * @param page the target page reference value
819      * @param dest the position destination
820      * @return the new PDF link object
821      */

822     public PDFLink makeLink(Rectangle2D JavaDoc rect, String JavaDoc page, String JavaDoc dest) {
823         PDFLink link = new PDFLink(rect);
824         getDocument().registerObject(link);
825
826         PDFGoTo gt = new PDFGoTo(page);
827         gt.setDestination(dest);
828         getDocument().addTrailerObject(gt);
829         PDFInternalLink internalLink = new PDFInternalLink(gt.referencePDF());
830         link.setAction(internalLink);
831
832         return link;
833     }
834
835     /**
836      * make a link object
837      *
838      * @param rect the clickable rectangle
839      * @param destination the destination file
840      * @param linkType the link type
841      * @param yoffset the yoffset on the page for an internal link
842      * @return the PDFLink object created
843      */

844     public PDFLink makeLink(Rectangle2D JavaDoc rect, String JavaDoc destination,
845                             int linkType, float yoffset) {
846
847         //PDFLink linkObject;
848
int index;
849
850         PDFLink link = new PDFLink(rect);
851
852         if (linkType == PDFLink.EXTERNAL) {
853             // check destination
854
if (destination.startsWith("http://")) {
855                 PDFUri uri = new PDFUri(destination);
856                 link.setAction(uri);
857             } else if (destination.endsWith(".pdf")) { // FileSpec
858
PDFGoToRemote remote = getGoToPDFAction(destination, null, -1);
859                 link.setAction(remote);
860             } else if ((index = destination.indexOf(".pdf#page=")) > 0) {
861                 //String file = destination.substring(0, index + 4);
862
int page = Integer.parseInt(destination.substring(index + 10));
863                 PDFGoToRemote remote = getGoToPDFAction(destination, null, page);
864                 link.setAction(remote);
865             } else if ((index = destination.indexOf(".pdf#dest=")) > 0) {
866                 //String file = destination.substring(0, index + 4);
867
String JavaDoc dest = destination.substring(index + 10);
868                 PDFGoToRemote remote = getGoToPDFAction(destination, dest, -1);
869                 link.setAction(remote);
870             } else { // URI
871
PDFUri uri = new PDFUri(destination);
872                 link.setAction(uri);
873             }
874         } else {
875             // linkType is internal
876
String JavaDoc goToReference = getGoToReference(destination, yoffset);
877             PDFInternalLink internalLink = new PDFInternalLink(goToReference);
878             link.setAction(internalLink);
879         }
880
881         PDFLink oldlink = getDocument().findLink(link);
882         if (oldlink == null) {
883             getDocument().registerObject(link);
884         } else {
885             link = oldlink;
886         }
887
888         return link;
889     }
890
891     private String JavaDoc getGoToReference(String JavaDoc destination, float yoffset) {
892         getDocument().getProfile().verifyActionAllowed();
893         String JavaDoc goToReference = null;
894         PDFGoTo gt = new PDFGoTo(destination);
895         gt.setYPosition(yoffset);
896         PDFGoTo oldgt = getDocument().findGoTo(gt);
897         if (oldgt == null) {
898             getDocument().assignObjectNumber(gt);
899             getDocument().addTrailerObject(gt);
900         } else {
901             gt = oldgt;
902         }
903
904         goToReference = gt.referencePDF();
905         return goToReference;
906     }
907
908     /**
909      * Create and return a goto pdf document action.
910      * This creates a pdf files spec and pdf goto remote action.
911      * It also checks available pdf objects so it will not create an
912      * object if it already exists.
913      *
914      * @param file the pdf file name
915      * @param dest the remote name destination, may be null
916      * @param page the remote page number, -1 means not specified
917      * @return the pdf goto remote object
918      */

919     private PDFGoToRemote getGoToPDFAction(String JavaDoc file, String JavaDoc dest, int page) {
920         getDocument().getProfile().verifyActionAllowed();
921         PDFFileSpec fileSpec = new PDFFileSpec(file);
922         PDFFileSpec oldspec = getDocument().findFileSpec(fileSpec);
923         if (oldspec == null) {
924             getDocument().registerObject(fileSpec);
925         } else {
926             fileSpec = oldspec;
927         }
928         PDFGoToRemote remote;
929
930         if (dest == null && page == -1) {
931             remote = new PDFGoToRemote(fileSpec);
932         } else if (dest != null) {
933             remote = new PDFGoToRemote(fileSpec, dest);
934         } else {
935             remote = new PDFGoToRemote(fileSpec, page);
936         }
937         PDFGoToRemote oldremote = getDocument().findGoToRemote(remote);
938         if (oldremote == null) {
939             getDocument().registerObject(remote);
940         } else {
941             remote = oldremote;
942         }
943         return remote;
944     }
945
946     /**
947      * Make an outline object and add it to the given outline
948      *
949      * @param parent parent PDFOutline object which may be null
950      * @param label the title for the new outline object
951      * @param destination the reference string for the action to go to
952      * @param yoffset the yoffset on the destination page
953      * @param showSubItems whether to initially display child outline items
954      * @return the new PDF outline object
955      */

956     public PDFOutline makeOutline(PDFOutline parent, String JavaDoc label,
957                                   String JavaDoc destination, float yoffset,
958                                   boolean showSubItems) {
959
960         String JavaDoc goToRef = getGoToReference(destination, yoffset);
961         PDFOutline obj = new PDFOutline(label, goToRef, showSubItems);
962
963         if (parent != null) {
964             parent.addOutline(obj);
965         }
966         getDocument().registerObject(obj);
967         return obj;
968     }
969
970
971
972     /* ========================= fonts ===================================== */
973
974     /**
975      * make a /Encoding object
976      *
977      * @param encodingName character encoding scheme name
978      * @return the created /Encoding object
979      */

980     public PDFEncoding makeEncoding(String JavaDoc encodingName) {
981         PDFEncoding encoding = new PDFEncoding(encodingName);
982
983         getDocument().registerObject(encoding);
984         return encoding;
985     }
986
987     /**
988      * make a Type1 /Font object
989      *
990      * @param fontname internal name to use for this font (eg "F1")
991      * @param basefont name of the base font (eg "Helvetica")
992      * @param encoding character encoding scheme used by the font
993      * @param metrics additional information about the font
994      * @param descriptor additional information about the font
995      * @return the created /Font object
996      */

997     public PDFFont makeFont(String JavaDoc fontname, String JavaDoc basefont,
998                             String JavaDoc encoding, FontMetrics metrics,
999                             FontDescriptor descriptor) {
1000        PDFFont preRegisteredfont = getDocument().findFont(fontname);
1001        if (preRegisteredfont != null) {
1002            return preRegisteredfont;
1003        }
1004
1005        if (descriptor == null) {
1006            PDFFont font = new PDFFont(fontname, FontType.TYPE1, basefont, encoding);
1007            getDocument().registerObject(font);
1008            return font;
1009        } else {
1010            FontType fonttype = metrics.getFontType();
1011
1012            PDFFontDescriptor pdfdesc = makeFontDescriptor(descriptor);
1013
1014            PDFFontNonBase14 font = null;
1015            if (fonttype == FontType.TYPE0) {
1016                /*
1017                 * Temporary commented out - customized CMaps
1018                 * isn't needed until /ToUnicode support is added
1019                 * PDFCMap cmap = new PDFCMap(++this.objectcount,
1020                 * "fop-ucs-H",
1021                 * new PDFCIDSystemInfo("Adobe",
1022                 * "Identity",
1023                 * 0));
1024                 * cmap.addContents();
1025                 * this.objects.add(cmap);
1026                 */

1027                font =
1028                    (PDFFontNonBase14)PDFFont.createFont(fontname, fonttype,
1029                                                         basefont,
1030                                                         "Identity-H");
1031            } else {
1032
1033                font =
1034                    (PDFFontNonBase14)PDFFont.createFont(fontname, fonttype,
1035                                                         basefont, encoding);
1036            }
1037            getDocument().registerObject(font);
1038
1039            font.setDescriptor(pdfdesc);
1040
1041            if (fonttype == FontType.TYPE0) {
1042                CIDFont cidMetrics;
1043                if (metrics instanceof LazyFont) {
1044                    cidMetrics = (CIDFont)((LazyFont) metrics).getRealFont();
1045                } else {
1046                    cidMetrics = (CIDFont)metrics;
1047                }
1048                PDFCIDSystemInfo sysInfo =
1049                    new PDFCIDSystemInfo(cidMetrics.getRegistry(),
1050                                         cidMetrics.getOrdering(),
1051                                         cidMetrics.getSupplement());
1052                PDFCIDFont cidFont =
1053                    new PDFCIDFont(basefont,
1054                                   cidMetrics.getCIDType(),
1055                                   cidMetrics.getDefaultWidth(),
1056                                   getSubsetWidths(cidMetrics), sysInfo,
1057                                   (PDFCIDFontDescriptor)pdfdesc);
1058                getDocument().registerObject(cidFont);
1059
1060                PDFCMap cmap = new PDFToUnicodeCMap(cidMetrics, "fop-ucs-H",
1061                    new PDFCIDSystemInfo("Adobe",
1062                        "Identity",
1063                        0));
1064                getDocument().registerObject(cmap);
1065                ((PDFFontType0)font).setCMAP(cmap);
1066                ((PDFFontType0)font).setDescendantFonts(cidFont);
1067            } else {
1068                int firstChar = 0;
1069                int lastChar = 255;
1070                if (metrics instanceof CustomFont) {
1071                    CustomFont cf = (CustomFont)metrics;
1072                    firstChar = cf.getFirstChar();
1073                    lastChar = cf.getLastChar();
1074                }
1075                font.setWidthMetrics(firstChar,
1076                                     lastChar,
1077                                     makeArray(metrics.getWidths()));
1078            }
1079
1080            return font;
1081        }
1082    }
1083
1084    public PDFWArray getSubsetWidths(CIDFont cidFont) {
1085        // Create widths for reencoded chars
1086
PDFWArray warray = new PDFWArray();
1087        int[] tmpWidth = new int[cidFont.usedGlyphsCount];
1088
1089        for (int i = 0; i < cidFont.usedGlyphsCount; i++) {
1090            Integer JavaDoc nw = (Integer JavaDoc)cidFont.usedGlyphsIndex.get(new Integer JavaDoc(i));
1091            int nwx = (nw == null) ? 0 : nw.intValue();
1092            tmpWidth[i] = cidFont.width[nwx];
1093        }
1094        warray.addEntry(0, tmpWidth);
1095        return warray;
1096    }
1097
1098    /**
1099     * make a /FontDescriptor object
1100     *
1101     * @param desc the font descriptor
1102     * @return the new PDF font descriptor
1103     */

1104    public PDFFontDescriptor makeFontDescriptor(FontDescriptor desc) {
1105        PDFFontDescriptor descriptor = null;
1106
1107        if (desc.getFontType() == FontType.TYPE0) {
1108            // CID Font
1109
descriptor = new PDFCIDFontDescriptor(desc.getFontName(),
1110                                            desc.getFontBBox(),
1111                                            desc.getCapHeight(),
1112                                            desc.getFlags(),
1113                                            desc.getItalicAngle(),
1114                                            desc.getStemV(), null);
1115        } else {
1116            // Create normal FontDescriptor
1117
descriptor = new PDFFontDescriptor(desc.getFontName(),
1118                                         desc.getAscender(),
1119                                         desc.getDescender(),
1120                                         desc.getCapHeight(),
1121                                         desc.getFlags(),
1122                                         new PDFRectangle(desc.getFontBBox()),
1123                                         desc.getItalicAngle(),
1124                                         desc.getStemV());
1125        }
1126        getDocument().registerObject(descriptor);
1127
1128        // Check if the font is embeddable
1129
if (desc.isEmbeddable()) {
1130            AbstractPDFStream stream = makeFontFile(desc);
1131            if (stream != null) {
1132                descriptor.setFontFile(desc.getFontType(), stream);
1133                getDocument().registerObject(stream);
1134            }
1135            CustomFont font = getCustomFont(desc);
1136            if (font instanceof CIDFont) {
1137                CIDFont cidFont = (CIDFont)font;
1138                buildCIDSet(descriptor, cidFont);
1139            }
1140        }
1141        return descriptor;
1142    }
1143
1144    private void buildCIDSet(PDFFontDescriptor descriptor, CIDFont cidFont) {
1145        BitSet JavaDoc cidSubset = new BitSet JavaDoc();
1146        Iterator JavaDoc iter = cidFont.usedGlyphs.keySet().iterator();
1147        while (iter.hasNext()) {
1148            Integer JavaDoc cid = (Integer JavaDoc)iter.next();
1149            cidSubset.set(cid.intValue());
1150        }
1151        PDFStream cidSet = makeStream(null, true);
1152        ByteArrayOutputStream baout = new ByteArrayOutputStream(cidSubset.length() / 8 + 1);
1153        int value = 0;
1154        for (int i = 0, c = cidSubset.length(); i < c; i++) {
1155            int shift = i % 8;
1156            boolean b = cidSubset.get(i);
1157            if (b) {
1158                value |= 1 << 7 - shift;
1159            }
1160            if (shift == 7) {
1161                baout.write(value);
1162                value = 0;
1163            }
1164        }
1165        baout.write(value);
1166        try {
1167            cidSet.setData(baout.toByteArray());
1168            descriptor.setCIDSet(cidSet);
1169        } catch (IOException JavaDoc ioe) {
1170            log.error(
1171                    "Failed to write CIDSet [" + cidFont + "] "
1172                    + cidFont.getFontName(), ioe);
1173        }
1174    }
1175
1176    /**
1177     * Embeds a font.
1178     * @param desc FontDescriptor of the font.
1179     * @return PDFStream The embedded font file
1180     */

1181    public AbstractPDFStream makeFontFile(FontDescriptor desc) {
1182        if (desc.getFontType() == FontType.OTHER) {
1183            throw new IllegalArgumentException JavaDoc("Trying to embed unsupported font type: "
1184                                                + desc.getFontType());
1185        }
1186
1187        CustomFont font = getCustomFont(desc);
1188
1189        InputStream JavaDoc in = null;
1190        try {
1191            Source JavaDoc source = font.getEmbedFileSource();
1192            if (source == null && font.getEmbedResourceName() != null) {
1193                source = new StreamSource JavaDoc(this.getClass()
1194                        .getResourceAsStream(font.getEmbedResourceName()));
1195            }
1196            if (source == null) {
1197                return null;
1198            }
1199            if (source instanceof StreamSource JavaDoc) {
1200                in = ((StreamSource JavaDoc) source).getInputStream();
1201            }
1202            if (in == null && source.getSystemId() != null) {
1203                try {
1204                    in = new java.net.URL JavaDoc(source.getSystemId()).openStream();
1205                } catch (MalformedURLException JavaDoc e) {
1206                    new FileNotFoundException JavaDoc(
1207                            "File not found. URL could not be resolved: "
1208                                    + e.getMessage());
1209                }
1210            }
1211            if (in == null) {
1212                return null;
1213            }
1214            //Make sure the InputStream is decorated with a BufferedInputStream
1215
if (!(in instanceof java.io.BufferedInputStream JavaDoc)) {
1216                in = new java.io.BufferedInputStream JavaDoc(in);
1217            }
1218            if (in == null) {
1219                return null;
1220            } else {
1221                try {
1222                    AbstractPDFStream embeddedFont;
1223                    if (desc.getFontType() == FontType.TYPE0) {
1224                        MultiByteFont mbfont = (MultiByteFont)font;
1225                        FontFileReader reader = new FontFileReader(in);
1226
1227                        TTFSubSetFile subset = new TTFSubSetFile();
1228                        byte[] subsetFont = subset.readFont(reader,
1229                                             mbfont.getTTCName(), mbfont.getUsedGlyphs());
1230                        // Only TrueType CID fonts are supported now
1231

1232                        embeddedFont = new PDFTTFStream(subsetFont.length);
1233                        ((PDFTTFStream)embeddedFont).setData(subsetFont, subsetFont.length);
1234                    } else if (desc.getFontType() == FontType.TYPE1) {
1235                        PFBParser parser = new PFBParser();
1236                        PFBData pfb = parser.parsePFB(in);
1237                        embeddedFont = new PDFT1Stream();
1238                        ((PDFT1Stream)embeddedFont).setData(pfb);
1239                    } else {
1240                        byte[] file = IOUtils.toByteArray(in);
1241                        embeddedFont = new PDFTTFStream(file.length);
1242                        ((PDFTTFStream)embeddedFont).setData(file, file.length);
1243                    }
1244
1245                    /*
1246                    embeddedFont.getFilterList().addFilter("flate");
1247                    if (getDocument().isEncryptionActive()) {
1248                        getDocument().applyEncryption(embeddedFont);
1249                    } else {
1250                        embeddedFont.getFilterList().addFilter("ascii-85");
1251                    }*/

1252
1253                    return embeddedFont;
1254                } finally {
1255                    in.close();
1256                }
1257            }
1258        } catch (IOException JavaDoc ioe) {
1259            log.error(
1260                    "Failed to embed font [" + desc + "] "
1261                    + desc.getFontName(), ioe);
1262            return (PDFStream) null;
1263        }
1264    }
1265
1266    private CustomFont getCustomFont(FontDescriptor desc) {
1267        Typeface tempFont;
1268        if (desc instanceof LazyFont) {
1269            tempFont = ((LazyFont)desc).getRealFont();
1270        } else {
1271            tempFont = (Typeface)desc;
1272        }
1273        if (!(tempFont instanceof CustomFont)) {
1274            throw new IllegalArgumentException JavaDoc(
1275                      "FontDescriptor must be instance of CustomFont, but is a "
1276                       + desc.getClass().getName());
1277        }
1278        return (CustomFont)tempFont;
1279    }
1280
1281
1282    /* ========================= streams =================================== */
1283
1284    /**
1285     * Make a stream object
1286     *
1287     * @param type the type of stream to be created
1288     * @param add if true then the stream will be added immediately
1289     * @return the stream object created
1290     */

1291    public PDFStream makeStream(String JavaDoc type, boolean add) {
1292
1293        // create a PDFStream with the next object number
1294
// and add it to the list of objects
1295
PDFStream obj = new PDFStream();
1296        obj.setDocument(getDocument());
1297        obj.getFilterList().addDefaultFilters(
1298                getDocument().getFilterMap(),
1299                type);
1300
1301        if (add) {
1302            getDocument().registerObject(obj);
1303        }
1304        //getDocument().applyEncryption(obj);
1305
return obj;
1306    }
1307
1308    /**
1309     * Create a PDFICCStream
1310     * @see PDFXObject
1311     * @see org.apache.fop.image.JpegImage
1312     * @see org.apache.fop.pdf.PDFDeviceColorSpace
1313     * @return the new PDF ICC stream object
1314     */

1315    public PDFICCStream makePDFICCStream() {
1316        PDFICCStream iccStream = new PDFICCStream();
1317        iccStream.getFilterList().addDefaultFilters(
1318                getDocument().getFilterMap(),
1319                PDFFilterList.CONTENT_FILTER);
1320
1321        getDocument().registerObject(iccStream);
1322        //getDocument().applyEncryption(iccStream);
1323
return iccStream;
1324    }
1325
1326    /* ========================= misc. objects ============================= */
1327
1328    /**
1329     * Makes a new ICCBased color space and registers it in the resource context.
1330     * @param res the PDF resource context to add the shading, may be null
1331     * @param explicitName the explicit name for the color space, may be null
1332     * @param iccStream the ICC stream to associate with this color space
1333     * @return the newly instantiated color space
1334     */

1335    public PDFICCBasedColorSpace makeICCBasedColorSpace(PDFResourceContext res,
1336            String JavaDoc explicitName, PDFICCStream iccStream) {
1337        PDFICCBasedColorSpace cs = new PDFICCBasedColorSpace(explicitName, iccStream);
1338        
1339        getDocument().registerObject(cs);
1340
1341        if (res != null) {
1342            res.getPDFResources().addColorSpace(cs);
1343        } else {
1344            getDocument().getResources().addColorSpace(cs);
1345        }
1346        
1347        return cs;
1348    }
1349
1350    /**
1351     * make an Array object (ex. Widths array for a font)
1352     *
1353     * @param values the int array values
1354     * @return the PDF Array with the int values
1355     */

1356    public PDFArray makeArray(int[] values) {
1357        PDFArray array = new PDFArray(values);
1358
1359        getDocument().registerObject(array);
1360        return array;
1361    }
1362
1363    /**
1364     * make an ExtGState for extra graphics options
1365     * This tries to find a GState that will setup the correct values
1366     * for the current context. If there is no suitable GState it will
1367     * create a new one.
1368     *
1369     * @param settings the settings required by the caller
1370     * @param current the current GState of the current PDF context
1371     * @return a PDF GState, either an existing GState or a new one
1372     */

1373    public PDFGState makeGState(Map JavaDoc settings, PDFGState current) {
1374
1375        // try to locate a gstate that has all the settings
1376
// or will inherit from the current gstate
1377
// compare "DEFAULT + settings" with "current + each gstate"
1378

1379        PDFGState wanted = new PDFGState();
1380        wanted.addValues(PDFGState.DEFAULT);
1381        wanted.addValues(settings);
1382
1383
1384        PDFGState existing = getDocument().findGState(wanted, current);
1385        if (existing != null) {
1386            return existing;
1387        }
1388
1389        PDFGState gstate = new PDFGState();
1390        gstate.addValues(settings);
1391        getDocument().registerObject(gstate);
1392        return gstate;
1393    }
1394
1395    /**
1396     * Make an annotation list object
1397     *
1398     * @return the annotation list object created
1399     */

1400    public PDFAnnotList makeAnnotList() {
1401        PDFAnnotList obj = new PDFAnnotList();
1402        getDocument().assignObjectNumber(obj);
1403        return obj;
1404    }
1405
1406}
1407
Popular Tags