RawSpeed
fast raw decoding library
Loading...
Searching...
No Matches
RafDecoder.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-2015 Pedro CĂ´rte-Real
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
9 License as published by the Free Software Foundation; either
10 version 2 of 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, write to the Free Software
19 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20*/
21
22#include "decoders/RafDecoder.h"
23#include "adt/Array1DRef.h"
24#include "adt/Array2DRef.h"
25#include "adt/Casts.h"
26#include "adt/Point.h"
28#include "common/RawImage.h"
32#include "io/Buffer.h"
33#include "io/ByteStream.h"
34#include "io/Endianness.h"
35#include "metadata/Camera.h"
39#include "tiff/TiffEntry.h"
40#include "tiff/TiffIFD.h"
41#include "tiff/TiffTag.h"
42#include <array>
43#include <cassert>
44#include <cstdint>
45#include <cstring>
46#include <memory>
47#include <string>
48#include <vector>
49
50namespace rawspeed {
51
53 static const std::array<char, 16> magic = {{'F', 'U', 'J', 'I', 'F', 'I', 'L',
54 'M', 'C', 'C', 'D', '-', 'R', 'A',
55 'W', ' '}};
56 const Buffer data = input.getSubView(0, magic.size());
57 return 0 == memcmp(data.begin(), magic.data(), magic.size());
58}
59
61 [[maybe_unused]] Buffer file) {
62 const auto id = rootIFD->getID();
63 const std::string& make = id.make;
64
65 // FIXME: magic
66
67 return make == "FUJIFILM";
68}
69
71 const auto* raw = mRootIFD->getIFDWithTag(TiffTag::FUJI_STRIPOFFSETS);
72 uint32_t height = 0;
73 uint32_t width = 0;
74
75 if (raw->hasEntry(TiffTag::FUJI_RAWIMAGEFULLHEIGHT)) {
76 height = raw->getEntry(TiffTag::FUJI_RAWIMAGEFULLHEIGHT)->getU32();
77 width = raw->getEntry(TiffTag::FUJI_RAWIMAGEFULLWIDTH)->getU32();
78 } else if (raw->hasEntry(TiffTag::FUJI_RAWIMAGEFULLSIZE)) {
79 const TiffEntry* e = raw->getEntry(TiffTag::FUJI_RAWIMAGEFULLSIZE);
80 height = e->getU16(0);
81 width = e->getU16(1);
82 } else {
83 ThrowRDE("Unable to locate image size");
84 }
85
86 if (width == 0 || height == 0 || width > 11808 || height > 8754)
87 ThrowRDE("Unexpected image dimensions found: (%u; %u)", width, height);
88
89 if (raw->hasEntry(TiffTag::FUJI_LAYOUT)) {
90 const TiffEntry* e = raw->getEntry(TiffTag::FUJI_LAYOUT);
91 alt_layout = !(e->getByte(0) >> 7);
92 }
93
94 const TiffEntry* offsets = raw->getEntry(TiffTag::FUJI_STRIPOFFSETS);
95 const TiffEntry* counts = raw->getEntry(TiffTag::FUJI_STRIPBYTECOUNTS);
96
97 if (offsets->count != 1 || counts->count != 1)
98 ThrowRDE("Multiple Strips found: %u %u", offsets->count, counts->count);
99
100 ByteStream input(offsets->getRootIfdData());
101 input = input.getSubStream(offsets->getU32(), counts->getU32());
102
103 if (isCompressed()) {
104 mRaw->metadata.mode = "compressed";
105
106 mRaw->dim = iPoint2D(width, height);
107
108 FujiDecompressor f(mRaw, input);
109
110 mRaw->createData();
111
112 f.decompress();
113
114 return mRaw;
115 }
116
117 // x-trans sensors report 14bpp, but data isn't packed
118 // thus, unless someone has any better ideas, let's autodetect it.
119 int bps;
120
121 // Some fuji SuperCCD cameras include a second raw image next to the first one
122 // that is identical but darker to the first. The two combined can produce
123 // a higher dynamic range image. Right now we're ignoring it.
124 bool double_width;
125
127
128 if (8UL * counts->getU32() >= 2UL * 16UL * width * height) {
129 bps = 16;
130 double_width = true;
131 } else if (8UL * counts->getU32() >= 2UL * 14UL * width * height) {
132 bps = 14;
133 double_width = true;
134 } else if (8UL * counts->getU32() >= 2UL * 12UL * width * height) {
135 bps = 12;
136 double_width = true;
137 } else if (8UL * counts->getU32() >= 16UL * width * height) {
138 bps = 16;
139 double_width = false;
140 } else if (8UL * counts->getU32() >= 14UL * width * height) {
141 bps = 14;
142 double_width = false;
143 } else if (8UL * counts->getU32() >= 12UL * width * height) {
144 bps = 12;
145 double_width = false;
146 } else {
147 ThrowRDE("Can not detect bitdepth. StripByteCounts = %u, width = %u, "
148 "height = %u",
149 counts->getU32(), width, height);
150 }
151
152 double_width = hints.contains("double_width_unpacked");
153 const uint32_t real_width = double_width ? 2U * width : width;
154
155 mRaw->dim = iPoint2D(real_width, height);
156
157 if (double_width) {
159 input, mRaw, iRectangle2D({0, 0}, iPoint2D(2 * width, height)),
160 2 * 2 * width, 16, BitOrder::LSB);
161 mRaw->createData();
162 u.readUncompressedRaw();
163 } else if (input.getByteOrder() == Endianness::big &&
165 // FIXME: ^ that if seems fishy
167 iRectangle2D({0, 0}, iPoint2D(width, height)),
168 2 * width, 16, BitOrder::MSB);
169 mRaw->createData();
170 u.readUncompressedRaw();
171 } else {
172 iPoint2D pos(0, 0);
173 if (hints.contains("jpeg32_bitorder")) {
174 UncompressedDecompressor u(input, mRaw, iRectangle2D(pos, mRaw->dim),
175 width * bps / 8, bps, BitOrder::MSB32);
176 mRaw->createData();
177 u.readUncompressedRaw();
178 } else {
179 UncompressedDecompressor u(input, mRaw, iRectangle2D(pos, mRaw->dim),
180 width * bps / 8, bps, BitOrder::LSB);
181 mRaw->createData();
182 u.readUncompressedRaw();
183 }
184 }
185
186 return mRaw;
187}
188
190 if (!this->checkCameraSupported(meta, mRootIFD->getID(), ""))
191 ThrowRDE("Unknown camera. Will not guess.");
192
193 if (isCompressed()) {
194 mRaw->metadata.mode = "compressed";
195
196 auto id = mRootIFD->getID();
197 const Camera* cam = meta->getCamera(id.make, id.model, mRaw->metadata.mode);
198 if (!cam)
199 ThrowRDE("Couldn't find camera %s %s", id.make.c_str(), id.model.c_str());
200
201 mRaw->cfa = cam->cfa;
202 }
203}
204
206 iPoint2D new_size(mRaw->dim);
207 iPoint2D crop_offset(0, 0);
208
209 if (applyCrop) {
210 if (cam->cropAvailable) {
211 new_size = cam->cropSize;
212 crop_offset = cam->cropPos;
213 } else {
214 const iRectangle2D vendor_crop = getDefaultCrop();
215 new_size = vendor_crop.dim;
216 crop_offset = vendor_crop.pos;
217 }
218 bool double_width = hints.contains("double_width_unpacked");
219 // If crop size is negative, use relative cropping
220 if (new_size.x <= 0) {
221 new_size.x =
222 mRaw->dim.x / (double_width ? 2 : 1) - crop_offset.x + new_size.x;
223 } else {
224 new_size.x /= (double_width ? 2 : 1);
225 }
226 if (new_size.y <= 0)
227 new_size.y = mRaw->dim.y - crop_offset.y + new_size.y;
228 }
229
230 bool rotate = hints.contains("fuji_rotate");
231 rotate = rotate && fujiRotate;
232
233 // Rotate 45 degrees - could be multithreaded.
234 if (rotate && !this->uncorrectedRawValues) {
235 // Calculate the 45 degree rotated size;
236 uint32_t rotatedsize;
237 uint32_t rotationPos;
238 if (alt_layout) {
239 rotatedsize = new_size.y + new_size.x / 2;
240 rotationPos = new_size.x / 2 - 1;
241 } else {
242 rotatedsize = new_size.x + new_size.y / 2;
243 rotationPos = new_size.x - 1;
244 }
245
246 iPoint2D final_size(rotatedsize, rotatedsize - 1);
247 RawImage rotated = RawImage::create(final_size, RawImageType::UINT16, 1);
248 rotated->clearArea(iRectangle2D(iPoint2D(0, 0), rotated->dim));
249 rotated->cfa = mRaw->cfa;
250 rotated->metadata = mRaw->metadata;
251 rotated->metadata.fujiRotationPos = rotationPos;
252
253 auto srcImg = mRaw->getU16DataAsUncroppedArray2DRef();
254 auto dstImg = rotated->getU16DataAsUncroppedArray2DRef();
255
256 for (int y = 0; y < new_size.y; y++) {
257 for (int x = 0; x < new_size.x; x++) {
258 int h;
259 int w;
260 if (alt_layout) { // Swapped x and y
261 h = rotatedsize - (new_size.y + 1 - y + (x >> 1));
262 w = ((x + 1) >> 1) + y;
263 } else {
264 h = new_size.x - 1 - x + (y >> 1);
265 w = ((y + 1) >> 1) + x;
266 }
267 if (h < rotated->dim.y && w < rotated->dim.x)
268 dstImg(h, w) = srcImg(crop_offset.y + y, crop_offset.x + x);
269 else
270 ThrowRDE("Trying to write out of bounds");
271 }
272 }
273 mRaw = rotated;
274 } else if (applyCrop) {
275 mRaw->subFrame(iRectangle2D(crop_offset, new_size));
276 }
277}
278
280 int iso = 0;
281 if (mRootIFD->hasEntryRecursive(TiffTag::ISOSPEEDRATINGS))
282 iso = mRootIFD->getEntryRecursive(TiffTag::ISOSPEEDRATINGS)->getU32();
283 mRaw->metadata.isoSpeed = iso;
284
285 // Set white point derived from Exif.Fujifilm.BitsPerSample if available,
286 // can be overridden by XML data.
287 if (mRootIFD->hasEntryRecursive(TiffTag::FUJI_BITSPERSAMPLE)) {
288 unsigned bps =
289 mRootIFD->getEntryRecursive(TiffTag::FUJI_BITSPERSAMPLE)->getU32();
290 if (bps > 16)
291 ThrowRDE("Unexpected bit depth: %u", bps);
292 mRaw->whitePoint = implicit_cast<int>((1UL << bps) - 1UL);
293 }
294
295 // This is where we'd normally call setMetaData but since we may still need
296 // to rotate the image for SuperCCD cameras we do everything ourselves
297 auto id = mRootIFD->getID();
298 const Camera* cam = meta->getCamera(id.make, id.model, mRaw->metadata.mode);
299 if (!cam)
300 ThrowRDE("Couldn't find camera");
301
302 assert(cam != nullptr);
303
304 mRaw->cfa = cam->cfa;
305
306 applyCorrections(cam);
307
308 // at least the (bayer sensor) X100 comes with a tag like this:
309 if (mRootIFD->hasEntryRecursive(TiffTag::FUJI_BLACKLEVEL)) {
310 const TiffEntry* sep_black =
311 mRootIFD->getEntryRecursive(TiffTag::FUJI_BLACKLEVEL);
312 if (sep_black->count == 4) {
313 mRaw->blackLevelSeparate =
314 Array2DRef(mRaw->blackLevelSeparateStorage.data(), 2, 2);
315 auto blackLevelSeparate1D = *mRaw->blackLevelSeparate->getAsArray1DRef();
316 for (int k = 0; k < 4; k++)
317 blackLevelSeparate1D(k) = sep_black->getU32(k);
318 } else if (sep_black->count == 36) {
319 mRaw->blackLevelSeparate =
320 Array2DRef(mRaw->blackLevelSeparateStorage.data(), 2, 2);
321 auto blackLevelSeparate1D = *mRaw->blackLevelSeparate->getAsArray1DRef();
322 for (int& k : blackLevelSeparate1D)
323 k = 0;
324
325 for (int y = 0; y < 6; y++) {
326 for (int x = 0; x < 6; x++)
327 blackLevelSeparate1D((2 * (y % 2)) + (x % 2)) +=
328 sep_black->getU32((6 * y) + x);
329 }
330
331 for (int& k : blackLevelSeparate1D)
332 k /= 9;
333 }
334
335 // Set black level to average of EXIF data, can be overridden by XML data.
336 int sum = 0;
337 auto blackLevelSeparate1D = *mRaw->blackLevelSeparate->getAsArray1DRef();
338 for (int b : blackLevelSeparate1D)
339 sum += b;
340 mRaw->blackLevel = (sum + 2) >> 2;
341 }
342
343 if (const CameraSensorInfo* sensor = cam->getSensorInfo(iso);
344 sensor && sensor->mWhiteLevel > 0) {
345 mRaw->blackLevel = sensor->mBlackLevel;
346 mRaw->whitePoint = sensor->mWhiteLevel;
347 }
348
349 mRaw->blackAreas = cam->blackAreas;
350
351 if (!cam->color_matrix.empty())
352 mRaw->metadata.colorMatrix = cam->color_matrix;
353 mRaw->metadata.canonical_make = cam->canonical_make;
354 mRaw->metadata.canonical_model = cam->canonical_model;
355 mRaw->metadata.canonical_alias = cam->canonical_alias;
356 mRaw->metadata.canonical_id = cam->canonical_id;
357 mRaw->metadata.make = id.make;
358 mRaw->metadata.model = id.model;
359
360 if (mRootIFD->hasEntryRecursive(TiffTag::FUJI_WB_GRBLEVELS)) {
361 const TiffEntry* wb =
362 mRootIFD->getEntryRecursive(TiffTag::FUJI_WB_GRBLEVELS);
363 if (wb->count == 3) {
364 std::array<float, 4> wbCoeffs = {};
365 wbCoeffs[0] = wb->getFloat(1);
366 wbCoeffs[1] = wb->getFloat(0);
367 wbCoeffs[2] = wb->getFloat(2);
368 mRaw->metadata.wbCoeffs = wbCoeffs;
369 }
370 } else if (mRootIFD->hasEntryRecursive(TiffTag::FUJIOLDWB)) {
371 const TiffEntry* wb = mRootIFD->getEntryRecursive(TiffTag::FUJIOLDWB);
372 if (wb->count == 8) {
373 std::array<float, 4> wbCoeffs = {};
374 wbCoeffs[0] = wb->getFloat(1);
375 wbCoeffs[1] = wb->getFloat(0);
376 wbCoeffs[2] = wb->getFloat(3);
377 mRaw->metadata.wbCoeffs = wbCoeffs;
378 }
379 }
380}
381
383 const auto* raw = mRootIFD->getIFDWithTag(TiffTag::FUJI_STRIPOFFSETS);
384 uint32_t height = 0;
385 uint32_t width = 0;
386
387 if (raw->hasEntry(TiffTag::FUJI_RAWIMAGEFULLHEIGHT)) {
388 height = raw->getEntry(TiffTag::FUJI_RAWIMAGEFULLHEIGHT)->getU32();
389 width = raw->getEntry(TiffTag::FUJI_RAWIMAGEFULLWIDTH)->getU32();
390 } else if (raw->hasEntry(TiffTag::IMAGEWIDTH)) {
391 const TiffEntry* e = raw->getEntry(TiffTag::IMAGEWIDTH);
392 height = e->getU16(0);
393 width = e->getU16(1);
394 } else {
395 ThrowRDE("Unable to locate image size");
396 }
397
398 if (width == 0 || height == 0 || width > 11808 || height > 8754)
399 ThrowRDE("Unexpected image dimensions found: (%u; %u)", width, height);
400
401 uint32_t bps;
402 if (raw->hasEntry(TiffTag::FUJI_BITSPERSAMPLE))
403 bps = raw->getEntry(TiffTag::FUJI_BITSPERSAMPLE)->getU32();
404 else
405 bps = 12;
406
407 uint32_t count = raw->getEntry(TiffTag::FUJI_STRIPBYTECOUNTS)->getU32();
408
409 // FIXME: This is not an ideal way to detect compression, but I'm not seeing
410 // anything in the diff between exiv2/exiftool dumps of {un,}compressed raws.
411 // Maybe we are supposed to check for valid FujiDecompressor::FujiHeader ?
412 return count * 8 / (width * height) < bps;
413}
414
416 // Crop tags alias baseline TIFF tags, but are in the Fujifilm proprietary
417 // directory that can be identified by a different unique tag.
418 if (const auto* raw = mRootIFD->getIFDWithTag(TiffTag::FUJI_RAFDATA);
419 raw->hasEntry(TiffTag::FUJI_RAWIMAGECROPTOPLEFT) &&
420 raw->hasEntry(TiffTag::FUJI_RAWIMAGECROPPEDSIZE)) {
421 const auto* pos = raw->getEntry(TiffTag::FUJI_RAWIMAGECROPTOPLEFT);
422 const uint16_t topBorder = pos->getU16(0);
423 const uint16_t leftBorder = pos->getU16(1);
424 const auto* dim = raw->getEntry(TiffTag::FUJI_RAWIMAGECROPPEDSIZE);
425 const uint16_t height = dim->getU16(0);
426 const uint16_t width = dim->getU16(1);
427 return {leftBorder, topBorder, width, height};
428 }
429 ThrowRDE("Cannot figure out vendor crop. Required entries were not found: "
430 "%X, %X",
431 static_cast<unsigned int>(TiffTag::FUJI_RAWIMAGECROPTOPLEFT),
432 static_cast<unsigned int>(TiffTag::FUJI_RAWIMAGECROPPEDSIZE));
433}
434
435} // namespace rawspeed
#define ThrowRDE(...)
iPoint2D dim(rawspeed::implicit_cast< int >(ceil(sqSide *sqARatio)), rawspeed::implicit_cast< int >(ceil(sqSide/sqARatio)))
Definition Common.cpp:55
assert(dim.area() >=area)
dim y
Definition Common.cpp:51
dim x
Definition Common.cpp:50
bool checkCameraSupported(const CameraMetaData *meta, const TiffID &id, const std::string &mode)
Buffer getSubView(size_type offset, size_type size_) const
Definition Buffer.h:78
const uint8_t * begin() const
Definition Buffer.h:99
ByteStream getSubStream(size_type offset, size_type size_) const
Definition ByteStream.h:54
std::string canonical_id
Definition Camera.h:100
std::string canonical_alias
Definition Camera.h:99
iPoint2D cropPos
Definition Camera.h:106
std::string canonical_model
Definition Camera.h:98
iPoint2D cropSize
Definition Camera.h:105
bool cropAvailable
Definition Camera.h:117
std::string canonical_make
Definition Camera.h:97
std::vector< BlackArea > blackAreas
Definition Camera.h:107
const CameraSensorInfo * getSensorInfo(int iso) const
Definition Camera.cpp:418
std::vector< NotARational< int > > color_matrix
Definition Camera.h:111
ColorFilterArray cfa
Definition Camera.h:103
const Camera * getCamera(const std::string &make, const std::string &model, const std::string &mode) const
Endianness getByteOrder() const
Definition Buffer.h:154
int isCompressed() const
static bool isAppropriateDecoder(const TiffRootIFD *rootIFD, Buffer file)
static bool isRAF(Buffer input)
void decodeMetaDataInternal(const CameraMetaData *meta) override
iRectangle2D getDefaultCrop() override
void checkSupportInternal(const CameraMetaData *meta) override
void applyCorrections(const Camera *cam)
RawImage decodeRawInternal() override
Array2DRef< uint16_t > getU16DataAsUncroppedArray2DRef() noexcept
Definition RawImage.h:290
void clearArea(iRectangle2D area)
Definition RawImage.cpp:326
ImageMetaData metadata
Definition RawImage.h:184
ColorFilterArray cfa
Definition RawImage.h:162
static RawImage create(RawImageType type=RawImageType::UINT16)
Definition RawImage.h:265
Definition TiffEntry.h:62
DataBuffer getRootIfdData() const
float getFloat(uint32_t index=0) const
uint32_t getU32(uint32_t index=0) const
uint32_t count
Definition TiffEntry.h:84
uint16_t getU16(uint32_t index=0) const
uint8_t getByte(uint32_t index=0) const
TiffID getID() const
Definition TiffIFD.cpp:325
value_type x
Definition Point.h:102
value_type y
Definition Point.h:103
constexpr RAWSPEED_READNONE Ttgt implicit_cast(Tsrc value)
Definition Casts.h:32
Array2DRef(Array1DRef< T > data, int width, int height, int pitch) -> Array2DRef< T >
Endianness getHostEndianness()
Definition Endianness.h:51
@ FUJI_RAWIMAGECROPPEDSIZE
Definition TiffTag.h:54
@ FUJI_RAWIMAGECROPTOPLEFT
Definition TiffTag.h:52
std::string make
Definition TiffIFD.h:134