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
factory(const IO::Stream::Ptr & s)122 RawFile *CRWFile::factory(const IO::Stream::Ptr &s)
123 {
124 return new CRWFile(s);
125 }
126
CRWFile(const IO::Stream::Ptr & s)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
~CRWFile()137 CRWFile::~CRWFile()
138 {
139 delete m_container;
140 }
141
_enumThumbnailSizes(std::vector<uint32_t> & list)142 ::or_error CRWFile::_enumThumbnailSizes(std::vector<uint32_t> &list)
143 {
144 ::or_error err = OR_ERROR_NOT_FOUND;
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
getContainer() const172 RawContainer* CRWFile::getContainer() const
173 {
174 return m_container;
175 }
176
_getRawData(RawData & data,uint32_t options)177 ::or_error CRWFile::_getRawData(RawData & data, uint32_t options)
178 {
179 ::or_error err = OR_ERROR_NOT_FOUND;
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);
257 data.setDataType(OR_DATA_TYPE_COMPRESSED_RAW);
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 data.swap(*dData);
273 }
274 }
275 data.setActiveArea((*active_area)[0], (*active_area)[1],
276 (*active_area)[2], (*active_area)[3]);
277 err = OR_ERROR_NONE;
278 }
279 return err;
280 }
281
getOrientation() const282 Option<uint32_t> CRWFile::getOrientation() const
283 {
284 const ImageSpec * img_spec = m_container->getImageSpec();
285 if (img_spec) {
286 return static_cast<uint32_t>(img_spec->exifOrientation());
287 }
288 return OptionNone();
289 }
290
getMakeOrModel(uint32_t index)291 Option<std::string> CRWFile::getMakeOrModel(uint32_t index)
292 {
293 if (index == EXIF_TAG_MAKE && !m_make.empty()) {
294 return m_make;
295 } else if (index == EXIF_TAG_MODEL && !m_model.empty()) {
296 return m_model;
297 }
298
299 Option<std::string> val;
300 CIFF::HeapRef heap = m_container->getCameraProps();
301 if (heap) {
302 auto propsRecs = heap->records();
303 auto iter = propsRecs.find(TAG_RAWMAKEMODEL);
304 if (iter == propsRecs.end()) {
305 LOGERR("Couldn't find the image info.\n");
306 } else {
307 char buf[256];
308 size_t sz = iter->second.length();
309 if(sz > 256) {
310 sz = 256;
311 }
312 /*size_t sz2 = */iter->second.fetchData(heap.get(),
313 (void*)buf, sz);
314 const char *p = buf;
315 while(*p) {
316 p++;
317 }
318 m_make = std::string(buf, p - buf);
319 p++;
320 m_model = p;
321
322 if (index == EXIF_TAG_MODEL) {
323 val = m_model;
324 } else if (index == EXIF_TAG_MAKE) {
325 val = m_make;
326 }
327 LOGDBG1("Make %s\n", m_make.c_str());
328 LOGDBG1("Model %s\n", m_model.c_str());
329 }
330 }
331 return val;
332 }
333
_getMetaValue(int32_t meta_index)334 MetaValue *CRWFile::_getMetaValue(int32_t meta_index)
335 {
336 MetaValue * val = NULL;
337
338 switch(META_INDEX_MASKOUT(meta_index)) {
339 case META_NS_TIFF:
340 {
341 uint32_t index = META_NS_MASKOUT(meta_index);
342 switch(index) {
343 case EXIF_TAG_ORIENTATION:
344 {
345 auto orientation = getOrientation();
346 if (orientation) {
347 val = new MetaValue(orientation.value());
348 }
349 break;
350 }
351 case EXIF_TAG_MAKE:
352 case EXIF_TAG_MODEL:
353 {
354 auto tag = getMakeOrModel(index);
355 if (tag) {
356 val = new MetaValue(tag.value());
357 }
358 break;
359 }
360 }
361 break;
362 }
363 case META_NS_EXIF:
364 break;
365 default:
366 LOGERR("Unknown Meta Namespace\n");
367 break;
368 }
369
370 return val;
371 }
372
_locateMainIfd()373 IfdDir::Ref CRWFile::_locateMainIfd()
374 {
375 auto ifd = std::make_shared<CiffMainIfd>(*this, *m_container);
376 ifd->load();
377 return ifd;
378 }
379
_locateExifIfd()380 IfdDir::Ref CRWFile::_locateExifIfd()
381 {
382 auto ifd = std::make_shared<CiffExifIfd>(*this, *m_container);
383 ifd->load();
384 return ifd;
385 }
386
_identifyId()387 void CRWFile::_identifyId()
388 {
389 std::string model;
390 std::string make;
391 try {
392 MetaValue * v = _getMetaValue(META_NS_TIFF | EXIF_TAG_MODEL);
393 if(v) {
394 model = v->getString(0);
395 }
396 delete v;
397 v = _getMetaValue(META_NS_TIFF | EXIF_TAG_MAKE);
398 if(v) {
399 make = v->getString(0);
400 }
401 delete v;
402 _setTypeId(_typeIdFromModel(make, model));
403 }
404 catch(...)
405 {
406 }
407 }
408
409 }
410 }
411
412 /*
413 Local Variables:
414 mode:c++
415 c-file-style:"stroustrup"
416 c-file-offsets:((innamespace . 0))
417 c-basic-offset: 4
418 tab-width: 4
419 indent-tabs-mode:nil
420 fill-column:80
421 End:
422 */
423