001: /*
002: * $Id: PdfSmartCopy.java 2909 2007-09-05 10:09:10Z psoares33 $
003: * $Name$
004: *
005: * Copyright 2007 Michael Neuweiler and Bruno Lowagie
006: *
007: * The contents of this file are subject to the Mozilla Public License Version 1.1
008: * (the "License"); you may not use this file except in compliance with the License.
009: * You may obtain a copy of the License at http://www.mozilla.org/MPL/
010: *
011: * Software distributed under the License is distributed on an "AS IS" basis,
012: * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
013: * for the specific language governing rights and limitations under the License.
014: *
015: * The Original Code is 'iText, a free JAVA-PDF library'.
016: *
017: * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by
018: * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie.
019: * All Rights Reserved.
020: * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer
021: * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved.
022: *
023: * This class was written by Michael Neuweiler based on hints given by Bruno Lowagie
024: *
025: * Contributor(s): all the names of the contributors are added in the source code
026: * where applicable.
027: *
028: * Alternatively, the contents of this file may be used under the terms of the
029: * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the
030: * provisions of LGPL are applicable instead of those above. If you wish to
031: * allow use of your version of this file only under the terms of the LGPL
032: * License and not to allow others to use your version of this file under
033: * the MPL, indicate your decision by deleting the provisions above and
034: * replace them with the notice and other provisions required by the LGPL.
035: * If you do not delete the provisions above, a recipient may use your version
036: * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE.
037: *
038: * This library is free software; you can redistribute it and/or modify it
039: * under the terms of the MPL as stated above or under the terms of the GNU
040: * Library General Public License as published by the Free Software Foundation;
041: * either version 2 of the License, or any later version.
042: *
043: * This library is distributed in the hope that it will be useful, but WITHOUT
044: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
045: * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more
046: * details.
047: *
048: * If you didn't download this code from the following link, you should check if
049: * you aren't using an obsolete version:
050: * http://www.lowagie.com/iText/
051: */
052: package com.lowagie.text.pdf;
053:
054: import java.io.IOException;
055: import java.io.OutputStream;
056: import java.util.HashMap;
057:
058: import com.lowagie.text.Document;
059: import com.lowagie.text.DocumentException;
060: import java.util.Arrays;
061:
062: /**
063: * PdfSmartCopy has the same functionality as PdfCopy,
064: * but when resources (such as fonts, images,...) are
065: * encountered, a reference to these resources is saved
066: * in a cache, so that they can be reused.
067: * This requires more memory, but reduces the file size
068: * of the resulting PDF document.
069: */
070:
071: public class PdfSmartCopy extends PdfCopy {
072:
073: /** the cache with the streams and references. */
074: private HashMap streamMap = null;
075:
076: /** Creates a PdfSmartCopy instance. */
077: public PdfSmartCopy(Document document, OutputStream os)
078: throws DocumentException {
079: super (document, os);
080: this .streamMap = new HashMap();
081: }
082:
083: /**
084: * Translate a PRIndirectReference to a PdfIndirectReference
085: * In addition, translates the object numbers, and copies the
086: * referenced object to the output file if it wasn't available
087: * in the cache yet. If it's in the cache, the reference to
088: * the already used stream is returned.
089: *
090: * NB: PRIndirectReferences (and PRIndirectObjects) really need to know what
091: * file they came from, because each file has its own namespace. The translation
092: * we do from their namespace to ours is *at best* heuristic, and guaranteed to
093: * fail under some circumstances.
094: */
095: protected PdfIndirectReference copyIndirect(PRIndirectReference in)
096: throws IOException, BadPdfFormatException {
097: PdfObject srcObj = PdfReader.getPdfObjectRelease(in);
098: ByteStore streamKey = null;
099: boolean validStream = false;
100: if (srcObj.isStream()
101: && !((PRStream) srcObj).contains(PdfName.BBOX)) {
102: validStream = true;
103: // Only the content and the key names is compared, probably the key values should also be compared
104: streamKey = new ByteStore((PRStream) srcObj);
105: PdfIndirectReference streamRef = (PdfIndirectReference) streamMap
106: .get(streamKey);
107: if (streamRef != null) {
108: return streamRef;
109: }
110: }
111:
112: PdfIndirectReference theRef;
113: RefKey key = new RefKey(in);
114: IndirectReferences iRef = (IndirectReferences) indirects
115: .get(key);
116: if (iRef != null) {
117: theRef = iRef.getRef();
118: if (iRef.getCopied()) {
119: return theRef;
120: }
121: } else {
122: theRef = body.getPdfIndirectReference();
123: iRef = new IndirectReferences(theRef);
124: indirects.put(key, iRef);
125: }
126: iRef.setCopied();
127:
128: if (validStream) {
129: streamMap.put(streamKey, theRef);
130: }
131:
132: PdfObject obj = copyObject(srcObj);
133: addToBody(obj, theRef);
134: return theRef;
135: }
136:
137: static class ByteStore {
138: private byte[] b;
139: private int hash;
140:
141: ByteStore(PRStream str) throws IOException {
142: byte[] streamContent = PdfReader.getStreamBytesRaw(str);
143: Object[] keys = str.getKeys().toArray();
144: Arrays.sort(keys);
145: ByteBuffer bb = new ByteBuffer();
146: for (int k = 0; k < keys.length; ++k) {
147: bb.append(keys[k].toString());
148: }
149: bb.append(streamContent);
150: this .b = bb.toByteArray();
151: }
152:
153: public boolean equals(Object obj) {
154: if (!(obj instanceof ByteStore))
155: return false;
156: if (hashCode() != obj.hashCode())
157: return false;
158: return Arrays.equals(b, ((ByteStore) obj).b);
159: }
160:
161: public int hashCode() {
162: if (hash == 0) {
163: int len = b.length;
164: for (int k = 0; k < len; ++k) {
165: hash = hash * 31 + (b[k] & 0xff);
166: }
167: }
168: return hash;
169: }
170: }
171: }
|