RawSpeed
fast raw decoding library
Loading...
Searching...
No Matches
CrwDecoder.cpp
Go to the documentation of this file.
1/*
2 RawSpeed - RAW file decoder.
3
4 Copyright (C) 2009-2014 Klaus Post
5 Copyright (C) 2014 Pedro CĂ´rte-Real
6 Copyright (C) 2015-2018 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 "rawspeedconfig.h"
24#include "decoders/CrwDecoder.h"
25#include "adt/Array1DRef.h"
26#include "adt/Casts.h"
27#include "adt/Invariant.h"
28#include "adt/Optional.h"
29#include "adt/Point.h"
30#include "common/RawImage.h"
31#include "decoders/RawDecoder.h"
34#include "io/Buffer.h"
35#include "metadata/Camera.h"
37#include "tiff/CiffEntry.h"
38#include "tiff/CiffIFD.h"
39#include "tiff/CiffTag.h"
40#include <array>
41#include <cassert>
42#include <cmath>
43#include <cstdint>
44#include <cstdlib>
45#include <cstring>
46#include <memory>
47#include <string>
48#include <string_view>
49#include <utility>
50#include <vector>
51
52using std::vector;
53
54using std::abs;
55
56namespace rawspeed {
57
58class CameraMetaData;
59
61 static const std::array<char, 8> magic = {
62 {'H', 'E', 'A', 'P', 'C', 'C', 'D', 'R'}};
63 static const size_t magic_offset = 6;
64 const Buffer data = input.getSubView(magic_offset, magic.size());
65 return 0 == memcmp(data.begin(), magic.data(), magic.size());
66}
67
68CrwDecoder::CrwDecoder(std::unique_ptr<const CiffIFD> rootIFD, Buffer file)
69 : RawDecoder(file), mRootIFD(std::move(rootIFD)) {}
70
72 const CiffEntry* rawData = mRootIFD->getEntry(CiffTag::RAWDATA);
73 if (!rawData)
74 ThrowRDE("Couldn't find the raw data chunk");
75
76 const CiffEntry* sensorInfo =
77 mRootIFD->getEntryRecursive(CiffTag::SENSORINFO);
78 if (!sensorInfo || sensorInfo->count < 6 ||
79 sensorInfo->type != CiffDataType::SHORT)
80 ThrowRDE("Couldn't find image sensor info");
81
82 assert(sensorInfo != nullptr);
83 uint32_t width = sensorInfo->getU16(1);
84 uint32_t height = sensorInfo->getU16(2);
85 mRaw->dim = iPoint2D(width, height);
86
87 if (width == 0 || height == 0 || width % 4 != 0 || width > 4104 ||
88 height > 3048 || (height * width) % 64 != 0)
89 ThrowRDE("Unexpected image dimensions found: (%u; %u)", width, height);
90
91 const CiffEntry* decTable =
92 mRootIFD->getEntryRecursive(CiffTag::DECODERTABLE);
93 if (!decTable || decTable->type != CiffDataType::LONG)
94 ThrowRDE("Couldn't find decoder table");
95
96 assert(decTable != nullptr);
97 uint32_t dec_table = decTable->getU32();
98
99 bool lowbits = !hints.contains("no_decompressed_lowbits");
100
101 ByteStream rawInput = rawData->getData();
102
104 if (lowbits) {
105 // If there are low bits, the first part (size is calculable) is low bits
106 // Each block is 4 pairs of 2 bits, so we have 1 block per 4 pixels
107 const int lBlocks = 1 * height * width / 4;
108 invariant(lBlocks > 0);
109 lowbitInput = rawInput.getStream(lBlocks);
110 }
111
112 // We always ignore next 514 bytes of 'padding'. No idea what is in there.
113 rawInput.skipBytes(514);
114
117
118 CrwDecompressor c(mRaw, dec_table, input, lowbitInput);
119 mRaw->createData();
120 c.decompress();
121
122 return mRaw;
123}
124
126 vector<const CiffIFD*> data = mRootIFD->getIFDsWithTag(CiffTag::MAKEMODEL);
127 if (data.empty())
128 ThrowRDE("Model name not found");
129 vector<std::string> makemodel =
130 data[0]->getEntry(CiffTag::MAKEMODEL)->getStrings();
131 if (makemodel.size() < 2)
132 ThrowRDE("wrong number of strings for make/model");
133 const std::string& make = makemodel[0];
134 const std::string& model = makemodel[1];
135
136 this->checkCameraSupported(meta, make, model, "");
137}
138
139// based on exiftool's Image::ExifTool::Canon::CanonEv
140float RAWSPEED_READNONE CrwDecoder::canonEv(const int64_t in) {
141 // remove sign
142 int64_t val = abs(in);
143 // remove fraction
144 int64_t frac = val & 0x1f;
145 val -= frac;
146 // convert 1/3 (0x0c) and 2/3 (0x14) codes
147 if (frac == 0x0c) {
148 frac = implicit_cast<int64_t>(32.0F / 3);
149 } else if (frac == 0x14) {
150 frac = implicit_cast<int64_t>(64.0F / 3);
151 }
152 return copysignf(implicit_cast<float>(val + frac) / 32.0F,
154}
155
157 int iso = 0;
158 mRaw->cfa.setCFA(iPoint2D(2, 2), CFAColor::RED, CFAColor::GREEN,
160 vector<const CiffIFD*> data = mRootIFD->getIFDsWithTag(CiffTag::MAKEMODEL);
161 if (data.empty())
162 ThrowRDE("Model name not found");
163 vector<std::string> makemodel =
164 data[0]->getEntry(CiffTag::MAKEMODEL)->getStrings();
165 if (makemodel.size() < 2)
166 ThrowRDE("wrong number of strings for make/model");
167 const std::string& make = makemodel[0];
168 const std::string& model = makemodel[1];
169 std::string mode;
170
171 if (mRootIFD->hasEntryRecursive(CiffTag::SHOTINFO)) {
172 const CiffEntry* shot_info = mRootIFD->getEntryRecursive(CiffTag::SHOTINFO);
173 if (shot_info->type == CiffDataType::SHORT && shot_info->count >= 2) {
174 // os << exp(canonEv(value.toLong()) * log(2.0)) * 100.0 / 32.0;
175 uint16_t iso_index = shot_info->getU16(2);
176 iso = implicit_cast<int>(
177 expf(canonEv(static_cast<int64_t>(iso_index)) * logf(2.0)) * 100.0F /
178 32.0F);
179 }
180 }
181
182 // Fetch the white balance
183 try {
184 if (mRootIFD->hasEntryRecursive(static_cast<CiffTag>(0x0032))) {
185 const CiffEntry* wb =
186 mRootIFD->getEntryRecursive(static_cast<CiffTag>(0x0032));
187 if (wb->type == CiffDataType::BYTE && wb->count == 768) {
188 // We're in a D30 file, values are RGGB
189 // This, not 0x102c tag, should be used.
190 std::array<uint16_t, 4> wbMuls{
191 {wb->getU16(36), wb->getU16(37), wb->getU16(38), wb->getU16(39)}};
192 for (const auto& mul : wbMuls) {
193 if (0 == mul)
194 ThrowRDE("WB coefficient is zero!");
195 }
196
197 std::array<float, 4> wbCoeffs = {};
198 wbCoeffs[0] = static_cast<float>(1024.0 / wbMuls[0]);
199 wbCoeffs[1] =
200 static_cast<float>((1024.0 / wbMuls[1]) + (1024.0 / wbMuls[2])) /
201 2.0F;
202 wbCoeffs[2] = static_cast<float>(1024.0 / wbMuls[3]);
203 mRaw->metadata.wbCoeffs = wbCoeffs;
204 } else if (wb->type == CiffDataType::BYTE &&
205 wb->count > 768) { // Other G series and S series cameras
206 // correct offset for most cameras
207 int offset = hints.get("wb_offset", 120);
208
209 std::array<uint16_t, 2> key = {{0x410, 0x45f3}};
210 if (!hints.contains("wb_mangle"))
211 key[0] = key[1] = 0;
212
213 offset /= 2;
214 std::array<float, 4> wbCoeffs = {};
215 wbCoeffs[0] = static_cast<float>(wb->getU16(offset + 1) ^ key[1]);
216 wbCoeffs[1] = static_cast<float>(wb->getU16(offset + 0) ^ key[0]);
217 wbCoeffs[2] = static_cast<float>(wb->getU16(offset + 2) ^ key[0]);
218 mRaw->metadata.wbCoeffs = wbCoeffs;
219 }
220 }
221 if (mRootIFD->hasEntryRecursive(static_cast<CiffTag>(0x102c))) {
222 const CiffEntry* entry =
223 mRootIFD->getEntryRecursive(static_cast<CiffTag>(0x102c));
224 if (entry->type == CiffDataType::SHORT && entry->getU16() > 512) {
225 // G1/Pro90 CYGM pattern
226 std::array<float, 4> wbCoeffs = {};
227 wbCoeffs[0] = static_cast<float>(entry->getU16(62));
228 wbCoeffs[1] = static_cast<float>(entry->getU16(63));
229 wbCoeffs[2] = static_cast<float>(entry->getU16(60));
230 wbCoeffs[3] = static_cast<float>(entry->getU16(61));
231 mRaw->metadata.wbCoeffs = wbCoeffs;
232 } else if (entry->type == CiffDataType::SHORT && entry->getU16() != 276) {
233 /* G2, S30, S40 */
234 std::array<float, 4> wbCoeffs = {};
235 wbCoeffs[0] = static_cast<float>(entry->getU16(51));
236 wbCoeffs[1] = (static_cast<float>(entry->getU16(50)) +
237 static_cast<float>(entry->getU16(53))) /
238 2.0F;
239 wbCoeffs[2] = static_cast<float>(entry->getU16(52));
240 mRaw->metadata.wbCoeffs = wbCoeffs;
241 }
242 }
243 if (mRootIFD->hasEntryRecursive(CiffTag::SHOTINFO) &&
244 mRootIFD->hasEntryRecursive(CiffTag::WHITEBALANCE)) {
245 const CiffEntry* shot_info =
246 mRootIFD->getEntryRecursive(CiffTag::SHOTINFO);
247 uint16_t wb_index = shot_info->getU16(7);
248 const CiffEntry* wb_data =
249 mRootIFD->getEntryRecursive(CiffTag::WHITEBALANCE);
250 /* CANON EOS D60, CANON EOS 10D, CANON EOS 300D */
251 if (wb_index > 9)
252 ThrowRDE("Invalid white balance index");
253 int wb_offset =
254 1 + ((std::string_view("0134567028")[wb_index] - '0') * 4);
255 std::array<float, 4> wbCoeffs = {};
256 wbCoeffs[0] = wb_data->getU16(wb_offset + 0);
257 wbCoeffs[1] = wb_data->getU16(wb_offset + 1);
258 wbCoeffs[2] = wb_data->getU16(wb_offset + 3);
259 mRaw->metadata.wbCoeffs = wbCoeffs;
260 }
261 } catch (const RawspeedException& e) {
262 mRaw->setError(e.what());
263 // We caught an exception reading WB, just ignore it
264 }
265
266 setMetaData(meta, make, model, mode, iso);
267}
268
269} // namespace rawspeed
#define invariant(expr)
Definition Invariant.h:27
#define ThrowRDE(...)
assert(dim.area() >=area)
Array1DRef< const uint8_t > getAsArray1DRef() const
Definition Buffer.h:70
Buffer getSubView(size_type offset, size_type size_) const
Definition Buffer.h:78
const uint8_t * begin() const
Definition Buffer.h:99
ByteStream getStream(size_type size_)
Definition ByteStream.h:119
void skipBytes(size_type nbytes)
Definition ByteStream.h:130
Buffer peekRemainingBuffer() const
Definition ByteStream.h:108
Definition CiffEntry.h:54
CiffDataType type
Definition CiffEntry.h:81
uint32_t getU32(uint32_t num=0) const
ByteStream getData() const
Definition CiffEntry.h:65
uint16_t getU16(uint32_t num=0) const
uint32_t count
Definition CiffEntry.h:82
void checkSupportInternal(const CameraMetaData *meta) override
RawImage decodeRawInternal() override
void decodeMetaDataInternal(const CameraMetaData *meta) override
CrwDecoder(std::unique_ptr< const CiffIFD > rootIFD, Buffer file)
std::unique_ptr< const CiffIFD > mRootIFD
Definition CrwDecoder.h:36
static bool isCRW(Buffer input)
static float canonEv(int64_t in)
virtual void setMetaData(const CameraMetaData *meta, const std::string &make, const std::string &model, const std::string &mode, int iso_speed=0)
RawDecoder(Buffer file)
bool checkCameraSupported(const CameraMetaData *meta, const std::string &make, const std::string &model, const std::string &mode)
constexpr RAWSPEED_READNONE Ttgt implicit_cast(Tsrc value)
Definition Casts.h:32