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 
45 using namespace Debug;
46 
47 namespace OpenRaw {
48 namespace 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 */
54 static 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 
77 const 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 
90 RawFile *MRWFile::factory(const IO::Stream::Ptr &_f)
91 {
92  return new MRWFile(_f);
93 }
94 
95 MRWFile::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 
103 MRWFile::~MRWFile()
104 {
105 }
106 
107 IfdDir::Ref MRWFile::_locateCfaIfd()
108 {
109  // in MRW the CFA IFD is the main IFD
110  return mainIfd();
111 }
112 
113 
114 IfdDir::Ref MRWFile::_locateMainIfd()
115 {
116  return m_container->setDirectory(0);
117 }
118 
119 
120 void 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.ok()) {
131  _setTypeId(_typeIdFromModel("Minolta", version.unwrap()));
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. */
154  MRWContainer *mc = (MRWContainer *)m_container;
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.unwrap();
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.unwrap();
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;
221  MRWContainer *mc = (MRWContainer *)m_container;
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).unwrap_or(0);
228  uint16_t x = mc->prd->uint16_val (MRW::PRD_SENSOR_WIDTH).unwrap_or(0);
229  uint8_t bpc = mc->prd->uint8_val (MRW::PRD_PIXEL_SIZE).unwrap_or(0);
230 
231  bool is_compressed = (mc->prd->uint8_val(MRW::PRD_STORAGE_TYPE).unwrap_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 %ld\n", 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).unwrap_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 */
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
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)
Definition: bitmapdata.cpp:169
void setBpc(uint32_t _bpc)
Definition: bitmapdata.cpp:164
std::shared_ptr< IfdEntry > Ref
Definition: ifdentry.hpp:165
Definition: trace.cpp:30
void setDataType(DataType _type)
Definition: bitmapdata.cpp:100
generic IFD based raw file.
Definition: ifdfile.hpp:48
virtual void setDimensions(uint32_t x, uint32_t y) override
Definition: rawdata.cpp:260