24 #include <boost/scoped_ptr.hpp>
25 #include <boost/scoped_array.hpp>
27 #include <libopenraw++/thumbnail.h>
28 #include <libopenraw++/rawdata.h>
31 #include "io/stream.h"
32 #include "io/streamclone.h"
36 #include "ifdfilecontainer.h"
37 #include "jfifcontainer.h"
39 #include "metavalue.h"
42 using namespace Debug;
43 using boost::scoped_ptr;
50 IFDFile::IFDFile(IO::Stream *s, Type _type,
51 bool instantiateContainer)
57 if(instantiateContainer) {
58 m_container =
new IFDFileContainer(m_io, 0);
70 IFDDir::Ref IFDFile::_locateExifIfd()
74 Trace(ERROR) <<
"IFDFile::_locateExifIfd() "
75 "main IFD not found\n";
82 void IFDFile::_identifyId()
88 Trace(ERROR) <<
"Main IFD not found to identify the file.\n";
92 if(
m_mainIfd->getValue(IFD::EXIF_TAG_MODEL, model)) {
101 ::or_error err = OR_ERROR_NONE;
103 Trace(DEBUG1) <<
"_enumThumbnailSizes()\n";
105 std::vector<IFDDir::Ref>::iterator iter;
107 Trace(DEBUG1) <<
"num of dirs " << dirs.size() <<
"\n";
108 for(iter = dirs.begin(); iter != dirs.end(); ++iter)
110 IFDDir::Ref & dir = *iter;
113 if (ret == OR_ERROR_NONE)
115 Trace(DEBUG1) <<
"Found " << list.back() <<
" pixels\n";
117 std::vector<IFDDir::Ref> subdirs;
118 if(dir->getSubIFDs(subdirs)) {
119 Trace(DEBUG1) <<
"Iterating subdirs\n";
120 std::vector<IFDDir::Ref>::iterator iter2;
121 for(iter2 = subdirs.begin(); iter2 != subdirs.end();
124 IFDDir::Ref & dir2 = *iter2;
127 if (ret == OR_ERROR_NONE)
129 Trace(DEBUG1) <<
"Found " << list.back() <<
" pixels\n";
134 if (list.size() <= 0) {
135 err = OR_ERROR_NOT_FOUND;
142 std::vector<uint32_t> &list)
144 ::or_error ret = OR_ERROR_NOT_FOUND;
148 ::or_data_type _type = OR_DATA_TYPE_NONE;
149 uint32_t subtype = 0;
151 Trace(DEBUG1) <<
"_locateThumbnail\n";
153 got_it = dir->getValue(IFD::EXIF_TAG_NEW_SUBFILE_TYPE, subtype);
154 Trace(DEBUG1) <<
"subtype " << subtype <<
"\n";
160 return OR_ERROR_NOT_FOUND;
168 uint16_t photom_int = 0;
169 got_it = dir->getValue(IFD::EXIF_TAG_PHOTOMETRIC_INTERPRETATION,
173 Trace(DEBUG1) <<
"photometric int " << photom_int <<
"\n";
178 Trace(DEBUG1) <<
"assume photometric int is RGB\n";
181 got_it = dir->getIntegerValue(IFD::EXIF_TAG_IMAGE_WIDTH, x);
182 got_it = dir->getIntegerValue(IFD::EXIF_TAG_IMAGE_LENGTH, y);
184 uint16_t compression = 0;
185 got_it = dir->getValue(IFD::EXIF_TAG_COMPRESSION, compression);
188 got_it = dir->getValue(IFD::EXIF_TAG_STRIP_OFFSETS, offset);
189 if (!got_it || (compression == 6) || (compression == 7)) {
191 got_it = dir->getValue(IFD::EXIF_TAG_JPEG_INTERCHANGE_FORMAT,
197 uint32_t byte_count = 0;
198 if(x && y && dir->getValue(IFD::EXIF_TAG_STRIP_BYTE_COUNTS, byte_count)) {
199 if(byte_count >= (x * y * 3)) {
200 _type = OR_DATA_TYPE_PIXMAP_8RGB;
203 _type = OR_DATA_TYPE_JPEG;
207 _type = OR_DATA_TYPE_JPEG;
208 Trace(DEBUG1) <<
"looking for JPEG at " << offset <<
"\n";
209 if (x == 0 || y == 0) {
211 scoped_ptr<JFIFContainer> jfif(
new JFIFContainer(s.get(), 0));
212 if (jfif->getDimensions(x,y)) {
213 Trace(DEBUG1) <<
"JPEG dimensions x=" << x
214 <<
" y=" << y <<
"\n";
217 _type = OR_DATA_TYPE_NONE;
218 Trace(WARNING) <<
"Couldn't get JPEG "
223 Trace(DEBUG1) <<
"JPEG (supposed) dimensions x=" << x
224 <<
" y=" << y <<
"\n";
230 else if (photom_int == 6) {
231 Trace(WARNING) <<
"Unsupported YCbCr photometric "
232 "interpretation in non JPEG.\n";
233 ret = OR_ERROR_INVALID_FORMAT;
236 Trace(DEBUG1) <<
"found strip offsets\n";
237 if (x != 0 && y != 0) {
238 _type = OR_DATA_TYPE_PIXMAP_8RGB;
241 if(_type != OR_DATA_TYPE_NONE) {
242 uint32_t dim = std::max(x, y);
253 ::or_error IFDFile::_getThumbnail(uint32_t size,
Thumbnail & thumbnail)
255 ::or_error ret = OR_ERROR_NOT_FOUND;
256 ThumbLocations::iterator iter = m_thumbLocations.find(size);
257 if(iter != m_thumbLocations.end())
263 uint32_t byte_length= 0;
270 case OR_DATA_TYPE_JPEG:
272 ->getValue(IFD::EXIF_TAG_JPEG_INTERCHANGE_FORMAT_LENGTH,
276 ->getValue(IFD::EXIF_TAG_JPEG_INTERCHANGE_FORMAT,
282 ->getValue(IFD::EXIF_TAG_STRIP_OFFSETS, offset);
284 ->getValue(IFD::EXIF_TAG_STRIP_BYTE_COUNTS, byte_length);
287 case OR_DATA_TYPE_PIXMAP_8RGB:
289 ->getValue(IFD::EXIF_TAG_STRIP_OFFSETS, offset);
291 ->getValue(IFD::EXIF_TAG_STRIP_BYTE_COUNTS, byte_length);
294 ->getIntegerValue(IFD::EXIF_TAG_IMAGE_WIDTH, x);
296 ->getIntegerValue(IFD::EXIF_TAG_IMAGE_LENGTH, y);
301 if (byte_length != 0) {
302 void *p = thumbnail.allocData(byte_length);
305 if (real_size < byte_length) {
306 Trace(WARNING) <<
"Size mismatch for data: ignoring.\n";
318 MetaValue *IFDFile::_getMetaValue(int32_t meta_index)
320 MetaValue * val = NULL;
322 if(META_INDEX_MASKOUT(meta_index) == META_NS_TIFF) {
328 else if(META_INDEX_MASKOUT(meta_index) == META_NS_EXIF) {
335 Trace(ERROR) <<
"Unknown Meta Namespace\n";
338 Trace(DEBUG1) <<
"Meta value for "
339 << META_NS_MASKOUT(meta_index) <<
"\n";
341 IFDEntry::Ref e = ifd->getEntry(META_NS_MASKOUT(meta_index));
343 val =
new MetaValue(e);
353 _convertArrayToCfaPattern(
const std::vector<uint8_t> &cfaPattern)
355 RawData::CfaPattern cfa_pattern = OR_CFA_PATTERN_NON_RGB22;
356 if(cfaPattern.size() != 4) {
357 Trace(WARNING) <<
"Unsupported bayer pattern\n";
360 Trace(DEBUG2) <<
"patter is = " << cfaPattern[0] <<
", "
361 << cfaPattern[1] <<
", " << cfaPattern[2]
362 <<
", " << cfaPattern[3] <<
"\n";
363 switch(cfaPattern[0]) {
365 switch(cfaPattern[1]) {
367 if((cfaPattern[2] == IFD::CFA_GREEN)
368 && (cfaPattern[3] == IFD::CFA_BLUE))
370 cfa_pattern = OR_CFA_PATTERN_RGGB;
376 switch(cfaPattern[1]) {
378 if((cfaPattern[2] == 2)
379 && (cfaPattern[3] == IFD::CFA_GREEN))
381 cfa_pattern = OR_CFA_PATTERN_GRBG;
385 if((cfaPattern[2] == IFD::CFA_RED)
386 && (cfaPattern[3] == IFD::CFA_GREEN))
388 cfa_pattern = OR_CFA_PATTERN_GBRG;
394 switch(cfaPattern[1]) {
396 if((cfaPattern[2] == IFD::CFA_GREEN)
397 && (cfaPattern[3] == IFD::CFA_RED))
399 cfa_pattern = OR_CFA_PATTERN_BGGR;
410 RawData::CfaPattern _convertNewCfaPattern(
const IFDEntry::Ref & e)
412 RawData::CfaPattern cfa_pattern = OR_CFA_PATTERN_NONE;
413 if(!e || (e->count() < 4)) {
419 if(hdim != 2 && vdim != 2) {
420 cfa_pattern = OR_CFA_PATTERN_NON_RGB22;
423 std::vector<uint8_t> cfaPattern;
424 cfaPattern.push_back(IFDTypeTrait<uint8_t>::get(*e, 4,
true));
425 cfaPattern.push_back(IFDTypeTrait<uint8_t>::get(*e, 5,
true));
426 cfaPattern.push_back(IFDTypeTrait<uint8_t>::get(*e, 6,
true));
427 cfaPattern.push_back(IFDTypeTrait<uint8_t>::get(*e, 7,
true));
428 cfa_pattern = _convertArrayToCfaPattern(cfaPattern);
435 RawData::CfaPattern _convertCfaPattern(
const IFDEntry::Ref & e)
437 std::vector<uint8_t> cfaPattern;
438 RawData::CfaPattern cfa_pattern = OR_CFA_PATTERN_NONE;
440 e->getArray(cfaPattern);
441 if(!cfaPattern.empty()) {
442 cfa_pattern = _convertArrayToCfaPattern(cfaPattern);
452 static RawData::CfaPattern _getCfaPattern(
const IFDDir::Ref & dir)
454 Trace(DEBUG1) << __FUNCTION__ <<
"\n";
455 RawData::CfaPattern cfa_pattern = OR_CFA_PATTERN_NONE;
459 cfa_pattern = _convertCfaPattern(e);
462 e = dir->getEntry(IFD::EXIF_TAG_NEW_CFA_PATTERN);
464 cfa_pattern = _convertNewCfaPattern(e);
470 Trace(ERROR) <<
"Exception in _getCfaPattern().\n";
479 ::or_error ret = OR_ERROR_NONE;
483 uint32_t byte_length = 0;
490 Trace(ERROR) <<
"dir is NULL\n";
491 return OR_ERROR_NOT_FOUND;
493 got_it = dir->getValue(IFD::EXIF_TAG_BITS_PER_SAMPLE, bpc);
495 Trace(ERROR) <<
"unable to guess Bits per sample\n";
498 got_it = dir->getValue(IFD::EXIF_TAG_STRIP_OFFSETS, offset);
500 IFDEntry::Ref e = dir->getEntry(IFD::EXIF_TAG_STRIP_BYTE_COUNTS);
502 std::vector<uint32_t> counts;
504 Trace(DEBUG1) <<
"counting tiles\n";
505 byte_length = std::accumulate(counts.begin(), counts.end(), 0);
508 Trace(DEBUG1) <<
"byte len not found\n";
509 return OR_ERROR_NOT_FOUND;
517 std::vector<uint32_t> offsets;
518 e->getArray(offsets);
519 if(offsets.size() > 1) {
523 Trace(DEBUG1) <<
"tile offsets empty\n";
524 return OR_ERROR_NOT_FOUND;
528 Trace(DEBUG1) <<
"tile offsets not found\n";
529 return OR_ERROR_NOT_FOUND;
531 e = dir->getEntry(IFD::TIFF_TAG_TILE_BYTECOUNTS);
533 std::vector<uint32_t> counts;
535 Trace(DEBUG1) <<
"counting tiles\n";
536 byte_length = std::accumulate(counts.begin(), counts.end(), 0);
539 Trace(DEBUG1) <<
"tile byte counts not found\n";
540 return OR_ERROR_NOT_FOUND;
543 got_it = dir->getIntegerValue(IFD::EXIF_TAG_IMAGE_WIDTH, x);
545 Trace(DEBUG1) <<
"X not found\n";
546 return OR_ERROR_NOT_FOUND;
548 got_it = dir->getIntegerValue(IFD::EXIF_TAG_IMAGE_LENGTH, y);
550 Trace(DEBUG1) <<
"Y not found\n";
551 return OR_ERROR_NOT_FOUND;
554 uint32_t compression = 0;
555 got_it = dir->getIntegerValue(IFD::EXIF_TAG_COMPRESSION, compression);
558 Trace(DEBUG1) <<
"Compression type not found\n";
560 BitmapData::DataType data_type = OR_DATA_TYPE_NONE;
564 case IFD::COMPRESS_NONE:
565 data_type = OR_DATA_TYPE_CFA;
567 case IFD::COMPRESS_NIKON_PACK:
568 data_type = OR_DATA_TYPE_CFA;
570 case IFD::COMPRESS_NIKON_QUANTIZED:
574 compression = IFD::COMPRESS_NIKON_PACK;
575 data_type = OR_DATA_TYPE_CFA;
584 data_type = OR_DATA_TYPE_COMPRESSED_CFA;
588 Trace(DEBUG1) <<
"RAW Compression is " << compression <<
"\n";
590 RawData::CfaPattern cfa_pattern = _getCfaPattern(dir);
591 if(cfa_pattern == OR_CFA_PATTERN_NONE) {
600 if((bpc == 12 || bpc == 14) && (compression == 1)
601 && (byte_length == (x * y * 2)))
603 Trace(DEBUG1) <<
"setting bpc from " << bpc
607 if((bpc == 16) || (data_type == OR_DATA_TYPE_COMPRESSED_CFA)) {
608 void *p = data.allocData(byte_length);
611 if (real_size < byte_length) {
612 Trace(WARNING) <<
"Size mismatch for data: ignoring.\n";
615 else if((bpc == 12) || (bpc == 8)) {
617 Unpack unpack(x, compression);
618 const size_t blocksize = (bpc == 8 ? x : unpack.block_size());
619 Trace(DEBUG1) <<
"Block size = " << blocksize <<
"\n";
620 Trace(DEBUG1) <<
"dimensions (x, y) " << x <<
", "
622 boost::scoped_array<uint8_t> block(
new uint8_t[blocksize]);
623 uint8_t * outdata = (uint8_t*)data.allocData(x * y * 2);
625 Trace(DEBUG1) <<
"offset of RAW data = " << offset <<
"\n";
640 std::copy(block.get(), block.get()+got,
642 outdata += (got << 1);
645 }
while((got != 0) && (fetched < byte_length));
648 Trace(ERROR) <<
"Unsupported bpc " << bpc <<
"\n";
649 return OR_ERROR_INVALID_FORMAT;
651 data.setCfaPattern(cfa_pattern);
653 data.setCompression(data_type == OR_DATA_TYPE_COMPRESSED_CFA
655 if((data_type == OR_DATA_TYPE_CFA) && (data.max() == 0)) {
656 data.setMax((1 << bpc) - 1);
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)
IFDFileContainer * m_container
virtual ::or_error _locateThumbnail(const IFDDir::Ref &dir, std::vector< uint32_t > &list)
size_t fetchData(void *buf, const off_t offset, const size_t buf_size)
virtual void setDimensions(uint32_t x, uint32_t y)
virtual ::or_error _enumThumbnailSizes(std::vector< uint32_t > &list)
void _setTypeId(TypeId _type_id)
cloned stream. Allow reading from a different offset
virtual void setDimensions(uint32_t x, uint32_t y)
std::vector< IFDDir::Ref > & directories()
void setDataType(DataType _type)
size_t unpack_be12to16(uint8_t *dest, const uint8_t *src, size_t size)
boost::shared_ptr< IFDEntry > Ref
static bool isCompressed(RawContainer &container, uint32_t offset)
::or_error _getRawDataFromDir(RawData &data, IFDDir::Ref &dir)