diff --git a/backend/Makefile.am b/backend/Makefile.am index 22d06496b..f3747417b 100644 --- a/backend/Makefile.am +++ b/backend/Makefile.am @@ -520,7 +520,7 @@ libsane_genesys_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) libsane_genesys_la_LIBADD = $(COMMON_LIBS) libgenesys.la ../sanei/sanei_magic.lo ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_usb.lo $(MATH_LIB) $(USB_LIBS) $(RESMGR_LIBS) EXTRA_DIST += genesys.conf.in # TODO: Why are this distributed but not compiled? -EXTRA_DIST += genesys_conv.cc genesys_conv_hlp.cc +EXTRA_DIST += genesys_conv.cc libgphoto2_i_la_SOURCES = gphoto2.c gphoto2.h libgphoto2_i_la_CPPFLAGS = $(AM_CPPFLAGS) $(GPHOTO2_CPPFLAGS) -DBACKEND_NAME=gphoto2 diff --git a/backend/genesys.cc b/backend/genesys.cc index a65717de9..a8a79922c 100644 --- a/backend/genesys.cc +++ b/backend/genesys.cc @@ -3442,10 +3442,7 @@ static void genesys_read_ordered_data(Genesys_Device* dev, SANE_Byte* destinatio size_t bytes; unsigned int channels, depth, src_pixels; uint8_t *work_buffer_src; - uint8_t *work_buffer_dst; - unsigned int dst_lines; Genesys_Buffer *src_buffer; - Genesys_Buffer *dst_buffer; if (dev->read_active != SANE_TRUE) { @@ -3520,54 +3517,6 @@ Problems with the first approach: src_buffer = &(dev->read_buffer); - // maybe shrink(or enlarge) lines - if (dev->session.pipeline_needs_shrink) { - - dst_buffer = &(dev->out_buffer); - - work_buffer_src = src_buffer->get_read_pos(); - bytes = src_buffer->avail(); - -/*lines in input*/ - dst_lines = (bytes * 8) / (src_pixels * channels * depth); - - /* how many lines can be processed here? */ - /* we are greedy. we work as much as possible */ - bytes = dst_buffer->size() - dst_buffer->avail(); - - if (dst_lines > (bytes * 8) / (dev->settings.requested_pixels * channels * depth)) { - dst_lines = (bytes * 8) / (dev->settings.requested_pixels * channels * depth); - } - - bytes = (dst_lines * dev->settings.requested_pixels * channels * depth) / 8; - - work_buffer_dst = dst_buffer->get_write_pos(bytes); - - DBG(DBG_info, "%s: shrinking %d lines\n", __func__, dst_lines); - - if (dst_lines != 0) - { - if (depth == 1) - genesys_shrink_lines_1(work_buffer_src, work_buffer_dst, dst_lines, src_pixels, - dev->settings.requested_pixels, channels); - else if (depth == 8) - genesys_shrink_lines_8(work_buffer_src, work_buffer_dst, dst_lines, src_pixels, - dev->settings.requested_pixels, channels); - else - genesys_shrink_lines_16(work_buffer_src, work_buffer_dst, dst_lines, src_pixels, - dev->settings.requested_pixels, channels); - - /* we just consumed this many bytes*/ - bytes = (dst_lines * src_pixels * channels * depth) / 8; - src_buffer->consume(bytes); - - /* we just created this many bytes*/ - bytes = (dst_lines * dev->settings.requested_pixels * channels * depth) / 8; - dst_buffer->produce(bytes); - } - src_buffer = dst_buffer; - } - /* move data to destination */ bytes = src_buffer->avail(); if (bytes > *len) diff --git a/backend/genesys_conv.cc b/backend/genesys_conv.cc index 14b852e8a..6ccc791cb 100644 --- a/backend/genesys_conv.cc +++ b/backend/genesys_conv.cc @@ -46,37 +46,6 @@ * Conversion filters for genesys backend */ - -/*8 bit*/ -#define SINGLE_BYTE -#define BYTES_PER_COMPONENT 1 -#define COMPONENT_TYPE uint8_t - -#define FUNC_NAME(f) f ## _8 - -#include "genesys_conv_hlp.cc" - -#undef FUNC_NAME - -#undef COMPONENT_TYPE -#undef BYTES_PER_COMPONENT -#undef SINGLE_BYTE - -/*16 bit*/ -#define DOUBLE_BYTE -#define BYTES_PER_COMPONENT 2 -#define COMPONENT_TYPE uint16_t - -#define FUNC_NAME(f) f ## _16 - -#include "genesys_conv_hlp.cc" - -#undef FUNC_NAME - -#undef COMPONENT_TYPE -#undef BYTES_PER_COMPONENT -#undef DOUBLE_BYTE - static void genesys_reverse_bits(uint8_t* src_data, uint8_t* dst_data, size_t bytes) { DBG_HELPER(dbg); @@ -195,114 +164,6 @@ static void genesys_gray_lineart(Genesys_Device* dev, } } -/** @brief shrink or grow scanned data to fit the final scan size - * This function shrinks the scanned data it the required resolution is lower than the hardware one, - * or grows it in case it is the opposite like when motor resolution is higher than - * sensor's one. - */ -static void genesys_shrink_lines_1(uint8_t* src_data, uint8_t* dst_data, - unsigned int lines, - unsigned int src_pixels, unsigned int dst_pixels, - unsigned int channels) -{ - DBG_HELPER(dbg); - unsigned int dst_x, src_x, y, c, cnt; - unsigned int avg[3], val; - uint8_t *src = (uint8_t *) src_data; - uint8_t *dst = (uint8_t *) dst_data; - - /* choose between case where me must reduce or grow the scanned data */ - if (src_pixels > dst_pixels) - { - /* shrink data */ - /* TODO action must be taken at bit level, no bytes */ - src_pixels /= 8; - dst_pixels /= 8; - /*take first _byte_ */ - for (y = 0; y < lines; y++) - { - cnt = src_pixels / 2; - src_x = 0; - for (dst_x = 0; dst_x < dst_pixels; dst_x++) - { - while (cnt < src_pixels && src_x < src_pixels) - { - cnt += dst_pixels; - - for (c = 0; c < channels; c++) - avg[c] = *src++; - src_x++; - } - cnt -= src_pixels; - - for (c = 0; c < channels; c++) - *dst++ = avg[c]; - } - } - } - else - { - /* common case where y res is double x res */ - for (y = 0; y < lines; y++) - { - if (2 * src_pixels == dst_pixels) - { - /* double and interleave on line */ - for (c = 0; c < src_pixels/8; c++) - { - /* first 4 bits */ - val = 0; - val |= (*src & 0x80) >> 0; /* X___ ____ --> X___ ____ */ - val |= (*src & 0x80) >> 1; /* X___ ____ --> _X__ ____ */ - val |= (*src & 0x40) >> 1; /* _X__ ____ --> __X_ ____ */ - val |= (*src & 0x40) >> 2; /* _X__ ____ --> ___X ____ */ - val |= (*src & 0x20) >> 2; /* __X_ ____ --> ____ X___ */ - val |= (*src & 0x20) >> 3; /* __X_ ____ --> ____ _X__ */ - val |= (*src & 0x10) >> 3; /* ___X ____ --> ____ __X_ */ - val |= (*src & 0x10) >> 4; /* ___X ____ --> ____ ___X */ - *dst = val; - dst++; - - /* last for bits */ - val = 0; - val |= (*src & 0x08) << 4; /* ____ X___ --> X___ ____ */ - val |= (*src & 0x08) << 3; /* ____ X___ --> _X__ ____ */ - val |= (*src & 0x04) << 3; /* ____ _X__ --> __X_ ____ */ - val |= (*src & 0x04) << 2; /* ____ _X__ --> ___X ____ */ - val |= (*src & 0x02) << 2; /* ____ __X_ --> ____ X___ */ - val |= (*src & 0x02) << 1; /* ____ __X_ --> ____ _X__ */ - val |= (*src & 0x01) << 1; /* ____ ___X --> ____ __X_ */ - val |= (*src & 0x01) << 0; /* ____ ___X --> ____ ___X */ - *dst = val; - dst++; - src++; - } - } - else - { - /* TODO: since depth is 1, we must interpolate bit within bytes */ - DBG (DBG_warn, "%s: inaccurate bit expansion!\n", __func__); - cnt = dst_pixels / 2; - dst_x = 0; - for (src_x = 0; src_x < src_pixels; src_x++) - { - for (c = 0; c < channels; c++) - avg[c] = *src++; - while (cnt < dst_pixels && dst_x < dst_pixels) - { - cnt += src_pixels; - for (c = 0; c < channels; c++) - *dst++ = avg[c]; - dst_x++; - } - cnt -= dst_pixels; - } - } - } - } -} - - /** Look in image for likely left/right/bottom paper edges, then crop image. */ static void genesys_crop(Genesys_Scanner* s) diff --git a/backend/genesys_conv_hlp.cc b/backend/genesys_conv_hlp.cc deleted file mode 100644 index ad6ef98d4..000000000 --- a/backend/genesys_conv_hlp.cc +++ /dev/null @@ -1,105 +0,0 @@ -/* sane - Scanner Access Now Easy. - - Copyright (C) 2005 Pierre Willenbrock - - This file is part of the SANE package. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, - MA 02111-1307, USA. - - As a special exception, the authors of SANE give permission for - additional uses of the libraries contained in this release of SANE. - - The exception is that, if you link a SANE library with other files - to produce an executable, this does not by itself cause the - resulting executable to be covered by the GNU General Public - License. Your use of that executable is in no way restricted on - account of linking the SANE library code into it. - - This exception does not, however, invalidate any other reasons why - the executable file might be covered by the GNU General Public - License. - - If you submit changes to SANE to the maintainers to be included in - a subsequent release, you agree by submitting the changes that - those changes may be distributed with this exception intact. - - If you write modifications of your own for SANE, it is your choice - whether to permit this exception to apply to your modifications. - If you do not wish that, delete this exception notice. -*/ - -/* - * Conversion filters for genesys backend - */ - -static void FUNC_NAME(genesys_shrink_lines) (uint8_t* src_data, uint8_t* dst_data, - unsigned int lines, - unsigned int src_pixels, unsigned int dst_pixels, - unsigned int channels) -{ - DBG_HELPER(dbg); - unsigned int dst_x, src_x, y, c, cnt; - unsigned int avg[3]; - unsigned int count; - COMPONENT_TYPE *src = (COMPONENT_TYPE *)src_data; - COMPONENT_TYPE *dst = (COMPONENT_TYPE *)dst_data; - - if (src_pixels > dst_pixels) { -/*average*/ - for (c = 0; c < channels; c++) - avg[c] = 0; - for(y = 0; y < lines; y++) { - cnt = src_pixels / 2; - src_x = 0; - for (dst_x = 0; dst_x < dst_pixels; dst_x++) { - count = 0; - while (cnt < src_pixels && src_x < src_pixels) { - cnt += dst_pixels; - - for (c = 0; c < channels; c++) - avg[c] += *src++; - src_x++; - count++; - } - cnt -= src_pixels; - - for (c = 0; c < channels; c++) { - *dst++ = avg[c] / count; - avg[c] = 0; - } - } - } - } else { -/*interpolate. copy pixels*/ - for(y = 0; y < lines; y++) { - cnt = dst_pixels / 2; - dst_x = 0; - for (src_x = 0; src_x < src_pixels; src_x++) { - for (c = 0; c < channels; c++) - avg[c] = *src++; - while ((cnt < dst_pixels || src_x + 1 == src_pixels) && - dst_x < dst_pixels) { - cnt += src_pixels; - - for (c = 0; c < channels; c++) - *dst++ = avg[c]; - dst_x++; - } - cnt -= dst_pixels; - } - } - } -} diff --git a/backend/genesys_device.cc b/backend/genesys_device.cc index e497a1a96..c09f41c44 100644 --- a/backend/genesys_device.cc +++ b/backend/genesys_device.cc @@ -55,7 +55,6 @@ Genesys_Device::~Genesys_Device() void Genesys_Device::clear() { read_buffer.clear(); - out_buffer.clear(); binarize_buffer.clear(); local_buffer.clear(); diff --git a/backend/genesys_device.h b/backend/genesys_device.h index b6983626d..acf80a7e1 100644 --- a/backend/genesys_device.h +++ b/backend/genesys_device.h @@ -282,7 +282,6 @@ struct Genesys_Device SANE_Bool needs_home_ta = 0; Genesys_Buffer read_buffer; - Genesys_Buffer out_buffer; // buffer for digital lineart from gray data Genesys_Buffer binarize_buffer; diff --git a/backend/genesys_gl124.cc b/backend/genesys_gl124.cc index 16e5702ef..57e9d1510 100644 --- a/backend/genesys_gl124.cc +++ b/backend/genesys_gl124.cc @@ -1053,9 +1053,6 @@ static void gl124_init_scan_regs(Genesys_Device* dev, const Genesys_Sensor& sens dev->read_buffer.clear(); dev->read_buffer.alloc(session.buffer_size_read); - dev->out_buffer.clear(); - dev->out_buffer.alloc(session.buffer_size_out); - dev->read_bytes_left_after_deseg = session.output_line_bytes * session.output_line_count; DBG(DBG_info, "%s: desegmented bytes to read = %lu\n", __func__, diff --git a/backend/genesys_gl646.cc b/backend/genesys_gl646.cc index 3e4874191..c4b333d10 100644 --- a/backend/genesys_gl646.cc +++ b/backend/genesys_gl646.cc @@ -718,9 +718,6 @@ static void gl646_setup_registers(Genesys_Device* dev, dev->read_buffer.clear(); dev->read_buffer.alloc(session.buffer_size_read); - dev->out_buffer.clear(); - dev->out_buffer.alloc(session.buffer_size_out); - build_image_pipeline(dev, session); /* scan bytes to read */ diff --git a/backend/genesys_gl841.cc b/backend/genesys_gl841.cc index b678809aa..e810b7918 100644 --- a/backend/genesys_gl841.cc +++ b/backend/genesys_gl841.cc @@ -1875,9 +1875,6 @@ dummy \ scanned lines dev->read_buffer.clear(); dev->read_buffer.alloc(session.buffer_size_read); - dev->out_buffer.clear(); - dev->out_buffer.alloc(session.buffer_size_out); - build_image_pipeline(dev, session); dev->read_bytes_left_after_deseg = session.output_line_bytes * session.output_line_count; diff --git a/backend/genesys_gl843.cc b/backend/genesys_gl843.cc index 32606df77..727a91734 100644 --- a/backend/genesys_gl843.cc +++ b/backend/genesys_gl843.cc @@ -1292,9 +1292,6 @@ static void gl843_init_scan_regs(Genesys_Device* dev, const Genesys_Sensor& sens dev->read_buffer.clear(); dev->read_buffer.alloc(session.buffer_size_read); - dev->out_buffer.clear(); - dev->out_buffer.alloc(session.buffer_size_out); - build_image_pipeline(dev, session); dev->read_bytes_left_after_deseg = session.output_line_bytes * session.output_line_count; diff --git a/backend/genesys_gl846.cc b/backend/genesys_gl846.cc index 27f9f3f9d..7b0d3006b 100644 --- a/backend/genesys_gl846.cc +++ b/backend/genesys_gl846.cc @@ -918,9 +918,6 @@ static void gl846_init_scan_regs(Genesys_Device* dev, const Genesys_Sensor& sens dev->read_buffer.clear(); dev->read_buffer.alloc(session.buffer_size_read); - dev->out_buffer.clear(); - dev->out_buffer.alloc(session.buffer_size_out); - dev->read_bytes_left_after_deseg = session.output_line_bytes * session.output_line_count; DBG(DBG_info, "%s: desegmented bytes to read = %lu\n", __func__, diff --git a/backend/genesys_gl847.cc b/backend/genesys_gl847.cc index c7cd1cc38..21ea22ea2 100644 --- a/backend/genesys_gl847.cc +++ b/backend/genesys_gl847.cc @@ -928,9 +928,6 @@ static void gl847_init_scan_regs(Genesys_Device* dev, const Genesys_Sensor& sens dev->read_buffer.clear(); dev->read_buffer.alloc(session.buffer_size_read); - dev->out_buffer.clear(); - dev->out_buffer.alloc(session.buffer_size_out); - dev->read_bytes_left_after_deseg = session.output_line_bytes * session.output_line_count; DBG(DBG_info, "%s: desegment bytes to read = %lu\n", __func__, diff --git a/backend/genesys_image_pipeline.cc b/backend/genesys_image_pipeline.cc index 555805460..e580a216f 100644 --- a/backend/genesys_image_pipeline.cc +++ b/backend/genesys_image_pipeline.cc @@ -451,6 +451,71 @@ ImagePipelineNodeExtract::ImagePipelineNodeExtract(ImagePipelineNode& source, ImagePipelineNodeExtract::~ImagePipelineNodeExtract() {} +ImagePipelineNodeScaleRows::ImagePipelineNodeScaleRows(ImagePipelineNode& source, + std::size_t width) : + source_(source), + width_{width} +{ + cached_line_.resize(source_.get_row_bytes()); +} + +void ImagePipelineNodeScaleRows::get_next_row_data(std::uint8_t* out_data) +{ + auto src_width = source_.get_width(); + auto dst_width = width_; + + source_.get_next_row_data(cached_line_.data()); + + const auto* src_data = cached_line_.data(); + auto format = get_format(); + auto channels = get_pixel_channels(format); + + if (src_width > dst_width) { + // average + std::uint32_t counter = src_width / 2; + unsigned src_x = 0; + for (unsigned dst_x = 0; dst_x < dst_width; dst_x++) { + unsigned avg[3] = {0, 0, 0}; + unsigned count = 0; + while (counter < src_width && src_x < src_width) { + counter += dst_width; + + for (unsigned c = 0; c < channels; c++) { + avg[c] += get_raw_channel_from_row(src_data, src_x, c, format); + } + + src_x++; + count++; + } + counter -= src_width; + + for (unsigned c = 0; c < channels; c++) { + set_raw_channel_to_row(out_data, dst_x, c, avg[c] / count, format); + } + } + } else { + // interpolate and copy pixels + std::uint32_t counter = dst_width / 2; + unsigned dst_x = 0; + + for (unsigned src_x = 0; src_x < src_width; src_x++) { + unsigned avg[3] = {0, 0, 0}; + for (unsigned c = 0; c < channels; c++) { + avg[c] += get_raw_channel_from_row(src_data, src_x, c, format); + } + while ((counter < dst_width || src_x + 1 == src_width) && dst_x < dst_width) { + counter += src_width; + + for (unsigned c = 0; c < channels; c++) { + set_raw_channel_to_row(out_data, dst_x, c, avg[c], format); + } + dst_x++; + } + counter -= dst_width; + } + } +} + void ImagePipelineNodeExtract::get_next_row_data(std::uint8_t* out_data) { while (current_line_ < offset_y_) { diff --git a/backend/genesys_image_pipeline.h b/backend/genesys_image_pipeline.h index df5fa93d7..2a45914f0 100644 --- a/backend/genesys_image_pipeline.h +++ b/backend/genesys_image_pipeline.h @@ -383,6 +383,25 @@ private: std::vector cached_line_; }; +// A pipeline node that scales rows to the specified width by using a point filter +class ImagePipelineNodeScaleRows : public ImagePipelineNode +{ +public: + ImagePipelineNodeScaleRows(ImagePipelineNode& source, std::size_t width); + + std::size_t get_width() const override { return 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_; + std::size_t width_ = 0; + + std::vector cached_line_; +}; + class ImagePipelineStack { public: diff --git a/backend/genesys_low.cc b/backend/genesys_low.cc index 83568774f..88bf7eb70 100644 --- a/backend/genesys_low.cc +++ b/backend/genesys_low.cc @@ -1531,6 +1531,10 @@ void build_image_pipeline(Genesys_Device* dev, const ScanSession& session) dev->pipeline.push_node(shifts); } + if (session.output_pixels != session.params.get_requested_pixels()) { + dev->pipeline.push_node(session.params.get_requested_pixels()); + } + auto read_from_pipeline = [dev](std::size_t size, std::uint8_t* out_data) { (void) size; // will be always equal to dev->pipeline.get_output_row_bytes()