libopenraw  0.3.7
crwfile.cpp
1 /*
2  * libopenraw - crwfile.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 <fcntl.h>
23 #include <stddef.h>
24 #include <cstdint>
25 #include <algorithm>
26 #include <functional>
27 #include <memory>
28 #include <map>
29 
30 #include <libopenraw/debug.h>
31 #include <libopenraw/metadata.h>
32 #include <libopenraw/cameraids.h>
33 
34 #include "rawdata.hpp"
35 #include "metavalue.hpp"
36 #include "mosaicinfo.hpp"
37 #include "rawfile.hpp"
38 #include "trace.hpp"
39 #include "io/streamclone.hpp"
40 #include "io/memstream.hpp"
41 #include "crwfile.hpp"
42 #include "ciffcontainer.hpp"
43 #include "jfifcontainer.hpp"
44 #include "crwdecompressor.hpp"
45 #include "rawfile_private.hpp"
46 #include "canon.hpp"
47 #include "ciff/ciffifd.hpp"
48 
49 using namespace Debug;
50 
51 namespace OpenRaw {
52 
53 namespace Internals {
54 
55 using namespace CIFF;
56 
57 #define OR_MAKE_CANON_TYPEID(camid) \
58  OR_MAKE_FILE_TYPEID(OR_TYPEID_VENDOR_CANON,camid)
59 
60 /* taken from dcraw, by default */
61 static const BuiltinColourMatrix s_matrices[] = {
62  { OR_MAKE_CANON_TYPEID(OR_TYPEID_CANON_D30), 0, 0,
63  { 9805,-2689,-1312,-5803,13064,3068,-2438,3075,8775 } },
64  { OR_MAKE_CANON_TYPEID(OR_TYPEID_CANON_D60), 0, 0xfa0,
65  { 6188,-1341,-890,-7168,14489,2937,-2640,3228,8483 } },
66  { OR_MAKE_CANON_TYPEID(OR_TYPEID_CANON_10D), 0, 0xfa0,
67  { 8197,-2000,-1118,-6714,14335,2592,-2536,3178,8266 } },
68  { OR_MAKE_CANON_TYPEID(OR_TYPEID_CANON_300D), 0, 0xfa0,
69  { 8197,-2000,-1118,-6714,14335,2592,-2536,3178,8266 } },
70 // { OR_MAKE_CANON_TYPEID(OR_TYPEID_CANON_G1), 0, 0,
71 // { -4778,9467,2172,4743,-1141,4344,-5146,9908,6077,-1566,11051,557 } },
72  { OR_MAKE_CANON_TYPEID(OR_TYPEID_CANON_G2), 0, 0,
73  { 9087,-2693,-1049,-6715,14382,2537,-2291,2819,7790 } },
74  { OR_MAKE_CANON_TYPEID(OR_TYPEID_CANON_G3), 0, 0,
75  { 9212,-2781,-1073,-6573,14189,2605,-2300,2844,7664 } },
76  { OR_MAKE_CANON_TYPEID(OR_TYPEID_CANON_G5), 0, 0,
77  { 9757,-2872,-933,-5972,13861,2301,-1622,2328,7212 } },
78  { OR_MAKE_CANON_TYPEID(OR_TYPEID_CANON_G6), 0, 0,
79  { 9877,-3775,-871,-7613,14807,3072,-1448,1305,7485 } },
80  { OR_MAKE_CANON_TYPEID(OR_TYPEID_CANON_PRO1), 0, 0,
81  { 10062,-3522,-999,-7643,15117,2730,-765,817,7323 } },
82  { OR_MAKE_CANON_TYPEID(OR_TYPEID_CANON_S30), 0, 0,
83  { 10566, -3652, -1129, -6552, 14662, 2006, -2197, 2581, 7670 } },
84  { OR_MAKE_CANON_TYPEID(OR_TYPEID_CANON_S40), 0, 0,
85  { 8510, -2487, -940, -6869, 14231, 2900, -2318, 2829, 9013 } },
86  { OR_MAKE_CANON_TYPEID(OR_TYPEID_CANON_S45), 0, 0,
87  { 8163, -2333, -955, -6682, 14174, 2751, -2077, 2597, 8041 } },
88  { OR_MAKE_CANON_TYPEID(OR_TYPEID_CANON_S50), 0, 0,
89  { 8882, -2571, -863, -6348, 14234, 2288, -1516, 2172, 6569 } },
90  { OR_MAKE_CANON_TYPEID(OR_TYPEID_CANON_S60), 0, 0,
91  { 8795, -2482, -797, -7804, 15403, 2573, -1422, 1996, 7082 } },
92  { OR_MAKE_CANON_TYPEID(OR_TYPEID_CANON_S70), 0, 0,
93  { 9976, -3810, -832, -7115, 14463, 2906, -901, 989, 7889 } },
94  { 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0, 0, 0 } }
95 };
96 
97 const RawFile::camera_ids_t CRWFile::s_def[] = {
98  { "Canon EOS D30" , OR_MAKE_CANON_TYPEID(OR_TYPEID_CANON_D30) },
99  { "Canon EOS D60" , OR_MAKE_CANON_TYPEID(OR_TYPEID_CANON_D60) },
100  { "Canon EOS 10D" , OR_MAKE_CANON_TYPEID(OR_TYPEID_CANON_10D) },
101  { "Canon EOS DIGITAL REBEL", OR_MAKE_CANON_TYPEID(OR_TYPEID_CANON_DIGITAL_REBEL) },
102  { "Canon EOS 300D DIGITAL", OR_MAKE_CANON_TYPEID(OR_TYPEID_CANON_300D) },
103  { "Canon PowerShot G1", OR_MAKE_CANON_TYPEID(OR_TYPEID_CANON_G1) },
104  { "Canon PowerShot G2", OR_MAKE_CANON_TYPEID(OR_TYPEID_CANON_G2) },
105  { "Canon PowerShot G3", OR_MAKE_CANON_TYPEID(OR_TYPEID_CANON_G3) },
106  { "Canon PowerShot G5", OR_MAKE_CANON_TYPEID(OR_TYPEID_CANON_G5) },
107  { "Canon PowerShot G6", OR_MAKE_CANON_TYPEID(OR_TYPEID_CANON_G6) },
108 // G7 is CHDK, So remove from the list from now.
109 // { "Canon PowerShot G7", OR_MAKE_CANON_TYPEID(OR_TYPEID_CANON_G7) },
110  { "Canon PowerShot Pro1", OR_MAKE_CANON_TYPEID(OR_TYPEID_CANON_PRO1) },
111  { "Canon PowerShot Pro70", OR_MAKE_CANON_TYPEID(OR_TYPEID_CANON_PRO70) },
112  { "Canon PowerShot Pro90 IS", OR_MAKE_CANON_TYPEID(OR_TYPEID_CANON_PRO90) },
113  { "Canon PowerShot S30", OR_MAKE_CANON_TYPEID(OR_TYPEID_CANON_S30) },
114  { "Canon PowerShot S40", OR_MAKE_CANON_TYPEID(OR_TYPEID_CANON_S40) },
115  { "Canon PowerShot S45", OR_MAKE_CANON_TYPEID(OR_TYPEID_CANON_S45) },
116  { "Canon PowerShot S50", OR_MAKE_CANON_TYPEID(OR_TYPEID_CANON_S50) },
117  { "Canon PowerShot S60", OR_MAKE_CANON_TYPEID(OR_TYPEID_CANON_S60) },
118  { "Canon PowerShot S70", OR_MAKE_CANON_TYPEID(OR_TYPEID_CANON_S70) },
119  { 0, 0 }
120 };
121 
122 RawFile *CRWFile::factory(const IO::Stream::Ptr &s)
123 {
124  return new CRWFile(s);
125 }
126 
127 CRWFile::CRWFile(const IO::Stream::Ptr &s)
128  : RawFile(OR_RAWFILE_TYPE_CRW),
129  m_io(s),
130  m_container(new CIFFContainer(m_io)),
131  m_x(0), m_y(0)
132 {
133  _setIdMap(s_def);
134  _setMatrices(s_matrices);
135 }
136 
137 CRWFile::~CRWFile()
138 {
139  delete m_container;
140 }
141 
142 ::or_error CRWFile::_enumThumbnailSizes(std::vector<uint32_t> &list)
143 {
145 
146  HeapRef heap = m_container->heap();
147  if(!heap) {
148  // this is not a CIFF file.
149  return err;
150  }
151  const RecordEntries& records = heap->records();
152  RecordEntries::const_iterator iter;
153  iter = records.find(TAG_JPEGIMAGE);
154  if (iter != records.end()) {
155  LOGDBG2("JPEG @%u\n", iter->second.offset());
156  m_x = m_y = 0;
157  uint32_t offset = heap->offset() + iter->second.offset();
158  IO::StreamClone::Ptr s(new IO::StreamClone(m_io, offset));
159  auto jfif = std::make_unique<JfifContainer>(s, 0);
160 
161  jfif->getDimensions(m_x, m_y);
162  LOGDBG1("JPEG dimensions x=%d y=%d\n", m_x, m_y);
163  uint32_t dim = std::max(m_x,m_y);
164  _addThumbnail(dim, ThumbDesc(m_x, m_y, OR_DATA_TYPE_JPEG, offset, iter->second.length()));
165  list.push_back(dim);
166  err = OR_ERROR_NONE;
167  }
168 
169  return err;
170 }
171 
172 RawContainer* CRWFile::getContainer() const
173 {
174  return m_container;
175 }
176 
177 ::or_error CRWFile::_getRawData(RawData & data, uint32_t options)
178 {
180 
181  const ImageSpec * img_spec = m_container->getImageSpec();
182  uint32_t x, y;
183  x = y = 0;
184  if(img_spec) {
185  x = img_spec->imageWidth;
186  y = img_spec->imageHeight;
187  }
188 
189  // locate decoder table
190  HeapRef exifProps = m_container->getExifInfo();
191  if (!exifProps) {
192  LOGERR("Couldn't find the exif info table.\n");
193  return err;
194  }
195  const RecordEntries& exifPropsRecs = exifProps->records();
196  auto iter = exifPropsRecs.find(TAG_DECODERTABLE);
197  if (iter == exifPropsRecs.end()) {
198  LOGERR("Couldn't find the decoder table.\n");
199  return err;
200  }
201  LOGDBG2("length = %d\n", iter->second.length());
202  LOGDBG2("offset = %lld\n", (long long int)(exifProps->offset() + iter->second.offset()));
203  auto file = m_container->file();
204  file->seek(exifProps->offset() + iter->second.offset(), SEEK_SET);
205 
206  auto result = m_container->readUInt32(file, m_container->endian());
207  if(result.empty()) {
208  LOGERR("Couldn't find decoder table\n");
209  return OR_ERROR_NOT_FOUND;
210  }
211 
212  uint32_t decoderTable = result.value();
213  LOGDBG2("decoder table = %u\n", decoderTable);
214 
215  // locate the CFA info
216  iter = exifPropsRecs.find(TAG_SENSORINFO);
217  if (iter == exifPropsRecs.end()) {
218  LOGERR("Couldn't find the sensor info.\n");
219  return err;
220  }
221  LOGDBG2("length = %u\n", iter->second.length());
222  LOGDBG2("offset = %lld\n", (long long int)(exifProps->offset() + iter->second.offset()));
223 
224  // This is the SensorInfo tag
225  // https://exiftool.org/TagNames/Canon.html#SensorInfo
226  file->seek(exifProps->offset() + iter->second.offset(), SEEK_SET);
227 
228  std::vector<uint16_t> sensor_info;
229  auto count_read = m_container->readUInt16Array(file, sensor_info, 9);
230  if (count_read != 9) {
231  LOGERR("SensorInfo short read %lu.\n", (LSIZE)count_read);
232  return OR_ERROR_NOT_FOUND;
233  }
234  LOGDBG1("read sensor info %lu\n", (LSIZE)count_read);
235  auto cfa_x = sensor_info[1];
236  auto cfa_y = sensor_info[2];
237  LOGDBG2("cfa, x %u, y %u\n", cfa_x, cfa_y);
238 
239  auto active_area = canon_parse_sensorinfo(sensor_info);
240  if (!active_area) {
241  LOGERR("SensorInfo: couldn't get active area.\n");
242  return OR_ERROR_NOT_FOUND;
243  }
244 
245  const RecordEntry *entry = m_container->getRawDataRecord();
246  if (entry) {
247  CIFF::HeapRef heap = m_container->heap();
248  LOGDBG2("RAW @%lld\n", (long long int)(heap->offset() + entry->offset()));
249  size_t byte_size = entry->length();
250  void *buf = data.allocData(byte_size);
251  size_t real_size = entry->fetchData(heap.get(), buf, byte_size);
252  if (real_size != byte_size) {
253  LOGWARN("wrong size\n");
254  }
255  data.setDimensions(x, y);
256  data.setCfaPatternType(OR_CFA_PATTERN_RGGB);
258 
259  // decompress if we need
260  if((options & OR_OPTIONS_DONT_DECOMPRESS) == 0) {
261  auto s = std::make_unique<IO::MemStream>((const uint8_t*)data.data(), data.size());
262  s->open(); // TODO check success
263 
264  CrwDecompressor decomp(s.get(), m_container);
265 
266  decomp.setOutputDimensions(cfa_x, cfa_y);
267  decomp.setDecoderTable(decoderTable);
268  RawDataPtr dData = decomp.decompress();
269  if (dData) {
270  LOGDBG1("Out size is %dx%d\n", dData->width(), dData->height());
271  dData->setCfaPatternType(data.mosaicInfo()->patternType());
272  dData->setPhotometricInterpretation(data.getPhotometricInterpretation());
273  data.swap(*dData);
274  }
275  }
276  data.setActiveArea((*active_area)[0], (*active_area)[1],
277  (*active_area)[2], (*active_area)[3]);
278  err = OR_ERROR_NONE;
279  }
280  return err;
281 }
282 
283 Option<uint32_t> CRWFile::getOrientation() const
284 {
285  const ImageSpec * img_spec = m_container->getImageSpec();
286  if (img_spec) {
287  return static_cast<uint32_t>(img_spec->exifOrientation());
288  }
289  return OptionNone();
290 }
291 
292 Option<std::string> CRWFile::getMakeOrModel(uint32_t index)
293 {
294  if (index == EXIF_TAG_MAKE && !m_make.empty()) {
295  return m_make;
296  } else if (index == EXIF_TAG_MODEL && !m_model.empty()) {
297  return m_model;
298  }
299 
301  CIFF::HeapRef heap = m_container->getCameraProps();
302  if (heap) {
303  auto propsRecs = heap->records();
304  auto iter = propsRecs.find(TAG_RAWMAKEMODEL);
305  if (iter == propsRecs.end()) {
306  LOGERR("Couldn't find the image info.\n");
307  } else {
308  char buf[256];
309  size_t sz = iter->second.length();
310  if(sz > 256) {
311  sz = 256;
312  }
313  /*size_t sz2 = */iter->second.fetchData(heap.get(),
314  (void*)buf, sz);
315  const char *p = buf;
316  while(*p) {
317  p++;
318  }
319  m_make = std::string(buf, p - buf);
320  p++;
321  m_model = p;
322 
323  if (index == EXIF_TAG_MODEL) {
324  val = m_model;
325  } else if (index == EXIF_TAG_MAKE) {
326  val = m_make;
327  }
328  LOGDBG1("Make %s\n", m_make.c_str());
329  LOGDBG1("Model %s\n", m_model.c_str());
330  }
331  }
332  return val;
333 }
334 
335 MetaValue *CRWFile::_getMetaValue(int32_t meta_index)
336 {
337  MetaValue * val = NULL;
338 
339  switch(META_INDEX_MASKOUT(meta_index)) {
340  case META_NS_TIFF:
341  {
342  uint32_t index = META_NS_MASKOUT(meta_index);
343  switch(index) {
344  case EXIF_TAG_ORIENTATION:
345  {
346  auto orientation = getOrientation();
347  if (orientation) {
348  val = new MetaValue(orientation.value());
349  }
350  break;
351  }
352  case EXIF_TAG_MAKE:
353  case EXIF_TAG_MODEL:
354  {
355  auto tag = getMakeOrModel(index);
356  if (tag) {
357  val = new MetaValue(tag.value());
358  }
359  break;
360  }
361  }
362  break;
363  }
364  case META_NS_EXIF:
365  break;
366  default:
367  LOGERR("Unknown Meta Namespace\n");
368  break;
369  }
370 
371  return val;
372 }
373 
374 IfdDir::Ref CRWFile::_locateMainIfd()
375 {
376  auto ifd = std::make_shared<CiffMainIfd>(*this, *m_container);
377  ifd->load();
378  return ifd;
379 }
380 
381 IfdDir::Ref CRWFile::_locateExifIfd()
382 {
383  auto ifd = std::make_shared<CiffExifIfd>(*this, *m_container);
384  ifd->load();
385  return ifd;
386 }
387 
388 void CRWFile::_identifyId()
389 {
390  std::string model;
391  std::string make;
392  try {
393  MetaValue * v = _getMetaValue(META_NS_TIFF | EXIF_TAG_MODEL);
394  if(v) {
395  model = v->getString(0);
396  }
397  delete v;
398  v = _getMetaValue(META_NS_TIFF | EXIF_TAG_MAKE);
399  if(v) {
400  make = v->getString(0);
401  }
402  delete v;
403  _setTypeId(_typeIdFromModel(make, model));
404  }
405  catch(...)
406  {
407  }
408 }
409 
410 }
411 }
412 
413 /*
414  Local Variables:
415  mode:c++
416  c-file-style:"stroustrup"
417  c-file-offsets:((innamespace . 0))
418  c-basic-offset: 4
419  tab-width: 4
420  indent-tabs-mode:nil
421  fill-column:80
422  End:
423 */
void setDataType(DataType _type)
Set the data type.
Definition: bitmapdata.cpp:91
size_t size() const
Get the size of the data.
Definition: bitmapdata.cpp:120
cloned stream. Allow reading from a different offset
Definition: streamclone.hpp:41
std::shared_ptr< Stream > Ptr
Definition: stream.hpp:47
ImageSpec struct from CIFF.
A record entry from a CIFF Heap.
Definition: recordentry.hpp:69
size_t fetchData(Heap *heap, void *buf, size_t size) const
Definition: recordentry.cpp:76
Heap heap(Heap &h, const CIFFContainer *container) const
Definition: recordentry.cpp:82
virtual RawDataPtr decompress() override
std::shared_ptr< IfdDir > Ref
Shared ptr of an IfdDir.
Definition: ifddir.hpp:56
Generic interface for the RAW file container.
Metadata value.
Definition: metavalue.hpp:35
::or_cfa_pattern patternType() const
Definition: mosaicinfo.cpp:199
Represent camera raw data.
Definition: rawdata.hpp:38
void swap(RawData &with)
Definition: rawdata.cpp:282
const MosaicInfo * mosaicInfo() const
Definition: rawdata.cpp:335
virtual void setDimensions(uint32_t x, uint32_t y) override
Set the pixel dimensions of the bitmap.
Definition: rawdata.cpp:297
Tag class to help create an empty Option.
Definition: option.hpp:41
An option type inspired by Rust.
Definition: option.hpp:47
Option< std::array< uint32_t, 4 > > canon_parse_sensorinfo(const std::vector< uint16_t > &sensor_info)
Parse the sensor info from a buffer of uint16_t.
Definition: canon.cpp:141
std::shared_ptr< Heap > HeapRef
Shared ptr to Heap.
Definition: heap.hpp:38
#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_error
Error codes returned by libopenraw.
Definition: consts.h:42
@ OR_DATA_TYPE_JPEG
Definition: consts.h:84
@ OR_DATA_TYPE_COMPRESSED_RAW
Definition: consts.h:88
@ OR_OPTIONS_DONT_DECOMPRESS
Definition: consts.h:114
@ OR_RAWFILE_TYPE_CRW
Definition: consts.h:62
@ OR_ERROR_NONE
Definition: consts.h:43
@ OR_ERROR_NOT_FOUND
Definition: consts.h:48
std::map< uint16_t, RecordEntry > RecordEntries
Definition: recordentry.hpp:65
Global namespace for libopenraw.
Definition: arwfile.cpp:29