genesys: Use new image pipeline for row scaling

merge-requests/183/head
Povilas Kanapickas 2019-09-13 17:04:02 +03:00
rodzic bf7e890fa4
commit cd712f9f99
15 zmienionych plików z 89 dodań i 316 usunięć

Wyświetl plik

@ -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

Wyświetl plik

@ -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)

Wyświetl plik

@ -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)

Wyświetl plik

@ -1,105 +0,0 @@
/* sane - Scanner Access Now Easy.
Copyright (C) 2005 Pierre Willenbrock <pierre@pirsoft.dnsalias.org>
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;
}
}
}
}

Wyświetl plik

@ -55,7 +55,6 @@ Genesys_Device::~Genesys_Device()
void Genesys_Device::clear()
{
read_buffer.clear();
out_buffer.clear();
binarize_buffer.clear();
local_buffer.clear();

Wyświetl plik

@ -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;

Wyświetl plik

@ -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__,

Wyświetl plik

@ -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 */

Wyświetl plik

@ -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;

Wyświetl plik

@ -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;

Wyświetl plik

@ -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__,

Wyświetl plik

@ -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__,

Wyświetl plik

@ -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_) {

Wyświetl plik

@ -383,6 +383,25 @@ private:
std::vector<uint8_t> 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<uint8_t> cached_line_;
};
class ImagePipelineStack
{
public:

Wyświetl plik

@ -1531,6 +1531,10 @@ void build_image_pipeline(Genesys_Device* dev, const ScanSession& session)
dev->pipeline.push_node<ImagePipelineNodePixelShiftLines>(shifts);
}
if (session.output_pixels != session.params.get_requested_pixels()) {
dev->pipeline.push_node<ImagePipelineNodeScaleRows>(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()