31 #include <libopenraw/consts.h> 32 #include <libopenraw/debug.h> 33 #include <libopenraw/metadata.h> 35 #include "bitmapdata.hpp" 36 #include "rawfile.hpp" 37 #include "rawdata.hpp" 39 #include "io/stream.hpp" 40 #include "io/streamclone.hpp" 42 #include "ifdentry.hpp" 43 #include "ifdfile.hpp" 44 #include "ifdfilecontainer.hpp" 45 #include "jfifcontainer.hpp" 46 #include "rawfile_private.hpp" 47 #include "neffile.hpp" 50 using namespace Debug;
59 IfdFile::IfdFile(
const IO::Stream::Ptr &s, Type _type,
60 bool instantiateContainer)
65 if(instantiateContainer) {
66 m_container =
new IfdFileContainer(m_io, 0);
77 IfdDir::Ref IfdFile::_locateExifIfd()
79 const IfdDir::Ref & _mainIfd = mainIfd();
81 Trace(ERROR) <<
"IfdFile::_locateExifIfd() " 82 "main IFD not found\n";
85 return _mainIfd->getExifIFD();
88 MakerNoteDir::Ref IfdFile::_locateMakerNoteIfd()
90 const IfdDir::Ref & _exifIfd = exifIfd();
93 return std::dynamic_pointer_cast<MakerNoteDir>(_exifIfd->getMakerNoteIfd());
95 return MakerNoteDir::Ref();
98 void IfdFile::_identifyId()
100 const IfdDir::Ref & _mainIfd = mainIfd();
102 Trace(ERROR) <<
"Main IFD not found to identify the file.\n";
105 std::string make, model;
106 if(_mainIfd->getValue(IFD::EXIF_TAG_MAKE, make) &&
107 _mainIfd->getValue(IFD::EXIF_TAG_MODEL, model)) {
108 _setTypeId(_typeIdFromModel(make, model));
116 ::or_error err = OR_ERROR_NONE;
118 Trace(DEBUG1) <<
"_enumThumbnailSizes()\n";
119 std::vector<IfdDir::Ref> & dirs = m_container->directories();
121 Trace(DEBUG1) <<
"num of dirs " << dirs.size() <<
"\n";
125 or_error ret = _locateThumbnail(dir, list);
126 if (ret == OR_ERROR_NONE)
128 Trace(DEBUG1) <<
"Found " << list.back() <<
" pixels\n";
130 std::vector<IfdDir::Ref> subdirs;
131 if(dir->getSubIFDs(subdirs)) {
132 Trace(DEBUG1) <<
"Iterating subdirs\n";
133 for(
auto dir2 : subdirs)
136 ret = _locateThumbnail(dir2, list);
137 if (ret == OR_ERROR_NONE)
139 Trace(DEBUG1) <<
"Found " << list.back() <<
" pixels\n";
144 if (list.size() <= 0) {
145 err = OR_ERROR_NOT_FOUND;
152 std::vector<uint32_t> &list)
154 ::or_error ret = OR_ERROR_NOT_FOUND;
158 ::or_data_type _type = OR_DATA_TYPE_NONE;
159 uint32_t subtype = 0;
161 Trace(DEBUG1) <<
"_locateThumbnail\n";
163 got_it = dir->getValue(IFD::EXIF_TAG_NEW_SUBFILE_TYPE, subtype);
164 Trace(DEBUG1) <<
"subtype " << subtype <<
"\n";
167 m_cfaIfd = _locateCfaIfd();
169 if(m_cfaIfd == dir) {
170 return OR_ERROR_NOT_FOUND;
178 uint16_t photom_int = 0;
179 got_it = dir->getValue(IFD::EXIF_TAG_PHOTOMETRIC_INTERPRETATION,
183 Trace(DEBUG1) <<
"photometric int " << photom_int <<
"\n";
187 photom_int = IFD::EV_PI_RGB;
188 Trace(DEBUG1) <<
"assume photometric int is RGB\n";
191 got_it = dir->getIntegerValue(IFD::EXIF_TAG_IMAGE_WIDTH, x);
192 got_it = dir->getIntegerValue(IFD::EXIF_TAG_IMAGE_LENGTH, y);
194 uint16_t compression = 0;
195 got_it = dir->getValue(IFD::EXIF_TAG_COMPRESSION, compression);
198 uint32_t byte_count = 0;
199 got_it = dir->getValue(IFD::EXIF_TAG_STRIP_BYTE_COUNTS, byte_count);
200 got_it = dir->getValue(IFD::EXIF_TAG_STRIP_OFFSETS, offset);
201 if (!got_it || (compression == 6) || (compression == 7)) {
203 got_it = dir->getValue(IFD::EXIF_TAG_JPEG_INTERCHANGE_FORMAT_LENGTH,
205 got_it = dir->getValue(IFD::EXIF_TAG_JPEG_INTERCHANGE_FORMAT,
212 if(byte_count >= (x * y * 3)) {
214 _type = OR_DATA_TYPE_NONE;
216 Trace(DEBUG1) <<
"8RGB as JPEG. Will ignore.\n";
217 ret = OR_ERROR_INVALID_FORMAT;
220 _type = OR_DATA_TYPE_JPEG;
224 _type = OR_DATA_TYPE_JPEG;
225 Trace(DEBUG1) <<
"looking for JPEG at " << offset <<
"\n";
226 if (x == 0 || y == 0) {
227 IO::Stream::Ptr s(std::make_shared<IO::StreamClone>(
229 std::unique_ptr<JfifContainer> jfif(
new JfifContainer(s, 0));
230 if (jfif->getDimensions(x,y)) {
231 Trace(DEBUG1) <<
"JPEG dimensions x=" << x
232 <<
" y=" << y <<
"\n";
235 _type = OR_DATA_TYPE_NONE;
236 Trace(WARNING) <<
"Couldn't get JPEG " 241 Trace(DEBUG1) <<
"JPEG (supposed) dimensions x=" << x
242 <<
" y=" << y <<
"\n";
248 else if (photom_int == IFD::EV_PI_YCBCR) {
249 Trace(WARNING) <<
"Unsupported YCbCr photometric " 250 "interpretation in non JPEG.\n";
251 ret = OR_ERROR_INVALID_FORMAT;
254 Trace(DEBUG1) <<
"found strip offsets\n";
255 if (x != 0 && y != 0) {
260 IfdEntry::Ref entry = dir->getEntry(IFD::EXIF_TAG_BITS_PER_SAMPLE);
261 std::vector<uint16_t> arr;
262 entry->getArray(arr);
263 for(
auto bpc : arr) {
266 Trace(DEBUG1) <<
"bpc != 8, not RGB8 " << bpc <<
"\n";
271 catch(
const std::exception & e) {
272 Trace(DEBUG1) <<
"Exception getting BPS " << e.what() <<
"\n";
275 _type = OR_DATA_TYPE_PIXMAP_8RGB;
279 if(_type != OR_DATA_TYPE_NONE) {
280 uint32_t dim = std::max(x, y);
281 offset += dir->container().offset();
282 _addThumbnail(dim,
ThumbDesc(x, y, _type,
283 offset, byte_count));
300 bool got_it = dir->getValue(IFD::EXIF_TAG_JPEG_INTERCHANGE_FORMAT_LENGTH, byte_length);
302 got_it = dir->getValue(IFD::EXIF_TAG_JPEG_INTERCHANGE_FORMAT, offset);
306 got_it = dir->getValue(IFD::EXIF_TAG_STRIP_OFFSETS, offset);
307 got_it = dir->getValue(IFD::EXIF_TAG_STRIP_BYTE_COUNTS, byte_length);
314 MetaValue *IfdFile::_getMetaValue(int32_t meta_index)
318 if(META_INDEX_MASKOUT(meta_index) == META_NS_TIFF) {
321 else if(META_INDEX_MASKOUT(meta_index) == META_NS_EXIF) {
325 Trace(ERROR) <<
"Unknown Meta Namespace\n";
328 Trace(DEBUG1) <<
"Meta value for " 329 << META_NS_MASKOUT(meta_index) <<
"\n";
331 IfdEntry::Ref e = ifd->getEntry(META_NS_MASKOUT(meta_index));
333 val = e->make_meta_value();
343 return (uint32_t)tiffCompression;
351 m_cfaIfd = _locateCfaIfd();
357 const IfdDir::Ref & IfdFile::mainIfd()
360 m_mainIfd = _locateMainIfd();
366 const IfdDir::Ref & IfdFile::exifIfd()
369 m_exifIfd = _locateExifIfd();
375 const MakerNoteDir::Ref & IfdFile::makerNoteIfd()
377 if(!m_makerNoteIfd) {
378 m_makerNoteIfd = _locateMakerNoteIfd();
380 return m_makerNoteIfd;
387 _convertArrayToCfaPattern(
const std::vector<uint8_t> &cfaPattern)
389 ::or_cfa_pattern cfa_pattern = OR_CFA_PATTERN_NON_RGB22;
390 if(cfaPattern.size() != 4) {
391 Trace(WARNING) <<
"Unsupported bayer pattern\n";
394 Trace(DEBUG2) <<
"patter is = " << cfaPattern[0] <<
", " 395 << cfaPattern[1] <<
", " << cfaPattern[2]
396 <<
", " << cfaPattern[3] <<
"\n";
397 switch(cfaPattern[0]) {
399 switch(cfaPattern[1]) {
401 if((cfaPattern[2] == IFD::CFA_GREEN)
402 && (cfaPattern[3] == IFD::CFA_BLUE))
404 cfa_pattern = OR_CFA_PATTERN_RGGB;
410 switch(cfaPattern[1]) {
412 if((cfaPattern[2] == 2)
413 && (cfaPattern[3] == IFD::CFA_GREEN))
415 cfa_pattern = OR_CFA_PATTERN_GRBG;
419 if((cfaPattern[2] == IFD::CFA_RED)
420 && (cfaPattern[3] == IFD::CFA_GREEN))
422 cfa_pattern = OR_CFA_PATTERN_GBRG;
428 switch(cfaPattern[1]) {
430 if((cfaPattern[2] == IFD::CFA_GREEN)
431 && (cfaPattern[3] == IFD::CFA_RED))
433 cfa_pattern = OR_CFA_PATTERN_BGGR;
444 ::or_cfa_pattern _convertNewCfaPattern(
const IfdEntry::Ref & e)
446 ::or_cfa_pattern cfa_pattern = OR_CFA_PATTERN_NONE;
447 if(!e || (e->count() < 4)) {
453 if(hdim != 2 && vdim != 2) {
454 cfa_pattern = OR_CFA_PATTERN_NON_RGB22;
457 std::vector<uint8_t> cfaPattern;
462 cfa_pattern = _convertArrayToCfaPattern(cfaPattern);
471 std::vector<uint8_t> cfaPattern;
472 ::or_cfa_pattern cfa_pattern = OR_CFA_PATTERN_NONE;
474 e->getArray(cfaPattern);
475 if(!cfaPattern.empty()) {
476 cfa_pattern = _convertArrayToCfaPattern(cfaPattern);
486 static ::or_cfa_pattern _getCfaPattern(
const IfdDir::Ref & dir)
488 Trace(DEBUG1) << __FUNCTION__ <<
"\n";
489 ::or_cfa_pattern cfa_pattern = OR_CFA_PATTERN_NONE;
493 cfa_pattern = _convertCfaPattern(e);
496 e = dir->getEntry(IFD::EXIF_TAG_NEW_CFA_PATTERN);
498 cfa_pattern = _convertNewCfaPattern(e);
504 Trace(ERROR) <<
"Exception in _getCfaPattern().\n";
514 ::or_error ret = OR_ERROR_NONE;
515 const IfdDir::Ref & _cfaIfd = cfaIfd();
516 Trace(DEBUG1) <<
"_getRawData()\n";
519 ret = _getRawDataFromDir(data, _cfaIfd);
520 if (ret != OR_ERROR_NONE) {
523 ret = _decompressIfNeeded(data, options);
526 ret = OR_ERROR_NOT_FOUND;
531 ::or_error IfdFile::_decompressIfNeeded(
RawData&, uint32_t)
533 return OR_ERROR_NONE;
539 ::or_error ret = OR_ERROR_NONE;
543 uint32_t byte_length = 0;
550 Trace(ERROR) <<
"dir is NULL\n";
551 return OR_ERROR_NOT_FOUND;
553 got_it = dir->getValue(IFD::EXIF_TAG_BITS_PER_SAMPLE, bpc);
555 Trace(ERROR) <<
"unable to guess Bits per sample\n";
558 got_it = dir->getValue(IFD::EXIF_TAG_STRIP_OFFSETS, offset);
560 IfdEntry::Ref e = dir->getEntry(IFD::EXIF_TAG_STRIP_BYTE_COUNTS);
562 Trace(DEBUG1) <<
"byte len not found\n";
563 return OR_ERROR_NOT_FOUND;
565 std::vector<uint32_t> counts;
567 Trace(DEBUG1) <<
"counting tiles\n";
568 byte_length = std::accumulate(counts.cbegin(), counts.cend(), 0);
575 Trace(DEBUG1) <<
"tile offsets empty\n";
576 return OR_ERROR_NOT_FOUND;
578 std::vector<uint32_t> offsets;
579 e->getArray(offsets);
580 if(offsets.size() == 0) {
581 Trace(DEBUG1) <<
"tile offsets not found\n";
582 return OR_ERROR_NOT_FOUND;
585 e = dir->getEntry(IFD::TIFF_TAG_TILE_BYTECOUNTS);
587 Trace(DEBUG1) <<
"tile byte counts not found\n";
588 return OR_ERROR_NOT_FOUND;
590 std::vector<uint32_t> counts;
592 Trace(DEBUG1) <<
"counting tiles\n";
593 byte_length = std::accumulate(counts.cbegin(), counts.cend(), 0);
595 got_it = dir->getIntegerValue(IFD::EXIF_TAG_IMAGE_WIDTH, x);
597 Trace(DEBUG1) <<
"X not found\n";
598 return OR_ERROR_NOT_FOUND;
600 got_it = dir->getIntegerValue(IFD::EXIF_TAG_IMAGE_LENGTH, y);
602 Trace(DEBUG1) <<
"Y not found\n";
603 return OR_ERROR_NOT_FOUND;
606 uint32_t photo_int = 0;
607 got_it = dir->getIntegerValue(IFD::EXIF_TAG_PHOTOMETRIC_INTERPRETATION,
611 photo_int = IFD::EV_PI_CFA;
614 uint16_t tiffCompression = 0;
615 got_it = dir->getValue(IFD::EXIF_TAG_COMPRESSION, tiffCompression);
617 Trace(DEBUG1) <<
"Compression type not found\n";
619 BitmapData::DataType data_type = OR_DATA_TYPE_NONE;
621 uint32_t compression = _translateCompressionType((IFD::TiffCompress)tiffCompression);
624 case IFD::COMPRESS_NONE:
625 data_type = OR_DATA_TYPE_RAW;
627 case IFD::COMPRESS_NIKON_PACK:
628 data_type = OR_DATA_TYPE_RAW;
630 case IFD::COMPRESS_NIKON_QUANTIZED:
634 compression = IFD::COMPRESS_NIKON_PACK;
635 data_type = OR_DATA_TYPE_RAW;
644 data_type = OR_DATA_TYPE_COMPRESSED_RAW;
648 Trace(DEBUG1) <<
"RAW Compression is " << compression <<
"\n";
650 ::or_cfa_pattern cfa_pattern = _getCfaPattern(dir);
651 if(cfa_pattern == OR_CFA_PATTERN_NONE) {
654 m_exifIfd = _locateExifIfd();
656 cfa_pattern = _getCfaPattern(m_exifIfd);
660 if((bpc == 12 || bpc == 14) && (compression == 1)
661 && (byte_length == (x * y * 2)))
663 Trace(DEBUG1) <<
"setting bpc from " << bpc
667 if((bpc == 16) || (data_type == OR_DATA_TYPE_COMPRESSED_RAW)) {
668 void *p = data.allocData(byte_length);
669 size_t real_size = m_container->fetchData(p, offset,
671 if (real_size < byte_length) {
672 Trace(WARNING) <<
"Size mismatch for data: ignoring.\n";
675 else if((bpc == 12) || (bpc == 8)) {
676 ret = _unpackData(bpc, compression, data, x, y, offset, byte_length);
677 Trace(DEBUG1) <<
"unpack result " << ret <<
"\n";
680 Trace(ERROR) <<
"Unsupported bpc " << bpc <<
"\n";
681 return OR_ERROR_INVALID_FORMAT;
683 data.setCfaPatternType(cfa_pattern);
685 data.setCompression(data_type == OR_DATA_TYPE_COMPRESSED_RAW
687 data.setPhotometricInterpretation((ExifPhotometricInterpretation)photo_int);
688 if((data_type == OR_DATA_TYPE_RAW) && (data.whiteLevel() == 0)) {
689 data.setWhiteLevel((1 << bpc) - 1);
697 ::or_error
IfdFile::_unpackData(uint16_t bpc, uint32_t compression,
RawData & data, uint32_t x, uint32_t y, uint32_t offset, uint32_t byte_length)
699 ::or_error ret = OR_ERROR_NONE;
701 uint32_t current_offset = offset;
702 Unpack unpack(x, compression);
703 const size_t blocksize = (bpc == 8 ? x : unpack.block_size());
704 Trace(DEBUG1) <<
"Block size = " << blocksize <<
"\n";
705 Trace(DEBUG1) <<
"dimensions (x, y) " << x <<
", " 707 std::unique_ptr<uint8_t[]> block(
new uint8_t[blocksize]);
708 size_t outsize = x * y * 2;
709 uint8_t * outdata = (uint8_t*)data.allocData(outsize);
711 Trace(DEBUG1) <<
"offset of RAW data = " << current_offset <<
"\n";
713 got = m_container->fetchData (block.get(),
714 current_offset, blocksize);
717 current_offset += got;
726 if(ret != OR_ERROR_NONE) {
732 std::copy(block.get(), block.get()+got,
734 outdata += (got << 1);
737 }
while((got != 0) && (fetched < byte_length));
CIFF is the container for CRW files. It is an attempt from Canon to make this a standard. I guess it failed.
static T get(IfdEntry &e, uint32_t idx=0, bool ignore_type=false) noexcept(false)
virtual ::or_error _enumThumbnailSizes(std::vector< uint32_t > &list) override
or_error unpack_be12to16(uint8_t *dest, size_t destsize, const uint8_t *src, size_t size, size_t &outsize)
virtual ::or_error _getRawData(RawData &data, uint32_t options) override
virtual uint32_t _getJpegThumbnailOffset(const IfdDir::Ref &dir, uint32_t &len)
std::shared_ptr< IfdEntry > Ref
virtual ::or_error _locateThumbnail(const IfdDir::Ref &dir, std::vector< uint32_t > &list)
static bool isCompressed(RawContainer &container, uint32_t offset)
virtual ::or_error _unpackData(uint16_t bpc, uint32_t compression, RawData &data, uint32_t x, uint32_t y, uint32_t offset, uint32_t byte_length)
const IfdDir::Ref & cfaIfd()
virtual RawContainer * getContainer() const override
void setDataType(DataType _type)
::or_error _getRawDataFromDir(RawData &data, const IfdDir::Ref &dir)
virtual uint32_t _translateCompressionType(IFD::TiffCompress tiffCompression)
virtual void setDimensions(uint32_t x, uint32_t y) override