From 0d9bafdc887b4fe90c99ad0bff4687776468ebc0 Mon Sep 17 00:00:00 2001 From: Simone Gotti Date: Sat, 30 Mar 2024 17:05:11 +0100 Subject: [PATCH 1/2] dcraw: add panasonic v8 decoder. Port panasonic v8 decoder from libraw. * Extract data required for the decoder from the panasonic custom exif tags * Add panasonic v8 decoder --- rtengine/dcraw.cc | 125 ++++++++- rtengine/dcraw.h | 38 ++- rtengine/panasonic_decoders.cc | 486 ++++++++++++++++++++++++++++++++- 3 files changed, 630 insertions(+), 19 deletions(-) diff --git a/rtengine/dcraw.cc b/rtengine/dcraw.cc index 6a9674faa..2b2d36013 100644 --- a/rtengine/dcraw.cc +++ b/rtengine/dcraw.cc @@ -6458,16 +6458,123 @@ int CLASS parse_tiff_ifd (int base) FORC3 cam_mul[c] = get2(); break; case 45: - if (pana_raw && len == 1 && type == 3) - { - RT_pana_info.encoding = get2(); - } - break; + if (pana_raw && len == 1 && type == 3) { + RT_pana_info.encoding = get2(); + } + break; case 46: - if (type != 7 || fgetc(ifp) != 0xff || fgetc(ifp) != 0xd8) break; - thumb_offset = ftell(ifp) - 2; - thumb_length = len; - break; + if (type != 7 || fgetc(ifp) != 0xff || fgetc(ifp) != 0xd8) break; + thumb_offset = ftell(ifp) - 2; + thumb_length = len; + break; + case 57: + if (pana_raw && len == 26 && type == 7) { + ushort cnt = get2(); + if (cnt > 6) cnt = 6; + for (i = 0; i < cnt; i++) + RT_pana_info.v8tags.tag39[i] = get4(); + } + break; + case 58: + if (pana_raw && type == 7 && len == 26) { + ushort cnt = get2(); + if (cnt > 6) cnt = 6; + for (i = 0; i < cnt; i++) { + get2(); + RT_pana_info.v8tags.tag3A[i] = get2(); + } + } + break; + case 59: + if (pana_raw && type == 3 && len == 1) + RT_pana_info.v8tags.tag3B = get2(); + break; + case 60: + case 61: + case 62: + case 63: + if (pana_raw && type == 3 && len == 1) + RT_pana_info.v8tags.initial[tag - 0x3c] = get2(); + break; + case 64: + if (pana_raw && type == 7 && len == 70) { + ushort count = get2(); + if (count > 17) count = 17; + for (i = 0; i < count; i++) { + ushort v1 = get2(); + if (v1 > 16u) v1 = 16u; + RT_pana_info.v8tags.tag40a[i] = v1; + ushort v2 = get2(); + if (v2 > 0xfffu) v2 = 0xfffu; + RT_pana_info.v8tags.tag40b[i] = v2; + } + } + break; + case 65: + if (pana_raw && type == 7 && len == 36) { + ushort count = get2(); + if (count > 17) count = 17; + for (i = 0; i < count; i++) { + ushort v1 = get2(); + if (v1 > 0x40u) v1 = 64; + RT_pana_info.v8tags.tag41[i] = v1; + } + } + break; + case 66: + if (pana_raw && type == 3 && len == 1) { + ushort val = get2(); + if (val > 5) val = 5; + RT_pana_info.v8tags.stripe_count = val; + } + break; + case 67: + if (pana_raw && type == 3 && len == 1) { + ushort val = get2(); + if (val > 5) val = 5; + RT_pana_info.v8tags.tag43 = val; + } + break; + case 68: + if (pana_raw && type == 7 && len == 50) { + ushort count = get2(); + if (count > 5) count = 5; + for (i = 0; i < count; i++) + RT_pana_info.v8tags.stripe_offsets[i] = get4(); + } + break; + case 69: + if (pana_raw && type == 7 && len == 50) { + ushort count = get2(); + if (count > 5) count = 5; + for (i = 0; i < count; i++) + RT_pana_info.v8tags.stripe_left[i] = get4(); + } + break; + case 70: + if (pana_raw && type == 7 && len == 50) { + ushort count = get2(); + if (count > 5) count = 5; + for (i = 0; i < count; i++) + RT_pana_info.v8tags.stripe_compressed_size[i] = get4(); + } + break; + case 71: + if (pana_raw && type == 7 && len == 26) { + ushort count = get2(); + if (count > 5) count = 5; + for (i = 0; i < count; i++) + RT_pana_info.v8tags.stripe_width[i] = get2(); + } + break; + case 72: + if (pana_raw && type == 7 && len == 26) { + ushort count = get2(); + if (count > 5) count = 5; + for (i = 0; i < count; i++) + RT_pana_info.v8tags.stripe_height[i] = get2(); + } + break; case 61440: /* Fuji HS10 table */ fseek (ifp, get4()+base, SEEK_SET); parse_tiff_ifd (base); diff --git a/rtengine/dcraw.h b/rtengine/dcraw.h index eaf87d618..30fce90e3 100644 --- a/rtengine/dcraw.h +++ b/rtengine/dcraw.h @@ -192,12 +192,6 @@ protected: std::string RT_software; double RT_baseline_exposure; - struct PanasonicRW2Info { - ushort bpp; - ushort encoding; - PanasonicRW2Info(): bpp(0), encoding(0) {} - }; - PanasonicRW2Info RT_pana_info; std::vector gainMaps; public: @@ -229,6 +223,29 @@ public: short CR3_CTMDtag; }; + struct PanasonicRW2Info { + struct v8_tags_t + { + uint32_t tag39[6]; + uint16_t tag3A[6]; + uint16_t tag3B; + uint16_t initial[4]; + uint16_t tag40a[17], tag40b[17], tag41[17]; + uint16_t stripe_count; // 0x42 + uint16_t tag43; + int64_t stripe_offsets[5]; //0x44 + uint16_t stripe_left[5]; // 0x45 + uint32_t stripe_compressed_size[5]; //0x46 + uint16_t stripe_width[5]; //0x47 + uint16_t stripe_height[5]; + }; + + ushort bpp; + ushort encoding; + v8_tags_t v8tags; + PanasonicRW2Info(): bpp(0), encoding(0), v8tags{} {} + }; + bool isBayer() const { return (filters != 0 && filters != 9); @@ -250,9 +267,11 @@ public: protected: CanonCR3Data RT_canon_CR3_data; - + CanonLevelsData RT_canon_levels_data; + PanasonicRW2Info RT_pana_info; + float cam_mul[4], pre_mul[4], cmatrix[3][4], rgb_cam[3][4]; void (DCraw::*write_thumb)(); @@ -411,7 +430,9 @@ void fuji_decode_strip (fuji_compressed_params* params, int cur_block, INT64 raw void fuji_compressed_load_raw(); void fuji_decode_loop(fuji_compressed_params* common_info, int count, INT64* raw_block_offsets, unsigned *block_sizes, uchar *q_bases); void parse_fuji_compressed_header(); -void fuji_14bit_load_raw(); +void fuji_14bit_load_raw(); +void pana8_decode_loop(void *data); +bool pana8_decode_strip(void* data, int stream); void pentax_load_raw(); void nikon_load_raw(); int nikon_is_compressed(); @@ -503,6 +524,7 @@ private: void panasonicC6_load_raw(); void panasonicC7_load_raw(); +void panasonicC8_load_raw(); void canon_rmf_load_raw(); void panasonic_load_raw(); diff --git a/rtengine/panasonic_decoders.cc b/rtengine/panasonic_decoders.cc index 62bac4526..5211b09b8 100644 --- a/rtengine/panasonic_decoders.cc +++ b/rtengine/panasonic_decoders.cc @@ -13,14 +13,17 @@ * * You should have received a copy of the GNU General Public License * along with RawTherapee. If not, see . -*/ + */ #include +#include #include "dcraw.h" +#include "rt_math.h" + // Code adapted from libraw /* -*- C++ -*- - * Copyright 2019 LibRaw LLC (info@libraw.org) + * Copyright (C) 2022-2024 Alex Tutubalin, LibRaw LLC * LibRaw is free software; you can redistribute it and/or modify it under the terms of the one of two licenses as you choose: @@ -33,6 +36,431 @@ */ +namespace +{ + +using pana8_tags_t = DCraw::PanasonicRW2Info::v8_tags_t; +using ushort = DCraw::ushort; +using INT64 = DCraw::INT64; + +// in 8-byte words, 800kb +#define PANA8_BUFSIZE 102400 + +class pana8_bufio_t +{ +public: + pana8_bufio_t(rtengine::IMFILE *stream, INT64 start, uint32_t len) : + data(PANA8_BUFSIZE), input(stream), baseoffset(start), begin(0), end(0), _size(len) + { + } + uint32_t size() { return ((_size + 7) / 8) * 8; } + uint64_t getQWord(uint32_t offset) + { + if (offset >= begin && offset < end) + return data[offset - begin]; + if (!input) return 0; + refill(offset); + if (offset >= begin && offset < end) + return data[offset - begin]; + return 0; + } + void refill(uint32_t newoffset); + + std::vector data; + rtengine::IMFILE *input; + INT64 baseoffset; + INT64 begin, end; + uint32_t _size; +}; + +struct pana8_param_t { + uint32_t range_shift, gamma_base; + uint32_t tag3A[6]; + uint32_t tag39[6]; + uint32_t tag3B; + uint32_t initial[4]; + uint32_t huff_coeff[17]; + uint32_t tag3B_2; + uint32_t noGammaFlag; + uint64_t hufftable1[17]; + uint64_t hufftable2[17]; + std::vector gammaTable; + std::vector extrahuff; + + pana8_param_t(const pana8_tags_t &init); + int32_t gammaCurve(uint32_t i); + bool DecodeC8( + pana8_bufio_t &bufio, + unsigned int width, unsigned int height, ushort *raw_image, ushort raw_width, ushort raw_height, uint16_t left_margin); + uint32_t GetDBit(uint64_t a2); +}; + +void invertBits(void *buf, size_t size); + +void pana8_bufio_t::refill(uint32_t newoffset) +{ + if (newoffset >= begin && newoffset < end) + return; + uint32_t readwords, remainwords, toread; +#ifdef _OPENMP +#pragma omp critical + { +#endif + fseek(input, baseoffset + newoffset * sizeof(int64_t), SEEK_SET); + remainwords = (_size - newoffset * sizeof(int64_t) + 7) >> 3; + toread = MIN(PANA8_BUFSIZE, remainwords); + uint32_t readbytes = fread(data.data(), 1, toread * sizeof(uint64_t), input); + readwords = (readbytes + 7) >> 3; +#ifdef _OPENMP + } +#endif + + if (INT64(readwords) < INT64(toread) - 1LL) + throw std::runtime_error("Unexpected end of file in CRX bitstream"); + + if (readwords > 0) + invertBits(data.data(), readwords * sizeof(uint64_t)); + begin = newoffset; + end = newoffset + readwords; +} + +struct pana8_base_t { + pana8_base_t() { coeff[0] = coeff[1] = coeff[2] = coeff[3] = 0; } + pana8_base_t(const pana8_base_t &s) { clone(s.coeff); } + void clone(const uint32_t *scoeff) + { // TODO: implement SSE load for SSE-enabled code + coeff[0] = scoeff[0]; + coeff[1] = scoeff[1]; + coeff[2] = scoeff[2]; + coeff[3] = scoeff[3]; + } + uint32_t coeff[4]; +}; + +bool pana8_param_t::DecodeC8(pana8_bufio_t &bufio, unsigned int width, unsigned int height, ushort *raw_image, ushort raw_width, ushort raw_height, uint16_t left_margin) +{ + unsigned halfwidth = width >> 1; + unsigned halfheight = height >> 1; + if (!halfwidth || !halfheight || bufio.size() < 9) + return false; // invalid input + + uint32_t datamax = tag3B_2 >> range_shift; + + pana8_base_t start_coeff; + for (int i = 0; i < 4; i++) + start_coeff.coeff[i] = initial[i] & 0xffffu; + + bool _extrahuff = (extrahuff.size() >= 0x10000); + + uint8_t *big_huff_table = nullptr; + if (_extrahuff) + big_huff_table = extrahuff.data(); + + uint16_t *gammatable = (gammaTable.size() >= 0x10000) && !noGammaFlag ? (uint16_t *)gammaTable.data() : 0; + +#ifdef PANA8_FULLY_BUFFERED + const uint8_t *inputbyteptr = source.data(); + uint32_t jobsz_in_qwords = source.size() >> 3; +#else + uint32_t jobsz_in_qwords = bufio.size() >> 3; +#endif + int32_t doublewidth = 4 * halfwidth; + std::vector outline(4 * doublewidth); + pana8_base_t line_base(start_coeff); + int64_t bittail = 0LL; + int32_t bitportion = 0; + uint32_t inqword = 0u; + + try { + for (uint32_t current_row = 0; current_row < halfheight; current_row++) { + uint8_t *outrowp = outline.data(); + pana8_base_t current_base(line_base); + + for (int32_t col = 0; col < doublewidth; col++) { + uint64_t pixbits; + if (bitportion < 0) { + uint32_t inqword_next = inqword + 1; + if ((int)inqword + 1 >= int(jobsz_in_qwords)) + return false; + bitportion += 64; + uint64_t inputqword = bufio.getQWord(inqword); + uint64_t inputqword_next = bufio.getQWord(inqword_next); + pixbits = (inputqword_next >> bitportion) | (inputqword << (64 - (uint8_t)(bitportion & 0xffu))); + if ((unsigned int)inqword < jobsz_in_qwords) + inqword = inqword_next; + } else { + if ((unsigned int)inqword >= jobsz_in_qwords) + return false; + uint64_t inputqword = bufio.getQWord(inqword); + pixbits = (inputqword >> bitportion) | bittail; + uint32_t step = (bitportion == 0); + if (!bitportion) + bitportion = 64; + inqword += step; + } + int huff_index = 0; + if (_extrahuff) { + huff_index = *(uint8_t *)(big_huff_table + ((pixbits >> 48) & 0xffffu)); + } else { + huff_index = int(GetDBit(pixbits)); + datamax = tag3B_2; + } + int32_t v37 = (huff_coeff[huff_index] >> 24) & 0x1F; + uint32_t hc = huff_coeff[huff_index]; + int64_t v38 = pixbits << (((hc >> 16) & 0xffffu) & 0x1F); + uint64_t v90 = (uint32_t)(huff_index - v37); + int32_t v39 = (uint16_t)((uint64_t)v38 >> ((uint8_t)v37 - (uint8_t)huff_index)) << ((huff_coeff[huff_index] >> 24) & 0xffu); + + if (huff_index - v37 <= 0) + v39 &= 0xffff0000u; + + int32_t delta1; + if (v38 < 0) { + delta1 = (uint16_t)v39; + } else if (huff_index) { + int32_t v40 = -1 << huff_index; + if ((uint8_t)v37) + delta1 = (uint16_t)v39 + v40; + else + delta1 = (uint16_t)v39 + v40 + 1; + } else { + delta1 = 0; + } + + uint32_t v42 = bitportion - ((huff_coeff[huff_index] >> 16) & 0x1F); + int32_t delta2 = uint8_t(v37) ? 1 << (v37 - 1) : 0; + uint32_t *destpixel = (uint32_t *)(outrowp + 16LL * (col >> 2)); + + int32_t delta = delta1 + delta2; + int32_t col_amp_3 = col & 3; + if (col_amp_3 == 2) { + int32_t val = current_base.coeff[1] + delta; + destpixel[1] = uint32_t(rtengine::LIM(val, 0, int(datamax))); + } else if (col_amp_3 == 1) { + int32_t val = current_base.coeff[2] + delta; + destpixel[2] = uint32_t(rtengine::LIM(val, 0, int(datamax))); + } else if ((col & 3) != 0) { // == 3 + int32_t val = current_base.coeff[3] + delta; + destpixel[3] = uint32_t(rtengine::LIM(val, 0, int(datamax))); + } else { // 0 + int32_t val = current_base.coeff[0] + delta; + destpixel[0] = uint32_t(rtengine::LIM(val, 0, int(datamax))); + } + if (huff_index <= v37) + v90 = 0LL; + bittail = v38 << v90; + bitportion = int32_t(v42 - v90); + + if (col_amp_3 == 3) + current_base.clone((uint32_t *)(outrowp + 16LL * (col >> 2))); + if (col == 3) + line_base.clone((uint32_t *)(outrowp)); + } + + int destrow = current_row * 2; + uint16_t *destrow0 = raw_image + (destrow * raw_width) + left_margin; + uint16_t *destrow1 = + raw_image + (destrow + 1) * raw_width + left_margin; + uint16_t *srcrow = (uint16_t *)(outrowp); + if (gammatable) { + for (unsigned col = 0; col < width - 1; col += 2) { + const int c6 = col * 4; + destrow0[col] = gammatable[srcrow[c6]]; + destrow0[col + 1] = gammatable[srcrow[c6 + 2]]; + destrow1[col] = gammatable[srcrow[c6 + 4]]; + destrow1[col + 1] = gammatable[srcrow[c6 + 6]]; + } + } else { + for (unsigned col = 0; col < width - 1; col += 2) { + const int c6 = col * 4; + destrow0[col] = srcrow[c6]; + destrow0[col + 1] = srcrow[c6 + 2]; + destrow1[col] = srcrow[c6 + 4]; + destrow1[col + 1] = srcrow[c6 + 6]; + } + } + } + } catch (...) { // buffer read may throw an exception + return false; + } + + return true; +} + +uint32_t pana8_param_t::GetDBit(uint64_t a2) +{ + for (int i = 0; i < 16; i++) { + if ((a2 & hufftable2[i]) == hufftable1[i]) + return i; + } + + return uint32_t((hufftable2[16] & a2) == hufftable1[16]) ^ 0x11u; +} + +pana8_param_t::pana8_param_t(const pana8_tags_t &meta) : + gammaTable(0) +{ + range_shift = gamma_base = tag3B = 0; + + memset(tag3A, 0, sizeof(tag3A)); + memset(tag39, 0, sizeof(tag3A)); + memset(tag3A, 0, sizeof(tag3A)); + memset(initial, 0, sizeof(tag3A)); + memset(huff_coeff, 0, sizeof(tag3A)); + memset(hufftable1, 0, sizeof(tag3A)); + memset(hufftable2, 0, sizeof(tag3A)); + + noGammaFlag = 1; + + for (int i = 0; i < 6; i++) { + tag3A[i] = meta.tag3A[i]; + tag39[i] = meta.tag39[i]; + } + + tag3B_2 = tag3B = meta.tag3B; + + for (int i = 0; i < 4; i++) + initial[i] = meta.initial[i]; + + for (int i = 0; i < 17; i++) + huff_coeff[i] = (uint32_t(meta.tag41[i]) << 24) | (uint32_t(meta.tag40a[i]) << 16) | meta.tag40b[i]; + + std::vector tempGamma(0x10000); + for (unsigned i = 0; i < 0x10000; i++) { + uint64_t val = gammaCurve(i); + tempGamma[i] = uint16_t(val & 0xffffu); + if (i != val) + noGammaFlag = 0; + } + + if (!noGammaFlag) + gammaTable = tempGamma; + + int v7 = 0; + + for (unsigned hindex = 0; hindex < 17; hindex++) { + uint32_t hc = huff_coeff[hindex]; + uint32_t hlow = (hc >> 16) & 0x1F; + int16_t v8 = 0; + if ((hc & 0x1F0000) != 0) { + int h7 = ((hc >> 16) & 0xffffu) & 7; + if (hlow - 1 >= 7) { + uint32_t hdiff = h7 - hlow; + v8 = 0; + do { + v8 = (v8 << 8) | 0xFFu; + hdiff += 8; + } while (hdiff); + } else { + v8 = 0; + } + for (; h7; --h7) { + v8 = 2 * v8 + 1; + } + } + + uint16_t v9 = hc & v8; + if (uint32_t(v7) < hlow) { + v7 = ((huff_coeff[hindex] >> 16) & 0xFFFFu) & 0x1F; + } + hufftable2[hindex] = 0xFFFFULL << (64 - hlow); + hufftable1[hindex] = (uint64_t)v9 << (64 - hlow); + } + + if (v7 < 17) { + if (extrahuff.size() < 0x10000) + extrahuff.resize(0x10000); + uint64_t v17 = 0LL; + + for (int j = 0LL; j < 0x10000; ++j) { + extrahuff[j] = uint8_t(GetDBit(v17) & 0xffu); + v17 += 0x1000000000000ULL; + } + } +} + +int32_t pana8_param_t::gammaCurve(uint32_t idx) +{ + unsigned int v2 = idx | 0xFFFF0000; + if ((idx & 0x10000) == 0) + v2 = idx & 0x1FFFF; + + int v3 = gamma_base + v2; + unsigned int v4 = MIN(v3, 0xFFFF); + + int v5 = 0; + if ((v4 & 0x80000000) != 0) + v4 = 0; + + if (v4 >= (0xFFFF & tag3A[1])) { + v5 = 1; + if (v4 >= (0xFFFF & tag3A[2])) { + v5 = 2; + if (v4 >= (0xFFFF & tag3A[3])) { + v5 = 3; + if (v4 >= (0xFFFF & tag3A[4])) + v5 = ((v4 | 0x500000000LL) - (uint64_t)(0xFFFF & tag3A[5])) >> 32; + } + } + } + unsigned int v6 = tag3A[v5]; + int v7 = tag39[v5]; + unsigned int v8 = v4 - (uint16_t)v6; + char v9 = v7 & 0x1F; + int64_t result = 0; + + if (v9 == 31) { + result = v5 == 5 ? 0xFFFFLL : ((tag3A[v5 + 1] >> 16) & 0xFFFF); + return MIN(uint32_t(result), tag3B); + } + if ((v7 & 0x10) == 0) { + if (v9 == 15) { + result = ((v6 >> 16) & 0xFFFF); + return MIN(uint32_t(result), tag3B); + } else if (v9 != 0) { + v8 = (v8 + (1 << (v9 - 1))) >> v9; + } + } else { + v8 <<= v7 & 0xF; + } + + result = v8 + ((v6 >> 16) & 0xFFFF); + + return MIN(uint32_t(result), tag3B); +} + +const static uint8_t _bitRevTable[256] = { + 0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, 0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0, 0x08, 0x88, 0x48, + 0xC8, 0x28, 0xA8, 0x68, 0xE8, 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8, 0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, + 0x64, 0xE4, 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4, 0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC, 0x1C, + 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC, 0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2, 0x12, 0x92, 0x52, 0xD2, + 0x32, 0xB2, 0x72, 0xF2, 0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA, 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, + 0xFA, 0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6, 0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6, 0x0E, 0x8E, + 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE, 0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE, 0x01, 0x81, 0x41, 0xC1, 0x21, + 0xA1, 0x61, 0xE1, 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1, 0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9, + 0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9, 0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5, 0x15, 0x95, 0x55, + 0xD5, 0x35, 0xB5, 0x75, 0xF5, 0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED, 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, + 0x7D, 0xFD, 0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3, 0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3, 0x0B, + 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB, 0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB, 0x07, 0x87, 0x47, 0xC7, + 0x27, 0xA7, 0x67, 0xE7, 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7, 0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, + 0xEF, 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF}; + +void invertBits(void *buf, size_t size) +{ + unsigned sz = unsigned(size / 8); + uint64_t *ptr = static_cast(buf); + for (unsigned i = 0; i < sz; i++) { + uint8_t *b = reinterpret_cast(&ptr[i]); + uint64_t r = ((uint64_t)_bitRevTable[b[0]] << 56) | ((uint64_t)_bitRevTable[b[1]] << 48) | + ((uint64_t)_bitRevTable[b[2]] << 40) | ((uint64_t)_bitRevTable[b[3]] << 32) | + ((uint64_t)_bitRevTable[b[4]] << 24) | ((uint64_t)_bitRevTable[b[5]] << 16) | + ((uint64_t)_bitRevTable[b[6]] << 8) | _bitRevTable[b[7]]; + ptr[i] = r; + } +} + +} // namespace + unsigned DCraw::pana_bits_t::operator() (int nbits, unsigned *bytes) { int byte; @@ -177,6 +605,8 @@ void DCraw::panasonic_load_raw() panasonicC6_load_raw(); } else if (RT_pana_info.encoding == 7) { panasonicC7_load_raw(); + } else if (RT_pana_info.encoding == 8) { + panasonicC8_load_raw(); } else { pana_bits_t pana_bits(ifp, load_flags, RT_pana_info.encoding); pana_bits(0, 0); @@ -321,3 +751,55 @@ void DCraw::panasonicC7_load_raw() free(iobuf); tiff_bps = RT_pana_info.bpp; } + +void DCraw::panasonicC8_load_raw() +{ + int errs = 0; + unsigned totalw = 0; + + if (RT_pana_info.v8tags.stripe_count > 5) errs++; + for (int i = 0; i < RT_pana_info.v8tags.stripe_count && i < 5; i++) { + if (RT_pana_info.v8tags.stripe_height[i] != raw_height) + errs++; + if (RT_pana_info.v8tags.stripe_offsets[i] < 0 || (RT_pana_info.v8tags.stripe_offsets[i] + INT64((RT_pana_info.v8tags.stripe_compressed_size[i] + 7u) / 8u)) > INT64(ifp->size)) + errs++; + totalw += RT_pana_info.v8tags.stripe_width[i]; + } + if (totalw != raw_width) errs++; + + if (errs) + derror(); + + pana8_param_t pana8_param(RT_pana_info.v8tags); + pana8_decode_loop(&pana8_param); +} + +void DCraw::pana8_decode_loop(void *data) +{ +#ifdef _OPENMP + int errs = 0, scount = MIN(5, RT_pana_info.v8tags.stripe_count); +#pragma omp parallel for + for (int stream = 0; stream < scount; stream++) { + if (!pana8_decode_strip(data, stream)) + errs++; + } + if (errs) + derror(); +#else + for (int stream = 0; stream < RT_pana_info.v8tags.stripe_count && stream < 5; stream++) + if (!pana8_decode_strip(data, stream)) + derror(); +#endif +} + +bool DCraw::pana8_decode_strip(void *data, int stream) +{ + pana8_param_t *pana8_param = (pana8_param_t *)data; + if (!data || stream < 0 || stream > 4 || stream > RT_pana_info.v8tags.stripe_count) return 1; // error + + unsigned exactbytes = (RT_pana_info.v8tags.stripe_compressed_size[stream] + 7u) / 8u; + pana8_bufio_t bufio(ifp, RT_pana_info.v8tags.stripe_offsets[stream], exactbytes); + return pana8_param->DecodeC8(bufio, RT_pana_info.v8tags.stripe_width[stream], + RT_pana_info.v8tags.stripe_height[stream], raw_image, raw_width, raw_height, + RT_pana_info.v8tags.stripe_left[stream]); +} From 3b4642fd07bd3d7d88feb3c07c3075cf2390a152 Mon Sep 17 00:00:00 2001 From: Simone Gotti Date: Sat, 30 Mar 2024 17:18:25 +0100 Subject: [PATCH 2/2] dcraw: add Panasonic DC-S5M2 and DC-S5M2X to adobe_coeffs --- rtengine/dcraw.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/rtengine/dcraw.cc b/rtengine/dcraw.cc index 2b2d36013..cfb949b86 100644 --- a/rtengine/dcraw.cc +++ b/rtengine/dcraw.cc @@ -8996,6 +8996,8 @@ void CLASS adobe_coeff (const char *make, const char *model) { 7610,-2780,-576,-4614,12195,2733,-1375,2393,6490 } }, { "Panasonic DMC-G8", 15, 0xfff, /* G8, G80, G81, G85 */ { 7610,-2780,-576,-4614,12195,2733,-1375,2393,6490 } }, + { "Panasonic DC-S5M2", 0, 0, /* DC-S5M2, DC-S5M2X */ + { 10308,-4206,-783,-4088,12102,2229,-125,1051,5912 } }, { "Panasonic DC-G9M2", 0, 0, { 8325,-3456,-623,-4330,12089,2528,-860,2646,5984 } }, { "Panasonic DC-G9", 15, 0xfff,