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
49namespace OpenRaw {
50
51class MetaValue;
52
53namespace Internals {
54
55
56IfdFile::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
67IfdFile::~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
74IfdDir::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
84MakerNoteDir::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
94void 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
112IfdFile::_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
279RawContainer* IfdFile::getContainer() const
280{
281 return m_container;
282}
283
284uint32_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
299MetaValue *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
325uint32_t IfdFile::_translateCompressionType(IFD::TiffCompress tiff_compression)
326{
327 return (uint32_t)tiff_compression;
328}
329
330
331
332const IfdDir::Ref & IfdFile::cfaIfd()
333{
334 if(!m_cfaIfd) {
335 m_cfaIfd = _locateCfaIfd();
336 }
337 return m_cfaIfd;
338}
339
340
341const IfdDir::Ref & IfdFile::mainIfd()
342{
343 if(!m_mainIfd) {
344 m_mainIfd = _locateMainIfd();
345 }
346 return m_mainIfd;
347}
348
349
350const IfdDir::Ref & IfdFile::exifIfd()
351{
352 if(!m_exifIfd) {
353 m_exifIfd = _locateExifIfd();
354 }
355 return m_exifIfd;
356}
357
358
359const MakerNoteDir::Ref & IfdFile::makerNoteIfd()
360{
361 if(!m_makerNoteIfd) {
362 m_makerNoteIfd = _locateMakerNoteIfd();
363 }
364 return m_makerNoteIfd;
365}
366
367
368namespace {
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
459static ::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
661IfdFile::_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*/
void setDataType(DataType _type)
Definition: bitmapdata.cpp:100
void setBpc(uint32_t _bpc)
Definition: bitmapdata.cpp:164
std::shared_ptr< IfdEntry > Ref
Definition: ifdentry.hpp:165
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 void setDimensions(uint32_t x, uint32_t y) override
Definition: rawdata.cpp:260
CIFF is the container for CRW files. It is an attempt from Canon to make this a standard....
Definition: arwfile.cpp:30