libopenraw
mrwfile.cpp
1/*
2 * libopenraw - mrwfile.cpp
3 *
4 * Copyright (C) 2006-2017 Hubert Figuière
5 * Copyright (C) 2008 Bradley Broom
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
23#include <stddef.h>
24#include <sys/types.h>
25#include <cstdint>
26#include <string>
27#include <memory>
28
29#include <libopenraw/cameraids.h>
30#include <libopenraw/debug.h>
31
32#include "thumbnail.hpp"
33#include "rawdata.hpp"
34
35#include "trace.hpp"
36#include "io/stream.hpp"
37#include "mrwcontainer.hpp"
38#include "ifd.hpp"
39#include "ifdentry.hpp"
40#include "ifdfilecontainer.hpp"
41#include "mrwfile.hpp"
42#include "unpack.hpp"
43#include "rawfile_private.hpp"
44
45using namespace Debug;
46
47namespace OpenRaw {
48namespace Internals {
49
50#define OR_MAKE_MINOLTA_TYPEID(camid) \
51 OR_MAKE_FILE_TYPEID(OR_TYPEID_VENDOR_MINOLTA,camid)
52
53/* taken from dcraw, by default */
54static const BuiltinColourMatrix s_matrices[] = {
55 { OR_MAKE_MINOLTA_TYPEID(OR_TYPEID_MINOLTA_MAXXUM_5D), 0, 0xffb,
56 { 10284,-3283,-1086,-7957,15762,2316,-829,882,6644 } },
57 { OR_MAKE_MINOLTA_TYPEID(OR_TYPEID_MINOLTA_MAXXUM_7D), 0, 0xffb,
58 { 10239,-3104,-1099,-8037,15727,2451,-927,925,6871 } },
59 { OR_MAKE_MINOLTA_TYPEID(OR_TYPEID_MINOLTA_DIMAGE5), 0, 0xf7d,
60 { 8983,-2942,-963,-6556,14476,2237,-2426,2887,8014 } },
61 { OR_MAKE_MINOLTA_TYPEID(OR_TYPEID_MINOLTA_DIMAGE7), 0, 0xf7d,
62 { 9144,-2777,-998,-6676,14556,2281,-2470,3019,7744 } },
63 { OR_MAKE_MINOLTA_TYPEID(OR_TYPEID_MINOLTA_DIMAGE7I), 0, 0xf7d,
64 { 9144,-2777,-998,-6676,14556,2281,-2470,3019,7744 } },
65 { OR_MAKE_MINOLTA_TYPEID(OR_TYPEID_MINOLTA_DIMAGE7HI), 0, 0xf7d,
66 { 11368,-3894,-1242,-6521,14358,2339,-2475,3056,7285 } },
67 { OR_MAKE_MINOLTA_TYPEID(OR_TYPEID_MINOLTA_A1), 0, 0xf8b,
68 { 9274,-2547,-1167,-8220,16323,1943,-2273,2720,8340 } },
69 { OR_MAKE_MINOLTA_TYPEID(OR_TYPEID_MINOLTA_A2), 0, 0xf8f,
70 { 9097,-2726,-1053,-8073,15506,2762,-966,981,7763 } },
71 { OR_MAKE_MINOLTA_TYPEID(OR_TYPEID_MINOLTA_A200), 0, 0,
72 { 8560,-2487,-986,-8112,15535,2771,-1209,1324,7743 } },
73
74 { 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0, 0, 0 } }
75};
76
77const struct IfdFile::camera_ids_t MRWFile::s_def[] = {
78 { "21860002", OR_MAKE_MINOLTA_TYPEID(OR_TYPEID_MINOLTA_MAXXUM_5D) },
79 { "21810002", OR_MAKE_MINOLTA_TYPEID(OR_TYPEID_MINOLTA_MAXXUM_7D) },
80 { "27730001", OR_MAKE_MINOLTA_TYPEID(OR_TYPEID_MINOLTA_DIMAGE5) },
81 { "27660001", OR_MAKE_MINOLTA_TYPEID(OR_TYPEID_MINOLTA_DIMAGE7) },
82 { "27790001", OR_MAKE_MINOLTA_TYPEID(OR_TYPEID_MINOLTA_DIMAGE7I) },
83 { "27780001", OR_MAKE_MINOLTA_TYPEID(OR_TYPEID_MINOLTA_DIMAGE7HI) },
84 { "27820001", OR_MAKE_MINOLTA_TYPEID(OR_TYPEID_MINOLTA_A1) },
85 { "27200001", OR_MAKE_MINOLTA_TYPEID(OR_TYPEID_MINOLTA_A2) },
86 { "27470002", OR_MAKE_MINOLTA_TYPEID(OR_TYPEID_MINOLTA_A200) },
87 { 0, 0 }
88};
89
90RawFile *MRWFile::factory(const IO::Stream::Ptr &_f)
91{
92 return new MRWFile(_f);
93}
94
95MRWFile::MRWFile(const IO::Stream::Ptr &_f)
96 : IfdFile(_f, OR_RAWFILE_TYPE_MRW, false)
97{
98 _setIdMap(s_def);
99 _setMatrices(s_matrices);
100 m_container = new MRWContainer (m_io, 0);
101}
102
103MRWFile::~MRWFile()
104{
105}
106
107IfdDir::Ref MRWFile::_locateCfaIfd()
108{
109 // in MRW the CFA IFD is the main IFD
110 return mainIfd();
111}
112
113
114IfdDir::Ref MRWFile::_locateMainIfd()
115{
116 return m_container->setDirectory(0);
117}
118
119
120void MRWFile::_identifyId()
121{
122 MRWContainer *mc = (MRWContainer *)m_container;
123
124 // it is important that the main IFD be loaded.
125 // this ensures it.
126 const IfdDir::Ref & _mainIfd = mainIfd();
127
128 if(_mainIfd && mc->prd) {
129 auto version = mc->prd->string_val(MRW::PRD_VERSION);
130 if (version) {
131 _setTypeId(_typeIdFromModel("Minolta", version.value()));
132 } else {
133 LOGERR("Coudln't read Minolta version\n");
134 }
135 }
136}
137
138
139/* This code only knows about Dimage 5/7, in which the thumbnail position is special. */
140::or_error MRWFile::_enumThumbnailSizes(std::vector<uint32_t> &list)
141{
142 ::or_error err = OR_ERROR_NOT_FOUND;
143 list.push_back (640);
144 err = OR_ERROR_NONE;
145 return err;
146}
147
148/* This code only knows about Dimage 5/7, in which the thumbnail position is special. */
149::or_error MRWFile::_getThumbnail(uint32_t /*size*/, Thumbnail & thumbnail)
150{
151 IfdDir::Ref dir;
152 IfdEntry::Ref maker_ent; /* Make note directory entry. */
153 IfdEntry::Ref thumb_ent; /* Thumbnail data directory entry. */
155
156 dir = _locateExifIfd();
157 if (!dir) {
158 LOGWARN("EXIF dir not found\n");
159 return OR_ERROR_NOT_FOUND;
160 }
161
162 maker_ent = dir->getEntry(IFD::EXIF_TAG_MAKER_NOTE);
163 if (!maker_ent) {
164 LOGWARN("maker note offset entry not found\n");
165 return OR_ERROR_NOT_FOUND;
166 }
167 uint32_t off = 0;
168 off = maker_ent->offset();
169
170 IfdDir::Ref ref(std::make_shared<IfdDir>(
171 mc->ttw->offset()
172 + MRW::DataBlockHeaderLength + off,
173 *m_container));
174 ref->load();
175
176 uint32_t tnail_offset = 0;
177 uint32_t tnail_len = 0;
178 thumb_ent = ref->getEntry(MRW::MRWTAG_THUMBNAIL);
179 if (thumb_ent) {
180 tnail_offset = thumb_ent->offset();
181 tnail_len = thumb_ent->count();
182 } else {
183 auto result = ref->getValue<uint32_t>(MRW::MRWTAG_THUMBNAIL_OFFSET);
184 if (result.empty()) {
185 LOGWARN("thumbnail offset entry not found\n");
186 return OR_ERROR_NOT_FOUND;
187 }
188 tnail_offset = result.value();
189
190 result = ref->getValue<uint32_t>(MRW::MRWTAG_THUMBNAIL_LENGTH);
191 if (result.empty()) {
192 LOGWARN("thumbnail lenght entry not found\n");
193 return OR_ERROR_NOT_FOUND;
194 }
195 tnail_len = result.value();
196 }
197
198 LOGDBG1("thumbnail offset found, offset == %u count == %u\n",
199 tnail_offset, tnail_len);
200 void *p = thumbnail.allocData (tnail_len);
201 size_t fetched = m_container->fetchData(p, mc->ttw->offset()
202 + MRW::DataBlockHeaderLength
203 + tnail_offset,
204 tnail_len);
205 if (fetched != tnail_len) {
206 LOGWARN("Unable to fetch all thumbnail data: %lu not %u bytes\n",
207 fetched, tnail_len);
208 }
209 /* Need to patch first byte. */
210 ((unsigned char *)p)[0] = 0xFF;
211
212 thumbnail.setDataType (OR_DATA_TYPE_JPEG);
213 thumbnail.setDimensions (640, 480);
214 return OR_ERROR_NONE;
215}
216
217
218::or_error MRWFile::_getRawData(RawData & data, uint32_t options)
219{
220 or_error ret = OR_ERROR_NONE;
222
223 if(!mc->prd) {
224 return OR_ERROR_NOT_FOUND;
225 }
226 /* Obtain sensor dimensions from PRD block. */
227 uint16_t y = mc->prd->uint16_val (MRW::PRD_SENSOR_LENGTH).value_or(0);
228 uint16_t x = mc->prd->uint16_val (MRW::PRD_SENSOR_WIDTH).value_or(0);
229 uint8_t bpc = mc->prd->uint8_val (MRW::PRD_PIXEL_SIZE).value_or(0);
230
231 bool is_compressed = (mc->prd->uint8_val(MRW::PRD_STORAGE_TYPE).value_or(0) == 0x59);
232 /* Allocate space for and retrieve pixel data.
233 * Currently only for cameras that don't compress pixel data.
234 */
235 /* Set pixel array parameters. */
236 uint32_t finaldatalen = 2 * x * y;
237 uint32_t datalen =
238 (is_compressed ? x * y + ((x * y) >> 1) : finaldatalen);
239
240 if(options & OR_OPTIONS_DONT_DECOMPRESS) {
241 finaldatalen = datalen;
242 }
243 if(is_compressed && (options & OR_OPTIONS_DONT_DECOMPRESS)) {
244 data.setDataType (OR_DATA_TYPE_COMPRESSED_RAW);
245 }
246 else {
247 data.setDataType (OR_DATA_TYPE_RAW);
248 }
249 data.setBpc(bpc);
250 // this seems to be the hardcoded value.
251 uint16_t black = 0;
252 uint16_t white = 0;
253 RawFile::_getBuiltinLevels(_getMatrices(), typeId(),
254 black, white);
255 data.setBlackLevel(black);
256 data.setWhiteLevel(white);
257 LOGDBG1("datalen = %d final datalen = %u\n", datalen, finaldatalen);
258 void *p = data.allocData(finaldatalen);
259 size_t fetched = 0;
260 off_t offset = mc->pixelDataOffset();
261 if(!is_compressed || (options & OR_OPTIONS_DONT_DECOMPRESS)) {
262 fetched = m_container->fetchData (p, offset, datalen);
263 }
264 else {
265 Unpack unpack(x, IFD::COMPRESS_NONE);
266 size_t blocksize = unpack.block_size();
267 std::unique_ptr<uint8_t[]> block(new uint8_t[blocksize]);
268 uint8_t * outdata = (uint8_t*)data.data();
269 size_t outsize = finaldatalen;
270 size_t got;
271 do {
272 LOGDBG2("fetchData @offset %lld\n", (long long int)offset);
273 got = m_container->fetchData (block.get(),
274 offset, blocksize);
275 fetched += got;
276 offset += got;
277 LOGDBG2("got %ld\n", got);
278 if(got) {
279 size_t out;
280 or_error err = unpack.unpack_be12to16(outdata, outsize,
281 block.get(), got, out);
282 outdata += out;
283 outsize -= out;
284 LOGDBG2("unpacked %ld bytes from %ld\n", out, got);
285 if(err != OR_ERROR_NONE) {
286 ret = err;
287 break;
288 }
289 }
290 } while((got != 0) && (fetched < datalen));
291 }
292 if (fetched < datalen) {
293 LOGWARN("Fetched only %ld of %u: continuing anyway.\n", fetched,
294 datalen);
295 }
296 uint16_t bpat = mc->prd->uint16_val (MRW::PRD_BAYER_PATTERN).value_or(0);
297 or_cfa_pattern cfa_pattern = OR_CFA_PATTERN_NONE;
298 switch(bpat)
299 {
300 case 0x0001:
301 cfa_pattern = OR_CFA_PATTERN_RGGB;
302 break;
303 case 0x0004:
304 cfa_pattern = OR_CFA_PATTERN_GBRG;
305 break;
306 default:
307 break;
308 }
309 data.setCfaPatternType(cfa_pattern);
310 data.setDimensions (x, y);
311
312 return ret;
313}
314
315}
316}
317/*
318 Local Variables:
319 mode:c++
320 c-file-style:"stroustrup"
321 c-file-offsets:((innamespace . 0))
322 indent-tabs-mode:nil
323 fill-column:80
324 End:
325*/
void setDataType(DataType _type)
Definition: bitmapdata.cpp:100
void setBpc(uint32_t _bpc)
Definition: bitmapdata.cpp:164
virtual void setDimensions(uint32_t x, uint32_t y)
Definition: bitmapdata.cpp:169
std::shared_ptr< IfdEntry > Ref
Definition: ifdentry.hpp:165
IO::Stream::Ptr m_io
Definition: ifdfile.hpp:89
IfdFileContainer * m_container
Definition: ifdfile.hpp:90
size_t fetchData(void *buf, off_t offset, size_t buf_size)
or_error unpack_be12to16(uint8_t *dest, size_t destsize, const uint8_t *src, size_t size, size_t &outsize)
Definition: unpack.cpp:58
virtual void setDimensions(uint32_t x, uint32_t y) override
Definition: rawdata.cpp:260
TypeId typeId()
Definition: rawfile.cpp:335
void _setTypeId(TypeId _type_id)
Definition: rawfile.cpp:348
CIFF is the container for CRW files. It is an attempt from Canon to make this a standard....
Definition: arwfile.cpp:30
virtual ::or_error _enumThumbnailSizes(std::vector< uint32_t > &list) override
Definition: mrwfile.cpp:140
virtual ::or_error _getRawData(RawData &data, uint32_t options) override
Definition: mrwfile.cpp:218