001/* 002 * $Id: PdfImage.java 4784 2011-03-15 08:33:00Z blowagie $ 003 * 004 * This file is part of the iText (R) project. 005 * Copyright (c) 1998-2011 1T3XT BVBA 006 * Authors: Bruno Lowagie, Paulo Soares, et al. 007 * 008 * This program is free software; you can redistribute it and/or modify 009 * it under the terms of the GNU Affero General Public License version 3 010 * as published by the Free Software Foundation with the addition of the 011 * following permission added to Section 15 as permitted in Section 7(a): 012 * FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY 1T3XT, 013 * 1T3XT DISCLAIMS THE WARRANTY OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. 014 * 015 * This program is distributed in the hope that it will be useful, but 016 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 017 * or FITNESS FOR A PARTICULAR PURPOSE. 018 * See the GNU Affero General Public License for more details. 019 * You should have received a copy of the GNU Affero General Public License 020 * along with this program; if not, see http://www.gnu.org/licenses or write to 021 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 022 * Boston, MA, 02110-1301 USA, or download the license from the following URL: 023 * http://itextpdf.com/terms-of-use/ 024 * 025 * The interactive user interfaces in modified source and object code versions 026 * of this program must display Appropriate Legal Notices, as required under 027 * Section 5 of the GNU Affero General Public License. 028 * 029 * In accordance with Section 7(b) of the GNU Affero General Public License, 030 * a covered work must retain the producer line in every PDF that is created 031 * or manipulated using iText. 032 * 033 * You can be released from the requirements of the license by purchasing 034 * a commercial license. Buying such a license is mandatory as soon as you 035 * develop commercial activities involving the iText software without 036 * disclosing the source code of your own applications. 037 * These activities include: offering paid services to customers as an ASP, 038 * serving PDFs on the fly in a web application, shipping iText with a closed 039 * source product. 040 * 041 * For more information, please contact iText Software Corp. at this 042 * address: sales@itextpdf.com 043 */ 044package com.itextpdf.text.pdf; 045 046import java.io.ByteArrayOutputStream; 047import java.io.IOException; 048import java.io.InputStream; 049import java.io.OutputStream; 050import com.itextpdf.text.error_messages.MessageLocalization; 051 052import com.itextpdf.text.Image; 053 054/** 055 * <CODE>PdfImage</CODE> is a <CODE>PdfStream</CODE> containing an image-<CODE>Dictionary</CODE> and -stream. 056 */ 057 058public class PdfImage extends PdfStream { 059 060 static final int TRANSFERSIZE = 4096; 061 // membervariables 062 063 /** This is the <CODE>PdfName</CODE> of the image. */ 064 protected PdfName name = null; 065 066 // constructor 067 068 /** 069 * Constructs a <CODE>PdfImage</CODE>-object. 070 * 071 * @param image the <CODE>Image</CODE>-object 072 * @param name the <CODE>PdfName</CODE> for this image 073 * @throws BadPdfFormatException on error 074 */ 075 076 public PdfImage(Image image, String name, PdfIndirectReference maskRef) throws BadPdfFormatException { 077 super(); 078 if (name == null) 079 generateImgResName( image ); 080 else 081 this.name = new PdfName(name); 082 put(PdfName.TYPE, PdfName.XOBJECT); 083 put(PdfName.SUBTYPE, PdfName.IMAGE); 084 put(PdfName.WIDTH, new PdfNumber(image.getWidth())); 085 put(PdfName.HEIGHT, new PdfNumber(image.getHeight())); 086 if (image.getLayer() != null) 087 put(PdfName.OC, image.getLayer().getRef()); 088 if (image.isMask() && (image.getBpc() == 1 || image.getBpc() > 0xff)) 089 put(PdfName.IMAGEMASK, PdfBoolean.PDFTRUE); 090 if (maskRef != null) { 091 if (image.isSmask()) 092 put(PdfName.SMASK, maskRef); 093 else 094 put(PdfName.MASK, maskRef); 095 } 096 if (image.isMask() && image.isInverted()) 097 put(PdfName.DECODE, new PdfLiteral("[1 0]")); 098 if (image.isInterpolation()) 099 put(PdfName.INTERPOLATE, PdfBoolean.PDFTRUE); 100 InputStream is = null; 101 try { 102 // Raw Image data 103 if (image.isImgRaw()) { 104 // will also have the CCITT parameters 105 int colorspace = image.getColorspace(); 106 int transparency[] = image.getTransparency(); 107 if (transparency != null && !image.isMask() && maskRef == null) { 108 StringBuilder s = new StringBuilder("["); 109 for (int k = 0; k < transparency.length; ++k) 110 s.append(transparency[k]).append(" "); 111 s.append("]"); 112 put(PdfName.MASK, new PdfLiteral(s.toString())); 113 } 114 bytes = image.getRawData(); 115 put(PdfName.LENGTH, new PdfNumber(bytes.length)); 116 int bpc = image.getBpc(); 117 if (bpc > 0xff) { 118 if (!image.isMask()) 119 put(PdfName.COLORSPACE, PdfName.DEVICEGRAY); 120 put(PdfName.BITSPERCOMPONENT, new PdfNumber(1)); 121 put(PdfName.FILTER, PdfName.CCITTFAXDECODE); 122 int k = bpc - Image.CCITTG3_1D; 123 PdfDictionary decodeparms = new PdfDictionary(); 124 if (k != 0) 125 decodeparms.put(PdfName.K, new PdfNumber(k)); 126 if ((colorspace & Image.CCITT_BLACKIS1) != 0) 127 decodeparms.put(PdfName.BLACKIS1, PdfBoolean.PDFTRUE); 128 if ((colorspace & Image.CCITT_ENCODEDBYTEALIGN) != 0) 129 decodeparms.put(PdfName.ENCODEDBYTEALIGN, PdfBoolean.PDFTRUE); 130 if ((colorspace & Image.CCITT_ENDOFLINE) != 0) 131 decodeparms.put(PdfName.ENDOFLINE, PdfBoolean.PDFTRUE); 132 if ((colorspace & Image.CCITT_ENDOFBLOCK) != 0) 133 decodeparms.put(PdfName.ENDOFBLOCK, PdfBoolean.PDFFALSE); 134 decodeparms.put(PdfName.COLUMNS, new PdfNumber(image.getWidth())); 135 decodeparms.put(PdfName.ROWS, new PdfNumber(image.getHeight())); 136 put(PdfName.DECODEPARMS, decodeparms); 137 } 138 else { 139 switch(colorspace) { 140 case 1: 141 put(PdfName.COLORSPACE, PdfName.DEVICEGRAY); 142 if (image.isInverted()) 143 put(PdfName.DECODE, new PdfLiteral("[1 0]")); 144 break; 145 case 3: 146 put(PdfName.COLORSPACE, PdfName.DEVICERGB); 147 if (image.isInverted()) 148 put(PdfName.DECODE, new PdfLiteral("[1 0 1 0 1 0]")); 149 break; 150 case 4: 151 default: 152 put(PdfName.COLORSPACE, PdfName.DEVICECMYK); 153 if (image.isInverted()) 154 put(PdfName.DECODE, new PdfLiteral("[1 0 1 0 1 0 1 0]")); 155 } 156 PdfDictionary additional = image.getAdditional(); 157 if (additional != null) 158 putAll(additional); 159 if (image.isMask() && (image.getBpc() == 1 || image.getBpc() > 8)) 160 remove(PdfName.COLORSPACE); 161 put(PdfName.BITSPERCOMPONENT, new PdfNumber(image.getBpc())); 162 if (image.isDeflated()) 163 put(PdfName.FILTER, PdfName.FLATEDECODE); 164 else { 165 flateCompress(image.getCompressionLevel()); 166 } 167 } 168 return; 169 } 170 // GIF, JPEG or PNG 171 String errorID; 172 if (image.getRawData() == null){ 173 is = image.getUrl().openStream(); 174 errorID = image.getUrl().toString(); 175 } 176 else{ 177 is = new java.io.ByteArrayInputStream(image.getRawData()); 178 errorID = "Byte array"; 179 } 180 switch(image.type()) { 181 case Image.JPEG: 182 put(PdfName.FILTER, PdfName.DCTDECODE); 183 switch(image.getColorspace()) { 184 case 1: 185 put(PdfName.COLORSPACE, PdfName.DEVICEGRAY); 186 break; 187 case 3: 188 put(PdfName.COLORSPACE, PdfName.DEVICERGB); 189 break; 190 default: 191 put(PdfName.COLORSPACE, PdfName.DEVICECMYK); 192 if (image.isInverted()) { 193 put(PdfName.DECODE, new PdfLiteral("[1 0 1 0 1 0 1 0]")); 194 } 195 } 196 put(PdfName.BITSPERCOMPONENT, new PdfNumber(8)); 197 if (image.getRawData() != null){ 198 bytes = image.getRawData(); 199 put(PdfName.LENGTH, new PdfNumber(bytes.length)); 200 return; 201 } 202 streamBytes = new ByteArrayOutputStream(); 203 transferBytes(is, streamBytes, -1); 204 break; 205 case Image.JPEG2000: 206 put(PdfName.FILTER, PdfName.JPXDECODE); 207 if (image.getColorspace() > 0) { 208 switch(image.getColorspace()) { 209 case 1: 210 put(PdfName.COLORSPACE, PdfName.DEVICEGRAY); 211 break; 212 case 3: 213 put(PdfName.COLORSPACE, PdfName.DEVICERGB); 214 break; 215 default: 216 put(PdfName.COLORSPACE, PdfName.DEVICECMYK); 217 } 218 put(PdfName.BITSPERCOMPONENT, new PdfNumber(image.getBpc())); 219 } 220 if (image.getRawData() != null){ 221 bytes = image.getRawData(); 222 put(PdfName.LENGTH, new PdfNumber(bytes.length)); 223 return; 224 } 225 streamBytes = new ByteArrayOutputStream(); 226 transferBytes(is, streamBytes, -1); 227 break; 228 case Image.JBIG2: 229 put(PdfName.FILTER, PdfName.JBIG2DECODE); 230 put(PdfName.COLORSPACE, PdfName.DEVICEGRAY); 231 put(PdfName.BITSPERCOMPONENT, new PdfNumber(1)); 232 if (image.getRawData() != null){ 233 bytes = image.getRawData(); 234 put(PdfName.LENGTH, new PdfNumber(bytes.length)); 235 return; 236 } 237 streamBytes = new ByteArrayOutputStream(); 238 transferBytes(is, streamBytes, -1); 239 break; 240 default: 241 throw new BadPdfFormatException(MessageLocalization.getComposedMessage("1.is.an.unknown.image.format", errorID)); 242 } 243 put(PdfName.LENGTH, new PdfNumber(streamBytes.size())); 244 } 245 catch(IOException ioe) { 246 throw new BadPdfFormatException(ioe.getMessage()); 247 } 248 finally { 249 if (is != null) { 250 try{ 251 is.close(); 252 } 253 catch (Exception ee) { 254 // empty on purpose 255 } 256 } 257 } 258 } 259 260 /** 261 * Returns the <CODE>PdfName</CODE> of the image. 262 * 263 * @return the name 264 */ 265 266 public PdfName name() { 267 return name; 268 } 269 270 static void transferBytes(InputStream in, OutputStream out, int len) throws IOException { 271 byte buffer[] = new byte[TRANSFERSIZE]; 272 if (len < 0) 273 len = 0x7fff0000; 274 int size; 275 while (len != 0) { 276 size = in.read(buffer, 0, Math.min(len, TRANSFERSIZE)); 277 if (size < 0) 278 return; 279 out.write(buffer, 0, size); 280 len -= size; 281 } 282 } 283 284 protected void importAll(PdfImage dup) { 285 name = dup.name; 286 compressed = dup.compressed; 287 compressionLevel = dup.compressionLevel; 288 streamBytes = dup.streamBytes; 289 bytes = dup.bytes; 290 hashMap = dup.hashMap; 291 } 292 293 /** 294 * Called when no resource name is provided in our constructor. This generates a 295 * name that is required to be unique within a given resource dictionary. 296 * @since 5.0.1 297 */ 298 private void generateImgResName( Image img ) { 299 name = new PdfName( "img" + Long.toHexString( img.getMySerialId() ) ); 300 } 301}