libopenraw
ifdfile.cpp
1 /*
2  * libopenraw - ifdfile.cpp
3  *
4  * Copyright (C) 2006-2016 Hubert Figuiere
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 using namespace Debug;
51 
52 namespace OpenRaw {
53 
54 class MetaValue;
55 
56 namespace Internals {
57 
58 
59 IfdFile::IfdFile(const IO::Stream::Ptr &s, Type _type,
60  bool instantiateContainer)
61  : RawFile(_type),
62  m_io(s),
63  m_container(nullptr)
64 {
65  if(instantiateContainer) {
66  m_container = new IfdFileContainer(m_io, 0);
67  }
68 }
69 
70 IfdFile::~IfdFile()
71 {
72  delete m_container;
73 }
74 
75 // this one seems to be pretty much the same for all the
76 // IFD based raw files
77 IfdDir::Ref IfdFile::_locateExifIfd()
78 {
79  const IfdDir::Ref & _mainIfd = mainIfd();
80  if (!_mainIfd) {
81  Trace(ERROR) << "IfdFile::_locateExifIfd() "
82  "main IFD not found\n";
83  return IfdDir::Ref();
84  }
85  return _mainIfd->getExifIFD();
86 }
87 
88 MakerNoteDir::Ref IfdFile::_locateMakerNoteIfd()
89 {
90  const IfdDir::Ref & _exifIfd = exifIfd();
91  if(_exifIfd) {
92  // to not have a recursive declaration, getMakerNoteIfd() return an IfdDir.
93  return std::dynamic_pointer_cast<MakerNoteDir>(_exifIfd->getMakerNoteIfd());
94  }
95  return MakerNoteDir::Ref();
96 }
97 
98 void IfdFile::_identifyId()
99 {
100  const IfdDir::Ref & _mainIfd = mainIfd();
101  if(!_mainIfd) {
102  Trace(ERROR) << "Main IFD not found to identify the file.\n";
103  return;
104  }
105  std::string make, model;
106  if(_mainIfd->getValue(IFD::EXIF_TAG_MAKE, make) &&
107  _mainIfd->getValue(IFD::EXIF_TAG_MODEL, model)) {
108  _setTypeId(_typeIdFromModel(make, model));
109  }
110 }
111 
112 
113 
114 ::or_error IfdFile::_enumThumbnailSizes(std::vector<uint32_t> &list)
115 {
116  ::or_error err = OR_ERROR_NONE;
117 
118  Trace(DEBUG1) << "_enumThumbnailSizes()\n";
119  std::vector<IfdDir::Ref> & dirs = m_container->directories();
120 
121  Trace(DEBUG1) << "num of dirs " << dirs.size() << "\n";
122  for(auto dir : dirs)
123  {
124  dir->load();
125  or_error ret = _locateThumbnail(dir, list);
126  if (ret == OR_ERROR_NONE)
127  {
128  Trace(DEBUG1) << "Found " << list.back() << " pixels\n";
129  }
130  std::vector<IfdDir::Ref> subdirs;
131  if(dir->getSubIFDs(subdirs)) {
132  Trace(DEBUG1) << "Iterating subdirs\n";
133  for(auto dir2 : subdirs)
134  {
135  dir2->load();
136  ret = _locateThumbnail(dir2, list);
137  if (ret == OR_ERROR_NONE)
138  {
139  Trace(DEBUG1) << "Found " << list.back() << " pixels\n";
140  }
141  }
142  }
143  }
144  if (list.size() <= 0) {
145  err = OR_ERROR_NOT_FOUND;
146  }
147  return err;
148 }
149 
150 
151 ::or_error IfdFile::_locateThumbnail(const IfdDir::Ref & dir,
152  std::vector<uint32_t> &list)
153 {
154  ::or_error ret = OR_ERROR_NOT_FOUND;
155  bool got_it;
156  uint32_t x = 0;
157  uint32_t y = 0;
158  ::or_data_type _type = OR_DATA_TYPE_NONE;
159  uint32_t subtype = 0;
160 
161  Trace(DEBUG1) << "_locateThumbnail\n";
162 
163  got_it = dir->getValue(IFD::EXIF_TAG_NEW_SUBFILE_TYPE, subtype);
164  Trace(DEBUG1) << "subtype " << subtype << "\n";
165  if(!got_it) {
166  if(!m_cfaIfd) {
167  m_cfaIfd = _locateCfaIfd();
168  }
169  if(m_cfaIfd == dir) {
170  return OR_ERROR_NOT_FOUND;
171  }
172  else {
173  subtype = 1;
174  }
175  }
176  if (subtype == 1) {
177 
178  uint16_t photom_int = 0;
179  got_it = dir->getValue(IFD::EXIF_TAG_PHOTOMETRIC_INTERPRETATION,
180  photom_int);
181 
182  if (got_it) {
183  Trace(DEBUG1) << "photometric int " << photom_int << "\n";
184  }
185  // photometric interpretation is RGB by default
186  else {
187  photom_int = IFD::EV_PI_RGB;
188  Trace(DEBUG1) << "assume photometric int is RGB\n";
189  }
190 
191  got_it = dir->getIntegerValue(IFD::EXIF_TAG_IMAGE_WIDTH, x);
192  got_it = dir->getIntegerValue(IFD::EXIF_TAG_IMAGE_LENGTH, y);
193 
194  uint16_t compression = 0;
195  got_it = dir->getValue(IFD::EXIF_TAG_COMPRESSION, compression);
196 
197  uint32_t offset = 0;
198  uint32_t byte_count = 0;
199  got_it = dir->getValue(IFD::EXIF_TAG_STRIP_BYTE_COUNTS, byte_count);
200  got_it = dir->getValue(IFD::EXIF_TAG_STRIP_OFFSETS, offset);
201  if (!got_it || (compression == 6) || (compression == 7)) {
202  if(!got_it) {
203  got_it = dir->getValue(IFD::EXIF_TAG_JPEG_INTERCHANGE_FORMAT_LENGTH,
204  byte_count);
205  got_it = dir->getValue(IFD::EXIF_TAG_JPEG_INTERCHANGE_FORMAT,
206  offset);
207  }
208  if (got_it) {
209  // workaround for CR2 files where 8RGB data is marked
210  // as JPEG. Check the real data size.
211  if(x && y) {
212  if(byte_count >= (x * y * 3)) {
213  //_type = OR_DATA_TYPE_PIXMAP_8RGB;
214  _type = OR_DATA_TYPE_NONE;
215  // See bug 72270
216  Trace(DEBUG1) << "8RGB as JPEG. Will ignore.\n";
217  ret = OR_ERROR_INVALID_FORMAT;
218  }
219  else {
220  _type = OR_DATA_TYPE_JPEG;
221  }
222  }
223  else {
224  _type = OR_DATA_TYPE_JPEG;
225  Trace(DEBUG1) << "looking for JPEG at " << offset << "\n";
226  if (x == 0 || y == 0) {
227  IO::Stream::Ptr s(std::make_shared<IO::StreamClone>(
228  m_io, offset));
229  std::unique_ptr<JfifContainer> jfif(new JfifContainer(s, 0));
230  if (jfif->getDimensions(x,y)) {
231  Trace(DEBUG1) << "JPEG dimensions x=" << x
232  << " y=" << y << "\n";
233  }
234  else {
235  _type = OR_DATA_TYPE_NONE;
236  Trace(WARNING) << "Couldn't get JPEG "
237  "dimensions.\n";
238  }
239  }
240  else {
241  Trace(DEBUG1) << "JPEG (supposed) dimensions x=" << x
242  << " y=" << y << "\n";
243  }
244  }
245 
246  }
247  }
248  else if (photom_int == IFD::EV_PI_YCBCR) {
249  Trace(WARNING) << "Unsupported YCbCr photometric "
250  "interpretation in non JPEG.\n";
251  ret = OR_ERROR_INVALID_FORMAT;
252  }
253  else {
254  Trace(DEBUG1) << "found strip offsets\n";
255  if (x != 0 && y != 0) {
256  // See bug 72270 - some CR2 have 16 bpc RGB thumbnails.
257  // by default it is RGB8. Unless stated otherwise.
258  bool isRGB8 = true;
259  try {
260  IfdEntry::Ref entry = dir->getEntry(IFD::EXIF_TAG_BITS_PER_SAMPLE);
261  std::vector<uint16_t> arr;
262  entry->getArray(arr);
263  for(auto bpc : arr) {
264  isRGB8 = (bpc == 8);
265  if (!isRGB8) {
266  Trace(DEBUG1) << "bpc != 8, not RGB8 " << bpc << "\n";
267  break;
268  }
269  }
270  }
271  catch(const std::exception & e) {
272  Trace(DEBUG1) << "Exception getting BPS " << e.what() << "\n";
273  }
274  if (isRGB8) {
275  _type = OR_DATA_TYPE_PIXMAP_8RGB;
276  }
277  }
278  }
279  if(_type != OR_DATA_TYPE_NONE) {
280  uint32_t dim = std::max(x, y);
281  offset += dir->container().offset();
282  _addThumbnail(dim, ThumbDesc(x, y, _type,
283  offset, byte_count));
284  list.push_back(dim);
285  ret = OR_ERROR_NONE;
286  }
287  }
288 
289  return ret;
290 }
291 
293 {
294  return m_container;
295 }
296 
297 uint32_t IfdFile::_getJpegThumbnailOffset(const IfdDir::Ref & dir, uint32_t & byte_length)
298 {
299  uint32_t offset = 0;
300  bool got_it = dir->getValue(IFD::EXIF_TAG_JPEG_INTERCHANGE_FORMAT_LENGTH, byte_length);
301  if(got_it) {
302  got_it = dir->getValue(IFD::EXIF_TAG_JPEG_INTERCHANGE_FORMAT, offset);
303  }
304  else {
305  // some case it is STRIP_OFFSETS for JPEG
306  got_it = dir->getValue(IFD::EXIF_TAG_STRIP_OFFSETS, offset);
307  got_it = dir->getValue(IFD::EXIF_TAG_STRIP_BYTE_COUNTS, byte_length);
308  }
309  return offset;
310 }
311 
312 
313 
314 MetaValue *IfdFile::_getMetaValue(int32_t meta_index)
315 {
316  MetaValue * val = nullptr;
317  IfdDir::Ref ifd;
318  if(META_INDEX_MASKOUT(meta_index) == META_NS_TIFF) {
319  ifd = mainIfd();
320  }
321  else if(META_INDEX_MASKOUT(meta_index) == META_NS_EXIF) {
322  ifd = exifIfd();
323  }
324  else {
325  Trace(ERROR) << "Unknown Meta Namespace\n";
326  }
327  if(ifd) {
328  Trace(DEBUG1) << "Meta value for "
329  << META_NS_MASKOUT(meta_index) << "\n";
330 
331  IfdEntry::Ref e = ifd->getEntry(META_NS_MASKOUT(meta_index));
332  if(e) {
333  val = e->make_meta_value();
334  }
335  }
336  return val;
337 }
338 
341 uint32_t IfdFile::_translateCompressionType(IFD::TiffCompress tiffCompression)
342 {
343  return (uint32_t)tiffCompression;
344 }
345 
346 
347 
348 const IfdDir::Ref & IfdFile::cfaIfd()
349 {
350  if(!m_cfaIfd) {
351  m_cfaIfd = _locateCfaIfd();
352  }
353  return m_cfaIfd;
354 }
355 
356 
357 const IfdDir::Ref & IfdFile::mainIfd()
358 {
359  if(!m_mainIfd) {
360  m_mainIfd = _locateMainIfd();
361  }
362  return m_mainIfd;
363 }
364 
365 
366 const IfdDir::Ref & IfdFile::exifIfd()
367 {
368  if(!m_exifIfd) {
369  m_exifIfd = _locateExifIfd();
370  }
371  return m_exifIfd;
372 }
373 
374 
375 const MakerNoteDir::Ref & IfdFile::makerNoteIfd()
376 {
377  if(!m_makerNoteIfd) {
378  m_makerNoteIfd = _locateMakerNoteIfd();
379  }
380  return m_makerNoteIfd;
381 }
382 
383 
384 namespace {
385 
386 ::or_cfa_pattern
387 _convertArrayToCfaPattern(const std::vector<uint8_t> &cfaPattern)
388 {
389  ::or_cfa_pattern cfa_pattern = OR_CFA_PATTERN_NON_RGB22;
390  if(cfaPattern.size() != 4) {
391  Trace(WARNING) << "Unsupported bayer pattern\n";
392  }
393  else {
394  Trace(DEBUG2) << "patter is = " << cfaPattern[0] << ", "
395  << cfaPattern[1] << ", " << cfaPattern[2]
396  << ", " << cfaPattern[3] << "\n";
397  switch(cfaPattern[0]) {
398  case IFD::CFA_RED:
399  switch(cfaPattern[1]) {
400  case IFD::CFA_GREEN:
401  if((cfaPattern[2] == IFD::CFA_GREEN)
402  && (cfaPattern[3] == IFD::CFA_BLUE))
403  {
404  cfa_pattern = OR_CFA_PATTERN_RGGB;
405  }
406  break;
407  }
408  break;
409  case IFD::CFA_GREEN:
410  switch(cfaPattern[1]) {
411  case IFD::CFA_RED:
412  if((cfaPattern[2] == 2)
413  && (cfaPattern[3] == IFD::CFA_GREEN))
414  {
415  cfa_pattern = OR_CFA_PATTERN_GRBG;
416  }
417  break;
418  case 2:
419  if((cfaPattern[2] == IFD::CFA_RED)
420  && (cfaPattern[3] == IFD::CFA_GREEN))
421  {
422  cfa_pattern = OR_CFA_PATTERN_GBRG;
423  }
424  break;
425  }
426  break;
427  case IFD::CFA_BLUE:
428  switch(cfaPattern[1]) {
429  case IFD::CFA_GREEN:
430  if((cfaPattern[2] == IFD::CFA_GREEN)
431  && (cfaPattern[3] == IFD::CFA_RED))
432  {
433  cfa_pattern = OR_CFA_PATTERN_BGGR;
434  }
435  break;
436  }
437  break;
438  }
439  //
440  }
441  return cfa_pattern;
442 }
443 
444 ::or_cfa_pattern _convertNewCfaPattern(const IfdEntry::Ref & e)
445 {
446  ::or_cfa_pattern cfa_pattern = OR_CFA_PATTERN_NONE;
447  if(!e || (e->count() < 4)) {
448  return cfa_pattern;
449  }
450 
451  uint16_t hdim = IfdTypeTrait<uint16_t>::get(*e, 0, true);
452  uint16_t vdim = IfdTypeTrait<uint16_t>::get(*e, 1, true);
453  if(hdim != 2 && vdim != 2) {
454  cfa_pattern = OR_CFA_PATTERN_NON_RGB22;
455  }
456  else {
457  std::vector<uint8_t> cfaPattern;
458  cfaPattern.push_back(IfdTypeTrait<uint8_t>::get(*e, 4, true));
459  cfaPattern.push_back(IfdTypeTrait<uint8_t>::get(*e, 5, true));
460  cfaPattern.push_back(IfdTypeTrait<uint8_t>::get(*e, 6, true));
461  cfaPattern.push_back(IfdTypeTrait<uint8_t>::get(*e, 7, true));
462  cfa_pattern = _convertArrayToCfaPattern(cfaPattern);
463  }
464  return cfa_pattern;
465 }
466 
467 
469 ::or_cfa_pattern _convertCfaPattern(const IfdEntry::Ref & e)
470 {
471  std::vector<uint8_t> cfaPattern;
472  ::or_cfa_pattern cfa_pattern = OR_CFA_PATTERN_NONE;
473 
474  e->getArray(cfaPattern);
475  if(!cfaPattern.empty()) {
476  cfa_pattern = _convertArrayToCfaPattern(cfaPattern);
477  }
478  return cfa_pattern;
479 }
480 
486 static ::or_cfa_pattern _getCfaPattern(const IfdDir::Ref & dir)
487 {
488  Trace(DEBUG1) << __FUNCTION__ << "\n";
489  ::or_cfa_pattern cfa_pattern = OR_CFA_PATTERN_NONE;
490  try {
491  IfdEntry::Ref e = dir->getEntry(IFD::EXIF_TAG_CFA_PATTERN);
492  if(e) {
493  cfa_pattern = _convertCfaPattern(e);
494  }
495  else {
496  e = dir->getEntry(IFD::EXIF_TAG_NEW_CFA_PATTERN);
497  if(e) {
498  cfa_pattern = _convertNewCfaPattern(e);
499  }
500  }
501  }
502  catch(...)
503  {
504  Trace(ERROR) << "Exception in _getCfaPattern().\n";
505  }
506  return cfa_pattern;
507 }
508 
509 } // end anon namespace
510 
511 
512 ::or_error IfdFile::_getRawData(RawData & data, uint32_t options)
513 {
514  ::or_error ret = OR_ERROR_NONE;
515  const IfdDir::Ref & _cfaIfd = cfaIfd();
516  Trace(DEBUG1) << "_getRawData()\n";
517 
518  if(_cfaIfd) {
519  ret = _getRawDataFromDir(data, _cfaIfd);
520  if (ret != OR_ERROR_NONE) {
521  return ret;
522  }
523  ret = _decompressIfNeeded(data, options);
524  }
525  else {
526  ret = OR_ERROR_NOT_FOUND;
527  }
528  return ret;
529 }
530 
531 ::or_error IfdFile::_decompressIfNeeded(RawData&, uint32_t)
532 {
533  return OR_ERROR_NONE;
534 }
535 
536 
537 ::or_error IfdFile::_getRawDataFromDir(RawData & data, const IfdDir::Ref & dir)
538 {
539  ::or_error ret = OR_ERROR_NONE;
540 
541  uint16_t bpc = 0;
542  uint32_t offset = 0;
543  uint32_t byte_length = 0;
544  bool got_it;
545  uint32_t x, y;
546  x = 0;
547  y = 0;
548 
549  if(!dir) {
550  Trace(ERROR) << "dir is NULL\n";
551  return OR_ERROR_NOT_FOUND;
552  }
553  got_it = dir->getValue(IFD::EXIF_TAG_BITS_PER_SAMPLE, bpc);
554  if(!got_it) {
555  Trace(ERROR) << "unable to guess Bits per sample\n";
556  }
557 
558  got_it = dir->getValue(IFD::EXIF_TAG_STRIP_OFFSETS, offset);
559  if(got_it) {
560  IfdEntry::Ref e = dir->getEntry(IFD::EXIF_TAG_STRIP_BYTE_COUNTS);
561  if(!e) {
562  Trace(DEBUG1) << "byte len not found\n";
563  return OR_ERROR_NOT_FOUND;
564  }
565  std::vector<uint32_t> counts;
566  e->getArray(counts);
567  Trace(DEBUG1) << "counting tiles\n";
568  byte_length = std::accumulate(counts.cbegin(), counts.cend(), 0);
569  }
570  else {
571  // the tile are individual JPEGS....
572  // TODO extract all of them.
573  IfdEntry::Ref e = dir->getEntry(IFD::TIFF_TAG_TILE_OFFSETS);
574  if(!e) {
575  Trace(DEBUG1) << "tile offsets empty\n";
576  return OR_ERROR_NOT_FOUND;
577  }
578  std::vector<uint32_t> offsets;
579  e->getArray(offsets);
580  if(offsets.size() == 0) {
581  Trace(DEBUG1) << "tile offsets not found\n";
582  return OR_ERROR_NOT_FOUND;
583  }
584  offset = offsets[0];
585  e = dir->getEntry(IFD::TIFF_TAG_TILE_BYTECOUNTS);
586  if(!e) {
587  Trace(DEBUG1) << "tile byte counts not found\n";
588  return OR_ERROR_NOT_FOUND;
589  }
590  std::vector<uint32_t> counts;
591  e->getArray(counts);
592  Trace(DEBUG1) << "counting tiles\n";
593  byte_length = std::accumulate(counts.cbegin(), counts.cend(), 0);
594  }
595  got_it = dir->getIntegerValue(IFD::EXIF_TAG_IMAGE_WIDTH, x);
596  if(!got_it) {
597  Trace(DEBUG1) << "X not found\n";
598  return OR_ERROR_NOT_FOUND;
599  }
600  got_it = dir->getIntegerValue(IFD::EXIF_TAG_IMAGE_LENGTH, y);
601  if(!got_it) {
602  Trace(DEBUG1) << "Y not found\n";
603  return OR_ERROR_NOT_FOUND;
604  }
605 
606  uint32_t photo_int = 0;
607  got_it = dir->getIntegerValue(IFD::EXIF_TAG_PHOTOMETRIC_INTERPRETATION,
608  photo_int);
609  if(!got_it) {
610  // Default is CFA.
611  photo_int = IFD::EV_PI_CFA;
612  }
613 
614  uint16_t tiffCompression = 0;
615  got_it = dir->getValue(IFD::EXIF_TAG_COMPRESSION, tiffCompression);
616  if(!got_it) {
617  Trace(DEBUG1) << "Compression type not found\n";
618  }
619  BitmapData::DataType data_type = OR_DATA_TYPE_NONE;
620 
621  uint32_t compression = _translateCompressionType((IFD::TiffCompress)tiffCompression);
622  switch(compression)
623  {
624  case IFD::COMPRESS_NONE:
625  data_type = OR_DATA_TYPE_RAW;
626  break;
627  case IFD::COMPRESS_NIKON_PACK:
628  data_type = OR_DATA_TYPE_RAW;
629  break;
630  case IFD::COMPRESS_NIKON_QUANTIZED:
631  // must check whether it is really compressed
632  // only for D100
633  if( !NefFile::isCompressed(*m_container, offset) ) {
634  compression = IFD::COMPRESS_NIKON_PACK;
635  data_type = OR_DATA_TYPE_RAW;
636  // this is a hack. we should check if
637  // we have a D100 instead, but that case is already
638  // a D100 corner case. WILL BREAK on compressed files.
639  // according to dcraw we must increase the size by 6.
640  x += 6;
641  break;
642  }
643  default:
644  data_type = OR_DATA_TYPE_COMPRESSED_RAW;
645  break;
646  }
647 
648  Trace(DEBUG1) << "RAW Compression is " << compression << "\n";
649 
650  ::or_cfa_pattern cfa_pattern = _getCfaPattern(dir);
651  if(cfa_pattern == OR_CFA_PATTERN_NONE) {
652  // some file have it in the exif IFD instead.
653  if(!m_exifIfd) {
654  m_exifIfd = _locateExifIfd();
655  }
656  cfa_pattern = _getCfaPattern(m_exifIfd);
657  }
658 
659 
660  if((bpc == 12 || bpc == 14) && (compression == 1)
661  && (byte_length == (x * y * 2)))
662  {
663  Trace(DEBUG1) << "setting bpc from " << bpc
664  << " to 16\n";
665  bpc = 16;
666  }
667  if((bpc == 16) || (data_type == OR_DATA_TYPE_COMPRESSED_RAW)) {
668  void *p = data.allocData(byte_length);
669  size_t real_size = m_container->fetchData(p, offset,
670  byte_length);
671  if (real_size < byte_length) {
672  Trace(WARNING) << "Size mismatch for data: ignoring.\n";
673  }
674  }
675  else if((bpc == 12) || (bpc == 8)) {
676  ret = _unpackData(bpc, compression, data, x, y, offset, byte_length);
677  Trace(DEBUG1) << "unpack result " << ret << "\n";
678  }
679  else {
680  Trace(ERROR) << "Unsupported bpc " << bpc << "\n";
681  return OR_ERROR_INVALID_FORMAT;
682  }
683  data.setCfaPatternType(cfa_pattern);
684  data.setDataType(data_type);
685  data.setCompression(data_type == OR_DATA_TYPE_COMPRESSED_RAW
686  ? compression : 1);
687  data.setPhotometricInterpretation((ExifPhotometricInterpretation)photo_int);
688  if((data_type == OR_DATA_TYPE_RAW) && (data.whiteLevel() == 0)) {
689  data.setWhiteLevel((1 << bpc) - 1);
690  }
691  data.setDimensions(x, y);
692 
693  return ret;
694 }
695 
696 
697 ::or_error IfdFile::_unpackData(uint16_t bpc, uint32_t compression, RawData & data, uint32_t x, uint32_t y, uint32_t offset, uint32_t byte_length)
698 {
699  ::or_error ret = OR_ERROR_NONE;
700  size_t fetched = 0;
701  uint32_t current_offset = offset;
702  Unpack unpack(x, compression);
703  const size_t blocksize = (bpc == 8 ? x : unpack.block_size());
704  Trace(DEBUG1) << "Block size = " << blocksize << "\n";
705  Trace(DEBUG1) << "dimensions (x, y) " << x << ", "
706  << y << "\n";
707  std::unique_ptr<uint8_t[]> block(new uint8_t[blocksize]);
708  size_t outsize = x * y * 2;
709  uint8_t * outdata = (uint8_t*)data.allocData(outsize);
710  size_t got;
711  Trace(DEBUG1) << "offset of RAW data = " << current_offset << "\n";
712  do {
713  got = m_container->fetchData (block.get(),
714  current_offset, blocksize);
715  fetched += got;
716  offset += got;
717  current_offset += got;
718  if(got) {
719  if(bpc == 12) {
720  size_t out;
721  ret = unpack.unpack_be12to16(outdata, outsize,
722  block.get(),
723  got, out);
724  outdata += out;
725  outsize -= out;
726  if(ret != OR_ERROR_NONE) {
727  break;
728  }
729  }
730  else {
731  // outdata point to uint16_t
732  std::copy(block.get(), block.get()+got,
733  (uint16_t*)outdata);
734  outdata += (got << 1);
735  }
736  }
737  } while((got != 0) && (fetched < byte_length));
738 
739  return ret;
740 }
741 
742 }
743 }
744 
745 /*
746  Local Variables:
747  mode:c++
748  c-file-style:"stroustrup"
749  c-file-offsets:((innamespace . 0))
750  tab-width:2
751  c-basic-offset:2
752  indent-tabs-mode:nil
753  fill-column:80
754  End:
755 */
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:269
virtual ::or_error _enumThumbnailSizes(std::vector< uint32_t > &list) override
Definition: ifdfile.cpp:114
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:512
virtual uint32_t _getJpegThumbnailOffset(const IfdDir::Ref &dir, uint32_t &len)
Definition: ifdfile.cpp:297
std::shared_ptr< IfdEntry > Ref
Definition: ifdentry.hpp:178
Definition: trace.cpp:30
virtual ::or_error _locateThumbnail(const IfdDir::Ref &dir, std::vector< uint32_t > &list)
Definition: ifdfile.cpp:151
static bool isCompressed(RawContainer &container, uint32_t offset)
Definition: neffile.cpp:257
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:697
const IfdDir::Ref & cfaIfd()
Definition: ifdfile.cpp:348
virtual RawContainer * getContainer() const override
Definition: ifdfile.cpp:292
void setDataType(DataType _type)
Definition: bitmapdata.cpp:100
::or_error _getRawDataFromDir(RawData &data, const IfdDir::Ref &dir)
Definition: ifdfile.cpp:537
virtual uint32_t _translateCompressionType(IFD::TiffCompress tiffCompression)
Definition: ifdfile.cpp:341
virtual void setDimensions(uint32_t x, uint32_t y) override
Definition: rawdata.cpp:260