libopenraw  0.3.7
mrwfile.cpp
1 /*
2  * libopenraw - mrwfile.cpp
3  *
4  * Copyright (C) 2006-2023 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 
104 {
105  // in MRW the CFA IFD is the main IFD
106  return mainIfd();
107 }
108 
110 {
111  auto ifd = m_container->setDirectory(0);
112  if (ifd) {
113  ifd->setType(OR_IFD_MAIN);
114  }
115  return ifd;
116 }
117 
119 {
121 
122  // it is important that the main IFD be loaded.
123  // this ensures it.
124  const IfdDir::Ref & _mainIfd = mainIfd();
125 
126  if(_mainIfd && mc->prd) {
127  auto version = mc->prd->string_val(MRW::PRD_VERSION);
128  if (version) {
129  _setTypeId(_typeIdFromModel("Minolta Co., Ltd.", version.value()));
130  } else {
131  LOGERR("Coudln't read Minolta version\n");
132  }
133  }
134 }
135 
136 
137 /* This code only knows about Dimage 5/7, in which the thumbnail position is
138  * special. */
139 ::or_error MRWFile::_enumThumbnailSizes(std::vector<uint32_t> &list)
140 {
141  list.push_back(640);
142  return OR_ERROR_NONE;
143 }
144 
145 /* This code only knows about Dimage 5/7, in which the thumbnail position is
146  * special. */
147 ::or_error MRWFile::_getThumbnail(uint32_t /*size*/, Thumbnail & thumbnail)
148 {
149  auto mnote = makerNoteIfd();
150  if (!mnote) {
151  LOGWARN("No MakerNote found\n");
152  return OR_ERROR_NOT_FOUND;
153  }
154 
155  uint32_t tnail_offset = 0;
156  uint32_t tnail_len = 0;
157  IfdEntry::Ref thumb_ent = mnote->getEntry(MRW::MRWTAG_THUMBNAIL);
158  if (thumb_ent) {
159  tnail_offset = thumb_ent->offset();
160  tnail_len = thumb_ent->count();
161  } else {
162  auto result = mnote->getValue<uint32_t>(MRW::MRWTAG_THUMBNAIL_OFFSET);
163  if (result.empty()) {
164  LOGWARN("thumbnail offset entry not found\n");
165  return OR_ERROR_NOT_FOUND;
166  }
167  tnail_offset = result.value();
168 
169  result = mnote->getValue<uint32_t>(MRW::MRWTAG_THUMBNAIL_LENGTH);
170  if (result.empty()) {
171  LOGWARN("thumbnail lenght entry not found\n");
172  return OR_ERROR_NOT_FOUND;
173  }
174  tnail_len = result.value();
175  }
176 
177  LOGDBG1("thumbnail offset found, offset == %u count == %u\n",
178  tnail_offset, tnail_len);
179  void *p = thumbnail.allocData(tnail_len);
180  MRWContainer *mc = (MRWContainer *)m_container;
181  size_t fetched = m_container->fetchData(p, mc->ttw->offset()
182  + MRW::DataBlockHeaderLength
183  + tnail_offset,
184  tnail_len);
185  if (fetched != tnail_len) {
186  LOGWARN("Unable to fetch all thumbnail data: %lu not %u bytes\n",
187  (LSIZE)fetched, tnail_len);
188  }
189  /* Need to patch first byte. */
190  ((unsigned char *)p)[0] = 0xFF;
191 
192  thumbnail.setDataType(OR_DATA_TYPE_JPEG);
193  thumbnail.setDimensions(640, 480);
194  return OR_ERROR_NONE;
195 }
196 
197 ::or_error MRWFile::_getRawData(RawData & data, uint32_t options)
198 {
199  or_error ret = OR_ERROR_NONE;
201 
202  if (!mc->prd) {
203  return OR_ERROR_NOT_FOUND;
204  }
205  /* Obtain sensor dimensions from PRD block. */
206  uint16_t y = mc->prd->uint16_val(MRW::PRD_SENSOR_LENGTH).value_or(0);
207  uint16_t x = mc->prd->uint16_val(MRW::PRD_SENSOR_WIDTH).value_or(0);
208  uint8_t bpc = mc->prd->uint8_val(MRW::PRD_PIXEL_SIZE).value_or(0);
209 
210  bool is_compressed = (mc->prd->uint8_val(MRW::PRD_STORAGE_TYPE).value_or(MRW::STORAGE_TYPE_UNPACKED) == MRW::STORAGE_TYPE_PACKED);
211  /* Allocate space for and retrieve pixel data.
212  * Currently only for cameras that don't compress pixel data.
213  */
214  /* Set pixel array parameters. */
215  uint32_t finaldatalen = 2 * x * y;
216  uint32_t datalen =
217  (is_compressed ? x * y + ((x * y) >> 1) : finaldatalen);
218 
219  if (options & OR_OPTIONS_DONT_DECOMPRESS) {
220  finaldatalen = datalen;
221  }
222  if (is_compressed && (options & OR_OPTIONS_DONT_DECOMPRESS)) {
224  } else {
226  }
227  data.setBpc(bpc);
228  // this seems to be the hardcoded value.
229  uint16_t black = 0;
230  uint16_t white = 0;
231  RawFile::_getBuiltinLevels(_getMatrices(), typeId(), black, white);
232  data.setBlackLevel(black);
233  data.setWhiteLevel(white);
234  LOGDBG1("datalen = %d final datalen = %u\n", datalen, finaldatalen);
235  void *p = data.allocData(finaldatalen);
236  size_t fetched = 0;
237  off_t offset = mc->pixelDataOffset();
238  if (!is_compressed || (options & OR_OPTIONS_DONT_DECOMPRESS)) {
239  fetched = m_container->fetchData(p, offset, datalen);
240  uint16_t* pixels = (uint16_t*)p;
241  for (auto i = 0; i < x * y; i++) {
242  *pixels = be16toh(*pixels);
243  pixels++;
244  }
245  } else {
246  Unpack unpack(x, IFD::COMPRESS_NONE);
247  size_t blocksize = unpack.block_size();
248  auto block = std::make_unique<uint8_t[]>(blocksize);
249  uint16_t* outdata = (uint16_t*)data.data();
250  size_t outsize = finaldatalen;
251  size_t got;
252  do {
253  LOGDBG2("fetchData @offset %lld\n", (long long int)offset);
254  got = m_container->fetchData(block.get(),
255  offset, blocksize);
256  fetched += got;
257  offset += got;
258  LOGDBG2("got %lu\n", (LSIZE)got);
259  if (got) {
260  size_t out;
261  or_error err = unpack.unpack_be12to16(outdata, outsize,
262  block.get(), got, out);
263  outdata += out / 2;
264  outsize -= out;
265  LOGDBG2("unpacked %lu bytes from %lu\n", (LSIZE)out, (LSIZE)got);
266  if (err != OR_ERROR_NONE) {
267  ret = err;
268  break;
269  }
270  }
271  } while ((got != 0) && (fetched < datalen));
272  }
273  if (fetched < datalen) {
274  LOGWARN("Fetched only %lu of %u: continuing anyway.\n", (LSIZE)fetched,
275  datalen);
276  }
277  uint16_t bpat = mc->prd->uint16_val(MRW::PRD_BAYER_PATTERN)
278  .value_or(MRW::BAYER_PATTERN_RGGB);
279  or_cfa_pattern cfa_pattern = OR_CFA_PATTERN_NONE;
280  switch (bpat)
281  {
282  case MRW::BAYER_PATTERN_RGGB:
283  cfa_pattern = OR_CFA_PATTERN_RGGB;
284  break;
285  case MRW::BAYER_PATTERN_GBRG:
286  cfa_pattern = OR_CFA_PATTERN_GBRG;
287  break;
288  default:
289  break;
290  }
291  data.setCfaPatternType(cfa_pattern);
292  data.setDimensions(x, y);
293 
294  return ret;
295 }
296 
297 }
298 }
299 /*
300  Local Variables:
301  mode:c++
302  c-file-style:"stroustrup"
303  c-file-offsets:((innamespace . 0))
304  indent-tabs-mode:nil
305  fill-column:80
306  End:
307 */
void setDataType(DataType _type)
Set the data type.
Definition: bitmapdata.cpp:91
void setBpc(uint32_t _bpc)
Set bit per channel.
Definition: bitmapdata.cpp:152
virtual void setDimensions(uint32_t x, uint32_t y)
Set the pixel dimensions of the bitmap.
Definition: bitmapdata.cpp:157
std::shared_ptr< Stream > Ptr
Definition: stream.hpp:47
std::shared_ptr< IfdDir > Ref
Shared ptr of an IfdDir.
Definition: ifddir.hpp:56
std::shared_ptr< IfdEntry > Ref
IfdEntry reference (ie shared pointer)
Definition: ifdentry.hpp:202
IfdDir::Ref setDirectory(int dir)
Set the current directory.
IO::Stream::Ptr m_io
Definition: ifdfile.hpp:106
IfdFileContainer * m_container
Definition: ifdfile.hpp:107
size_t fetchData(void *buf, off_t offset, size_t buf_size) const
Fetch the data chunk from the file.
or_error unpack_be12to16(uint16_t *dest, size_t destsize, const uint8_t *src, size_t size, size_t &outsize) const
Definition: unpack.cpp:58
Represent camera raw data.
Definition: rawdata.hpp:38
virtual void setDimensions(uint32_t x, uint32_t y) override
Set the pixel dimensions of the bitmap.
Definition: rawdata.cpp:297
RAW file.
Definition: rawfile.hpp:66
TypeId typeId()
The RAW file type ID. Identify it if needed.
Definition: rawfile.cpp:380
void _setTypeId(TypeId _type_id)
Set the file type id.
Definition: rawfile.cpp:428
Internals::MakerNoteDir::Ref makerNoteIfd()
Get the MakerNote IFD.
Definition: rawfile.cpp:724
Internals::IfdDir::Ref mainIfd()
Get the main IFD.
Definition: rawfile.cpp:706
Represent a thumbnail.
Definition: thumbnail.hpp:32
or_cfa_pattern
CFA pattern types.
Definition: consts.h:94
or_error
Error codes returned by libopenraw.
Definition: consts.h:42
@ OR_CFA_PATTERN_NONE
Definition: consts.h:95
@ OR_DATA_TYPE_JPEG
Definition: consts.h:84
@ OR_DATA_TYPE_COMPRESSED_RAW
Definition: consts.h:88
@ OR_DATA_TYPE_RAW
Definition: consts.h:87
@ OR_OPTIONS_DONT_DECOMPRESS
Definition: consts.h:114
@ OR_IFD_MAIN
Main (like in TIFF)
Definition: consts.h:144
@ OR_RAWFILE_TYPE_MRW
Definition: consts.h:64
@ OR_ERROR_NONE
Definition: consts.h:43
@ OR_ERROR_NOT_FOUND
Definition: consts.h:48
Global namespace for libopenraw.
Definition: arwfile.cpp:29
virtual ::or_error _enumThumbnailSizes(std::vector< uint32_t > &list) override
List the thumbnails in the IFD.
Definition: mrwfile.cpp:139
virtual void _identifyId() override
Identify the file and set the ID internally.
Definition: mrwfile.cpp:118
virtual ::or_error _getRawData(RawData &data, uint32_t options) override
Get the RAW data.
Definition: mrwfile.cpp:197
virtual IfdDir::Ref _locateCfaIfd() override
Locate the IFD for the raw data.
Definition: mrwfile.cpp:103
virtual IfdDir::Ref _locateMainIfd() override
Locate the main IFD.
Definition: mrwfile.cpp:109