1 /*
2     RawSpeed - RAW file decoder.
3 
4     Copyright (C) 2009-2014 Klaus Post
5     Copyright (C) 2014-2015 Pedro Côrte-Real
6     Copyright (C) 2017 Roman Lebedev
7 
8     This library is free software; you can redistribute it and/or
9     modify it under the terms of the GNU Lesser General Public
10     License as published by the Free Software Foundation; either
11     version 2 of the License, or (at your option) any later version.
12 
13     This library is distributed in the hope that it will be useful,
14     but WITHOUT ANY WARRANTY; without even the implied warranty of
15     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16     Lesser General Public License for more details.
17 
18     You should have received a copy of the GNU Lesser General Public
19     License along with this library; if not, write to the Free Software
20     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22 
23 #include "decoders/MrwDecoder.h"
24 #include "common/Point.h"                           // for iPoint2D
25 #include "decoders/RawDecoderException.h"           // for ThrowRDE
26 #include "decompressors/UncompressedDecompressor.h" // for UncompressedDeco...
27 #include "io/Buffer.h"                              // for DataBuffer, Buffer
28 #include "io/ByteStream.h"                          // for ByteStream
29 #include "io/Endianness.h"                          // for Endianness, Endi...
30 #include "metadata/Camera.h"                        // for Hints
31 #include "parsers/TiffParser.h"                     // for TiffParser
32 #include "tiff/TiffIFD.h"                           // for TiffRootIFDOwner
33 #include <cassert>                                  // for assert
34 #include <cstring>                                  // for memcmp
35 #include <memory>                                   // for unique_ptr
36 
37 namespace rawspeed {
38 
39 class CameraMetaData;
40 
MrwDecoder(const Buffer & file)41 MrwDecoder::MrwDecoder(const Buffer& file) : RawDecoder(file) { parseHeader(); }
42 
isMRW(const Buffer & input)43 int MrwDecoder::isMRW(const Buffer& input) {
44   static const std::array<char, 4> magic = {{0x00, 'M', 'R', 'M'}};
45   const unsigned char* data = input.getData(0, magic.size());
46   return 0 == memcmp(data, magic.data(), magic.size());
47 }
48 
parseHeader()49 void MrwDecoder::parseHeader() {
50   if (!isMRW(mFile))
51     ThrowRDE("This isn't actually a MRW file, why are you calling me?");
52 
53   const DataBuffer db(mFile, Endianness::big);
54   ByteStream bs(db);
55 
56   // magic
57   bs.skipBytes(4);
58 
59   // the size of the rest of the header, up to the image data
60   const auto headerSize = bs.getU32();
61   (void)bs.check(headerSize);
62 
63   // ... and offset to the image data at the same time
64   const auto dataOffset = bs.getPosition() + headerSize;
65   assert(bs.getPosition() == 8);
66 
67   // now, let's parse rest of the header.
68   bs = bs.getSubStream(0, dataOffset);
69   bs.skipBytes(8);
70 
71   bool foundPRD = false;
72   while (bs.getRemainSize() > 0) {
73     uint32_t tag = bs.getU32();
74     uint32_t len = bs.getU32();
75     (void)bs.check(len);
76     if (!len)
77       ThrowRDE("Found entry of zero length, MRW is corrupt.");
78 
79     const auto origPos = bs.getPosition();
80 
81     switch (tag) {
82     case 0x505244: {            // PRD
83       foundPRD = true;
84       bs.skipBytes(8);          // Version Number
85       raw_height = bs.getU16(); // CCD Size Y
86       raw_width = bs.getU16();  // CCD Size X
87 
88       if (!raw_width || !raw_height || raw_width > 3280 || raw_height > 2456) {
89         ThrowRDE("Unexpected image dimensions found: (%u; %u)", raw_width,
90                  raw_height);
91       }
92 
93       bs.skipBytes(2);          // Image Size Y
94       bs.skipBytes(2);          // Image Size X
95 
96       bpp = bs.getByte(); // DataSize
97       if (12 != bpp && 16 != bpp)
98         ThrowRDE("Unknown data size");
99 
100       if ((raw_height * raw_width * bpp) % 8 != 0)
101         ThrowRDE("Bad combination of image size and raw dimensions.");
102 
103       if (12 != bs.getByte()) // PixelSize
104         ThrowRDE("Unexpected pixel size");
105 
106       const auto SM = bs.getByte(); // StorageMethod
107       if (0x52 != SM && 0x59 != SM)
108         ThrowRDE("Unknown storage method");
109       packed = (0x59 == SM);
110 
111       if ((12 == bpp) != packed)
112         ThrowRDE("Packed/BPP sanity check failed!");
113 
114       bs.skipBytes(1); // Unknown1
115       bs.skipBytes(2); // Unknown2
116       bs.skipBytes(2); // BayerPattern
117       break;
118     }
119     case 0x545457: // TTW
120       // Base value for offsets needs to be at the beginning of the TIFF block,
121       // not the file
122       rootIFD = TiffParser::parse(nullptr, bs.getBuffer(len));
123       break;
124     case 0x574247:     // WBG
125       bs.skipBytes(4); // 4 factors
126       static_assert(4 == (sizeof(wb_coeffs) / sizeof(wb_coeffs[0])),
127                     "wrong coeff count");
128       for (auto& wb_coeff : wb_coeffs)
129         wb_coeff = static_cast<float>(bs.getU16()); // gain
130 
131       // FIXME?
132       // Gf = Gr / 2^(6+F)
133       break;
134     default:
135       // unknown block, let's just ignore
136       break;
137     }
138 
139     bs.setPosition(origPos + len);
140   }
141 
142   if (!foundPRD)
143     ThrowRDE("Did not find PRD tag. Image corrupt.");
144 
145   // processed all of the header. the image data is directly next
146 
147   const auto imageBits = raw_height * raw_width * bpp;
148   assert(imageBits > 0);
149   assert(imageBits % 8 == 0);
150 
151   imageData = db.getSubView(bs.getPosition(), imageBits / 8);
152 }
153 
decodeRawInternal()154 RawImage MrwDecoder::decodeRawInternal() {
155   mRaw->dim = iPoint2D(raw_width, raw_height);
156   mRaw->createData();
157 
158   DataBuffer db(imageData, Endianness::big);
159   ByteStream bs(db);
160   UncompressedDecompressor u(bs, mRaw);
161 
162   if (packed)
163     u.decode12BitRaw<Endianness::big>(raw_width, raw_height);
164   else
165     u.decodeRawUnpacked<12, Endianness::big>(raw_width, raw_height);
166 
167   return mRaw;
168 }
169 
checkSupportInternal(const CameraMetaData * meta)170 void MrwDecoder::checkSupportInternal(const CameraMetaData* meta) {
171   if (!rootIFD)
172     ThrowRDE("Couldn't find make and model");
173 
174   auto id = rootIFD->getID();
175   this->checkCameraSupported(meta, id.make, id.model, "");
176 }
177 
decodeMetaDataInternal(const CameraMetaData * meta)178 void MrwDecoder::decodeMetaDataInternal(const CameraMetaData* meta) {
179   //Default
180   int iso = 0;
181 
182   if (!rootIFD)
183     ThrowRDE("Couldn't find make and model");
184 
185   auto id = rootIFD->getID();
186   setMetaData(meta, id.make, id.model, "", iso);
187 
188   if (hints.has("swapped_wb")) {
189     mRaw->metadata.wbCoeffs[0] = wb_coeffs[2];
190     mRaw->metadata.wbCoeffs[1] = wb_coeffs[0];
191     mRaw->metadata.wbCoeffs[2] = wb_coeffs[1];
192   } else {
193     mRaw->metadata.wbCoeffs[0] = wb_coeffs[0];
194     mRaw->metadata.wbCoeffs[1] = wb_coeffs[1];
195     mRaw->metadata.wbCoeffs[2] = wb_coeffs[3];
196   }
197 }
198 
199 } // namespace rawspeed
200