From ab21f77b95f24c2f4470d9b8b4ed525ac14aee90 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Mon, 1 Jan 2024 16:09:04 -0800 Subject: [PATCH] Implement Sony Pixel Shift for LibRaw --- rtengine/dcraw.h | 10 +++++++ rtengine/rawimage.cc | 66 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+) diff --git a/rtengine/dcraw.h b/rtengine/dcraw.h index 2bf8f2965..a6551b515 100644 --- a/rtengine/dcraw.h +++ b/rtengine/dcraw.h @@ -136,6 +136,15 @@ protected: ushort *linebuf[_ltotal]; }; + /** + * Metadata for merged pixel-shift image. + */ + struct MergedPixelshift + { + bool is_merged_pixelshift = false; + unsigned sub_frame_shot_select; + }; + int fuji_total_lines, fuji_total_blocks, fuji_block_width, fuji_bits, fuji_raw_type; ushort raw_height, raw_width, height, width, top_margin, left_margin; @@ -162,6 +171,7 @@ protected: ThreeValBool RT_matrix_from_constant; std::string RT_software; double RT_baseline_exposure; + struct MergedPixelshift merged_pixelshift; struct PanasonicRW2Info { ushort bpp; diff --git a/rtengine/rawimage.cc b/rtengine/rawimage.cc index c7aca8b05..51ef67630 100644 --- a/rtengine/rawimage.cc +++ b/rtengine/rawimage.cc @@ -505,6 +505,22 @@ int RawImage::loadRaw(bool loadData, unsigned int imageNum, bool closeFile, Prog libraw->imgdata.rawparams.shot_select = shot_select; int err = libraw->open_buffer(ifp->data, ifp->size); + + merged_pixelshift.is_merged_pixelshift = + err == LIBRAW_SUCCESS && + (strncmp(libraw->unpack_function_name(), "sony_arq_load_raw", 17) == 0 && + libraw->imgdata.idata.raw_count == 1 && + libraw->imgdata.idata.colors == 4); + + if (err == LIBRAW_REQUEST_FOR_NONEXISTENT_IMAGE || (merged_pixelshift.is_merged_pixelshift && shot_select)) { + // Try again last valid frame. Sony Pixel Shift, for example, has a + // single frame, but we want to represent the data as four. + shot_select = merged_pixelshift.is_merged_pixelshift ? shot_select / 4 : shot_select; + shot_select = std::min(shot_select, std::max(libraw->imgdata.idata.raw_count, 1u) - 1); + libraw->imgdata.rawparams.shot_select = shot_select; + err = libraw->open_buffer(ifp->data, ifp->size); + } + if (err == LIBRAW_FILE_UNSUPPORTED || err == LIBRAW_TOO_BIG) { // fallback to the internal one return err; @@ -532,6 +548,18 @@ int RawImage::loadRaw(bool loadData, unsigned int imageNum, bool closeFile, Prog colors = d.colors; tiff_bps = 0; + if (merged_pixelshift.is_merged_pixelshift || + (strncmp(libraw->unpack_function_name(), "sony_arq_load_raw", 17) == 0 && + is_raw == 1 && colors == 4)) { + // Represent merged pixelshift as 4 sub-frames. + merged_pixelshift.is_merged_pixelshift = true; + merged_pixelshift.sub_frame_shot_select = imageNum % 4; + + filters = 0x94949494; + colors = 3; + is_raw = 4; + } + for (int i = 0; i < 6; ++i) { for (int j = 0; j < 6; ++j) { xtrans[i][j] = d.xtrans[i][j]; @@ -576,6 +604,9 @@ int RawImage::loadRaw(bool loadData, unsigned int imageNum, bool closeFile, Prog cam_mul[i] = cd.cam_mul[i]; pre_mul[i] = cd.pre_mul[i]; } + if (merged_pixelshift.is_merged_pixelshift) { + pre_mul[3] = 0.f; // 4th value is undefined after reducing to 3 colors. + } for (int i = 0; i < 3; ++i) { for (int j = 0; j < 4; ++j) { @@ -1102,6 +1133,41 @@ float** RawImage::compress_image(unsigned int frameNum, bool freeImage) delete [] float_raw_image; float_raw_image = nullptr; + } else if (merged_pixelshift.is_merged_pixelshift) { + // Frame 0 is not shifted. Frame 1 is shifted down. Frame 2 is shifted + // down and right. Frame 3 is shifted right. + int h_shift = (merged_pixelshift.sub_frame_shot_select >> 1) & 1; + int v_shift = ((merged_pixelshift.sub_frame_shot_select + 1u) >> 1) & 1; + + // Reset edges to 0. + for (int row = 0; row < v_shift; ++row) { + for (int col = 0; col < width; ++col) { + this->data[row][col] = 0; + } + } + for (int col = 0; col < h_shift; ++col) { + for (int row = 0; row < height; ++row) { + this->data[row][col] = 0; + } + } + + const int image_v_shift = top_margin - v_shift; + const int image_h_shift = left_margin - h_shift; + const unsigned original_filters = filters; + + filters = 0xb4b4b4b4; // R G1 B G2. + +#ifdef _OPENMP + #pragma omp parallel for +#endif + + for (int row = v_shift; row < height; row++) { + for (int col = h_shift; col < width; col++) { + this->data[row][col] = image[(row + image_v_shift) * iwidth + col + image_h_shift][FC(row, col)]; + } + } + + filters = original_filters; } else if (filters != 0 && !isXtrans()) { #ifdef _OPENMP #pragma omp parallel for