1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 package org.apache.pdfbox.pdmodel.graphics.xobject; 18 19 import java.awt.image.BufferedImage; 20 import java.io.FileOutputStream; 21 import java.io.IOException; 22 import java.io.OutputStream; 23 import java.io.File; 24 25 import org.apache.commons.logging.Log; 26 import org.apache.commons.logging.LogFactory; 27 import org.apache.pdfbox.cos.COSBase; 28 import org.apache.pdfbox.cos.COSName; 29 import org.apache.pdfbox.pdmodel.PDDocument; 30 import org.apache.pdfbox.pdmodel.common.PDStream; 31 import org.apache.pdfbox.pdmodel.graphics.color.PDColorSpace; 32 import org.apache.pdfbox.pdmodel.graphics.color.PDColorSpaceFactory; 33 import org.apache.pdfbox.pdmodel.graphics.color.PDDeviceGray; 34 import org.apache.pdfbox.pdmodel.graphics.PDGraphicsState; 35 36 /** 37 * The prototype for all PDImages. 38 * 39 * @author <a href="mailto:ben@benlitchfield.com">Ben Litchfield</a> 40 * @author mathiak 41 * @version $Revision: 1.9 $ 42 */ 43 public abstract class PDXObjectImage extends PDXObject 44 { 45 46 /** 47 * Log instance. 48 */ 49 private static final Log log = LogFactory.getLog(PDXObjectImage.class); 50 51 /** 52 * The XObject subtype. 53 */ 54 public static final String SUB_TYPE = "Image"; 55 56 /** 57 * This contains the suffix used when writing to file. 58 */ 59 private String suffix; 60 61 private PDGraphicsState graphicsState; 62 63 /** 64 * Standard constuctor. 65 * 66 * @param imageStream The XObject is passed as a COSStream. 67 * @param fileSuffix The file suffix, jpg/png. 68 */ 69 public PDXObjectImage(PDStream imageStream, String fileSuffix) 70 { 71 super( imageStream ); 72 suffix = fileSuffix; 73 } 74 75 /** 76 * Standard constuctor. 77 * 78 * @param doc The document to store the stream in. 79 * @param fileSuffix The file suffix, jpg/png. 80 */ 81 public PDXObjectImage(PDDocument doc, String fileSuffix) 82 { 83 super( doc ); 84 getCOSStream().setName( COSName.SUBTYPE, SUB_TYPE ); 85 suffix = fileSuffix; 86 } 87 88 /** 89 * Returns an java.awt.Image, that can be used for display etc. 90 * 91 * @return This PDF object as an AWT image. 92 * 93 * @throws IOException If there is an error creating the image. 94 */ 95 public abstract BufferedImage getRGBImage() throws IOException; 96 97 /** 98 * Writes the Image to out. 99 * @param out the OutputStream that the Image is written to. 100 * @throws IOException when somethings wrong with out 101 */ 102 public abstract void write2OutputStream(OutputStream out) throws IOException; 103 104 /** 105 * Writes the image to a file with the filename + an appropriate suffix, like "Image.jpg". 106 * The suffix is automatically set by the 107 * @param filename the filename 108 * @throws IOException When somethings wrong with the corresponding file. 109 */ 110 public void write2file(String filename) throws IOException 111 { 112 FileOutputStream out = null; 113 try 114 { 115 out = new FileOutputStream(filename + "." + suffix); 116 write2OutputStream(out); 117 out.flush(); 118 } 119 finally 120 { 121 if( out != null ) 122 { 123 out.close(); 124 } 125 } 126 } 127 128 /** 129 * Writes the image to a file with the filename + an appropriate 130 suffix, like "Image.jpg". 131 * The suffix is automatically set by the 132 * @param file the file 133 * @throws IOException When somethings wrong with the corresponding 134 file. 135 */ 136 public void write2file(File file) throws IOException 137 { 138 FileOutputStream out = null; 139 try 140 { 141 out = new FileOutputStream(file); 142 write2OutputStream(out); 143 out.flush(); 144 } 145 finally 146 { 147 if( out != null ) 148 { 149 out.close(); 150 } 151 } 152 } 153 154 /** 155 * Get the height of the image. 156 * 157 * @return The height of the image. 158 */ 159 public int getHeight() 160 { 161 return getCOSStream().getInt( "Height", -1 ); 162 } 163 164 /** 165 * Set the height of the image. 166 * 167 * @param height The height of the image. 168 */ 169 public void setHeight( int height ) 170 { 171 getCOSStream().setInt( "Height", height ); 172 } 173 174 /** 175 * Get the width of the image. 176 * 177 * @return The width of the image. 178 */ 179 public int getWidth() 180 { 181 return getCOSStream().getInt( "Width", -1 ); 182 } 183 184 /** 185 * Set the width of the image. 186 * 187 * @param width The width of the image. 188 */ 189 public void setWidth( int width ) 190 { 191 getCOSStream().setInt( "Width", width ); 192 } 193 194 /** 195 * The bits per component of this image. This will return -1 if one has not 196 * been set. 197 * 198 * @return The number of bits per component. 199 */ 200 public int getBitsPerComponent() 201 { 202 return getCOSStream().getInt( new String[] { "BPC", "BitsPerComponent"}, -1 ); 203 } 204 205 /** 206 * Set the number of bits per component. 207 * 208 * @param bpc The number of bits per component. 209 */ 210 public void setBitsPerComponent( int bpc ) 211 { 212 getCOSStream().setInt( "BitsPerComponent", bpc ); 213 } 214 215 /** 216 * This will get the color space or null if none exists. 217 * 218 * @return The color space for this image. 219 * 220 * @throws IOException If there is an error getting the colorspace. 221 */ 222 public PDColorSpace getColorSpace() throws IOException 223 { 224 COSBase cs = getCOSStream().getDictionaryObject( new String[]{ "CS", "ColorSpace" } ); 225 PDColorSpace retval = null; 226 if( cs != null ) 227 { 228 retval = PDColorSpaceFactory.createColorSpace( cs ); 229 if (retval == null) 230 { 231 log.info("About to return NULL from createColorSpace branch"); 232 } 233 } 234 else 235 { 236 //there are some cases where the 'required' CS value is not present 237 //but we know that it will be grayscale for a CCITT filter. 238 COSBase filter = getCOSStream().getDictionaryObject( "Filter" ); 239 if( COSName.CCITTFAX_DECODE.equals( filter ) || 240 COSName.CCITTFAX_DECODE_ABBREVIATION.equals( filter ) ) 241 { 242 retval = new PDDeviceGray(); 243 if (retval == null) 244 { 245 log.info("About to return NULL from CCITT branch"); 246 } 247 } 248 else if (getImageMask()) 249 { 250 //Stencil Mask branch. Section 4.8.5 of the reference, page 350 in version 1.7. 251 retval = graphicsState.getNonStrokingColor().getColorSpace(); 252 log.info("Stencil Mask branch returning " + retval.toString()); 253 //throw new IOException("Trace the Stencil Mask!!!!"); 254 255 } 256 else 257 { 258 log.info("About to return NULL from unhandled branch." 259 + " filter = " + filter); 260 } 261 } 262 return retval; 263 } 264 265 /** 266 * This will set the color space for this image. 267 * 268 * @param cs The color space for this image. 269 */ 270 public void setColorSpace( PDColorSpace cs ) 271 { 272 COSBase base = null; 273 if( cs != null ) 274 { 275 base = cs.getCOSObject(); 276 } 277 getCOSStream().setItem( COSName.getPDFName( "ColorSpace" ), base ); 278 } 279 280 /** 281 * This will get the suffix for this image type, jpg/png. 282 * 283 * @return The image suffix. 284 */ 285 public String getSuffix() 286 { 287 return suffix; 288 } 289 290 /** 291 * Get the ImageMask flag. Used in Stencil Masking. Section 4.8.5 of the spec. 292 * 293 * @return The ImageMask flag. This is optional and defaults to False, so if it does not exist, we return False 294 */ 295 public boolean getImageMask() 296 { 297 return getCOSStream().getBoolean( "ImageMask", false ); 298 } 299 300 /** 301 * Allow the Invoke operator to set the graphics state so that, 302 * in the case of an Image Mask, we can get to the current nonstroking colorspace. 303 * @param newGS The new graphicstate 304 */ 305 public void setGraphicsState(PDGraphicsState newGS) 306 { 307 graphicsState = newGS; 308 } 309 }