libopenraw
|
00001 /* 00002 * libopenraw - mrwfile.cpp 00003 * 00004 * Copyright (C) 2006,2008 Hubert Figuiere 00005 * Copyright (C) 2008 Bradley Broom 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 00023 #include <iostream> 00024 #include <boost/scoped_array.hpp> 00025 #include <libopenraw/libopenraw.h> 00026 #include <libopenraw++/thumbnail.h> 00027 #include <libopenraw++/rawdata.h> 00028 00029 #include "debug.h" 00030 #include "io/stream.h" 00031 #include "io/file.h" 00032 #include "mrwcontainer.h" 00033 #include "ifd.h" 00034 #include "mrwfile.h" 00035 #include "unpack.h" 00036 00037 using namespace Debug; 00038 00039 namespace OpenRaw { 00040 00041 00042 namespace Internals { 00043 00044 const struct IFDFile::camera_ids_t MRWFile::s_def[] = { 00045 { "21860002", OR_MAKE_FILE_TYPEID(OR_TYPEID_VENDOR_MINOLTA, 00046 OR_TYPEID_MINOLTA_MAXXUM_5D) }, 00047 { "21810002", OR_MAKE_FILE_TYPEID(OR_TYPEID_VENDOR_MINOLTA, 00048 OR_TYPEID_MINOLTA_MAXXUM_7D) }, 00049 { "27730001", OR_MAKE_FILE_TYPEID(OR_TYPEID_VENDOR_MINOLTA, 00050 OR_TYPEID_MINOLTA_DIMAGE5) }, 00051 { "27660001", OR_MAKE_FILE_TYPEID(OR_TYPEID_VENDOR_MINOLTA, 00052 OR_TYPEID_MINOLTA_DIMAGE7) }, 00053 { "27790001", OR_MAKE_FILE_TYPEID(OR_TYPEID_VENDOR_MINOLTA, 00054 OR_TYPEID_MINOLTA_DIMAGE7I) }, 00055 { "27780001", OR_MAKE_FILE_TYPEID(OR_TYPEID_VENDOR_MINOLTA, 00056 OR_TYPEID_MINOLTA_DIMAGE7HI) }, 00057 { "27820001", OR_MAKE_FILE_TYPEID(OR_TYPEID_VENDOR_MINOLTA, 00058 OR_TYPEID_MINOLTA_A1) }, 00059 { "27200001", OR_MAKE_FILE_TYPEID(OR_TYPEID_VENDOR_MINOLTA, 00060 OR_TYPEID_MINOLTA_A2) }, 00061 { "27470002", OR_MAKE_FILE_TYPEID(OR_TYPEID_VENDOR_MINOLTA, 00062 OR_TYPEID_MINOLTA_A200) }, 00063 { 0, 0 } 00064 }; 00065 00066 RawFile *MRWFile::factory(IO::Stream *_f) 00067 { 00068 return new MRWFile(_f); 00069 } 00070 00071 MRWFile::MRWFile(IO::Stream* _f) 00072 : IFDFile(_f, OR_RAWFILE_TYPE_MRW, false) 00073 { 00074 _setIdMap(s_def); 00075 m_container = new MRWContainer (m_io, 0); 00076 } 00077 00078 MRWFile::~MRWFile() 00079 { 00080 } 00081 00082 IFDDir::Ref MRWFile::_locateCfaIfd() 00083 { 00084 // in MRW the CFA IFD is the main IFD 00085 if(!m_mainIfd) { 00086 m_mainIfd = _locateMainIfd(); 00087 } 00088 return m_mainIfd; 00089 } 00090 00091 00092 IFDDir::Ref MRWFile::_locateMainIfd() 00093 { 00094 return m_container->setDirectory(0); 00095 } 00096 00097 00098 void MRWFile::_identifyId() 00099 { 00100 MRWContainer *mc = (MRWContainer *)m_container; 00101 if(!m_mainIfd) { 00102 m_mainIfd = _locateMainIfd(); 00103 } 00104 00105 if(mc->prd) { 00106 std::string version = mc->prd->string_val(MRW::PRD_VERSION); 00107 _setTypeId(_typeIdFromModel(version)); 00108 } 00109 } 00110 00111 00112 /* This code only knows about Dimage 5/7, in which the thumbnail position is special. */ 00113 ::or_error MRWFile::_enumThumbnailSizes(std::vector<uint32_t> &list) 00114 { 00115 ::or_error err = OR_ERROR_NOT_FOUND; 00116 list.push_back (640); 00117 err = OR_ERROR_NONE; 00118 return err; 00119 } 00120 00121 /* This code only knows about Dimage 5/7, in which the thumbnail position is special. */ 00122 ::or_error MRWFile::_getThumbnail(uint32_t /*size*/, Thumbnail & thumbnail) 00123 { 00124 IFDDir::Ref dir; 00125 IFDEntry::Ref maker_ent; /* Make note directory entry. */ 00126 IFDEntry::Ref thumb_ent; /* Thumbnail data directory entry. */ 00127 ::or_error ret = OR_ERROR_NOT_FOUND; 00128 MRWContainer *mc = (MRWContainer *)m_container; 00129 00130 dir = _locateExifIfd(); 00131 if (!dir) { 00132 Trace(WARNING) << "EXIF dir not found\n"; 00133 return ret; 00134 } 00135 00136 maker_ent = dir->getEntry(IFD::EXIF_TAG_MAKER_NOTE); 00137 if (!maker_ent) { 00138 Trace(WARNING) << "maker note offset entry not found\n"; 00139 return ret; 00140 } 00141 uint32_t off = 0; 00142 off = maker_ent->offset(); 00143 00144 IFDDir::Ref ref(new IFDDir(mc->ttw->offset() + 00145 MRW::DataBlockHeaderLength + off, 00146 *m_container)); 00147 ref->load(); 00148 00149 uint32_t tnail_offset = 0; 00150 uint32_t tnail_len = 0; 00151 thumb_ent = ref->getEntry(MRW::MRWTAG_THUMBNAIL); 00152 if (thumb_ent) { 00153 tnail_offset = thumb_ent->offset(); 00154 tnail_len = thumb_ent->count(); 00155 } 00156 else if(ref->getValue(MRW::MRWTAG_THUMBNAIL_OFFSET, tnail_offset)) { 00157 if(!ref->getValue(MRW::MRWTAG_THUMBNAIL_LENGTH, tnail_len)) { 00158 Trace(WARNING) << "thumbnail lenght entry not found\n"; 00159 return ret; 00160 } 00161 } 00162 else 00163 { 00164 Trace(WARNING) << "thumbnail offset entry not found\n"; 00165 return ret; 00166 } 00167 00168 Trace(DEBUG1) << "thumbnail offset found, " 00169 << " offset == " << tnail_offset << " count == " 00170 << tnail_len << "\n"; 00171 void *p = thumbnail.allocData (tnail_len); 00172 size_t fetched = m_container->fetchData(p, mc->ttw->offset() 00173 + MRW::DataBlockHeaderLength 00174 + tnail_offset, 00175 tnail_len); 00176 if (fetched != tnail_len) { 00177 Trace(WARNING) << "Unable to fetch all thumbnail data: " 00178 << fetched << " not " << tnail_len 00179 << " bytes\n"; 00180 } 00181 /* Need to patch first byte. */ 00182 ((unsigned char *)p)[0] = 0xFF; 00183 00184 thumbnail.setDataType (OR_DATA_TYPE_JPEG); 00185 thumbnail.setDimensions (640, 480); 00186 return OR_ERROR_NONE; 00187 } 00188 00189 00190 ::or_error MRWFile::_getRawData(RawData & data, uint32_t options) 00191 { 00192 MRWContainer *mc = (MRWContainer *)m_container; 00193 00194 if(!mc->prd) { 00195 return OR_ERROR_NOT_FOUND; 00196 } 00197 /* Obtain sensor dimensions from PRD block. */ 00198 uint16_t y = mc->prd->uint16_val (MRW::PRD_SENSOR_LENGTH); 00199 uint16_t x = mc->prd->uint16_val (MRW::PRD_SENSOR_WIDTH); 00200 uint8_t bpc = mc->prd->uint8_val (MRW::PRD_PIXEL_SIZE); 00201 00202 bool is_compressed = (mc->prd->uint8_val(MRW::PRD_STORAGE_TYPE) == 0x59); 00203 /* Allocate space for and retrieve pixel data. 00204 * Currently only for cameras that don't compress pixel data. 00205 */ 00206 /* Set pixel array parameters. */ 00207 uint32_t finaldatalen = 2 * x * y; 00208 uint32_t datalen = 00209 (is_compressed ? x * y + ((x * y) >> 1) : finaldatalen); 00210 00211 if(options & OR_OPTIONS_DONT_DECOMPRESS) { 00212 finaldatalen = datalen; 00213 } 00214 if(is_compressed && (options & OR_OPTIONS_DONT_DECOMPRESS)) { 00215 data.setDataType (OR_DATA_TYPE_COMPRESSED_CFA); 00216 } 00217 else { 00218 data.setDataType (OR_DATA_TYPE_CFA); 00219 } 00220 data.setBpc(bpc); 00221 // this seems to be the hardcoded value. 00222 data.setMax(0xf7d); 00223 Trace(DEBUG1) << "datalen = " << datalen << 00224 " final datalen = " << finaldatalen << "\n"; 00225 void *p = data.allocData(finaldatalen); 00226 size_t fetched = 0; 00227 off_t offset = mc->pixelDataOffset(); 00228 if(!is_compressed || (options & OR_OPTIONS_DONT_DECOMPRESS)) { 00229 fetched = m_container->fetchData (p, offset, datalen); 00230 } 00231 else { 00232 Unpack unpack(x, IFD::COMPRESS_NONE); 00233 size_t blocksize = unpack.block_size(); 00234 boost::scoped_array<uint8_t> block(new uint8_t[blocksize]); 00235 uint8_t * outdata = (uint8_t*)data.data(); 00236 size_t got; 00237 do { 00238 Trace(DEBUG2) << "fatchData @offset " << offset << "\n"; 00239 got = m_container->fetchData (block.get(), 00240 offset, blocksize); 00241 fetched += got; 00242 offset += got; 00243 Trace(DEBUG2) << "got " << got << "\n"; 00244 if(got) { 00245 size_t out = unpack.unpack_be12to16(outdata, 00246 block.get(), got); 00247 outdata += out; 00248 Trace(DEBUG2) << "unpacked " << out 00249 << " bytes from " << got << "\n"; 00250 } 00251 } while((got != 0) && (fetched < datalen)); 00252 } 00253 if (fetched < datalen) { 00254 Trace(WARNING) << "Fetched only " << fetched << 00255 " of " << datalen << ": continuing anyway.\n"; 00256 } 00257 uint16_t bpat = mc->prd->uint16_val (MRW::PRD_BAYER_PATTERN); 00258 or_cfa_pattern cfa_pattern = OR_CFA_PATTERN_NONE; 00259 switch(bpat) 00260 { 00261 case 0x0001: 00262 cfa_pattern = OR_CFA_PATTERN_RGGB; 00263 break; 00264 case 0x0004: 00265 cfa_pattern = OR_CFA_PATTERN_GBRG; 00266 break; 00267 default: 00268 break; 00269 } 00270 data.setCfaPattern(cfa_pattern); 00271 data.setDimensions (x, y); 00272 00273 return OR_ERROR_NONE; 00274 } 00275 00276 } 00277 }