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" 57 IfdFile::IfdFile(
const IO::Stream::Ptr &s, Type _type,
58 bool instantiateContainer)
63 if(instantiateContainer) {
64 m_container =
new IfdFileContainer(m_io, 0);
75 IfdDir::Ref IfdFile::_locateExifIfd()
77 const IfdDir::Ref & _mainIfd = mainIfd();
79 LOGERR(
"IfdFile::_locateExifIfd() main IFD not found\n");
82 return _mainIfd->getExifIFD();
85 MakerNoteDir::Ref IfdFile::_locateMakerNoteIfd()
87 const IfdDir::Ref & _exifIfd = exifIfd();
90 return std::dynamic_pointer_cast<MakerNoteDir>(_exifIfd->getMakerNoteIfd());
92 return MakerNoteDir::Ref();
95 void IfdFile::_identifyId()
97 const IfdDir::Ref & _mainIfd = mainIfd();
99 LOGERR(
"Main IFD not found to identify the file.\n");
103 auto make = _mainIfd->getValue<std::string>(IFD::EXIF_TAG_MAKE);
104 auto model = _mainIfd->getValue<std::string>(IFD::EXIF_TAG_MODEL);
105 if (make.ok() && model.ok()) {
106 _setTypeId(_typeIdFromModel(make.unwrap(), model.unwrap()));
115 ::or_error err = OR_ERROR_NONE;
117 LOGDBG1(
"_enumThumbnailSizes()\n");
118 std::vector<IfdDir::Ref> & dirs = m_container->directories();
120 LOGDBG1(
"num of dirs %lu\n", dirs.size());
124 or_error ret = _locateThumbnail(dir, list);
125 if (ret == OR_ERROR_NONE) {
126 LOGDBG1(
"Found %u pixels\n", list.back());
128 auto result = dir->getSubIFDs();
130 std::vector<IfdDir::Ref> subdirs = result.unwrap();
131 LOGDBG1(
"Iterating subdirs\n");
132 for(
auto dir2 : subdirs)
135 ret = _locateThumbnail(dir2, list);
136 if (ret == OR_ERROR_NONE) {
137 LOGDBG1(
"Found %u pixels\n", list.back());
142 if (list.size() <= 0) {
143 err = OR_ERROR_NOT_FOUND;
150 std::vector<uint32_t> &list)
152 ::or_error ret = OR_ERROR_NOT_FOUND;
153 ::or_data_type _type = OR_DATA_TYPE_NONE;
154 uint32_t subtype = 0;
156 LOGDBG1(
"_locateThumbnail\n");
158 auto result = dir->getValue<uint32_t>(IFD::EXIF_TAG_NEW_SUBFILE_TYPE);
159 if (result.empty()) {
161 m_cfaIfd = _locateCfaIfd();
163 if(m_cfaIfd == dir) {
164 return OR_ERROR_NOT_FOUND;
170 subtype = result.unwrap();
172 LOGDBG1(
"subtype %u\n", subtype);
175 uint16_t photom_int =
176 dir->getValue<uint16_t>(IFD::EXIF_TAG_PHOTOMETRIC_INTERPRETATION).unwrap_or(IFD::EV_PI_RGB);
178 uint32_t x = dir->getIntegerValue(IFD::EXIF_TAG_IMAGE_WIDTH).unwrap_or(0);
179 uint32_t y = dir->getIntegerValue(IFD::EXIF_TAG_IMAGE_LENGTH).unwrap_or(0);
181 uint16_t compression = dir->getValue<uint16_t>(IFD::EXIF_TAG_COMPRESSION).unwrap_or(0);
184 uint32_t byte_count = dir->getValue<uint32_t>(IFD::EXIF_TAG_STRIP_BYTE_COUNTS).unwrap_or(0);
186 result = dir->getValue<uint32_t>(IFD::EXIF_TAG_STRIP_OFFSETS);
187 bool got_it = result.ok();
189 offset = result.unwrap();
191 if (!got_it || (compression == 6) || (compression == 7)) {
194 dir->getValue<uint32_t>(IFD::EXIF_TAG_JPEG_INTERCHANGE_FORMAT_LENGTH).unwrap_or(0);
195 result = dir->getValue<uint32_t>(IFD::EXIF_TAG_JPEG_INTERCHANGE_FORMAT);
196 got_it = result.ok();
198 offset = result.unwrap();
205 if(byte_count >= (x * y * 3)) {
207 _type = OR_DATA_TYPE_NONE;
209 LOGDBG1(
"8RGB as JPEG. Will ignore.\n");
210 ret = OR_ERROR_INVALID_FORMAT;
213 _type = OR_DATA_TYPE_JPEG;
217 _type = OR_DATA_TYPE_JPEG;
218 LOGDBG1(
"looking for JPEG at %u\n", offset);
219 if (x == 0 || y == 0) {
220 IO::Stream::Ptr s(std::make_shared<IO::StreamClone>(
222 std::unique_ptr<JfifContainer> jfif(
new JfifContainer(s, 0));
223 if (jfif->getDimensions(x,y)) {
224 LOGDBG1(
"JPEG dimensions x=%u y=%u\n", x, y);
227 _type = OR_DATA_TYPE_NONE;
228 LOGWARN(
"Couldn't get JPEG dimensions.\n");
232 LOGDBG1(
"JPEG (supposed) dimensions x=%u y=%u\n", x, y);
238 else if (photom_int == IFD::EV_PI_YCBCR) {
239 LOGWARN(
"Unsupported YCbCr photometric interpretation in non JPEG.\n");
240 ret = OR_ERROR_INVALID_FORMAT;
243 LOGDBG1(
"found strip offsets\n");
244 if (x != 0 && y != 0) {
248 IfdEntry::Ref entry = dir->getEntry(IFD::EXIF_TAG_BITS_PER_SAMPLE);
249 auto result2 = entry->getArray<uint16_t>();
251 std::vector<uint16_t> arr = result2.unwrap();
252 for(
auto bpc : arr) {
255 LOGDBG1(
"bpc != 8, not RGB8 %u\n", bpc);
260 LOGDBG1(
"Error getting BPS\n");
263 _type = OR_DATA_TYPE_PIXMAP_8RGB;
267 if(_type != OR_DATA_TYPE_NONE) {
268 uint32_t dim = std::max(x, y);
269 offset += dir->container().offset();
270 _addThumbnail(dim,
ThumbDesc(x, y, _type,
271 offset, byte_count));
287 auto result = dir->getValue<uint32_t>(IFD::EXIF_TAG_JPEG_INTERCHANGE_FORMAT_LENGTH);
289 byte_length = result.unwrap();
290 return dir->getValue<uint32_t>(IFD::EXIF_TAG_JPEG_INTERCHANGE_FORMAT).unwrap_or(0);
294 byte_length = dir->getValue<uint32_t>(IFD::EXIF_TAG_STRIP_BYTE_COUNTS).unwrap_or(0);
295 return dir->getValue<uint32_t>(IFD::EXIF_TAG_STRIP_OFFSETS).unwrap_or(0);
300 MetaValue *IfdFile::_getMetaValue(int32_t meta_index)
304 if(META_INDEX_MASKOUT(meta_index) == META_NS_TIFF) {
307 else if(META_INDEX_MASKOUT(meta_index) == META_NS_EXIF) {
311 LOGERR(
"Unknown Meta Namespace\n");
314 LOGDBG1(
"Meta value for %u\n", META_NS_MASKOUT(meta_index));
316 IfdEntry::Ref e = ifd->getEntry(META_NS_MASKOUT(meta_index));
318 val = e->make_meta_value();
328 return (uint32_t)tiff_compression;
336 m_cfaIfd = _locateCfaIfd();
342 const IfdDir::Ref & IfdFile::mainIfd()
345 m_mainIfd = _locateMainIfd();
351 const IfdDir::Ref & IfdFile::exifIfd()
354 m_exifIfd = _locateExifIfd();
360 const MakerNoteDir::Ref & IfdFile::makerNoteIfd()
362 if(!m_makerNoteIfd) {
363 m_makerNoteIfd = _locateMakerNoteIfd();
365 return m_makerNoteIfd;
372 _convertArrayToCfaPattern(
const std::vector<uint8_t> &cfaPattern)
374 ::or_cfa_pattern cfa_pattern = OR_CFA_PATTERN_NON_RGB22;
375 if(cfaPattern.size() != 4) {
376 LOGWARN(
"Unsupported bayer pattern\n");
379 LOGDBG2(
"pattern is = %d, %d, %d, %d\n", cfaPattern[0],
380 cfaPattern[1], cfaPattern[2], cfaPattern[3]);
381 switch(cfaPattern[0]) {
383 if ((cfaPattern[1] == IFD::CFA_GREEN)
384 && (cfaPattern[2] == IFD::CFA_GREEN)
385 && (cfaPattern[3] == IFD::CFA_BLUE)) {
386 cfa_pattern = OR_CFA_PATTERN_RGGB;
390 switch(cfaPattern[1]) {
392 if ((cfaPattern[2] == IFD::CFA_BLUE)
393 && (cfaPattern[3] == IFD::CFA_GREEN)) {
394 cfa_pattern = OR_CFA_PATTERN_GRBG;
398 if ((cfaPattern[2] == IFD::CFA_RED)
399 && (cfaPattern[3] == IFD::CFA_GREEN)) {
400 cfa_pattern = OR_CFA_PATTERN_GBRG;
406 if ((cfaPattern[1] ==IFD::CFA_GREEN)
407 && (cfaPattern[2] == IFD::CFA_GREEN)
408 && (cfaPattern[3] == IFD::CFA_RED)) {
409 cfa_pattern = OR_CFA_PATTERN_BGGR;
418 ::or_cfa_pattern _convertNewCfaPattern(
const IfdEntry::Ref & e)
420 ::or_cfa_pattern cfa_pattern = OR_CFA_PATTERN_NONE;
421 if(!e || (e->count() < 4)) {
427 if(hdim != 2 && vdim != 2) {
428 cfa_pattern = OR_CFA_PATTERN_NON_RGB22;
431 std::vector<uint8_t> cfaPattern;
436 cfa_pattern = _convertArrayToCfaPattern(cfaPattern);
445 ::or_cfa_pattern cfa_pattern = OR_CFA_PATTERN_NONE;
447 auto result = e->getArray<uint8_t>();
449 cfa_pattern = _convertArrayToCfaPattern(result.unwrap());
460 static ::or_cfa_pattern _getCfaPattern(
const IfdDir::Ref & dir)
462 LOGDBG1(
"%s\n", __FUNCTION__);
463 ::or_cfa_pattern cfa_pattern = OR_CFA_PATTERN_NONE;
467 cfa_pattern = _convertCfaPattern(e);
470 e = dir->getEntry(IFD::EXIF_TAG_NEW_CFA_PATTERN);
472 cfa_pattern = _convertNewCfaPattern(e);
478 LOGERR(
"Exception in _getCfaPattern().\n");
488 ::or_error ret = OR_ERROR_NONE;
489 const IfdDir::Ref & _cfaIfd = cfaIfd();
490 LOGDBG1(
"_getRawData()\n");
493 ret = _getRawDataFromDir(data, _cfaIfd);
494 if (ret != OR_ERROR_NONE) {
497 ret = _decompressIfNeeded(data, options);
500 ret = OR_ERROR_NOT_FOUND;
505 ::or_error IfdFile::_decompressIfNeeded(
RawData&, uint32_t)
507 return OR_ERROR_NONE;
513 ::or_error ret = OR_ERROR_NONE;
516 uint32_t byte_length = 0;
519 LOGERR(
"dir is NULL\n");
520 return OR_ERROR_NOT_FOUND;
522 auto result = dir->getValue<uint16_t>(IFD::EXIF_TAG_BITS_PER_SAMPLE);
524 LOGERR(
"unable to guess Bits per sample\n");
526 uint16_t bpc = result.unwrap_or(0);
528 auto result2 = dir->getValue<uint32_t>(IFD::EXIF_TAG_STRIP_OFFSETS);
530 offset = result2.unwrap();
531 IfdEntry::Ref e = dir->getEntry(IFD::EXIF_TAG_STRIP_BYTE_COUNTS);
533 LOGDBG1(
"byte len not found\n");
534 return OR_ERROR_NOT_FOUND;
536 auto result3 = e->getArray<uint32_t>();
538 std::vector<uint32_t> counts = result3.unwrap();
539 LOGDBG1(
"counting tiles\n");
540 byte_length = std::accumulate(counts.cbegin(), counts.cend(), 0);
548 LOGDBG1(
"tile offsets empty\n");
549 return OR_ERROR_NOT_FOUND;
551 auto result3 = e->getArray<uint32_t>();
552 if (result3.empty()) {
553 LOGDBG1(
"tile offsets not found\n");
554 return OR_ERROR_NOT_FOUND;
556 std::vector<uint32_t> offsets = result3.unwrap();
558 e = dir->getEntry(IFD::TIFF_TAG_TILE_BYTECOUNTS);
560 LOGDBG1(
"tile byte counts not found\n");
561 return OR_ERROR_NOT_FOUND;
563 result3 = e->getArray<uint32_t>();
565 std::vector<uint32_t> counts = result3.unwrap();
566 LOGDBG1(
"counting tiles\n");
567 byte_length = std::accumulate(counts.cbegin(), counts.cend(), 0);
571 result2 = dir->getIntegerValue(IFD::EXIF_TAG_IMAGE_WIDTH);
572 if(result2.empty()) {
573 LOGDBG1(
"X not found\n");
574 return OR_ERROR_NOT_FOUND;
576 uint32_t x = result2.unwrap();
578 result2 = dir->getIntegerValue(IFD::EXIF_TAG_IMAGE_LENGTH);
579 if(result2.empty()) {
580 LOGDBG1(
"Y not found\n");
581 return OR_ERROR_NOT_FOUND;
583 uint32_t y = result2.unwrap();
586 = dir->getIntegerValue(IFD::EXIF_TAG_PHOTOMETRIC_INTERPRETATION)
587 .unwrap_or(IFD::EV_PI_CFA);
589 BitmapData::DataType data_type = OR_DATA_TYPE_NONE;
591 result = dir->getValue<uint16_t>(IFD::EXIF_TAG_COMPRESSION);
593 LOGDBG1(
"Compression type not found\n");
595 uint32_t compression = _translateCompressionType(
596 static_cast<IFD::TiffCompress>(result.unwrap_or(0)));
600 case IFD::COMPRESS_NONE:
601 data_type = OR_DATA_TYPE_RAW;
603 case IFD::COMPRESS_NIKON_PACK:
604 data_type = OR_DATA_TYPE_RAW;
606 case IFD::COMPRESS_NIKON_QUANTIZED:
610 compression = IFD::COMPRESS_NIKON_PACK;
611 data_type = OR_DATA_TYPE_RAW;
620 data_type = OR_DATA_TYPE_COMPRESSED_RAW;
624 LOGDBG1(
"RAW Compression is %u\n", compression);
625 LOGDBG1(
"bpc is %u\n", bpc);
627 ::or_cfa_pattern cfa_pattern = _getCfaPattern(dir);
628 if(cfa_pattern == OR_CFA_PATTERN_NONE) {
631 m_exifIfd = _locateExifIfd();
633 cfa_pattern = _getCfaPattern(m_exifIfd);
637 if((bpc == 12 || bpc == 14) && (compression == IFD::COMPRESS_NONE)
638 && (byte_length == (x * y * 2))) {
640 LOGDBG1(
"setting bpc from %u to 16\n", bpc);
643 if((bpc == 16) || (data_type == OR_DATA_TYPE_COMPRESSED_RAW)) {
644 void *p = data.allocData(byte_length);
645 size_t real_size = m_container->fetchData(p, offset,
647 if (real_size < byte_length) {
648 LOGWARN(
"Size mismatch for data: ignoring.\n");
651 else if((bpc == 12) || (bpc == 8)) {
652 ret = _unpackData(bpc, compression, data, x, y, offset, byte_length);
653 LOGDBG1(
"unpack result %d\n", ret);
656 LOGERR(
"Unsupported bpc %u\n", bpc);
657 return OR_ERROR_INVALID_FORMAT;
659 data.setCfaPatternType(cfa_pattern);
662 data.setCompression(data_type == OR_DATA_TYPE_COMPRESSED_RAW
664 data.setPhotometricInterpretation((ExifPhotometricInterpretation)photo_int);
665 if((data_type == OR_DATA_TYPE_RAW) && (data.whiteLevel() == 0)) {
666 data.setWhiteLevel((1 << bpc) - 1);
676 uint32_t x, uint32_t y, uint32_t offset, uint32_t byte_length)
678 ::or_error ret = OR_ERROR_NONE;
680 uint32_t current_offset = offset;
681 Unpack unpack(x, compression);
682 const size_t blocksize = (bpc == 8 ? x : unpack.block_size());
683 LOGDBG1(
"Block size = %lu\n", blocksize);
684 LOGDBG1(
"dimensions (x, y) %u, %u\n", x, y);
685 std::unique_ptr<uint8_t[]> block(
new uint8_t[blocksize]);
686 size_t outsize = x * y * 2;
687 uint8_t * outdata = (uint8_t*)data.allocData(outsize);
689 LOGDBG1(
"offset of RAW data = %u\n", current_offset);
691 got = m_container->fetchData (block.get(),
692 current_offset, blocksize);
695 current_offset += got;
704 if(ret != OR_ERROR_NONE) {
710 std::copy(block.get(), block.get()+got,
712 outdata += (got << 1);
715 }
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)
void setBpc(uint32_t _bpc)
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