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"
48 #include "xtranspattern.hpp"
58 bool instantiateContainer)
63 if(instantiateContainer) {
64 m_container =
new IfdFileContainer(m_io, 0);
81 auto ifd = m_container->setDirectory(0);
93 void IfdFile::_identifyId()
99 if (vendorCameraIdLocation(ifd, index, model_map) && ifd) {
100 auto id = ifd->getIntegerValue(index);
102 auto id_value =
id.value();
103 auto type_id = modelid_to_typeid(*model_map, id_value);
108 LOGERR(
"unknown model ID 0x%x (%u)\n", id_value, id_value);
115 LOGERR(
"Main IFD not found to identify the file.\n");
119 auto make = _mainIfd->getValue<std::string>(IFD::EXIF_TAG_MAKE);
120 auto model = _mainIfd->getValue<std::string>(IFD::EXIF_TAG_MODEL);
123 model = _mainIfd->getValue<std::string>(IFD::DNG_TAG_UNIQUE_CAMERA_MODEL);
129 _setTypeId(_typeIdFromModel(make.value(), model.value()));
133 ::or_error IfdFile::_addThumbnailFromStream(uint32_t offset, uint32_t len,
134 std::vector<uint32_t>& list)
137 LOGDBG1(
"fetching JPEG\n");
139 auto jfif = std::make_unique<JfifContainer>(s, 0);
143 jfif->getDimensions(x, y);
144 LOGDBG1(
"JPEG dimensions x=%d y=%d\n", x, y);
146 uint32_t dim = std::max(x, y);
149 if (dim && std::find(list.begin(), list.end(), dim) == list.end()) {
159 std::vector<uint32_t>& list)
163 auto val_offset = e->offset();
165 val_offset += offset;
167 err =_addThumbnailFromStream(val_offset, e->count(), list);
173 IfdFile::_enumThumbnailSizes(std::vector<uint32_t> &list)
177 LOGDBG1(
"_enumThumbnailSizes()\n");
178 std::vector<IfdDir::Ref> & dirs = m_container->directories();
180 LOGDBG1(
"num of dirs %lu\n", (LSIZE)dirs.size());
184 or_error ret = _locateThumbnail(dir, list);
186 LOGDBG1(
"Found %u pixels\n", list.back());
188 auto result = dir->getSubIFDs();
190 std::vector<IfdDir::Ref> subdirs = result.value();
191 LOGDBG1(
"Iterating subdirs\n");
192 for(
auto dir2 : subdirs)
195 ret = _locateThumbnail(dir2, list);
197 LOGDBG1(
"Found %u pixels\n", list.back());
202 if (list.size() <= 0) {
210 std::vector<uint32_t> &list)
214 uint32_t subtype = 0;
216 LOGDBG1(
"_locateThumbnail\n");
218 auto result = dir->getValue<uint32_t>(IFD::EXIF_TAG_NEW_SUBFILE_TYPE);
219 if (result.empty()) {
220 if (cfaIfd() == dir) {
227 subtype = result.value();
229 LOGDBG1(
"subtype %u\n", subtype);
232 uint16_t photom_int =
233 dir->getValue<uint16_t>(IFD::EXIF_TAG_PHOTOMETRIC_INTERPRETATION).value_or(IFD::EV_PI_RGB);
235 uint32_t x = dir->getIntegerValue(IFD::EXIF_TAG_IMAGE_WIDTH).value_or(0);
236 uint32_t y = dir->getIntegerValue(IFD::EXIF_TAG_IMAGE_LENGTH).value_or(0);
238 uint16_t compression = dir->getValue<uint16_t>(IFD::EXIF_TAG_COMPRESSION).value_or(0);
241 uint32_t byte_count = dir->getValue<uint32_t>(IFD::EXIF_TAG_STRIP_BYTE_COUNTS).value_or(0);
243 result = dir->getValue<uint32_t>(IFD::EXIF_TAG_STRIP_OFFSETS);
244 bool got_it = result.has_value();
246 offset = result.value();
248 if (!got_it || (compression == 6) || (compression == 7)) {
251 dir->getValue<uint32_t>(IFD::EXIF_TAG_JPEG_INTERCHANGE_FORMAT_LENGTH).value_or(0);
252 result = dir->getValue<uint32_t>(IFD::EXIF_TAG_JPEG_INTERCHANGE_FORMAT);
253 got_it = result.has_value();
255 offset = result.value();
262 if(byte_count >= (x * y * 3)) {
264 _type = OR_DATA_TYPE_NONE;
266 LOGDBG1(
"8RGB as JPEG. Will ignore.\n");
275 LOGDBG1(
"looking for JPEG at %u\n", offset);
276 if (x == 0 || y == 0) {
277 auto s =std::make_shared<IO::StreamClone>(m_io, offset);
278 auto jfif = std::make_unique<JfifContainer>(s, 0);
279 if (jfif->getDimensions(x,y)) {
280 LOGDBG1(
"JPEG dimensions x=%u y=%u\n", x, y);
283 _type = OR_DATA_TYPE_NONE;
284 LOGWARN(
"Couldn't get JPEG dimensions.\n");
288 LOGDBG1(
"JPEG (supposed) dimensions x=%u y=%u\n", x, y);
294 else if (photom_int == IFD::EV_PI_YCBCR) {
295 LOGWARN(
"Unsupported YCbCr photometric interpretation in non JPEG.\n");
299 LOGDBG1(
"found strip offsets\n");
300 if (x != 0 && y != 0) {
304 IfdEntry::Ref entry = dir->getEntry(IFD::EXIF_TAG_BITS_PER_SAMPLE);
305 auto result2 = dir->getEntryArrayValue<uint16_t>(*entry);
307 std::vector<uint16_t> arr = result2.value();
308 for(
auto bpc : arr) {
311 LOGDBG1(
"bpc != 8, not RGB8 %u\n", bpc);
316 LOGDBG1(
"Error getting BPS\n");
323 if(_type != OR_DATA_TYPE_NONE) {
324 uint32_t dim = std::max(x, y);
325 offset += dir->container().offset();
326 _addThumbnail(dim,
ThumbDesc(x, y, _type,
327 offset, byte_count));
341 uint32_t IfdFile::_getJpegThumbnailOffset(
const IfdDir::Ref & dir, uint32_t & byte_length)
343 auto result = dir->getValue<uint32_t>(IFD::EXIF_TAG_JPEG_INTERCHANGE_FORMAT_LENGTH);
345 byte_length = result.value();
346 return dir->getValue<uint32_t>(IFD::EXIF_TAG_JPEG_INTERCHANGE_FORMAT).value_or(0);
350 byte_length = dir->getValue<uint32_t>(IFD::EXIF_TAG_STRIP_BYTE_COUNTS).value_or(0);
351 return dir->getValue<uint32_t>(IFD::EXIF_TAG_STRIP_OFFSETS).value_or(0);
367 LOGERR(
"Unknown Meta Namespace\n");
374 val = ifd->makeMetaValue(*e);
384 return (uint32_t)tiff_compression;
390 _convertArrayToCfaPattern(
const std::vector<uint8_t> &cfaPattern)
393 if(cfaPattern.size() != 4) {
394 if (cfaPattern.size() == 36) {
396 return XTransPattern::xtransPattern();
398 LOGWARN(
"Unsupported bayer pattern of size %lu\n", (LSIZE)cfaPattern.size());
400 LOGDBG2(
"pattern is = %d, %d, %d, %d\n", cfaPattern[0],
401 cfaPattern[1], cfaPattern[2], cfaPattern[3]);
402 switch(cfaPattern[0]) {
404 if ((cfaPattern[1] == IFD::CFA_GREEN)
405 && (cfaPattern[2] == IFD::CFA_GREEN)
406 && (cfaPattern[3] == IFD::CFA_BLUE)) {
407 cfa_pattern = OR_CFA_PATTERN_RGGB;
411 switch(cfaPattern[1]) {
413 if ((cfaPattern[2] == IFD::CFA_BLUE)
414 && (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)) {
421 cfa_pattern = OR_CFA_PATTERN_GBRG;
427 if ((cfaPattern[1] ==IFD::CFA_GREEN)
428 && (cfaPattern[2] == IFD::CFA_GREEN)
429 && (cfaPattern[3] == IFD::CFA_RED)) {
430 cfa_pattern = OR_CFA_PATTERN_BGGR;
435 return MosaicInfo::twoByTwoPattern(cfa_pattern);
440 const MosaicInfo *_convertNewCfaPattern(
const IfdDir::Ref& dir, IfdEntry& e)
446 uint16_t hdim = dir->getEntryValue<uint16_t>(e, 0,
true);
447 uint16_t vdim = dir->getEntryValue<uint16_t>(e, 1,
true);
448 if(hdim != 2 && vdim != 2) {
450 if (hdim != 6 && vdim != 6) {
451 LOGWARN(
"CFA pattern dimension %dx%d are incompatible", hdim, vdim);
454 return XTransPattern::xtransPattern();
456 std::vector<uint8_t> cfaPattern;
457 cfaPattern.push_back(dir->getEntryValue<uint8_t>(e, 4,
true));
458 cfaPattern.push_back(dir->getEntryValue<uint8_t>(e, 5,
true));
459 cfaPattern.push_back(dir->getEntryValue<uint8_t>(e, 6,
true));
460 cfaPattern.push_back(dir->getEntryValue<uint8_t>(e, 7,
true));
461 return _convertArrayToCfaPattern(cfaPattern);
467 const MosaicInfo *_convertCfaPattern(
const IfdDir::Ref& dir, IfdEntry& e)
469 LOGDBG1(
"%s\n", __FUNCTION__);
470 auto result = dir->getEntryArrayValue<uint8_t>(e);
472 return _convertArrayToCfaPattern(result.value());
483 const MosaicInfo *_getMosaicInfo(
const IfdDir::Ref & dir)
485 LOGDBG1(
"%s\n", __FUNCTION__);
486 const MosaicInfo *mosaic_info =
nullptr;
488 IfdEntry::Ref e = dir->getEntry(IFD::EXIF_TAG_CFA_PATTERN);
490 mosaic_info = _convertCfaPattern(dir, *e);
492 e = dir->getEntry(IFD::EXIF_TAG_NEW_CFA_PATTERN);
494 mosaic_info = _convertNewCfaPattern(dir, *e);
500 LOGERR(
"Exception in _getCfaPattern().\n");
512 LOGDBG1(
"_getRawData()\n");
515 ret = _getRawDataFromDir(data, _cfaIfd);
519 ret = _decompressIfNeeded(data, options);
538 uint32_t byte_length = 0;
541 LOGERR(
"dir is NULL\n");
544 auto result = dir->getValue<uint16_t>(IFD::EXIF_TAG_BITS_PER_SAMPLE);
546 LOGERR(
"unable to guess Bits per sample\n");
548 uint16_t bpc = result.value_or(0);
550 auto result2 = dir->getValue<uint32_t>(IFD::EXIF_TAG_STRIP_OFFSETS);
552 offset = result2.value();
553 IfdEntry::Ref e = dir->getEntry(IFD::EXIF_TAG_STRIP_BYTE_COUNTS);
555 LOGDBG1(
"byte len not found\n");
558 auto result3 = dir->getEntryArrayValue<uint32_t>(*e);
560 std::vector<uint32_t> counts = result3.value();
561 LOGDBG1(
"counting tiles\n");
562 byte_length = std::accumulate(counts.cbegin(), counts.cend(), 0);
570 LOGDBG1(
"tile offsets empty\n");
573 auto result3 = dir->getEntryArrayValue<uint32_t>(*e);
575 LOGDBG1(
"tile offsets not found\n");
578 std::vector<uint32_t> offsets = result3.value();
580 e = dir->getEntry(IFD::TIFF_TAG_TILE_BYTECOUNTS);
582 LOGDBG1(
"tile byte counts not found\n");
585 result3 = dir->getEntryArrayValue<uint32_t>(*e);
587 std::vector<uint32_t> counts = result3.value();
588 LOGDBG1(
"counting tiles\n");
589 byte_length = std::accumulate(counts.cbegin(), counts.cend(), 0);
593 result2 = dir->getIntegerValue(IFD::EXIF_TAG_IMAGE_WIDTH);
594 if(result2.empty()) {
595 LOGDBG1(
"X not found\n");
598 uint32_t x = result2.value();
600 result2 = dir->getIntegerValue(IFD::EXIF_TAG_IMAGE_LENGTH);
602 LOGDBG1(
"Y not found\n");
605 uint32_t y = result2.value();
608 = dir->getIntegerValue(IFD::EXIF_TAG_PHOTOMETRIC_INTERPRETATION)
609 .value_or(IFD::EV_PI_CFA);
613 result = dir->getValue<uint16_t>(IFD::EXIF_TAG_COMPRESSION);
615 LOGDBG1(
"Compression type not found\n");
617 uint32_t compression = _translateCompressionType(
622 case IFD::COMPRESS_NONE:
625 case IFD::COMPRESS_NIKON_PACK:
626 case IFD::COMPRESS_PENTAX_PACK:
634 LOGDBG1(
"RAW Compression is %u\n", compression);
635 LOGDBG1(
"bpc is %u\n", bpc);
637 const MosaicInfo *mosaic_info = _getMosaicInfo(dir);
640 mosaic_info = _getMosaicInfo(exifIfd());
646 auto actual_bpc = bpc;
647 if((bpc == 12 || bpc == 14) && (compression == IFD::COMPRESS_NONE)
648 && (byte_length == (x * y * 2))) {
650 LOGDBG1(
"setting bpc from %u to 16\n", bpc);
654 void *p = data.allocData(byte_length);
655 size_t real_size = m_container->fetchData(p, offset,
657 if (real_size < byte_length) {
658 LOGWARN(
"Size mismatch for data: ignoring.\n");
661 else if((bpc == 12) || (bpc == 8)) {
662 ret = _unpackData(bpc, compression, data, x, y, offset, byte_length);
663 LOGDBG1(
"unpack result %d\n", ret);
666 LOGERR(
"Unsupported bpc %u\n", bpc);
669 data.setMosaicInfo(mosaic_info);
674 data.setPhotometricInterpretation((ExifPhotometricInterpretation)photo_int);
675 if(data.whiteLevel() == 0) {
676 data.setWhiteLevel((1 << actual_bpc) - 1);
685 IfdFile::_unpackData(uint16_t bpc, uint32_t compression,
RawData & data,
686 uint32_t x, uint32_t y, uint32_t offset, uint32_t byte_length)
690 uint32_t current_offset = offset;
691 Unpack unpack(x, compression);
692 const size_t blocksize = (bpc == 8 ? x : unpack.block_size());
693 LOGDBG1(
"Block size = %lu\n", (LSIZE)blocksize);
694 LOGDBG1(
"dimensions (x, y) %u, %u\n", x, y);
695 auto block = std::make_unique<uint8_t[]>(blocksize);
696 size_t outsize = x * y * 2;
697 uint16_t* outdata = (uint16_t*)data.allocData(outsize);
699 LOGDBG1(
"offset of RAW data = %u\n", current_offset);
701 got = m_container->fetchData (block.get(),
702 current_offset, blocksize);
705 current_offset += got;
718 std::copy(block.get(), block.get() + got, outdata);
722 }
while((got != 0) && (fetched < byte_length));
void setDataType(DataType _type)
Set the data type.
void setBpc(uint32_t _bpc)
Set bit per channel.
std::shared_ptr< Stream > Ptr
std::shared_ptr< IfdDir > Ref
Shared ptr of an IfdDir.
std::shared_ptr< IfdEntry > Ref
IfdEntry reference (ie shared pointer)
Generic interface for the RAW file container.
or_error unpack_be12to16(uint16_t *dest, size_t destsize, const uint8_t *src, size_t size, size_t &outsize) const
Info on the mosaic for the Colour Filter Array.
Represent camera raw data.
virtual void setDimensions(uint32_t x, uint32_t y) override
Set the pixel dimensions of the bitmap.
or_cfa_pattern
CFA pattern types.
or_error
Error codes returned by libopenraw.
@ OR_CFA_PATTERN_NON_RGB22
@ OR_DATA_TYPE_COMPRESSED_RAW
@ OR_DATA_TYPE_PIXMAP_8RGB
@ OR_IFD_MAIN
Main (like in TIFF)
@ OR_ERROR_INVALID_FORMAT
TiffCompress
TIFF compression.
std::map< uint32_t, ::or_rawfile_typeid > ModelIdMap
Global namespace for libopenraw.