From 0b1bfa3f1201b5cfa9e93ecbc4fcf00a57d6b63d Mon Sep 17 00:00:00 2001 From: Povilas Kanapickas Date: Fri, 13 Sep 2019 17:04:00 +0300 Subject: [PATCH] genesys: Swap 16-bit pixel endian on big endian machines --- backend/genesys_conv_hlp.cc | 19 ------ backend/genesys_image_pipeline.cc | 23 +++++++ backend/genesys_image_pipeline.h | 17 +++++ backend/genesys_low.cc | 6 ++ .../backend/genesys/tests_image_pipeline.cc | 67 ++++++++++++++++++- 5 files changed, 111 insertions(+), 21 deletions(-) diff --git a/backend/genesys_conv_hlp.cc b/backend/genesys_conv_hlp.cc index 17e2e61f3..7f993256e 100644 --- a/backend/genesys_conv_hlp.cc +++ b/backend/genesys_conv_hlp.cc @@ -45,25 +45,6 @@ * Conversion filters for genesys backend */ -#if defined(DOUBLE_BYTE) && defined(WORDS_BIGENDIAN) -static void FUNC_NAME(genesys_reorder_components_endian) (uint8_t* src_data, uint8_t* dst_data, - unsigned int lines, unsigned int pixels, - unsigned int channels) -{ - DBG_HELPER(dbg); - unsigned int c; - uint8_t *src = src_data; - uint8_t *dst = dst_data; - - for(c = 0; c < lines * pixels * channels; c++) { - *dst++ = src[1]; - *dst++ = src[0]; - src += 2; - } -} -#endif /*defined(DOUBLE_BYTE) && defined(WORDS_BIGENDIAN)*/ - - static void FUNC_NAME(genesys_reverse_ccd) (uint8_t* src_data, uint8_t* dst_data, unsigned int lines, unsigned int components_per_line, unsigned int *ccd_shift, unsigned int component_count) diff --git a/backend/genesys_image_pipeline.cc b/backend/genesys_image_pipeline.cc index 25e55d5e1..555805460 100644 --- a/backend/genesys_image_pipeline.cc +++ b/backend/genesys_image_pipeline.cc @@ -210,6 +210,29 @@ ImagePipelineNodeDeinterleaveLines::ImagePipelineNodeDeinterleaveLines( interleaved_lines, pixels_per_chunk) {} +ImagePipelineNodeSwap16BitEndian::ImagePipelineNodeSwap16BitEndian(ImagePipelineNode& source) : + source_(source), + needs_swapping_{false} +{ + if (get_pixel_format_depth(source_.get_format()) == 16) { + needs_swapping_ = true; + } else { + DBG(DBG_info, "%s: this pipeline node does nothing for non 16-bit formats", __func__); + } +} + +void ImagePipelineNodeSwap16BitEndian::get_next_row_data(std::uint8_t* out_data) +{ + source_.get_next_row_data(out_data); + if (needs_swapping_) { + std::size_t pixels = get_row_bytes() / 2; + for (std::size_t i = 0; i < pixels; ++i) { + std::swap(*out_data, *(out_data + 1)); + out_data += 2; + } + } +} + ImagePipelineNodeMergeMonoLines::ImagePipelineNodeMergeMonoLines(ImagePipelineNode& source, ColorOrder color_order) : source_(source), diff --git a/backend/genesys_image_pipeline.h b/backend/genesys_image_pipeline.h index 4bb456fdd..df5fa93d7 100644 --- a/backend/genesys_image_pipeline.h +++ b/backend/genesys_image_pipeline.h @@ -248,6 +248,23 @@ public: std::size_t pixels_per_chunk); }; +// A pipeline that swaps bytes in 16-bit components on big-endian systems +class ImagePipelineNodeSwap16BitEndian : public ImagePipelineNode +{ +public: + ImagePipelineNodeSwap16BitEndian(ImagePipelineNode& source); + + std::size_t get_width() const override { return source_.get_width(); } + std::size_t get_height() const override { return source_.get_height(); } + PixelFormat get_format() const override { return source_.get_format(); } + + void get_next_row_data(std::uint8_t* out_data) override; + +private: + ImagePipelineNode& source_; + bool needs_swapping_ = false; +}; + // A pipeline node that merges 3 mono lines into a color channel class ImagePipelineNodeMergeMonoLines : public ImagePipelineNode { diff --git a/backend/genesys_low.cc b/backend/genesys_low.cc index b65ec422a..39a4b13e0 100644 --- a/backend/genesys_low.cc +++ b/backend/genesys_low.cc @@ -1501,6 +1501,12 @@ void build_image_pipeline(Genesys_Device* dev, const ScanSession& session) get_fake_usb_buffer_model(session), read_data_from_usb); } +#ifdef WORDS_BIGENDIAN + if (get_pixel_format_depth(format) == 16) { + dev->pipeline.push_node(); + } +#endif + if (dev->model->is_cis && session.params.channels == 3) { dev->pipeline.push_node(dev->model->line_mode_color_order); } diff --git a/testsuite/backend/genesys/tests_image_pipeline.cc b/testsuite/backend/genesys/tests_image_pipeline.cc index 3cc2ecd24..5ebc0def8 100644 --- a/testsuite/backend/genesys/tests_image_pipeline.cc +++ b/testsuite/backend/genesys/tests_image_pipeline.cc @@ -175,7 +175,7 @@ void test_node_desegment_1_line() ASSERT_EQ(out_data, expected_data); } -void test_node_deinterleave_lines() +void test_node_deinterleave_lines_i8() { using Data = std::vector; @@ -203,6 +203,67 @@ void test_node_deinterleave_lines() ASSERT_EQ(out_data, expected_data); } +void test_node_deinterleave_lines_rgb888() +{ + using Data = std::vector; + + Data in_data = { + 1, 2, 3, 7, 8, 9, 13, 14, 15, 19, 20, 21, + 4, 5, 6, 10, 11, 12, 16, 17, 18, 22, 23, 24, + }; + + ImagePipelineStack stack; + stack.push_first_node(4, 2, PixelFormat::RGB888, + std::move(in_data)); + stack.push_node(2, 1); + + ASSERT_EQ(stack.get_output_width(), 8u); + ASSERT_EQ(stack.get_output_height(), 1u); + ASSERT_EQ(stack.get_output_row_bytes(), 24u); + ASSERT_EQ(stack.get_output_format(), PixelFormat::RGB888); + + auto out_data = stack.get_all_data(); + + Data expected_data; + expected_data.resize(24, 0); + std::iota(expected_data.begin(), expected_data.end(), 1); // will fill with 1, 2, 3, ..., 20 + + ASSERT_EQ(out_data, expected_data); +} + +void test_node_swap_16bit_endian() +{ + using Data = std::vector; + + Data in_data = { + 0x10, 0x20, 0x30, 0x11, 0x21, 0x31, + 0x12, 0x22, 0x32, 0x13, 0x23, 0x33, + 0x14, 0x24, 0x34, 0x15, 0x25, 0x35, + 0x16, 0x26, 0x36, 0x17, 0x27, 0x37, + }; + + ImagePipelineStack stack; + stack.push_first_node(4, 1, PixelFormat::RGB161616, + std::move(in_data)); + stack.push_node(); + + ASSERT_EQ(stack.get_output_width(), 4u); + ASSERT_EQ(stack.get_output_height(), 1u); + ASSERT_EQ(stack.get_output_row_bytes(), 24u); + ASSERT_EQ(stack.get_output_format(), PixelFormat::RGB161616); + + auto out_data = stack.get_all_data(); + + Data expected_data = { + 0x20, 0x10, 0x11, 0x30, 0x31, 0x21, + 0x22, 0x12, 0x13, 0x32, 0x33, 0x23, + 0x24, 0x14, 0x15, 0x34, 0x35, 0x25, + 0x26, 0x16, 0x17, 0x36, 0x37, 0x27, + }; + + ASSERT_EQ(out_data, expected_data); +} + void test_node_merge_mono_lines() { using Data = std::vector; @@ -335,7 +396,9 @@ void test_image_pipeline() test_node_buffered_callable_source(); test_node_format_convert(); test_node_desegment_1_line(); - test_node_deinterleave_lines(); + test_node_deinterleave_lines_i8(); + test_node_deinterleave_lines_rgb888(); + test_node_swap_16bit_endian(); test_node_merge_mono_lines(); test_node_split_mono_lines(); test_node_component_shift_lines();