libopenraw
ifdfile.cpp
1 /*
2  * libopenraw - ifdfile.cpp
3  *
4  * Copyright (C) 2006-2017 Hubert Figuière
5  * Copyright (C) 2008 Novell, Inc.
6  *
7  * This library is free software: you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public License
9  * as published by the Free Software Foundation, either version 3 of
10  * the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library. If not, see
19  * <http://www.gnu.org/licenses/>.
20  */
21 
22 #include <stddef.h>
23 
24 #include <algorithm>
25 #include <cstdint>
26 #include <exception>
27 #include <memory>
28 #include <numeric>
29 #include <string>
30 
31 #include <libopenraw/consts.h>
32 #include <libopenraw/debug.h>
33 #include <libopenraw/metadata.h>
34 
35 #include "bitmapdata.hpp"
36 #include "rawfile.hpp"
37 #include "rawdata.hpp"
38 #include "trace.hpp"
39 #include "io/stream.hpp"
40 #include "io/streamclone.hpp"
41 #include "ifd.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" // I wonder if this is smart as it break the abstraction.
48 #include "unpack.hpp"
49 
50 namespace OpenRaw {
51 
52 class MetaValue;
53 
54 namespace Internals {
55 
56 
57 IfdFile::IfdFile(const IO::Stream::Ptr &s, Type _type,
58  bool instantiateContainer)
59  : RawFile(_type),
60  m_io(s),
61  m_container(nullptr)
62 {
63  if(instantiateContainer) {
64  m_container = new IfdFileContainer(m_io, 0);
65  }
66 }
67 
68 IfdFile::~IfdFile()
69 {
70  delete m_container;
71 }
72 
73 // this one seems to be pretty much the same for all the
74 // IFD based raw files
75 IfdDir::Ref IfdFile::_locateExifIfd()
76 {
77  const IfdDir::Ref & _mainIfd = mainIfd();
78  if (!_mainIfd) {
79  LOGERR("IfdFile::_locateExifIfd() main IFD not found\n");
80  return IfdDir::Ref();
81  }
82  return _mainIfd->getExifIFD();
83 }
84 
85 MakerNoteDir::Ref IfdFile::_locateMakerNoteIfd()
86 {
87  const IfdDir::Ref & _exifIfd = exifIfd();
88  if(_exifIfd) {
89  // to not have a recursive declaration, getMakerNoteIfd() return an IfdDir.
90  return std::dynamic_pointer_cast<MakerNoteDir>(_exifIfd->getMakerNoteIfd());
91  }
92  return MakerNoteDir::Ref();
93 }
94 
95 void IfdFile::_identifyId()
96 {
97  const IfdDir::Ref & _mainIfd = mainIfd();
98  if (!_mainIfd) {
99  LOGERR("Main IFD not found to identify the file.\n");
100  return;
101  }
102 
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()));
107  }
108 }
109 
110 
111 
112 ::or_error
113 IfdFile::_enumThumbnailSizes(std::vector<uint32_t> &list)
114 {
115  ::or_error err = OR_ERROR_NONE;
116 
117  LOGDBG1("_enumThumbnailSizes()\n");
118  std::vector<IfdDir::Ref> & dirs = m_container->directories();
119 
120  LOGDBG1("num of dirs %lu\n", dirs.size());
121  for(auto dir : dirs)
122  {
123  dir->load();
124  or_error ret = _locateThumbnail(dir, list);
125  if (ret == OR_ERROR_NONE) {
126  LOGDBG1("Found %u pixels\n", list.back());
127  }
128  auto result = dir->getSubIFDs();
129  if (result.ok()) {
130  std::vector<IfdDir::Ref> subdirs = result.unwrap();
131  LOGDBG1("Iterating subdirs\n");
132  for(auto dir2 : subdirs)
133  {
134  dir2->load();
135  ret = _locateThumbnail(dir2, list);
136  if (ret == OR_ERROR_NONE) {
137  LOGDBG1("Found %u pixels\n", list.back());
138  }
139  }
140  }
141  }
142  if (list.size() <= 0) {
143  err = OR_ERROR_NOT_FOUND;
144  }
145  return err;
146 }
147 
148 
149 ::or_error IfdFile::_locateThumbnail(const IfdDir::Ref & dir,
150  std::vector<uint32_t> &list)
151 {
152  ::or_error ret = OR_ERROR_NOT_FOUND;
153  ::or_data_type _type = OR_DATA_TYPE_NONE;
154  uint32_t subtype = 0;
155 
156  LOGDBG1("_locateThumbnail\n");
157 
158  auto result = dir->getValue<uint32_t>(IFD::EXIF_TAG_NEW_SUBFILE_TYPE);
159  if (result.empty()) {
160  if(!m_cfaIfd) {
161  m_cfaIfd = _locateCfaIfd();
162  }
163  if(m_cfaIfd == dir) {
164  return OR_ERROR_NOT_FOUND;
165  }
166  else {
167  subtype = 1;
168  }
169  } else {
170  subtype = result.unwrap();
171  }
172  LOGDBG1("subtype %u\n", subtype);
173  if (subtype == 1) {
174 
175  uint16_t photom_int =
176  dir->getValue<uint16_t>(IFD::EXIF_TAG_PHOTOMETRIC_INTERPRETATION).unwrap_or(IFD::EV_PI_RGB);
177 
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);
180 
181  uint16_t compression = dir->getValue<uint16_t>(IFD::EXIF_TAG_COMPRESSION).unwrap_or(0);
182 
183  uint32_t offset = 0;
184  uint32_t byte_count = dir->getValue<uint32_t>(IFD::EXIF_TAG_STRIP_BYTE_COUNTS).unwrap_or(0);
185 
186  result = dir->getValue<uint32_t>(IFD::EXIF_TAG_STRIP_OFFSETS);
187  bool got_it = result.ok();
188  if (result.ok()) {
189  offset = result.unwrap();
190  }
191  if (!got_it || (compression == 6) || (compression == 7)) {
192  if (!got_it) {
193  byte_count =
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();
197  if (got_it) {
198  offset = result.unwrap();
199  }
200  }
201  if (got_it) {
202  // workaround for CR2 files where 8RGB data is marked
203  // as JPEG. Check the real data size.
204  if(x && y) {
205  if(byte_count >= (x * y * 3)) {
206  //_type = OR_DATA_TYPE_PIXMAP_8RGB;
207  _type = OR_DATA_TYPE_NONE;
208  // See bug 72270
209  LOGDBG1("8RGB as JPEG. Will ignore.\n");
210  ret = OR_ERROR_INVALID_FORMAT;
211  }
212  else {
213  _type = OR_DATA_TYPE_JPEG;
214  }
215  }
216  else {
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>(
221  m_io, offset));
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);
225  }
226  else {
227  _type = OR_DATA_TYPE_NONE;
228  LOGWARN("Couldn't get JPEG dimensions.\n");
229  }
230  }
231  else {
232  LOGDBG1("JPEG (supposed) dimensions x=%u y=%u\n", x, y);
233  }
234  }
235 
236  }
237  }
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;
241  }
242  else {
243  LOGDBG1("found strip offsets\n");
244  if (x != 0 && y != 0) {
245  // See bug 72270 - some CR2 have 16 bpc RGB thumbnails.
246  // by default it is RGB8. Unless stated otherwise.
247  bool isRGB8 = true;
248  IfdEntry::Ref entry = dir->getEntry(IFD::EXIF_TAG_BITS_PER_SAMPLE);
249  auto result2 = entry->getArray<uint16_t>();
250  if (result2.ok()) {
251  std::vector<uint16_t> arr = result2.unwrap();
252  for(auto bpc : arr) {
253  isRGB8 = (bpc == 8);
254  if (!isRGB8) {
255  LOGDBG1("bpc != 8, not RGB8 %u\n", bpc);
256  break;
257  }
258  }
259  } else {
260  LOGDBG1("Error getting BPS\n");
261  }
262  if (isRGB8) {
263  _type = OR_DATA_TYPE_PIXMAP_8RGB;
264  }
265  }
266  }
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));
272  list.push_back(dim);
273  ret = OR_ERROR_NONE;
274  }
275  }
276 
277  return ret;
278 }
279 
281 {
282  return m_container;
283 }
284 
285 uint32_t IfdFile::_getJpegThumbnailOffset(const IfdDir::Ref & dir, uint32_t & byte_length)
286 {
287  auto result = dir->getValue<uint32_t>(IFD::EXIF_TAG_JPEG_INTERCHANGE_FORMAT_LENGTH);
288  if (result.ok()) {
289  byte_length = result.unwrap();
290  return dir->getValue<uint32_t>(IFD::EXIF_TAG_JPEG_INTERCHANGE_FORMAT).unwrap_or(0);
291  }
292 
293  // some case it is STRIP_OFFSETS for JPEG
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);
296 }
297 
298 
299 
300 MetaValue *IfdFile::_getMetaValue(int32_t meta_index)
301 {
302  MetaValue * val = nullptr;
303  IfdDir::Ref ifd;
304  if(META_INDEX_MASKOUT(meta_index) == META_NS_TIFF) {
305  ifd = mainIfd();
306  }
307  else if(META_INDEX_MASKOUT(meta_index) == META_NS_EXIF) {
308  ifd = exifIfd();
309  }
310  else {
311  LOGERR("Unknown Meta Namespace\n");
312  }
313  if(ifd) {
314  LOGDBG1("Meta value for %u\n", META_NS_MASKOUT(meta_index));
315 
316  IfdEntry::Ref e = ifd->getEntry(META_NS_MASKOUT(meta_index));
317  if(e) {
318  val = e->make_meta_value();
319  }
320  }
321  return val;
322 }
323 
326 uint32_t IfdFile::_translateCompressionType(IFD::TiffCompress tiff_compression)
327 {
328  return (uint32_t)tiff_compression;
329 }
330 
331 
332 
333 const IfdDir::Ref & IfdFile::cfaIfd()
334 {
335  if(!m_cfaIfd) {
336  m_cfaIfd = _locateCfaIfd();
337  }
338  return m_cfaIfd;
339 }
340 
341 
342 const IfdDir::Ref & IfdFile::mainIfd()
343 {
344  if(!m_mainIfd) {
345  m_mainIfd = _locateMainIfd();
346  }
347  return m_mainIfd;
348 }
349 
350 
351 const IfdDir::Ref & IfdFile::exifIfd()
352 {
353  if(!m_exifIfd) {
354  m_exifIfd = _locateExifIfd();
355  }
356  return m_exifIfd;
357 }
358 
359 
360 const MakerNoteDir::Ref & IfdFile::makerNoteIfd()
361 {
362  if(!m_makerNoteIfd) {
363  m_makerNoteIfd = _locateMakerNoteIfd();
364  }
365  return m_makerNoteIfd;
366 }
367 
368 
369 namespace {
370 
371 ::or_cfa_pattern
372 _convertArrayToCfaPattern(const std::vector<uint8_t> &cfaPattern)
373 {
374  ::or_cfa_pattern cfa_pattern = OR_CFA_PATTERN_NON_RGB22;
375  if(cfaPattern.size() != 4) {
376  LOGWARN("Unsupported bayer pattern\n");
377  }
378  else {
379  LOGDBG2("pattern is = %d, %d, %d, %d\n", cfaPattern[0],
380  cfaPattern[1], cfaPattern[2], cfaPattern[3]);
381  switch(cfaPattern[0]) {
382  case IFD::CFA_RED:
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;
387  }
388  break;
389  case IFD::CFA_GREEN:
390  switch(cfaPattern[1]) {
391  case IFD::CFA_RED:
392  if ((cfaPattern[2] == IFD::CFA_BLUE)
393  && (cfaPattern[3] == IFD::CFA_GREEN)) {
394  cfa_pattern = OR_CFA_PATTERN_GRBG;
395  }
396  break;
397  case 2:
398  if ((cfaPattern[2] == IFD::CFA_RED)
399  && (cfaPattern[3] == IFD::CFA_GREEN)) {
400  cfa_pattern = OR_CFA_PATTERN_GBRG;
401  }
402  break;
403  }
404  break;
405  case IFD::CFA_BLUE:
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;
410  }
411  break;
412  }
413  //
414  }
415  return cfa_pattern;
416 }
417 
418 ::or_cfa_pattern _convertNewCfaPattern(const IfdEntry::Ref & e)
419 {
420  ::or_cfa_pattern cfa_pattern = OR_CFA_PATTERN_NONE;
421  if(!e || (e->count() < 4)) {
422  return cfa_pattern;
423  }
424 
425  uint16_t hdim = IfdTypeTrait<uint16_t>::get(*e, 0, true);
426  uint16_t vdim = IfdTypeTrait<uint16_t>::get(*e, 1, true);
427  if(hdim != 2 && vdim != 2) {
428  cfa_pattern = OR_CFA_PATTERN_NON_RGB22;
429  }
430  else {
431  std::vector<uint8_t> cfaPattern;
432  cfaPattern.push_back(IfdTypeTrait<uint8_t>::get(*e, 4, true));
433  cfaPattern.push_back(IfdTypeTrait<uint8_t>::get(*e, 5, true));
434  cfaPattern.push_back(IfdTypeTrait<uint8_t>::get(*e, 6, true));
435  cfaPattern.push_back(IfdTypeTrait<uint8_t>::get(*e, 7, true));
436  cfa_pattern = _convertArrayToCfaPattern(cfaPattern);
437  }
438  return cfa_pattern;
439 }
440 
441 
443 ::or_cfa_pattern _convertCfaPattern(const IfdEntry::Ref & e)
444 {
445  ::or_cfa_pattern cfa_pattern = OR_CFA_PATTERN_NONE;
446 
447  auto result = e->getArray<uint8_t>();
448  if (result.ok()) {
449  cfa_pattern = _convertArrayToCfaPattern(result.unwrap());
450  }
451 
452  return cfa_pattern;
453 }
454 
460 static ::or_cfa_pattern _getCfaPattern(const IfdDir::Ref & dir)
461 {
462  LOGDBG1("%s\n", __FUNCTION__);
463  ::or_cfa_pattern cfa_pattern = OR_CFA_PATTERN_NONE;
464  try {
465  IfdEntry::Ref e = dir->getEntry(IFD::EXIF_TAG_CFA_PATTERN);
466  if(e) {
467  cfa_pattern = _convertCfaPattern(e);
468  }
469  else {
470  e = dir->getEntry(IFD::EXIF_TAG_NEW_CFA_PATTERN);
471  if(e) {
472  cfa_pattern = _convertNewCfaPattern(e);
473  }
474  }
475  }
476  catch(...)
477  {
478  LOGERR("Exception in _getCfaPattern().\n");
479  }
480  return cfa_pattern;
481 }
482 
483 } // end anon namespace
484 
485 
486 ::or_error IfdFile::_getRawData(RawData & data, uint32_t options)
487 {
488  ::or_error ret = OR_ERROR_NONE;
489  const IfdDir::Ref & _cfaIfd = cfaIfd();
490  LOGDBG1("_getRawData()\n");
491 
492  if(_cfaIfd) {
493  ret = _getRawDataFromDir(data, _cfaIfd);
494  if (ret != OR_ERROR_NONE) {
495  return ret;
496  }
497  ret = _decompressIfNeeded(data, options);
498  }
499  else {
500  ret = OR_ERROR_NOT_FOUND;
501  }
502  return ret;
503 }
504 
505 ::or_error IfdFile::_decompressIfNeeded(RawData&, uint32_t)
506 {
507  return OR_ERROR_NONE;
508 }
509 
510 
511 ::or_error IfdFile::_getRawDataFromDir(RawData & data, const IfdDir::Ref & dir)
512 {
513  ::or_error ret = OR_ERROR_NONE;
514 
515  uint32_t offset = 0;
516  uint32_t byte_length = 0;
517 
518  if(!dir) {
519  LOGERR("dir is NULL\n");
520  return OR_ERROR_NOT_FOUND;
521  }
522  auto result = dir->getValue<uint16_t>(IFD::EXIF_TAG_BITS_PER_SAMPLE);
523  if(result.empty()) {
524  LOGERR("unable to guess Bits per sample\n");
525  }
526  uint16_t bpc = result.unwrap_or(0);
527 
528  auto result2 = dir->getValue<uint32_t>(IFD::EXIF_TAG_STRIP_OFFSETS);
529  if(result2.ok()) {
530  offset = result2.unwrap();
531  IfdEntry::Ref e = dir->getEntry(IFD::EXIF_TAG_STRIP_BYTE_COUNTS);
532  if(!e) {
533  LOGDBG1("byte len not found\n");
534  return OR_ERROR_NOT_FOUND;
535  }
536  auto result3 = e->getArray<uint32_t>();
537  if (result3.ok()) {
538  std::vector<uint32_t> counts = result3.unwrap();
539  LOGDBG1("counting tiles\n");
540  byte_length = std::accumulate(counts.cbegin(), counts.cend(), 0);
541  }
542  }
543  else {
544  // the tile are individual JPEGS....
545  // TODO extract all of them.
546  IfdEntry::Ref e = dir->getEntry(IFD::TIFF_TAG_TILE_OFFSETS);
547  if(!e) {
548  LOGDBG1("tile offsets empty\n");
549  return OR_ERROR_NOT_FOUND;
550  }
551  auto result3 = e->getArray<uint32_t>();
552  if (result3.empty()) {
553  LOGDBG1("tile offsets not found\n");
554  return OR_ERROR_NOT_FOUND;
555  }
556  std::vector<uint32_t> offsets = result3.unwrap();
557  offset = offsets[0];
558  e = dir->getEntry(IFD::TIFF_TAG_TILE_BYTECOUNTS);
559  if(!e) {
560  LOGDBG1("tile byte counts not found\n");
561  return OR_ERROR_NOT_FOUND;
562  }
563  result3 = e->getArray<uint32_t>();
564  if (result3.ok()) {
565  std::vector<uint32_t> counts = result3.unwrap();
566  LOGDBG1("counting tiles\n");
567  byte_length = std::accumulate(counts.cbegin(), counts.cend(), 0);
568  }
569  }
570 
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;
575  }
576  uint32_t x = result2.unwrap();
577 
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;
582  }
583  uint32_t y = result2.unwrap();
584 
585  uint32_t photo_int
586  = dir->getIntegerValue(IFD::EXIF_TAG_PHOTOMETRIC_INTERPRETATION)
587  .unwrap_or(IFD::EV_PI_CFA);
588 
589  BitmapData::DataType data_type = OR_DATA_TYPE_NONE;
590 
591  result = dir->getValue<uint16_t>(IFD::EXIF_TAG_COMPRESSION);
592  if(result.empty()) {
593  LOGDBG1("Compression type not found\n");
594  }
595  uint32_t compression = _translateCompressionType(
596  static_cast<IFD::TiffCompress>(result.unwrap_or(0)));
597 
598  switch(compression)
599  {
600  case IFD::COMPRESS_NONE:
601  data_type = OR_DATA_TYPE_RAW;
602  break;
603  case IFD::COMPRESS_NIKON_PACK:
604  data_type = OR_DATA_TYPE_RAW;
605  break;
606  case IFD::COMPRESS_NIKON_QUANTIZED:
607  // must check whether it is really compressed
608  // only for D100
609  if (!NefFile::isCompressed(*m_container, offset)) {
610  compression = IFD::COMPRESS_NIKON_PACK;
611  data_type = OR_DATA_TYPE_RAW;
612  // this is a hack. we should check if
613  // we have a D100 instead, but that case is already
614  // a D100 corner case. WILL BREAK on compressed files.
615  // according to dcraw we must increase the size by 6.
616  x += 6;
617  break;
618  }
619  default:
620  data_type = OR_DATA_TYPE_COMPRESSED_RAW;
621  break;
622  }
623 
624  LOGDBG1("RAW Compression is %u\n", compression);
625  LOGDBG1("bpc is %u\n", bpc);
626 
627  ::or_cfa_pattern cfa_pattern = _getCfaPattern(dir);
628  if(cfa_pattern == OR_CFA_PATTERN_NONE) {
629  // some file have it in the exif IFD instead.
630  if(!m_exifIfd) {
631  m_exifIfd = _locateExifIfd();
632  }
633  cfa_pattern = _getCfaPattern(m_exifIfd);
634  }
635 
636 
637  if((bpc == 12 || bpc == 14) && (compression == IFD::COMPRESS_NONE)
638  && (byte_length == (x * y * 2))) {
639  // We turn this to a 16-bits per sample. MSB are 0
640  LOGDBG1("setting bpc from %u to 16\n", bpc);
641  bpc = 16;
642  }
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,
646  byte_length);
647  if (real_size < byte_length) {
648  LOGWARN("Size mismatch for data: ignoring.\n");
649  }
650  }
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);
654  }
655  else {
656  LOGERR("Unsupported bpc %u\n", bpc);
657  return OR_ERROR_INVALID_FORMAT;
658  }
659  data.setCfaPatternType(cfa_pattern);
660  data.setDataType(data_type);
661  data.setBpc(bpc);
662  data.setCompression(data_type == OR_DATA_TYPE_COMPRESSED_RAW
663  ? compression : 1);
664  data.setPhotometricInterpretation((ExifPhotometricInterpretation)photo_int);
665  if((data_type == OR_DATA_TYPE_RAW) && (data.whiteLevel() == 0)) {
666  data.setWhiteLevel((1 << bpc) - 1);
667  }
668  data.setDimensions(x, y);
669 
670  return ret;
671 }
672 
673 
674 ::or_error
675 IfdFile::_unpackData(uint16_t bpc, uint32_t compression, RawData & data,
676  uint32_t x, uint32_t y, uint32_t offset, uint32_t byte_length)
677 {
678  ::or_error ret = OR_ERROR_NONE;
679  size_t fetched = 0;
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);
688  size_t got;
689  LOGDBG1("offset of RAW data = %u\n", current_offset);
690  do {
691  got = m_container->fetchData (block.get(),
692  current_offset, blocksize);
693  fetched += got;
694  offset += got;
695  current_offset += got;
696  if(got) {
697  if(bpc == 12) {
698  size_t out;
699  ret = unpack.unpack_be12to16(outdata, outsize,
700  block.get(),
701  got, out);
702  outdata += out;
703  outsize -= out;
704  if(ret != OR_ERROR_NONE) {
705  break;
706  }
707  }
708  else {
709  // outdata point to uint16_t
710  std::copy(block.get(), block.get()+got,
711  (uint16_t*)outdata);
712  outdata += (got << 1);
713  }
714  }
715  } while((got != 0) && (fetched < byte_length));
716 
717  return ret;
718 }
719 
720 }
721 }
722 
723 /*
724  Local Variables:
725  mode:c++
726  c-file-style:"stroustrup"
727  c-file-offsets:((innamespace . 0))
728  tab-width:2
729  c-basic-offset:2
730  indent-tabs-mode:nil
731  fill-column:80
732  End:
733 */
CIFF is the container for CRW files. It is an attempt from Canon to make this a standard. I guess it failed.
Definition: arwfile.cpp:30
static T get(IfdEntry &e, uint32_t idx=0, bool ignore_type=false) noexcept(false)
Definition: ifdentry.hpp:262
virtual ::or_error _enumThumbnailSizes(std::vector< uint32_t > &list) override
Definition: ifdfile.cpp:113
or_error unpack_be12to16(uint8_t *dest, size_t destsize, const uint8_t *src, size_t size, size_t &outsize)
Definition: unpack.cpp:58
virtual ::or_error _getRawData(RawData &data, uint32_t options) override
Definition: ifdfile.cpp:486
virtual uint32_t _getJpegThumbnailOffset(const IfdDir::Ref &dir, uint32_t &len)
Definition: ifdfile.cpp:285
void setBpc(uint32_t _bpc)
Definition: bitmapdata.cpp:164
std::shared_ptr< IfdEntry > Ref
Definition: ifdentry.hpp:165
virtual ::or_error _locateThumbnail(const IfdDir::Ref &dir, std::vector< uint32_t > &list)
Definition: ifdfile.cpp:149
static bool isCompressed(RawContainer &container, uint32_t offset)
Definition: neffile.cpp:418
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)
Definition: ifdfile.cpp:675
const IfdDir::Ref & cfaIfd()
Definition: ifdfile.cpp:333
virtual RawContainer * getContainer() const override
Definition: ifdfile.cpp:280
void setDataType(DataType _type)
Definition: bitmapdata.cpp:100
::or_error _getRawDataFromDir(RawData &data, const IfdDir::Ref &dir)
Definition: ifdfile.cpp:511
virtual uint32_t _translateCompressionType(IFD::TiffCompress tiffCompression)
Definition: ifdfile.cpp:326
virtual void setDimensions(uint32_t x, uint32_t y) override
Definition: rawdata.cpp:260