diff --git a/internal/libraw_cameraids.h b/internal/libraw_cameraids.h index 210c28a3..03a7203d 100644 --- a/internal/libraw_cameraids.h +++ b/internal/libraw_cameraids.h @@ -344,4 +344,5 @@ it under the terms of the one of two licenses as you choose: #define SonyID_ZV_E10M2 0x18fULL #define SonyID_ILME_FX2 0x196ULL #define SonyID_ILCE_7M5 0x197ULL +#define SonyID_ILCE_7RM6 0x19aULL #endif diff --git a/src/decoders/sony_arw6.cpp b/src/decoders/sony_arw6.cpp index db168c5a..eedce605 100644 --- a/src/decoders/sony_arw6.cpp +++ b/src/decoders/sony_arw6.cpp @@ -16,6 +16,7 @@ #include #include +#include #include #include @@ -26,11 +27,6 @@ const int SONY_ARW6_INTERNAL_BIAS = 2048; const size_t SONY_ARW6_MAX_PLANE_SAMPLES = size_t(128) * 1024 * 1024; const INT64 SONY_ARW6_WORKING_BYTES_PER_TILE_PIXEL = 24; -static inline int sony_arw6_align_up(int value, int multiple) -{ - return ((value + multiple - 1) / multiple) * multiple; -} - static inline INT64 sony_arw6_memory_limit_bytes(unsigned max_raw_memory_mb) { return INT64(max_raw_memory_mb) * INT64(1024 * 1024); @@ -790,12 +786,61 @@ static int sony_arw6_infer_packet_width(int group, int packet_type, throw LIBRAW_EXCEPTION_IO_CORRUPT; } -static int sony_arw6_expected_packet_rows(int group, int coded_height) +/* ---- ARW6 vertical canvas geometry ---- + + A tile's component rows (comp_height = tile height / 2) sit on a shared + 1-D "canvas" that is split into chunks of SONY_ARW6_CHUNK_ROWS canvas + rows starting at SONY_ARW6_CHUNK_ORIGIN. Every sub-band occupies a + lattice — a strided subset of canvas rows (step = canvas rows per lattice + row; even lattices at phase 0, odd ones at phase step/2). A chunk stores + each orientation's in-image lattice rows in orientation order (HL, LH, + HH), filling the record's fixed plane slots sequentially, so a partial + first/last chunk shifts rows across the linear planes. None of this is + stored in the file; it all derives from comp_height. Cross-validated + bit-exactly against Adobe DNG Converter output; the layout matches the + reverse-engineered format description in abbradar/arw6_decode. */ + +static const int SONY_ARW6_CHUNK_ROWS = 8; /* canvas rows per chunk (4 levels) */ +static const int SONY_ARW6_CHUNK_ORIGIN = 4; /* canvas row where chunk 0 begins */ + +static inline int sony_arw6_ceil_div(int a, int b) +{ + return (a + b - 1) / b; /* a >= 0, b > 0 */ +} + +/* First data row on the canvas: the chunk origin plus the offset that makes + the first and last chunks symmetric. */ +static int sony_arw6_comp_top(int comp_height) +{ + const int m = (comp_height / 2) % SONY_ARW6_CHUNK_ROWS; + return SONY_ARW6_CHUNK_ORIGIN + + (SONY_ARW6_CHUNK_ROWS - m) % SONY_ARW6_CHUNK_ROWS; +} + +static int sony_arw6_chunk_count(int comp_height) +{ + return sony_arw6_ceil_div(sony_arw6_comp_top(comp_height) + comp_height - + SONY_ARW6_CHUNK_ORIGIN, + SONY_ARW6_CHUNK_ROWS); +} + +struct SonyArw6Span +{ + int top; /* first in-image lattice row */ + int bottom; /* one past the last in-image lattice row */ + int base; /* lattice row at/after the chunk-0 origin */ + int rpc; /* lattice rows per chunk */ +}; + +static SonyArw6Span sony_arw6_make_span(int comp_top, int comp_height, + int step, int phase) { - sony_arw6_require(group >= 0 && group <= 4); - sony_arw6_require(coded_height > 0 && coded_height <= 0x7fff); - const int padded_height = sony_arw6_align_up(coded_height, 16); - return (padded_height / 16 + 1) * sony_arw6_row_multiplier(group); + SonyArw6Span s; + s.top = sony_arw6_ceil_div(comp_top - phase, step); + s.bottom = sony_arw6_ceil_div(comp_top + comp_height - phase, step); + s.base = sony_arw6_ceil_div(SONY_ARW6_CHUNK_ORIGIN - phase, step); + s.rpc = SONY_ARW6_CHUNK_ROWS / step; + return s; } static std::vector @@ -922,7 +967,7 @@ static SonyArw6Packet sony_arw6_parse_packet(const uchar *data, uint32_t length) static std::vector sony_arw6_decode_packet_arrays(const uchar *stream, uint32_t stream_size, const std::vector &dir, - int mosaic_width, int coded_height, int group, + int mosaic_width, int n_blocks, int group, int index) { const SonyArw6DirectoryEntry e = sony_arw6_find_entry(dir, group, index); @@ -931,19 +976,16 @@ sony_arw6_decode_packet_arrays(const uchar *stream, uint32_t stream_size, const int row_width = sony_arw6_infer_packet_width(group, p.type, mosaic_width); const int row_multiplier = sony_arw6_row_multiplier(group); const int rows = p.block_count * row_multiplier; - const int expected_rows = sony_arw6_expected_packet_rows(group, coded_height); const int groups_per_row = (row_width + 3) / 4; sony_arw6_require(row_width > 0 && groups_per_row > 0 && rows > 0); - if (rows != expected_rows) - sony_arw6_require((coded_height & 15) && - expected_rows - rows == row_multiplier); + sony_arw6_require(p.block_count == n_blocks); sony_arw6_require(size_t(p.block_count) <= (stream_size / 16U + 1U)); /* weak corruption guard */ std::vector planes; planes.reserve(components); for (int c = 0; c < components; c++) - planes.push_back(SonyArw6Plane(expected_rows, row_width)); + planes.push_back(SonyArw6Plane(rows, row_width)); for (int ri = 0; ri < p.block_count; ri++) { @@ -966,19 +1008,18 @@ sony_arw6_decode_packet_arrays(const uchar *stream, uint32_t stream_size, return planes; } -static SonyArw6Plane sony_arw6_integrate_type1(const SonyArw6Plane &coeffs, - int rows, int dc_offset) +static SonyArw6Plane sony_arw6_integrate_type1(const SonyArw6Plane &coeffs) { - sony_arw6_require(rows > 0 && rows <= coeffs.rows); - SonyArw6Plane out(rows, coeffs.cols); - for (int y = 0; y < rows; y++) + sony_arw6_require(coeffs.rows > 0); + SonyArw6Plane out(coeffs.rows, coeffs.cols); + for (int y = 0; y < coeffs.rows; y++) { int32_t acc = sony_arw6_sign16(coeffs.at(y, 0)) * 2; - out.at(y, 0) = acc / 2 + dc_offset; + out.at(y, 0) = acc / 2; for (int x = 1; x < coeffs.cols; x++) { acc += sony_arw6_sign16(coeffs.at(y, x)) * 2; - out.at(y, x) = acc / 2 + dc_offset; + out.at(y, x) = acc / 2; } } return out; @@ -994,32 +1035,6 @@ static SonyArw6Plane sony_arw6_head_rows(const SonyArw6Plane &src, int rows) return out; } -static SonyArw6Plane sony_arw6_inv53_axis0(const SonyArw6Plane &low, - const SonyArw6Plane &high) -{ - sony_arw6_require(low.rows == high.rows && low.cols == high.cols); - SonyArw6Plane lo2(low.rows, low.cols); - for (int y = 0; y < low.rows; y++) - for (int x = 0; x < low.cols; x++) - { - const int32_t hp = high.at(y ? y - 1 : 0, x); - const int32_t hc = high.at(y, x); - lo2.at(y, x) = low.at(y, x) - sony_arw6_floor_shift(hp + hc + 2, 2); - } - - SonyArw6Plane out(low.rows * 2, low.cols); - for (int y = 0; y < low.rows; y++) - for (int x = 0; x < low.cols; x++) - { - const int32_t ln = lo2.at(y + 1 < low.rows ? y + 1 : y, x); - const int32_t hi2 = - high.at(y, x) + sony_arw6_floor_shift(lo2.at(y, x) + ln, 1); - out.at(y * 2, x) = lo2.at(y, x); - out.at(y * 2 + 1, x) = hi2; - } - return out; -} - static SonyArw6Plane sony_arw6_inv53_axis1(const SonyArw6Plane &low, const SonyArw6Plane &high) { @@ -1046,265 +1061,135 @@ static SonyArw6Plane sony_arw6_inv53_axis1(const SonyArw6Plane &low, return out; } -static SonyArw6Plane sony_arw6_inv53_axis0_high_leading( - const SonyArw6Plane &low, const SonyArw6Plane &high) +/* Copy orientation `oi`'s in-image lattice rows out of the fixed per-record + plane slots (slot s of chunk c = plane s/rm, plane row c*rm + s%rm). A + chunk's stored rows fill the slots sequentially in orientation order, so + partial first/last chunks shift rows across the linear planes. HH rows in + a partial chunk window are stored at half amplitude; `hh_edge` restores + them via sony_arw6_edge_detail(). */ +static SonyArw6Plane sony_arw6_extract_orientation( + const std::vector &planes, int n_chunks, + const SonyArw6Span *spans, int n_orient, int oi, bool hh_edge, + bool odd_edge_mode) { - sony_arw6_require(low.cols == high.cols); - sony_arw6_require(high.rows == low.rows || high.rows == low.rows + 1); - SonyArw6Plane lo2(low.rows, low.cols); - SonyArw6Plane hi2(high.rows, high.cols); - - if (high.rows == low.rows + 1) + const SonyArw6Span &sp = spans[oi]; + /* Records hold rpc rows per plane slot; every span in a packet shares it + (step * rpc == SONY_ARW6_CHUNK_ROWS). */ + const int row_multiplier = sp.rpc; + const int count = sp.bottom - sp.top; + sony_arw6_require(count > 0 && !planes.empty()); + const int cols = planes[0].cols; + const int slots_per_rec = int(planes.size()) * row_multiplier; + SonyArw6Plane out(count, cols); + for (int c = 0; c < n_chunks; c++) { - for (int y = 0; y < low.rows; y++) - for (int x = 0; x < low.cols; x++) - lo2.at(y, x) = - low.at(y, x) - - sony_arw6_floor_shift(high.at(y, x) + high.at(y + 1, x) + 2, 2); - - for (int x = 0; x < high.cols; x++) - { - hi2.at(0, x) = high.at(0, x) + lo2.at(0, x); - hi2.at(high.rows - 1, x) = high.at(high.rows - 1, x) + - lo2.at(low.rows - 1, x); - } - for (int y = 1; y < high.rows - 1; y++) - for (int x = 0; x < high.cols; x++) - hi2.at(y, x) = high.at(y, x) + - sony_arw6_floor_shift(lo2.at(y - 1, x) + - lo2.at(y, x), - 1); - - SonyArw6Plane out(low.rows * 2 + 1, low.cols); - for (int y = 0; y < low.rows; y++) + int slot = 0; + for (int o = 0; o < n_orient; o++) { - memcpy(out.row(y * 2), hi2.row(y), sizeof(int32_t) * size_t(low.cols)); - memcpy(out.row(y * 2 + 1), lo2.row(y), - sizeof(int32_t) * size_t(low.cols)); + const SonyArw6Span &osp = spans[o]; + const int lo = std::max(osp.base + c * osp.rpc, osp.top); + const int hi = std::min(osp.base + (c + 1) * osp.rpc, osp.bottom); + const int window = hi - lo; + if (window <= 0) + continue; + if (o == oi) + { + const bool partial = window < osp.rpc; + for (int r = 0; r < window; r++) + { + const int s = slot + r; + sony_arw6_require(s < slots_per_rec); + const int plane_row = c * row_multiplier + s % row_multiplier; + sony_arw6_require(plane_row < planes[s / row_multiplier].rows); + const int32_t *src = planes[s / row_multiplier].row(plane_row); + int32_t *dst = out.row(lo + r - sp.top); + if (hh_edge && partial) + for (int x = 0; x < cols; x++) + dst[x] = sony_arw6_edge_detail(src[x], odd_edge_mode); + else + memcpy(dst, src, sizeof(int32_t) * size_t(cols)); + } + } + slot += window; } - memcpy(out.row(out.rows - 1), hi2.row(hi2.rows - 1), - sizeof(int32_t) * size_t(low.cols)); - return out; - } - - for (int y = 0; y < low.rows; y++) - for (int x = 0; x < low.cols; x++) - { - const int next_y = y + 1 < high.rows ? y + 1 : y; - lo2.at(y, x) = - low.at(y, x) - - sony_arw6_floor_shift(high.at(y, x) + high.at(next_y, x) + 2, 2); - } - for (int x = 0; x < high.cols; x++) - hi2.at(0, x) = high.at(0, x) + lo2.at(0, x); - for (int y = 1; y < high.rows; y++) - for (int x = 0; x < high.cols; x++) - hi2.at(y, x) = - high.at(y, x) + - sony_arw6_floor_shift(lo2.at(y - 1, x) + lo2.at(y, x), 1); - - SonyArw6Plane out(low.rows * 2, low.cols); - for (int y = 0; y < low.rows; y++) - { - memcpy(out.row(y * 2), hi2.row(y), sizeof(int32_t) * size_t(low.cols)); - memcpy(out.row(y * 2 + 1), lo2.row(y), - sizeof(int32_t) * size_t(low.cols)); } return out; } -static SonyArw6Plane sony_arw6_synthesize_level(const SonyArw6Plane &ll, - const SonyArw6Plane &sub0, - const SonyArw6Plane &sub1, - const SonyArw6Plane &sub2) +static inline int sony_arw6_clamp_index(int i, int n) { - const int h = ll.rows; - const int w = ll.cols; - sony_arw6_require(sub0.cols == w && sub1.cols == w && sub2.cols == w); - sony_arw6_require(sub0.rows >= h + 1 && sub1.rows >= h + 1 && - sub2.rows >= h + 1); - SonyArw6Plane lh(h, w), hh(h, w); - for (int y = 0; y < h - 1; y++) - for (int x = 0; x < w; x++) - { - lh.at(y, x) = sub1.at(y + 1, x); - hh.at(y, x) = sub2.at(y + 1, x); - } - for (int x = 0; x < w; x++) - { - lh.at(h - 1, x) = sub0.at(h, x); - hh.at(h - 1, x) = sub1.at(h, x); - } - SonyArw6Plane low_horizontal = sony_arw6_inv53_axis0(ll, lh); - SonyArw6Plane high_horizontal = - sony_arw6_inv53_axis0(sony_arw6_head_rows(sub0, h), hh); - return sony_arw6_inv53_axis1(low_horizontal, high_horizontal); + return i < 0 ? 0 : (i >= n ? n - 1 : i); } -static SonyArw6Plane sony_arw6_synthesize_guard_group1( - const SonyArw6Plane &ll, const SonyArw6Plane &sub0, - const SonyArw6Plane &sub1, const SonyArw6Plane &sub2) +/* One vertical inverse 5/3 lift interleaving the coarse and detail + sub-bands. `coarse_odd` puts the coarse samples on the odd output rows (the + parity of the merged span's top canvas coordinate). Row counts may differ + by one; a trailing sample past the grid edge is dropped. */ +static SonyArw6Plane sony_arw6_idwt53_vert(const SonyArw6Plane &low, + const SonyArw6Plane &high, + bool coarse_odd) { - const int h = ll.rows; - const int w = ll.cols; - sony_arw6_require(sub0.cols == w && sub1.cols == w && sub2.cols == w); - sony_arw6_require(sub0.rows >= h + 2 && sub1.rows >= h + 2 && - sub2.rows >= h + 2); - - SonyArw6Plane lh(h + 1, w), hh(h + 1, w), hl(h, w); - for (int y = 0; y < h; y++) - for (int x = 0; x < w; x++) - { - hl.at(y, x) = sub0.at(y + 1, x); - lh.at(y, x) = sub1.at(y + 1, x); - hh.at(y, x) = sub2.at(y + 1, x); - } - for (int x = 0; x < w; x++) + const int n_low = low.rows; + const int n_high = high.rows; + const int n_out = n_low + n_high; + sony_arw6_require(n_low > 0 && n_high > 0 && low.cols == high.cols && + n_low - n_high <= 1 && n_high - n_low <= 1); + const int w = low.cols; + const int c = coarse_odd ? 1 : 0; + SonyArw6Plane out(n_out, w); + for (int n = 0; n < n_low; n++) { - lh.at(h, x) = sub0.at(h + 1, x); - hh.at(h, x) = sub1.at(h + 1, x); + const int pos = 2 * n + c; + if (pos >= n_out) + continue; + const int h0 = sony_arw6_clamp_index(n - 1 + c, n_high); + const int h1 = sony_arw6_clamp_index(n + c, n_high); + for (int x = 0; x < w; x++) + out.at(pos, x) = + low.at(n, x) - + sony_arw6_floor_shift(high.at(h0, x) + high.at(h1, x) + 2, 2); } - - SonyArw6Plane low_horizontal = - sony_arw6_inv53_axis0_high_leading(ll, lh); - SonyArw6Plane high_horizontal = - sony_arw6_inv53_axis0_high_leading(hl, hh); - return sony_arw6_inv53_axis1(low_horizontal, high_horizontal); -} - -static SonyArw6Plane sony_arw6_synthesize_guard_group2( - const SonyArw6Plane &ll, const SonyArw6Plane &sub0, - const SonyArw6Plane &sub1, const SonyArw6Plane &sub2, - bool odd_edge_mode) -{ - const int h = ll.rows; - const int w = ll.cols; - sony_arw6_require(sub0.cols == w && sub1.cols == w && sub2.cols == w); - sony_arw6_require(sub0.rows >= h + 3 && sub1.rows >= h + 1 && - sub2.rows >= h + 1); - - SonyArw6Plane hl(h, w), lh(h, w), hh(h, w); - for (int x = 0; x < w; x++) + for (int n = 0; n < n_high; n++) { - lh.at(0, x) = sub0.at(0, x); - hh.at(0, x) = sony_arw6_edge_detail(sub0.at(1, x), odd_edge_mode); - } - for (int y = 0; y < h; y++) - for (int x = 0; x < w; x++) - hl.at(y, x) = sub0.at(y + 2, x); - for (int y = 1; y < h; y++) + const int pos = 2 * n + 1 - c; + if (pos >= n_out) + continue; + const int e0 = 2 * sony_arw6_clamp_index(n - c, n_low) + c; + const int e1 = 2 * sony_arw6_clamp_index(n + 1 - c, n_low) + c; for (int x = 0; x < w; x++) - { - lh.at(y, x) = sub1.at(y + 1, x); - hh.at(y, x) = sub2.at(y + 1, x); - } - - SonyArw6Plane low_horizontal = - sony_arw6_inv53_axis0_high_leading(ll, lh); - SonyArw6Plane high_horizontal = - sony_arw6_inv53_axis0_high_leading(hl, hh); - return sony_arw6_inv53_axis1(low_horizontal, high_horizontal); -} - -static SonyArw6Plane sony_arw6_synthesize_guard_group3( - const SonyArw6Plane &ll, const SonyArw6Plane &sub0, - const SonyArw6Plane &sub1, const SonyArw6Plane &sub2, - bool odd_edge_mode) -{ - const int h = ll.rows; - const int w = ll.cols; - sony_arw6_require(sub0.cols == w && sub1.cols == w && sub2.cols == w); - sony_arw6_require(sub0.rows >= h + 5 && sub1.rows >= h + 2 && - sub2.rows >= h + 2); - - SonyArw6Plane hl(h, w), lh(h, w), hh(h, w); - for (int x = 0; x < w; x++) - { - hl.at(0, x) = sub0.at(0, x); - lh.at(0, x) = sub0.at(1, x); - hh.at(0, x) = sony_arw6_edge_detail(sub0.at(2, x), odd_edge_mode); - lh.at(h - 1, x) = sub0.at(h + 3, x); - hh.at(h - 1, x) = - sony_arw6_edge_detail(sub0.at(h + 4, x), odd_edge_mode); + out.at(pos, x) = + high.at(n, x) + + sony_arw6_floor_shift(out.at(e0, x) + out.at(e1, x), 1); } - for (int y = 1; y < h; y++) - for (int x = 0; x < w; x++) - hl.at(y, x) = sub0.at(y + 3, x); - for (int y = 1; y < h - 1; y++) - for (int x = 0; x < w; x++) - { - lh.at(y, x) = sub1.at(y + 3, x); - hh.at(y, x) = sub2.at(y + 3, x); - } - - SonyArw6Plane low_horizontal = sony_arw6_inv53_axis0(ll, lh); - SonyArw6Plane high_horizontal = sony_arw6_inv53_axis0(hl, hh); - return sony_arw6_inv53_axis1(low_horizontal, high_horizontal); + return out; } -static SonyArw6Plane sony_arw6_synthesize_level_stride( - const SonyArw6Plane &ll, const SonyArw6Plane &sub0, - const SonyArw6Plane &sub1, const SonyArw6Plane &sub2, int edge_rows, - bool odd_edge_mode) +/* One inverse 2-D level: vertical lifts of the LL|LH and HL|HH column pairs + at the level's parity, then the horizontal lift (always standard phase). */ +static SonyArw6Plane sony_arw6_merge_level(const SonyArw6Plane &ll, + const SonyArw6Plane &hl, + const SonyArw6Plane &lh, + const SonyArw6Plane &hh, bool coarse_odd) { - if (edge_rows == 0) - return sony_arw6_synthesize_level(ll, sub0, sub1, sub2); - - const int h = ll.rows; - const int w = ll.cols; - sony_arw6_require(sub0.cols == w && sub1.cols == w && sub2.cols == w); - sony_arw6_require(sub0.rows >= h + edge_rows * 2 && - sub1.rows >= h + edge_rows && - sub2.rows >= h); - - SonyArw6Plane hl(h, w), lh(h, w), hh(h, w); - for (int y = 0; y < edge_rows; y++) - for (int x = 0; x < w; x++) - { - hl.at(y, x) = sub0.at(y, x); - lh.at(y, x) = sub0.at(y + edge_rows, x); - hh.at(y, x) = sony_arw6_edge_detail(sub1.at(y, x), odd_edge_mode); - } - for (int y = edge_rows; y < h - edge_rows; y++) - for (int x = 0; x < w; x++) - { - hl.at(y, x) = sub0.at(y + edge_rows, x); - lh.at(y, x) = sub1.at(y + edge_rows, x); - hh.at(y, x) = sub2.at(y + edge_rows, x); - } - for (int y = h - edge_rows; y < h; y++) - { - const int k = y - (h - edge_rows); - for (int x = 0; x < w; x++) - { - hl.at(y, x) = sub0.at(h + k, x); - lh.at(y, x) = sub0.at(h + edge_rows + k, x); - hh.at(y, x) = sony_arw6_edge_detail(sub1.at(h + k, x), odd_edge_mode); - } - } - - SonyArw6Plane low_horizontal = sony_arw6_inv53_axis0(ll, lh); - SonyArw6Plane high_horizontal = sony_arw6_inv53_axis0(hl, hh); - return sony_arw6_inv53_axis1(low_horizontal, high_horizontal); + SonyArw6Plane left = sony_arw6_idwt53_vert(ll, lh, coarse_odd); + SonyArw6Plane right = sony_arw6_idwt53_vert(hl, hh, coarse_odd); + const int rows = std::min(left.rows, right.rows); + if (left.rows != rows) + left = sony_arw6_head_rows(left, rows); + if (right.rows != rows) + right = sony_arw6_head_rows(right, rows); + return sony_arw6_inv53_axis1(left, right); } +/* Recombine the merged green_lo with the extracted green_hi rows: the + always-flipped horizontal green split (green_hi lands on the even output + columns). */ static SonyArw6Plane sony_arw6_final_green(const SonyArw6Plane &ll, - const SonyArw6Plane &detail, - int top_rows) + const SonyArw6Plane &selected) { const int h = ll.rows; const int w = ll.cols; - sony_arw6_require(top_rows >= 0 && top_rows <= 8); - sony_arw6_require(detail.cols == w && - detail.rows >= 8 + std::max(0, h - top_rows)); - - SonyArw6Plane selected(h, w); - for (int y = 0; y < h; y++) - { - const int src_y = y < top_rows ? y : y + 8 - top_rows; - for (int x = 0; x < w; x++) - selected.at(y, x) = detail.at(src_y, x); - } + sony_arw6_require(selected.cols == w && selected.rows >= h); SonyArw6Plane odd_green(h, w); for (int y = 0; y < h; y++) @@ -1390,133 +1275,69 @@ static SonyArw6DecodedTile sony_arw6_decode_stream_tile(const uchar *stream, sony_arw6_require(sony_arw6_parse_stream_header(stream, stream_size, header)); const std::vector dir = sony_arw6_parse_directory(stream, stream_size); - const int coded_height = header.logical_height; - sony_arw6_require(header.coded_width > 0 && coded_height > 0); - const int padded_height = sony_arw6_align_up(coded_height, 16); - const bool guarded_height = coded_height != padded_height; - const int low_rows = padded_height / 16; - const int low_start = guarded_height ? 1 : 0; - const int low_count = low_rows - low_start; - - std::vector g0 = - sony_arw6_decode_packet_arrays(stream, stream_size, dir, - header.coded_width, coded_height, 0, 0); - SonyArw6Plane green = - sony_arw6_integrate_type1(g0[0], low_start + low_count, 0); - if (low_start) + const int comp_height = header.coded_half_height; + sony_arw6_require(header.coded_width > 0 && comp_height > 0); + const int comp_top = sony_arw6_comp_top(comp_height); + const int n_chunks = sony_arw6_chunk_count(comp_height); + + /* components 0..2 = green_lo, chroma_r, chroma_b */ + const SonyArw6Span ll_span = sony_arw6_make_span(comp_top, comp_height, 8, 0); + SonyArw6Plane comps[3]; + for (int comp = 0; comp < 3; comp++) { - SonyArw6Plane cropped(low_count, green.cols); - for (int y = 0; y < low_count; y++) - memcpy(cropped.row(y), green.row(y + low_start), - sizeof(int32_t) * size_t(green.cols)); - green = cropped; - } - - std::vector r0 = - sony_arw6_decode_packet_arrays(stream, stream_size, dir, - header.coded_width, coded_height, 0, 1); - SonyArw6Plane red_residual = - sony_arw6_integrate_type1(r0[0], low_start + low_count, 0); - if (low_start) - { - SonyArw6Plane cropped(low_count, red_residual.cols); - for (int y = 0; y < low_count; y++) - memcpy(cropped.row(y), red_residual.row(y + low_start), - sizeof(int32_t) * size_t(red_residual.cols)); - red_residual = cropped; - } - - std::vector b0 = - sony_arw6_decode_packet_arrays(stream, stream_size, dir, - header.coded_width, coded_height, 0, 2); - SonyArw6Plane blue_residual = - sony_arw6_integrate_type1(b0[0], low_start + low_count, 0); - if (low_start) - { - SonyArw6Plane cropped(low_count, blue_residual.cols); - for (int y = 0; y < low_count; y++) - memcpy(cropped.row(y), blue_residual.row(y + low_start), - sizeof(int32_t) * size_t(blue_residual.cols)); - blue_residual = cropped; + std::vector p = + sony_arw6_decode_packet_arrays(stream, stream_size, dir, + header.coded_width, n_chunks, 0, + comp); + SonyArw6Plane ll = sony_arw6_extract_orientation(p, n_chunks, &ll_span, 1, + 0, false, false); + comps[comp] = sony_arw6_integrate_type1(ll); } + /* detail groups, coarsest first */ for (int group = 1; group <= 3; group++) { - const int edge_rows = group == 1 ? 0 : (group == 2 ? 1 : 2); - const bool color_odd_edge = group == 3; - - std::vector planes = - sony_arw6_decode_packet_arrays(stream, stream_size, dir, - header.coded_width, coded_height, group, - 0); - if (guarded_height) - { - if (group == 1) - green = sony_arw6_synthesize_guard_group1(green, planes[0], - planes[1], planes[2]); - else if (group == 2) - green = sony_arw6_synthesize_guard_group2(green, planes[0], - planes[1], planes[2], false); - else - green = sony_arw6_synthesize_guard_group3(green, planes[0], - planes[1], planes[2], false); - } - else - green = sony_arw6_synthesize_level_stride(green, planes[0], planes[1], - planes[2], edge_rows, false); - - planes = sony_arw6_decode_packet_arrays(stream, stream_size, dir, - header.coded_width, coded_height, - group, 1); - if (guarded_height) + const int step = 8 >> (group - 1); + SonyArw6Span spans[3]; + spans[0] = sony_arw6_make_span(comp_top, comp_height, step, 0); /* HL */ + spans[1] = + sony_arw6_make_span(comp_top, comp_height, step, step / 2); /* LH */ + spans[2] = spans[1]; /* HH */ + /* The merged span's top canvas coordinate decides which output parity + the coarse rows land on. */ + const bool coarse_odd = (sony_arw6_ceil_div(comp_top, step / 2) & 1) != 0; + + for (int comp = 0; comp < 3; comp++) { - if (group == 1) - red_residual = sony_arw6_synthesize_guard_group1( - red_residual, planes[0], planes[1], planes[2]); - else if (group == 2) - red_residual = sony_arw6_synthesize_guard_group2( - red_residual, planes[0], planes[1], planes[2], false); - else - red_residual = sony_arw6_synthesize_guard_group3( - red_residual, planes[0], planes[1], planes[2], color_odd_edge); - } - else - red_residual = sony_arw6_synthesize_level_stride( - red_residual, planes[0], planes[1], planes[2], edge_rows, - color_odd_edge); - - planes = sony_arw6_decode_packet_arrays(stream, stream_size, dir, - header.coded_width, coded_height, - group, 2); - if (guarded_height) - { - if (group == 1) - blue_residual = sony_arw6_synthesize_guard_group1( - blue_residual, planes[0], planes[1], planes[2]); - else if (group == 2) - blue_residual = sony_arw6_synthesize_guard_group2( - blue_residual, planes[0], planes[1], planes[2], false); - else - blue_residual = sony_arw6_synthesize_guard_group3( - blue_residual, planes[0], planes[1], planes[2], color_odd_edge); + const bool odd_edge = group == 3 && comp != 0; + std::vector p = + sony_arw6_decode_packet_arrays(stream, stream_size, dir, + header.coded_width, n_chunks, + group, comp); + SonyArw6Plane hl = sony_arw6_extract_orientation(p, n_chunks, spans, 3, + 0, false, false); + SonyArw6Plane lh = sony_arw6_extract_orientation(p, n_chunks, spans, 3, + 1, false, false); + SonyArw6Plane hh = sony_arw6_extract_orientation(p, n_chunks, spans, 3, + 2, true, odd_edge); + comps[comp] = sony_arw6_merge_level(comps[comp], hl, lh, hh, coarse_odd); } - else - blue_residual = sony_arw6_synthesize_level_stride( - blue_residual, planes[0], planes[1], planes[2], edge_rows, - color_odd_edge); } + const SonyArw6Span hi_span = sony_arw6_make_span(comp_top, comp_height, 1, 0); std::vector g4 = sony_arw6_decode_packet_arrays(stream, stream_size, dir, - header.coded_width, coded_height, 4, 0); - SonyArw6Plane full_green = - sony_arw6_final_green(green, g4[0], guarded_height ? 2 : 4); + header.coded_width, n_chunks, 4, 0); + SonyArw6Plane green_hi = sony_arw6_extract_orientation(g4, n_chunks, + &hi_span, 1, 0, + false, false); + SonyArw6Plane full_green = sony_arw6_final_green(comps[0], green_hi); SonyArw6DecodedTile out; - out.green = green; - out.red_residual = red_residual; - out.blue_residual = blue_residual; - out.full_green = full_green; + out.green = std::move(comps[0]); + out.red_residual = std::move(comps[1]); + out.blue_residual = std::move(comps[2]); + out.full_green = std::move(full_green); return out; } diff --git a/src/metadata/identify.cpp b/src/metadata/identify.cpp index 1bd6545f..4dab56c9 100644 --- a/src/metadata/identify.cpp +++ b/src/metadata/identify.cpp @@ -3005,6 +3005,31 @@ void LibRaw::identify_finetune_dcr(char head[64], INT64 fsize, INT64 flen) imgdata.process_warnings |= LIBRAW_WARN_VENDOR_CROP_SUGGESTED; } + } + else if (unique_id == SonyID_ILCE_7RM6) + { + if (raw_width == 10240) // FF, Lossless compressed + { + width = 9984; + height = 6656; + } + else if (raw_width == 10016) // FF compressed (RAW 2) + { + width = 9984; + height = 6656; + } + else if (raw_width == 6656) // APS-C, Lossless compressed + { + width = 6528; + height = 4352; + } + else if (raw_width == 6592) // APS-C compressed (RAW 2) + { + width = 6528; + height = 4352; + } + else + imgdata.process_warnings |= LIBRAW_WARN_VENDOR_CROP_SUGGESTED; } else if (raw_width == 3984) { // Sony DSC-R1; diff --git a/src/metadata/normalize_model.cpp b/src/metadata/normalize_model.cpp index e852c4a9..5e138298 100644 --- a/src/metadata/normalize_model.cpp +++ b/src/metadata/normalize_model.cpp @@ -399,6 +399,7 @@ void LibRaw::GetNormalizedModel() { SonyID_ZV_E10M2, "ZV-E10M2"}, { SonyID_ILME_FX2, "ILME-FX2"}, { SonyID_ILCE_7M5, "ILCE-7M5"}, + { SonyID_ILCE_7RM6, "ILCE-7RM6"}, }; static const char *orig; diff --git a/src/metadata/sony.cpp b/src/metadata/sony.cpp index 497c477b..3eb52d58 100644 --- a/src/metadata/sony.cpp +++ b/src/metadata/sony.cpp @@ -338,6 +338,8 @@ void LibRaw::setSonyBodyFeatures(unsigned long long id) { LIBRAW_SONY_Tag2010None, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, {SonyID_ILCE_7M5, sbfILCE_FF, LIBRAW_SONY_Tag2010None, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, + {SonyID_ILCE_7RM6, sbfILCE_FF, + LIBRAW_SONY_Tag2010None, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}, {SonyID_ILCE_7RM3A, sbfILCE_FF, LIBRAW_SONY_Tag2010i, 0x0320, 0x019f, 0x024b, 0x024c, 0x0208}, {SonyID_ILCE_7RM4A, sbfILCE_FF, @@ -449,6 +451,7 @@ void LibRaw::setSonyBodyFeatures(unsigned long long id) { break; case SonyID_ILME_FX2: case SonyID_ILCE_7M5: + case SonyID_ILCE_7RM6: case SonyID_ZV_E1: case SonyID_ILCE_6700: case SonyID_ILCE_7CR: diff --git a/src/tables/cameralist.cpp b/src/tables/cameralist.cpp index 75bf4f1f..575bf20f 100644 --- a/src/tables/cameralist.cpp +++ b/src/tables/cameralist.cpp @@ -1192,6 +1192,7 @@ static const char *static_camera_list[] = { "Sony ILCE-7RM4 (A7R IV)", "Sony ILCE-7RM4A (A7R IVA)", "Sony ILCE-7RM5 (A7R V)", + "Sony ILCE-7RM6 (A7R VI)", "Sony ILCE-7S (A7S)", "Sony ILCE-7SM2 (A7S II)", "Sony ILCE-7SM3 (A7S III)", diff --git a/src/tables/colordata.cpp b/src/tables/colordata.cpp index 0e38f4cf..c9f349a0 100644 --- a/src/tables/colordata.cpp +++ b/src/tables/colordata.cpp @@ -1747,6 +1747,8 @@ int LibRaw::adobe_coeff(unsigned make_idx, const char *t_model, { LIBRAW_CAMERAMAKER_Sony, "ILCE-7RM5", 0, 0, { 8200, -2976, -719, -4296, 12053, 2532, -429, 1282, 5774 } }, + { LIBRAW_CAMERAMAKER_Sony, "ILCE-7RM6", 0, 0, + { 11765,-5595,-1192,-3689,11507,2485,51,681,5731 } }, { LIBRAW_CAMERAMAKER_Sony, "ILCE-7RM4", 0, 0, // same CMs: ILCE-7RM4, ILCE-7RM4A { 7662, -2686,-660,-5240, 12965,2530, -796, 1508, 6167 } }, { LIBRAW_CAMERAMAKER_Sony, "ILCE-7RM3", 0, 0, // same CMs: ILCE-7RM3, ILCE-7RM3A