libopenraw
crwfile.cpp
1 /*
2  * libopenraw - crwfile.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 <fcntl.h>
23 #include <stddef.h>
24 #include <cstdint>
25 #include <algorithm>
26 #include <functional>
27 #include <memory>
28 
29 #include <libopenraw/debug.h>
30 #include <libopenraw/metadata.h>
31 #include <libopenraw/cameraids.h>
32 
33 #include "rawdata.hpp"
34 #include "metavalue.hpp"
35 #include "cfapattern.hpp"
36 #include "rawfile.hpp"
37 #include "trace.hpp"
38 #include "io/streamclone.hpp"
39 #include "io/memstream.hpp"
40 #include "crwfile.hpp"
41 #include "ciffcontainer.hpp"
42 #include "jfifcontainer.hpp"
43 #include "crwdecompressor.hpp"
44 #include "rawfile_private.hpp"
45 
46 using namespace Debug;
47 
48 namespace OpenRaw {
49 
50 namespace Internals {
51 
52 using namespace CIFF;
53 
54 #define OR_MAKE_CANON_TYPEID(camid) \
55  OR_MAKE_FILE_TYPEID(OR_TYPEID_VENDOR_CANON,camid)
56 
57 /* taken from dcraw, by default */
58 static const BuiltinColourMatrix s_matrices[] = {
59  { OR_MAKE_CANON_TYPEID(OR_TYPEID_CANON_D30), 0, 0,
60  { 9805,-2689,-1312,-5803,13064,3068,-2438,3075,8775 } },
61  { OR_MAKE_CANON_TYPEID(OR_TYPEID_CANON_D60), 0, 0xfa0,
62  { 6188,-1341,-890,-7168,14489,2937,-2640,3228,8483 } },
63  { OR_MAKE_CANON_TYPEID(OR_TYPEID_CANON_10D), 0, 0xfa0,
64  { 8197,-2000,-1118,-6714,14335,2592,-2536,3178,8266 } },
65  { OR_MAKE_CANON_TYPEID(OR_TYPEID_CANON_300D), 0, 0xfa0,
66  { 8197,-2000,-1118,-6714,14335,2592,-2536,3178,8266 } },
67 // { OR_MAKE_CANON_TYPEID(OR_TYPEID_CANON_G1), 0, 0,
68 // { -4778,9467,2172,4743,-1141,4344,-5146,9908,6077,-1566,11051,557 } },
69  { OR_MAKE_CANON_TYPEID(OR_TYPEID_CANON_G2), 0, 0,
70  { 9087,-2693,-1049,-6715,14382,2537,-2291,2819,7790 } },
71  { OR_MAKE_CANON_TYPEID(OR_TYPEID_CANON_G3), 0, 0,
72  { 9212,-2781,-1073,-6573,14189,2605,-2300,2844,7664 } },
73  { OR_MAKE_CANON_TYPEID(OR_TYPEID_CANON_G5), 0, 0,
74  { 9757,-2872,-933,-5972,13861,2301,-1622,2328,7212 } },
75  { OR_MAKE_CANON_TYPEID(OR_TYPEID_CANON_G6), 0, 0,
76  { 9877,-3775,-871,-7613,14807,3072,-1448,1305,7485 } },
77  { OR_MAKE_CANON_TYPEID(OR_TYPEID_CANON_PRO1), 0, 0,
78  { 10062,-3522,-999,-7643,15117,2730,-765,817,7323 } },
79  { 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0, 0, 0 } }
80 };
81 
82 const RawFile::camera_ids_t CRWFile::s_def[] = {
83  { "Canon EOS D30" , OR_MAKE_CANON_TYPEID(OR_TYPEID_CANON_D30) },
84  { "Canon EOS D60" , OR_MAKE_CANON_TYPEID(OR_TYPEID_CANON_D60) },
85  { "Canon EOS 10D" , OR_MAKE_CANON_TYPEID(OR_TYPEID_CANON_10D) },
86  { "Canon EOS 300D DIGITAL", OR_MAKE_CANON_TYPEID(OR_TYPEID_CANON_300D) },
87  { "Canon PowerShot G1", OR_MAKE_CANON_TYPEID(OR_TYPEID_CANON_G1) },
88  { "Canon PowerShot G2", OR_MAKE_CANON_TYPEID(OR_TYPEID_CANON_G2) },
89  { "Canon PowerShot G3", OR_MAKE_CANON_TYPEID(OR_TYPEID_CANON_G3) },
90  { "Canon PowerShot G5", OR_MAKE_CANON_TYPEID(OR_TYPEID_CANON_G5) },
91  { "Canon PowerShot G6", OR_MAKE_CANON_TYPEID(OR_TYPEID_CANON_G6) },
92  { "Canon PowerShot G7", OR_MAKE_CANON_TYPEID(OR_TYPEID_CANON_G7) },
93  { "Canon PowerShot Pro1", OR_MAKE_CANON_TYPEID(OR_TYPEID_CANON_PRO1) },
94  { 0, 0 }
95 };
96 
97 RawFile *CRWFile::factory(const IO::Stream::Ptr &s)
98 {
99  return new CRWFile(s);
100 }
101 
102 CRWFile::CRWFile(const IO::Stream::Ptr &s)
103  : RawFile(OR_RAWFILE_TYPE_CRW),
104  m_io(s),
105  m_container(new CIFFContainer(m_io)),
106  m_x(0), m_y(0)
107 {
108  _setIdMap(s_def);
109  _setMatrices(s_matrices);
110 }
111 
112 CRWFile::~CRWFile()
113 {
114  delete m_container;
115 }
116 
117 ::or_error CRWFile::_enumThumbnailSizes(std::vector<uint32_t> &list)
118 {
119  ::or_error err = OR_ERROR_NOT_FOUND;
120 
121  Heap::Ref heap = m_container->heap();
122  if(!heap) {
123  // this is not a CIFF file.
124  return err;
125  }
126  const RecordEntry::List & records = heap->records();
127  RecordEntry::List::const_iterator iter;
128  iter = std::find_if(records.cbegin(), records.cend(), std::bind(
129  &RecordEntry::isA, std::placeholders::_1,
130  static_cast<uint16_t>(TAG_JPEGIMAGE)));
131  if (iter != records.end()) {
132  LOGDBG2("JPEG @%u\n", (*iter).offset);
133  m_x = m_y = 0;
134  uint32_t offset = heap->offset() + (*iter).offset;
135  IO::StreamClone::Ptr s(new IO::StreamClone(m_io, offset));
136  std::unique_ptr<JfifContainer> jfif(new JfifContainer(s, 0));
137 
138  jfif->getDimensions(m_x, m_y);
139  LOGDBG1("JPEG dimensions x=%d y=%d\n", m_x, m_y);
140  uint32_t dim = std::max(m_x,m_y);
141  _addThumbnail(dim, ThumbDesc(m_x, m_y, OR_DATA_TYPE_JPEG, offset, (*iter).length));
142  list.push_back(dim);
143  err = OR_ERROR_NONE;
144  }
145 
146  return err;
147 }
148 
150 {
151  return m_container;
152 }
153 
154 ::or_error CRWFile::_getRawData(RawData & data, uint32_t options)
155 {
156  ::or_error err = OR_ERROR_NOT_FOUND;
157  Heap::Ref props = m_container->getImageProps();
158 
159  if(!props) {
160  return OR_ERROR_NOT_FOUND;
161  }
162  const ImageSpec * img_spec = m_container->getImageSpec();
163  uint32_t x, y;
164  x = y = 0;
165  if(img_spec) {
166  x = img_spec->imageWidth;
167  y = img_spec->imageHeight;
168  }
169 
170  // locate decoder table
171  const CIFF::RecordEntry::List & propsRecs = props->records();
172  auto iter = std::find_if(propsRecs.cbegin(), propsRecs.cend(), std::bind(
173  &RecordEntry::isA, std::placeholders::_1,
174  static_cast<uint16_t>(TAG_EXIFINFORMATION)));
175  if (iter == propsRecs.end()) {
176  LOGERR("Couldn't find the Exif information.\n");
177  return OR_ERROR_NOT_FOUND;
178  }
179 
180  Heap exifProps(iter->offset + props->offset(), iter->length, m_container);
181 
182  const RecordEntry::List & exifPropsRecs = exifProps.records();
183  iter = std::find_if(exifPropsRecs.cbegin(), exifPropsRecs.cend(),
184  std::bind(
185  &RecordEntry::isA, std::placeholders::_1,
186  static_cast<uint16_t>(TAG_DECODERTABLE)));
187  if (iter == exifPropsRecs.end()) {
188  LOGERR("Couldn't find the decoder table.\n");
189  return err;
190  }
191  LOGDBG2("length = %d\n", iter->length);
192  LOGDBG2("offset = %ld\n", exifProps.offset() + iter->offset);
193  auto file = m_container->file();
194  file->seek(exifProps.offset() + iter->offset, SEEK_SET);
195 
196  auto result = m_container->readUInt32(file);
197  if(result.empty()) {
198  LOGERR("Couldn't find decoder table\n");
199  return OR_ERROR_NOT_FOUND;
200  }
201 
202  uint32_t decoderTable = result.unwrap();
203  LOGDBG2("decoder table = %u\n", decoderTable);
204 
205  // locate the CFA info
206  iter = std::find_if(exifPropsRecs.cbegin(), exifPropsRecs.cend(), std::bind(
207  &RecordEntry::isA, std::placeholders::_1,
208  static_cast<uint16_t>(TAG_SENSORINFO)));
209  if (iter == exifPropsRecs.end()) {
210  LOGERR("Couldn't find the sensor info.\n");
211  return err;
212  }
213  LOGDBG2("length = %u\n", iter->length);
214  LOGDBG2("offset = %ld\n", exifProps.offset() + iter->offset);
215 
216  // go figure what the +2 is. looks like it is the byte #
217  file->seek(exifProps.offset() + iter->offset + 2, SEEK_SET);
218 
219  auto cfa_x = m_container->readUInt16(file);
220  auto cfa_y = m_container->readUInt16(file);
221  if(cfa_x.empty() || cfa_y.empty()) {
222  LOGERR("Couldn't find the sensor size.\n");
223  return OR_ERROR_NOT_FOUND;
224  }
225 
226 
227  const CIFF::RecordEntry *entry = m_container->getRawDataRecord();
228  if (entry) {
229  CIFF::Heap::Ref heap = m_container->heap();
230  LOGDBG2("RAW @%ld\n", heap->offset() + entry->offset);
231  size_t byte_size = entry->length;
232  void *buf = data.allocData(byte_size);
233  size_t real_size = entry->fetchData(heap.get(), buf, byte_size);
234  if (real_size != byte_size) {
235  LOGWARN("wrong size\n");
236  }
237  data.setDimensions(x, y);
238  data.setCfaPatternType(OR_CFA_PATTERN_RGGB);
239  data.setDataType(OR_DATA_TYPE_COMPRESSED_RAW);
240 
241  // decompress if we need
242  if((options & OR_OPTIONS_DONT_DECOMPRESS) == 0) {
243  std::unique_ptr<IO::Stream> s(new IO::MemStream(data.data(),
244  data.size()));
245  s->open(); // TODO check success
246 
247  CrwDecompressor decomp(s.get(), m_container);
248 
249  decomp.setOutputDimensions(cfa_x.unwrap(), cfa_y.unwrap());
250  decomp.setDecoderTable(decoderTable);
251  RawDataPtr dData = decomp.decompress();
252  if (dData) {
253  LOGDBG1("Out size is %dx%d\n", dData->width(), dData->height());
254  dData->setCfaPatternType(data.cfaPattern()->patternType());
255  data.swap(*dData);
256  }
257  }
258  err = OR_ERROR_NONE;
259  }
260  return err;
261 }
262 
263 MetaValue *CRWFile::_getMetaValue(int32_t meta_index)
264 {
265  MetaValue * val = NULL;
266 
267  switch(META_INDEX_MASKOUT(meta_index)) {
268  case META_NS_TIFF:
269  {
270  uint32_t index = META_NS_MASKOUT(meta_index);
271  switch(index) {
272  case EXIF_TAG_ORIENTATION:
273  {
274  const ImageSpec * img_spec = m_container->getImageSpec();
275  if(img_spec) {
276  val = new MetaValue(static_cast<uint32_t>(
277  img_spec->exifOrientation()));
278  }
279  break;
280  }
281  case EXIF_TAG_MAKE:
282  case EXIF_TAG_MODEL:
283  {
284  if (index == EXIF_TAG_MAKE && !m_make.empty()) {
285  val = new MetaValue(m_make);
286  break;
287  }
288  if (index == EXIF_TAG_MODEL && !m_model.empty()) {
289  val = new MetaValue(m_model);
290  break;
291  }
292 
293  CIFF::Heap::Ref heap = m_container->getCameraProps();
294  if(heap) {
295  auto propsRecs = heap->records();
296  auto iter
297  = std::find_if(propsRecs.cbegin(), propsRecs.cend(),
298  [](const CIFF::RecordEntry &e){
299  return e.isA(static_cast<uint16_t>(CIFF::TAG_RAWMAKEMODEL));
300  });
301  if (iter == propsRecs.end()) {
302  LOGERR("Couldn't find the image info.\n");
303  }
304  else {
305  char buf[256];
306  size_t sz = iter->length;
307  if(sz > 256) {
308  sz = 256;
309  }
310  /*size_t sz2 = */iter->fetchData(heap.get(),
311  (void*)buf, sz);
312  const char *p = buf;
313  while(*p) {
314  p++;
315  }
316  m_make = std::string(buf, p - buf);
317  p++;
318  m_model = p;
319 
320  if (index == EXIF_TAG_MODEL) {
321  val = new MetaValue(m_model);
322  }
323  else if (index == EXIF_TAG_MAKE) {
324  val = new MetaValue(m_make);
325  }
326  LOGDBG1("Make %s\n", m_make.c_str());
327  LOGDBG1("Model %s\n", m_model.c_str());
328  }
329  }
330 
331 
332  break;
333  }
334  }
335  break;
336  }
337  case META_NS_EXIF:
338  break;
339  default:
340  LOGERR("Unknown Meta Namespace\n");
341  break;
342  }
343 
344  return val;
345 }
346 
347 void CRWFile::_identifyId()
348 {
349  std::string model;
350  std::string make;
351  try {
352  MetaValue * v = _getMetaValue(META_NS_TIFF | EXIF_TAG_MODEL);
353  if(v) {
354  model = v->getString(0);
355  }
356  delete v;
357  v = _getMetaValue(META_NS_TIFF | EXIF_TAG_MAKE);
358  if(v) {
359  make = v->getString(0);
360  }
361  delete v;
362  _setTypeId(_typeIdFromModel(make, model));
363  }
364  catch(...)
365  {
366  }
367 }
368 
369 }
370 }
371 
372 /*
373  Local Variables:
374  mode:c++
375  c-file-style:"stroustrup"
376  c-file-offsets:((innamespace . 0))
377  indent-tabs-mode:nil
378  fill-column:80
379  End:
380 */
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
size_t size() const
Definition: bitmapdata.cpp:129
size_t fetchData(Heap *heap, void *buf, size_t size) const
void swap(RawData &with)
Definition: rawdata.cpp:245
cloned stream. Allow reading from a different offset
Definition: streamclone.hpp:36
Option< uint32_t > readUInt32(const IO::Stream::Ptr &f)
Definition: trace.cpp:30
::or_cfa_pattern patternType() const
Definition: cfapattern.cpp:186
virtual ::or_error _getRawData(RawData &data, uint32_t options) override
Definition: crwfile.cpp:154
const CfaPattern * cfaPattern() const
Definition: rawdata.cpp:287
bool isA(uint16_t _typeCode) const
void setDataType(DataType _type)
Definition: bitmapdata.cpp:100
Option< uint16_t > readUInt16(const IO::Stream::Ptr &f)
virtual RawContainer * getContainer() const override
Definition: crwfile.cpp:149
virtual void setDimensions(uint32_t x, uint32_t y) override
Definition: rawdata.cpp:260
virtual ::or_error _enumThumbnailSizes(std::vector< uint32_t > &list) override
Definition: crwfile.cpp:117