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