libopenraw  0.3.7
ifdfile.cpp
1 /*
2  * libopenraw - ifdfile.cpp
3  *
4  * Copyright (C) 2006-2020 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 #include "xtranspattern.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 IfdDir::Ref IfdFile::_locateCfaIfd()
74 {
75  // CFA IFD is the main IFD by default
76  return mainIfd();
77 }
78 
79 IfdDir::Ref IfdFile::_locateMainIfd()
80 {
81  auto ifd = m_container->setDirectory(0);
82  if (ifd) {
83  ifd->setType(OR_IFD_MAIN);
84  }
85  return ifd;
86 }
87 
88 namespace {
89 
90 
91 }
92 
93 void IfdFile::_identifyId()
94 {
95  // Identify from the vendor internal ID.
96  IfdDir::Ref ifd;
97  uint16_t index = 0;
98  const ModelIdMap* model_map = nullptr;
99  if (vendorCameraIdLocation(ifd, index, model_map) && ifd) {
100  auto id = ifd->getIntegerValue(index);
101  if (id) {
102  auto id_value = id.value();
103  auto type_id = modelid_to_typeid(*model_map, id_value);
104  if (type_id != 0) {
105  _setTypeId(type_id);
106  return;
107  }
108  LOGERR("unknown model ID 0x%x (%u)\n", id_value, id_value);
109  }
110  }
111 
112  // Fallback on using strings.
113  const IfdDir::Ref & _mainIfd = mainIfd();
114  if (!_mainIfd) {
115  LOGERR("Main IFD not found to identify the file.\n");
116  return;
117  }
118 
119  auto make = _mainIfd->getValue<std::string>(IFD::EXIF_TAG_MAKE);
120  auto model = _mainIfd->getValue<std::string>(IFD::EXIF_TAG_MODEL);
121  if (!model) {
122  // BlackMagic CinemaDNG doesn't have Make and Model.
123  model = _mainIfd->getValue<std::string>(IFD::DNG_TAG_UNIQUE_CAMERA_MODEL);
124  if (!make) {
125  make = model;
126  }
127  }
128  if (make && model) {
129  _setTypeId(_typeIdFromModel(make.value(), model.value()));
130  }
131 }
132 
133 ::or_error IfdFile::_addThumbnailFromStream(uint32_t offset, uint32_t len,
134  std::vector<uint32_t>& list)
135 {
136  auto err = OR_ERROR_NOT_FOUND;
137  LOGDBG1("fetching JPEG\n");
138  IO::Stream::Ptr s = std::make_shared<IO::StreamClone>(m_io, offset);
139  auto jfif = std::make_unique<JfifContainer>(s, 0);
140 
141  uint32_t x, y;
142  x = y = 0;
143  jfif->getDimensions(x, y);
144  LOGDBG1("JPEG dimensions x=%d y=%d\n", x, y);
145 
146  uint32_t dim = std::max(x, y);
147  // "Olympus" MakerNote carries a 160 px thubnail we might already have.
148  // We don't check it is the same.
149  if (dim && std::find(list.begin(), list.end(), dim) == list.end()) {
150  _addThumbnail(dim, ThumbDesc(x, y, OR_DATA_TYPE_JPEG, offset, len));
151  list.push_back(dim);
152  err = OR_ERROR_NONE;
153  }
154 
155  return err;
156 }
157 
158 ::or_error IfdFile::_addThumbnailFromEntry(const IfdEntry::Ref& e, off_t offset,
159  std::vector<uint32_t>& list)
160 {
162  if (e) {
163  auto val_offset = e->offset();
164 
165  val_offset += offset;
166 
167  err =_addThumbnailFromStream(val_offset, e->count(), list);
168  }
169  return err;
170 }
171 
173 IfdFile::_enumThumbnailSizes(std::vector<uint32_t> &list)
174 {
176 
177  LOGDBG1("_enumThumbnailSizes()\n");
178  std::vector<IfdDir::Ref> & dirs = m_container->directories();
179 
180  LOGDBG1("num of dirs %lu\n", (LSIZE)dirs.size());
181  for(auto dir : dirs)
182  {
183  dir->load();
184  or_error ret = _locateThumbnail(dir, list);
185  if (ret == OR_ERROR_NONE) {
186  LOGDBG1("Found %u pixels\n", list.back());
187  }
188  auto result = dir->getSubIFDs();
189  if (result) {
190  std::vector<IfdDir::Ref> subdirs = result.value();
191  LOGDBG1("Iterating subdirs\n");
192  for(auto dir2 : subdirs)
193  {
194  dir2->load();
195  ret = _locateThumbnail(dir2, list);
196  if (ret == OR_ERROR_NONE) {
197  LOGDBG1("Found %u pixels\n", list.back());
198  }
199  }
200  }
201  }
202  if (list.size() <= 0) {
203  err = OR_ERROR_NOT_FOUND;
204  }
205  return err;
206 }
207 
208 
209 ::or_error IfdFile::_locateThumbnail(const IfdDir::Ref & dir,
210  std::vector<uint32_t> &list)
211 {
213  ::or_data_type _type = OR_DATA_TYPE_NONE;
214  uint32_t subtype = 0;
215 
216  LOGDBG1("_locateThumbnail\n");
217 
218  auto result = dir->getValue<uint32_t>(IFD::EXIF_TAG_NEW_SUBFILE_TYPE);
219  if (result.empty()) {
220  if (cfaIfd() == dir) {
221  return OR_ERROR_NOT_FOUND;
222  }
223  else {
224  subtype = 1;
225  }
226  } else {
227  subtype = result.value();
228  }
229  LOGDBG1("subtype %u\n", subtype);
230  if (subtype == 1) {
231 
232  uint16_t photom_int =
233  dir->getValue<uint16_t>(IFD::EXIF_TAG_PHOTOMETRIC_INTERPRETATION).value_or(IFD::EV_PI_RGB);
234 
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);
237 
238  uint16_t compression = dir->getValue<uint16_t>(IFD::EXIF_TAG_COMPRESSION).value_or(0);
239 
240  uint32_t offset = 0;
241  uint32_t byte_count = dir->getValue<uint32_t>(IFD::EXIF_TAG_STRIP_BYTE_COUNTS).value_or(0);
242 
243  result = dir->getValue<uint32_t>(IFD::EXIF_TAG_STRIP_OFFSETS);
244  bool got_it = result.has_value();
245  if (got_it) {
246  offset = result.value();
247  }
248  if (!got_it || (compression == 6) || (compression == 7)) {
249  if (!got_it) {
250  byte_count =
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();
254  if (got_it) {
255  offset = result.value();
256  }
257  }
258  if (got_it) {
259  // workaround for CR2 files where 8RGB data is marked
260  // as JPEG. Check the real data size.
261  if(x && y) {
262  if(byte_count >= (x * y * 3)) {
263  //_type = OR_DATA_TYPE_PIXMAP_8RGB;
264  _type = OR_DATA_TYPE_NONE;
265  // See bug 72270
266  LOGDBG1("8RGB as JPEG. Will ignore.\n");
268  }
269  else {
270  _type = OR_DATA_TYPE_JPEG;
271  }
272  }
273  else {
274  _type = OR_DATA_TYPE_JPEG;
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);
281  }
282  else {
283  _type = OR_DATA_TYPE_NONE;
284  LOGWARN("Couldn't get JPEG dimensions.\n");
285  }
286  }
287  else {
288  LOGDBG1("JPEG (supposed) dimensions x=%u y=%u\n", x, y);
289  }
290  }
291 
292  }
293  }
294  else if (photom_int == IFD::EV_PI_YCBCR) {
295  LOGWARN("Unsupported YCbCr photometric interpretation in non JPEG.\n");
297  }
298  else {
299  LOGDBG1("found strip offsets\n");
300  if (x != 0 && y != 0) {
301  // See bug 72270 - some CR2 have 16 bpc RGB thumbnails.
302  // by default it is RGB8. Unless stated otherwise.
303  bool isRGB8 = true;
304  IfdEntry::Ref entry = dir->getEntry(IFD::EXIF_TAG_BITS_PER_SAMPLE);
305  auto result2 = dir->getEntryArrayValue<uint16_t>(*entry);
306  if (result2) {
307  std::vector<uint16_t> arr = result2.value();
308  for(auto bpc : arr) {
309  isRGB8 = (bpc == 8);
310  if (!isRGB8) {
311  LOGDBG1("bpc != 8, not RGB8 %u\n", bpc);
312  break;
313  }
314  }
315  } else {
316  LOGDBG1("Error getting BPS\n");
317  }
318  if (isRGB8) {
319  _type = OR_DATA_TYPE_PIXMAP_8RGB;
320  }
321  }
322  }
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));
328  list.push_back(dim);
329  ret = OR_ERROR_NONE;
330  }
331  }
332 
333  return ret;
334 }
335 
336 RawContainer* IfdFile::getContainer() const
337 {
338  return m_container;
339 }
340 
341 uint32_t IfdFile::_getJpegThumbnailOffset(const IfdDir::Ref & dir, uint32_t & byte_length)
342 {
343  auto result = dir->getValue<uint32_t>(IFD::EXIF_TAG_JPEG_INTERCHANGE_FORMAT_LENGTH);
344  if (result) {
345  byte_length = result.value();
346  return dir->getValue<uint32_t>(IFD::EXIF_TAG_JPEG_INTERCHANGE_FORMAT).value_or(0);
347  }
348 
349  // some case it is STRIP_OFFSETS for JPEG
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);
352 }
353 
354 
355 
356 MetaValue *IfdFile::_getMetaValue(int32_t meta_index)
357 {
358  MetaValue * val = nullptr;
359  IfdDir::Ref ifd;
360  if(META_INDEX_MASKOUT(meta_index) == META_NS_TIFF) {
361  ifd = mainIfd();
362  }
363  else if(META_INDEX_MASKOUT(meta_index) == META_NS_EXIF) {
364  ifd = exifIfd();
365  }
366  else {
367  LOGERR("Unknown Meta Namespace\n");
368  }
369  if(ifd) {
370  LOGDBG1("Meta value for %u\n", META_NS_MASKOUT(meta_index));
371 
372  IfdEntry::Ref e = ifd->getEntry(META_NS_MASKOUT(meta_index));
373  if (e) {
374  val = ifd->makeMetaValue(*e);
375  }
376  }
377  return val;
378 }
379 
382 uint32_t IfdFile::_translateCompressionType(IFD::TiffCompress tiff_compression)
383 {
384  return (uint32_t)tiff_compression;
385 }
386 
387 namespace {
388 
389 const MosaicInfo *
390 _convertArrayToCfaPattern(const std::vector<uint8_t> &cfaPattern)
391 {
393  if(cfaPattern.size() != 4) {
394  if (cfaPattern.size() == 36) {
395  // XXX don't assume this is X-Trans
396  return XTransPattern::xtransPattern();
397  }
398  LOGWARN("Unsupported bayer pattern of size %lu\n", (LSIZE)cfaPattern.size());
399  } else {
400  LOGDBG2("pattern is = %d, %d, %d, %d\n", cfaPattern[0],
401  cfaPattern[1], cfaPattern[2], cfaPattern[3]);
402  switch(cfaPattern[0]) {
403  case IFD::CFA_RED:
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;
408  }
409  break;
410  case IFD::CFA_GREEN:
411  switch(cfaPattern[1]) {
412  case IFD::CFA_RED:
413  if ((cfaPattern[2] == IFD::CFA_BLUE)
414  && (cfaPattern[3] == IFD::CFA_GREEN)) {
415  cfa_pattern = OR_CFA_PATTERN_GRBG;
416  }
417  break;
418  case IFD::CFA_BLUE:
419  if ((cfaPattern[2] == IFD::CFA_RED)
420  && (cfaPattern[3] == IFD::CFA_GREEN)) {
421  cfa_pattern = OR_CFA_PATTERN_GBRG;
422  }
423  break;
424  }
425  break;
426  case IFD::CFA_BLUE:
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;
431  }
432  break;
433  }
434  //
435  return MosaicInfo::twoByTwoPattern(cfa_pattern);
436  }
437  return nullptr;
438 }
439 
440 const MosaicInfo *_convertNewCfaPattern(const IfdDir::Ref& dir, IfdEntry& e)
441 {
442  if (e.count() < 4) {
443  return nullptr;
444  }
445 
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) {
449  // cfa_pattern = OR_CFA_PATTERN_NON_RGB22;
450  if (hdim != 6 && vdim != 6) {
451  LOGWARN("CFA pattern dimension %dx%d are incompatible", hdim, vdim);
452  return nullptr;
453  }
454  return XTransPattern::xtransPattern();
455  } else {
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);
462  }
463 }
464 
465 
467 const MosaicInfo *_convertCfaPattern(const IfdDir::Ref& dir, IfdEntry& e)
468 {
469  LOGDBG1("%s\n", __FUNCTION__);
470  auto result = dir->getEntryArrayValue<uint8_t>(e);
471  if (result) {
472  return _convertArrayToCfaPattern(result.value());
473  }
474 
475  return nullptr;
476 }
477 
483 const MosaicInfo *_getMosaicInfo(const IfdDir::Ref & dir)
484 {
485  LOGDBG1("%s\n", __FUNCTION__);
486  const MosaicInfo *mosaic_info = nullptr;
487  try {
488  IfdEntry::Ref e = dir->getEntry(IFD::EXIF_TAG_CFA_PATTERN);
489  if (e) {
490  mosaic_info = _convertCfaPattern(dir, *e);
491  } else {
492  e = dir->getEntry(IFD::EXIF_TAG_NEW_CFA_PATTERN);
493  if (e) {
494  mosaic_info = _convertNewCfaPattern(dir, *e);
495  }
496  }
497  }
498  catch(...)
499  {
500  LOGERR("Exception in _getCfaPattern().\n");
501  }
502  return mosaic_info;
503 }
504 
505 } // end anon namespace
506 
507 
508 ::or_error IfdFile::_getRawData(RawData & data, uint32_t options)
509 {
511  const IfdDir::Ref & _cfaIfd = cfaIfd();
512  LOGDBG1("_getRawData()\n");
513 
514  if(_cfaIfd) {
515  ret = _getRawDataFromDir(data, _cfaIfd);
516  if (ret != OR_ERROR_NONE) {
517  return ret;
518  }
519  ret = _decompressIfNeeded(data, options);
520  }
521  else {
522  ret = OR_ERROR_NOT_FOUND;
523  }
524  return ret;
525 }
526 
527 ::or_error IfdFile::_decompressIfNeeded(RawData&, uint32_t)
528 {
529  return OR_ERROR_NONE;
530 }
531 
532 
533 ::or_error IfdFile::_getRawDataFromDir(RawData & data, const IfdDir::Ref & dir)
534 {
536 
537  uint32_t offset = 0;
538  uint32_t byte_length = 0;
539 
540  if(!dir) {
541  LOGERR("dir is NULL\n");
542  return OR_ERROR_NOT_FOUND;
543  }
544  auto result = dir->getValue<uint16_t>(IFD::EXIF_TAG_BITS_PER_SAMPLE);
545  if(result.empty()) {
546  LOGERR("unable to guess Bits per sample\n");
547  }
548  uint16_t bpc = result.value_or(0);
549 
550  auto result2 = dir->getValue<uint32_t>(IFD::EXIF_TAG_STRIP_OFFSETS);
551  if(result2) {
552  offset = result2.value();
553  IfdEntry::Ref e = dir->getEntry(IFD::EXIF_TAG_STRIP_BYTE_COUNTS);
554  if(!e) {
555  LOGDBG1("byte len not found\n");
556  return OR_ERROR_NOT_FOUND;
557  }
558  auto result3 = dir->getEntryArrayValue<uint32_t>(*e);
559  if (result3) {
560  std::vector<uint32_t> counts = result3.value();
561  LOGDBG1("counting tiles\n");
562  byte_length = std::accumulate(counts.cbegin(), counts.cend(), 0);
563  }
564  }
565  else {
566  // the tile are individual JPEGS....
567  // TODO extract all of them.
568  IfdEntry::Ref e = dir->getEntry(IFD::TIFF_TAG_TILE_OFFSETS);
569  if(!e) {
570  LOGDBG1("tile offsets empty\n");
571  return OR_ERROR_NOT_FOUND;
572  }
573  auto result3 = dir->getEntryArrayValue<uint32_t>(*e);
574  if (!result3) {
575  LOGDBG1("tile offsets not found\n");
576  return OR_ERROR_NOT_FOUND;
577  }
578  std::vector<uint32_t> offsets = result3.value();
579  offset = offsets[0];
580  e = dir->getEntry(IFD::TIFF_TAG_TILE_BYTECOUNTS);
581  if(!e) {
582  LOGDBG1("tile byte counts not found\n");
583  return OR_ERROR_NOT_FOUND;
584  }
585  result3 = dir->getEntryArrayValue<uint32_t>(*e);
586  if (result3) {
587  std::vector<uint32_t> counts = result3.value();
588  LOGDBG1("counting tiles\n");
589  byte_length = std::accumulate(counts.cbegin(), counts.cend(), 0);
590  }
591  }
592 
593  result2 = dir->getIntegerValue(IFD::EXIF_TAG_IMAGE_WIDTH);
594  if(result2.empty()) {
595  LOGDBG1("X not found\n");
596  return OR_ERROR_NOT_FOUND;
597  }
598  uint32_t x = result2.value();
599 
600  result2 = dir->getIntegerValue(IFD::EXIF_TAG_IMAGE_LENGTH);
601  if(!result2) {
602  LOGDBG1("Y not found\n");
603  return OR_ERROR_NOT_FOUND;
604  }
605  uint32_t y = result2.value();
606 
607  uint32_t photo_int
608  = dir->getIntegerValue(IFD::EXIF_TAG_PHOTOMETRIC_INTERPRETATION)
609  .value_or(IFD::EV_PI_CFA);
610 
611  BitmapData::DataType data_type = OR_DATA_TYPE_NONE;
612 
613  result = dir->getValue<uint16_t>(IFD::EXIF_TAG_COMPRESSION);
614  if(!result) {
615  LOGDBG1("Compression type not found\n");
616  }
617  uint32_t compression = _translateCompressionType(
618  static_cast<IFD::TiffCompress>(result.value_or(0)));
619 
620  switch(compression)
621  {
622  case IFD::COMPRESS_NONE:
623  data_type = OR_DATA_TYPE_RAW;
624  break;
625  case IFD::COMPRESS_NIKON_PACK:
626  case IFD::COMPRESS_PENTAX_PACK:
627  data_type = OR_DATA_TYPE_RAW;
628  break;
629  default:
630  data_type = OR_DATA_TYPE_COMPRESSED_RAW;
631  break;
632  }
633 
634  LOGDBG1("RAW Compression is %u\n", compression);
635  LOGDBG1("bpc is %u\n", bpc);
636 
637  const MosaicInfo *mosaic_info = _getMosaicInfo(dir);
638  if (!mosaic_info) {
639  // some file have it in the exif IFD instead.
640  mosaic_info = _getMosaicInfo(exifIfd());
641  }
642 
643 
644  // This is the actual bit per component since we might readjust
645  // for padding.
646  auto actual_bpc = bpc;
647  if((bpc == 12 || bpc == 14) && (compression == IFD::COMPRESS_NONE)
648  && (byte_length == (x * y * 2))) {
649  // We turn this to a 16-bits per sample. MSB are 0
650  LOGDBG1("setting bpc from %u to 16\n", bpc);
651  bpc = 16;
652  }
653  if((bpc == 16) || (data_type == OR_DATA_TYPE_COMPRESSED_RAW)) {
654  void *p = data.allocData(byte_length);
655  size_t real_size = m_container->fetchData(p, offset,
656  byte_length);
657  if (real_size < byte_length) {
658  LOGWARN("Size mismatch for data: ignoring.\n");
659  }
660  }
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);
664  }
665  else {
666  LOGERR("Unsupported bpc %u\n", bpc);
668  }
669  data.setMosaicInfo(mosaic_info);
670  data.setDataType(data_type);
671  data.setBpc(bpc);
672  data.setCompression(data_type == OR_DATA_TYPE_COMPRESSED_RAW
673  ? compression : 1);
674  data.setPhotometricInterpretation((ExifPhotometricInterpretation)photo_int);
675  if(data.whiteLevel() == 0) {
676  data.setWhiteLevel((1 << actual_bpc) - 1);
677  }
678  data.setDimensions(x, y);
679 
680  return ret;
681 }
682 
683 
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)
687 {
689  size_t fetched = 0;
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);
698  size_t got;
699  LOGDBG1("offset of RAW data = %u\n", current_offset);
700  do {
701  got = m_container->fetchData (block.get(),
702  current_offset, blocksize);
703  fetched += got;
704  offset += got;
705  current_offset += got;
706  if (got) {
707  if (bpc == 12) {
708  size_t out;
709  ret = unpack.unpack_be12to16(outdata, outsize,
710  block.get(),
711  got, out);
712  outdata += out / 2;
713  outsize -= out;
714  if (ret != OR_ERROR_NONE) {
715  break;
716  }
717  } else {
718  std::copy(block.get(), block.get() + got, outdata);
719  outdata += got;
720  }
721  }
722  } while((got != 0) && (fetched < byte_length));
723 
724  return ret;
725 }
726 
727 }
728 }
729 
730 /*
731  Local Variables:
732  mode:c++
733  c-file-style:"stroustrup"
734  c-file-offsets:((innamespace . 0))
735  tab-width:4
736  c-basic-offset:4
737  indent-tabs-mode:nil
738  fill-column:80
739  End:
740 */
void setDataType(DataType _type)
Set the data type.
Definition: bitmapdata.cpp:91
void setBpc(uint32_t _bpc)
Set bit per channel.
Definition: bitmapdata.cpp:152
std::shared_ptr< Stream > Ptr
Definition: stream.hpp:47
std::shared_ptr< IfdDir > Ref
Shared ptr of an IfdDir.
Definition: ifddir.hpp:56
std::shared_ptr< IfdEntry > Ref
IfdEntry reference (ie shared pointer)
Definition: ifdentry.hpp:202
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
Definition: unpack.cpp:58
Metadata value.
Definition: metavalue.hpp:35
Info on the mosaic for the Colour Filter Array.
Definition: mosaicinfo.hpp:33
Represent camera raw data.
Definition: rawdata.hpp:38
virtual void setDimensions(uint32_t x, uint32_t y) override
Set the pixel dimensions of the bitmap.
Definition: rawdata.cpp:297
#define META_NS_MASKOUT(x)
Mask the namespace out.
Definition: metadata.h:56
#define META_INDEX_MASKOUT(x)
Mask the index out.
Definition: metadata.h:58
@ META_NS_TIFF
Definition: metadata.h:52
@ META_NS_EXIF
Definition: metadata.h:51
or_cfa_pattern
CFA pattern types.
Definition: consts.h:94
or_data_type
Data types.
Definition: consts.h:80
or_error
Error codes returned by libopenraw.
Definition: consts.h:42
@ OR_CFA_PATTERN_NON_RGB22
Definition: consts.h:96
@ OR_DATA_TYPE_JPEG
Definition: consts.h:84
@ OR_DATA_TYPE_COMPRESSED_RAW
Definition: consts.h:88
@ OR_DATA_TYPE_RAW
Definition: consts.h:87
@ OR_DATA_TYPE_PIXMAP_8RGB
Definition: consts.h:82
@ OR_IFD_MAIN
Main (like in TIFF)
Definition: consts.h:144
@ OR_ERROR_NONE
Definition: consts.h:43
@ OR_ERROR_INVALID_FORMAT
Definition: consts.h:50
@ OR_ERROR_NOT_FOUND
Definition: consts.h:48
TiffCompress
TIFF compression.
Definition: ifd.hpp:55
std::map< uint32_t, ::or_rawfile_typeid > ModelIdMap
Definition: rawfile.hpp:54
Global namespace for libopenraw.
Definition: arwfile.cpp:29