libopenraw
|
00001 /* 00002 * libopenraw - crwfile.cpp 00003 * 00004 * Copyright (C) 2006-2008 Hubert Figuiere 00005 * Copyright (c) 2008 Novell, Inc. 00006 * 00007 * This library is free software: you can redistribute it and/or 00008 * modify it under the terms of the GNU Lesser General Public License 00009 * as published by the Free Software Foundation, either version 3 of 00010 * the License, or (at your option) any later version. 00011 * 00012 * This library is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 * Lesser General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU Lesser General Public 00018 * License along with this library. If not, see 00019 * <http://www.gnu.org/licenses/>. 00020 */ 00021 00022 #include <algorithm> 00023 #include <utility> 00024 #include <boost/bind.hpp> 00025 #include <boost/scoped_ptr.hpp> 00026 00027 #include <libopenraw/libopenraw.h> 00028 #include <libopenraw++/thumbnail.h> 00029 #include <libopenraw++/rawdata.h> 00030 00031 #include "debug.h" 00032 #include "io/file.h" 00033 #include "io/streamclone.h" 00034 #include "io/memstream.h" 00035 #include "crwfile.h" 00036 #include "ciffcontainer.h" 00037 #include "jfifcontainer.h" 00038 #include "crwdecompressor.h" 00039 #include "metavalue.h" 00040 00041 #include "rawfilefactory.h" 00042 00043 using namespace Debug; 00044 using boost::scoped_ptr; 00045 00046 namespace OpenRaw { 00047 00048 namespace Internals { 00049 00050 using namespace CIFF; 00051 00052 const RawFile::camera_ids_t CRWFile::s_def[] = { 00053 { "Canon EOS D30" , OR_MAKE_FILE_TYPEID(OR_TYPEID_VENDOR_CANON, 00054 OR_TYPEID_CANON_D30) }, 00055 { "Canon EOS D60" , OR_MAKE_FILE_TYPEID(OR_TYPEID_VENDOR_CANON, 00056 OR_TYPEID_CANON_D60) }, 00057 { "Canon EOS 10D" , OR_MAKE_FILE_TYPEID(OR_TYPEID_VENDOR_CANON, 00058 OR_TYPEID_CANON_10D) }, 00059 { "Canon EOS 300D DIGITAL", OR_MAKE_FILE_TYPEID(OR_TYPEID_VENDOR_CANON, 00060 OR_TYPEID_CANON_300D) }, 00061 { "Canon PowerShot G1", OR_MAKE_FILE_TYPEID(OR_TYPEID_VENDOR_CANON, 00062 OR_TYPEID_CANON_G1) }, 00063 { "Canon PowerShot G2", OR_MAKE_FILE_TYPEID(OR_TYPEID_VENDOR_CANON, 00064 OR_TYPEID_CANON_G2) }, 00065 { "Canon PowerShot G3", OR_MAKE_FILE_TYPEID(OR_TYPEID_VENDOR_CANON, 00066 OR_TYPEID_CANON_G3) }, 00067 { "Canon PowerShot G5", OR_MAKE_FILE_TYPEID(OR_TYPEID_VENDOR_CANON, 00068 OR_TYPEID_CANON_G5) }, 00069 { "Canon PowerShot G6", OR_MAKE_FILE_TYPEID(OR_TYPEID_VENDOR_CANON, 00070 OR_TYPEID_CANON_G6) }, 00071 { "Canon PowerShot G7", OR_MAKE_FILE_TYPEID(OR_TYPEID_VENDOR_CANON, 00072 OR_TYPEID_CANON_G7) }, 00073 { "Canon PowerShot Pro1", OR_MAKE_FILE_TYPEID(OR_TYPEID_VENDOR_CANON, 00074 OR_TYPEID_CANON_PRO1) }, 00075 { 0, 0 } 00076 }; 00077 00078 RawFile *CRWFile::factory(IO::Stream *s) 00079 { 00080 return new CRWFile(s); 00081 } 00082 00083 CRWFile::CRWFile(IO::Stream *s) 00084 : RawFile(s, OR_RAWFILE_TYPE_CRW), 00085 m_io(s), 00086 m_container(new CIFFContainer(m_io)), 00087 m_x(0), m_y(0) 00088 { 00089 _setIdMap(s_def); 00090 } 00091 00092 CRWFile::~CRWFile() 00093 { 00094 delete m_container; 00095 delete m_io; 00096 } 00097 00098 ::or_error CRWFile::_enumThumbnailSizes(std::vector<uint32_t> &list) 00099 { 00100 ::or_error err = OR_ERROR_NOT_FOUND; 00101 00102 Heap::Ref heap = m_container->heap(); 00103 if(!heap) { 00104 // this is not a CIFF file. 00105 return err; 00106 } 00107 const RecordEntry::List & records = heap->records(); 00108 RecordEntry::List::const_iterator iter; 00109 iter = std::find_if(records.begin(), records.end(), boost::bind( 00110 &RecordEntry::isA, _1, 00111 static_cast<uint16_t>(TAG_JPEGIMAGE))); 00112 if (iter != records.end()) { 00113 Trace(DEBUG2) << "JPEG @" << (*iter).offset << "\n"; 00114 m_x = m_y = 0; 00115 00116 scoped_ptr<IO::StreamClone> s(new IO::StreamClone(m_io, heap->offset() 00117 + (*iter).offset)); 00118 scoped_ptr<JFIFContainer> jfif(new JFIFContainer(s.get(), 0)); 00119 00120 jfif->getDimensions(m_x, m_y); 00121 Trace(DEBUG1) << "JPEG dimensions x=" << m_x 00122 << " y=" << m_y << "\n"; 00123 list.push_back(std::max(m_x,m_y)); 00124 err = OR_ERROR_NONE; 00125 } 00126 00127 return err; 00128 } 00129 00130 ::or_error CRWFile::_getThumbnail(uint32_t /*size*/, Thumbnail & thumbnail) 00131 { 00132 ::or_error err = OR_ERROR_NOT_FOUND; 00133 Heap::Ref heap = m_container->heap(); 00134 if(!heap) { 00135 // this is not a CIFF file. 00136 return err; 00137 } 00138 00139 const RecordEntry::List & records = heap->records(); 00140 RecordEntry::List::const_iterator iter; 00141 iter = std::find_if(records.begin(), records.end(), boost::bind( 00142 &RecordEntry::isA, _1, 00143 static_cast<uint16_t>(TAG_JPEGIMAGE))); 00144 if (iter != records.end()) { 00145 Trace(DEBUG2) << "JPEG @" << (*iter).offset << "\n"; 00146 size_t byte_size = (*iter).length; 00147 void *buf = thumbnail.allocData(byte_size); 00148 size_t real_size = (*iter).fetchData(heap.get(), buf, byte_size); 00149 if (real_size != byte_size) { 00150 Trace(WARNING) << "wrong size\n"; 00151 } 00152 thumbnail.setDimensions(m_x, m_y); 00153 thumbnail.setDataType(OR_DATA_TYPE_JPEG); 00154 err = OR_ERROR_NONE; 00155 } 00156 00157 return err; 00158 } 00159 00160 ::or_error CRWFile::_getRawData(RawData & data, uint32_t options) 00161 { 00162 ::or_error err = OR_ERROR_NOT_FOUND; 00163 Heap::Ref props = m_container->getImageProps(); 00164 00165 if(!props) { 00166 return OR_ERROR_NOT_FOUND; 00167 } 00168 const ImageSpec * img_spec = m_container->getImageSpec(); 00169 uint32_t x, y; 00170 x = y = 0; 00171 int32_t orientation = 0; 00172 if(img_spec) { 00173 x = img_spec->imageWidth; 00174 y = img_spec->imageHeight; 00175 orientation = img_spec->exifOrientation(); 00176 } 00177 00178 // locate decoder table 00179 const CIFF::RecordEntry::List & propsRecs = props->records(); 00180 CIFF::RecordEntry::List::const_iterator iter; 00181 iter = std::find_if(propsRecs.begin(), propsRecs.end(), boost::bind( 00182 &RecordEntry::isA, _1, 00183 static_cast<uint16_t>(TAG_EXIFINFORMATION))); 00184 if (iter == propsRecs.end()) { 00185 Trace(ERROR) << "Couldn't find the Exif information.\n"; 00186 return err; 00187 } 00188 00189 Heap exifProps(iter->offset + props->offset(), iter->length, m_container); 00190 00191 const RecordEntry::List & exifPropsRecs = exifProps.records(); 00192 iter = std::find_if(exifPropsRecs.begin(), exifPropsRecs.end(), 00193 boost::bind( 00194 &RecordEntry::isA, _1, 00195 static_cast<uint16_t>(TAG_DECODERTABLE))); 00196 if (iter == exifPropsRecs.end()) { 00197 Trace(ERROR) << "Couldn't find the decoder table.\n"; 00198 return err; 00199 } 00200 Trace(DEBUG2) << "length = " << iter->length << "\n"; 00201 Trace(DEBUG2) << "offset = " << exifProps.offset() + iter->offset << "\n"; 00202 IO::Stream *file = m_container->file(); 00203 file->seek(exifProps.offset() + iter->offset, SEEK_SET); 00204 uint32_t decoderTable; 00205 if(m_container->readUInt32(file, decoderTable)) { 00206 Trace(DEBUG2) << "decoder table = " << decoderTable << "\n"; 00207 } 00208 00209 // locate the CFA info 00210 uint16_t cfa_x, cfa_y; 00211 iter = std::find_if(exifPropsRecs.begin(), exifPropsRecs.end(), boost::bind( 00212 &RecordEntry::isA, _1, 00213 static_cast<uint16_t>(TAG_SENSORINFO))); 00214 if (iter == exifPropsRecs.end()) { 00215 Trace(ERROR) << "Couldn't find the sensor info.\n"; 00216 return err; 00217 } 00218 Trace(DEBUG2) << "length = " << iter->length << "\n"; 00219 Trace(DEBUG2) << "offset = " << exifProps.offset() + iter->offset << "\n"; 00220 00221 // go figure what the +2 is. looks like it is the byte # 00222 file->seek(exifProps.offset() + iter->offset + 2, SEEK_SET); 00223 if(!(m_container->readUInt16(file, cfa_x) 00224 && m_container->readUInt16(file, cfa_y))) { 00225 Trace(ERROR) << "Couldn't find the sensor size.\n"; 00226 return err; 00227 } 00228 00229 00230 const CIFF::RecordEntry *entry = m_container->getRawDataRecord(); 00231 if (entry) { 00232 CIFF::Heap::Ref heap = m_container->heap(); 00233 Trace(DEBUG2) << "RAW @" << heap->offset() + entry->offset << "\n"; 00234 size_t byte_size = entry->length; 00235 void *buf = data.allocData(byte_size); 00236 size_t real_size = entry->fetchData(heap.get(), buf, byte_size); 00237 if (real_size != byte_size) { 00238 Trace(WARNING) << "wrong size\n"; 00239 } 00240 data.setDimensions(x, y); 00241 data.setCfaPattern(OR_CFA_PATTERN_RGGB); 00242 data.setDataType(OR_DATA_TYPE_COMPRESSED_CFA); 00243 00244 // decompress if we need 00245 if((options & OR_OPTIONS_DONT_DECOMPRESS) == 0) { 00246 boost::scoped_ptr<IO::Stream> s(new IO::MemStream(data.data(), 00247 data.size())); 00248 s->open(); // TODO check success 00249 00250 CrwDecompressor decomp(s.get(), m_container); 00251 00252 decomp.setOutputDimensions(cfa_x, cfa_y); 00253 decomp.setDecoderTable(decoderTable); 00254 RawData *dData = decomp.decompress(); 00255 if (dData != NULL) { 00256 Trace(DEBUG1) << "Out size is " << dData->x() 00257 << "x" << dData->y() << "\n"; 00258 dData->setCfaPattern(data.cfaPattern()); 00259 data.swap(*dData); 00260 delete dData; 00261 } 00262 } 00263 err = OR_ERROR_NONE; 00264 } 00265 return err; 00266 } 00267 00268 MetaValue *CRWFile::_getMetaValue(int32_t meta_index) 00269 { 00270 MetaValue * val = NULL; 00271 00272 switch(META_INDEX_MASKOUT(meta_index)) { 00273 case META_NS_TIFF: 00274 { 00275 switch(META_NS_MASKOUT(meta_index)) { 00276 case EXIF_TAG_ORIENTATION: 00277 { 00278 const ImageSpec * img_spec = m_container->getImageSpec(); 00279 if(img_spec) { 00280 val = new MetaValue(static_cast<uint32_t>( 00281 img_spec->exifOrientation())); 00282 } 00283 break; 00284 } 00285 case EXIF_TAG_MODEL: 00286 { 00287 CIFF::Heap::Ref heap = m_container->getCameraProps(); 00288 if(heap) { 00289 const CIFF::RecordEntry::List & propsRecs = heap->records(); 00290 CIFF::RecordEntry::List::const_iterator iter; 00291 iter = std::find_if(propsRecs.begin(), propsRecs.end(), 00292 boost::bind( 00293 &CIFF::RecordEntry::isA, _1, 00294 static_cast<uint16_t>(CIFF::TAG_RAWMAKEMODEL))); 00295 if (iter == propsRecs.end()) { 00296 Trace(ERROR) << "Couldn't find the image info.\n"; 00297 } 00298 else { 00299 char buf[256]; 00300 size_t sz = iter->length; 00301 if(sz > 256) { 00302 sz = 256; 00303 } 00304 size_t sz2; 00305 std::string model; 00306 sz2 = iter->fetchData(heap.get(), (void*)buf, sz); 00307 char *p = buf; 00308 while(*p) { 00309 p++; 00310 } 00311 p++; 00312 model = p; 00313 val = new MetaValue(model); 00314 Trace(DEBUG1) << "Model " << model << "\n"; 00315 } 00316 } 00317 00318 00319 break; 00320 } 00321 } 00322 break; 00323 } 00324 case META_NS_EXIF: 00325 break; 00326 default: 00327 Trace(ERROR) << "Unknown Meta Namespace\n"; 00328 break; 00329 } 00330 00331 return val; 00332 } 00333 00334 void CRWFile::_identifyId() 00335 { 00336 MetaValue * v = _getMetaValue(META_NS_TIFF | EXIF_TAG_MODEL); 00337 if(v) { 00338 std::string model; 00339 try { 00340 model = v->getString(); 00341 _setTypeId(_typeIdFromModel(model)); 00342 } 00343 catch(...) 00344 { 00345 } 00346 delete v; 00347 } 00348 } 00349 00350 } 00351 } 00352 00353 /* 00354 Local Variables: 00355 mode:c++ 00356 c-file-style:"stroustrup" 00357 c-file-offsets:((innamespace . 0)) 00358 indent-tabs-mode:nil 00359 fill-column:80 00360 End: 00361 */