libopenraw
cr2file.cpp
00001 /*
00002  * libopenraw - cr2file.cpp
00003  *
00004  * Copyright (C) 2006-2010 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 <boost/scoped_ptr.hpp>
00023 #include <boost/any.hpp>
00024 #include <libopenraw/libopenraw.h>
00025 #include <libopenraw++/thumbnail.h>
00026 #include <libopenraw++/rawdata.h>
00027 
00028 #include "trace.h"
00029 #include "io/file.h"
00030 #include "io/memstream.h"
00031 #include "ifdfilecontainer.h"
00032 #include "ifd.h"
00033 #include "cr2file.h"
00034 #include "jfifcontainer.h"
00035 #include "ljpegdecompressor.h"
00036 #include "rawfilefactory.h"
00037 
00038 using namespace Debug;
00039 
00040 namespace OpenRaw {
00041 
00042     namespace Internals {
00043         const IFDFile::camera_ids_t Cr2File::s_def[] = {
00044             { "Canon EOS-1D Mark II", OR_MAKE_FILE_TYPEID(OR_TYPEID_VENDOR_CANON,
00045                                                           OR_TYPEID_CANON_1DMKII) },
00046             { "Canon EOS-1D Mark III", OR_MAKE_FILE_TYPEID(OR_TYPEID_VENDOR_CANON,
00047                                                            OR_TYPEID_CANON_1DMKIII) },
00048             { "Canon EOS-1D Mark IV", OR_MAKE_FILE_TYPEID(OR_TYPEID_VENDOR_CANON,
00049                                                             OR_TYPEID_CANON_1DMKIV) },
00050             { "Canon EOS-1Ds Mark II", OR_MAKE_FILE_TYPEID(OR_TYPEID_VENDOR_CANON,
00051                                                            OR_TYPEID_CANON_1DSMKII) },
00052             { "Canon EOS-1Ds Mark III", OR_MAKE_FILE_TYPEID(OR_TYPEID_VENDOR_CANON,
00053                                                             OR_TYPEID_CANON_1DSMKIII) },
00054             { "Canon EOS 20D" , OR_MAKE_FILE_TYPEID(OR_TYPEID_VENDOR_CANON,
00055                                                     OR_TYPEID_CANON_20D) },
00056             { "Canon EOS 20Da", OR_MAKE_FILE_TYPEID(OR_TYPEID_VENDOR_CANON,
00057                                                     OR_TYPEID_CANON_20DA) },
00058             { "Canon EOS 30D", OR_MAKE_FILE_TYPEID(OR_TYPEID_VENDOR_CANON,
00059                                                    OR_TYPEID_CANON_30D) },
00060             { "Canon EOS 350D DIGITAL", OR_MAKE_FILE_TYPEID(OR_TYPEID_VENDOR_CANON,
00061                                                     OR_TYPEID_CANON_350D) },            
00062             { "Canon EOS DIGITAL REBEL XT", OR_MAKE_FILE_TYPEID(OR_TYPEID_VENDOR_CANON,
00063                                                     OR_TYPEID_CANON_350D) },            
00064             { "Canon EOS 40D", OR_MAKE_FILE_TYPEID(OR_TYPEID_VENDOR_CANON,
00065                                                    OR_TYPEID_CANON_40D) },
00066             { "Canon EOS 400D DIGITAL", OR_MAKE_FILE_TYPEID(OR_TYPEID_VENDOR_CANON,
00067                                                   OR_TYPEID_CANON_400D) },
00068             { "Canon EOS 450D", OR_MAKE_FILE_TYPEID(OR_TYPEID_VENDOR_CANON,
00069                                                   OR_TYPEID_CANON_450D) },
00070     { "Canon EOS 50D", OR_MAKE_FILE_TYPEID(OR_TYPEID_VENDOR_CANON,
00071                                            OR_TYPEID_CANON_50D) },
00072             { "Canon EOS 500D", OR_MAKE_FILE_TYPEID(OR_TYPEID_VENDOR_CANON,
00073                                                   OR_TYPEID_CANON_500D) },
00074             { "Canon EOS 550D", OR_MAKE_FILE_TYPEID(OR_TYPEID_VENDOR_CANON,
00075                                                     OR_TYPEID_CANON_550D) },
00076     { "Canon EOS 60D", OR_MAKE_FILE_TYPEID(OR_TYPEID_VENDOR_CANON,
00077                                            OR_TYPEID_CANON_60D) },
00078             { "Canon EOS 1000D", OR_MAKE_FILE_TYPEID(OR_TYPEID_VENDOR_CANON,
00079                                                     OR_TYPEID_CANON_1000D) },
00080             { "Canon EOS 5D", OR_MAKE_FILE_TYPEID(OR_TYPEID_VENDOR_CANON,
00081                                                   OR_TYPEID_CANON_5D) },
00082             { "Canon EOS 5D Mark II", OR_MAKE_FILE_TYPEID(OR_TYPEID_VENDOR_CANON,
00083                                                   OR_TYPEID_CANON_5DMKII) },
00084             { "Canon EOS 7D", OR_MAKE_FILE_TYPEID(OR_TYPEID_VENDOR_CANON,
00085                                                   OR_TYPEID_CANON_7D) },
00086             { "Canon PowerShot G9", OR_MAKE_FILE_TYPEID(OR_TYPEID_VENDOR_CANON, 
00087                                                         OR_TYPEID_CANON_G9) },
00088             { "Canon PowerShot G10", OR_MAKE_FILE_TYPEID(OR_TYPEID_VENDOR_CANON, 
00089                                                         OR_TYPEID_CANON_G11) },
00090             { "Canon PowerShot G11", OR_MAKE_FILE_TYPEID(OR_TYPEID_VENDOR_CANON, 
00091                                                         OR_TYPEID_CANON_G11) },
00092             { 0, 0 }
00093         };
00094 
00095         RawFile *Cr2File::factory(IO::Stream * s)
00096         {
00097             return new Cr2File(s);
00098         }
00099 
00100         Cr2File::Cr2File(IO::Stream * s)
00101             : IFDFile(s, OR_RAWFILE_TYPE_CR2)
00102         {
00103             _setIdMap(s_def);
00104         }
00105 
00106         Cr2File::~Cr2File()
00107         {
00108         }
00109 
00110 
00111         IFDDir::Ref  Cr2File::_locateCfaIfd()
00112         {
00113             return m_container->setDirectory(3);
00114         }
00115 
00116 
00117         IFDDir::Ref  Cr2File::_locateMainIfd()
00118         {
00119             return m_container->setDirectory(0);
00120         }
00121 
00122         ::or_error Cr2File::_getRawData(RawData & data, uint32_t options)
00123         {
00124             ::or_error ret = OR_ERROR_NONE;
00125             if(!m_cfaIfd) {
00126                 m_cfaIfd = _locateCfaIfd();
00127             }
00128             if(!m_cfaIfd) {
00129                 Trace(DEBUG1) << "cfa IFD not found\n";
00130                 return OR_ERROR_NOT_FOUND;
00131             }
00132 
00133             Trace(DEBUG1) << "_getRawData()\n";
00134             uint32_t offset = 0;
00135             uint32_t byte_length = 0;
00136             bool got_it;
00137             got_it = m_cfaIfd->getValue(IFD::EXIF_TAG_STRIP_OFFSETS, offset);
00138             if(!got_it) {
00139                 Trace(DEBUG1) << "offset not found\n";
00140                 return OR_ERROR_NOT_FOUND;
00141             }
00142             got_it = m_cfaIfd->getValue(IFD::EXIF_TAG_STRIP_BYTE_COUNTS, byte_length);
00143             if(!got_it) {
00144                 Trace(DEBUG1) << "byte len not found\n";
00145                 return OR_ERROR_NOT_FOUND;
00146             }
00147             // get the "slicing", tag 0xc640 (3 SHORT)
00148             std::vector<uint16_t> slices;
00149             IFDEntry::Ref e = m_cfaIfd->getEntry(IFD::EXIF_TAG_CR2_SLICE);
00150             if (e) {
00151                 e->getArray(slices);
00152                 Trace(DEBUG1) << "Found slice entry " << slices << "\n";
00153             }
00154 
00155             if(!m_exifIfd) {
00156                 m_exifIfd = _locateExifIfd();
00157             }
00158             if (m_exifIfd) {
00159                 uint16_t x, y;
00160                 x = 0;
00161                 y = 0;
00162                 got_it = m_exifIfd->getValue(IFD::EXIF_TAG_PIXEL_X_DIMENSION, x);
00163                 if(!got_it) {
00164                     Trace(DEBUG1) << "X not found\n";
00165                     return OR_ERROR_NOT_FOUND;
00166                 }
00167                 got_it = m_exifIfd->getValue(IFD::EXIF_TAG_PIXEL_Y_DIMENSION, y);
00168                 if(!got_it) {
00169                     Trace(DEBUG1) << "Y not found\n";
00170                     return OR_ERROR_NOT_FOUND;
00171                 }
00172                 
00173                 void *p = data.allocData(byte_length);
00174                 size_t real_size = m_container->fetchData(p, offset, 
00175                                                           byte_length);
00176                 if (real_size < byte_length) {
00177                     Trace(WARNING) << "Size mismatch for data: ignoring.\n";
00178                 }
00179                 data.setCfaPattern(OR_CFA_PATTERN_RGGB);
00180                 data.setDataType(OR_DATA_TYPE_COMPRESSED_CFA);
00181                 data.setDimensions(x, y);
00182                 Trace(DEBUG1) << "In size is " << data.x() 
00183                               << "x" << data.y() << "\n";
00184                 // decompress if we need
00185                 if((options & OR_OPTIONS_DONT_DECOMPRESS) == 0) {
00186                     boost::scoped_ptr<IO::Stream> s(new IO::MemStream(data.data(),
00187                                                                       data.size()));
00188                     s->open(); // TODO check success
00189                     boost::scoped_ptr<JFIFContainer> jfif(new JFIFContainer(s.get(), 0));
00190                     LJpegDecompressor decomp(s.get(), jfif.get());
00191                     // in fact on Canon CR2 files slices either do not exists
00192                     // or is 3.
00193                     if(slices.size() > 1) {
00194                         decomp.setSlices(slices); 
00195                     }
00196                     RawData *dData = decomp.decompress();
00197                     if (dData != NULL) {
00198                         Trace(DEBUG1) << "Out size is " << dData->x() 
00199                                                     << "x" << dData->y() << "\n";
00200                         // must re-set the cfaPattern
00201                         dData->setCfaPattern(data.cfaPattern());
00202                         data.swap(*dData);
00203                         delete dData;
00204                     }
00205                 }
00206             }
00207             else {
00208                 Trace(ERROR) << "unable to find ExifIFD\n";
00209                 ret = OR_ERROR_NOT_FOUND;
00210             }
00211             return ret;
00212         }
00213 
00214 
00215     }
00216 }