RawSpeed
fast raw decoding library
Loading...
Searching...
No Matches
FujiDecompressor.cpp
Go to the documentation of this file.
1/*
2 RawSpeed - RAW file decoder.
3
4 Copyright (C) 2016 Alexey Danilchenko
5 Copyright (C) 2016 Alex Tutubalin
6 Copyright (C) 2017 Uwe Müssel
7 Copyright (C) 2017 Roman Lebedev
8
9 This library is free software; you can redistribute it and/or
10 modify it under the terms of the GNU Lesser General Public
11 License as published by the Free Software Foundation; either
12 version 2.1 of the License, or (at your option) any later version.
13
14 This library is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 Lesser General Public License for more details.
18
19 You should have received a copy of the GNU Lesser General Public
20 License along with this library; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22*/
23
24#include "rawspeedconfig.h"
26#include "MemorySanitizer.h"
27#include "adt/Array1DRef.h"
28#include "adt/Array2DRef.h"
29#include "adt/Casts.h"
31#include "adt/Invariant.h"
32#include "adt/Optional.h"
33#include "adt/Point.h"
35#include "common/BayerPhase.h"
36#include "common/Common.h"
37#include "common/RawImage.h"
38#include "common/XTransPhase.h"
40#include "io/Buffer.h"
41#include "io/ByteStream.h"
42#include "io/Endianness.h"
44#include <algorithm>
45#include <array>
46#include <bit>
47#include <cassert>
48#include <cstdint>
49#include <cstdlib>
50#include <cstring>
51#include <string>
52#include <utility>
53#include <vector>
54
55namespace rawspeed {
56
57namespace {
58
59struct BayerTag;
60struct XTransTag;
61
62template <typename T> constexpr iPoint2D MCU;
63
64template <> constexpr iPoint2D MCU<BayerTag> = {2, 2};
65
66template <> constexpr iPoint2D MCU<XTransTag> = {6, 6};
67
68struct int_pair final {
69 int value1;
70 int value2;
71};
72
94
97
98 [[nodiscard]] int8_t qTableLookup(int cur_val) const;
99
100 std::vector<int8_t> q_table; /* quantization table */
101 std::array<int, 5> q_point; /* quantization points */
108};
109
110struct FujiStrip final {
111 // part of which 'image' this block is
113
114 // which strip is this, 0 .. h.blocks_in_row-1
115 const int n;
116
117 // the compressed data of this strip
119
120 FujiStrip() = delete;
121 FujiStrip(const FujiStrip&) = delete;
122 FujiStrip(FujiStrip&&) noexcept = delete;
123 FujiStrip& operator=(const FujiStrip&) noexcept = delete;
124 FujiStrip& operator=(FujiStrip&&) noexcept = delete;
125
126 FujiStrip(const FujiDecompressor::FujiHeader& h_, int block,
127 Array1DRef<const uint8_t> input_)
128 : h(h_), n(block), input(input_) {
129 invariant(n >= 0 && n < h.blocks_in_row);
130 }
131
132 // each strip's line corresponds to 6 output lines.
133 static int RAWSPEED_READONLY lineHeight() { return 6; }
134
135 // how many vertical lines does this block encode?
136 [[nodiscard]] int RAWSPEED_READONLY height() const { return h.total_lines; }
137
138 // how many horizontal pixels does this block encode?
139 [[nodiscard]] int RAWSPEED_READONLY width() const {
140 // if this is not the last block, we are good.
141 if ((n + 1) != h.blocks_in_row)
142 return h.block_size;
143
144 // ok, this is the last block...
145
146 invariant(h.block_size * h.blocks_in_row >= h.raw_width);
147 return h.raw_width - offsetX();
148 }
149
150 // how many horizontal pixels does this block encode?
151 [[nodiscard]] iPoint2D numMCUs(iPoint2D MCU) const {
152 invariant(width() % MCU.x == 0);
153 invariant(lineHeight() % MCU.y == 0);
154 return {width() / MCU.x, lineHeight() / MCU.y};
155 }
156
157 // where vertically does this block start?
158 [[nodiscard]] int offsetY(int line = 0) const {
159 (void)height(); // A note for NDEBUG builds that *this is used.
160 invariant(line >= 0 && line < height());
161 return lineHeight() * line;
162 }
163
164 // where horizontally does this block start?
165 [[nodiscard]] int offsetX() const { return h.block_size * n; }
166};
167
168int8_t GetGradient(const fuji_compressed_params& p, int cur_val) {
169 cur_val -= p.q_point[4];
170
171 int abs_cur_val = std::abs(cur_val);
172
173 int grad = 0;
174 if (abs_cur_val > 0)
175 grad = 1;
176 if (abs_cur_val >= p.q_point[1])
177 grad = 2;
178 if (abs_cur_val >= p.q_point[2])
179 grad = 3;
180 if (abs_cur_val >= p.q_point[3])
181 grad = 4;
182
183 if (cur_val < 0)
184 grad *= -1;
185
186 return implicit_cast<int8_t>(grad);
187}
188
191 if ((h.block_size % 3 && h.raw_type == 16) ||
192 (h.block_size & 1 && h.raw_type == 0)) {
193 ThrowRDE("fuji_block_checks");
194 }
195
196 if (h.raw_type == 16) {
197 line_width = (h.block_size * 2) / 3;
198 } else {
199 line_width = h.block_size >> 1;
200 }
201
202 q_point[0] = 0;
203 q_point[1] = 0x12;
204 q_point[2] = 0x43;
205 q_point[3] = 0x114;
206 q_point[4] = (1 << h.raw_bits) - 1;
207 min_value = 0x40;
208
209 // populting gradients
210 const int NumGradientTableEntries = 2 * (1 << h.raw_bits);
211 q_table.resize(NumGradientTableEntries);
212 for (int i = 0; i != NumGradientTableEntries; ++i) {
213 q_table[i] = GetGradient(*this, i);
214 }
215
216 if (q_point[4] == 0xFFFF) { // (1 << h.raw_bits) - 1
217 total_values = 0x10000; // 1 << h.raw_bits
218 raw_bits = 16; // h.raw_bits
219 max_bits = 64; // h.raw_bits * (64 / h.raw_bits)
220 maxDiff = 1024; // 1 << (h.raw_bits - 6)
221 } else if (q_point[4] == 0x3FFF) {
222 total_values = 0x4000;
223 raw_bits = 14;
224 max_bits = 56;
225 maxDiff = 256;
226 } else if (q_point[4] == 0xFFF) {
227 total_values = 4096;
228 raw_bits = 12;
229 max_bits = 48; // out-of-family, there's greater pattern at play.
230 maxDiff = 64;
231
232 ThrowRDE("Aha, finally, a 12-bit compressed RAF! Please consider providing "
233 "samples on <https://raw.pixls.us/>, thanks!");
234 } else {
235 ThrowRDE("FUJI q_point");
236 }
237}
238
239int8_t fuji_compressed_params::qTableLookup(int cur_val) const {
240 return q_table[cur_val];
241}
242
247
251
252 void reset();
253
255
256 // tables of gradients
257 std::array<std::array<int_pair, 41>, 3> grad_even;
258 std::array<std::array<int_pair, 41>, 3> grad_odd;
259
260 std::vector<uint16_t> linealloc;
262
263 void fuji_decode_strip(const FujiStrip& strip);
264
265 template <typename Tag, typename T>
266 void copy_line(const FujiStrip& strip, int cur_line, T idx) const;
267
268 void copy_line_to_xtrans(const FujiStrip& strip, int cur_line) const;
269 void copy_line_to_bayer(const FujiStrip& strip, int cur_line) const;
270
271 static int fuji_zerobits(BitStreamerMSB& pump);
272 static int bitDiff(int value1, int value2);
273
274 [[nodiscard]] int fuji_decode_sample(int grad, int interp_val,
275 std::array<int_pair, 41>& grads);
276 [[nodiscard]] int fuji_decode_sample_even(xt_lines c, int col,
277 std::array<int_pair, 41>& grads);
278 [[nodiscard]] int fuji_decode_sample_odd(xt_lines c, int col,
279 std::array<int_pair, 41>& grads);
280
281 [[nodiscard]] int fuji_quant_gradient(int v1, int v2) const;
282
283 [[nodiscard]] std::pair<int, int>
285 [[nodiscard]] std::pair<int, int>
287 [[nodiscard]] int fuji_decode_interpolation_even(xt_lines c, int col) const;
288
289 void fuji_extend_generic(int start, int end) const;
290 void fuji_extend_red() const;
291 void fuji_extend_green() const;
292 void fuji_extend_blue() const;
293
294 template <typename T> void fuji_decode_block(T func_even, int cur_line);
295 void xtrans_decode_block(int cur_line);
296 void fuji_bayer_decode_block(int cur_line);
297};
298
301 const fuji_compressed_params& common_info_)
302 : img(img_), header(header_), common_info(common_info_),
303 linealloc(ltotal * (common_info.line_width + 2), 0),
304 lines(&linealloc[0], common_info.line_width + 2, ltotal) {}
305
308
309 // Zero-initialize first two (read-only, carry-in) lines of each color,
310 // including first and last helper columns of the second row.
311 // This is needed for correctness.
312 for (xt_lines color : {R0, G0, B0}) {
313 memset(&lines(color, 0), 0, 2 * sizeof(uint16_t) * lines.width());
314
315 // On the first row, we don't need to zero-init helper columns.
316 MSan::Allocated(lines(color, 0));
317 MSan::Allocated(lines(color, lines.width() - 1));
318 }
319
320 // And the first (real, uninitialized) line of each color gets the content
321 // of the last helper column from the last decoded sample of previous
322 // line of that color.
323 // Again, this is needed for correctness.
324 for (xt_lines color : {R2, G2, B2})
325 lines(color, lines.width() - 1) = lines(color - 1, lines.width() - 2);
326
327 for (int j = 0; j < 3; j++) {
328 for (int i = 0; i < 41; i++) {
329 grad_even[j][i].value1 = common_info.maxDiff;
330 grad_even[j][i].value2 = 1;
331 grad_odd[j][i].value1 = common_info.maxDiff;
332 grad_odd[j][i].value2 = 1;
333 }
334 }
335}
336
337template <typename Tag, typename T>
338void fuji_compressed_block::copy_line(const FujiStrip& strip, int cur_line,
339 T idx) const {
340 std::array<CFAColor, MCU<Tag>.x * MCU<Tag>.y> CFAData;
341 if constexpr (std::is_same_v<XTransTag, Tag>)
342 CFAData = getAsCFAColors(XTransPhase(0, 0));
343 else if constexpr (std::is_same_v<BayerTag, Tag>)
345 else
346 __builtin_unreachable();
347 const Array2DRef<const CFAColor> CFA(CFAData.data(), MCU<Tag>.x, MCU<Tag>.y);
348
349 iPoint2D MCUIdx;
350 assert(MCU<Tag> == strip.h.MCU);
351 const iPoint2D NumMCUs = strip.numMCUs(MCU<Tag>);
352 for (MCUIdx.x = 0; MCUIdx.x != NumMCUs.x; ++MCUIdx.x) {
353 for (MCUIdx.y = 0; MCUIdx.y != NumMCUs.y; ++MCUIdx.y) {
354 const auto out =
355 CroppedArray2DRef(img, strip.offsetX() + (MCU<Tag>.x * MCUIdx.x),
356 strip.offsetY(cur_line) + (MCU<Tag>.y * MCUIdx.y),
357 MCU<Tag>.x, MCU<Tag>.y);
358 for (int MCURow = 0; MCURow != MCU<Tag>.y; ++MCURow) {
359 for (int MCUCol = 0; MCUCol != MCU<Tag>.x; ++MCUCol) {
360 int imgRow = (MCU<Tag>.y * MCUIdx.y) + MCURow;
361 int imgCol = (MCU<Tag>.x * MCUIdx.x) + MCUCol;
362
363 int row;
364
365 switch (CFA(MCURow, MCUCol)) {
366 using enum CFAColor;
367 case RED: // red
368 row = R2 + (imgRow >> 1);
369 break;
370
371 case GREEN: // green
372 row = G2 + imgRow;
373 break;
374
375 case BLUE: // blue
376 row = B2 + (imgRow >> 1);
377 break;
378
379 default:
380 __builtin_unreachable();
381 }
382
383 out(MCURow, MCUCol) = lines(row, 1 + idx(imgCol));
384 }
385 }
386 }
387 }
388}
389
391 int cur_line) const {
392 auto index = [](int imgCol) {
393 return (((imgCol * 2 / 3) & 0x7FFFFFFE) | ((imgCol % 3) & 1)) +
394 ((imgCol % 3) >> 1);
395 };
396
397 copy_line<XTransTag>(strip, cur_line, index);
398}
399
401 int cur_line) const {
402 auto index = [](int imgCol) { return imgCol >> 1; };
403
404 copy_line<BayerTag>(strip, cur_line, index);
405}
406
408 int count = 0;
409
410 // Count-and-skip all the leading `0`s.
411 while (true) {
412 constexpr int batchSize = 32;
413 pump.fill(batchSize);
414 uint32_t batch = pump.peekBitsNoFill(batchSize);
415 int numZerosInThisBatch = std::countl_zero(batch);
416 count += numZerosInThisBatch;
417 bool allZeroes = numZerosInThisBatch == batchSize;
418 int numBitsToSkip = numZerosInThisBatch;
419 if (!allZeroes)
420 numBitsToSkip += 1; // Also skip the first `1`.
421 pump.skipBitsNoFill(numBitsToSkip);
422 if (!allZeroes)
423 break; // We're done!
424 }
425
426 return count;
427}
428
429// Given two non-negative numbers, how many times must the second number
430// be multiplied by 2, for it to become not smaller than the first number?
431// We are operating on arithmetical numbers here, without overflows.
432int RAWSPEED_READNONE fuji_compressed_block::bitDiff(int value1, int value2) {
433 invariant(value1 >= 0);
434 invariant(value2 > 0);
435
436 int lz1 = std::countl_zero(static_cast<unsigned>(value1));
437 int lz2 = std::countl_zero(static_cast<unsigned>(value2));
438 int decBits = std::max(lz2 - lz1, 0);
439 if ((value2 << decBits) < value1)
440 ++decBits;
441 return std::min(decBits, 15);
442}
443
444__attribute__((always_inline)) inline int
445fuji_compressed_block::fuji_decode_sample(int grad, int interp_val,
446 std::array<int_pair, 41>& grads) {
447 int gradient = std::abs(grad);
448
449 int sampleBits = fuji_zerobits(*pump);
450
451 int codeBits;
452 int codeDelta;
453 if (sampleBits < common_info.max_bits - common_info.raw_bits - 1) {
454 codeBits = bitDiff(grads[gradient].value1, grads[gradient].value2);
455 codeDelta = sampleBits << codeBits;
456 } else {
457 codeBits = common_info.raw_bits;
458 codeDelta = 1;
459 }
460
461 int code = 0;
462 pump->fill(32);
463 if (codeBits)
464 code = pump->getBitsNoFill(codeBits);
465 code += codeDelta;
466
467 if (code < 0 || code >= common_info.total_values) {
468 ThrowRDE("fuji_decode_sample");
469 }
470
471 if (code & 1) {
472 code = -1 - code / 2;
473 } else {
474 code /= 2;
475 }
476
477 grads[gradient].value1 += std::abs(code);
478
479 if (grads[gradient].value2 == common_info.min_value) {
480 grads[gradient].value1 >>= 1;
481 grads[gradient].value2 >>= 1;
482 }
483
484 grads[gradient].value2++;
485
486 if (grad < 0) {
487 interp_val -= code;
488 } else {
489 interp_val += code;
490 }
491
492 if (interp_val < 0) {
493 interp_val += common_info.total_values;
494 } else if (interp_val > common_info.q_point[4]) {
495 interp_val -= common_info.total_values;
496 }
497
498 if (interp_val < 0)
499 return 0;
500
501 return std::min(interp_val, common_info.q_point[4]);
502}
503
504__attribute__((always_inline)) inline int
505fuji_compressed_block::fuji_quant_gradient(int v1, int v2) const {
506 const auto& ci = common_info;
507 return (9 * ci.qTableLookup(ci.q_point[4] + v1)) +
508 ci.qTableLookup(ci.q_point[4] + v2);
509}
510
511__attribute__((always_inline)) inline std::pair<int, int>
513 int col) const {
514 int Rb = lines(c - 1, 1 + (2 * (col + 0)) + 0);
515 int Rc = lines(c - 1, 1 + (2 * (col - 1)) + 1);
516 int Rd = lines(c - 1, 1 + (2 * (col + 0)) + 1);
517 int Rf = lines(c - 2, 1 + (2 * (col + 0)) + 0);
518
519 int diffRcRb = std::abs(Rc - Rb);
520 int diffRfRb = std::abs(Rf - Rb);
521 int diffRdRb = std::abs(Rd - Rb);
522
523 int Term0 = 2 * Rb;
524 int Term1;
525 int Term2;
526 if (diffRcRb > std::max(diffRfRb, diffRdRb)) {
527 Term1 = Rf;
528 Term2 = Rd;
529 } else {
530 if (diffRdRb > std::max(diffRcRb, diffRfRb)) {
531 Term1 = Rf;
532 } else {
533 Term1 = Rd;
534 }
535 Term2 = Rc;
536 }
537
538 int interp_val = Term0 + Term1 + Term2;
539 interp_val >>= 2;
540
541 int grad = fuji_quant_gradient(Rb - Rf, Rc - Rb);
542 return {grad, interp_val};
543}
544
545__attribute__((always_inline)) inline std::pair<int, int>
547 int col) const {
548 int Ra = lines(c + 0, 1 + (2 * (col + 0)) + 0);
549 int Rb = lines(c - 1, 1 + (2 * (col + 0)) + 1);
550 int Rc = lines(c - 1, 1 + (2 * (col + 0)) + 0);
551 int Rd = lines(c - 1, 1 + (2 * (col + 1)) + 0);
552 int Rg = lines(c + 0, 1 + (2 * (col + 1)) + 0);
553
554 int interp_val = (Ra + Rg);
555 if (auto [min, max] = std::minmax(Rc, Rd); Rb < min || Rb > max) {
556 interp_val += 2 * Rb;
557 interp_val >>= 1;
558 }
559 interp_val >>= 1;
560
561 int grad = fuji_quant_gradient(Rb - Rc, Rc - Ra);
562 return {grad, interp_val};
563}
564
565__attribute__((always_inline)) inline int
567 xt_lines c, int col, std::array<int_pair, 41>& grads) {
568 auto [grad, interp_val] = fuji_decode_interpolation_even_inner(c, col);
569 return fuji_decode_sample(grad, interp_val, grads);
570}
571
572__attribute__((always_inline)) inline int
574 std::array<int_pair, 41>& grads) {
575 auto [grad, interp_val] = fuji_decode_interpolation_odd_inner(c, col);
576 return fuji_decode_sample(grad, interp_val, grads);
577}
578
579__attribute__((always_inline)) inline int
581 int col) const {
582 auto [grad, interp_val] = fuji_decode_interpolation_even_inner(c, col);
583 return interp_val;
584}
585
586void fuji_compressed_block::fuji_extend_generic(int start, int end) const {
587 for (int i = start; i <= end; i++) {
588 lines(i, 0) = lines(i - 1, 1);
589 lines(i, lines.width() - 1) = lines(i - 1, lines.width() - 2);
590 }
591}
592
595}
596
599}
600
603}
604
605template <typename T>
606__attribute__((always_inline)) inline void
608 [[maybe_unused]] int cur_line) {
609 invariant(common_info.line_width % 2 == 0);
610 const int line_width = common_info.line_width / 2;
611
612 auto pass = [this, &line_width, func_even](std::array<xt_lines, 2> c,
613 int row) {
614 int grad = row % 3;
615
616 struct ColorPos final {
617 int even = 0;
618 int odd = 0;
619 };
620
621 std::array<ColorPos, 2> pos;
622 for (int i = 0; i != line_width + 4; ++i) {
623 if (i < line_width) {
624 for (int comp = 0; comp != 2; comp++) {
625 int& col = pos[comp].even;
626 int sample = func_even(c[comp], col, grad_even[grad], row, i, comp);
627 lines(c[comp], 1 + (2 * col) + 0) = implicit_cast<uint16_t>(sample);
628 ++col;
629 }
630 }
631
632 if (i >= 4) {
633 for (int comp = 0; comp != 2; comp++) {
634 int& col = pos[comp].odd;
635 int sample = fuji_decode_sample_odd(c[comp], col, grad_odd[grad]);
636 lines(c[comp], 1 + (2 * col) + 1) = implicit_cast<uint16_t>(sample);
637 ++col;
638 }
639 }
640 }
641 };
642
643 using Tag = BayerTag;
644 const std::array<CFAColor, MCU<Tag>.x * MCU<Tag>.y> CFAData =
646 const Array2DRef<const CFAColor> CFA(CFAData.data(), MCU<Tag>.x, MCU<Tag>.y);
647
648 std::array<int, 3> PerColorCounter;
649 std::fill(PerColorCounter.begin(), PerColorCounter.end(), 0);
650 auto ColorCounter = [&PerColorCounter](CFAColor c) -> int& {
651 switch (c) {
652 using enum CFAColor;
653 case RED:
654 case GREEN:
655 case BLUE:
656 return PerColorCounter[static_cast<uint8_t>(c)];
657 default:
658 __builtin_unreachable();
659 }
660 };
661
662 auto CurLineForColor = [&ColorCounter](CFAColor c) {
663 xt_lines res;
664 switch (c) {
665 using enum CFAColor;
666 case RED:
667 res = R2;
668 break;
669 case GREEN:
670 res = G2;
671 break;
672 case BLUE:
673 res = B2;
674 break;
675 default:
676 __builtin_unreachable();
677 }
678 int& off = ColorCounter(c);
679 res = static_cast<xt_lines>(res + off);
680 ++off;
681 return res;
682 };
683
684 for (int row = 0; row != 6; ++row) {
685 CFAColor c0 = CFA(row % CFA.height(), /*col=*/0);
686 CFAColor c1 = CFA(row % CFA.height(), /*col=*/1);
687 pass({CurLineForColor(c0), CurLineForColor(c1)}, row);
688 for (CFAColor c : {c0, c1}) {
689 switch (c) {
690 case CFAColor::RED:
692 break;
693 case CFAColor::GREEN:
695 break;
696 case CFAColor::BLUE:
698 break;
699 default:
700 __builtin_unreachable();
701 }
702 }
703 }
704}
705
708 [this](xt_lines c, int col, std::array<int_pair, 41>& grads, int row,
709 int i, int comp) {
710 if ((comp == 0 && (row == 0 || (row == 2 && i % 2 == 0) ||
711 (row == 4 && i % 2 != 0) || row == 5)) ||
712 (comp == 1 && (row == 1 || row == 2 || (row == 3 && i % 2 != 0) ||
713 (row == 5 && i % 2 == 0))))
714 return fuji_decode_interpolation_even(c, col);
715 invariant((comp == 0 && (row == 1 || (row == 2 && i % 2 != 0) ||
716 row == 3 || (row == 4 && i % 2 == 0))) ||
717 (comp == 1 && (row == 0 || (row == 3 && i % 2 == 0) ||
718 row == 4 || (row == 5 && i % 2 != 0))));
719 return fuji_decode_sample_even(c, col, grads);
720 },
721 cur_line);
722}
723
726 [this](xt_lines c, int col, std::array<int_pair, 41>& grads,
727 [[maybe_unused]] int row, [[maybe_unused]] int i,
728 [[maybe_unused]] int comp) {
729 return fuji_decode_sample_even(c, col, grads);
730 },
731 cur_line);
732}
733
735 const unsigned line_size = sizeof(uint16_t) * (common_info.line_width + 2);
736
737 struct i_pair final {
738 int a;
739 int b;
740 };
741
742 const std::array<i_pair, 3> colors = {{{R0, 5}, {G0, 8}, {B0, 5}}};
743
744 for (int cur_line = 0; cur_line < strip.height(); cur_line++) {
745 if (header.raw_type == 16) {
746 xtrans_decode_block(cur_line);
747 } else {
748 fuji_bayer_decode_block(cur_line);
749 }
750
751 if (header.raw_type == 16) {
752 copy_line_to_xtrans(strip, cur_line);
753 } else {
754 copy_line_to_bayer(strip, cur_line);
755 }
756
757 if (cur_line + 1 == strip.height())
758 break;
759
760 // Last two lines of each color become the first two lines.
761 for (auto i : colors) {
762 memcpy(&lines(i.a, 0), &lines(i.a + i.b - 2, 0), 2 * line_size);
763 }
764
765 for (auto i : colors) {
766 const auto out = CroppedArray2DRef(
767 lines, /*offsetCols=*/0, /*offsetRows=*/i.a + 2,
768 /*croppedWidth=*/lines.width(), /*croppedHeight=*/i.b - 2);
769
770 // All other lines of each color become uninitialized.
771 MSan::Allocated(out);
772
773 // And the first (real, uninitialized) line of each color gets the content
774 // of the last helper column from the last decoded sample of previous
775 // line of that color.
776 lines(i.a + 2, lines.width() - 1) = lines(i.a + 2 - 1, lines.width() - 2);
777 }
778 }
779}
780
784
786
788
789 void decompressThread() const noexcept;
790
791public:
793 Array1DRef<const Array1DRef<const uint8_t>> strips,
794 const FujiDecompressor::FujiHeader& h);
795
796 void decompress();
797};
798
800 RawImage mRaw_, Array1DRef<const Array1DRef<const uint8_t>> strips_,
801 const FujiDecompressor::FujiHeader& h_)
802 : mRaw(std::move(mRaw_)), strips(strips_), header(h_), common_info(header) {
803}
804
806 fuji_compressed_block block_info(mRaw->getU16DataAsUncroppedArray2DRef(),
808
809#ifdef HAVE_OPENMP
810#pragma omp for schedule(static)
811#endif
812 for (int block = 0; block < header.blocks_in_row; ++block) {
813 try {
814 FujiStrip strip(header, block, strips(block));
815 block_info.reset();
816 block_info.pump = BitStreamerMSB(strip.input);
817 block_info.fuji_decode_strip(strip);
818 } catch (const RawspeedException& err) {
819 // Propagate the exception out of OpenMP magic.
820 mRaw->setError(err.what());
821 } catch (...) {
822 // We should not get any other exception type here.
823 __builtin_unreachable();
824 }
825 }
826}
827
829#ifdef HAVE_OPENMP
830#pragma omp parallel default(none) \
831 num_threads(rawspeed_get_number_of_processor_cores())
832#endif
834
835 std::string firstErr;
836 if (mRaw->isTooManyErrors(1, &firstErr)) {
837 ThrowRDE("Too many errors encountered. Giving up. First Error:\n%s",
838 firstErr.c_str());
839 }
840}
841
842} // namespace
843
845 : mRaw(std::move(img)), input(input_) {
846 if (mRaw->getCpp() != 1 || mRaw->getDataType() != RawImageType::UINT16 ||
847 mRaw->getBpp() != sizeof(uint16_t))
848 ThrowRDE("Unexpected component count / data type");
849
850 input.setByteOrder(Endianness::big);
851
853 if (!header)
854 ThrowRDE("compressed RAF header check");
855
856 if (mRaw->dim != iPoint2D(header.raw_width, header.raw_height))
857 ThrowRDE("RAF header specifies different dimensions!");
858
859 if (12 == header.raw_bits) {
860 ThrowRDE("Aha, finally, a 12-bit compressed RAF! Please consider providing "
861 "samples on <https://raw.pixls.us/>, thanks!");
862 }
863
864 if (mRaw->cfa.getSize() == iPoint2D(6, 6)) {
866 if (!p)
867 ThrowRDE("Invalid X-Trans CFA");
868 if (p != iPoint2D(0, 0))
869 ThrowRDE("Unexpected X-Trans phase: {%i,%i}. Please file a bug!", p->x,
870 p->y);
871 } else if (mRaw->cfa.getSize() == iPoint2D(2, 2)) {
873 if (!p)
874 ThrowRDE("Invalid Bayer CFA");
875 if (p != BayerPhase::RGGB)
876 ThrowRDE("Unexpected Bayer phase: %i. Please file a bug!",
877 static_cast<int>(*p));
878 } else {
879 ThrowRDE("Unexpected CFA size");
880 }
881
882 // read block sizes
883 std::vector<uint32_t> block_sizes;
884 block_sizes.resize(header.blocks_in_row);
885 for (auto& block_size : block_sizes)
886 block_size = input.getU32();
887
888 // some padding?
889 if (const uint64_t raw_offset = sizeof(uint32_t) * header.blocks_in_row;
890 raw_offset & 0xC) {
891 const int padding = 0x10 - (raw_offset & 0xC);
892 input.skipBytes(padding);
893 }
894
895 // calculating raw block offsets
896 strips.reserve(header.blocks_in_row);
897
898 for (const auto& block_size : block_sizes)
899 strips.emplace_back(input.getStream(block_size).getAsArray1DRef());
900}
901
903 FujiDecompressorImpl impl(
904 mRaw,
907 header);
908 impl.decompress();
909}
910
912 : signature(bs.getU16()), version(bs.getByte()), raw_type(bs.getByte()),
913 raw_bits(bs.getByte()), raw_height(bs.getU16()),
914 raw_rounded_width(bs.getU16()), raw_width(bs.getU16()),
915 block_size(bs.getU16()), blocks_in_row(bs.getByte()),
916 total_lines(bs.getU16()),
917 MCU(raw_type == 16 ? ::rawspeed::MCU<XTransTag>
918 : ::rawspeed::MCU<BayerTag>) {}
919
920FujiDecompressor::FujiHeader::operator bool() const {
921 // general validation
922 const bool invalid =
923 (signature != 0x4953 || version != 1 || raw_height > 0x3000 ||
924 raw_height < FujiStrip::lineHeight() ||
925 raw_height % FujiStrip::lineHeight() || raw_width > 0x3000 ||
926 raw_width < 0x300 || raw_width % 24 || raw_rounded_width > 0x3000 ||
932 total_lines > 0x800 || total_lines == 0 ||
933 total_lines != raw_height / FujiStrip::lineHeight() ||
934 (raw_bits != 12 && raw_bits != 14 && raw_bits != 16) ||
935 (raw_type != 16 && raw_type != 0));
936
937 return !invalid;
938}
939
940} // namespace rawspeed
#define invariant(expr)
Definition Invariant.h:27
#define ThrowRDE(...)
assert(dim.area() >=area)
std::vector< Array1DRef< const uint8_t > > strips
FujiDecompressor(RawImage img, ByteStream input)
const Array1DRef< const Array1DRef< const uint8_t > > strips
FujiDecompressorImpl(RawImage mRaw, Array1DRef< const Array1DRef< const uint8_t > > strips, const FujiDecompressor::FujiHeader &h)
value_type x
Definition Point.h:102
value_type y
Definition Point.h:103
int8_t GetGradient(const fuji_compressed_params &p, int cur_val)
__attribute__((always_inline)) inline int fuji_compressed_block
constexpr uint64_t RAWSPEED_READNONE roundUpDivisionSafe(uint64_t value, uint64_t div)
Definition Common.h:145
constexpr RAWSPEED_READNONE Ttgt implicit_cast(Tsrc value)
Definition Casts.h:32
std::array< CFAColor, 4 > getAsCFAColors(BayerPhase p)
Definition BayerPhase.h:97
Optional< BayerPhase > getAsBayerPhase(const ColorFilterArray &CFA)
Definition BayerPhase.h:131
throw T(buf.data())
Array2DRef(Array1DRef< T > data, int width, int height, int pitch) -> Array2DRef< T >
CroppedArray2DRef(Array2DRef< T > base_, int offsetCols_, int offsetRows_, int croppedWidth_, int croppedHeight_) -> CroppedArray2DRef< typename Array2DRef< T >::value_type >
iPoint2D XTransPhase
Definition XTransPhase.h:34
Optional< XTransPhase > getAsXTransPhase(const ColorFilterArray &CFA)
Definition XTransPhase.h:73
static void Allocated(const void *addr, size_t size)
int fuji_decode_sample(int grad, int interp_val, std::array< int_pair, 41 > &grads)
std::pair< int, int > fuji_decode_interpolation_odd_inner(xt_lines c, int col) const
std::pair< int, int > fuji_decode_interpolation_even_inner(xt_lines c, int col) const
int fuji_decode_sample_even(xt_lines c, int col, std::array< int_pair, 41 > &grads)
void copy_line(const FujiStrip &strip, int cur_line, T idx) const
fuji_compressed_block(Array2DRef< uint16_t > img, const FujiDecompressor::FujiHeader &header, const fuji_compressed_params &common_info)
int fuji_decode_sample_odd(xt_lines c, int col, std::array< int_pair, 41 > &grads)