00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <algorithm>
00023 #include <numeric>
00024 #include <boost/scoped_ptr.hpp>
00025 #include <boost/scoped_array.hpp>
00026
00027 #include <libopenraw++/thumbnail.h>
00028 #include <libopenraw++/rawdata.h>
00029
00030 #include "debug.h"
00031 #include "io/stream.h"
00032 #include "io/streamclone.h"
00033 #include "io/file.h"
00034 #include "ifd.h"
00035 #include "ifdfile.h"
00036 #include "ifdfilecontainer.h"
00037 #include "jfifcontainer.h"
00038 #include "neffile.h"
00039 #include "metavalue.h"
00040 #include "unpack.h"
00041
00042 using namespace Debug;
00043 using boost::scoped_ptr;
00044
00045
00046 namespace OpenRaw {
00047 namespace Internals {
00048
00049
00050 IFDFile::IFDFile(IO::Stream *s, Type _type,
00051 bool instantiateContainer)
00052 : RawFile(s, _type),
00053 m_thumbLocations(),
00054 m_io(s),
00055 m_container(NULL)
00056 {
00057 if(instantiateContainer) {
00058 m_container = new IFDFileContainer(m_io, 0);
00059 }
00060 }
00061
00062 IFDFile::~IFDFile()
00063 {
00064 delete m_container;
00065 delete m_io;
00066 }
00067
00068
00069
00070 IFDDir::Ref IFDFile::_locateExifIfd()
00071 {
00072 m_mainIfd = _locateMainIfd();
00073 if (!m_mainIfd) {
00074 Trace(ERROR) << "IFDFile::_locateExifIfd() "
00075 "main IFD not found\n";
00076 return IFDDir::Ref();
00077 }
00078 return m_mainIfd->getExifIFD();
00079 }
00080
00081
00082 void IFDFile::_identifyId()
00083 {
00084 if(!m_mainIfd) {
00085 m_mainIfd = _locateMainIfd();
00086 }
00087 std::string model;
00088 if(m_mainIfd->getValue(IFD::EXIF_TAG_MODEL, model)) {
00089 _setTypeId(_typeIdFromModel(model));
00090 }
00091 }
00092
00093
00094
00095 ::or_error IFDFile::_enumThumbnailSizes(std::vector<uint32_t> &list)
00096 {
00097 ::or_error err = OR_ERROR_NONE;
00098
00099 Trace(DEBUG1) << "_enumThumbnailSizes()\n";
00100 std::vector<IFDDir::Ref> & dirs = m_container->directories();
00101 std::vector<IFDDir::Ref>::iterator iter;
00102
00103 Trace(DEBUG1) << "num of dirs " << dirs.size() << "\n";
00104 for(iter = dirs.begin(); iter != dirs.end(); ++iter)
00105 {
00106 IFDDir::Ref & dir = *iter;
00107 dir->load();
00108 or_error ret = _locateThumbnail(dir, list);
00109 if (ret == OR_ERROR_NONE)
00110 {
00111 Trace(DEBUG1) << "Found " << list.back() << " pixels\n";
00112 }
00113 std::vector<IFDDir::Ref> subdirs;
00114 if(dir->getSubIFDs(subdirs)) {
00115 Trace(DEBUG1) << "Iterating subdirs\n";
00116 std::vector<IFDDir::Ref>::iterator iter2;
00117 for(iter2 = subdirs.begin(); iter2 != subdirs.end();
00118 ++iter2)
00119 {
00120 IFDDir::Ref & dir2 = *iter2;
00121 dir2->load();
00122 ret = _locateThumbnail(dir2, list);
00123 if (ret == OR_ERROR_NONE)
00124 {
00125 Trace(DEBUG1) << "Found " << list.back() << " pixels\n";
00126 }
00127 }
00128 }
00129 }
00130 if (list.size() <= 0) {
00131 err = OR_ERROR_NOT_FOUND;
00132 }
00133 return err;
00134 }
00135
00136
00137 ::or_error IFDFile::_locateThumbnail(const IFDDir::Ref & dir,
00138 std::vector<uint32_t> &list)
00139 {
00140 ::or_error ret = OR_ERROR_NOT_FOUND;
00141 bool got_it;
00142 uint32_t x = 0;
00143 uint32_t y = 0;
00144 ::or_data_type _type = OR_DATA_TYPE_NONE;
00145 uint32_t subtype = 0;
00146
00147 Trace(DEBUG1) << "_locateThumbnail\n";
00148
00149 got_it = dir->getValue(IFD::EXIF_TAG_NEW_SUBFILE_TYPE, subtype);
00150 Trace(DEBUG1) << "subtype " << subtype << "\n";
00151 if(!got_it) {
00152 if(!m_cfaIfd) {
00153 m_cfaIfd = _locateCfaIfd();
00154 }
00155 if(m_cfaIfd == dir) {
00156 return OR_ERROR_NOT_FOUND;
00157 }
00158 else {
00159 subtype = 1;
00160 }
00161 }
00162 if (subtype == 1) {
00163
00164 uint16_t photom_int = 0;
00165 got_it = dir->getValue(IFD::EXIF_TAG_PHOTOMETRIC_INTERPRETATION,
00166 photom_int);
00167
00168 if (got_it) {
00169 Trace(DEBUG1) << "photometric int " << photom_int << "\n";
00170 }
00171
00172 if (!got_it || (photom_int == 2)) {
00173
00174 got_it = dir->getIntegerValue(IFD::EXIF_TAG_IMAGE_WIDTH, x);
00175 got_it = dir->getIntegerValue(IFD::EXIF_TAG_IMAGE_LENGTH, y);
00176
00177 uint16_t compression = 0;
00178 got_it = dir->getValue(IFD::EXIF_TAG_COMPRESSION, compression);
00179
00180 uint32_t offset = 0;
00181 got_it = dir->getValue(IFD::EXIF_TAG_STRIP_OFFSETS, offset);
00182 if (!got_it || (compression == 6) || (compression == 7)) {
00183 if(!got_it) {
00184 got_it = dir->getValue(IFD::EXIF_TAG_JPEG_INTERCHANGE_FORMAT,
00185 offset);
00186 }
00187 if (got_it) {
00188
00189
00190 uint32_t byte_count = 0;
00191 if(x && y && dir->getValue(IFD::EXIF_TAG_STRIP_BYTE_COUNTS, byte_count)) {
00192 if(byte_count >= (x * y * 3)) {
00193 _type = OR_DATA_TYPE_PIXMAP_8RGB;
00194 }
00195 else {
00196 _type = OR_DATA_TYPE_JPEG;
00197 }
00198 }
00199 else {
00200 _type = OR_DATA_TYPE_JPEG;
00201 Trace(DEBUG1) << "looking for JPEG at " << offset << "\n";
00202 if (x == 0 || y == 0) {
00203 scoped_ptr<IO::StreamClone> s(new IO::StreamClone(m_io, offset));
00204 scoped_ptr<JFIFContainer> jfif(new JFIFContainer(s.get(), 0));
00205 if (jfif->getDimensions(x,y)) {
00206 Trace(DEBUG1) << "JPEG dimensions x=" << x
00207 << " y=" << y << "\n";
00208 }
00209 else {
00210 _type = OR_DATA_TYPE_NONE;
00211 Trace(WARNING) << "Couldn't get JPEG "
00212 "dimensions.\n";
00213 }
00214 }
00215 else {
00216 Trace(DEBUG1) << "JPEG (supposed) dimensions x=" << x
00217 << " y=" << y << "\n";
00218 }
00219 }
00220
00221 }
00222 }
00223 else {
00224 Trace(DEBUG1) << "found strip offsets\n";
00225 if (x != 0 && y != 0) {
00226 _type = OR_DATA_TYPE_PIXMAP_8RGB;
00227 }
00228 }
00229 if(_type != OR_DATA_TYPE_NONE) {
00230 uint32_t dim = std::max(x, y);
00231 m_thumbLocations[dim] = IFDThumbDesc(x, y, _type, dir);
00232 list.push_back(dim);
00233 ret = OR_ERROR_NONE;
00234 }
00235 }
00236 else if (photom_int == 6) {
00237 Trace(WARNING) << "Unsupported YCbCr photometric "
00238 "interpretation.\n";
00239 ret = OR_ERROR_INVALID_FORMAT;
00240 }
00241 }
00242
00243 return ret;
00244 }
00245
00246
00247 ::or_error IFDFile::_getThumbnail(uint32_t size, Thumbnail & thumbnail)
00248 {
00249 ::or_error ret = OR_ERROR_NOT_FOUND;
00250 ThumbLocations::iterator iter = m_thumbLocations.find(size);
00251 if(iter != m_thumbLocations.end())
00252 {
00253 bool got_it;
00254
00255 IFDThumbDesc & desc = iter->second;
00256 thumbnail.setDataType(desc.type);
00257 uint32_t byte_length= 0;
00258 uint32_t offset = 0;
00259 uint32_t x = desc.x;
00260 uint32_t y = desc.y;
00261
00262 switch(desc.type)
00263 {
00264 case OR_DATA_TYPE_JPEG:
00265 got_it = desc.ifddir
00266 ->getValue(IFD::EXIF_TAG_JPEG_INTERCHANGE_FORMAT_LENGTH,
00267 byte_length);
00268 if(got_it) {
00269 got_it = desc.ifddir
00270 ->getValue(IFD::EXIF_TAG_JPEG_INTERCHANGE_FORMAT,
00271 offset);
00272 }
00273 else {
00274
00275 got_it = desc.ifddir
00276 ->getValue(IFD::EXIF_TAG_STRIP_OFFSETS, offset);
00277 got_it = desc.ifddir
00278 ->getValue(IFD::EXIF_TAG_STRIP_BYTE_COUNTS, byte_length);
00279 }
00280 break;
00281 case OR_DATA_TYPE_PIXMAP_8RGB:
00282 got_it = desc.ifddir
00283 ->getValue(IFD::EXIF_TAG_STRIP_OFFSETS, offset);
00284 got_it = desc.ifddir
00285 ->getValue(IFD::EXIF_TAG_STRIP_BYTE_COUNTS, byte_length);
00286
00287 got_it = desc.ifddir
00288 ->getIntegerValue(IFD::EXIF_TAG_IMAGE_WIDTH, x);
00289 got_it = desc.ifddir
00290 ->getIntegerValue(IFD::EXIF_TAG_IMAGE_LENGTH, y);
00291 break;
00292 default:
00293 break;
00294 }
00295 if (byte_length != 0) {
00296 void *p = thumbnail.allocData(byte_length);
00297 size_t real_size = m_container->fetchData(p, offset,
00298 byte_length);
00299 if (real_size < byte_length) {
00300 Trace(WARNING) << "Size mismatch for data: ignoring.\n";
00301 }
00302
00303 thumbnail.setDimensions(x, y);
00304 ret = OR_ERROR_NONE;
00305 }
00306 }
00307
00308 return ret;
00309 }
00310
00311
00312 MetaValue *IFDFile::_getMetaValue(int32_t meta_index)
00313 {
00314 MetaValue * val = NULL;
00315 IFDDir::Ref ifd;
00316 if(META_INDEX_MASKOUT(meta_index) == META_NS_TIFF) {
00317 if(!m_mainIfd) {
00318 m_mainIfd = _locateMainIfd();
00319 }
00320 ifd = m_mainIfd;
00321 }
00322 else if(META_INDEX_MASKOUT(meta_index) == META_NS_EXIF) {
00323 if(!m_exifIfd) {
00324 m_exifIfd = _locateExifIfd();
00325 }
00326 ifd = m_exifIfd;
00327 }
00328 else {
00329 Trace(ERROR) << "Unknown Meta Namespace\n";
00330 }
00331 if(ifd) {
00332 Trace(DEBUG1) << "Meta value for "
00333 << META_NS_MASKOUT(meta_index) << "\n";
00334
00335 IFDEntry::Ref e = ifd->getEntry(META_NS_MASKOUT(meta_index));
00336 if(e) {
00337 val = new MetaValue(e);
00338 }
00339 }
00340 return val;
00341 }
00342
00343
00344 namespace {
00345
00346 RawData::CfaPattern
00347 _convertArrayToCfaPattern(const std::vector<uint8_t> &cfaPattern)
00348 {
00349 RawData::CfaPattern cfa_pattern = OR_CFA_PATTERN_NON_RGB22;
00350 if(cfaPattern.size() != 4) {
00351 Trace(WARNING) << "Unsupported bayer pattern\n";
00352 }
00353 else {
00354 Trace(DEBUG2) << "patter is = " << cfaPattern[0] << ", "
00355 << cfaPattern[1] << ", " << cfaPattern[2]
00356 << ", " << cfaPattern[3] << "\n";
00357 switch(cfaPattern[0]) {
00358 case IFD::CFA_RED:
00359 switch(cfaPattern[1]) {
00360 case IFD::CFA_GREEN:
00361 if((cfaPattern[2] == IFD::CFA_GREEN)
00362 && (cfaPattern[3] == IFD::CFA_BLUE))
00363 {
00364 cfa_pattern = OR_CFA_PATTERN_RGGB;
00365 }
00366 break;
00367 }
00368 break;
00369 case IFD::CFA_GREEN:
00370 switch(cfaPattern[1]) {
00371 case IFD::CFA_RED:
00372 if((cfaPattern[2] == 2)
00373 && (cfaPattern[3] == IFD::CFA_GREEN))
00374 {
00375 cfa_pattern = OR_CFA_PATTERN_GRBG;
00376 }
00377 break;
00378 case 2:
00379 if((cfaPattern[2] == IFD::CFA_RED)
00380 && (cfaPattern[3] == IFD::CFA_GREEN))
00381 {
00382 cfa_pattern = OR_CFA_PATTERN_GBRG;
00383 }
00384 break;
00385 }
00386 break;
00387 case IFD::CFA_BLUE:
00388 switch(cfaPattern[1]) {
00389 case IFD::CFA_GREEN:
00390 if((cfaPattern[2] == IFD::CFA_GREEN)
00391 && (cfaPattern[3] == IFD::CFA_RED))
00392 {
00393 cfa_pattern = OR_CFA_PATTERN_BGGR;
00394 }
00395 break;
00396 }
00397 break;
00398 }
00399
00400 }
00401 return cfa_pattern;
00402 }
00403
00404 RawData::CfaPattern _convertNewCfaPattern(const IFDEntry::Ref & e)
00405 {
00406 RawData::CfaPattern cfa_pattern = OR_CFA_PATTERN_NONE;
00407 if(!e || (e->count() < 4)) {
00408 return cfa_pattern;
00409 }
00410
00411 uint16_t hdim = IFDTypeTrait<uint16_t>::get(*e, 0, true);
00412 uint16_t vdim = IFDTypeTrait<uint16_t>::get(*e, 1, true);
00413 if(hdim != 2 && vdim != 2) {
00414 cfa_pattern = OR_CFA_PATTERN_NON_RGB22;
00415 }
00416 else {
00417 std::vector<uint8_t> cfaPattern;
00418 cfaPattern.push_back(IFDTypeTrait<uint8_t>::get(*e, 4, true));
00419 cfaPattern.push_back(IFDTypeTrait<uint8_t>::get(*e, 5, true));
00420 cfaPattern.push_back(IFDTypeTrait<uint8_t>::get(*e, 6, true));
00421 cfaPattern.push_back(IFDTypeTrait<uint8_t>::get(*e, 7, true));
00422 cfa_pattern = _convertArrayToCfaPattern(cfaPattern);
00423 }
00424 return cfa_pattern;
00425 }
00426
00427
00429 RawData::CfaPattern _convertCfaPattern(const IFDEntry::Ref & e)
00430 {
00431 std::vector<uint8_t> cfaPattern;
00432 RawData::CfaPattern cfa_pattern = OR_CFA_PATTERN_NONE;
00433
00434 e->getArray(cfaPattern);
00435 if(!cfaPattern.empty()) {
00436 cfa_pattern = _convertArrayToCfaPattern(cfaPattern);
00437 }
00438 return cfa_pattern;
00439 }
00440
00446 static RawData::CfaPattern _getCfaPattern(const IFDDir::Ref & dir)
00447 {
00448 Trace(DEBUG1) << __FUNCTION__ << "\n";
00449 RawData::CfaPattern cfa_pattern = OR_CFA_PATTERN_NONE;
00450 try {
00451 IFDEntry::Ref e = dir->getEntry(IFD::EXIF_TAG_CFA_PATTERN);
00452 if(e) {
00453 cfa_pattern = _convertCfaPattern(e);
00454 }
00455 else {
00456 e = dir->getEntry(IFD::EXIF_TAG_NEW_CFA_PATTERN);
00457 if(e) {
00458 cfa_pattern = _convertNewCfaPattern(e);
00459 }
00460 }
00461 }
00462 catch(...)
00463 {
00464 Trace(ERROR) << "Exception in _getCfaPattern().\n";
00465 }
00466 return cfa_pattern;
00467 }
00468
00469 }
00470
00471 ::or_error IFDFile::_getRawDataFromDir(RawData & data, IFDDir::Ref & dir)
00472 {
00473 ::or_error ret = OR_ERROR_NONE;
00474
00475 uint16_t bpc = 0;
00476 uint32_t offset = 0;
00477 uint32_t byte_length = 0;
00478 bool got_it;
00479 uint32_t x, y;
00480 x = 0;
00481 y = 0;
00482
00483 got_it = dir->getValue(IFD::EXIF_TAG_BITS_PER_SAMPLE, bpc);
00484 if(!got_it) {
00485 Trace(ERROR) << "unable to guess Bits per sample\n";
00486 }
00487
00488 got_it = dir->getValue(IFD::EXIF_TAG_STRIP_OFFSETS, offset);
00489 if(got_it) {
00490 IFDEntry::Ref e = dir->getEntry(IFD::EXIF_TAG_STRIP_BYTE_COUNTS);
00491 if(e) {
00492 std::vector<uint32_t> counts;
00493 e->getArray(counts);
00494 Trace(DEBUG1) << "counting tiles\n";
00495 byte_length = std::accumulate(counts.begin(), counts.end(), 0);
00496 }
00497 else {
00498 Trace(DEBUG1) << "byte len not found\n";
00499 return OR_ERROR_NOT_FOUND;
00500 }
00501 }
00502 else {
00503
00504
00505 IFDEntry::Ref e = dir->getEntry(IFD::TIFF_TAG_TILE_OFFSETS);
00506 if(e) {
00507 std::vector<uint32_t> offsets;
00508 e->getArray(offsets);
00509 if(offsets.size() > 1) {
00510 offset = offsets[0];
00511 }
00512 else {
00513 Trace(DEBUG1) << "tile offsets empty\n";
00514 return OR_ERROR_NOT_FOUND;
00515 }
00516 }
00517 else {
00518 Trace(DEBUG1) << "tile offsets not found\n";
00519 return OR_ERROR_NOT_FOUND;
00520 }
00521 e = dir->getEntry(IFD::TIFF_TAG_TILE_BYTECOUNTS);
00522 if(e) {
00523 std::vector<uint32_t> counts;
00524 e->getArray(counts);
00525 Trace(DEBUG1) << "counting tiles\n";
00526 byte_length = std::accumulate(counts.begin(), counts.end(), 0);
00527 }
00528 else {
00529 Trace(DEBUG1) << "tile byte counts not found\n";
00530 return OR_ERROR_NOT_FOUND;
00531 }
00532 }
00533 got_it = dir->getIntegerValue(IFD::EXIF_TAG_IMAGE_WIDTH, x);
00534 if(!got_it) {
00535 Trace(DEBUG1) << "X not found\n";
00536 return OR_ERROR_NOT_FOUND;
00537 }
00538 got_it = dir->getIntegerValue(IFD::EXIF_TAG_IMAGE_LENGTH, y);
00539 if(!got_it) {
00540 Trace(DEBUG1) << "Y not found\n";
00541 return OR_ERROR_NOT_FOUND;
00542 }
00543
00544 uint32_t compression = 0;
00545 got_it = dir->getIntegerValue(IFD::EXIF_TAG_COMPRESSION, compression);
00546 if(!got_it)
00547 {
00548 Trace(DEBUG1) << "Compression type not found\n";
00549 }
00550 BitmapData::DataType data_type = OR_DATA_TYPE_NONE;
00551
00552 switch(compression)
00553 {
00554 case IFD::COMPRESS_NONE:
00555 data_type = OR_DATA_TYPE_CFA;
00556 break;
00557 case IFD::COMPRESS_NIKON_PACK:
00558 data_type = OR_DATA_TYPE_CFA;
00559 break;
00560 case IFD::COMPRESS_NIKON_QUANTIZED:
00561
00562
00563 if( !NEFFile::isCompressed(*m_container, offset) ) {
00564 compression = IFD::COMPRESS_NIKON_PACK;
00565 data_type = OR_DATA_TYPE_CFA;
00566
00567
00568
00569
00570 x += 6;
00571 break;
00572 }
00573 default:
00574 data_type = OR_DATA_TYPE_COMPRESSED_CFA;
00575 break;
00576 }
00577
00578 Trace(DEBUG1) << "RAW Compression is " << compression << "\n";
00579
00580 RawData::CfaPattern cfa_pattern = _getCfaPattern(dir);
00581 if(cfa_pattern == OR_CFA_PATTERN_NONE) {
00582
00583 if(!m_exifIfd) {
00584 m_exifIfd = _locateExifIfd();
00585 }
00586 cfa_pattern = _getCfaPattern(m_exifIfd);
00587 }
00588
00589
00590 if((bpc == 12 || bpc == 14) && (compression == 1)
00591 && (byte_length == (x * y * 2)))
00592 {
00593 Trace(DEBUG1) << "setting bpc from " << bpc
00594 << " to 16\n";
00595 bpc = 16;
00596 }
00597 if((bpc == 16) || (data_type == OR_DATA_TYPE_COMPRESSED_CFA)) {
00598 void *p = data.allocData(byte_length);
00599 size_t real_size = m_container->fetchData(p, offset,
00600 byte_length);
00601 if (real_size < byte_length) {
00602 Trace(WARNING) << "Size mismatch for data: ignoring.\n";
00603 }
00604 }
00605 else if((bpc == 12) || (bpc == 8)) {
00606 size_t fetched = 0;
00607 Unpack unpack(x, compression);
00608 const size_t blocksize = (bpc == 8 ? x : unpack.block_size());
00609 Trace(DEBUG1) << "Block size = " << blocksize << "\n";
00610 Trace(DEBUG1) << "dimensions (x, y) " << x << ", "
00611 << y << "\n";
00612 boost::scoped_array<uint8_t> block(new uint8_t[blocksize]);
00613 uint8_t * outdata = (uint8_t*)data.allocData(x * y * 2);
00614 size_t got;
00615 Trace(DEBUG1) << "offset of RAW data = " << offset << "\n";
00616 do {
00617 got = m_container->fetchData (block.get(),
00618 offset, blocksize);
00619 fetched += got;
00620 offset += got;
00621 if(got) {
00622 if(bpc == 12) {
00623 size_t out = unpack.unpack_be12to16(outdata,
00624 block.get(),
00625 got);
00626 outdata += out;
00627 }
00628 else {
00629
00630 std::copy(block.get(), block.get()+got,
00631 (uint16_t*)outdata);
00632 outdata += (got << 1);
00633 }
00634 }
00635 } while((got != 0) && (fetched < byte_length));
00636 }
00637 else {
00638 Trace(ERROR) << "Unsupported bpc " << bpc << "\n";
00639 return OR_ERROR_INVALID_FORMAT;
00640 }
00641 data.setCfaPattern(cfa_pattern);
00642 data.setDataType(data_type);
00643 data.setCompression(data_type == OR_DATA_TYPE_COMPRESSED_CFA
00644 ? compression : 1);
00645 if((data_type == OR_DATA_TYPE_CFA) && (data.max() == 0)) {
00646 data.setMax((1 << bpc) - 1);
00647 }
00648 data.setDimensions(x, y);
00649
00650 return ret;
00651 }
00652
00653 }
00654 }
00655
00656
00657
00658
00659
00660
00661
00662
00663
00664