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