genesys: Add image pipeline to invert pixel values

merge-requests/442/head
Povilas Kanapickas 2020-05-09 13:29:51 +03:00
rodzic a05983ba28
commit 52cd02d78c
4 zmienionych plików z 168 dodań i 1 usunięć

Wyświetl plik

@ -319,6 +319,49 @@ bool ImagePipelineNodeSwap16BitEndian::get_next_row_data(std::uint8_t* out_data)
return got_data;
}
ImagePipelineNodeInvert::ImagePipelineNodeInvert(ImagePipelineNode& source) :
source_(source)
{
}
bool ImagePipelineNodeInvert::get_next_row_data(std::uint8_t* out_data)
{
bool got_data = source_.get_next_row_data(out_data);
auto num_values = get_width() * get_pixel_channels(source_.get_format());
auto depth = get_pixel_format_depth(source_.get_format());
switch (depth) {
case 16: {
auto* data = reinterpret_cast<std::uint16_t*>(out_data);
for (std::size_t i = 0; i < num_values; ++i) {
*data = 0xffff - *data;
data++;
}
break;
}
case 8: {
auto* data = out_data;
for (std::size_t i = 0; i < num_values; ++i) {
*data = 0xff - *data;
data++;
}
break;
}
case 1: {
auto* data = out_data;
for (std::size_t i = 0; i < num_values; ++i) {
*data = ~*data;
data++;
}
break;
}
default:
throw SaneException("Unsupported pixel depth");
}
return got_data;
}
ImagePipelineNodeMergeMonoLines::ImagePipelineNodeMergeMonoLines(ImagePipelineNode& source,
ColorOrder color_order) :
source_(source),

Wyświetl plik

@ -301,7 +301,7 @@ public:
std::size_t pixels_per_chunk);
};
// A pipeline that swaps bytes in 16-bit components on big-endian systems
// A pipeline that swaps bytes in 16-bit components and does nothing otherwise.
class ImagePipelineNodeSwap16BitEndian : public ImagePipelineNode
{
public:
@ -320,6 +320,23 @@ private:
bool needs_swapping_ = false;
};
class ImagePipelineNodeInvert : public ImagePipelineNode
{
public:
ImagePipelineNodeInvert(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(); }
bool eof() const override { return source_.eof(); }
bool get_next_row_data(std::uint8_t* out_data) override;
private:
ImagePipelineNode& source_;
};
// A pipeline node that merges 3 mono lines into a color channel
class ImagePipelineNodeMergeMonoLines : public ImagePipelineNode
{

Wyświetl plik

@ -51,6 +51,7 @@
namespace genesys {
// 16-bit values are in host endian
enum class PixelFormat
{
UNKNOWN,

Wyświetl plik

@ -282,6 +282,109 @@ void test_node_swap_16bit_endian()
ASSERT_EQ(out_data, expected_data);
}
void test_node_invert_16_bits()
{
using Data16 = std::vector<std::uint16_t>;
using Data = std::vector<std::uint8_t>;
Data16 in_data = {
0x1020, 0x3011, 0x2131,
0x1222, 0x3213, 0x2333,
0x1424, 0x3415, 0x2525,
0x1626, 0x3617, 0x2737,
};
Data in_data_8bit;
in_data_8bit.resize(in_data.size() * 2);
std::memcpy(in_data_8bit.data(), in_data.data(), in_data_8bit.size());
ImagePipelineStack stack;
stack.push_first_node<ImagePipelineNodeArraySource>(4, 1, PixelFormat::RGB161616,
std::move(in_data_8bit));
stack.push_node<ImagePipelineNodeInvert>();
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_8bit = stack.get_all_data();
Data16 out_data;
out_data.resize(out_data_8bit.size() / 2);
std::memcpy(out_data.data(), out_data_8bit.data(), out_data_8bit.size());
Data16 expected_data = {
0xefdf, 0xcfee, 0xdece,
0xeddd, 0xcdec, 0xdccc,
0xebdb, 0xcbea, 0xdada,
0xe9d9, 0xc9e8, 0xd8c8,
};
ASSERT_EQ(out_data, expected_data);
}
void test_node_invert_8_bits()
{
using Data = std::vector<std::uint8_t>;
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<ImagePipelineNodeArraySource>(8, 1, PixelFormat::RGB888,
std::move(in_data));
stack.push_node<ImagePipelineNodeInvert>();
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 = {
0xef, 0xdf, 0xcf, 0xee, 0xde, 0xce,
0xed, 0xdd, 0xcd, 0xec, 0xdc, 0xcc,
0xeb, 0xdb, 0xcb, 0xea, 0xda, 0xca,
0xe9, 0xd9, 0xc9, 0xe8, 0xd8, 0xc8,
};
ASSERT_EQ(out_data, expected_data);
}
void test_node_invert_1_bits()
{
using Data = std::vector<std::uint8_t>;
Data in_data = {
0x10, 0x20, 0x30, 0x11, 0x21, 0x31,
0x16, 0x26, 0x36, 0x17, 0x27, 0x37,
};
ImagePipelineStack stack;
stack.push_first_node<ImagePipelineNodeArraySource>(32, 1, PixelFormat::RGB111,
std::move(in_data));
stack.push_node<ImagePipelineNodeInvert>();
ASSERT_EQ(stack.get_output_width(), 32u);
ASSERT_EQ(stack.get_output_height(), 1u);
ASSERT_EQ(stack.get_output_row_bytes(), 12u);
ASSERT_EQ(stack.get_output_format(), PixelFormat::RGB111);
auto out_data = stack.get_all_data();
Data expected_data = {
0xef, 0xdf, 0xcf, 0xee, 0xde, 0xce,
0xe9, 0xd9, 0xc9, 0xe8, 0xd8, 0xc8,
};
ASSERT_EQ(out_data, expected_data);
}
void test_node_merge_mono_lines()
{
using Data = std::vector<std::uint8_t>;
@ -490,6 +593,9 @@ void test_image_pipeline()
test_node_deinterleave_lines_i8();
test_node_deinterleave_lines_rgb888();
test_node_swap_16bit_endian();
test_node_invert_16_bits();
test_node_invert_8_bits();
test_node_invert_1_bits();
test_node_merge_mono_lines();
test_node_split_mono_lines();
test_node_component_shift_lines();