libopenraw
crwfile.cpp
1 /*
2  * libopenraw - crwfile.cpp
3  *
4  * Copyright (C) 2006-2016 Hubert Figuiere
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  Trace(DEBUG2) << "JPEG @" << (*iter).offset << "\n";
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  Trace(DEBUG1) << "JPEG dimensions x=" << m_x
140  << " y=" << m_y << "\n";
141  uint32_t dim = std::max(m_x,m_y);
142  _addThumbnail(dim, ThumbDesc(m_x, m_y, OR_DATA_TYPE_JPEG, offset, (*iter).length));
143  list.push_back(dim);
144  err = OR_ERROR_NONE;
145  }
146 
147  return err;
148 }
149 
151 {
152  return m_container;
153 }
154 
155 ::or_error CRWFile::_getRawData(RawData & data, uint32_t options)
156 {
157  ::or_error err = OR_ERROR_NOT_FOUND;
158  Heap::Ref props = m_container->getImageProps();
159 
160  if(!props) {
161  return OR_ERROR_NOT_FOUND;
162  }
163  const ImageSpec * img_spec = m_container->getImageSpec();
164  uint32_t x, y;
165  x = y = 0;
166  if(img_spec) {
167  x = img_spec->imageWidth;
168  y = img_spec->imageHeight;
169  }
170 
171  // locate decoder table
172  const CIFF::RecordEntry::List & propsRecs = props->records();
173  auto iter = std::find_if(propsRecs.cbegin(), propsRecs.cend(), std::bind(
174  &RecordEntry::isA, std::placeholders::_1,
175  static_cast<uint16_t>(TAG_EXIFINFORMATION)));
176  if (iter == propsRecs.end()) {
177  Trace(ERROR) << "Couldn't find the Exif information.\n";
178  return err;
179  }
180 
181  Heap exifProps(iter->offset + props->offset(), iter->length, m_container);
182 
183  const RecordEntry::List & exifPropsRecs = exifProps.records();
184  iter = std::find_if(exifPropsRecs.cbegin(), exifPropsRecs.cend(),
185  std::bind(
186  &RecordEntry::isA, std::placeholders::_1,
187  static_cast<uint16_t>(TAG_DECODERTABLE)));
188  if (iter == exifPropsRecs.end()) {
189  Trace(ERROR) << "Couldn't find the decoder table.\n";
190  return err;
191  }
192  Trace(DEBUG2) << "length = " << iter->length << "\n";
193  Trace(DEBUG2) << "offset = " << exifProps.offset() + iter->offset << "\n";
194  auto file = m_container->file();
195  file->seek(exifProps.offset() + iter->offset, SEEK_SET);
196  uint32_t decoderTable;
197  if(m_container->readUInt32(file, decoderTable)) {
198  Trace(DEBUG2) << "decoder table = " << decoderTable << "\n";
199  }
200 
201  // locate the CFA info
202  uint16_t cfa_x, cfa_y;
203  iter = std::find_if(exifPropsRecs.cbegin(), exifPropsRecs.cend(), std::bind(
204  &RecordEntry::isA, std::placeholders::_1,
205  static_cast<uint16_t>(TAG_SENSORINFO)));
206  if (iter == exifPropsRecs.end()) {
207  Trace(ERROR) << "Couldn't find the sensor info.\n";
208  return err;
209  }
210  Trace(DEBUG2) << "length = " << iter->length << "\n";
211  Trace(DEBUG2) << "offset = " << exifProps.offset() + iter->offset << "\n";
212 
213  // go figure what the +2 is. looks like it is the byte #
214  file->seek(exifProps.offset() + iter->offset + 2, SEEK_SET);
215  if(!(m_container->readUInt16(file, cfa_x)
216  && m_container->readUInt16(file, cfa_y))) {
217  Trace(ERROR) << "Couldn't find the sensor size.\n";
218  return err;
219  }
220 
221 
222  const CIFF::RecordEntry *entry = m_container->getRawDataRecord();
223  if (entry) {
224  CIFF::Heap::Ref heap = m_container->heap();
225  Trace(DEBUG2) << "RAW @" << heap->offset() + entry->offset << "\n";
226  size_t byte_size = entry->length;
227  void *buf = data.allocData(byte_size);
228  size_t real_size = entry->fetchData(heap.get(), buf, byte_size);
229  if (real_size != byte_size) {
230  Trace(WARNING) << "wrong size\n";
231  }
232  data.setDimensions(x, y);
233  data.setCfaPatternType(OR_CFA_PATTERN_RGGB);
234  data.setDataType(OR_DATA_TYPE_COMPRESSED_RAW);
235 
236  // decompress if we need
237  if((options & OR_OPTIONS_DONT_DECOMPRESS) == 0) {
238  std::unique_ptr<IO::Stream> s(new IO::MemStream(data.data(),
239  data.size()));
240  s->open(); // TODO check success
241 
242  CrwDecompressor decomp(s.get(), m_container);
243 
244  decomp.setOutputDimensions(cfa_x, cfa_y);
245  decomp.setDecoderTable(decoderTable);
246  RawData *dData = decomp.decompress();
247  if (dData != NULL) {
248  Trace(DEBUG1) << "Out size is " << dData->width()
249  << "x" << dData->height() << "\n";
250  dData->setCfaPatternType(data.cfaPattern()->patternType());
251  data.swap(*dData);
252  delete dData;
253  }
254  }
255  err = OR_ERROR_NONE;
256  }
257  return err;
258 }
259 
260 MetaValue *CRWFile::_getMetaValue(int32_t meta_index)
261 {
262  MetaValue * val = NULL;
263 
264  switch(META_INDEX_MASKOUT(meta_index)) {
265  case META_NS_TIFF:
266  {
267  uint32_t index = META_NS_MASKOUT(meta_index);
268  switch(index) {
269  case EXIF_TAG_ORIENTATION:
270  {
271  const ImageSpec * img_spec = m_container->getImageSpec();
272  if(img_spec) {
273  val = new MetaValue(static_cast<uint32_t>(
274  img_spec->exifOrientation()));
275  }
276  break;
277  }
278  case EXIF_TAG_MAKE:
279  case EXIF_TAG_MODEL:
280  {
281  if (index == EXIF_TAG_MAKE && !m_make.empty()) {
282  val = new MetaValue(m_make);
283  break;
284  }
285  if (index == EXIF_TAG_MODEL && !m_model.empty()) {
286  val = new MetaValue(m_model);
287  break;
288  }
289 
290  CIFF::Heap::Ref heap = m_container->getCameraProps();
291  if(heap) {
292  auto propsRecs = heap->records();
293  auto iter
294  = std::find_if(propsRecs.cbegin(), propsRecs.cend(),
295  [](const CIFF::RecordEntry &e){
296  return e.isA(static_cast<uint16_t>(CIFF::TAG_RAWMAKEMODEL));
297  });
298  if (iter == propsRecs.end()) {
299  Trace(ERROR) << "Couldn't find the image info.\n";
300  }
301  else {
302  char buf[256];
303  size_t sz = iter->length;
304  if(sz > 256) {
305  sz = 256;
306  }
307  /*size_t sz2 = */iter->fetchData(heap.get(),
308  (void*)buf, sz);
309  const char *p = buf;
310  while(*p) {
311  p++;
312  }
313  m_make = std::string(buf, p - buf);
314  p++;
315  m_model = p;
316 
317  if (index == EXIF_TAG_MODEL) {
318  val = new MetaValue(m_model);
319  }
320  else if (index == EXIF_TAG_MAKE) {
321  val = new MetaValue(m_make);
322  }
323  Trace(DEBUG1) << "Make " << m_make << "\n";
324  Trace(DEBUG1) << "Model " << m_model << "\n";
325  }
326  }
327 
328 
329  break;
330  }
331  }
332  break;
333  }
334  case META_NS_EXIF:
335  break;
336  default:
337  Trace(ERROR) << "Unknown Meta Namespace\n";
338  break;
339  }
340 
341  return val;
342 }
343 
344 void CRWFile::_identifyId()
345 {
346  std::string model;
347  std::string make;
348  try {
349  MetaValue * v = _getMetaValue(META_NS_TIFF | EXIF_TAG_MODEL);
350  if(v) {
351  model = v->getString(0);
352  }
353  delete v;
354  v = _getMetaValue(META_NS_TIFF | EXIF_TAG_MAKE);
355  if(v) {
356  make = v->getString(0);
357  }
358  delete v;
359  _setTypeId(_typeIdFromModel(make, model));
360  }
361  catch(...)
362  {
363  }
364 }
365 
366 }
367 }
368 
369 /*
370  Local Variables:
371  mode:c++
372  c-file-style:"stroustrup"
373  c-file-offsets:((innamespace . 0))
374  indent-tabs-mode:nil
375  fill-column:80
376  End:
377 */
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
bool readUInt32(const IO::Stream::Ptr &f, uint32_t &v)
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
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:155
bool readUInt16(const IO::Stream::Ptr &f, uint16_t &v)
const CfaPattern * cfaPattern() const
Definition: rawdata.cpp:287
bool isA(uint16_t _typeCode) const
void setDataType(DataType _type)
Definition: bitmapdata.cpp:100
virtual RawContainer * getContainer() const override
Definition: crwfile.cpp:150
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