Source Code Cross Referenced for PdfWriter.java in  » PDF » pdf-itext » com » lowagie » text » 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 » PDF » pdf itext » com.lowagie.text.pdf 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * $Id: PdfWriter.java 2904 2007-08-30 17:18:07Z psoares33 $
0003:         *
0004:         * Copyright 1999, 2000, 2001, 2002 Bruno Lowagie
0005:         *
0006:         * The contents of this file are subject to the Mozilla Public License Version 1.1
0007:         * (the "License"); you may not use this file except in compliance with the License.
0008:         * You may obtain a copy of the License at http://www.mozilla.org/MPL/
0009:         *
0010:         * Software distributed under the License is distributed on an "AS IS" basis,
0011:         * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
0012:         * for the specific language governing rights and limitations under the License.
0013:         *
0014:         * The Original Code is 'iText, a free JAVA-PDF library'.
0015:         *
0016:         * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by
0017:         * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie.
0018:         * All Rights Reserved.
0019:         * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer
0020:         * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved.
0021:         *
0022:         * Contributor(s): all the names of the contributors are added in the source code
0023:         * where applicable.
0024:         *
0025:         * Alternatively, the contents of this file may be used under the terms of the
0026:         * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the
0027:         * provisions of LGPL are applicable instead of those above.  If you wish to
0028:         * allow use of your version of this file only under the terms of the LGPL
0029:         * License and not to allow others to use your version of this file under
0030:         * the MPL, indicate your decision by deleting the provisions above and
0031:         * replace them with the notice and other provisions required by the LGPL.
0032:         * If you do not delete the provisions above, a recipient may use your version
0033:         * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE.
0034:         *
0035:         * This library is free software; you can redistribute it and/or modify it
0036:         * under the terms of the MPL as stated above or under the terms of the GNU
0037:         * Library General Public License as published by the Free Software Foundation;
0038:         * either version 2 of the License, or any later version.
0039:         *
0040:         * This library is distributed in the hope that it will be useful, but WITHOUT
0041:         * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
0042:         * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more
0043:         * details.
0044:         *
0045:         * If you didn't download this code from the following link, you should check if
0046:         * you aren't using an obsolete version:
0047:         * http://www.lowagie.com/iText/
0048:         */
0049:
0050:        package com.lowagie.text.pdf;
0051:
0052:        import java.awt.Color;
0053:        import java.io.ByteArrayOutputStream;
0054:        import java.io.IOException;
0055:        import java.io.OutputStream;
0056:        import java.util.ArrayList;
0057:        import java.util.HashMap;
0058:        import java.util.HashSet;
0059:        import java.util.Iterator;
0060:        import java.util.Map;
0061:        import java.util.TreeMap;
0062:        import java.util.TreeSet;
0063:        import java.security.cert.Certificate;
0064:
0065:        import com.lowagie.text.DocListener;
0066:        import com.lowagie.text.DocWriter;
0067:        import com.lowagie.text.Document;
0068:        import com.lowagie.text.DocumentException;
0069:        import com.lowagie.text.ExceptionConverter;
0070:        import com.lowagie.text.Image;
0071:        import com.lowagie.text.ImgWMF;
0072:        import com.lowagie.text.Rectangle;
0073:        import com.lowagie.text.Table;
0074:        import com.lowagie.text.pdf.collection.PdfCollection;
0075:        import com.lowagie.text.pdf.events.PdfPageEventForwarder;
0076:        import com.lowagie.text.pdf.interfaces.PdfAnnotations;
0077:        import com.lowagie.text.pdf.interfaces.PdfDocumentActions;
0078:        import com.lowagie.text.pdf.interfaces.PdfEncryptionSettings;
0079:        import com.lowagie.text.pdf.interfaces.PdfPageActions;
0080:        import com.lowagie.text.pdf.interfaces.PdfVersion;
0081:        import com.lowagie.text.pdf.interfaces.PdfViewerPreferences;
0082:        import com.lowagie.text.pdf.interfaces.PdfXConformance;
0083:        import com.lowagie.text.pdf.interfaces.PdfRunDirection;
0084:        import com.lowagie.text.pdf.internal.PdfVersionImp;
0085:        import com.lowagie.text.pdf.internal.PdfXConformanceImp;
0086:        import com.lowagie.text.xml.xmp.XmpWriter;
0087:
0088:        /**
0089:         * A <CODE>DocWriter</CODE> class for PDF.
0090:         * <P>
0091:         * When this <CODE>PdfWriter</CODE> is added
0092:         * to a certain <CODE>PdfDocument</CODE>, the PDF representation of every Element
0093:         * added to this Document will be written to the outputstream.</P>
0094:         */
0095:
0096:        public class PdfWriter extends DocWriter implements 
0097:                PdfViewerPreferences, PdfEncryptionSettings, PdfVersion,
0098:                PdfDocumentActions, PdfPageActions, PdfXConformance,
0099:                PdfRunDirection, PdfAnnotations {
0100:
0101:            // INNER CLASSES
0102:
0103:            /**
0104:             * This class generates the structure of a PDF document.
0105:             * <P>
0106:             * This class covers the third section of Chapter 5 in the 'Portable Document Format
0107:             * Reference Manual version 1.3' (page 55-60). It contains the body of a PDF document
0108:             * (section 5.14) and it can also generate a Cross-reference Table (section 5.15).
0109:             *
0110:             * @see		PdfWriter
0111:             * @see		PdfObject
0112:             * @see		PdfIndirectObject
0113:             */
0114:
0115:            public static class PdfBody {
0116:
0117:                // inner classes
0118:
0119:                /**
0120:                 * <CODE>PdfCrossReference</CODE> is an entry in the PDF Cross-Reference table.
0121:                 */
0122:
0123:                static class PdfCrossReference implements  Comparable {
0124:
0125:                    // membervariables
0126:                    private int type;
0127:
0128:                    /**	Byte offset in the PDF file. */
0129:                    private int offset;
0130:
0131:                    private int refnum;
0132:                    /**	generation of the object. */
0133:                    private int generation;
0134:
0135:                    // constructors
0136:                    /**
0137:                     * Constructs a cross-reference element for a PdfIndirectObject.
0138:                     * @param refnum
0139:                     * @param	offset		byte offset of the object
0140:                     * @param	generation	generationnumber of the object
0141:                     */
0142:
0143:                    PdfCrossReference(int refnum, int offset, int generation) {
0144:                        type = 0;
0145:                        this .offset = offset;
0146:                        this .refnum = refnum;
0147:                        this .generation = generation;
0148:                    }
0149:
0150:                    /**
0151:                     * Constructs a cross-reference element for a PdfIndirectObject.
0152:                     * @param refnum
0153:                     * @param	offset		byte offset of the object
0154:                     */
0155:
0156:                    PdfCrossReference(int refnum, int offset) {
0157:                        type = 1;
0158:                        this .offset = offset;
0159:                        this .refnum = refnum;
0160:                        this .generation = 0;
0161:                    }
0162:
0163:                    PdfCrossReference(int type, int refnum, int offset,
0164:                            int generation) {
0165:                        this .type = type;
0166:                        this .offset = offset;
0167:                        this .refnum = refnum;
0168:                        this .generation = generation;
0169:                    }
0170:
0171:                    int getRefnum() {
0172:                        return refnum;
0173:                    }
0174:
0175:                    /**
0176:                     * Returns the PDF representation of this <CODE>PdfObject</CODE>.
0177:                     * @param os
0178:                     * @throws IOException
0179:                     */
0180:
0181:                    public void toPdf(OutputStream os) throws IOException {
0182:                        StringBuffer off = new StringBuffer("0000000000")
0183:                                .append(offset);
0184:                        off.delete(0, off.length() - 10);
0185:                        StringBuffer gen = new StringBuffer("00000")
0186:                                .append(generation);
0187:                        gen.delete(0, gen.length() - 5);
0188:
0189:                        off.append(' ').append(gen).append(
0190:                                generation == 65535 ? " f \n" : " n \n");
0191:                        os.write(getISOBytes(off.toString()));
0192:                    }
0193:
0194:                    /**
0195:                     * Writes PDF syntax to the OutputStream
0196:                     * @param midSize
0197:                     * @param os
0198:                     * @throws IOException
0199:                     */
0200:                    public void toPdf(int midSize, OutputStream os)
0201:                            throws IOException {
0202:                        os.write((byte) type);
0203:                        while (--midSize >= 0)
0204:                            os
0205:                                    .write((byte) ((offset >>> (8 * midSize)) & 0xff));
0206:                        os.write((byte) ((generation >>> 8) & 0xff));
0207:                        os.write((byte) (generation & 0xff));
0208:                    }
0209:
0210:                    /**
0211:                     * @see java.lang.Comparable#compareTo(java.lang.Object)
0212:                     */
0213:                    public int compareTo(Object o) {
0214:                        PdfCrossReference other = (PdfCrossReference) o;
0215:                        return (refnum < other.refnum ? -1
0216:                                : (refnum == other.refnum ? 0 : 1));
0217:                    }
0218:
0219:                    /**
0220:                     * @see java.lang.Object#equals(java.lang.Object)
0221:                     */
0222:                    public boolean equals(Object obj) {
0223:                        if (obj instanceof  PdfCrossReference) {
0224:                            PdfCrossReference other = (PdfCrossReference) obj;
0225:                            return (refnum == other.refnum);
0226:                        } else
0227:                            return false;
0228:                    }
0229:
0230:                    /**
0231:                     * @see java.lang.Object#hashCode()
0232:                     */
0233:                    public int hashCode() {
0234:                        return refnum;
0235:                    }
0236:
0237:                }
0238:
0239:                private static final int OBJSINSTREAM = 200;
0240:
0241:                // membervariables
0242:
0243:                /** array containing the cross-reference table of the normal objects. */
0244:                private TreeSet xrefs;
0245:                private int refnum;
0246:                /** the current byteposition in the body. */
0247:                private int position;
0248:                private PdfWriter writer;
0249:                private ByteBuffer index;
0250:                private ByteBuffer streamObjects;
0251:                private int currentObjNum;
0252:                private int numObj = 0;
0253:
0254:                // constructors
0255:
0256:                /**
0257:                 * Constructs a new <CODE>PdfBody</CODE>.
0258:                 * @param writer
0259:                 */
0260:                PdfBody(PdfWriter writer) {
0261:                    xrefs = new TreeSet();
0262:                    xrefs.add(new PdfCrossReference(0, 0, 65535));
0263:                    position = writer.getOs().getCounter();
0264:                    refnum = 1;
0265:                    this .writer = writer;
0266:                }
0267:
0268:                // methods
0269:
0270:                void setRefnum(int refnum) {
0271:                    this .refnum = refnum;
0272:                }
0273:
0274:                private PdfWriter.PdfBody.PdfCrossReference addToObjStm(
0275:                        PdfObject obj, int nObj) throws IOException {
0276:                    if (numObj >= OBJSINSTREAM)
0277:                        flushObjStm();
0278:                    if (index == null) {
0279:                        index = new ByteBuffer();
0280:                        streamObjects = new ByteBuffer();
0281:                        currentObjNum = getIndirectReferenceNumber();
0282:                        numObj = 0;
0283:                    }
0284:                    int p = streamObjects.size();
0285:                    int idx = numObj++;
0286:                    PdfEncryption enc = writer.crypto;
0287:                    writer.crypto = null;
0288:                    obj.toPdf(writer, streamObjects);
0289:                    writer.crypto = enc;
0290:                    streamObjects.append(' ');
0291:                    index.append(nObj).append(' ').append(p).append(' ');
0292:                    return new PdfWriter.PdfBody.PdfCrossReference(2, nObj,
0293:                            currentObjNum, idx);
0294:                }
0295:
0296:                private void flushObjStm() throws IOException {
0297:                    if (numObj == 0)
0298:                        return;
0299:                    int first = index.size();
0300:                    index.append(streamObjects);
0301:                    PdfStream stream = new PdfStream(index.toByteArray());
0302:                    stream.flateCompress();
0303:                    stream.put(PdfName.TYPE, PdfName.OBJSTM);
0304:                    stream.put(PdfName.N, new PdfNumber(numObj));
0305:                    stream.put(PdfName.FIRST, new PdfNumber(first));
0306:                    add(stream, currentObjNum);
0307:                    index = null;
0308:                    streamObjects = null;
0309:                    numObj = 0;
0310:                }
0311:
0312:                /**
0313:                 * Adds a <CODE>PdfObject</CODE> to the body.
0314:                 * <P>
0315:                 * This methods creates a <CODE>PdfIndirectObject</CODE> with a
0316:                 * certain number, containing the given <CODE>PdfObject</CODE>.
0317:                 * It also adds a <CODE>PdfCrossReference</CODE> for this object
0318:                 * to an <CODE>ArrayList</CODE> that will be used to build the
0319:                 * Cross-reference Table.
0320:                 *
0321:                 * @param		object			a <CODE>PdfObject</CODE>
0322:                 * @return		a <CODE>PdfIndirectObject</CODE>
0323:                 * @throws IOException
0324:                 */
0325:
0326:                PdfIndirectObject add(PdfObject object) throws IOException {
0327:                    return add(object, getIndirectReferenceNumber());
0328:                }
0329:
0330:                PdfIndirectObject add(PdfObject object, boolean inObjStm)
0331:                        throws IOException {
0332:                    return add(object, getIndirectReferenceNumber(), inObjStm);
0333:                }
0334:
0335:                /**
0336:                 * Gets a PdfIndirectReference for an object that will be created in the future.
0337:                 * @return a PdfIndirectReference
0338:                 */
0339:
0340:                PdfIndirectReference getPdfIndirectReference() {
0341:                    return new PdfIndirectReference(0,
0342:                            getIndirectReferenceNumber());
0343:                }
0344:
0345:                int getIndirectReferenceNumber() {
0346:                    int n = refnum++;
0347:                    xrefs.add(new PdfCrossReference(n, 0, 65536));
0348:                    return n;
0349:                }
0350:
0351:                /**
0352:                 * Adds a <CODE>PdfObject</CODE> to the body given an already existing
0353:                 * PdfIndirectReference.
0354:                 * <P>
0355:                 * This methods creates a <CODE>PdfIndirectObject</CODE> with the number given by
0356:                 * <CODE>ref</CODE>, containing the given <CODE>PdfObject</CODE>.
0357:                 * It also adds a <CODE>PdfCrossReference</CODE> for this object
0358:                 * to an <CODE>ArrayList</CODE> that will be used to build the
0359:                 * Cross-reference Table.
0360:                 *
0361:                 * @param		object			a <CODE>PdfObject</CODE>
0362:                 * @param		ref		        a <CODE>PdfIndirectReference</CODE>
0363:                 * @return		a <CODE>PdfIndirectObject</CODE>
0364:                 * @throws IOException
0365:                 */
0366:
0367:                PdfIndirectObject add(PdfObject object, PdfIndirectReference ref)
0368:                        throws IOException {
0369:                    return add(object, ref.getNumber());
0370:                }
0371:
0372:                PdfIndirectObject add(PdfObject object,
0373:                        PdfIndirectReference ref, boolean inObjStm)
0374:                        throws IOException {
0375:                    return add(object, ref.getNumber(), inObjStm);
0376:                }
0377:
0378:                PdfIndirectObject add(PdfObject object, int refNumber)
0379:                        throws IOException {
0380:                    return add(object, refNumber, true); // to false
0381:                }
0382:
0383:                PdfIndirectObject add(PdfObject object, int refNumber,
0384:                        boolean inObjStm) throws IOException {
0385:                    if (inObjStm && object.canBeInObjStm()
0386:                            && writer.isFullCompression()) {
0387:                        PdfCrossReference pxref = addToObjStm(object, refNumber);
0388:                        PdfIndirectObject indirect = new PdfIndirectObject(
0389:                                refNumber, object, writer);
0390:                        if (!xrefs.add(pxref)) {
0391:                            xrefs.remove(pxref);
0392:                            xrefs.add(pxref);
0393:                        }
0394:                        return indirect;
0395:                    } else {
0396:                        PdfIndirectObject indirect = new PdfIndirectObject(
0397:                                refNumber, object, writer);
0398:                        PdfCrossReference pxref = new PdfCrossReference(
0399:                                refNumber, position);
0400:                        if (!xrefs.add(pxref)) {
0401:                            xrefs.remove(pxref);
0402:                            xrefs.add(pxref);
0403:                        }
0404:                        indirect.writeTo(writer.getOs());
0405:                        position = writer.getOs().getCounter();
0406:                        return indirect;
0407:                    }
0408:                }
0409:
0410:                /**
0411:                 * Returns the offset of the Cross-Reference table.
0412:                 *
0413:                 * @return		an offset
0414:                 */
0415:
0416:                int offset() {
0417:                    return position;
0418:                }
0419:
0420:                /**
0421:                 * Returns the total number of objects contained in the CrossReferenceTable of this <CODE>Body</CODE>.
0422:                 *
0423:                 * @return	a number of objects
0424:                 */
0425:
0426:                int size() {
0427:                    return Math.max(((PdfCrossReference) xrefs.last())
0428:                            .getRefnum() + 1, refnum);
0429:                }
0430:
0431:                /**
0432:                 * Returns the CrossReferenceTable of the <CODE>Body</CODE>.
0433:                 * @param os
0434:                 * @param root
0435:                 * @param info
0436:                 * @param encryption
0437:                 * @param fileID
0438:                 * @param prevxref
0439:                 * @throws IOException
0440:                 */
0441:
0442:                void writeCrossReferenceTable(OutputStream os,
0443:                        PdfIndirectReference root, PdfIndirectReference info,
0444:                        PdfIndirectReference encryption, PdfObject fileID,
0445:                        int prevxref) throws IOException {
0446:                    int refNumber = 0;
0447:                    if (writer.isFullCompression()) {
0448:                        flushObjStm();
0449:                        refNumber = getIndirectReferenceNumber();
0450:                        xrefs.add(new PdfCrossReference(refNumber, position));
0451:                    }
0452:                    PdfCrossReference entry = (PdfCrossReference) xrefs.first();
0453:                    int first = entry.getRefnum();
0454:                    int len = 0;
0455:                    ArrayList sections = new ArrayList();
0456:                    for (Iterator i = xrefs.iterator(); i.hasNext();) {
0457:                        entry = (PdfCrossReference) i.next();
0458:                        if (first + len == entry.getRefnum())
0459:                            ++len;
0460:                        else {
0461:                            sections.add(new Integer(first));
0462:                            sections.add(new Integer(len));
0463:                            first = entry.getRefnum();
0464:                            len = 1;
0465:                        }
0466:                    }
0467:                    sections.add(new Integer(first));
0468:                    sections.add(new Integer(len));
0469:                    if (writer.isFullCompression()) {
0470:                        int mid = 4;
0471:                        int mask = 0xff000000;
0472:                        for (; mid > 1; --mid) {
0473:                            if ((mask & position) != 0)
0474:                                break;
0475:                            mask >>>= 8;
0476:                        }
0477:                        ByteBuffer buf = new ByteBuffer();
0478:
0479:                        for (Iterator i = xrefs.iterator(); i.hasNext();) {
0480:                            entry = (PdfCrossReference) i.next();
0481:                            entry.toPdf(mid, buf);
0482:                        }
0483:                        PdfStream xr = new PdfStream(buf.toByteArray());
0484:                        buf = null;
0485:                        xr.flateCompress();
0486:                        xr.put(PdfName.SIZE, new PdfNumber(size()));
0487:                        xr.put(PdfName.ROOT, root);
0488:                        if (info != null) {
0489:                            xr.put(PdfName.INFO, info);
0490:                        }
0491:                        if (encryption != null)
0492:                            xr.put(PdfName.ENCRYPT, encryption);
0493:                        if (fileID != null)
0494:                            xr.put(PdfName.ID, fileID);
0495:                        xr
0496:                                .put(PdfName.W, new PdfArray(new int[] { 1,
0497:                                        mid, 2 }));
0498:                        xr.put(PdfName.TYPE, PdfName.XREF);
0499:                        PdfArray idx = new PdfArray();
0500:                        for (int k = 0; k < sections.size(); ++k)
0501:                            idx.add(new PdfNumber(((Integer) sections.get(k))
0502:                                    .intValue()));
0503:                        xr.put(PdfName.INDEX, idx);
0504:                        if (prevxref > 0)
0505:                            xr.put(PdfName.PREV, new PdfNumber(prevxref));
0506:                        PdfEncryption enc = writer.crypto;
0507:                        writer.crypto = null;
0508:                        PdfIndirectObject indirect = new PdfIndirectObject(
0509:                                refNumber, xr, writer);
0510:                        indirect.writeTo(writer.getOs());
0511:                        writer.crypto = enc;
0512:                    } else {
0513:                        os.write(getISOBytes("xref\n"));
0514:                        Iterator i = xrefs.iterator();
0515:                        for (int k = 0; k < sections.size(); k += 2) {
0516:                            first = ((Integer) sections.get(k)).intValue();
0517:                            len = ((Integer) sections.get(k + 1)).intValue();
0518:                            os.write(getISOBytes(String.valueOf(first)));
0519:                            os.write(getISOBytes(" "));
0520:                            os.write(getISOBytes(String.valueOf(len)));
0521:                            os.write('\n');
0522:                            while (len-- > 0) {
0523:                                entry = (PdfCrossReference) i.next();
0524:                                entry.toPdf(os);
0525:                            }
0526:                        }
0527:                    }
0528:                }
0529:            }
0530:
0531:            /**
0532:             * <CODE>PdfTrailer</CODE> is the PDF Trailer object.
0533:             * <P>
0534:             * This object is described in the 'Portable Document Format Reference Manual version 1.3'
0535:             * section 5.16 (page 59-60).
0536:             */
0537:
0538:            static class PdfTrailer extends PdfDictionary {
0539:
0540:                // membervariables
0541:
0542:                int offset;
0543:
0544:                // constructors
0545:
0546:                /**
0547:                 * Constructs a PDF-Trailer.
0548:                 *
0549:                 * @param		size		the number of entries in the <CODE>PdfCrossReferenceTable</CODE>
0550:                 * @param		offset		offset of the <CODE>PdfCrossReferenceTable</CODE>
0551:                 * @param		root		an indirect reference to the root of the PDF document
0552:                 * @param		info		an indirect reference to the info object of the PDF document
0553:                 * @param encryption
0554:                 * @param fileID
0555:                 * @param prevxref
0556:                 */
0557:
0558:                PdfTrailer(int size, int offset, PdfIndirectReference root,
0559:                        PdfIndirectReference info,
0560:                        PdfIndirectReference encryption, PdfObject fileID,
0561:                        int prevxref) {
0562:                    this .offset = offset;
0563:                    put(PdfName.SIZE, new PdfNumber(size));
0564:                    put(PdfName.ROOT, root);
0565:                    if (info != null) {
0566:                        put(PdfName.INFO, info);
0567:                    }
0568:                    if (encryption != null)
0569:                        put(PdfName.ENCRYPT, encryption);
0570:                    if (fileID != null)
0571:                        put(PdfName.ID, fileID);
0572:                    if (prevxref > 0)
0573:                        put(PdfName.PREV, new PdfNumber(prevxref));
0574:                }
0575:
0576:                /**
0577:                 * Returns the PDF representation of this <CODE>PdfObject</CODE>.
0578:                 * @param writer
0579:                 * @param os
0580:                 * @throws IOException
0581:                 */
0582:                public void toPdf(PdfWriter writer, OutputStream os)
0583:                        throws IOException {
0584:                    os.write(getISOBytes("trailer\n"));
0585:                    super .toPdf(null, os);
0586:                    os.write(getISOBytes("\nstartxref\n"));
0587:                    os.write(getISOBytes(String.valueOf(offset)));
0588:                    os.write(getISOBytes("\n%%EOF\n"));
0589:                }
0590:            }
0591:
0592:            //	ESSENTIALS 
0593:
0594:            //	Construct a PdfWriter instance
0595:
0596:            /**
0597:             * Constructs a <CODE>PdfWriter</CODE>.
0598:             */
0599:            protected PdfWriter() {
0600:            }
0601:
0602:            /**
0603:             * Constructs a <CODE>PdfWriter</CODE>.
0604:             * <P>
0605:             * Remark: a PdfWriter can only be constructed by calling the method
0606:             * <CODE>getInstance(Document document, OutputStream os)</CODE>.
0607:             *
0608:             * @param	document	The <CODE>PdfDocument</CODE> that has to be written
0609:             * @param	os			The <CODE>OutputStream</CODE> the writer has to write to.
0610:             */
0611:
0612:            protected PdfWriter(PdfDocument document, OutputStream os) {
0613:                super (document, os);
0614:                pdf = document;
0615:                directContent = new PdfContentByte(this );
0616:                directContentUnder = new PdfContentByte(this );
0617:            }
0618:
0619:            /**
0620:             * Use this method to get an instance of the <CODE>PdfWriter</CODE>.
0621:             *
0622:             * @param	document	The <CODE>Document</CODE> that has to be written
0623:             * @param	os	The <CODE>OutputStream</CODE> the writer has to write to.
0624:             * @return	a new <CODE>PdfWriter</CODE>
0625:             *
0626:             * @throws	DocumentException on error
0627:             */
0628:
0629:            public static PdfWriter getInstance(Document document,
0630:                    OutputStream os) throws DocumentException {
0631:                PdfDocument pdf = new PdfDocument();
0632:                document.addDocListener(pdf);
0633:                PdfWriter writer = new PdfWriter(pdf, os);
0634:                pdf.addWriter(writer);
0635:                return writer;
0636:            }
0637:
0638:            /**
0639:             * Use this method to get an instance of the <CODE>PdfWriter</CODE>.
0640:             *
0641:             * @return a new <CODE>PdfWriter</CODE>
0642:             * @param document The <CODE>Document</CODE> that has to be written
0643:             * @param os The <CODE>OutputStream</CODE> the writer has to write to.
0644:             * @param listener A <CODE>DocListener</CODE> to pass to the PdfDocument.
0645:             * @throws DocumentException on error
0646:             */
0647:
0648:            public static PdfWriter getInstance(Document document,
0649:                    OutputStream os, DocListener listener)
0650:                    throws DocumentException {
0651:                PdfDocument pdf = new PdfDocument();
0652:                pdf.addDocListener(listener);
0653:                document.addDocListener(pdf);
0654:                PdfWriter writer = new PdfWriter(pdf, os);
0655:                pdf.addWriter(writer);
0656:                return writer;
0657:            }
0658:
0659:            //	the PdfDocument instance
0660:
0661:            /** the pdfdocument object. */
0662:            protected PdfDocument pdf;
0663:
0664:            /**
0665:             * Gets the <CODE>PdfDocument</CODE> associated with this writer.
0666:             * @return the <CODE>PdfDocument</CODE>
0667:             */
0668:
0669:            PdfDocument getPdfDocument() {
0670:                return pdf;
0671:            }
0672:
0673:            /**
0674:             * Use this method to get the info dictionary if you want to
0675:             * change it directly (add keys and values to the info dictionary).
0676:             * @return the info dictionary
0677:             */
0678:            public PdfDictionary getInfo() {
0679:                return pdf.getInfo();
0680:            }
0681:
0682:            /**
0683:             * Use this method to get the current vertical page position.
0684:             * @param ensureNewLine Tells whether a new line shall be enforced. This may cause side effects 
0685:             *   for elements that do not terminate the lines they've started because those lines will get
0686:             *   terminated. 
0687:             * @return The current vertical page position.
0688:             */
0689:            public float getVerticalPosition(boolean ensureNewLine) {
0690:                return pdf.getVerticalPosition(ensureNewLine);
0691:            }
0692:
0693:            //	the PdfDirectContentByte instances
0694:
0695:            /*
0696:             * You should see Direct Content as a canvas on which you can draw
0697:             * graphics and text. One canvas goes on top of the page (getDirectContent),
0698:             * the other goes underneath (getDirectContentUnder).
0699:             * You can always the same object throughout your document,
0700:             * even if you have moved to a new page. Whatever you add on
0701:             * the canvas will be displayed on top or under the current page.
0702:             */
0703:
0704:            /** The direct content in this document. */
0705:            protected PdfContentByte directContent;
0706:
0707:            /** The direct content under in this document. */
0708:            protected PdfContentByte directContentUnder;
0709:
0710:            /**
0711:             * Use this method to get the direct content for this document.
0712:             * There is only one direct content, multiple calls to this method
0713:             * will allways retrieve the same object.
0714:             * @return the direct content
0715:             */
0716:
0717:            public PdfContentByte getDirectContent() {
0718:                if (!open)
0719:                    throw new RuntimeException("The document is not open.");
0720:                return directContent;
0721:            }
0722:
0723:            /**
0724:             * Use this method to get the direct content under for this document.
0725:             * There is only one direct content, multiple calls to this method
0726:             * will allways retrieve the same object.
0727:             * @return the direct content
0728:             */
0729:
0730:            public PdfContentByte getDirectContentUnder() {
0731:                if (!open)
0732:                    throw new RuntimeException("The document is not open.");
0733:                return directContentUnder;
0734:            }
0735:
0736:            /**
0737:             * Resets all the direct contents to empty.
0738:             * This happens when a new page is started.
0739:             */
0740:            void resetContent() {
0741:                directContent.reset();
0742:                directContentUnder.reset();
0743:            }
0744:
0745:            //	PDF body
0746:
0747:            /*
0748:             * A PDF file has 4 parts: a header, a body, a cross-reference table, and a trailer.
0749:             * The body contains all the PDF objects that make up the PDF document.
0750:             * Each element gets a reference (a set of numbers) and the byte position of
0751:             * every object is stored in the cross-reference table.
0752:             * Use these methods only if you know what you're doing.
0753:             */
0754:
0755:            /** body of the PDF document */
0756:            protected PdfBody body;
0757:
0758:            /**
0759:             * Adds the local destinations to the body of the document.
0760:             * @param dest the <CODE>HashMap</CODE> containing the destinations
0761:             * @throws IOException on error
0762:             */
0763:
0764:            void addLocalDestinations(TreeMap dest) throws IOException {
0765:                for (Iterator i = dest.entrySet().iterator(); i.hasNext();) {
0766:                    Map.Entry entry = (Map.Entry) i.next();
0767:                    String name = (String) entry.getKey();
0768:                    Object obj[] = (Object[]) entry.getValue();
0769:                    PdfDestination destination = (PdfDestination) obj[2];
0770:                    if (destination == null)
0771:                        throw new RuntimeException("The name '" + name
0772:                                + "' has no local destination.");
0773:                    if (obj[1] == null)
0774:                        obj[1] = getPdfIndirectReference();
0775:                    addToBody(destination, (PdfIndirectReference) obj[1]);
0776:                }
0777:            }
0778:
0779:            /**
0780:             * Use this method to add a PDF object to the PDF body.
0781:             * Use this method only if you know what you're doing!
0782:             * @param object
0783:             * @return a PdfIndirectObject
0784:             * @throws IOException
0785:             */
0786:            public PdfIndirectObject addToBody(PdfObject object)
0787:                    throws IOException {
0788:                PdfIndirectObject iobj = body.add(object);
0789:                return iobj;
0790:            }
0791:
0792:            /**
0793:             * Use this method to add a PDF object to the PDF body.
0794:             * Use this method only if you know what you're doing!
0795:             * @param object
0796:             * @param inObjStm
0797:             * @return a PdfIndirectObject
0798:             * @throws IOException
0799:             */
0800:            public PdfIndirectObject addToBody(PdfObject object,
0801:                    boolean inObjStm) throws IOException {
0802:                PdfIndirectObject iobj = body.add(object, inObjStm);
0803:                return iobj;
0804:            }
0805:
0806:            /**
0807:             * Use this method to add a PDF object to the PDF body.
0808:             * Use this method only if you know what you're doing!
0809:             * @param object
0810:             * @param ref
0811:             * @return a PdfIndirectObject
0812:             * @throws IOException
0813:             */
0814:            public PdfIndirectObject addToBody(PdfObject object,
0815:                    PdfIndirectReference ref) throws IOException {
0816:                PdfIndirectObject iobj = body.add(object, ref);
0817:                return iobj;
0818:            }
0819:
0820:            /**
0821:             * Use this method to add a PDF object to the PDF body.
0822:             * Use this method only if you know what you're doing!
0823:             * @param object
0824:             * @param ref
0825:             * @param inObjStm
0826:             * @return a PdfIndirectObject
0827:             * @throws IOException
0828:             */
0829:            public PdfIndirectObject addToBody(PdfObject object,
0830:                    PdfIndirectReference ref, boolean inObjStm)
0831:                    throws IOException {
0832:                PdfIndirectObject iobj = body.add(object, ref, inObjStm);
0833:                return iobj;
0834:            }
0835:
0836:            /**
0837:             * Use this method to add a PDF object to the PDF body.
0838:             * Use this method only if you know what you're doing!
0839:             * @param object
0840:             * @param refNumber
0841:             * @return a PdfIndirectObject
0842:             * @throws IOException
0843:             */
0844:            public PdfIndirectObject addToBody(PdfObject object, int refNumber)
0845:                    throws IOException {
0846:                PdfIndirectObject iobj = body.add(object, refNumber);
0847:                return iobj;
0848:            }
0849:
0850:            /**
0851:             * Use this method to add a PDF object to the PDF body.
0852:             * Use this method only if you know what you're doing!
0853:             * @param object
0854:             * @param refNumber
0855:             * @param inObjStm
0856:             * @return a PdfIndirectObject
0857:             * @throws IOException
0858:             */
0859:            public PdfIndirectObject addToBody(PdfObject object, int refNumber,
0860:                    boolean inObjStm) throws IOException {
0861:                PdfIndirectObject iobj = body.add(object, refNumber, inObjStm);
0862:                return iobj;
0863:            }
0864:
0865:            /**
0866:             * Use this to get an <CODE>PdfIndirectReference</CODE> for an object that
0867:             * will be created in the future.
0868:             * Use this method only if you know what you're doing!
0869:             * @return the <CODE>PdfIndirectReference</CODE>
0870:             */
0871:
0872:            public PdfIndirectReference getPdfIndirectReference() {
0873:                return body.getPdfIndirectReference();
0874:            }
0875:
0876:            int getIndirectReferenceNumber() {
0877:                return body.getIndirectReferenceNumber();
0878:            }
0879:
0880:            /**
0881:             * Returns the outputStreamCounter.
0882:             * @return the outputStreamCounter
0883:             */
0884:            OutputStreamCounter getOs() {
0885:                return os;
0886:            }
0887:
0888:            //	PDF Catalog
0889:
0890:            /*
0891:             * The Catalog is also called the root object of the document.
0892:             * Whereas the Cross-Reference maps the objects number with the
0893:             * byte offset so that the viewer can find the objects, the
0894:             * Catalog tells the viewer the numbers of the objects needed
0895:             * to render the document.
0896:             */
0897:
0898:            protected PdfDictionary getCatalog(PdfIndirectReference rootObj) {
0899:                PdfDictionary catalog = pdf.getCatalog(rootObj);
0900:                // [F12] tagged PDF
0901:                if (tagged) {
0902:                    try {
0903:                        getStructureTreeRoot().buildTree();
0904:                    } catch (Exception e) {
0905:                        throw new ExceptionConverter(e);
0906:                    }
0907:                    catalog.put(PdfName.STRUCTTREEROOT, structureTreeRoot
0908:                            .getReference());
0909:                    PdfDictionary mi = new PdfDictionary();
0910:                    mi.put(PdfName.MARKED, PdfBoolean.PDFTRUE);
0911:                    if (userProperties)
0912:                        mi.put(PdfName.USERPROPERTIES, PdfBoolean.PDFTRUE);
0913:                    catalog.put(PdfName.MARKINFO, mi);
0914:                }
0915:                // [F13] OCG
0916:                if (!documentOCG.isEmpty()) {
0917:                    fillOCProperties(false);
0918:                    catalog.put(PdfName.OCPROPERTIES, OCProperties);
0919:                }
0920:                return catalog;
0921:            }
0922:
0923:            /** Holds value of property extraCatalog this is used for Output Intents. */
0924:            protected PdfDictionary extraCatalog;
0925:
0926:            /**
0927:             * Sets extra keys to the catalog.
0928:             * @return the catalog to change
0929:             */
0930:            public PdfDictionary getExtraCatalog() {
0931:                if (extraCatalog == null)
0932:                    extraCatalog = new PdfDictionary();
0933:                return this .extraCatalog;
0934:            }
0935:
0936:            //	PdfPages
0937:
0938:            /*
0939:             * The page root keeps the complete page tree of the document.
0940:             * There's an entry in the Catalog that refers to the root
0941:             * of the page tree, the page tree contains the references
0942:             * to pages and other page trees.
0943:             */
0944:
0945:            /** The root of the page tree. */
0946:            protected PdfPages root = new PdfPages(this );
0947:            /** The PdfIndirectReference to the pages. */
0948:            protected ArrayList pageReferences = new ArrayList();
0949:            /** The current page number. */
0950:            protected int currentPageNumber = 1;
0951:
0952:            /**
0953:             * Use this method to make sure the page tree has a lineair structure
0954:             * (every leave is attached directly to the root).
0955:             * Use this method to allow page reordering with method reorderPages.
0956:             */
0957:            public void setLinearPageMode() {
0958:                root.setLinearMode(null);
0959:            }
0960:
0961:            /**
0962:             * Use this method to reorder the pages in the document.
0963:             * A <CODE>null</CODE> argument value only returns the number of pages to process.
0964:             * It is advisable to issue a <CODE>Document.newPage()</CODE> before using this method.
0965:             * @return the total number of pages
0966:             * @param order an array with the new page sequence. It must have the
0967:             * same size as the number of pages.
0968:             * @throws DocumentException if all the pages are not present in the array
0969:             */
0970:            public int reorderPages(int order[]) throws DocumentException {
0971:                return root.reorderPages(order);
0972:            }
0973:
0974:            /**
0975:             * Use this method to get a reference to a page existing or not.
0976:             * If the page does not exist yet the reference will be created
0977:             * in advance. If on closing the document, a page number greater
0978:             * than the total number of pages was requested, an exception
0979:             * is thrown.
0980:             * @param page the page number. The first page is 1
0981:             * @return the reference to the page
0982:             */
0983:            public PdfIndirectReference getPageReference(int page) {
0984:                --page;
0985:                if (page < 0)
0986:                    throw new IndexOutOfBoundsException(
0987:                            "The page numbers start at 1.");
0988:                PdfIndirectReference ref;
0989:                if (page < pageReferences.size()) {
0990:                    ref = (PdfIndirectReference) pageReferences.get(page);
0991:                    if (ref == null) {
0992:                        ref = body.getPdfIndirectReference();
0993:                        pageReferences.set(page, ref);
0994:                    }
0995:                } else {
0996:                    int empty = page - pageReferences.size();
0997:                    for (int k = 0; k < empty; ++k)
0998:                        pageReferences.add(null);
0999:                    ref = body.getPdfIndirectReference();
1000:                    pageReferences.add(ref);
1001:                }
1002:                return ref;
1003:            }
1004:
1005:            /**
1006:             * Gets the pagenumber of this document.
1007:             * This number can be different from the real pagenumber,
1008:             * if you have (re)set the page number previously.
1009:             * @return a page number
1010:             */
1011:
1012:            public int getPageNumber() {
1013:                return pdf.getPageNumber();
1014:            }
1015:
1016:            PdfIndirectReference getCurrentPage() {
1017:                return getPageReference(currentPageNumber);
1018:            }
1019:
1020:            public int getCurrentPageNumber() {
1021:                return currentPageNumber;
1022:            }
1023:
1024:            /**
1025:             * Adds some <CODE>PdfContents</CODE> to this Writer.
1026:             * <P>
1027:             * The document has to be open before you can begin to add content
1028:             * to the body of the document.
1029:             *
1030:             * @return a <CODE>PdfIndirectReference</CODE>
1031:             * @param page the <CODE>PdfPage</CODE> to add
1032:             * @param contents the <CODE>PdfContents</CODE> of the page
1033:             * @throws PdfException on error
1034:             */
1035:
1036:            PdfIndirectReference add(PdfPage page, PdfContents contents)
1037:                    throws PdfException {
1038:                if (!open) {
1039:                    throw new PdfException("The document isn't open.");
1040:                }
1041:                PdfIndirectObject object;
1042:                try {
1043:                    object = addToBody(contents);
1044:                } catch (IOException ioe) {
1045:                    throw new ExceptionConverter(ioe);
1046:                }
1047:                page.add(object.getIndirectReference());
1048:                // [U5]
1049:                if (group != null) {
1050:                    page.put(PdfName.GROUP, group);
1051:                    group = null;
1052:                }
1053:                root.addPage(page);
1054:                currentPageNumber++;
1055:                return null;
1056:            }
1057:
1058:            //	page events
1059:
1060:            /*
1061:             * Page events are specific for iText, not for PDF.
1062:             * Upon specific events (for instance when a page starts
1063:             * or ends), the corresponing method in the page event
1064:             * implementation that is added to the writer is invoked.
1065:             */
1066:
1067:            /** The <CODE>PdfPageEvent</CODE> for this document. */
1068:            private PdfPageEvent pageEvent;
1069:
1070:            /**
1071:             * Sets the <CODE>PdfPageEvent</CODE> for this document.
1072:             * @param event the <CODE>PdfPageEvent</CODE> for this document
1073:             */
1074:
1075:            public void setPageEvent(PdfPageEvent event) {
1076:                if (event == null)
1077:                    this .pageEvent = null;
1078:                else if (this .pageEvent == null)
1079:                    this .pageEvent = event;
1080:                else if (this .pageEvent instanceof  PdfPageEventForwarder)
1081:                    ((PdfPageEventForwarder) this .pageEvent)
1082:                            .addPageEvent(event);
1083:                else {
1084:                    PdfPageEventForwarder forward = new PdfPageEventForwarder();
1085:                    forward.addPageEvent(this .pageEvent);
1086:                    forward.addPageEvent(event);
1087:                    this .pageEvent = forward;
1088:                }
1089:            }
1090:
1091:            /**
1092:             * Gets the <CODE>PdfPageEvent</CODE> for this document or <CODE>null</CODE>
1093:             * if none is set.
1094:             * @return the <CODE>PdfPageEvent</CODE> for this document or <CODE>null</CODE>
1095:             * if none is set
1096:             */
1097:
1098:            public PdfPageEvent getPageEvent() {
1099:                return pageEvent;
1100:            }
1101:
1102:            //	Open en Close method + method that create the PDF
1103:
1104:            /** A number refering to the previous Cross-Reference Table. */
1105:            protected int prevxref = 0;
1106:
1107:            /**
1108:             * Signals that the <CODE>Document</CODE> has been opened and that
1109:             * <CODE>Elements</CODE> can be added.
1110:             * <P>
1111:             * When this method is called, the PDF-document header is
1112:             * written to the outputstream.
1113:             * @see com.lowagie.text.DocWriter#open()
1114:             */
1115:            public void open() {
1116:                super .open();
1117:                try {
1118:                    pdf_version.writeHeader(os);
1119:                    body = new PdfBody(this );
1120:                    if (pdfxConformance.isPdfX32002()) {
1121:                        PdfDictionary sec = new PdfDictionary();
1122:                        sec.put(PdfName.GAMMA, new PdfArray(new float[] { 2.2f,
1123:                                2.2f, 2.2f }));
1124:                        sec.put(PdfName.MATRIX, new PdfArray(new float[] {
1125:                                0.4124f, 0.2126f, 0.0193f, 0.3576f, 0.7152f,
1126:                                0.1192f, 0.1805f, 0.0722f, 0.9505f }));
1127:                        sec.put(PdfName.WHITEPOINT, new PdfArray(new float[] {
1128:                                0.9505f, 1f, 1.089f }));
1129:                        PdfArray arr = new PdfArray(PdfName.CALRGB);
1130:                        arr.add(sec);
1131:                        setDefaultColorspace(PdfName.DEFAULTRGB, addToBody(arr)
1132:                                .getIndirectReference());
1133:                    }
1134:                } catch (IOException ioe) {
1135:                    throw new ExceptionConverter(ioe);
1136:                }
1137:            }
1138:
1139:            /**
1140:             * Signals that the <CODE>Document</CODE> was closed and that no other
1141:             * <CODE>Elements</CODE> will be added.
1142:             * <P>
1143:             * The pages-tree is built and written to the outputstream.
1144:             * A Catalog is constructed, as well as an Info-object,
1145:             * the referencetable is composed and everything is written
1146:             * to the outputstream embedded in a Trailer.
1147:             * @see com.lowagie.text.DocWriter#close()
1148:             */
1149:            public void close() {
1150:                if (open) {
1151:                    if ((currentPageNumber - 1) != pageReferences.size())
1152:                        throw new RuntimeException("The page "
1153:                                + pageReferences.size()
1154:                                + " was requested but the document has only "
1155:                                + (currentPageNumber - 1) + " pages.");
1156:                    pdf.close();
1157:                    try {
1158:                        addSharedObjectsToBody();
1159:                        // add the root to the body
1160:                        PdfIndirectReference rootRef = root.writePageTree();
1161:                        // make the catalog-object and add it to the body
1162:                        PdfDictionary catalog = getCatalog(rootRef);
1163:                        // [C9] if there is XMP data to add: add it
1164:                        if (xmpMetadata != null) {
1165:                            PdfStream xmp = new PdfStream(xmpMetadata);
1166:                            xmp.put(PdfName.TYPE, PdfName.METADATA);
1167:                            xmp.put(PdfName.SUBTYPE, PdfName.XML);
1168:                            if (crypto != null && !crypto.isMetadataEncrypted()) {
1169:                                PdfArray ar = new PdfArray();
1170:                                ar.add(PdfName.CRYPT);
1171:                                xmp.put(PdfName.FILTER, ar);
1172:                            }
1173:                            catalog.put(PdfName.METADATA, body.add(xmp)
1174:                                    .getIndirectReference());
1175:                        }
1176:                        // [C10] make pdfx conformant
1177:                        if (isPdfX()) {
1178:                            pdfxConformance.completeInfoDictionary(getInfo());
1179:                            pdfxConformance
1180:                                    .completeExtraCatalog(getExtraCatalog());
1181:                        }
1182:                        // [C11] Output Intents
1183:                        if (extraCatalog != null) {
1184:                            catalog.mergeDifferent(extraCatalog);
1185:                        }
1186:
1187:                        writeOutlines(catalog, false);
1188:
1189:                        // add the Catalog to the body
1190:                        PdfIndirectObject indirectCatalog = addToBody(catalog,
1191:                                false);
1192:                        // add the info-object to the body
1193:                        PdfIndirectObject infoObj = addToBody(getInfo(), false);
1194:
1195:                        // [F1] encryption
1196:                        PdfIndirectReference encryption = null;
1197:                        PdfObject fileID = null;
1198:                        body.flushObjStm();
1199:                        if (crypto != null) {
1200:                            PdfIndirectObject encryptionObject = addToBody(
1201:                                    crypto.getEncryptionDictionary(), false);
1202:                            encryption = encryptionObject
1203:                                    .getIndirectReference();
1204:                            fileID = crypto.getFileID();
1205:                        } else
1206:                            fileID = PdfEncryption.createInfoId(PdfEncryption
1207:                                    .createDocumentId());
1208:
1209:                        // write the cross-reference table of the body
1210:                        body.writeCrossReferenceTable(os, indirectCatalog
1211:                                .getIndirectReference(), infoObj
1212:                                .getIndirectReference(), encryption, fileID,
1213:                                prevxref);
1214:
1215:                        // make the trailer
1216:                        // [F2] full compression
1217:                        if (fullCompression) {
1218:                            os.write(getISOBytes("startxref\n"));
1219:                            os
1220:                                    .write(getISOBytes(String.valueOf(body
1221:                                            .offset())));
1222:                            os.write(getISOBytes("\n%%EOF\n"));
1223:                        } else {
1224:                            PdfTrailer trailer = new PdfTrailer(body.size(),
1225:                                    body.offset(), indirectCatalog
1226:                                            .getIndirectReference(), infoObj
1227:                                            .getIndirectReference(),
1228:                                    encryption, fileID, prevxref);
1229:                            trailer.toPdf(this , os);
1230:                        }
1231:                        super .close();
1232:                    } catch (IOException ioe) {
1233:                        throw new ExceptionConverter(ioe);
1234:                    }
1235:                }
1236:            }
1237:
1238:            protected void addSharedObjectsToBody() throws IOException {
1239:                // [F3] add the fonts
1240:                for (Iterator it = documentFonts.values().iterator(); it
1241:                        .hasNext();) {
1242:                    FontDetails details = (FontDetails) it.next();
1243:                    details.writeFont(this );
1244:                }
1245:                // [F4] add the form XObjects
1246:                for (Iterator it = formXObjects.values().iterator(); it
1247:                        .hasNext();) {
1248:                    Object objs[] = (Object[]) it.next();
1249:                    PdfTemplate template = (PdfTemplate) objs[1];
1250:                    if (template != null
1251:                            && template.getIndirectReference() instanceof  PRIndirectReference)
1252:                        continue;
1253:                    if (template != null
1254:                            && template.getType() == PdfTemplate.TYPE_TEMPLATE) {
1255:                        addToBody(template.getFormXObject(), template
1256:                                .getIndirectReference());
1257:                    }
1258:                }
1259:                // [F5] add all the dependencies in the imported pages
1260:                for (Iterator it = importedPages.values().iterator(); it
1261:                        .hasNext();) {
1262:                    currentPdfReaderInstance = (PdfReaderInstance) it.next();
1263:                    currentPdfReaderInstance.writeAllPages();
1264:                }
1265:                currentPdfReaderInstance = null;
1266:                // [F6] add the spotcolors
1267:                for (Iterator it = documentColors.values().iterator(); it
1268:                        .hasNext();) {
1269:                    ColorDetails color = (ColorDetails) it.next();
1270:                    addToBody(color.getSpotColor(this ), color
1271:                            .getIndirectReference());
1272:                }
1273:                // [F7] add the pattern
1274:                for (Iterator it = documentPatterns.keySet().iterator(); it
1275:                        .hasNext();) {
1276:                    PdfPatternPainter pat = (PdfPatternPainter) it.next();
1277:                    addToBody(pat.getPattern(), pat.getIndirectReference());
1278:                }
1279:                // [F8] add the shading patterns
1280:                for (Iterator it = documentShadingPatterns.keySet().iterator(); it
1281:                        .hasNext();) {
1282:                    PdfShadingPattern shadingPattern = (PdfShadingPattern) it
1283:                            .next();
1284:                    shadingPattern.addToBody();
1285:                }
1286:                // [F9] add the shadings
1287:                for (Iterator it = documentShadings.keySet().iterator(); it
1288:                        .hasNext();) {
1289:                    PdfShading shading = (PdfShading) it.next();
1290:                    shading.addToBody();
1291:                }
1292:                // [F10] add the extgstate
1293:                for (Iterator it = documentExtGState.entrySet().iterator(); it
1294:                        .hasNext();) {
1295:                    Map.Entry entry = (Map.Entry) it.next();
1296:                    PdfDictionary gstate = (PdfDictionary) entry.getKey();
1297:                    PdfObject obj[] = (PdfObject[]) entry.getValue();
1298:                    addToBody(gstate, (PdfIndirectReference) obj[1]);
1299:                }
1300:                // [F11] add the properties
1301:                for (Iterator it = documentProperties.entrySet().iterator(); it
1302:                        .hasNext();) {
1303:                    Map.Entry entry = (Map.Entry) it.next();
1304:                    Object prop = entry.getKey();
1305:                    PdfObject[] obj = (PdfObject[]) entry.getValue();
1306:                    if (prop instanceof  PdfLayerMembership) {
1307:                        PdfLayerMembership layer = (PdfLayerMembership) prop;
1308:                        addToBody(layer.getPdfObject(), layer.getRef());
1309:                    } else if ((prop instanceof  PdfDictionary)
1310:                            && !(prop instanceof  PdfLayer)) {
1311:                        addToBody((PdfDictionary) prop,
1312:                                (PdfIndirectReference) obj[1]);
1313:                    }
1314:                }
1315:                // [F13] add the OCG layers
1316:                for (Iterator it = documentOCG.iterator(); it.hasNext();) {
1317:                    PdfOCG layer = (PdfOCG) it.next();
1318:                    addToBody(layer.getPdfObject(), layer.getRef());
1319:                }
1320:            }
1321:
1322:            // Root data for the PDF document (used when composing the Catalog)
1323:
1324:            //  [C1] Outlines (bookmarks)
1325:
1326:            /**
1327:             * Use this method to get the root outline
1328:             * and construct bookmarks.
1329:             * @return the root outline
1330:             */
1331:
1332:            public PdfOutline getRootOutline() {
1333:                return directContent.getRootOutline();
1334:            }
1335:
1336:            protected java.util.List newBookmarks;
1337:
1338:            /**
1339:             * Sets the bookmarks. The list structure is defined in
1340:             * {@link SimpleBookmark}.
1341:             * @param outlines the bookmarks or <CODE>null</CODE> to remove any
1342:             */
1343:            public void setOutlines(java.util.List outlines) {
1344:                newBookmarks = outlines;
1345:            }
1346:
1347:            protected void writeOutlines(PdfDictionary catalog,
1348:                    boolean namedAsNames) throws IOException {
1349:                if (newBookmarks == null || newBookmarks.isEmpty())
1350:                    return;
1351:                PdfDictionary top = new PdfDictionary();
1352:                PdfIndirectReference topRef = getPdfIndirectReference();
1353:                Object kids[] = SimpleBookmark.iterateOutlines(this , topRef,
1354:                        newBookmarks, namedAsNames);
1355:                top.put(PdfName.FIRST, (PdfIndirectReference) kids[0]);
1356:                top.put(PdfName.LAST, (PdfIndirectReference) kids[1]);
1357:                top.put(PdfName.COUNT, new PdfNumber(((Integer) kids[2])
1358:                        .intValue()));
1359:                addToBody(top, topRef);
1360:                catalog.put(PdfName.OUTLINES, topRef);
1361:            }
1362:
1363:            //	[C2] PdfVersion interface
1364:            /** possible PDF version (header) */
1365:            public static final char VERSION_1_2 = '2';
1366:            /** possible PDF version (header) */
1367:            public static final char VERSION_1_3 = '3';
1368:            /** possible PDF version (header) */
1369:            public static final char VERSION_1_4 = '4';
1370:            /** possible PDF version (header) */
1371:            public static final char VERSION_1_5 = '5';
1372:            /** possible PDF version (header) */
1373:            public static final char VERSION_1_6 = '6';
1374:            /** possible PDF version (header) */
1375:            public static final char VERSION_1_7 = '7';
1376:
1377:            /** possible PDF version (catalog) */
1378:            public static final PdfName PDF_VERSION_1_2 = new PdfName("1.2");
1379:            /** possible PDF version (catalog) */
1380:            public static final PdfName PDF_VERSION_1_3 = new PdfName("1.3");
1381:            /** possible PDF version (catalog) */
1382:            public static final PdfName PDF_VERSION_1_4 = new PdfName("1.4");
1383:            /** possible PDF version (catalog) */
1384:            public static final PdfName PDF_VERSION_1_5 = new PdfName("1.5");
1385:            /** possible PDF version (catalog) */
1386:            public static final PdfName PDF_VERSION_1_6 = new PdfName("1.6");
1387:            /** possible PDF version (catalog) */
1388:            public static final PdfName PDF_VERSION_1_7 = new PdfName("1.7");
1389:
1390:            /** Stores the version information for the header and the catalog. */
1391:            protected PdfVersionImp pdf_version = new PdfVersionImp();
1392:
1393:            /** @see com.lowagie.text.pdf.interfaces.PdfVersion#setPdfVersion(char) */
1394:            public void setPdfVersion(char version) {
1395:                pdf_version.setPdfVersion(version);
1396:            }
1397:
1398:            /** @see com.lowagie.text.pdf.interfaces.PdfVersion#setAtLeastPdfVersion(char) */
1399:            public void setAtLeastPdfVersion(char version) {
1400:                pdf_version.setAtLeastPdfVersion(version);
1401:            }
1402:
1403:            /** @see com.lowagie.text.pdf.interfaces.PdfVersion#setPdfVersion(com.lowagie.text.pdf.PdfName) */
1404:            public void setPdfVersion(PdfName version) {
1405:                pdf_version.setPdfVersion(version);
1406:            }
1407:
1408:            /**
1409:             * Returns the version information.
1410:             */
1411:            PdfVersionImp getPdfVersion() {
1412:                return pdf_version;
1413:            }
1414:
1415:            //  [C3] PdfViewerPreferences interface
1416:
1417:            // page layout (section 13.1.1 of "iText in Action")
1418:
1419:            /** A viewer preference */
1420:            public static final int PageLayoutSinglePage = 1;
1421:            /** A viewer preference */
1422:            public static final int PageLayoutOneColumn = 2;
1423:            /** A viewer preference */
1424:            public static final int PageLayoutTwoColumnLeft = 4;
1425:            /** A viewer preference */
1426:            public static final int PageLayoutTwoColumnRight = 8;
1427:            /** A viewer preference */
1428:            public static final int PageLayoutTwoPageLeft = 16;
1429:            /** A viewer preference */
1430:            public static final int PageLayoutTwoPageRight = 32;
1431:
1432:            // page mode (section 13.1.2 of "iText in Action")
1433:
1434:            /** A viewer preference */
1435:            public static final int PageModeUseNone = 64;
1436:            /** A viewer preference */
1437:            public static final int PageModeUseOutlines = 128;
1438:            /** A viewer preference */
1439:            public static final int PageModeUseThumbs = 256;
1440:            /** A viewer preference */
1441:            public static final int PageModeFullScreen = 512;
1442:            /** A viewer preference */
1443:            public static final int PageModeUseOC = 1024;
1444:            /** A viewer preference */
1445:            public static final int PageModeUseAttachments = 2048;
1446:
1447:            // values for setting viewer preferences in iText versions older than 2.x
1448:
1449:            /** A viewer preference */
1450:            public static final int HideToolbar = 1 << 12;
1451:            /** A viewer preference */
1452:            public static final int HideMenubar = 1 << 13;
1453:            /** A viewer preference */
1454:            public static final int HideWindowUI = 1 << 14;
1455:            /** A viewer preference */
1456:            public static final int FitWindow = 1 << 15;
1457:            /** A viewer preference */
1458:            public static final int CenterWindow = 1 << 16;
1459:            /** A viewer preference */
1460:            public static final int DisplayDocTitle = 1 << 17;
1461:
1462:            /** A viewer preference */
1463:            public static final int NonFullScreenPageModeUseNone = 1 << 18;
1464:            /** A viewer preference */
1465:            public static final int NonFullScreenPageModeUseOutlines = 1 << 19;
1466:            /** A viewer preference */
1467:            public static final int NonFullScreenPageModeUseThumbs = 1 << 20;
1468:            /** A viewer preference */
1469:            public static final int NonFullScreenPageModeUseOC = 1 << 21;
1470:
1471:            /** A viewer preference */
1472:            public static final int DirectionL2R = 1 << 22;
1473:            /** A viewer preference */
1474:            public static final int DirectionR2L = 1 << 23;
1475:
1476:            /** A viewer preference */
1477:            public static final int PrintScalingNone = 1 << 24;
1478:
1479:            /** @see com.lowagie.text.pdf.interfaces.PdfViewerPreferences#setViewerPreferences(int) */
1480:            public void setViewerPreferences(int preferences) {
1481:                pdf.setViewerPreferences(preferences);
1482:            }
1483:
1484:            /** @see com.lowagie.text.pdf.interfaces.PdfViewerPreferences#addViewerPreference(com.lowagie.text.pdf.PdfName, com.lowagie.text.pdf.PdfObject) */
1485:            public void addViewerPreference(PdfName key, PdfObject value) {
1486:                pdf.addViewerPreference(key, value);
1487:            }
1488:
1489:            //	[C4] Page labels
1490:
1491:            /**
1492:             * Use this method to add page labels
1493:             * @param pageLabels the page labels
1494:             */
1495:            public void setPageLabels(PdfPageLabels pageLabels) {
1496:                pdf.setPageLabels(pageLabels);
1497:            }
1498:
1499:            //	[C5] named objects: named destinations, javascript, embedded files
1500:
1501:            /**
1502:             * Use this method to add a JavaScript action at the document level.
1503:             * When the document opens, all this JavaScript runs.
1504:             * @param js The JavaScript action
1505:             */
1506:            public void addJavaScript(PdfAction js) {
1507:                pdf.addJavaScript(js);
1508:            }
1509:
1510:            /**
1511:             * Use this method to add a JavaScript action at the document level.
1512:             * When the document opens, all this JavaScript runs.
1513:             * @param code the JavaScript code
1514:             * @param unicode select JavaScript unicode. Note that the internal
1515:             * Acrobat JavaScript engine does not support unicode,
1516:             * so this may or may not work for you
1517:             */
1518:            public void addJavaScript(String code, boolean unicode) {
1519:                addJavaScript(PdfAction.javaScript(code, this , unicode));
1520:            }
1521:
1522:            /**
1523:             * Use this method to adds a JavaScript action at the document level.
1524:             * When the document opens, all this JavaScript runs.
1525:             * @param code the JavaScript code
1526:             */
1527:            public void addJavaScript(String code) {
1528:                addJavaScript(code, false);
1529:            }
1530:
1531:            /**
1532:             * Use this method to add a JavaScript action at the document level.
1533:             * When the document opens, all this JavaScript runs.
1534:             * @param name	The name of the JS Action in the name tree
1535:             * @param js The JavaScript action
1536:             */
1537:            public void addJavaScript(String name, PdfAction js) {
1538:                pdf.addJavaScript(name, js);
1539:            }
1540:
1541:            /**
1542:             * Use this method to add a JavaScript action at the document level.
1543:             * When the document opens, all this JavaScript runs.
1544:             * @param name	The name of the JS Action in the name tree
1545:             * @param code the JavaScript code
1546:             * @param unicode select JavaScript unicode. Note that the internal
1547:             * Acrobat JavaScript engine does not support unicode,
1548:             * so this may or may not work for you
1549:             */
1550:            public void addJavaScript(String name, String code, boolean unicode) {
1551:                addJavaScript(name, PdfAction.javaScript(code, this , unicode));
1552:            }
1553:
1554:            /**
1555:             * Use this method to adds a JavaScript action at the document level.
1556:             * When the document opens, all this JavaScript runs.
1557:             * @param name	The name of the JS Action in the name tree
1558:             * @param code the JavaScript code
1559:             */
1560:            public void addJavaScript(String name, String code) {
1561:                addJavaScript(name, code, false);
1562:            }
1563:
1564:            /**
1565:             * Use this method to add a file attachment at the document level.
1566:             * @param description the file description
1567:             * @param fileStore an array with the file. If it's <CODE>null</CODE>
1568:             * the file will be read from the disk
1569:             * @param file the path to the file. It will only be used if
1570:             * <CODE>fileStore</CODE> is not <CODE>null</CODE>
1571:             * @param fileDisplay the actual file name stored in the pdf
1572:             * @throws IOException on error
1573:             */
1574:            public void addFileAttachment(String description, byte fileStore[],
1575:                    String file, String fileDisplay) throws IOException {
1576:                addFileAttachment(description, PdfFileSpecification
1577:                        .fileEmbedded(this , file, fileDisplay, fileStore));
1578:            }
1579:
1580:            /**
1581:             * Use this method to add a file attachment at the document level.
1582:             * @param description the file description
1583:             * @param fs the file specification
1584:             */
1585:            public void addFileAttachment(String description,
1586:                    PdfFileSpecification fs) throws IOException {
1587:                pdf.addFileAttachment(description, fs);
1588:            }
1589:
1590:            /**
1591:             * Use this method to add a file attachment at the document level.
1592:             * @param fs the file specification
1593:             */
1594:            public void addFileAttachment(PdfFileSpecification fs)
1595:                    throws IOException {
1596:                addFileAttachment(null, fs);
1597:            }
1598:
1599:            // [C6] Actions (open and additional)
1600:
1601:            /** action value */
1602:            public static final PdfName DOCUMENT_CLOSE = PdfName.WC;
1603:            /** action value */
1604:            public static final PdfName WILL_SAVE = PdfName.WS;
1605:            /** action value */
1606:            public static final PdfName DID_SAVE = PdfName.DS;
1607:            /** action value */
1608:            public static final PdfName WILL_PRINT = PdfName.WP;
1609:            /** action value */
1610:            public static final PdfName DID_PRINT = PdfName.DP;
1611:
1612:            /** @see com.lowagie.text.pdf.interfaces.PdfDocumentActions#setOpenAction(java.lang.String) */
1613:            public void setOpenAction(String name) {
1614:                pdf.setOpenAction(name);
1615:            }
1616:
1617:            /** @see com.lowagie.text.pdf.interfaces.PdfDocumentActions#setOpenAction(com.lowagie.text.pdf.PdfAction) */
1618:            public void setOpenAction(PdfAction action) {
1619:                pdf.setOpenAction(action);
1620:            }
1621:
1622:            /** @see com.lowagie.text.pdf.interfaces.PdfDocumentActions#setAdditionalAction(com.lowagie.text.pdf.PdfName, com.lowagie.text.pdf.PdfAction) */
1623:            public void setAdditionalAction(PdfName actionType, PdfAction action)
1624:                    throws DocumentException {
1625:                if (!(actionType.equals(DOCUMENT_CLOSE)
1626:                        || actionType.equals(WILL_SAVE)
1627:                        || actionType.equals(DID_SAVE)
1628:                        || actionType.equals(WILL_PRINT) || actionType
1629:                        .equals(DID_PRINT))) {
1630:                    throw new DocumentException(
1631:                            "Invalid additional action type: "
1632:                                    + actionType.toString());
1633:                }
1634:                pdf.addAdditionalAction(actionType, action);
1635:            }
1636:
1637:            // 	[C7] portable collections
1638:
1639:            /**
1640:             * Use this method to add the Collection dictionary.
1641:             * @param collection a dictionary of type PdfCollection
1642:             */
1643:            public void setCollection(PdfCollection collection) {
1644:                setAtLeastPdfVersion(VERSION_1_7);
1645:                pdf.setCollection(collection);
1646:            }
1647:
1648:            //	[C8] AcroForm
1649:
1650:            /** signature value */
1651:            public static final int SIGNATURE_EXISTS = 1;
1652:            /** signature value */
1653:            public static final int SIGNATURE_APPEND_ONLY = 2;
1654:
1655:            /** @see com.lowagie.text.pdf.interfaces.PdfAnnotations#getAcroForm() */
1656:            public PdfAcroForm getAcroForm() {
1657:                return pdf.getAcroForm();
1658:            }
1659:
1660:            /** @see com.lowagie.text.pdf.interfaces.PdfAnnotations#addAnnotation(com.lowagie.text.pdf.PdfAnnotation) */
1661:            public void addAnnotation(PdfAnnotation annot) {
1662:                pdf.addAnnotation(annot);
1663:            }
1664:
1665:            void addAnnotation(PdfAnnotation annot, int page) {
1666:                addAnnotation(annot);
1667:            }
1668:
1669:            /** @see com.lowagie.text.pdf.interfaces.PdfAnnotations#addCalculationOrder(com.lowagie.text.pdf.PdfFormField) */
1670:            public void addCalculationOrder(PdfFormField annot) {
1671:                pdf.addCalculationOrder(annot);
1672:            }
1673:
1674:            /** @see com.lowagie.text.pdf.interfaces.PdfAnnotations#setSigFlags(int) */
1675:            public void setSigFlags(int f) {
1676:                pdf.setSigFlags(f);
1677:            }
1678:
1679:            //	[C9] Metadata
1680:
1681:            /** XMP Metadata for the document. */
1682:            protected byte[] xmpMetadata = null;
1683:
1684:            /**
1685:             * Use this method to set the XMP Metadata.
1686:             * @param xmpMetadata The xmpMetadata to set.
1687:             */
1688:            public void setXmpMetadata(byte[] xmpMetadata) {
1689:                this .xmpMetadata = xmpMetadata;
1690:            }
1691:
1692:            /**
1693:             * Use this method to set the XMP Metadata for each page.
1694:             * @param xmpMetadata The xmpMetadata to set.
1695:             */
1696:            public void setPageXmpMetadata(byte[] xmpMetadata) {
1697:                pdf.setXmpMetadata(xmpMetadata);
1698:            }
1699:
1700:            /**
1701:             * Use this method to creates XMP Metadata based
1702:             * on the metadata in the PdfDocument.
1703:             */
1704:            public void createXmpMetadata() {
1705:                setXmpMetadata(createXmpMetadataBytes());
1706:            }
1707:
1708:            /**
1709:             * @return an XmpMetadata byte array
1710:             */
1711:            private byte[] createXmpMetadataBytes() {
1712:                ByteArrayOutputStream baos = new ByteArrayOutputStream();
1713:                try {
1714:                    XmpWriter xmp = new XmpWriter(baos, pdf.getInfo(),
1715:                            pdfxConformance.getPDFXConformance());
1716:                    xmp.close();
1717:                } catch (IOException ioe) {
1718:                    ioe.printStackTrace();
1719:                }
1720:                return baos.toByteArray();
1721:            }
1722:
1723:            //	[C10] PDFX Conformance
1724:            /** A PDF/X level. */
1725:            public static final int PDFXNONE = 0;
1726:            /** A PDF/X level. */
1727:            public static final int PDFX1A2001 = 1;
1728:            /** A PDF/X level. */
1729:            public static final int PDFX32002 = 2;
1730:            /** PDFA-1A level. */
1731:            public static final int PDFA1A = 3;
1732:            /** PDFA-1B level. */
1733:            public static final int PDFA1B = 4;
1734:
1735:            /** Stores the PDF/X level. */
1736:            private PdfXConformanceImp pdfxConformance = new PdfXConformanceImp();
1737:
1738:            /** @see com.lowagie.text.pdf.interfaces.PdfXConformance#setPDFXConformance(int) */
1739:            public void setPDFXConformance(int pdfx) {
1740:                if (pdfxConformance.getPDFXConformance() == pdfx)
1741:                    return;
1742:                if (pdf.isOpen())
1743:                    throw new PdfXConformanceException(
1744:                            "PDFX conformance can only be set before opening the document.");
1745:                if (crypto != null)
1746:                    throw new PdfXConformanceException(
1747:                            "A PDFX conforming document cannot be encrypted.");
1748:                if (pdfx != PDFXNONE)
1749:                    setPdfVersion(VERSION_1_3);
1750:                pdfxConformance.setPDFXConformance(pdfx);
1751:            }
1752:
1753:            /** @see com.lowagie.text.pdf.interfaces.PdfXConformance#getPDFXConformance() */
1754:            public int getPDFXConformance() {
1755:                return pdfxConformance.getPDFXConformance();
1756:            }
1757:
1758:            /** @see com.lowagie.text.pdf.interfaces.PdfXConformance#isPdfX() */
1759:            public boolean isPdfX() {
1760:                return pdfxConformance.isPdfX();
1761:            }
1762:
1763:            //	[C11] Output intents
1764:
1765:            /**
1766:             * Use this method to set the values of the output intent dictionary.
1767:             * Null values are allowed to suppress any key.
1768:             * @param outputConditionIdentifier a value
1769:             * @param outputCondition a value
1770:             * @param registryName a value
1771:             * @param info a value
1772:             * @param destOutputProfile a value
1773:             * @throws IOException on error
1774:             */
1775:            public void setOutputIntents(String outputConditionIdentifier,
1776:                    String outputCondition, String registryName, String info,
1777:                    byte destOutputProfile[]) throws IOException {
1778:                getExtraCatalog();
1779:                PdfDictionary out = new PdfDictionary(PdfName.OUTPUTINTENT);
1780:                if (outputCondition != null)
1781:                    out.put(PdfName.OUTPUTCONDITION, new PdfString(
1782:                            outputCondition, PdfObject.TEXT_UNICODE));
1783:                if (outputConditionIdentifier != null)
1784:                    out.put(PdfName.OUTPUTCONDITIONIDENTIFIER, new PdfString(
1785:                            outputConditionIdentifier, PdfObject.TEXT_UNICODE));
1786:                if (registryName != null)
1787:                    out.put(PdfName.REGISTRYNAME, new PdfString(registryName,
1788:                            PdfObject.TEXT_UNICODE));
1789:                if (info != null)
1790:                    out.put(PdfName.INFO, new PdfString(info,
1791:                            PdfObject.TEXT_UNICODE));
1792:                if (destOutputProfile != null) {
1793:                    PdfStream stream = new PdfStream(destOutputProfile);
1794:                    stream.flateCompress();
1795:                    out.put(PdfName.DESTOUTPUTPROFILE, addToBody(stream)
1796:                            .getIndirectReference());
1797:                }
1798:                out.put(PdfName.S, PdfName.GTS_PDFX);
1799:                extraCatalog.put(PdfName.OUTPUTINTENTS, new PdfArray(out));
1800:            }
1801:
1802:            /**
1803:             * Use this method to copy the output intent dictionary
1804:             * from another document to this one.
1805:             * @param reader the other document
1806:             * @param checkExistence <CODE>true</CODE> to just check for the existence of a valid output intent
1807:             * dictionary, <CODE>false</CODE> to insert the dictionary if it exists
1808:             * @throws IOException on error
1809:             * @return <CODE>true</CODE> if the output intent dictionary exists, <CODE>false</CODE>
1810:             * otherwise
1811:             */
1812:            public boolean setOutputIntents(PdfReader reader,
1813:                    boolean checkExistence) throws IOException {
1814:                PdfDictionary catalog = reader.getCatalog();
1815:                PdfArray outs = (PdfArray) PdfReader.getPdfObject(catalog
1816:                        .get(PdfName.OUTPUTINTENTS));
1817:                if (outs == null)
1818:                    return false;
1819:                ArrayList arr = outs.getArrayList();
1820:                if (arr.isEmpty())
1821:                    return false;
1822:                PdfDictionary out = (PdfDictionary) PdfReader
1823:                        .getPdfObject((PdfObject) arr.get(0));
1824:                PdfObject obj = PdfReader.getPdfObject(out.get(PdfName.S));
1825:                if (obj == null || !PdfName.GTS_PDFX.equals(obj))
1826:                    return false;
1827:                if (checkExistence)
1828:                    return true;
1829:                PRStream stream = (PRStream) PdfReader.getPdfObject(out
1830:                        .get(PdfName.DESTOUTPUTPROFILE));
1831:                byte destProfile[] = null;
1832:                if (stream != null) {
1833:                    destProfile = PdfReader.getStreamBytes(stream);
1834:                }
1835:                setOutputIntents(getNameString(out,
1836:                        PdfName.OUTPUTCONDITIONIDENTIFIER), getNameString(out,
1837:                        PdfName.OUTPUTCONDITION), getNameString(out,
1838:                        PdfName.REGISTRYNAME),
1839:                        getNameString(out, PdfName.INFO), destProfile);
1840:                return true;
1841:            }
1842:
1843:            private static String getNameString(PdfDictionary dic, PdfName key) {
1844:                PdfObject obj = PdfReader.getPdfObject(dic.get(key));
1845:                if (obj == null || !obj.isString())
1846:                    return null;
1847:                return ((PdfString) obj).toUnicodeString();
1848:            }
1849:
1850:            // PDF Objects that have an impact on the PDF body
1851:
1852:            //	[F1] PdfEncryptionSettings interface
1853:
1854:            // types of encryption
1855:
1856:            /** Type of encryption */
1857:            public static final int STANDARD_ENCRYPTION_40 = 0;
1858:            /** Type of encryption */
1859:            public static final int STANDARD_ENCRYPTION_128 = 1;
1860:            /** Type of encryption */
1861:            public static final int ENCRYPTION_AES_128 = 2;
1862:            /** Mask to separate the encryption type from the encryption mode. */
1863:            static final int ENCRYPTION_MASK = 7;
1864:            /** Add this to the mode to keep the metadata in clear text */
1865:            public static final int DO_NOT_ENCRYPT_METADATA = 8;
1866:
1867:            // permissions
1868:
1869:            /** The operation permitted when the document is opened with the user password */
1870:            public static final int AllowPrinting = 4 + 2048;
1871:            /** The operation permitted when the document is opened with the user password */
1872:            public static final int AllowModifyContents = 8;
1873:            /** The operation permitted when the document is opened with the user password */
1874:            public static final int AllowCopy = 16;
1875:            /** The operation permitted when the document is opened with the user password */
1876:            public static final int AllowModifyAnnotations = 32;
1877:            /** The operation permitted when the document is opened with the user password */
1878:            public static final int AllowFillIn = 256;
1879:            /** The operation permitted when the document is opened with the user password */
1880:            public static final int AllowScreenReaders = 512;
1881:            /** The operation permitted when the document is opened with the user password */
1882:            public static final int AllowAssembly = 1024;
1883:            /** The operation permitted when the document is opened with the user password */
1884:            public static final int AllowDegradedPrinting = 4;
1885:
1886:            // Strength of the encryption (kept for historical reasons)
1887:            /** Type of standard encryption strength*/
1888:            public static final boolean STRENGTH40BITS = false;
1889:            /** Type of standard encryption strength */
1890:            public static final boolean STRENGTH128BITS = true;
1891:
1892:            /** Contains the business logic for cryptography. */
1893:            protected PdfEncryption crypto;
1894:
1895:            PdfEncryption getEncryption() {
1896:                return crypto;
1897:            }
1898:
1899:            /** @see com.lowagie.text.pdf.interfaces.PdfEncryptionSettings#setEncryption(byte[], byte[], int, int) */
1900:            public void setEncryption(byte userPassword[],
1901:                    byte ownerPassword[], int permissions, int encryptionType)
1902:                    throws DocumentException {
1903:                if (pdf.isOpen())
1904:                    throw new DocumentException(
1905:                            "Encryption can only be added before opening the document.");
1906:                crypto = new PdfEncryption();
1907:                crypto.setCryptoMode(encryptionType, 0);
1908:                crypto.setupAllKeys(userPassword, ownerPassword, permissions);
1909:            }
1910:
1911:            /** @see com.lowagie.text.pdf.interfaces.PdfEncryptionSettings#setEncryption(java.security.cert.Certificate[], int[], int) */
1912:            public void setEncryption(Certificate[] certs, int[] permissions,
1913:                    int encryptionType) throws DocumentException {
1914:                if (pdf.isOpen())
1915:                    throw new DocumentException(
1916:                            "Encryption can only be added before opening the document.");
1917:                crypto = new PdfEncryption();
1918:                if (certs != null) {
1919:                    for (int i = 0; i < certs.length; i++) {
1920:                        crypto.addRecipient(certs[i], permissions[i]);
1921:                    }
1922:                }
1923:                crypto.setCryptoMode(encryptionType, 0);
1924:                crypto.getEncryptionDictionary();
1925:            }
1926:
1927:            /**
1928:             * Sets the encryption options for this document. The userPassword and the
1929:             *  ownerPassword can be null or have zero length. In this case the ownerPassword
1930:             *  is replaced by a random string. The open permissions for the document can be
1931:             *  AllowPrinting, AllowModifyContents, AllowCopy, AllowModifyAnnotations,
1932:             *  AllowFillIn, AllowScreenReaders, AllowAssembly and AllowDegradedPrinting.
1933:             *  The permissions can be combined by ORing them.
1934:             * @param userPassword the user password. Can be null or empty
1935:             * @param ownerPassword the owner password. Can be null or empty
1936:             * @param permissions the user permissions
1937:             * @param strength128Bits <code>true</code> for 128 bit key length, <code>false</code> for 40 bit key length
1938:             * @throws DocumentException if the document is already open
1939:             * @deprecated use the methods described in the PdfEncryptionSettings interface
1940:             */
1941:            public void setEncryption(byte userPassword[],
1942:                    byte ownerPassword[], int permissions,
1943:                    boolean strength128Bits) throws DocumentException {
1944:                setEncryption(userPassword, ownerPassword, permissions,
1945:                        strength128Bits ? STANDARD_ENCRYPTION_128
1946:                                : STANDARD_ENCRYPTION_40);
1947:            }
1948:
1949:            /**
1950:             * Sets the encryption options for this document. The userPassword and the
1951:             *  ownerPassword can be null or have zero length. In this case the ownerPassword
1952:             *  is replaced by a random string. The open permissions for the document can be
1953:             *  AllowPrinting, AllowModifyContents, AllowCopy, AllowModifyAnnotations,
1954:             *  AllowFillIn, AllowScreenReaders, AllowAssembly and AllowDegradedPrinting.
1955:             *  The permissions can be combined by ORing them.
1956:             * @param strength <code>true</code> for 128 bit key length, <code>false</code> for 40 bit key length
1957:             * @param userPassword the user password. Can be null or empty
1958:             * @param ownerPassword the owner password. Can be null or empty
1959:             * @param permissions the user permissions
1960:             * @throws DocumentException if the document is already open
1961:             * @deprecated use the methods described in the PdfEncryptionSettings interface
1962:             */
1963:            public void setEncryption(boolean strength, String userPassword,
1964:                    String ownerPassword, int permissions)
1965:                    throws DocumentException {
1966:                setEncryption(getISOBytes(userPassword),
1967:                        getISOBytes(ownerPassword), permissions,
1968:                        strength ? STANDARD_ENCRYPTION_128
1969:                                : STANDARD_ENCRYPTION_40);
1970:            }
1971:
1972:            /**
1973:             * Sets the encryption options for this document. The userPassword and the
1974:             *  ownerPassword can be null or have zero length. In this case the ownerPassword
1975:             *  is replaced by a random string. The open permissions for the document can be
1976:             *  AllowPrinting, AllowModifyContents, AllowCopy, AllowModifyAnnotations,
1977:             *  AllowFillIn, AllowScreenReaders, AllowAssembly and AllowDegradedPrinting.
1978:             *  The permissions can be combined by ORing them.
1979:             * @param encryptionType the type of encryption. It can be one of STANDARD_ENCRYPTION_40, STANDARD_ENCRYPTION_128 or ENCRYPTION_AES128.
1980:             * Optionally DO_NOT_ENCRYPT_METADATA can be ored to output the metadata in cleartext
1981:             * @param userPassword the user password. Can be null or empty
1982:             * @param ownerPassword the owner password. Can be null or empty
1983:             * @param permissions the user permissions
1984:             * @throws DocumentException if the document is already open
1985:             * @deprecated use the methods described in the PdfEncryptionSettings interface
1986:             */
1987:            public void setEncryption(int encryptionType, String userPassword,
1988:                    String ownerPassword, int permissions)
1989:                    throws DocumentException {
1990:                setEncryption(getISOBytes(userPassword),
1991:                        getISOBytes(ownerPassword), permissions, encryptionType);
1992:            }
1993:
1994:            //	[F2] compression
1995:
1996:            /** Holds value of property fullCompression. */
1997:            protected boolean fullCompression = false;
1998:
1999:            /**
2000:             * Use this method to find out if 1.5 compression is on.
2001:             * @return the 1.5 compression status
2002:             */
2003:            public boolean isFullCompression() {
2004:                return this .fullCompression;
2005:            }
2006:
2007:            /**
2008:             * Use this method to set the document's compression to the
2009:             * PDF 1.5 mode with object streams and xref streams.
2010:             * It can be set at any time but once set it can't be unset.
2011:             * <p>
2012:             * If set before opening the document it will also set the pdf version to 1.5.
2013:             */
2014:            public void setFullCompression() {
2015:                this .fullCompression = true;
2016:                setAtLeastPdfVersion(VERSION_1_5);
2017:            }
2018:
2019:            //	[F3] adding fonts
2020:
2021:            /** The fonts of this document */
2022:            protected HashMap documentFonts = new HashMap();
2023:
2024:            /** The font number counter for the fonts in the document. */
2025:            protected int fontNumber = 1;
2026:
2027:            /**
2028:             * Adds a <CODE>BaseFont</CODE> to the document but not to the page resources.
2029:             * It is used for templates.
2030:             * @param bf the <CODE>BaseFont</CODE> to add
2031:             * @return an <CODE>Object[]</CODE> where position 0 is a <CODE>PdfName</CODE>
2032:             * and position 1 is an <CODE>PdfIndirectReference</CODE>
2033:             */
2034:
2035:            FontDetails addSimple(BaseFont bf) {
2036:                if (bf.getFontType() == BaseFont.FONT_TYPE_DOCUMENT) {
2037:                    return new FontDetails(new PdfName("F" + (fontNumber++)),
2038:                            ((DocumentFont) bf).getIndirectReference(), bf);
2039:                }
2040:                FontDetails ret = (FontDetails) documentFonts.get(bf);
2041:                if (ret == null) {
2042:                    PdfXConformanceImp.checkPDFXConformance(this ,
2043:                            PdfXConformanceImp.PDFXKEY_FONT, bf);
2044:                    ret = new FontDetails(new PdfName("F" + (fontNumber++)),
2045:                            body.getPdfIndirectReference(), bf);
2046:                    documentFonts.put(bf, ret);
2047:                }
2048:                return ret;
2049:            }
2050:
2051:            void eliminateFontSubset(PdfDictionary fonts) {
2052:                for (Iterator it = documentFonts.values().iterator(); it
2053:                        .hasNext();) {
2054:                    FontDetails ft = (FontDetails) it.next();
2055:                    if (fonts.get(ft.getFontName()) != null)
2056:                        ft.setSubset(false);
2057:                }
2058:            }
2059:
2060:            //	[F4] adding (and releasing) form XObjects
2061:
2062:            /** The form XObjects in this document. The key is the xref and the value
2063:                is Object[]{PdfName, template}.*/
2064:            protected HashMap formXObjects = new HashMap();
2065:
2066:            /** The name counter for the form XObjects name. */
2067:            protected int formXObjectsCounter = 1;
2068:
2069:            /**
2070:             * Adds a template to the document but not to the page resources.
2071:             * @param template the template to add
2072:             * @param forcedName the template name, rather than a generated one. Can be null
2073:             * @return the <CODE>PdfName</CODE> for this template
2074:             */
2075:
2076:            PdfName addDirectTemplateSimple(PdfTemplate template,
2077:                    PdfName forcedName) {
2078:                PdfIndirectReference ref = template.getIndirectReference();
2079:                Object obj[] = (Object[]) formXObjects.get(ref);
2080:                PdfName name = null;
2081:                try {
2082:                    if (obj == null) {
2083:                        if (forcedName == null) {
2084:                            name = new PdfName("Xf" + formXObjectsCounter);
2085:                            ++formXObjectsCounter;
2086:                        } else
2087:                            name = forcedName;
2088:                        if (template.getType() == PdfTemplate.TYPE_IMPORTED)
2089:                            template = null;
2090:                        formXObjects.put(ref, new Object[] { name, template });
2091:                    } else
2092:                        name = (PdfName) obj[0];
2093:                } catch (Exception e) {
2094:                    throw new ExceptionConverter(e);
2095:                }
2096:                return name;
2097:            }
2098:
2099:            /**
2100:             * Use this method to releases the memory used by a template.
2101:             * This method writes the template to the output.
2102:             * The template can still be added to any content
2103:             * but changes to the template itself won't have any effect.
2104:             * @param tp the template to release
2105:             * @throws IOException on error
2106:             */
2107:            public void releaseTemplate(PdfTemplate tp) throws IOException {
2108:                PdfIndirectReference ref = tp.getIndirectReference();
2109:                Object[] objs = (Object[]) formXObjects.get(ref);
2110:                if (objs == null || objs[1] == null)
2111:                    return;
2112:                PdfTemplate template = (PdfTemplate) objs[1];
2113:                if (template.getIndirectReference() instanceof  PRIndirectReference)
2114:                    return;
2115:                if (template.getType() == PdfTemplate.TYPE_TEMPLATE) {
2116:                    addToBody(template.getFormXObject(), template
2117:                            .getIndirectReference());
2118:                    objs[1] = null;
2119:                }
2120:            }
2121:
2122:            //	[F5] adding pages imported form other PDF documents
2123:
2124:            protected HashMap importedPages = new HashMap();
2125:
2126:            /**
2127:             * Use this method to get a page from other PDF document.
2128:             * The page can be used as any other PdfTemplate.
2129:             * Note that calling this method more than once with the same parameters
2130:             * will retrieve the same object.
2131:             * @param reader the PDF document where the page is
2132:             * @param pageNumber the page number. The first page is 1
2133:             * @return the template representing the imported page
2134:             */
2135:            public PdfImportedPage getImportedPage(PdfReader reader,
2136:                    int pageNumber) {
2137:                PdfReaderInstance inst = (PdfReaderInstance) importedPages
2138:                        .get(reader);
2139:                if (inst == null) {
2140:                    inst = reader.getPdfReaderInstance(this );
2141:                    importedPages.put(reader, inst);
2142:                }
2143:                return inst.getImportedPage(pageNumber);
2144:            }
2145:
2146:            /**
2147:             * Use this method to writes the reader to the document
2148:             * and free the memory used by it.
2149:             * The main use is when concatenating multiple documents
2150:             * to keep the memory usage restricted to the current
2151:             * appending document.
2152:             * @param reader the <CODE>PdfReader</CODE> to free
2153:             * @throws IOException on error
2154:             */
2155:            public void freeReader(PdfReader reader) throws IOException {
2156:                currentPdfReaderInstance = (PdfReaderInstance) importedPages
2157:                        .get(reader);
2158:                if (currentPdfReaderInstance == null)
2159:                    return;
2160:                currentPdfReaderInstance.writeAllPages();
2161:                currentPdfReaderInstance = null;
2162:                importedPages.remove(reader);
2163:            }
2164:
2165:            /**
2166:             * Use this method to gets the current document size. 
2167:             * This size only includes the data already writen
2168:             * to the output stream, it does not include templates or fonts.
2169:             * It is usefull if used with <CODE>freeReader()</CODE>
2170:             * when concatenating many documents and an idea of
2171:             * the current size is needed.
2172:             * @return the approximate size without fonts or templates
2173:             */
2174:            public int getCurrentDocumentSize() {
2175:                return body.offset() + body.size() * 20 + 0x48;
2176:            }
2177:
2178:            protected PdfReaderInstance currentPdfReaderInstance;
2179:
2180:            protected int getNewObjectNumber(PdfReader reader, int number,
2181:                    int generation) {
2182:                return currentPdfReaderInstance.getNewObjectNumber(number,
2183:                        generation);
2184:            }
2185:
2186:            RandomAccessFileOrArray getReaderFile(PdfReader reader) {
2187:                return currentPdfReaderInstance.getReaderFile();
2188:            }
2189:
2190:            //	[F6] spot colors
2191:
2192:            /** The colors of this document */
2193:            protected HashMap documentColors = new HashMap();
2194:
2195:            /** The color number counter for the colors in the document. */
2196:            protected int colorNumber = 1;
2197:
2198:            PdfName getColorspaceName() {
2199:                return new PdfName("CS" + (colorNumber++));
2200:            }
2201:
2202:            /**
2203:             * Adds a <CODE>SpotColor</CODE> to the document but not to the page resources.
2204:             * @param spc the <CODE>SpotColor</CODE> to add
2205:             * @return an <CODE>Object[]</CODE> where position 0 is a <CODE>PdfName</CODE>
2206:             * and position 1 is an <CODE>PdfIndirectReference</CODE>
2207:             */
2208:            ColorDetails addSimple(PdfSpotColor spc) {
2209:                ColorDetails ret = (ColorDetails) documentColors.get(spc);
2210:                if (ret == null) {
2211:                    ret = new ColorDetails(getColorspaceName(), body
2212:                            .getPdfIndirectReference(), spc);
2213:                    documentColors.put(spc, ret);
2214:                }
2215:                return ret;
2216:            }
2217:
2218:            //	[F7] document patterns
2219:
2220:            /** The patterns of this document */
2221:            protected HashMap documentPatterns = new HashMap();
2222:
2223:            /** The patten number counter for the colors in the document. */
2224:            protected int patternNumber = 1;
2225:
2226:            PdfName addSimplePattern(PdfPatternPainter painter) {
2227:                PdfName name = (PdfName) documentPatterns.get(painter);
2228:                try {
2229:                    if (name == null) {
2230:                        name = new PdfName("P" + patternNumber);
2231:                        ++patternNumber;
2232:                        documentPatterns.put(painter, name);
2233:                    }
2234:                } catch (Exception e) {
2235:                    throw new ExceptionConverter(e);
2236:                }
2237:                return name;
2238:            }
2239:
2240:            //	[F8] shading patterns
2241:
2242:            protected HashMap documentShadingPatterns = new HashMap();
2243:
2244:            void addSimpleShadingPattern(PdfShadingPattern shading) {
2245:                if (!documentShadingPatterns.containsKey(shading)) {
2246:                    shading.setName(patternNumber);
2247:                    ++patternNumber;
2248:                    documentShadingPatterns.put(shading, null);
2249:                    addSimpleShading(shading.getShading());
2250:                }
2251:            }
2252:
2253:            //	[F9] document shadings
2254:
2255:            protected HashMap documentShadings = new HashMap();
2256:
2257:            void addSimpleShading(PdfShading shading) {
2258:                if (!documentShadings.containsKey(shading)) {
2259:                    documentShadings.put(shading, null);
2260:                    shading.setName(documentShadings.size());
2261:                }
2262:            }
2263:
2264:            // [F10] extended graphics state (for instance for transparency)
2265:
2266:            protected HashMap documentExtGState = new HashMap();
2267:
2268:            PdfObject[] addSimpleExtGState(PdfDictionary gstate) {
2269:                if (!documentExtGState.containsKey(gstate)) {
2270:                    PdfXConformanceImp.checkPDFXConformance(this ,
2271:                            PdfXConformanceImp.PDFXKEY_GSTATE, gstate);
2272:                    documentExtGState.put(gstate, new PdfObject[] {
2273:                            new PdfName("GS" + (documentExtGState.size() + 1)),
2274:                            getPdfIndirectReference() });
2275:                }
2276:                return (PdfObject[]) documentExtGState.get(gstate);
2277:            }
2278:
2279:            //	[F11] adding properties (OCG, marked content)
2280:
2281:            protected HashMap documentProperties = new HashMap();
2282:
2283:            PdfObject[] addSimpleProperty(Object prop, PdfIndirectReference refi) {
2284:                if (!documentProperties.containsKey(prop)) {
2285:                    if (prop instanceof  PdfOCG)
2286:                        PdfXConformanceImp.checkPDFXConformance(this ,
2287:                                PdfXConformanceImp.PDFXKEY_LAYER, null);
2288:                    documentProperties.put(prop,
2289:                            new PdfObject[] {
2290:                                    new PdfName("Pr"
2291:                                            + (documentProperties.size() + 1)),
2292:                                    refi });
2293:                }
2294:                return (PdfObject[]) documentProperties.get(prop);
2295:            }
2296:
2297:            boolean propertyExists(Object prop) {
2298:                return documentProperties.containsKey(prop);
2299:            }
2300:
2301:            //	[F12] tagged PDF
2302:
2303:            protected boolean tagged = false;
2304:            protected PdfStructureTreeRoot structureTreeRoot;
2305:
2306:            /**
2307:             * Mark this document for tagging. It must be called before open.
2308:             */
2309:            public void setTagged() {
2310:                if (open)
2311:                    throw new IllegalArgumentException(
2312:                            "Tagging must be set before opening the document.");
2313:                tagged = true;
2314:            }
2315:
2316:            /**
2317:             * Check if the document is marked for tagging.
2318:             * @return <CODE>true</CODE> if the document is marked for tagging
2319:             */
2320:            public boolean isTagged() {
2321:                return tagged;
2322:            }
2323:
2324:            /**
2325:             * Gets the structure tree root. If the document is not marked for tagging it will return <CODE>null</CODE>.
2326:             * @return the structure tree root
2327:             */
2328:            public PdfStructureTreeRoot getStructureTreeRoot() {
2329:                if (tagged && structureTreeRoot == null)
2330:                    structureTreeRoot = new PdfStructureTreeRoot(this );
2331:                return structureTreeRoot;
2332:            }
2333:
2334:            //	[F13] Optional Content Groups    
2335:            protected HashSet documentOCG = new HashSet();
2336:            protected ArrayList documentOCGorder = new ArrayList();
2337:            protected PdfOCProperties OCProperties;
2338:            protected PdfArray OCGRadioGroup = new PdfArray();
2339:
2340:            /**
2341:             * Use this method to get the <B>Optional Content Properties Dictionary</B>.
2342:             * Each call fills the dictionary with the current layer state.
2343:             * It's advisable to only call this method right before close
2344:             * and do any modifications at that time.
2345:             * @return the Optional Content Properties Dictionary
2346:             */
2347:            public PdfOCProperties getOCProperties() {
2348:                fillOCProperties(true);
2349:                return OCProperties;
2350:            }
2351:
2352:            /**
2353:             * Use this method to set a collection of optional content groups
2354:             * whose states are intended to follow a "radio button" paradigm.
2355:             * That is, the state of at most one optional content group
2356:             * in the array should be ON at a time: if one group is turned
2357:             * ON, all others must be turned OFF.
2358:             * @param group the radio group
2359:             */
2360:            public void addOCGRadioGroup(ArrayList group) {
2361:                PdfArray ar = new PdfArray();
2362:                for (int k = 0; k < group.size(); ++k) {
2363:                    PdfLayer layer = (PdfLayer) group.get(k);
2364:                    if (layer.getTitle() == null)
2365:                        ar.add(layer.getRef());
2366:                }
2367:                if (ar.size() == 0)
2368:                    return;
2369:                OCGRadioGroup.add(ar);
2370:            }
2371:
2372:            private static void getOCGOrder(PdfArray order, PdfLayer layer) {
2373:                if (!layer.isOnPanel())
2374:                    return;
2375:                if (layer.getTitle() == null)
2376:                    order.add(layer.getRef());
2377:                ArrayList children = layer.getChildren();
2378:                if (children == null)
2379:                    return;
2380:                PdfArray kids = new PdfArray();
2381:                if (layer.getTitle() != null)
2382:                    kids.add(new PdfString(layer.getTitle(),
2383:                            PdfObject.TEXT_UNICODE));
2384:                for (int k = 0; k < children.size(); ++k) {
2385:                    getOCGOrder(kids, (PdfLayer) children.get(k));
2386:                }
2387:                if (kids.size() > 0)
2388:                    order.add(kids);
2389:            }
2390:
2391:            private void addASEvent(PdfName event, PdfName category) {
2392:                PdfArray arr = new PdfArray();
2393:                for (Iterator it = documentOCG.iterator(); it.hasNext();) {
2394:                    PdfLayer layer = (PdfLayer) it.next();
2395:                    PdfDictionary usage = (PdfDictionary) layer
2396:                            .get(PdfName.USAGE);
2397:                    if (usage != null && usage.get(category) != null)
2398:                        arr.add(layer.getRef());
2399:                }
2400:                if (arr.size() == 0)
2401:                    return;
2402:                PdfDictionary d = (PdfDictionary) OCProperties.get(PdfName.D);
2403:                PdfArray arras = (PdfArray) d.get(PdfName.AS);
2404:                if (arras == null) {
2405:                    arras = new PdfArray();
2406:                    d.put(PdfName.AS, arras);
2407:                }
2408:                PdfDictionary as = new PdfDictionary();
2409:                as.put(PdfName.EVENT, event);
2410:                as.put(PdfName.CATEGORY, new PdfArray(category));
2411:                as.put(PdfName.OCGS, arr);
2412:                arras.add(as);
2413:            }
2414:
2415:            private void fillOCProperties(boolean erase) {
2416:                if (OCProperties == null)
2417:                    OCProperties = new PdfOCProperties();
2418:                if (erase) {
2419:                    OCProperties.remove(PdfName.OCGS);
2420:                    OCProperties.remove(PdfName.D);
2421:                }
2422:                if (OCProperties.get(PdfName.OCGS) == null) {
2423:                    PdfArray gr = new PdfArray();
2424:                    for (Iterator it = documentOCG.iterator(); it.hasNext();) {
2425:                        PdfLayer layer = (PdfLayer) it.next();
2426:                        gr.add(layer.getRef());
2427:                    }
2428:                    OCProperties.put(PdfName.OCGS, gr);
2429:                }
2430:                if (OCProperties.get(PdfName.D) != null)
2431:                    return;
2432:                ArrayList docOrder = new ArrayList(documentOCGorder);
2433:                for (Iterator it = docOrder.iterator(); it.hasNext();) {
2434:                    PdfLayer layer = (PdfLayer) it.next();
2435:                    if (layer.getParent() != null)
2436:                        it.remove();
2437:                }
2438:                PdfArray order = new PdfArray();
2439:                for (Iterator it = docOrder.iterator(); it.hasNext();) {
2440:                    PdfLayer layer = (PdfLayer) it.next();
2441:                    getOCGOrder(order, layer);
2442:                }
2443:                PdfDictionary d = new PdfDictionary();
2444:                OCProperties.put(PdfName.D, d);
2445:                d.put(PdfName.ORDER, order);
2446:                PdfArray gr = new PdfArray();
2447:                for (Iterator it = documentOCG.iterator(); it.hasNext();) {
2448:                    PdfLayer layer = (PdfLayer) it.next();
2449:                    if (!layer.isOn())
2450:                        gr.add(layer.getRef());
2451:                }
2452:                if (gr.size() > 0)
2453:                    d.put(PdfName.OFF, gr);
2454:                if (OCGRadioGroup.size() > 0)
2455:                    d.put(PdfName.RBGROUPS, OCGRadioGroup);
2456:                addASEvent(PdfName.VIEW, PdfName.ZOOM);
2457:                addASEvent(PdfName.VIEW, PdfName.VIEW);
2458:                addASEvent(PdfName.PRINT, PdfName.PRINT);
2459:                addASEvent(PdfName.EXPORT, PdfName.EXPORT);
2460:                d.put(PdfName.LISTMODE, PdfName.VISIBLEPAGES);
2461:            }
2462:
2463:            void registerLayer(PdfOCG layer) {
2464:                PdfXConformanceImp.checkPDFXConformance(this ,
2465:                        PdfXConformanceImp.PDFXKEY_LAYER, null);
2466:                if (layer instanceof  PdfLayer) {
2467:                    PdfLayer la = (PdfLayer) layer;
2468:                    if (la.getTitle() == null) {
2469:                        if (!documentOCG.contains(layer)) {
2470:                            documentOCG.add(layer);
2471:                            documentOCGorder.add(layer);
2472:                        }
2473:                    } else {
2474:                        documentOCGorder.add(layer);
2475:                    }
2476:                } else
2477:                    throw new IllegalArgumentException(
2478:                            "Only PdfLayer is accepted.");
2479:            }
2480:
2481:            //	User methods to change aspects of the page
2482:
2483:            //	[U1] page size
2484:
2485:            /**
2486:             * Use this method to get the size of the media box.
2487:             * @return a Rectangle
2488:             */
2489:            public Rectangle getPageSize() {
2490:                return pdf.getPageSize();
2491:            }
2492:
2493:            /**
2494:             * Use this method to set the crop box.
2495:             * The crop box should not be rotated even if the page is rotated.
2496:             * This change only takes effect in the next page.
2497:             * @param crop the crop box
2498:             */
2499:            public void setCropBoxSize(Rectangle crop) {
2500:                pdf.setCropBoxSize(crop);
2501:            }
2502:
2503:            /**
2504:             * Use this method to set the page box sizes.
2505:             * Allowed names are: "crop", "trim", "art" and "bleed".
2506:             * @param boxName the box size
2507:             * @param size the size
2508:             */
2509:            public void setBoxSize(String boxName, Rectangle size) {
2510:                pdf.setBoxSize(boxName, size);
2511:            }
2512:
2513:            /**
2514:             * Use this method to get the size of a trim, art, crop or bleed box,
2515:             * or null if not defined.
2516:             * @param boxName crop, trim, art or bleed
2517:             */
2518:            public Rectangle getBoxSize(String boxName) {
2519:                return pdf.getBoxSize(boxName);
2520:            }
2521:
2522:            //	[U2] take care of empty pages
2523:
2524:            /**
2525:             * Use this method to make sure a page is added,
2526:             * even if it's empty. If you use setPageEmpty(false),
2527:             * invoking newPage() after a blank page will add a newPage.
2528:             * @param pageEmpty the state
2529:             */
2530:            public void setPageEmpty(boolean pageEmpty) {
2531:                pdf.setPageEmpty(pageEmpty);
2532:            }
2533:
2534:            //  [U3] page actions (open and close)
2535:
2536:            /** action value */
2537:            public static final PdfName PAGE_OPEN = PdfName.O;
2538:            /** action value */
2539:            public static final PdfName PAGE_CLOSE = PdfName.C;
2540:
2541:            /** @see com.lowagie.text.pdf.interfaces.PdfPageActions#setPageAction(com.lowagie.text.pdf.PdfName, com.lowagie.text.pdf.PdfAction) */
2542:            public void setPageAction(PdfName actionType, PdfAction action)
2543:                    throws DocumentException {
2544:                if (!actionType.equals(PAGE_OPEN)
2545:                        && !actionType.equals(PAGE_CLOSE))
2546:                    throw new DocumentException(
2547:                            "Invalid page additional action type: "
2548:                                    + actionType.toString());
2549:                pdf.setPageAction(actionType, action);
2550:            }
2551:
2552:            /** @see com.lowagie.text.pdf.interfaces.PdfPageActions#setDuration(int) */
2553:            public void setDuration(int seconds) {
2554:                pdf.setDuration(seconds);
2555:            }
2556:
2557:            /** @see com.lowagie.text.pdf.interfaces.PdfPageActions#setTransition(com.lowagie.text.pdf.PdfTransition) */
2558:            public void setTransition(PdfTransition transition) {
2559:                pdf.setTransition(transition);
2560:            }
2561:
2562:            //	[U4] Thumbnail image
2563:
2564:            /**
2565:             * Use this method to set the thumbnail image for the current page.
2566:             * @param image the image
2567:             * @throws PdfException on error
2568:             * @throws DocumentException or error
2569:             */
2570:            public void setThumbnail(Image image) throws PdfException,
2571:                    DocumentException {
2572:                pdf.setThumbnail(image);
2573:            }
2574:
2575:            //	[U5] Transparency groups
2576:
2577:            /**
2578:             * A group attributes dictionary specifying the attributes
2579:             * of the page's page group for use in the transparent
2580:             * imaging model
2581:             */
2582:            protected PdfDictionary group;
2583:
2584:            /**
2585:             * Use this method to get the group dictionary.
2586:             * @return Value of property group.
2587:             */
2588:            public PdfDictionary getGroup() {
2589:                return this .group;
2590:            }
2591:
2592:            /**
2593:             * Use this method to set the group dictionary.
2594:             * @param group New value of property group.
2595:             */
2596:            public void setGroup(PdfDictionary group) {
2597:                this .group = group;
2598:            }
2599:
2600:            //	[U6] space char ratio
2601:
2602:            /** The default space-char ratio. */
2603:            public static final float SPACE_CHAR_RATIO_DEFAULT = 2.5f;
2604:            /** Disable the inter-character spacing. */
2605:            public static final float NO_SPACE_CHAR_RATIO = 10000000f;
2606:
2607:            /**
2608:             * The ratio between the extra word spacing and the extra character spacing.
2609:             * Extra word spacing will grow <CODE>ratio</CODE> times more than extra character spacing.
2610:             */
2611:            private float spaceCharRatio = SPACE_CHAR_RATIO_DEFAULT;
2612:
2613:            /**
2614:             * Use this method to gets the space/character extra spacing ratio
2615:             * for fully justified text.
2616:             * @return the space/character extra spacing ratio
2617:             */
2618:            public float getSpaceCharRatio() {
2619:                return spaceCharRatio;
2620:            }
2621:
2622:            /**
2623:             * Use this method to set the ratio between the extra word spacing and
2624:             * the extra character spacing when the text is fully justified.
2625:             * Extra word spacing will grow <CODE>spaceCharRatio</CODE> times more
2626:             * than extra character spacing. If the ratio is <CODE>PdfWriter.NO_SPACE_CHAR_RATIO</CODE>
2627:             * then the extra character spacing will be zero.
2628:             * @param spaceCharRatio the ratio between the extra word spacing and the extra character spacing
2629:             */
2630:            public void setSpaceCharRatio(float spaceCharRatio) {
2631:                if (spaceCharRatio < 0.001f)
2632:                    this .spaceCharRatio = 0.001f;
2633:                else
2634:                    this .spaceCharRatio = spaceCharRatio;
2635:            }
2636:
2637:            //	[U7] run direction (doesn't actually do anything)
2638:
2639:            /** Use the default run direction. */
2640:            public static final int RUN_DIRECTION_DEFAULT = 0;
2641:            /** Do not use bidirectional reordering. */
2642:            public static final int RUN_DIRECTION_NO_BIDI = 1;
2643:            /** Use bidirectional reordering with left-to-right
2644:             * preferential run direction.
2645:             */
2646:            public static final int RUN_DIRECTION_LTR = 2;
2647:            /** Use bidirectional reordering with right-to-left
2648:             * preferential run direction.
2649:             */
2650:            public static final int RUN_DIRECTION_RTL = 3;
2651:
2652:            protected int runDirection = RUN_DIRECTION_NO_BIDI;
2653:
2654:            /**
2655:             * Use this method to set the run direction.
2656:             * This is only used as a placeholder as it does not affect anything.
2657:             * @param runDirection the run direction
2658:             */
2659:            public void setRunDirection(int runDirection) {
2660:                if (runDirection < RUN_DIRECTION_NO_BIDI
2661:                        || runDirection > RUN_DIRECTION_RTL)
2662:                    throw new RuntimeException("Invalid run direction: "
2663:                            + runDirection);
2664:                this .runDirection = runDirection;
2665:            }
2666:
2667:            /**
2668:             * Use this method to set the run direction.
2669:             * @return the run direction
2670:             */
2671:            public int getRunDirection() {
2672:                return runDirection;
2673:            }
2674:
2675:            //	[U8] user units     
2676:
2677:            protected float userunit = 0f;
2678:
2679:            /**
2680:             * Use this method to get the user unit.
2681:             * A user unit is a value that defines the default user space unit.
2682:             * The minimum UserUnit is 1 (1 unit = 1/72 inch).
2683:             * The maximum UserUnit is 75,000.
2684:             * Note that this userunit only works starting with PDF1.6!
2685:             * @return Returns the userunit.
2686:             */
2687:            public float getUserunit() {
2688:                return userunit;
2689:            }
2690:
2691:            /**
2692:             * Use this method to set the user unit.
2693:             * A UserUnit is a value that defines the default user space unit.
2694:             * The minimum UserUnit is 1 (1 unit = 1/72 inch).
2695:             * The maximum UserUnit is 75,000.
2696:             * Note that this userunit only works starting with PDF1.6!
2697:             * @param userunit The userunit to set.
2698:             * @throws DocumentException on error
2699:             */
2700:            public void setUserunit(float userunit) throws DocumentException {
2701:                if (userunit < 1f || userunit > 75000f)
2702:                    throw new DocumentException(
2703:                            "UserUnit should be a value between 1 and 75000.");
2704:                this .userunit = userunit;
2705:                setAtLeastPdfVersion(VERSION_1_6);
2706:            }
2707:
2708:            // Miscellaneous topics
2709:
2710:            //	[M1] Color settings
2711:
2712:            protected PdfDictionary defaultColorspace = new PdfDictionary();
2713:
2714:            /**
2715:             * Use this method to get the default colorspaces.
2716:             * @return the default colorspaces
2717:             */
2718:            public PdfDictionary getDefaultColorspace() {
2719:                return defaultColorspace;
2720:            }
2721:
2722:            /**
2723:             * Use this method to sets the default colorspace that will be applied
2724:             * to all the document. The colorspace is only applied if another colorspace
2725:             * with the same name is not present in the content.
2726:             * <p>
2727:             * The colorspace is applied immediately when creating templates and
2728:             * at the page end for the main document content.
2729:             * @param key the name of the colorspace. It can be <CODE>PdfName.DEFAULTGRAY</CODE>, <CODE>PdfName.DEFAULTRGB</CODE>
2730:             * or <CODE>PdfName.DEFAULTCMYK</CODE>
2731:             * @param cs the colorspace. A <CODE>null</CODE> or <CODE>PdfNull</CODE> removes any colorspace with the same name
2732:             */
2733:            public void setDefaultColorspace(PdfName key, PdfObject cs) {
2734:                if (cs == null || cs.isNull())
2735:                    defaultColorspace.remove(key);
2736:                defaultColorspace.put(key, cs);
2737:            }
2738:
2739:            //	[M2] spot patterns
2740:
2741:            protected HashMap documentSpotPatterns = new HashMap();
2742:            protected ColorDetails patternColorspaceRGB;
2743:            protected ColorDetails patternColorspaceGRAY;
2744:            protected ColorDetails patternColorspaceCMYK;
2745:
2746:            ColorDetails addSimplePatternColorspace(Color color) {
2747:                int type = ExtendedColor.getType(color);
2748:                if (type == ExtendedColor.TYPE_PATTERN
2749:                        || type == ExtendedColor.TYPE_SHADING)
2750:                    throw new RuntimeException(
2751:                            "An uncolored tile pattern can not have another pattern or shading as color.");
2752:                try {
2753:                    switch (type) {
2754:                    case ExtendedColor.TYPE_RGB:
2755:                        if (patternColorspaceRGB == null) {
2756:                            patternColorspaceRGB = new ColorDetails(
2757:                                    getColorspaceName(), body
2758:                                            .getPdfIndirectReference(), null);
2759:                            PdfArray array = new PdfArray(PdfName.PATTERN);
2760:                            array.add(PdfName.DEVICERGB);
2761:                            addToBody(array, patternColorspaceRGB
2762:                                    .getIndirectReference());
2763:                        }
2764:                        return patternColorspaceRGB;
2765:                    case ExtendedColor.TYPE_CMYK:
2766:                        if (patternColorspaceCMYK == null) {
2767:                            patternColorspaceCMYK = new ColorDetails(
2768:                                    getColorspaceName(), body
2769:                                            .getPdfIndirectReference(), null);
2770:                            PdfArray array = new PdfArray(PdfName.PATTERN);
2771:                            array.add(PdfName.DEVICECMYK);
2772:                            addToBody(array, patternColorspaceCMYK
2773:                                    .getIndirectReference());
2774:                        }
2775:                        return patternColorspaceCMYK;
2776:                    case ExtendedColor.TYPE_GRAY:
2777:                        if (patternColorspaceGRAY == null) {
2778:                            patternColorspaceGRAY = new ColorDetails(
2779:                                    getColorspaceName(), body
2780:                                            .getPdfIndirectReference(), null);
2781:                            PdfArray array = new PdfArray(PdfName.PATTERN);
2782:                            array.add(PdfName.DEVICEGRAY);
2783:                            addToBody(array, patternColorspaceGRAY
2784:                                    .getIndirectReference());
2785:                        }
2786:                        return patternColorspaceGRAY;
2787:                    case ExtendedColor.TYPE_SEPARATION: {
2788:                        ColorDetails details = addSimple(((SpotColor) color)
2789:                                .getPdfSpotColor());
2790:                        ColorDetails patternDetails = (ColorDetails) documentSpotPatterns
2791:                                .get(details);
2792:                        if (patternDetails == null) {
2793:                            patternDetails = new ColorDetails(
2794:                                    getColorspaceName(), body
2795:                                            .getPdfIndirectReference(), null);
2796:                            PdfArray array = new PdfArray(PdfName.PATTERN);
2797:                            array.add(details.getIndirectReference());
2798:                            addToBody(array, patternDetails
2799:                                    .getIndirectReference());
2800:                            documentSpotPatterns.put(details, patternDetails);
2801:                        }
2802:                        return patternDetails;
2803:                    }
2804:                    default:
2805:                        throw new RuntimeException(
2806:                                "Invalid color type in PdfWriter.addSimplePatternColorspace().");
2807:                    }
2808:                } catch (Exception e) {
2809:                    throw new RuntimeException(e.getMessage());
2810:                }
2811:            }
2812:
2813:            //	[M3] Images
2814:
2815:            /**
2816:             * Use this method to get the strictImageSequence status.
2817:             * @return value of property strictImageSequence
2818:             */
2819:            public boolean isStrictImageSequence() {
2820:                return pdf.isStrictImageSequence();
2821:            }
2822:
2823:            /**
2824:             * Use this method to set the image sequence, so that it follows
2825:             * the text in strict order (or not).
2826:             * @param strictImageSequence new value of property strictImageSequence
2827:             *
2828:             */
2829:            public void setStrictImageSequence(boolean strictImageSequence) {
2830:                pdf.setStrictImageSequence(strictImageSequence);
2831:            }
2832:
2833:            /**
2834:             * Use this method to clear text wrapping around images (if applicable).
2835:             * @throws DocumentException
2836:             */
2837:            public void clearTextWrap() throws DocumentException {
2838:                pdf.clearTextWrap();
2839:            }
2840:
2841:            /** Dictionary, containing all the images of the PDF document */
2842:            protected PdfDictionary imageDictionary = new PdfDictionary();
2843:
2844:            /** This is the list with all the images in the document. */
2845:            private HashMap images = new HashMap();
2846:
2847:            /**
2848:             * Use this method to adds an image to the document
2849:             * but not to the page resources. It is used with
2850:             * templates and <CODE>Document.add(Image)</CODE>.
2851:             * Use this method only if you know what you're doing!
2852:             * @param image the <CODE>Image</CODE> to add
2853:             * @return the name of the image added
2854:             * @throws PdfException on error
2855:             * @throws DocumentException on error
2856:             */
2857:            public PdfName addDirectImageSimple(Image image)
2858:                    throws PdfException, DocumentException {
2859:                return addDirectImageSimple(image, null);
2860:            }
2861:
2862:            /**
2863:             * Adds an image to the document but not to the page resources.
2864:             * It is used with templates and <CODE>Document.add(Image)</CODE>.
2865:             * Use this method only if you know what you're doing!
2866:             * @param image the <CODE>Image</CODE> to add
2867:             * @param fixedRef the reference to used. It may be <CODE>null</CODE>,
2868:             * a <CODE>PdfIndirectReference</CODE> or a <CODE>PRIndirectReference</CODE>.
2869:             * @return the name of the image added
2870:             * @throws PdfException on error
2871:             * @throws DocumentException on error
2872:             */
2873:            public PdfName addDirectImageSimple(Image image,
2874:                    PdfIndirectReference fixedRef) throws PdfException,
2875:                    DocumentException {
2876:                PdfName name;
2877:                // if the images is already added, just retrieve the name
2878:                if (images.containsKey(image.getMySerialId())) {
2879:                    name = (PdfName) images.get(image.getMySerialId());
2880:                }
2881:                // if it's a new image, add it to the document
2882:                else {
2883:                    if (image.isImgTemplate()) {
2884:                        name = new PdfName("img" + images.size());
2885:                        if (image instanceof  ImgWMF) {
2886:                            try {
2887:                                ImgWMF wmf = (ImgWMF) image;
2888:                                wmf.readWMF(PdfTemplate.createTemplate(this , 0,
2889:                                        0));
2890:                            } catch (Exception e) {
2891:                                throw new DocumentException(e);
2892:                            }
2893:                        }
2894:                    } else {
2895:                        PdfIndirectReference dref = image.getDirectReference();
2896:                        if (dref != null) {
2897:                            PdfName rname = new PdfName("img" + images.size());
2898:                            images.put(image.getMySerialId(), rname);
2899:                            imageDictionary.put(rname, dref);
2900:                            return rname;
2901:                        }
2902:                        Image maskImage = image.getImageMask();
2903:                        PdfIndirectReference maskRef = null;
2904:                        if (maskImage != null) {
2905:                            PdfName mname = (PdfName) images.get(maskImage
2906:                                    .getMySerialId());
2907:                            maskRef = getImageReference(mname);
2908:                        }
2909:                        PdfImage i = new PdfImage(image, "img" + images.size(),
2910:                                maskRef);
2911:                        if (image.hasICCProfile()) {
2912:                            PdfICCBased icc = new PdfICCBased(image
2913:                                    .getICCProfile());
2914:                            PdfIndirectReference iccRef = add(icc);
2915:                            PdfArray iccArray = new PdfArray();
2916:                            iccArray.add(PdfName.ICCBASED);
2917:                            iccArray.add(iccRef);
2918:                            PdfObject colorspace = i.get(PdfName.COLORSPACE);
2919:                            if (colorspace != null && colorspace.isArray()) {
2920:                                ArrayList ar = ((PdfArray) colorspace)
2921:                                        .getArrayList();
2922:                                if (ar.size() > 1
2923:                                        && PdfName.INDEXED.equals(ar.get(0)))
2924:                                    ar.set(1, iccArray);
2925:                                else
2926:                                    i.put(PdfName.COLORSPACE, iccArray);
2927:                            } else
2928:                                i.put(PdfName.COLORSPACE, iccArray);
2929:                        }
2930:                        add(i, fixedRef);
2931:                        name = i.name();
2932:                    }
2933:                    images.put(image.getMySerialId(), name);
2934:                }
2935:                return name;
2936:            }
2937:
2938:            /**
2939:             * Writes a <CODE>PdfImage</CODE> to the outputstream.
2940:             *
2941:             * @param pdfImage the image to be added
2942:             * @return a <CODE>PdfIndirectReference</CODE> to the encapsulated image
2943:             * @throws PdfException when a document isn't open yet, or has been closed
2944:             */
2945:
2946:            PdfIndirectReference add(PdfImage pdfImage,
2947:                    PdfIndirectReference fixedRef) throws PdfException {
2948:                if (!imageDictionary.contains(pdfImage.name())) {
2949:                    PdfXConformanceImp.checkPDFXConformance(this ,
2950:                            PdfXConformanceImp.PDFXKEY_IMAGE, pdfImage);
2951:                    if (fixedRef instanceof  PRIndirectReference) {
2952:                        PRIndirectReference r2 = (PRIndirectReference) fixedRef;
2953:                        fixedRef = new PdfIndirectReference(0,
2954:                                getNewObjectNumber(r2.getReader(), r2
2955:                                        .getNumber(), r2.getGeneration()));
2956:                    }
2957:                    try {
2958:                        if (fixedRef == null)
2959:                            fixedRef = addToBody(pdfImage)
2960:                                    .getIndirectReference();
2961:                        else
2962:                            addToBody(pdfImage, fixedRef);
2963:                    } catch (IOException ioe) {
2964:                        throw new ExceptionConverter(ioe);
2965:                    }
2966:                    imageDictionary.put(pdfImage.name(), fixedRef);
2967:                    return fixedRef;
2968:                }
2969:                return (PdfIndirectReference) imageDictionary.get(pdfImage
2970:                        .name());
2971:            }
2972:
2973:            /**
2974:             * return the <CODE>PdfIndirectReference</CODE> to the image with a given name.
2975:             *
2976:             * @param name the name of the image
2977:             * @return a <CODE>PdfIndirectReference</CODE>
2978:             */
2979:
2980:            PdfIndirectReference getImageReference(PdfName name) {
2981:                return (PdfIndirectReference) imageDictionary.get(name);
2982:            }
2983:
2984:            protected PdfIndirectReference add(PdfICCBased icc) {
2985:                PdfIndirectObject object;
2986:                try {
2987:                    object = addToBody(icc);
2988:                } catch (IOException ioe) {
2989:                    throw new ExceptionConverter(ioe);
2990:                }
2991:                return object.getIndirectReference();
2992:            }
2993:
2994:            //	[M4] Old table functionality; do we still need it?
2995:
2996:            /**
2997:             * Sometimes it is necessary to know where the just added <CODE>Table</CODE> ends.
2998:             *
2999:             * For instance to avoid to add another table in a page that is ending up, because
3000:             * the new table will be probably splitted just after the header (it is an
3001:             * unpleasant effect, isn't it?).
3002:             *
3003:             * Added on September 8th, 2001
3004:             * by Francesco De Milato
3005:             * francesco.demilato@tiscalinet.it
3006:             * @param table the <CODE>Table</CODE>
3007:             * @return the bottom height of the just added table
3008:             * @deprecated	this method will probably disappear in one of the next releases
3009:             */
3010:
3011:            public float getTableBottom(Table table) {
3012:                return pdf.bottom(table) - pdf.indentBottom();
3013:            }
3014:
3015:            /**
3016:             * Gets a pre-rendered table.
3017:             * (Contributed by dperezcar@fcc.es) 
3018:             * @param table		Contains the table definition.  Its contents are deleted, after being pre-rendered.
3019:             * @return a PdfTable
3020:             * @deprecated	this method will probably disappear in one of the next releases
3021:             */
3022:
3023:            public PdfTable getPdfTable(Table table) {
3024:                return pdf.getPdfTable(table, true);
3025:            }
3026:
3027:            /**
3028:             * Row additions to the original {@link Table} used to build the {@link PdfTable} are processed and pre-rendered,
3029:             * and then the contents are deleted. 
3030:             * If the pre-rendered table doesn't fit, then it is fully rendered and its data discarded.  
3031:             * There shouldn't be any column change in the underlying {@link Table} object.
3032:             * (Contributed by dperezcar@fcc.es) 
3033:             *
3034:             * @param	table		The pre-rendered table obtained from {@link #getPdfTable(Table)} 
3035:             * @return	true if the table is rendered and emptied.
3036:             * @throws DocumentException
3037:             * @see #getPdfTable(Table)
3038:             * @deprecated	this method will probably disappear in one of the next releases
3039:             */
3040:
3041:            public boolean breakTableIfDoesntFit(PdfTable table)
3042:                    throws DocumentException {
3043:                return pdf.breakTableIfDoesntFit(table);
3044:            }
3045:
3046:            /**
3047:             * Checks if a <CODE>Table</CODE> fits the current page of the <CODE>PdfDocument</CODE>.
3048:             *
3049:             * @param	table	the table that has to be checked
3050:             * @param	margin	a certain margin
3051:             * @return	<CODE>true</CODE> if the <CODE>Table</CODE> fits the page, <CODE>false</CODE> otherwise.
3052:             * @deprecated	this method will probably disappear in one of the next releases
3053:             */
3054:
3055:            public boolean fitsPage(Table table, float margin) {
3056:                return pdf.bottom(table) > pdf.indentBottom() + margin;
3057:            }
3058:
3059:            /**
3060:             * Checks if a <CODE>Table</CODE> fits the current page of the <CODE>PdfDocument</CODE>.
3061:             *
3062:             * @param	table	the table that has to be checked
3063:             * @return	<CODE>true</CODE> if the <CODE>Table</CODE> fits the page, <CODE>false</CODE> otherwise.
3064:             * @deprecated	this method will probably disappear in one of the next releases
3065:             */
3066:
3067:            public boolean fitsPage(Table table) {
3068:                return fitsPage(table, 0);
3069:            }
3070:
3071:            /**
3072:             * Checks if a <CODE>PdfPTable</CODE> fits the current page of the <CODE>PdfDocument</CODE>.
3073:             *
3074:             * @param	table	the table that has to be checked
3075:             * @param	margin	a certain margin
3076:             * @return	<CODE>true</CODE> if the <CODE>PdfPTable</CODE> fits the page, <CODE>false</CODE> otherwise.
3077:             * @deprecated	this method will probably disappear in one of the next releases
3078:             */
3079:            public boolean fitsPage(PdfPTable table, float margin) {
3080:                return pdf.fitsPage(table, margin);
3081:            }
3082:
3083:            /**
3084:             * Checks if a <CODE>PdfPTable</CODE> fits the current page of the <CODE>PdfDocument</CODE>.
3085:             *
3086:             * @param	table	the table that has to be checked
3087:             * @return	<CODE>true</CODE> if the <CODE>PdfPTable</CODE> fits the page, <CODE>false</CODE> otherwise.
3088:             * @deprecated	this method will probably disappear in one of the next releases
3089:             */
3090:            public boolean fitsPage(PdfPTable table) {
3091:                return pdf.fitsPage(table, 0);
3092:            }
3093:
3094:            /**
3095:             * A flag indicating the presence of structure elements that contain user properties attributes.
3096:             */
3097:            private boolean userProperties;
3098:
3099:            /**
3100:             * Gets the flag indicating the presence of structure elements that contain user properties attributes.
3101:             * @return the user properties flag
3102:             */
3103:            public boolean isUserProperties() {
3104:                return this .userProperties;
3105:            }
3106:
3107:            /**
3108:             * Sets the flag indicating the presence of structure elements that contain user properties attributes.
3109:             * @param userProperties the user properties flag
3110:             */
3111:            public void setUserProperties(boolean userProperties) {
3112:                this.userProperties = userProperties;
3113:            }
3114:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.