Source Code Cross Referenced for PDFDocument.java in  » Graphic-Library » fop » org » apache » fop » pdf » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Graphic Library » fop » org.apache.fop.pdf 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * Licensed to the Apache Software Foundation (ASF) under one or more
0003:         * contributor license agreements.  See the NOTICE file distributed with
0004:         * this work for additional information regarding copyright ownership.
0005:         * The ASF licenses this file to You under the Apache License, Version 2.0
0006:         * (the "License"); you may not use this file except in compliance with
0007:         * the License.  You may obtain a copy of the License at
0008:         * 
0009:         *      http://www.apache.org/licenses/LICENSE-2.0
0010:         * 
0011:         * Unless required by applicable law or agreed to in writing, software
0012:         * distributed under the License is distributed on an "AS IS" BASIS,
0013:         * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014:         * See the License for the specific language governing permissions and
0015:         * limitations under the License.
0016:         */
0017:
0018:        /* $Id: PDFDocument.java 535883 2007-05-07 14:30:23Z jeremias $ */
0019:
0020:        package org.apache.fop.pdf;
0021:
0022:        // Java
0023:        import java.io.IOException;
0024:        import java.io.InputStream;
0025:        import java.io.OutputStream;
0026:        import java.io.UnsupportedEncodingException;
0027:        import java.security.MessageDigest;
0028:        import java.security.NoSuchAlgorithmException;
0029:        import java.text.DateFormat;
0030:        import java.text.SimpleDateFormat;
0031:        import java.util.Collections;
0032:        import java.util.Date;
0033:        import java.util.List;
0034:        import java.util.Map;
0035:        import java.util.Iterator;
0036:
0037:        import org.apache.commons.logging.Log;
0038:        import org.apache.commons.logging.LogFactory;
0039:
0040:        /* image support modified from work of BoBoGi */
0041:        /* font support based on work by Takayuki Takeuchi */
0042:
0043:        /**
0044:         * class representing a PDF document.
0045:         *
0046:         * The document is built up by calling various methods and then finally
0047:         * output to given filehandle using output method.
0048:         *
0049:         * A PDF document consists of a series of numbered objects preceded by a
0050:         * header and followed by an xref table and trailer. The xref table
0051:         * allows for quick access to objects by listing their character
0052:         * positions within the document. For this reason the PDF document must
0053:         * keep track of the character position of each object.  The document
0054:         * also keeps direct track of the /Root, /Info and /Resources objects.
0055:         *
0056:         * Modified by Mark Lillywhite, mark-fop@inomial.com. The changes
0057:         * involve: ability to output pages one-at-a-time in a streaming
0058:         * fashion (rather than storing them all for output at the end);
0059:         * ability to write the /Pages object after writing the rest
0060:         * of the document; ability to write to a stream and flush
0061:         * the object list; enhanced trailer output; cleanups.
0062:         *
0063:         */
0064:        public class PDFDocument {
0065:
0066:            private static final Integer LOCATION_PLACEHOLDER = new Integer(0);
0067:
0068:            /** Integer constant to represent PDF 1.3 */
0069:            public static final int PDF_VERSION_1_3 = 3;
0070:
0071:            /** Integer constant to represent PDF 1.4 */
0072:            public static final int PDF_VERSION_1_4 = 4;
0073:
0074:            /**
0075:             * the encoding to use when converting strings to PDF commandos.
0076:             */
0077:            public static final String ENCODING = "ISO-8859-1";
0078:
0079:            private Log log = LogFactory.getLog("org.apache.fop.pdf");
0080:
0081:            /**
0082:             * the current character position
0083:             */
0084:            protected int position = 0;
0085:
0086:            /**
0087:             * the character position of each object
0088:             */
0089:            protected List location = new java.util.ArrayList();
0090:
0091:            /** List of objects to write in the trailer */
0092:            private List trailerObjects = new java.util.ArrayList();
0093:
0094:            /**
0095:             * the counter for object numbering
0096:             */
0097:            protected int objectcount = 0;
0098:
0099:            /**
0100:             * the objects themselves
0101:             */
0102:            protected List objects = new java.util.LinkedList();
0103:
0104:            /**
0105:             * character position of xref table
0106:             */
0107:            protected int xref;
0108:
0109:            /** Indicates what PDF version is active */
0110:            protected int pdfVersion = PDF_VERSION_1_4;
0111:
0112:            /**
0113:             * Indicates which PDF profiles are active (PDF/A, PDF/X etc.)
0114:             */
0115:            protected PDFProfile pdfProfile = new PDFProfile(this );
0116:
0117:            /**
0118:             * the /Root object
0119:             */
0120:            protected PDFRoot root;
0121:
0122:            /** The root outline object */
0123:            private PDFOutline outlineRoot = null;
0124:
0125:            /** The /Pages object (mark-fop@inomial.com) */
0126:            private PDFPages pages;
0127:
0128:            /**
0129:             * the /Info object
0130:             */
0131:            protected PDFInfo info;
0132:
0133:            /**
0134:             * the /Resources object
0135:             */
0136:            protected PDFResources resources;
0137:
0138:            /**
0139:             * the documents encryption, if exists
0140:             */
0141:            protected PDFEncryption encryption;
0142:
0143:            /**
0144:             * the colorspace (0=RGB, 1=CMYK)
0145:             */
0146:            protected PDFDeviceColorSpace colorspace = new PDFDeviceColorSpace(
0147:                    PDFDeviceColorSpace.DEVICE_RGB);
0148:
0149:            /**
0150:             * the counter for Pattern name numbering (e.g. 'Pattern1')
0151:             */
0152:            protected int patternCount = 0;
0153:
0154:            /**
0155:             * the counter for Shading name numbering
0156:             */
0157:            protected int shadingCount = 0;
0158:
0159:            /**
0160:             * the counter for XObject numbering
0161:             */
0162:            protected int xObjectCount = 0;
0163:
0164:            /**
0165:             * the XObjects Map.
0166:             * Should be modified (works only for image subtype)
0167:             */
0168:            protected Map xObjectsMap = new java.util.HashMap();
0169:
0170:            /**
0171:             * the Font Map.
0172:             */
0173:            protected Map fontMap = new java.util.HashMap();
0174:
0175:            /**
0176:             * The filter map.
0177:             */
0178:            protected Map filterMap = new java.util.HashMap();
0179:
0180:            /**
0181:             * List of PDFGState objects.
0182:             */
0183:            protected List gstates = new java.util.ArrayList();
0184:
0185:            /**
0186:             * List of functions.
0187:             */
0188:            protected List functions = new java.util.ArrayList();
0189:
0190:            /**
0191:             * List of shadings.
0192:             */
0193:            protected List shadings = new java.util.ArrayList();
0194:
0195:            /**
0196:             * List of patterns.
0197:             */
0198:            protected List patterns = new java.util.ArrayList();
0199:
0200:            /**
0201:             * List of Links.
0202:             */
0203:            protected List links = new java.util.ArrayList();
0204:
0205:            /**
0206:             * List of Destinations.
0207:             */
0208:            protected List destinations;
0209:
0210:            /**
0211:             * List of FileSpecs.
0212:             */
0213:            protected List filespecs = new java.util.ArrayList();
0214:
0215:            /**
0216:             * List of GoToRemotes.
0217:             */
0218:            protected List gotoremotes = new java.util.ArrayList();
0219:
0220:            /**
0221:             * List of GoTos.
0222:             */
0223:            protected List gotos = new java.util.ArrayList();
0224:
0225:            /**
0226:             * The PDFDests object for the name dictionary.
0227:             * Note: This object is not a list.
0228:             */
0229:            private PDFDests dests;
0230:
0231:            private PDFFactory factory;
0232:
0233:            private boolean encodingOnTheFly = true;
0234:
0235:            /**
0236:             * Creates an empty PDF document.
0237:             *
0238:             * The constructor creates a /Root and /Pages object to
0239:             * track the document but does not write these objects until
0240:             * the trailer is written. Note that the object ID of the
0241:             * pages object is determined now, and the xref table is
0242:             * updated later. This allows Pages to refer to their
0243:             * Parent before we write it out.
0244:             *
0245:             * @param prod the name of the producer of this pdf document
0246:             */
0247:            public PDFDocument(String prod) {
0248:
0249:                this .factory = new PDFFactory(this );
0250:
0251:                /* create the /Root, /Info and /Resources objects */
0252:                this .pages = getFactory().makePages();
0253:
0254:                // Create the Root object
0255:                this .root = getFactory().makeRoot(pages);
0256:
0257:                // Create the Resources object
0258:                this .resources = getFactory().makeResources();
0259:
0260:                // Make the /Info record
0261:                this .info = getFactory().makeInfo(prod);
0262:            }
0263:
0264:            /**
0265:             * @return the integer representing the active PDF version (one of PDFDocument.PDF_VERSION_*)
0266:             */
0267:            public int getPDFVersion() {
0268:                return this .pdfVersion;
0269:            }
0270:
0271:            /** @return the String representing the active PDF version */
0272:            public String getPDFVersionString() {
0273:                switch (getPDFVersion()) {
0274:                case PDF_VERSION_1_3:
0275:                    return "1.3";
0276:                case PDF_VERSION_1_4:
0277:                    return "1.4";
0278:                default:
0279:                    throw new IllegalStateException(
0280:                            "Unsupported PDF version selected");
0281:                }
0282:            }
0283:
0284:            /** @return the PDF profile currently active. */
0285:            public PDFProfile getProfile() {
0286:                return this .pdfProfile;
0287:            }
0288:
0289:            /**
0290:             * Returns the factory for PDF objects.
0291:             * @return PDFFactory the factory
0292:             */
0293:            public PDFFactory getFactory() {
0294:                return this .factory;
0295:            }
0296:
0297:            /**
0298:             * Indicates whether stream encoding on-the-fly is enabled. If enabled
0299:             * stream can be serialized without the need for a buffer to merely
0300:             * calculate the stream length.
0301:             * @return boolean true if on-the-fly encoding is enabled
0302:             */
0303:            public boolean isEncodingOnTheFly() {
0304:                return this .encodingOnTheFly;
0305:            }
0306:
0307:            /**
0308:             * Converts text to a byte array for writing to a PDF file.
0309:             * @param text text to convert/encode
0310:             * @return byte[] the resulting byte array
0311:             */
0312:            public static byte[] encode(String text) {
0313:                try {
0314:                    return text.getBytes(ENCODING);
0315:                } catch (UnsupportedEncodingException uee) {
0316:                    return text.getBytes();
0317:                }
0318:            }
0319:
0320:            /**
0321:             * set the producer of the document
0322:             *
0323:             * @param producer string indicating application producing the PDF
0324:             */
0325:            public void setProducer(String producer) {
0326:                this .info.setProducer(producer);
0327:            }
0328:
0329:            /**
0330:             * Set the creation date of the document.
0331:             * 
0332:             * @param date Date to be stored as creation date in the PDF.
0333:             */
0334:            public void setCreationDate(Date date) {
0335:                info.setCreationDate(date);
0336:            }
0337:
0338:            /**
0339:             * Set the creator of the document.
0340:             *
0341:             * @param creator string indicating application creating the document
0342:             */
0343:            public void setCreator(String creator) {
0344:                this .info.setCreator(creator);
0345:            }
0346:
0347:            /**
0348:             * Set the filter map to use for filters in this document.
0349:             *
0350:             * @param map the map of filter lists for each stream type
0351:             */
0352:            public void setFilterMap(Map map) {
0353:                this .filterMap = map;
0354:            }
0355:
0356:            /**
0357:             * Get the filter map used for filters in this document.
0358:             *
0359:             * @return the map of filters being used
0360:             */
0361:            public Map getFilterMap() {
0362:                return this .filterMap;
0363:            }
0364:
0365:            /**
0366:             * Returns the PDFPages object associated with the root object.
0367:             * @return the PDFPages object
0368:             */
0369:            public PDFPages getPages() {
0370:                return this .pages;
0371:            }
0372:
0373:            /**
0374:             * Get the PDF root object.
0375:             *
0376:             * @return the PDFRoot object
0377:             */
0378:            public PDFRoot getRoot() {
0379:                return this .root;
0380:            }
0381:
0382:            /**
0383:             * Get the pdf info object for this document.
0384:             *
0385:             * @return the PDF Info object for this document
0386:             */
0387:            public PDFInfo getInfo() {
0388:                return info;
0389:            }
0390:
0391:            /**
0392:             * Registers a PDFObject in this PDF document. The PDF is assigned a new
0393:             * object number.
0394:             * @param obj PDFObject to add
0395:             * @return PDFObject the PDFObject added (its object number set)
0396:             */
0397:            public PDFObject registerObject(PDFObject obj) {
0398:                assignObjectNumber(obj);
0399:                addObject(obj);
0400:                return obj;
0401:            }
0402:
0403:            /**
0404:             * Assigns the PDFObject a object number and sets the parent of the
0405:             * PDFObject to this PDFDocument.
0406:             * @param obj PDFObject to assign a number to
0407:             */
0408:            public void assignObjectNumber(PDFObject obj) {
0409:                if (obj == null) {
0410:                    throw new NullPointerException("obj must not be null");
0411:                }
0412:                if (obj.hasObjectNumber()) {
0413:                    throw new IllegalStateException(
0414:                            "Error registering a PDFObject: "
0415:                                    + "PDFObject already has an object number");
0416:                }
0417:                PDFDocument currentParent = obj.getDocument();
0418:                if (currentParent != null && currentParent != this ) {
0419:                    throw new IllegalStateException(
0420:                            "Error registering a PDFObject: "
0421:                                    + "PDFObject already has a parent PDFDocument");
0422:                }
0423:
0424:                obj.setObjectNumber(++this .objectcount);
0425:
0426:                if (currentParent == null) {
0427:                    obj.setDocument(this );
0428:                }
0429:            }
0430:
0431:            /**
0432:             * Adds an PDFObject to this document. The object must have a object number
0433:             * assigned.
0434:             * @param obj PDFObject to add
0435:             */
0436:            public void addObject(PDFObject obj) {
0437:                if (obj == null) {
0438:                    throw new NullPointerException("obj must not be null");
0439:                }
0440:                if (!obj.hasObjectNumber()) {
0441:                    throw new IllegalStateException(
0442:                            "Error adding a PDFObject: "
0443:                                    + "PDFObject doesn't have an object number");
0444:                }
0445:
0446:                //Add object to list
0447:                this .objects.add(obj);
0448:
0449:                //Add object to special lists where necessary
0450:                if (obj instanceof  PDFFunction) {
0451:                    this .functions.add(obj);
0452:                }
0453:                if (obj instanceof  PDFShading) {
0454:                    final String shadingName = "Sh" + (++this .shadingCount);
0455:                    ((PDFShading) obj).setName(shadingName);
0456:                    this .shadings.add(obj);
0457:                }
0458:                if (obj instanceof  PDFPattern) {
0459:                    final String patternName = "Pa" + (++this .patternCount);
0460:                    ((PDFPattern) obj).setName(patternName);
0461:                    this .patterns.add(obj);
0462:                }
0463:                if (obj instanceof  PDFFont) {
0464:                    final PDFFont font = (PDFFont) obj;
0465:                    this .fontMap.put(font.getName(), font);
0466:                }
0467:                if (obj instanceof  PDFGState) {
0468:                    this .gstates.add(obj);
0469:                }
0470:                if (obj instanceof  PDFPage) {
0471:                    this .pages.notifyKidRegistered((PDFPage) obj);
0472:                }
0473:                if (obj instanceof  PDFLink) {
0474:                    this .links.add(obj);
0475:                }
0476:                if (obj instanceof  PDFFileSpec) {
0477:                    this .filespecs.add(obj);
0478:                }
0479:                if (obj instanceof  PDFGoToRemote) {
0480:                    this .gotoremotes.add(obj);
0481:                }
0482:            }
0483:
0484:            /**
0485:             * Add trailer object.
0486:             * Adds an object to the list of trailer objects.
0487:             *
0488:             * @param obj the PDF object to add
0489:             */
0490:            public void addTrailerObject(PDFObject obj) {
0491:                this .trailerObjects.add(obj);
0492:
0493:                if (obj instanceof  PDFGoTo) {
0494:                    this .gotos.add(obj);
0495:                }
0496:            }
0497:
0498:            /**
0499:             * Apply the encryption filter to a PDFStream if encryption is enabled.
0500:             * @param stream PDFStream to encrypt
0501:             */
0502:            public void applyEncryption(AbstractPDFStream stream) {
0503:                if (isEncryptionActive()) {
0504:                    this .encryption.applyFilter(stream);
0505:                }
0506:            }
0507:
0508:            /**
0509:             * Enables PDF encryption.
0510:             * @param params The encryption parameters for the pdf file
0511:             */
0512:            public void setEncryption(PDFEncryptionParams params) {
0513:                getProfile().verifyEncryptionAllowed();
0514:                this .encryption = PDFEncryptionManager.newInstance(
0515:                        ++this .objectcount, params);
0516:                ((PDFObject) this .encryption).setDocument(this );
0517:                if (encryption != null) {
0518:                    /**@todo this cast is ugly. PDFObject should be transformed to an interface. */
0519:                    addTrailerObject((PDFObject) this .encryption);
0520:                } else {
0521:                    log.warn("PDF encryption is unavailable. PDF will be "
0522:                            + "generated without encryption.");
0523:                }
0524:            }
0525:
0526:            /**
0527:             * Indicates whether encryption is active for this PDF or not.
0528:             * @return boolean True if encryption is active
0529:             */
0530:            public boolean isEncryptionActive() {
0531:                return this .encryption != null;
0532:            }
0533:
0534:            /**
0535:             * Returns the active Encryption object.
0536:             * @return the Encryption object
0537:             */
0538:            public PDFEncryption getEncryption() {
0539:                return encryption;
0540:            }
0541:
0542:            private Object findPDFObject(List list, PDFObject compare) {
0543:                for (Iterator iter = list.iterator(); iter.hasNext();) {
0544:                    Object obj = iter.next();
0545:                    if (compare.equals(obj)) {
0546:                        return obj;
0547:                    }
0548:                }
0549:                return null;
0550:            }
0551:
0552:            /**
0553:             * Looks through the registered functions to see if one that is equal to
0554:             * a reference object exists
0555:             * @param compare reference object
0556:             * @return the function if it was found, null otherwise
0557:             */
0558:            protected PDFFunction findFunction(PDFFunction compare) {
0559:                return (PDFFunction) findPDFObject(functions, compare);
0560:            }
0561:
0562:            /**
0563:             * Looks through the registered shadings to see if one that is equal to
0564:             * a reference object exists
0565:             * @param compare reference object
0566:             * @return the shading if it was found, null otherwise
0567:             */
0568:            protected PDFShading findShading(PDFShading compare) {
0569:                return (PDFShading) findPDFObject(shadings, compare);
0570:            }
0571:
0572:            /**
0573:             * Find a previous pattern.
0574:             * The problem with this is for tiling patterns the pattern
0575:             * data stream is stored and may use up memory, usually this
0576:             * would only be a small amount of data.
0577:             * @param compare reference object
0578:             * @return the shading if it was found, null otherwise
0579:             */
0580:            protected PDFPattern findPattern(PDFPattern compare) {
0581:                return (PDFPattern) findPDFObject(patterns, compare);
0582:            }
0583:
0584:            /**
0585:             * Finds a font.
0586:             * @param fontname name of the font
0587:             * @return PDFFont the requested font, null if it wasn't found
0588:             */
0589:            protected PDFFont findFont(String fontname) {
0590:                return (PDFFont) fontMap.get(fontname);
0591:            }
0592:
0593:            /**
0594:             * Finds a named destination.
0595:             * @param compare reference object to use as search template
0596:             * @return the link if found, null otherwise
0597:             */
0598:            protected PDFDestination findDestination(PDFDestination compare) {
0599:                int index = getDestinationList().indexOf(compare);
0600:                if (index >= 0) {
0601:                    return (PDFDestination) getDestinationList().get(index);
0602:                } else {
0603:                    return null;
0604:                }
0605:            }
0606:
0607:            /**
0608:             * Finds a link.
0609:             * @param compare reference object to use as search template
0610:             * @return the link if found, null otherwise
0611:             */
0612:            protected PDFLink findLink(PDFLink compare) {
0613:                return (PDFLink) findPDFObject(links, compare);
0614:            }
0615:
0616:            /**
0617:             * Finds a file spec.
0618:             * @param compare reference object to use as search template
0619:             * @return the file spec if found, null otherwise
0620:             */
0621:            protected PDFFileSpec findFileSpec(PDFFileSpec compare) {
0622:                return (PDFFileSpec) findPDFObject(filespecs, compare);
0623:            }
0624:
0625:            /**
0626:             * Finds a goto remote.
0627:             * @param compare reference object to use as search template
0628:             * @return the goto remote if found, null otherwise
0629:             */
0630:            protected PDFGoToRemote findGoToRemote(PDFGoToRemote compare) {
0631:                return (PDFGoToRemote) findPDFObject(gotoremotes, compare);
0632:            }
0633:
0634:            /**
0635:             * Finds a goto.
0636:             * @param compare reference object to use as search template
0637:             * @return the goto if found, null otherwise
0638:             */
0639:            protected PDFGoTo findGoTo(PDFGoTo compare) {
0640:                return (PDFGoTo) findPDFObject(gotos, compare);
0641:            }
0642:
0643:            /**
0644:             * Looks for an existing GState to use
0645:             * @param wanted requested features
0646:             * @param current currently active features
0647:             * @return PDFGState the GState if found, null otherwise
0648:             */
0649:            protected PDFGState findGState(PDFGState wanted, PDFGState current) {
0650:                PDFGState poss;
0651:                Iterator iter = gstates.iterator();
0652:                while (iter.hasNext()) {
0653:                    PDFGState avail = (PDFGState) iter.next();
0654:                    poss = new PDFGState();
0655:                    poss.addValues(current);
0656:                    poss.addValues(avail);
0657:                    if (poss.equals(wanted)) {
0658:                        return avail;
0659:                    }
0660:                }
0661:                return null;
0662:            }
0663:
0664:            /**
0665:             * Get the PDF color space object.
0666:             *
0667:             * @return the color space
0668:             */
0669:            public PDFDeviceColorSpace getPDFColorSpace() {
0670:                return this .colorspace;
0671:            }
0672:
0673:            /**
0674:             * Get the color space.
0675:             *
0676:             * @return the color space
0677:             */
0678:            public int getColorSpace() {
0679:                return getPDFColorSpace().getColorSpace();
0680:            }
0681:
0682:            /**
0683:             * Set the color space.
0684:             * This is used when creating gradients.
0685:             *
0686:             * @param theColorspace the new color space
0687:             */
0688:            public void setColorSpace(int theColorspace) {
0689:                this .colorspace.setColorSpace(theColorspace);
0690:                return;
0691:            }
0692:
0693:            /**
0694:             * Get the font map for this document.
0695:             *
0696:             * @return the map of fonts used in this document
0697:             */
0698:            public Map getFontMap() {
0699:                return fontMap;
0700:            }
0701:
0702:            /**
0703:             * Resolve a URI.
0704:             *
0705:             * @param uri the uri to resolve
0706:             * @throws java.io.FileNotFoundException if the URI could not be resolved
0707:             * @return the InputStream from the URI.
0708:             */
0709:            protected InputStream resolveURI(String uri)
0710:                    throws java.io.FileNotFoundException {
0711:                try {
0712:                    /**@todo Temporary hack to compile, improve later */
0713:                    return new java.net.URL(uri).openStream();
0714:                } catch (Exception e) {
0715:                    throw new java.io.FileNotFoundException(
0716:                            "URI could not be resolved (" + e.getMessage()
0717:                                    + "): " + uri);
0718:                }
0719:            }
0720:
0721:            /**
0722:             * Get an image from the image map.
0723:             *
0724:             * @param key the image key to look for
0725:             * @return the image or PDFXObject for the key if found
0726:             */
0727:            public PDFXObject getImage(String key) {
0728:                PDFXObject xObject = (PDFXObject) xObjectsMap.get(key);
0729:                return xObject;
0730:            }
0731:
0732:            /**
0733:             * Gets the PDFDests object (which represents the /Dests entry).
0734:             *
0735:             * @return the PDFDests object (which represents the /Dests entry).
0736:             */
0737:            public PDFDests getDests() {
0738:                return dests;
0739:            }
0740:
0741:            /**
0742:             * Adds a destination to the document.
0743:             * @param destination the destination object
0744:             */
0745:            public void addDestination(PDFDestination destination) {
0746:                if (this .destinations == null) {
0747:                    this .destinations = new java.util.ArrayList();
0748:                }
0749:                this .destinations.add(destination);
0750:            }
0751:
0752:            /**
0753:             * Gets the list of named destinations.
0754:             *
0755:             * @return the list of named destinations.
0756:             */
0757:            public List getDestinationList() {
0758:                if (hasDestinations()) {
0759:                    return destinations;
0760:                } else {
0761:                    return Collections.EMPTY_LIST;
0762:                }
0763:            }
0764:
0765:            /**
0766:             * Gets whether the document has named destinations.
0767:             *
0768:             * @return whether the document has named destinations.
0769:             */
0770:            public boolean hasDestinations() {
0771:                return this .destinations != null
0772:                        && !this .destinations.isEmpty();
0773:            }
0774:
0775:            /**
0776:             * Add an image to the PDF document.
0777:             * This adds an image to the PDF objects.
0778:             * If an image with the same key already exists it will return the
0779:             * old PDFXObject.
0780:             *
0781:             * @param res the PDF resource context to add to, may be null
0782:             * @param img the PDF image to add
0783:             * @return the PDF XObject that references the PDF image data
0784:             */
0785:            public PDFXObject addImage(PDFResourceContext res, PDFImage img) {
0786:                // check if already created
0787:                String key = img.getKey();
0788:                PDFXObject xObject = (PDFXObject) xObjectsMap.get(key);
0789:                if (xObject != null) {
0790:                    if (res != null) {
0791:                        res.getPDFResources().addXObject(xObject);
0792:                    }
0793:                    return xObject;
0794:                }
0795:
0796:                // setup image
0797:                img.setup(this );
0798:                // create a new XObject
0799:                xObject = new PDFXObject(++this .xObjectCount, img);
0800:                registerObject(xObject);
0801:                this .resources.addXObject(xObject);
0802:                if (res != null) {
0803:                    res.getPDFResources().addXObject(xObject);
0804:                }
0805:                this .xObjectsMap.put(key, xObject);
0806:                return xObject;
0807:            }
0808:
0809:            /**
0810:             * Add a form XObject to the PDF document.
0811:             * This adds a Form XObject to the PDF objects.
0812:             * If a Form XObject with the same key already exists it will return the
0813:             * old PDFFormXObject.
0814:             *
0815:             * @param res the PDF resource context to add to, may be null
0816:             * @param cont the PDF Stream contents of the Form XObject
0817:             * @param formres the PDF Resources for the Form XObject data
0818:             * @param key the key for the object
0819:             * @return the PDF Form XObject that references the PDF data
0820:             */
0821:            public PDFFormXObject addFormXObject(PDFResourceContext res,
0822:                    PDFStream cont, PDFResources formres, String key) {
0823:                PDFFormXObject xObject;
0824:                xObject = new PDFFormXObject(++this .xObjectCount, cont, formres
0825:                        .referencePDF());
0826:                registerObject(xObject);
0827:                this .resources.addXObject(xObject);
0828:                if (res != null) {
0829:                    res.getPDFResources().addXObject(xObject);
0830:                }
0831:                return xObject;
0832:            }
0833:
0834:            /**
0835:             * Get the root Outlines object. This method does not write
0836:             * the outline to the PDF document, it simply creates a
0837:             * reference for later.
0838:             *
0839:             * @return the PDF Outline root object
0840:             */
0841:            public PDFOutline getOutlineRoot() {
0842:                if (outlineRoot != null) {
0843:                    return outlineRoot;
0844:                }
0845:
0846:                outlineRoot = new PDFOutline(null, null, true);
0847:                assignObjectNumber(outlineRoot);
0848:                addTrailerObject(outlineRoot);
0849:                root.setRootOutline(outlineRoot);
0850:                return outlineRoot;
0851:            }
0852:
0853:            /**
0854:             * get the /Resources object for the document
0855:             *
0856:             * @return the /Resources object
0857:             */
0858:            public PDFResources getResources() {
0859:                return this .resources;
0860:            }
0861:
0862:            /**
0863:             * Ensure there is room in the locations xref for the number of
0864:             * objects that have been created.
0865:             */
0866:            private void setLocation(int objidx, int position) {
0867:                while (location.size() <= objidx) {
0868:                    location.add(LOCATION_PLACEHOLDER);
0869:                }
0870:                location.set(objidx, new Integer(position));
0871:            }
0872:
0873:            /**
0874:             * write the entire document out
0875:             *
0876:             * @param stream the OutputStream to output the document to
0877:             * @throws IOException if there is an exception writing to the output stream
0878:             */
0879:            public void output(OutputStream stream) throws IOException {
0880:                //Write out objects until the list is empty. This approach (used with a
0881:                //LinkedList) allows for output() methods to create and register objects
0882:                //on the fly even during serialization.
0883:                while (this .objects.size() > 0) {
0884:                    /* Retrieve first */
0885:                    PDFObject object = (PDFObject) this .objects.remove(0);
0886:                    /*
0887:                     * add the position of this object to the list of object
0888:                     * locations
0889:                     */
0890:                    setLocation(object.getObjectNumber() - 1, this .position);
0891:
0892:                    /*
0893:                     * output the object and increment the character position
0894:                     * by the object's length
0895:                     */
0896:                    this .position += object.output(stream);
0897:                }
0898:
0899:                //Clear all objects written to the file
0900:                //this.objects.clear();
0901:            }
0902:
0903:            /**
0904:             * Write the PDF header.
0905:             *
0906:             * This method must be called prior to formatting
0907:             * and outputting AreaTrees.
0908:             *
0909:             * @param stream the OutputStream to write the header to
0910:             * @throws IOException if there is an exception writing to the output stream
0911:             */
0912:            public void outputHeader(OutputStream stream) throws IOException {
0913:                this .position = 0;
0914:
0915:                getProfile().verifyPDFVersion();
0916:
0917:                byte[] pdf = encode("%PDF-" + getPDFVersionString() + "\n");
0918:                stream.write(pdf);
0919:                this .position += pdf.length;
0920:
0921:                // output a binary comment as recommended by the PDF spec (3.4.1)
0922:                byte[] bin = { (byte) '%', (byte) 0xAA, (byte) 0xAB,
0923:                        (byte) 0xAC, (byte) 0xAD, (byte) '\n' };
0924:                stream.write(bin);
0925:                this .position += bin.length;
0926:            }
0927:
0928:            /** @return the "ID" entry for the file trailer */
0929:            protected String getIDEntry() {
0930:                try {
0931:                    MessageDigest digest = MessageDigest.getInstance("MD5");
0932:                    DateFormat df = new SimpleDateFormat(
0933:                            "yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'SSS");
0934:                    digest.update(encode(df.format(new Date())));
0935:                    //Ignoring the filename here for simplicity even though it's recommended by the PDF spec
0936:                    digest.update(encode(String.valueOf(this .position)));
0937:                    digest.update(getInfo().toPDF());
0938:                    byte[] res = digest.digest();
0939:                    String s = PDFText.toHex(res);
0940:                    return "/ID [" + s + " " + s + "]";
0941:                } catch (NoSuchAlgorithmException e) {
0942:                    if (getProfile().isIDEntryRequired()) {
0943:                        throw new UnsupportedOperationException(
0944:                                "MD5 not available: " + e.getMessage());
0945:                    } else {
0946:                        return ""; //Entry is optional if PDF/A or PDF/X are not active
0947:                    }
0948:                }
0949:            }
0950:
0951:            /**
0952:             * write the trailer
0953:             *
0954:             * @param stream the OutputStream to write the trailer to
0955:             * @throws IOException if there is an exception writing to the output stream
0956:             */
0957:            public void outputTrailer(OutputStream stream) throws IOException {
0958:                if (hasDestinations()) {
0959:                    Collections.sort(destinations, new DestinationComparator());
0960:                    dests = getFactory().makeDests(destinations);
0961:                    if (this .root.getNames() == null) {
0962:                        this .root.setNames(getFactory().makeNames());
0963:                    }
0964:                    this .root.getNames().setDests(dests);
0965:                }
0966:                output(stream);
0967:                for (int count = 0; count < trailerObjects.size(); count++) {
0968:                    PDFObject o = (PDFObject) trailerObjects.get(count);
0969:                    this .location.set(o.getObjectNumber() - 1, new Integer(
0970:                            this .position));
0971:                    this .position += o.output(stream);
0972:                }
0973:                /* output the xref table and increment the character position
0974:                  by the table's length */
0975:                this .position += outputXref(stream);
0976:
0977:                // Determine existance of encryption dictionary
0978:                String encryptEntry = "";
0979:                if (this .encryption != null) {
0980:                    encryptEntry = this .encryption.getTrailerEntry();
0981:                }
0982:
0983:                /* construct the trailer */
0984:                String pdf = "trailer\n" + "<<\n" + "/Size "
0985:                        + (this .objectcount + 1) + "\n" + "/Root "
0986:                        + this .root.referencePDF() + "\n" + "/Info "
0987:                        + this .info.referencePDF() + "\n" + getIDEntry() + "\n"
0988:                        + encryptEntry + ">>\n" + "startxref\n" + this .xref
0989:                        + "\n" + "%%EOF\n";
0990:
0991:                /* write the trailer */
0992:                stream.write(encode(pdf));
0993:            }
0994:
0995:            /**
0996:             * write the xref table
0997:             *
0998:             * @param stream the OutputStream to write the xref table to
0999:             * @return the number of characters written
1000:             */
1001:            private int outputXref(OutputStream stream) throws IOException {
1002:
1003:                /* remember position of xref table */
1004:                this .xref = this .position;
1005:
1006:                /* construct initial part of xref */
1007:                StringBuffer pdf = new StringBuffer(128);
1008:                pdf.append("xref\n0 " + (this .objectcount + 1)
1009:                        + "\n0000000000 65535 f \n");
1010:
1011:                for (int count = 0; count < this .location.size(); count++) {
1012:                    String x = this .location.get(count).toString();
1013:
1014:                    /* contruct xref entry for object */
1015:                    String padding = "0000000000";
1016:                    String loc = padding.substring(x.length()) + x;
1017:
1018:                    /* append to xref table */
1019:                    pdf = pdf.append(loc + " 00000 n \n");
1020:                }
1021:
1022:                /* write the xref table and return the character length */
1023:                byte[] pdfBytes = encode(pdf.toString());
1024:                stream.write(pdfBytes);
1025:                return pdfBytes.length;
1026:            }
1027:
1028:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.