libopenraw
crwfile.cpp
1 /*
2  * libopenraw - crwfile.cpp
3  *
4  * Copyright (C) 2006-2008 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 <algorithm>
23 #include <utility>
24 #include <boost/bind.hpp>
25 #include <boost/scoped_ptr.hpp>
26 
27 #include <libopenraw/libopenraw.h>
28 #include <libopenraw++/thumbnail.h>
29 #include <libopenraw++/rawdata.h>
30 
31 #include "trace.h"
32 #include "io/file.h"
33 #include "io/streamclone.h"
34 #include "io/memstream.h"
35 #include "crwfile.h"
36 #include "ciffcontainer.h"
37 #include "jfifcontainer.h"
38 #include "crwdecompressor.h"
39 #include "metavalue.h"
40 
41 #include "rawfilefactory.h"
42 
43 using namespace Debug;
44 using boost::scoped_ptr;
45 
46 namespace OpenRaw {
47 
48 namespace Internals {
49 
50 using namespace CIFF;
51 
52 const RawFile::camera_ids_t CRWFile::s_def[] = {
53  { "Canon EOS D30" , OR_MAKE_FILE_TYPEID(OR_TYPEID_VENDOR_CANON,
54  OR_TYPEID_CANON_D30) },
55  { "Canon EOS D60" , OR_MAKE_FILE_TYPEID(OR_TYPEID_VENDOR_CANON,
56  OR_TYPEID_CANON_D60) },
57  { "Canon EOS 10D" , OR_MAKE_FILE_TYPEID(OR_TYPEID_VENDOR_CANON,
58  OR_TYPEID_CANON_10D) },
59  { "Canon EOS 300D DIGITAL", OR_MAKE_FILE_TYPEID(OR_TYPEID_VENDOR_CANON,
60  OR_TYPEID_CANON_300D) },
61  { "Canon PowerShot G1", OR_MAKE_FILE_TYPEID(OR_TYPEID_VENDOR_CANON,
62  OR_TYPEID_CANON_G1) },
63  { "Canon PowerShot G2", OR_MAKE_FILE_TYPEID(OR_TYPEID_VENDOR_CANON,
64  OR_TYPEID_CANON_G2) },
65  { "Canon PowerShot G3", OR_MAKE_FILE_TYPEID(OR_TYPEID_VENDOR_CANON,
66  OR_TYPEID_CANON_G3) },
67  { "Canon PowerShot G5", OR_MAKE_FILE_TYPEID(OR_TYPEID_VENDOR_CANON,
68  OR_TYPEID_CANON_G5) },
69  { "Canon PowerShot G6", OR_MAKE_FILE_TYPEID(OR_TYPEID_VENDOR_CANON,
70  OR_TYPEID_CANON_G6) },
71  { "Canon PowerShot G7", OR_MAKE_FILE_TYPEID(OR_TYPEID_VENDOR_CANON,
72  OR_TYPEID_CANON_G7) },
73  { "Canon PowerShot Pro1", OR_MAKE_FILE_TYPEID(OR_TYPEID_VENDOR_CANON,
74  OR_TYPEID_CANON_PRO1) },
75  { 0, 0 }
76 };
77 
78 RawFile *CRWFile::factory(IO::Stream *s)
79 {
80  return new CRWFile(s);
81 }
82 
83 CRWFile::CRWFile(IO::Stream *s)
84  : RawFile(s, OR_RAWFILE_TYPE_CRW),
85  m_io(s),
86  m_container(new CIFFContainer(m_io)),
87  m_x(0), m_y(0)
88 {
89  _setIdMap(s_def);
90 }
91 
92 CRWFile::~CRWFile()
93 {
94  delete m_container;
95  delete m_io;
96 }
97 
98 ::or_error CRWFile::_enumThumbnailSizes(std::vector<uint32_t> &list)
99 {
100  ::or_error err = OR_ERROR_NOT_FOUND;
101 
102  Heap::Ref heap = m_container->heap();
103  if(!heap) {
104  // this is not a CIFF file.
105  return err;
106  }
107  const RecordEntry::List & records = heap->records();
108  RecordEntry::List::const_iterator iter;
109  iter = std::find_if(records.begin(), records.end(), boost::bind(
110  &RecordEntry::isA, _1,
111  static_cast<uint16_t>(TAG_JPEGIMAGE)));
112  if (iter != records.end()) {
113  Trace(DEBUG2) << "JPEG @" << (*iter).offset << "\n";
114  m_x = m_y = 0;
115 
116  scoped_ptr<IO::StreamClone> s(new IO::StreamClone(m_io, heap->offset()
117  + (*iter).offset));
118  scoped_ptr<JFIFContainer> jfif(new JFIFContainer(s.get(), 0));
119 
120  jfif->getDimensions(m_x, m_y);
121  Trace(DEBUG1) << "JPEG dimensions x=" << m_x
122  << " y=" << m_y << "\n";
123  list.push_back(std::max(m_x,m_y));
124  err = OR_ERROR_NONE;
125  }
126 
127  return err;
128 }
129 
130 ::or_error CRWFile::_getThumbnail(uint32_t /*size*/, Thumbnail & thumbnail)
131 {
132  ::or_error err = OR_ERROR_NOT_FOUND;
133  Heap::Ref heap = m_container->heap();
134  if(!heap) {
135  // this is not a CIFF file.
136  return err;
137  }
138 
139  const RecordEntry::List & records = heap->records();
140  RecordEntry::List::const_iterator iter;
141  iter = std::find_if(records.begin(), records.end(), boost::bind(
142  &RecordEntry::isA, _1,
143  static_cast<uint16_t>(TAG_JPEGIMAGE)));
144  if (iter != records.end()) {
145  Trace(DEBUG2) << "JPEG @" << (*iter).offset << "\n";
146  size_t byte_size = (*iter).length;
147  void *buf = thumbnail.allocData(byte_size);
148  size_t real_size = (*iter).fetchData(heap.get(), buf, byte_size);
149  if (real_size != byte_size) {
150  Trace(WARNING) << "wrong size\n";
151  }
152  thumbnail.setDimensions(m_x, m_y);
153  thumbnail.setDataType(OR_DATA_TYPE_JPEG);
154  err = OR_ERROR_NONE;
155  }
156 
157  return err;
158 }
159 
160 ::or_error CRWFile::_getRawData(RawData & data, uint32_t options)
161 {
162  ::or_error err = OR_ERROR_NOT_FOUND;
163  Heap::Ref props = m_container->getImageProps();
164 
165  if(!props) {
166  return OR_ERROR_NOT_FOUND;
167  }
168  const ImageSpec * img_spec = m_container->getImageSpec();
169  uint32_t x, y;
170  x = y = 0;
171  int32_t orientation = 0;
172  if(img_spec) {
173  x = img_spec->imageWidth;
174  y = img_spec->imageHeight;
175  orientation = img_spec->exifOrientation();
176  }
177 
178  // locate decoder table
179  const CIFF::RecordEntry::List & propsRecs = props->records();
180  CIFF::RecordEntry::List::const_iterator iter;
181  iter = std::find_if(propsRecs.begin(), propsRecs.end(), boost::bind(
182  &RecordEntry::isA, _1,
183  static_cast<uint16_t>(TAG_EXIFINFORMATION)));
184  if (iter == propsRecs.end()) {
185  Trace(ERROR) << "Couldn't find the Exif information.\n";
186  return err;
187  }
188 
189  Heap exifProps(iter->offset + props->offset(), iter->length, m_container);
190 
191  const RecordEntry::List & exifPropsRecs = exifProps.records();
192  iter = std::find_if(exifPropsRecs.begin(), exifPropsRecs.end(),
193  boost::bind(
194  &RecordEntry::isA, _1,
195  static_cast<uint16_t>(TAG_DECODERTABLE)));
196  if (iter == exifPropsRecs.end()) {
197  Trace(ERROR) << "Couldn't find the decoder table.\n";
198  return err;
199  }
200  Trace(DEBUG2) << "length = " << iter->length << "\n";
201  Trace(DEBUG2) << "offset = " << exifProps.offset() + iter->offset << "\n";
202  IO::Stream *file = m_container->file();
203  file->seek(exifProps.offset() + iter->offset, SEEK_SET);
204  uint32_t decoderTable;
205  if(m_container->readUInt32(file, decoderTable)) {
206  Trace(DEBUG2) << "decoder table = " << decoderTable << "\n";
207  }
208 
209  // locate the CFA info
210  uint16_t cfa_x, cfa_y;
211  iter = std::find_if(exifPropsRecs.begin(), exifPropsRecs.end(), boost::bind(
212  &RecordEntry::isA, _1,
213  static_cast<uint16_t>(TAG_SENSORINFO)));
214  if (iter == exifPropsRecs.end()) {
215  Trace(ERROR) << "Couldn't find the sensor info.\n";
216  return err;
217  }
218  Trace(DEBUG2) << "length = " << iter->length << "\n";
219  Trace(DEBUG2) << "offset = " << exifProps.offset() + iter->offset << "\n";
220 
221  // go figure what the +2 is. looks like it is the byte #
222  file->seek(exifProps.offset() + iter->offset + 2, SEEK_SET);
223  if(!(m_container->readUInt16(file, cfa_x)
224  && m_container->readUInt16(file, cfa_y))) {
225  Trace(ERROR) << "Couldn't find the sensor size.\n";
226  return err;
227  }
228 
229 
230  const CIFF::RecordEntry *entry = m_container->getRawDataRecord();
231  if (entry) {
232  CIFF::Heap::Ref heap = m_container->heap();
233  Trace(DEBUG2) << "RAW @" << heap->offset() + entry->offset << "\n";
234  size_t byte_size = entry->length;
235  void *buf = data.allocData(byte_size);
236  size_t real_size = entry->fetchData(heap.get(), buf, byte_size);
237  if (real_size != byte_size) {
238  Trace(WARNING) << "wrong size\n";
239  }
240  data.setDimensions(x, y);
241  data.setCfaPattern(OR_CFA_PATTERN_RGGB);
242  data.setDataType(OR_DATA_TYPE_COMPRESSED_CFA);
243 
244  // decompress if we need
245  if((options & OR_OPTIONS_DONT_DECOMPRESS) == 0) {
246  boost::scoped_ptr<IO::Stream> s(new IO::MemStream(data.data(),
247  data.size()));
248  s->open(); // TODO check success
249 
250  CrwDecompressor decomp(s.get(), m_container);
251 
252  decomp.setOutputDimensions(cfa_x, cfa_y);
253  decomp.setDecoderTable(decoderTable);
254  RawData *dData = decomp.decompress();
255  if (dData != NULL) {
256  Trace(DEBUG1) << "Out size is " << dData->x()
257  << "x" << dData->y() << "\n";
258  dData->setCfaPattern(data.cfaPattern());
259  data.swap(*dData);
260  delete dData;
261  }
262  }
263  err = OR_ERROR_NONE;
264  }
265  return err;
266 }
267 
268 MetaValue *CRWFile::_getMetaValue(int32_t meta_index)
269 {
270  MetaValue * val = NULL;
271 
272  switch(META_INDEX_MASKOUT(meta_index)) {
273  case META_NS_TIFF:
274  {
275  switch(META_NS_MASKOUT(meta_index)) {
276  case EXIF_TAG_ORIENTATION:
277  {
278  const ImageSpec * img_spec = m_container->getImageSpec();
279  if(img_spec) {
280  val = new MetaValue(static_cast<uint32_t>(
281  img_spec->exifOrientation()));
282  }
283  break;
284  }
285  case EXIF_TAG_MODEL:
286  {
287  CIFF::Heap::Ref heap = m_container->getCameraProps();
288  if(heap) {
289  const CIFF::RecordEntry::List & propsRecs = heap->records();
290  CIFF::RecordEntry::List::const_iterator iter;
291  iter = std::find_if(propsRecs.begin(), propsRecs.end(),
292  boost::bind(
294  static_cast<uint16_t>(CIFF::TAG_RAWMAKEMODEL)));
295  if (iter == propsRecs.end()) {
296  Trace(ERROR) << "Couldn't find the image info.\n";
297  }
298  else {
299  char buf[256];
300  size_t sz = iter->length;
301  if(sz > 256) {
302  sz = 256;
303  }
304  size_t sz2;
305  std::string model;
306  sz2 = iter->fetchData(heap.get(), (void*)buf, sz);
307  char *p = buf;
308  while(*p) {
309  p++;
310  }
311  p++;
312  model = p;
313  val = new MetaValue(model);
314  Trace(DEBUG1) << "Model " << model << "\n";
315  }
316  }
317 
318 
319  break;
320  }
321  }
322  break;
323  }
324  case META_NS_EXIF:
325  break;
326  default:
327  Trace(ERROR) << "Unknown Meta Namespace\n";
328  break;
329  }
330 
331  return val;
332 }
333 
334 void CRWFile::_identifyId()
335 {
336  MetaValue * v = _getMetaValue(META_NS_TIFF | EXIF_TAG_MODEL);
337  if(v) {
338  std::string model;
339  try {
340  model = v->getString();
341  _setTypeId(_typeIdFromModel(model));
342  }
343  catch(...)
344  {
345  }
346  delete v;
347  }
348 }
349 
350 }
351 }
352 
353 /*
354  Local Variables:
355  mode:c++
356  c-file-style:"stroustrup"
357  c-file-offsets:((innamespace . 0))
358  indent-tabs-mode:nil
359  fill-column:80
360  End:
361 */
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:33
virtual void setDimensions(uint32_t x, uint32_t y)
Definition: rawdata.cpp:132
bool readUInt16(IO::Stream *f, uint16_t &v)
void _setTypeId(TypeId _type_id)
Definition: rawfile.cpp:304
void swap(RawData &with)
Definition: rawdata.cpp:117
cloned stream. Allow reading from a different offset
Definition: streamclone.h:35
virtual void setDimensions(uint32_t x, uint32_t y)
Definition: bitmapdata.cpp:148
bool isA(uint16_t _typeCode) const
virtual ::or_error _getThumbnail(uint32_t size, Thumbnail &thumbnail)
Definition: crwfile.cpp:130
virtual int seek(off_t offset, int whence)=0
Definition: trace.cpp:28
void setDataType(DataType _type)
Definition: bitmapdata.cpp:92
virtual ::or_error _getRawData(RawData &data, uint32_t options)
Definition: crwfile.cpp:160
size_t fetchData(Heap *heap, void *buf, size_t size) const
virtual ::or_error _enumThumbnailSizes(std::vector< uint32_t > &list)
Definition: crwfile.cpp:98
base virtual class for IO
Definition: stream.h:40
bool readUInt32(IO::Stream *f, uint32_t &v)
size_t size() const
Definition: bitmapdata.cpp:122