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.io.IOException; 20 import java.util.List; 21 22 import org.apache.pdfbox.cos.COSBase; 23 import org.apache.pdfbox.cos.COSName; 24 import org.apache.pdfbox.cos.COSStream; 25 26 import org.apache.pdfbox.pdmodel.PDDocument; 27 import org.apache.pdfbox.pdmodel.common.COSObjectable; 28 import org.apache.pdfbox.pdmodel.common.PDMetadata; 29 import org.apache.pdfbox.pdmodel.common.PDStream; 30 31 /** 32 * The base class for all XObjects in the PDF document. 33 * 34 * @author <a href="mailto:ben@benlitchfield.com">Ben Litchfield</a> 35 * @author mathiak 36 * @author Marcel Kammer 37 * @version $Revision: 1.14 $ 38 */ 39 public abstract class PDXObject implements COSObjectable 40 { 41 private PDStream xobject; 42 43 /** 44 * Standard constuctor. 45 * 46 * @param xobj The XObject dictionary. 47 */ 48 public PDXObject(COSStream xobj) 49 { 50 xobject = new PDStream( xobj ); 51 xobject.getStream().setName( COSName.TYPE, "XObject" ); 52 } 53 54 /** 55 * Standard constuctor. 56 * 57 * @param xobj The XObject dictionary. 58 */ 59 public PDXObject(PDStream xobj) 60 { 61 xobject = xobj; 62 xobject.getStream().setName( COSName.TYPE, "XObject" ); 63 } 64 65 /** 66 * Standard constuctor. 67 * 68 * @param doc The doc to store the object contents. 69 */ 70 public PDXObject(PDDocument doc) 71 { 72 xobject = new PDStream(doc); 73 xobject.getStream().setName( COSName.TYPE, "XObject" ); 74 } 75 76 /** 77 * Returns the stream. 78 * 79 * {@inheritDoc} 80 */ 81 public COSBase getCOSObject() 82 { 83 return xobject.getCOSObject(); 84 } 85 86 /** 87 * Returns the stream. 88 * @return The stream for this object. 89 */ 90 public COSStream getCOSStream() 91 { 92 return xobject.getStream(); 93 } 94 95 /** 96 * Returns the stream. 97 * @return The stream for this object. 98 */ 99 public PDStream getPDStream() 100 { 101 return xobject; 102 } 103 104 /** 105 * Create the correct xobject from the cos base. 106 * 107 * @param xobject The cos level xobject to create. 108 * 109 * @return a pdmodel xobject 110 * @throws IOException If there is an error creating the xobject. 111 */ 112 public static PDXObject createXObject( COSBase xobject ) throws IOException 113 { 114 PDXObject retval = null; 115 if( xobject == null ) 116 { 117 retval = null; 118 } 119 else if( xobject instanceof COSStream ) 120 { 121 COSStream xstream = (COSStream)xobject; 122 String subtype = xstream.getNameAsString( "Subtype" ); 123 if( subtype.equals( PDXObjectImage.SUB_TYPE ) ) 124 { 125 PDStream image = new PDStream( xstream ); 126 // See if filters are DCT or JPX otherwise treat as Bitmap-like 127 // There might be a problem with several filters, but that's ToDo until 128 // I find an example 129 List filters = image.getFilters(); 130 if( filters != null && filters.contains( COSName.DCT_DECODE.getName() ) ) 131 { 132 return new PDJpeg(image); 133 } 134 else if ( filters != null && filters.contains( COSName.CCITTFAX_DECODE.getName() ) ) 135 { 136 return new PDCcitt(image); 137 } 138 else if( filters != null && filters.contains(COSName.JPX_DECODE.getName())) 139 { 140 //throw new IOException( "JPXDecode has not been implemented for images" ); 141 //JPX Decode is not really supported right now, but if we are just doing 142 //text extraction then we don't want to throw an exception, so for now 143 //just return a PDPixelMap, which will break later on if it is 144 //actually used, but for text extraction it is not used. 145 146 return new PDPixelMap( image ); 147 148 } 149 /*else if( filters != null && filters.contains(COSName.FLATE_DECODE.getName())) 150 { 151 retval = new PDPixelMap(image); 152 }*/ 153 else 154 { 155 retval = new PDPixelMap(image); 156 //throw new IOException ("Default branch: filters = " + filters.toString()); 157 } 158 } 159 else if( subtype.equals( PDXObjectForm.SUB_TYPE ) ) 160 { 161 retval = new PDXObjectForm( xstream ); 162 } 163 else 164 { 165 throw new IOException( "Unknown xobject subtype '" + subtype + "'" ); 166 } 167 } 168 else 169 { 170 throw new IOException( "Unknown xobject type:" + xobject.getClass().getName() ); 171 } 172 173 return retval; 174 } 175 176 /** 177 * Get the metadata that is part of the document catalog. This will 178 * return null if there is no meta data for this object. 179 * 180 * @return The metadata for this object. 181 */ 182 public PDMetadata getMetadata() 183 { 184 PDMetadata retval = null; 185 COSStream mdStream = (COSStream)xobject.getStream().getDictionaryObject( "Metadata" ); 186 if( mdStream != null ) 187 { 188 retval = new PDMetadata( mdStream ); 189 } 190 return retval; 191 } 192 193 /** 194 * Set the metadata for this object. This can be null. 195 * 196 * @param meta The meta data for this object. 197 */ 198 public void setMetadata( PDMetadata meta ) 199 { 200 xobject.getStream().setItem( "Metadata", meta ); 201 } 202 }