RawSpeed
fast raw decoding library
Loading...
Searching...
No Matches
OrfDecoder.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 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/OrfDecoder.h"
24#include "adt/Array1DRef.h"
25#include "adt/Array2DRef.h"
26#include "adt/Casts.h"
27#include "adt/NORangesSet.h"
28#include "adt/Point.h"
31#include "common/Common.h"
32#include "common/RawImage.h"
36#include "io/Buffer.h"
37#include "io/ByteStream.h"
38#include "io/Endianness.h"
40#include "tiff/TiffEntry.h"
41#include "tiff/TiffIFD.h"
42#include "tiff/TiffTag.h"
43#include <array>
44#include <cassert>
45#include <cstdint>
46#include <memory>
47#include <string>
48
49namespace rawspeed {
50
51class CameraMetaData;
52
54 [[maybe_unused]] Buffer file) {
55 const auto id = rootIFD->getID();
56 const std::string& make = id.make;
57
58 // FIXME: magic
59
60 return make == "OLYMPUS IMAGING CORP." || make == "OLYMPUS CORPORATION" ||
61 make == "OLYMPUS OPTICAL CO.,LTD" || make == "OM Digital Solutions";
62}
63
65 const auto* raw = mRootIFD->getIFDWithTag(TiffTag::STRIPOFFSETS);
66
67 const TiffEntry* offsets = raw->getEntry(TiffTag::STRIPOFFSETS);
68 const TiffEntry* counts = raw->getEntry(TiffTag::STRIPBYTECOUNTS);
69
70 if (counts->count != offsets->count) {
72 "Byte count number does not match strip size: count:%u, strips:%u ",
73 counts->count, offsets->count);
74 }
75
76 const uint32_t off = offsets->getU32(0);
77 uint32_t size = counts->getU32(0);
78 auto end = [&off, &size]() { return off + size; };
79
80 for (uint32_t i = 0; i < counts->count; i++) {
81 const auto offset = offsets->getU32(i);
82 const auto count = counts->getU32(i);
83 if (!mFile.isValid(offset, count))
84 ThrowRDE("Truncated file");
85
86 if (count < 1)
87 ThrowRDE("Empty slice");
88
89 if (i == 0)
90 continue;
91
92 if (offset < end())
93 ThrowRDE("Slices overlap");
94
95 // Now, everything would be great, but some uncompressed raws
96 // (packed_with_control i believe) have "padding" between at least
97 // the first two slices, and we need to account for it.
98 const uint32_t padding = offset - end();
99
100 size += padding;
101 size += count;
102 }
103
104 ByteStream input(offsets->getRootIfdData());
105 input.setPosition(off);
106
107 return input.getStream(size);
108}
109
111 const auto* raw = mRootIFD->getIFDWithTag(TiffTag::STRIPOFFSETS);
112
113 if (int compression = raw->getEntry(TiffTag::COMPRESSION)->getU32();
114 1 != compression)
115 ThrowRDE("Unsupported compression");
116
117 uint32_t width = raw->getEntry(TiffTag::IMAGEWIDTH)->getU32();
118 uint32_t height = raw->getEntry(TiffTag::IMAGELENGTH)->getU32();
119
120 if (!width || !height || width % 2 != 0 || width > 10400 || height > 7796)
121 ThrowRDE("Unexpected image dimensions found: (%u; %u)", width, height);
122
123 mRaw->dim = iPoint2D(width, height);
124
125 ByteStream input(handleSlices());
126
127 if (decodeUncompressed(input, width, height, input.getSize()))
128 return mRaw;
129
130 if (raw->getEntry(TiffTag::STRIPOFFSETS)->count != 1)
131 ThrowRDE("%u stripes, and not uncompressed. Unsupported.",
132 raw->getEntry(TiffTag::STRIPOFFSETS)->count);
133
134 if (const int bitsPerPixel = getBitsPerPixel(); bitsPerPixel == 12) {
135 input.skipBytes(7);
136 } else if (bitsPerPixel == 14) {
137 input.skipBytes(8);
138 } else {
139 ThrowRDE("%i-bit images are not supported currently.", bitsPerPixel);
140 }
141
142 const OlympusDecompressor o(mRaw);
143 mRaw->createData();
144 o.decompress(input);
145
146 return mRaw;
147}
148
150 int result = 12;
151 if (mRootIFD->hasEntryRecursive(TiffTag::OLYMPUSIMAGEPROCESSING)) {
152 // Newer cameras process the Image Processing SubIFD in the makernote
153 const TiffEntry* img_entry =
154 mRootIFD->getEntryRecursive(TiffTag::OLYMPUSIMAGEPROCESSING);
155 // get makernote ifd with containing Buffer
157
158 TiffRootIFD image_processing(nullptr, &ifds, img_entry->getRootIfdData(),
159 img_entry->getU32());
160
161 if (image_processing.hasEntry(static_cast<TiffTag>(0x0611))) {
162 const TiffEntry* validBits =
163 image_processing.getEntry(static_cast<TiffTag>(0x0611));
164 result = validBits->getU16();
165 }
166 }
167 return result;
168}
169
171 uint32_t h,
172 uint32_t size) const {
173 int inputPitchBits = 12 * w;
174 assert(inputPitchBits % 8 == 0);
175
176 int inputPitchBytes = inputPitchBits / 8;
177
178 const auto numEvenLines = implicit_cast<int>(roundUpDivisionSafe(h, 2));
179 const auto evenLinesInput = s.getStream(numEvenLines, inputPitchBytes)
180 .peekRemainingBuffer()
181 .getAsArray1DRef();
182
183 const auto oddLinesInputBegin =
184 implicit_cast<int>(roundUp(evenLinesInput.size(), 1U << 11U));
185 assert(oddLinesInputBegin >= evenLinesInput.size());
186 int padding = oddLinesInputBegin - evenLinesInput.size();
187 assert(padding >= 0);
188 s.skipBytes(padding);
189
190 const int numOddLines = h - numEvenLines;
191 const auto oddLinesInput = s.getStream(numOddLines, inputPitchBytes)
192 .peekRemainingBuffer()
193 .getAsArray1DRef();
194
195 // By now we know we have enough input to produce the image.
196 mRaw->createData();
197
198 const Array2DRef<uint16_t> out(mRaw->getU16DataAsUncroppedArray2DRef());
199 {
200 BitStreamerMSB bs(evenLinesInput);
201 for (int i = 0; i != numEvenLines; ++i) {
202 for (unsigned col = 0; col != w; ++col) {
203 int row = 2 * i;
204 out(row, col) = implicit_cast<uint16_t>(bs.getBits(12));
205 }
206 }
207 }
208 {
209 BitStreamerMSB bs(oddLinesInput);
210 for (int i = 0; i != numOddLines; ++i) {
211 for (unsigned col = 0; col != w; ++col) {
212 int row = 1 + (2 * i);
213 out(row, col) = implicit_cast<uint16_t>(bs.getBits(12));
214 }
215 }
216 }
217}
218
220 uint32_t size) const {
221 // FIXME: most of this logic should be in UncompressedDecompressor,
222 // one way or another.
223
224 if (size == h * ((w * 12 / 8) + ((w + 2) / 10))) {
225 // 12-bit packed 'with control' raw
227 (12 * w / 8) + ((w + 2) / 10), 12,
229 mRaw->createData();
230 u.decode12BitRawWithControl<Endianness::little>();
231 return true;
232 }
233
234 iPoint2D dimensions(w, h);
235 iPoint2D pos(0, 0);
236 if (size == w * h * 12 / 8) { // We're in a 12-bit packed raw
237 UncompressedDecompressor u(s, mRaw, iRectangle2D(pos, dimensions),
238 w * 12 / 8, 12, BitOrder::MSB32);
239 mRaw->createData();
240 u.readUncompressedRaw();
241 return true;
242 }
243
244 if (size == w * h * 2) { // We're in an unpacked raw
245 // FIXME: seems fishy
246 if (s.getByteOrder() == getHostEndianness()) {
248 16 * w / 8, 16, BitOrder::LSB);
249 mRaw->createData();
250 u.decode12BitRawUnpackedLeftAligned<Endianness::little>();
251 } else {
253 16 * w / 8, 16, BitOrder::MSB);
254 mRaw->createData();
255 u.decode12BitRawUnpackedLeftAligned<Endianness::big>();
256 }
257 return true;
258 }
259
260 if (size > w * h * 3 / 2) {
261 // We're in one of those weird interlaced packed raws
262 decodeUncompressedInterleaved(s, w, h, size);
263 return true;
264 }
265
266 // Does not appear to be uncomporessed. Maybe it's compressed?
267 return false;
268}
269
271 if (!mRootIFD->hasEntryRecursive(TiffTag::EXIFCFAPATTERN))
272 ThrowRDE("No EXIFCFAPATTERN entry found!");
273
274 const TiffEntry* CFA = mRootIFD->getEntryRecursive(TiffTag::EXIFCFAPATTERN);
275 if (CFA->type != TiffDataType::UNDEFINED || CFA->count != 8) {
276 ThrowRDE("Bad EXIFCFAPATTERN entry (type %u, count %u).",
277 static_cast<unsigned>(CFA->type), CFA->count);
278 }
279
280 iPoint2D cfaSize(CFA->getU16(0), CFA->getU16(1));
281 if (cfaSize != iPoint2D{2, 2})
282 ThrowRDE("Bad CFA size: (%i, %i)", cfaSize.x, cfaSize.y);
283
284 mRaw->cfa.setSize(cfaSize);
285
286 auto int2enum = [](uint8_t i) {
287 switch (i) {
288 using enum CFAColor;
289 case 0:
290 return RED;
291 case 1:
292 return GREEN;
293 case 2:
294 return BLUE;
295 default:
296 ThrowRDE("Unexpected CFA color: %u", i);
297 }
298 };
299
300 for (int y = 0; y < cfaSize.y; y++) {
301 for (int x = 0; x < cfaSize.x; x++) {
302 uint8_t c1 = CFA->getByte(4 + x + (y * cfaSize.x));
303 CFAColor c2 = int2enum(c1);
304 mRaw->cfa.setColorAt(iPoint2D(x, y), c2);
305 }
306 }
307}
308
310 mRaw->whitePoint = (1U << 12) - 1;
311
312 int iso = 0;
313
314 if (mRootIFD->hasEntryRecursive(TiffTag::ISOSPEEDRATINGS))
315 iso = mRootIFD->getEntryRecursive(TiffTag::ISOSPEEDRATINGS)->getU32();
316
317 parseCFA();
318
319 setMetaData(meta, "", iso);
320
321 if (mRootIFD->hasEntryRecursive(TiffTag::OLYMPUSREDMULTIPLIER) &&
322 mRootIFD->hasEntryRecursive(TiffTag::OLYMPUSBLUEMULTIPLIER)) {
323 std::array<float, 4> wbCoeffs = {};
324 wbCoeffs[0] = static_cast<float>(
325 mRootIFD->getEntryRecursive(TiffTag::OLYMPUSREDMULTIPLIER)->getU16());
326 wbCoeffs[1] = 256.0F;
327 wbCoeffs[2] = static_cast<float>(
328 mRootIFD->getEntryRecursive(TiffTag::OLYMPUSBLUEMULTIPLIER)->getU16());
329 mRaw->metadata.wbCoeffs = wbCoeffs;
330 } else if (mRootIFD->hasEntryRecursive(TiffTag::OLYMPUSIMAGEPROCESSING)) {
331 // Newer cameras process the Image Processing SubIFD in the makernote
332 const TiffEntry* img_entry =
333 mRootIFD->getEntryRecursive(TiffTag::OLYMPUSIMAGEPROCESSING);
334 // get makernote ifd with containing Buffer
336
337 TiffRootIFD image_processing(nullptr, &ifds, img_entry->getRootIfdData(),
338 img_entry->getU32());
339
340 // Get the WB
341 if (image_processing.hasEntry(static_cast<TiffTag>(0x0100))) {
342 const TiffEntry* wb =
343 image_processing.getEntry(static_cast<TiffTag>(0x0100));
344 if (wb->count == 2 || wb->count == 4) {
345 std::array<float, 4> wbCoeffs = {};
346 wbCoeffs[0] = wb->getFloat(0);
347 wbCoeffs[1] = 256.0F;
348 wbCoeffs[2] = wb->getFloat(1);
349 mRaw->metadata.wbCoeffs = wbCoeffs;
350 }
351 }
352
353 // Get the black levels
354 if (image_processing.hasEntry(static_cast<TiffTag>(0x0600))) {
355 const TiffEntry* blackEntry =
356 image_processing.getEntry(static_cast<TiffTag>(0x0600));
357 // Order is assumed to be RGGB
358 if (blackEntry->count == 4) {
359 mRaw->blackLevelSeparate =
360 Array2DRef(mRaw->blackLevelSeparateStorage.data(), 2, 2);
361 auto blackLevelSeparate1D =
362 *mRaw->blackLevelSeparate->getAsArray1DRef();
363 for (int i = 0; i < 4; i++) {
364 auto c = mRaw->cfa.getColorAt(i & 1, i >> 1);
365 int j;
366 switch (c) {
367 using enum CFAColor;
368 case RED:
369 j = 0;
370 break;
371 case GREEN:
372 j = i < 2 ? 1 : 2;
373 break;
374 case BLUE:
375 j = 3;
376 break;
377 default:
378 ThrowRDE("Unexpected CFA color: %u", static_cast<unsigned>(c));
379 }
380
381 blackLevelSeparate1D(i) = blackEntry->getU16(j);
382 }
383 // Adjust whitelevel based on the read black (we assume the dynamic
384 // range is the same)
385 mRaw->whitePoint =
386 *mRaw->whitePoint - (mRaw->blackLevel - blackLevelSeparate1D(0));
387 if (getBitsPerPixel() == 14) {
388 mRaw->whitePoint = *mRaw->whitePoint * 4;
389 mRaw->blackLevel = mRaw->blackLevel * 4;
390 for (int i = 0; i < 4; i++) {
391 blackLevelSeparate1D(i) = blackLevelSeparate1D(i) * 4;
392 }
393 }
394 }
395 }
396 }
397}
398
399} // namespace rawspeed
#define s
#define ThrowRDE(...)
assert(dim.area() >=area)
dim y
Definition Common.cpp:51
dim x
Definition Common.cpp:50
void setMetaData(const CameraMetaData *meta, const TiffID &id, const std::string &mode, int iso_speed)
uint32_t getBits(int nbits)
size_type RAWSPEED_READONLY getSize() const
Definition Buffer.h:115
void setPosition(size_type newPos)
Definition ByteStream.h:83
ByteStream getStream(size_type size_)
Definition ByteStream.h:119
void skipBytes(size_type nbytes)
Definition ByteStream.h:130
void decompress(const ByteStream &input) const
RawImage decodeRawInternal() override
void decodeUncompressedInterleaved(ByteStream s, uint32_t w, uint32_t h, uint32_t size) const
void decodeMetaDataInternal(const CameraMetaData *meta) override
void parseCFA() const
ByteStream handleSlices() const
bool decodeUncompressed(ByteStream s, uint32_t w, uint32_t h, uint32_t size) const
int getBitsPerPixel() const
static bool isAppropriateDecoder(const TiffRootIFD *rootIFD, Buffer file)
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
TiffDataType type
Definition TiffEntry.h:83
uint8_t getByte(uint32_t index=0) const
bool RAWSPEED_READONLY hasEntry(TiffTag tag) const
Definition TiffIFD.h:119
TiffEntry * getEntry(TiffTag tag) const
Definition TiffIFD.cpp:313
TiffID getID() const
Definition TiffIFD.cpp:325
value_type x
Definition Point.h:102
value_type y
Definition Point.h:103
constexpr uint64_t RAWSPEED_READNONE roundUpDivisionSafe(uint64_t value, uint64_t div)
Definition Common.h:145
constexpr uint64_t RAWSPEED_READNONE roundUp(uint64_t value, uint64_t multiple)
Definition Common.h:134
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
std::string make
Definition TiffIFD.h:134