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
46using namespace Debug;
47
48namespace OpenRaw {
49
50namespace Internals {
51
52using 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 */
58static 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
82const 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
97RawFile *CRWFile::factory(const IO::Stream::Ptr &s)
98{
99 return new CRWFile(s);
100}
101
102CRWFile::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
112CRWFile::~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 = %lld\n", (long long int)(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.value();
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 = %lld\n", (long long int)(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 @%lld\n", (long long int)(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.value(), cfa_y.value());
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
263MetaValue *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
347void 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*/
void setDataType(DataType _type)
size_t size() const
::or_cfa_pattern patternType() const
cloned stream. Allow reading from a different offset
size_t fetchData(Heap *heap, void *buf, size_t size) const
bool isA(uint16_t _typeCode) const
virtual::or_error _enumThumbnailSizes(std::vector< uint32_t > &list) override
Definition crwfile.cpp:117
virtual RawContainer * getContainer() const override
Definition crwfile.cpp:149
virtual::or_error _getRawData(RawData &data, uint32_t options) override
Definition crwfile.cpp:154
virtual RawDataPtr decompress() override
void swap(RawData &with)
Definition rawdata.cpp:245
const CfaPattern * cfaPattern() const
Definition rawdata.cpp:287
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