31#include <libopenraw/consts.h>
32#include <libopenraw/debug.h>
33#include <libopenraw/metadata.h>
35#include "bitmapdata.hpp"
39#include "io/stream.hpp"
40#include "io/streamclone.hpp"
42#include "ifdentry.hpp"
44#include "ifdfilecontainer.hpp"
45#include "jfifcontainer.hpp"
46#include "rawfile_private.hpp"
56IfdFile::IfdFile(
const IO::Stream::Ptr &s, Type _type,
57 bool instantiateContainer)
62 if(instantiateContainer) {
63 m_container =
new IfdFileContainer(m_io, 0);
74IfdDir::Ref IfdFile::_locateExifIfd()
76 const IfdDir::Ref & _mainIfd = mainIfd();
78 LOGERR(
"IfdFile::_locateExifIfd() main IFD not found\n");
81 return _mainIfd->getExifIFD();
84MakerNoteDir::Ref IfdFile::_locateMakerNoteIfd()
86 const IfdDir::Ref & _exifIfd = exifIfd();
89 return std::dynamic_pointer_cast<MakerNoteDir>(_exifIfd->getMakerNoteIfd());
91 return MakerNoteDir::Ref();
94void IfdFile::_identifyId()
96 const IfdDir::Ref & _mainIfd = mainIfd();
98 LOGERR(
"Main IFD not found to identify the file.\n");
102 auto make = _mainIfd->getValue<std::string>(IFD::EXIF_TAG_MAKE);
103 auto model = _mainIfd->getValue<std::string>(IFD::EXIF_TAG_MODEL);
105 _setTypeId(_typeIdFromModel(make.value(), model.value()));
114 ::or_error err = OR_ERROR_NONE;
116 LOGDBG1(
"_enumThumbnailSizes()\n");
117 std::vector<IfdDir::Ref> & dirs =
m_container->directories();
119 LOGDBG1(
"num of dirs %lu\n", dirs.size());
124 if (ret == OR_ERROR_NONE) {
125 LOGDBG1(
"Found %u pixels\n", list.back());
127 auto result = dir->getSubIFDs();
129 std::vector<IfdDir::Ref> subdirs = result.value();
130 LOGDBG1(
"Iterating subdirs\n");
131 for(
auto dir2 : subdirs)
135 if (ret == OR_ERROR_NONE) {
136 LOGDBG1(
"Found %u pixels\n", list.back());
141 if (list.size() <= 0) {
142 err = OR_ERROR_NOT_FOUND;
149 std::vector<uint32_t> &list)
151 ::or_error ret = OR_ERROR_NOT_FOUND;
152 ::or_data_type _type = OR_DATA_TYPE_NONE;
153 uint32_t subtype = 0;
155 LOGDBG1(
"_locateThumbnail\n");
157 auto result = dir->getValue<uint32_t>(IFD::EXIF_TAG_NEW_SUBFILE_TYPE);
158 if (result.empty()) {
160 m_cfaIfd = _locateCfaIfd();
162 if(m_cfaIfd == dir) {
163 return OR_ERROR_NOT_FOUND;
169 subtype = result.value();
171 LOGDBG1(
"subtype %u\n", subtype);
174 uint16_t photom_int =
175 dir->getValue<uint16_t>(IFD::EXIF_TAG_PHOTOMETRIC_INTERPRETATION).value_or(IFD::EV_PI_RGB);
177 uint32_t x = dir->getIntegerValue(IFD::EXIF_TAG_IMAGE_WIDTH).value_or(0);
178 uint32_t y = dir->getIntegerValue(IFD::EXIF_TAG_IMAGE_LENGTH).value_or(0);
180 uint16_t compression = dir->getValue<uint16_t>(IFD::EXIF_TAG_COMPRESSION).value_or(0);
183 uint32_t byte_count = dir->getValue<uint32_t>(IFD::EXIF_TAG_STRIP_BYTE_COUNTS).value_or(0);
185 result = dir->getValue<uint32_t>(IFD::EXIF_TAG_STRIP_OFFSETS);
186 bool got_it = result.has_value();
188 offset = result.value();
190 if (!got_it || (compression == 6) || (compression == 7)) {
193 dir->getValue<uint32_t>(IFD::EXIF_TAG_JPEG_INTERCHANGE_FORMAT_LENGTH).value_or(0);
194 result = dir->getValue<uint32_t>(IFD::EXIF_TAG_JPEG_INTERCHANGE_FORMAT);
195 got_it = result.has_value();
197 offset = result.value();
204 if(byte_count >= (x * y * 3)) {
206 _type = OR_DATA_TYPE_NONE;
208 LOGDBG1(
"8RGB as JPEG. Will ignore.\n");
209 ret = OR_ERROR_INVALID_FORMAT;
212 _type = OR_DATA_TYPE_JPEG;
216 _type = OR_DATA_TYPE_JPEG;
217 LOGDBG1(
"looking for JPEG at %u\n", offset);
218 if (x == 0 || y == 0) {
219 IO::Stream::Ptr s(std::make_shared<IO::StreamClone>(
221 std::unique_ptr<JfifContainer> jfif(
new JfifContainer(s, 0));
222 if (jfif->getDimensions(x,y)) {
223 LOGDBG1(
"JPEG dimensions x=%u y=%u\n", x, y);
226 _type = OR_DATA_TYPE_NONE;
227 LOGWARN(
"Couldn't get JPEG dimensions.\n");
231 LOGDBG1(
"JPEG (supposed) dimensions x=%u y=%u\n", x, y);
237 else if (photom_int == IFD::EV_PI_YCBCR) {
238 LOGWARN(
"Unsupported YCbCr photometric interpretation in non JPEG.\n");
239 ret = OR_ERROR_INVALID_FORMAT;
242 LOGDBG1(
"found strip offsets\n");
243 if (x != 0 && y != 0) {
247 IfdEntry::Ref entry = dir->getEntry(IFD::EXIF_TAG_BITS_PER_SAMPLE);
248 auto result2 = entry->getArray<uint16_t>();
250 std::vector<uint16_t> arr = result2.value();
251 for(
auto bpc : arr) {
254 LOGDBG1(
"bpc != 8, not RGB8 %u\n", bpc);
259 LOGDBG1(
"Error getting BPS\n");
262 _type = OR_DATA_TYPE_PIXMAP_8RGB;
266 if(_type != OR_DATA_TYPE_NONE) {
267 uint32_t dim = std::max(x, y);
268 offset += dir->container().offset();
269 _addThumbnail(dim,
ThumbDesc(x, y, _type,
270 offset, byte_count));
286 auto result = dir->getValue<uint32_t>(IFD::EXIF_TAG_JPEG_INTERCHANGE_FORMAT_LENGTH);
288 byte_length = result.value();
289 return dir->getValue<uint32_t>(IFD::EXIF_TAG_JPEG_INTERCHANGE_FORMAT).value_or(0);
293 byte_length = dir->getValue<uint32_t>(IFD::EXIF_TAG_STRIP_BYTE_COUNTS).value_or(0);
294 return dir->getValue<uint32_t>(IFD::EXIF_TAG_STRIP_OFFSETS).value_or(0);
299MetaValue *IfdFile::_getMetaValue(int32_t meta_index)
303 if(META_INDEX_MASKOUT(meta_index) == META_NS_TIFF) {
306 else if(META_INDEX_MASKOUT(meta_index) == META_NS_EXIF) {
310 LOGERR(
"Unknown Meta Namespace\n");
313 LOGDBG1(
"Meta value for %u\n", META_NS_MASKOUT(meta_index));
315 IfdEntry::Ref e = ifd->getEntry(META_NS_MASKOUT(meta_index));
317 val = e->make_meta_value();
327 return (uint32_t)tiff_compression;
335 m_cfaIfd = _locateCfaIfd();
341const IfdDir::Ref & IfdFile::mainIfd()
344 m_mainIfd = _locateMainIfd();
350const IfdDir::Ref & IfdFile::exifIfd()
353 m_exifIfd = _locateExifIfd();
359const MakerNoteDir::Ref & IfdFile::makerNoteIfd()
361 if(!m_makerNoteIfd) {
362 m_makerNoteIfd = _locateMakerNoteIfd();
364 return m_makerNoteIfd;
371_convertArrayToCfaPattern(
const std::vector<uint8_t> &cfaPattern)
373 ::or_cfa_pattern cfa_pattern = OR_CFA_PATTERN_NON_RGB22;
374 if(cfaPattern.size() != 4) {
375 LOGWARN(
"Unsupported bayer pattern\n");
378 LOGDBG2(
"pattern is = %d, %d, %d, %d\n", cfaPattern[0],
379 cfaPattern[1], cfaPattern[2], cfaPattern[3]);
380 switch(cfaPattern[0]) {
382 if ((cfaPattern[1] == IFD::CFA_GREEN)
383 && (cfaPattern[2] == IFD::CFA_GREEN)
384 && (cfaPattern[3] == IFD::CFA_BLUE)) {
385 cfa_pattern = OR_CFA_PATTERN_RGGB;
389 switch(cfaPattern[1]) {
391 if ((cfaPattern[2] == IFD::CFA_BLUE)
392 && (cfaPattern[3] == IFD::CFA_GREEN)) {
393 cfa_pattern = OR_CFA_PATTERN_GRBG;
397 if ((cfaPattern[2] == IFD::CFA_RED)
398 && (cfaPattern[3] == IFD::CFA_GREEN)) {
399 cfa_pattern = OR_CFA_PATTERN_GBRG;
405 if ((cfaPattern[1] ==IFD::CFA_GREEN)
406 && (cfaPattern[2] == IFD::CFA_GREEN)
407 && (cfaPattern[3] == IFD::CFA_RED)) {
408 cfa_pattern = OR_CFA_PATTERN_BGGR;
417::or_cfa_pattern _convertNewCfaPattern(
const IfdEntry::Ref & e)
419 ::or_cfa_pattern cfa_pattern = OR_CFA_PATTERN_NONE;
420 if(!e || (e->count() < 4)) {
424 uint16_t hdim = IfdTypeTrait<uint16_t>::get(*e, 0,
true);
425 uint16_t vdim = IfdTypeTrait<uint16_t>::get(*e, 1,
true);
426 if(hdim != 2 && vdim != 2) {
427 cfa_pattern = OR_CFA_PATTERN_NON_RGB22;
430 std::vector<uint8_t> cfaPattern;
431 cfaPattern.push_back(IfdTypeTrait<uint8_t>::get(*e, 4,
true));
432 cfaPattern.push_back(IfdTypeTrait<uint8_t>::get(*e, 5,
true));
433 cfaPattern.push_back(IfdTypeTrait<uint8_t>::get(*e, 6,
true));
434 cfaPattern.push_back(IfdTypeTrait<uint8_t>::get(*e, 7,
true));
435 cfa_pattern = _convertArrayToCfaPattern(cfaPattern);
442::or_cfa_pattern _convertCfaPattern(
const IfdEntry::Ref & e)
444 ::or_cfa_pattern cfa_pattern = OR_CFA_PATTERN_NONE;
446 auto result = e->getArray<uint8_t>();
448 cfa_pattern = _convertArrayToCfaPattern(result.value());
459static ::or_cfa_pattern _getCfaPattern(
const IfdDir::Ref & dir)
461 LOGDBG1(
"%s\n", __FUNCTION__);
462 ::or_cfa_pattern cfa_pattern = OR_CFA_PATTERN_NONE;
464 IfdEntry::Ref e = dir->getEntry(IFD::EXIF_TAG_CFA_PATTERN);
466 cfa_pattern = _convertCfaPattern(e);
469 e = dir->getEntry(IFD::EXIF_TAG_NEW_CFA_PATTERN);
471 cfa_pattern = _convertNewCfaPattern(e);
477 LOGERR(
"Exception in _getCfaPattern().\n");
487 ::or_error ret = OR_ERROR_NONE;
488 const IfdDir::Ref & _cfaIfd =
cfaIfd();
489 LOGDBG1(
"_getRawData()\n");
493 if (ret != OR_ERROR_NONE) {
496 ret = _decompressIfNeeded(data, options);
499 ret = OR_ERROR_NOT_FOUND;
504::or_error IfdFile::_decompressIfNeeded(
RawData&, uint32_t)
506 return OR_ERROR_NONE;
512 ::or_error ret = OR_ERROR_NONE;
515 uint32_t byte_length = 0;
518 LOGERR(
"dir is NULL\n");
519 return OR_ERROR_NOT_FOUND;
521 auto result = dir->getValue<uint16_t>(IFD::EXIF_TAG_BITS_PER_SAMPLE);
523 LOGERR(
"unable to guess Bits per sample\n");
525 uint16_t bpc = result.value_or(0);
527 auto result2 = dir->getValue<uint32_t>(IFD::EXIF_TAG_STRIP_OFFSETS);
529 offset = result2.value();
530 IfdEntry::Ref e = dir->getEntry(IFD::EXIF_TAG_STRIP_BYTE_COUNTS);
532 LOGDBG1(
"byte len not found\n");
533 return OR_ERROR_NOT_FOUND;
535 auto result3 = e->getArray<uint32_t>();
537 std::vector<uint32_t> counts = result3.value();
538 LOGDBG1(
"counting tiles\n");
539 byte_length = std::accumulate(counts.cbegin(), counts.cend(), 0);
547 LOGDBG1(
"tile offsets empty\n");
548 return OR_ERROR_NOT_FOUND;
550 auto result3 = e->getArray<uint32_t>();
552 LOGDBG1(
"tile offsets not found\n");
553 return OR_ERROR_NOT_FOUND;
555 std::vector<uint32_t> offsets = result3.value();
557 e = dir->getEntry(IFD::TIFF_TAG_TILE_BYTECOUNTS);
559 LOGDBG1(
"tile byte counts not found\n");
560 return OR_ERROR_NOT_FOUND;
562 result3 = e->getArray<uint32_t>();
564 std::vector<uint32_t> counts = result3.value();
565 LOGDBG1(
"counting tiles\n");
566 byte_length = std::accumulate(counts.cbegin(), counts.cend(), 0);
570 result2 = dir->getIntegerValue(IFD::EXIF_TAG_IMAGE_WIDTH);
571 if(result2.empty()) {
572 LOGDBG1(
"X not found\n");
573 return OR_ERROR_NOT_FOUND;
575 uint32_t x = result2.value();
577 result2 = dir->getIntegerValue(IFD::EXIF_TAG_IMAGE_LENGTH);
579 LOGDBG1(
"Y not found\n");
580 return OR_ERROR_NOT_FOUND;
582 uint32_t y = result2.value();
585 = dir->getIntegerValue(IFD::EXIF_TAG_PHOTOMETRIC_INTERPRETATION)
586 .value_or(IFD::EV_PI_CFA);
588 BitmapData::DataType data_type = OR_DATA_TYPE_NONE;
590 result = dir->getValue<uint16_t>(IFD::EXIF_TAG_COMPRESSION);
592 LOGDBG1(
"Compression type not found\n");
595 static_cast<IFD::TiffCompress
>(result.value_or(0)));
599 case IFD::COMPRESS_NONE:
600 data_type = OR_DATA_TYPE_RAW;
602 case IFD::COMPRESS_NIKON_PACK:
603 data_type = OR_DATA_TYPE_RAW;
606 data_type = OR_DATA_TYPE_COMPRESSED_RAW;
610 LOGDBG1(
"RAW Compression is %u\n", compression);
611 LOGDBG1(
"bpc is %u\n", bpc);
613 ::or_cfa_pattern cfa_pattern = _getCfaPattern(dir);
614 if(cfa_pattern == OR_CFA_PATTERN_NONE) {
617 m_exifIfd = _locateExifIfd();
619 cfa_pattern = _getCfaPattern(m_exifIfd);
623 if((bpc == 12 || bpc == 14) && (compression == IFD::COMPRESS_NONE)
624 && (byte_length == (x * y * 2))) {
626 LOGDBG1(
"setting bpc from %u to 16\n", bpc);
629 if((bpc == 16) || (data_type == OR_DATA_TYPE_COMPRESSED_RAW)) {
630 void *p = data.allocData(byte_length);
631 size_t real_size =
m_container->fetchData(p, offset,
633 if (real_size < byte_length) {
634 LOGWARN(
"Size mismatch for data: ignoring.\n");
637 else if((bpc == 12) || (bpc == 8)) {
638 ret =
_unpackData(bpc, compression, data, x, y, offset, byte_length);
639 LOGDBG1(
"unpack result %d\n", ret);
642 LOGERR(
"Unsupported bpc %u\n", bpc);
643 return OR_ERROR_INVALID_FORMAT;
645 data.setCfaPatternType(cfa_pattern);
648 data.setCompression(data_type == OR_DATA_TYPE_COMPRESSED_RAW
650 data.setPhotometricInterpretation((ExifPhotometricInterpretation)photo_int);
651 if((data_type == OR_DATA_TYPE_RAW) && (data.whiteLevel() == 0)) {
652 data.setWhiteLevel((1 << bpc) - 1);
662 uint32_t x, uint32_t y, uint32_t offset, uint32_t byte_length)
664 ::or_error ret = OR_ERROR_NONE;
666 uint32_t current_offset = offset;
667 Unpack unpack(x, compression);
668 const size_t blocksize = (bpc == 8 ? x : unpack.block_size());
669 LOGDBG1(
"Block size = %lu\n", blocksize);
670 LOGDBG1(
"dimensions (x, y) %u, %u\n", x, y);
671 std::unique_ptr<uint8_t[]> block(
new uint8_t[blocksize]);
672 size_t outsize = x * y * 2;
673 uint8_t * outdata = (uint8_t*)data.allocData(outsize);
675 LOGDBG1(
"offset of RAW data = %u\n", current_offset);
678 current_offset, blocksize);
681 current_offset += got;
690 if(ret != OR_ERROR_NONE) {
696 std::copy(block.get(), block.get()+got,
698 outdata += (got << 1);
701 }
while((got != 0) && (fetched < byte_length));
void setDataType(DataType _type)
void setBpc(uint32_t _bpc)
std::shared_ptr< IfdEntry > Ref
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)
virtual::or_error _enumThumbnailSizes(std::vector< uint32_t > &list) override
IfdFileContainer * m_container
virtual::or_error _getRawData(RawData &data, uint32_t options) override
virtual::or_error _locateThumbnail(const IfdDir::Ref &dir, std::vector< uint32_t > &list)
::or_error _getRawDataFromDir(RawData &data, const IfdDir::Ref &dir)
virtual RawContainer * getContainer() const override
virtual uint32_t _getJpegThumbnailOffset(const IfdDir::Ref &dir, uint32_t &len)
const IfdDir::Ref & cfaIfd()
virtual uint32_t _translateCompressionType(IFD::TiffCompress tiffCompression)
or_error unpack_be12to16(uint8_t *dest, size_t destsize, const uint8_t *src, size_t size, size_t &outsize)
virtual void setDimensions(uint32_t x, uint32_t y) override
CIFF is the container for CRW files. It is an attempt from Canon to make this a standard....