libopenraw
crwfile.cpp
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 "trace.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 */