kopia lustrzana https://gitlab.com/sane-project/backends
genesys: Use new image pipeline for row scaling
rodzic
bf7e890fa4
commit
cd712f9f99
|
@ -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)
|
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
|
EXTRA_DIST += genesys.conf.in
|
||||||
# TODO: Why are this distributed but not compiled?
|
# 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_SOURCES = gphoto2.c gphoto2.h
|
||||||
libgphoto2_i_la_CPPFLAGS = $(AM_CPPFLAGS) $(GPHOTO2_CPPFLAGS) -DBACKEND_NAME=gphoto2
|
libgphoto2_i_la_CPPFLAGS = $(AM_CPPFLAGS) $(GPHOTO2_CPPFLAGS) -DBACKEND_NAME=gphoto2
|
||||||
|
|
|
@ -3442,10 +3442,7 @@ static void genesys_read_ordered_data(Genesys_Device* dev, SANE_Byte* destinatio
|
||||||
size_t bytes;
|
size_t bytes;
|
||||||
unsigned int channels, depth, src_pixels;
|
unsigned int channels, depth, src_pixels;
|
||||||
uint8_t *work_buffer_src;
|
uint8_t *work_buffer_src;
|
||||||
uint8_t *work_buffer_dst;
|
|
||||||
unsigned int dst_lines;
|
|
||||||
Genesys_Buffer *src_buffer;
|
Genesys_Buffer *src_buffer;
|
||||||
Genesys_Buffer *dst_buffer;
|
|
||||||
|
|
||||||
if (dev->read_active != SANE_TRUE)
|
if (dev->read_active != SANE_TRUE)
|
||||||
{
|
{
|
||||||
|
@ -3520,54 +3517,6 @@ Problems with the first approach:
|
||||||
|
|
||||||
src_buffer = &(dev->read_buffer);
|
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 */
|
/* move data to destination */
|
||||||
bytes = src_buffer->avail();
|
bytes = src_buffer->avail();
|
||||||
if (bytes > *len)
|
if (bytes > *len)
|
||||||
|
|
|
@ -46,37 +46,6 @@
|
||||||
* Conversion filters for genesys backend
|
* 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)
|
static void genesys_reverse_bits(uint8_t* src_data, uint8_t* dst_data, size_t bytes)
|
||||||
{
|
{
|
||||||
DBG_HELPER(dbg);
|
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.
|
/** Look in image for likely left/right/bottom paper edges, then crop image.
|
||||||
*/
|
*/
|
||||||
static void genesys_crop(Genesys_Scanner* s)
|
static void genesys_crop(Genesys_Scanner* s)
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -55,7 +55,6 @@ Genesys_Device::~Genesys_Device()
|
||||||
void Genesys_Device::clear()
|
void Genesys_Device::clear()
|
||||||
{
|
{
|
||||||
read_buffer.clear();
|
read_buffer.clear();
|
||||||
out_buffer.clear();
|
|
||||||
binarize_buffer.clear();
|
binarize_buffer.clear();
|
||||||
local_buffer.clear();
|
local_buffer.clear();
|
||||||
|
|
||||||
|
|
|
@ -282,7 +282,6 @@ struct Genesys_Device
|
||||||
SANE_Bool needs_home_ta = 0;
|
SANE_Bool needs_home_ta = 0;
|
||||||
|
|
||||||
Genesys_Buffer read_buffer;
|
Genesys_Buffer read_buffer;
|
||||||
Genesys_Buffer out_buffer;
|
|
||||||
|
|
||||||
// buffer for digital lineart from gray data
|
// buffer for digital lineart from gray data
|
||||||
Genesys_Buffer binarize_buffer;
|
Genesys_Buffer binarize_buffer;
|
||||||
|
|
|
@ -1053,9 +1053,6 @@ static void gl124_init_scan_regs(Genesys_Device* dev, const Genesys_Sensor& sens
|
||||||
dev->read_buffer.clear();
|
dev->read_buffer.clear();
|
||||||
dev->read_buffer.alloc(session.buffer_size_read);
|
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;
|
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__,
|
DBG(DBG_info, "%s: desegmented bytes to read = %lu\n", __func__,
|
||||||
|
|
|
@ -718,9 +718,6 @@ static void gl646_setup_registers(Genesys_Device* dev,
|
||||||
dev->read_buffer.clear();
|
dev->read_buffer.clear();
|
||||||
dev->read_buffer.alloc(session.buffer_size_read);
|
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);
|
build_image_pipeline(dev, session);
|
||||||
|
|
||||||
/* scan bytes to read */
|
/* scan bytes to read */
|
||||||
|
|
|
@ -1875,9 +1875,6 @@ dummy \ scanned lines
|
||||||
dev->read_buffer.clear();
|
dev->read_buffer.clear();
|
||||||
dev->read_buffer.alloc(session.buffer_size_read);
|
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);
|
build_image_pipeline(dev, session);
|
||||||
|
|
||||||
dev->read_bytes_left_after_deseg = session.output_line_bytes * session.output_line_count;
|
dev->read_bytes_left_after_deseg = session.output_line_bytes * session.output_line_count;
|
||||||
|
|
|
@ -1292,9 +1292,6 @@ static void gl843_init_scan_regs(Genesys_Device* dev, const Genesys_Sensor& sens
|
||||||
dev->read_buffer.clear();
|
dev->read_buffer.clear();
|
||||||
dev->read_buffer.alloc(session.buffer_size_read);
|
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);
|
build_image_pipeline(dev, session);
|
||||||
|
|
||||||
dev->read_bytes_left_after_deseg = session.output_line_bytes * session.output_line_count;
|
dev->read_bytes_left_after_deseg = session.output_line_bytes * session.output_line_count;
|
||||||
|
|
|
@ -918,9 +918,6 @@ static void gl846_init_scan_regs(Genesys_Device* dev, const Genesys_Sensor& sens
|
||||||
dev->read_buffer.clear();
|
dev->read_buffer.clear();
|
||||||
dev->read_buffer.alloc(session.buffer_size_read);
|
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;
|
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__,
|
DBG(DBG_info, "%s: desegmented bytes to read = %lu\n", __func__,
|
||||||
|
|
|
@ -928,9 +928,6 @@ static void gl847_init_scan_regs(Genesys_Device* dev, const Genesys_Sensor& sens
|
||||||
dev->read_buffer.clear();
|
dev->read_buffer.clear();
|
||||||
dev->read_buffer.alloc(session.buffer_size_read);
|
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;
|
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__,
|
DBG(DBG_info, "%s: desegment bytes to read = %lu\n", __func__,
|
||||||
|
|
|
@ -451,6 +451,71 @@ ImagePipelineNodeExtract::ImagePipelineNodeExtract(ImagePipelineNode& source,
|
||||||
|
|
||||||
ImagePipelineNodeExtract::~ImagePipelineNodeExtract() {}
|
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)
|
void ImagePipelineNodeExtract::get_next_row_data(std::uint8_t* out_data)
|
||||||
{
|
{
|
||||||
while (current_line_ < offset_y_) {
|
while (current_line_ < offset_y_) {
|
||||||
|
|
|
@ -383,6 +383,25 @@ private:
|
||||||
std::vector<uint8_t> cached_line_;
|
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
|
class ImagePipelineStack
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -1531,6 +1531,10 @@ void build_image_pipeline(Genesys_Device* dev, const ScanSession& session)
|
||||||
dev->pipeline.push_node<ImagePipelineNodePixelShiftLines>(shifts);
|
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)
|
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()
|
(void) size; // will be always equal to dev->pipeline.get_output_row_bytes()
|
||||||
|
|
Ładowanie…
Reference in New Issue