kopia lustrzana https://gitlab.com/sane-project/backends
1386 wiersze
48 KiB
C
1386 wiersze
48 KiB
C
/* sane - Scanner Access Now Easy.
|
|
|
|
Copyright (C) 1997, 1998, 2002, 2013 Franck Schnefra, Michel Roelofs,
|
|
Emmanuel Blot, Mikko Tyolajarvi, David Mosberger-Tang, Wolfgang Goeller,
|
|
Petter Reinholdtsen, Gary Plewa, Sebastien Sable, Max Ushakov,
|
|
Andrew Goodbody, Oliver Schwartz and Kevin Charter
|
|
|
|
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.
|
|
|
|
This file is a component of the implementation of a backend for many
|
|
of the AGFA SnapScan and Acer Vuego/Prisa flatbed scanners. */
|
|
|
|
|
|
/* $Id$
|
|
SnapScan backend data sources (implementation) */
|
|
|
|
/**************************************************************************************
|
|
If you get confused from all the structs (like I did when I first saw them),
|
|
think of it as "C++ in C". If you're accustomed to OO and UML maybe the
|
|
following diagram helps you to make sense of it:
|
|
|
|
------------------------
|
|
! Source !
|
|
------------------------
|
|
!pss: SnapScan_Scanner*!
|
|
------------------------ +psub
|
|
!init() = 0 !-----------------
|
|
!remaining() = 0 ! !
|
|
!bytesPerLine() ! !
|
|
!pixelsPerLine() ! !
|
|
!get() = 0 ! !{TransformerSource forwards
|
|
!done() = 0 ! ! function calls to corres-
|
|
------------------------ ! ponding functions in psub}
|
|
^ !
|
|
/_\ !
|
|
! !
|
|
-------------------------------------------------- /\
|
|
! ! ! ! \/
|
|
------------- ------------- ------------- -------------------
|
|
!SCSISource ! ! FDSource ! !BufSource ! !TransformerSource!
|
|
============= ============= ============= ===================
|
|
!remaining()! !remaining()! !remaining()! !init() !
|
|
!get() ! !get() ! !get() ! !remaining() !
|
|
!done() ! !done() ! !done() ! !bytesPerLine() !
|
|
!init() ! !init() ! !init() ! !pixelsPerLine() !
|
|
------------- ------------- ------------- !get() !
|
|
!done() !
|
|
-------------------
|
|
^
|
|
/_\
|
|
!
|
|
------------------------------------
|
|
! ! !
|
|
---------------- ------------- -------------
|
|
! Expander ! ! RGBRouter ! ! Inverter !
|
|
================ ============= =============
|
|
!remaining() ! !remaining()! !remaining()!
|
|
!bytesPerLine()! !get() ! !get() !
|
|
!get() ! !done() ! !done() !
|
|
!done() ! !init() ! !init() !
|
|
!init() ! ------------- -------------
|
|
----------------
|
|
All instances of the descendants of TransformerSource can be chained together. For
|
|
color scanning, a typical source chain would consist of an RGBRouter sitting on top
|
|
of a SCSISource. In the get() method, RGBRouter will then call the get() method of
|
|
the subsource, process the data and return it.
|
|
|
|
I hope this makes sense to you (and I got the right idea of the original author's
|
|
intention).
|
|
***********************************************************************************/
|
|
|
|
#ifndef __FUNCTION__
|
|
#define __FUNCTION__ "(undef)"
|
|
#endif
|
|
|
|
static SANE_Status Source_init (Source *pself,
|
|
SnapScan_Scanner *pss,
|
|
SourceRemaining remaining,
|
|
SourceBytesPerLine bytesPerLine,
|
|
SourcePixelsPerLine pixelsPerLine,
|
|
SourceGet get,
|
|
SourceDone done)
|
|
{
|
|
pself->pss = pss;
|
|
pself->remaining = remaining;
|
|
pself->bytesPerLine = bytesPerLine;
|
|
pself->pixelsPerLine = pixelsPerLine;
|
|
pself->get = get;
|
|
pself->done = done;
|
|
return SANE_STATUS_GOOD;
|
|
}
|
|
|
|
/* these are defaults, normally used only by base sources */
|
|
|
|
static SANE_Int Source_bytesPerLine (Source *pself)
|
|
{
|
|
return pself->pss->bytes_per_line;
|
|
}
|
|
|
|
static SANE_Int Source_pixelsPerLine (Source *pself)
|
|
{
|
|
return pself->pss->pixels_per_line;
|
|
}
|
|
|
|
/**********************************************************************/
|
|
|
|
/* the base sources */
|
|
typedef enum
|
|
{
|
|
SCSI_SRC,
|
|
FD_SRC,
|
|
BUF_SRC
|
|
} BaseSourceType;
|
|
|
|
|
|
typedef struct
|
|
{
|
|
SOURCE_GUTS;
|
|
SANE_Int scsi_buf_pos; /* current position in scsi buffer */
|
|
SANE_Int scsi_buf_max; /* data limit */
|
|
SANE_Int absolute_max; /* largest possible data read */
|
|
} SCSISource;
|
|
|
|
static SANE_Int SCSISource_remaining (Source *pself)
|
|
{
|
|
SCSISource *ps = (SCSISource *) pself;
|
|
return ps->pss->bytes_remaining + (ps->scsi_buf_max - ps->scsi_buf_pos);
|
|
}
|
|
|
|
static SANE_Status SCSISource_get (Source *pself,
|
|
SANE_Byte *pbuf,
|
|
SANE_Int *plen)
|
|
{
|
|
SCSISource *ps = (SCSISource *) pself;
|
|
SANE_Status status = SANE_STATUS_GOOD;
|
|
SANE_Int remaining = *plen;
|
|
char* me = "SCSISource_get";
|
|
|
|
DBG (DL_CALL_TRACE, "%s\n", me);
|
|
while (remaining > 0
|
|
&& pself->remaining(pself) > 0
|
|
&& status == SANE_STATUS_GOOD
|
|
&& !cancelRead)
|
|
{
|
|
SANE_Int ndata = ps->scsi_buf_max - ps->scsi_buf_pos;
|
|
DBG (DL_DATA_TRACE, "%s: ndata %d; remaining %d\n", me, ndata, remaining);
|
|
if (ndata == 0)
|
|
{
|
|
ps->pss->expected_read_bytes = MIN((size_t)ps->absolute_max,
|
|
ps->pss->bytes_remaining);
|
|
ps->scsi_buf_pos = 0;
|
|
ps->scsi_buf_max = 0;
|
|
status = scsi_read (ps->pss, READ_IMAGE);
|
|
if (status != SANE_STATUS_GOOD)
|
|
break;
|
|
ps->scsi_buf_max = ps->pss->read_bytes;
|
|
ndata = ps->pss->read_bytes;
|
|
ps->pss->bytes_remaining -= ps->pss->read_bytes;
|
|
DBG (DL_DATA_TRACE, "%s: pos: %d; max: %d; expected: %lu; read: %lu\n",
|
|
me, ps->scsi_buf_pos, ps->scsi_buf_max, (u_long) ps->pss->expected_read_bytes,
|
|
(u_long) ps->pss->read_bytes);
|
|
}
|
|
ndata = MIN(ndata, remaining);
|
|
memcpy (pbuf, ps->pss->buf + ps->scsi_buf_pos, (size_t)ndata);
|
|
pbuf += ndata;
|
|
ps->scsi_buf_pos += ndata;
|
|
remaining -= ndata;
|
|
}
|
|
*plen -= remaining;
|
|
return status;
|
|
}
|
|
|
|
static SANE_Status SCSISource_done (Source *pself)
|
|
{
|
|
DBG(DL_MINOR_INFO, "SCSISource_done\n");
|
|
UNREFERENCED_PARAMETER(pself);
|
|
return SANE_STATUS_GOOD;
|
|
}
|
|
|
|
static SANE_Status SCSISource_init (SCSISource *pself, SnapScan_Scanner *pss)
|
|
{
|
|
SANE_Status status = Source_init ((Source *) pself, pss,
|
|
SCSISource_remaining,
|
|
Source_bytesPerLine,
|
|
Source_pixelsPerLine,
|
|
SCSISource_get,
|
|
SCSISource_done);
|
|
if (status == SANE_STATUS_GOOD)
|
|
{
|
|
pself->scsi_buf_max = 0;
|
|
pself->scsi_buf_pos = 0;
|
|
pself->absolute_max =
|
|
(pss->phys_buf_sz/pss->bytes_per_line)*pss->bytes_per_line;
|
|
}
|
|
return status;
|
|
}
|
|
|
|
/* File sources */
|
|
|
|
typedef struct
|
|
{
|
|
SOURCE_GUTS;
|
|
int fd;
|
|
SANE_Int bytes_remaining;
|
|
} FDSource;
|
|
|
|
static SANE_Int FDSource_remaining (Source *pself)
|
|
{
|
|
FDSource *ps = (FDSource *) pself;
|
|
return ps->bytes_remaining;
|
|
}
|
|
|
|
static SANE_Status FDSource_get (Source *pself, SANE_Byte *pbuf, SANE_Int *plen)
|
|
{
|
|
SANE_Status status = SANE_STATUS_GOOD;
|
|
FDSource *ps = (FDSource *) pself;
|
|
SANE_Int remaining = *plen;
|
|
|
|
while (remaining > 0
|
|
&& pself->remaining(pself) > 0
|
|
&& status == SANE_STATUS_GOOD)
|
|
{
|
|
SANE_Int bytes_read = read (ps->fd, pbuf, remaining);
|
|
if (bytes_read == -1)
|
|
{
|
|
if (errno == EAGAIN)
|
|
{
|
|
/* No data currently available */
|
|
break;
|
|
}
|
|
/* It's an IO error */
|
|
DBG (DL_MAJOR_ERROR, "%s: read failed: %s\n",
|
|
__FUNCTION__, strerror(errno));
|
|
status = SANE_STATUS_IO_ERROR;
|
|
}
|
|
else if (bytes_read == 0)
|
|
{
|
|
/* EOF of current reading */
|
|
DBG(DL_DATA_TRACE, "%s: EOF\n",__FUNCTION__);
|
|
break;
|
|
}
|
|
ps->bytes_remaining -= bytes_read;
|
|
remaining -= bytes_read;
|
|
pbuf += bytes_read;
|
|
}
|
|
*plen -= remaining;
|
|
return status;
|
|
}
|
|
|
|
static SANE_Status FDSource_done (Source *pself)
|
|
{
|
|
close(((FDSource *) pself)->fd);
|
|
return SANE_STATUS_GOOD;
|
|
}
|
|
|
|
static SANE_Status FDSource_init (FDSource *pself,
|
|
SnapScan_Scanner *pss,
|
|
int fd)
|
|
{
|
|
SANE_Status status = Source_init ((Source *) pself,
|
|
pss,
|
|
FDSource_remaining,
|
|
Source_bytesPerLine,
|
|
Source_pixelsPerLine,
|
|
FDSource_get,
|
|
FDSource_done);
|
|
if (status == SANE_STATUS_GOOD)
|
|
{
|
|
pself->fd = fd;
|
|
pself->bytes_remaining = pss->bytes_per_line * (pss->lines + pss->chroma);
|
|
}
|
|
return status;
|
|
}
|
|
|
|
|
|
/* buffer sources simply read from a pre-filled buffer; we have these
|
|
so that we can include source chain processing overhead in the
|
|
measure_transfer_rate() function */
|
|
|
|
typedef struct
|
|
{
|
|
SOURCE_GUTS;
|
|
SANE_Byte *buf;
|
|
SANE_Int buf_size;
|
|
SANE_Int buf_pos;
|
|
} BufSource;
|
|
|
|
static SANE_Int BufSource_remaining (Source *pself)
|
|
{
|
|
BufSource *ps = (BufSource *) pself;
|
|
return ps->buf_size - ps->buf_pos;
|
|
}
|
|
|
|
static SANE_Status BufSource_get (Source *pself,
|
|
SANE_Byte *pbuf,
|
|
SANE_Int *plen)
|
|
{
|
|
BufSource *ps = (BufSource *) pself;
|
|
SANE_Status status = SANE_STATUS_GOOD;
|
|
SANE_Int to_move = MIN(*plen, pself->remaining(pself));
|
|
if (to_move == 0)
|
|
{
|
|
status = SANE_STATUS_EOF;
|
|
}
|
|
else
|
|
{
|
|
memcpy (pbuf, ps->buf + ps->buf_pos, to_move);
|
|
ps->buf_pos += to_move;
|
|
*plen = to_move;
|
|
}
|
|
return status;
|
|
}
|
|
|
|
static SANE_Status BufSource_done (Source *pself)
|
|
{
|
|
UNREFERENCED_PARAMETER(pself);
|
|
return SANE_STATUS_GOOD;
|
|
}
|
|
|
|
static SANE_Status BufSource_init (BufSource *pself,
|
|
SnapScan_Scanner *pss,
|
|
SANE_Byte *buf,
|
|
SANE_Int buf_size)
|
|
{
|
|
SANE_Status status = Source_init ((Source *) pself,
|
|
pss,
|
|
BufSource_remaining,
|
|
Source_bytesPerLine,
|
|
Source_pixelsPerLine,
|
|
BufSource_get,
|
|
BufSource_done);
|
|
DBG(DL_DATA_TRACE, "BufSource_init: buf_size=%d\n", buf_size);
|
|
if (status == SANE_STATUS_GOOD)
|
|
{
|
|
pself->buf = buf;
|
|
pself->buf_size = buf_size;
|
|
pself->buf_pos = 0;
|
|
}
|
|
return status;
|
|
}
|
|
|
|
/* base source creation */
|
|
|
|
static SANE_Status create_base_source (SnapScan_Scanner *pss,
|
|
BaseSourceType st,
|
|
Source **pps)
|
|
{
|
|
SANE_Status status = SANE_STATUS_GOOD;
|
|
*pps = NULL;
|
|
switch (st)
|
|
{
|
|
case SCSI_SRC:
|
|
*pps = (Source *) malloc(sizeof(SCSISource));
|
|
if (*pps == NULL)
|
|
{
|
|
DBG (DL_MAJOR_ERROR, "failed to allocate SCSISource");
|
|
status = SANE_STATUS_NO_MEM;
|
|
}
|
|
else
|
|
{
|
|
status = SCSISource_init ((SCSISource *) *pps, pss);
|
|
}
|
|
break;
|
|
case FD_SRC:
|
|
*pps = (Source *) malloc(sizeof(FDSource));
|
|
if (*pps == NULL)
|
|
{
|
|
DBG (DL_MAJOR_ERROR, "failed to allocate FDSource");
|
|
status = SANE_STATUS_NO_MEM;
|
|
}
|
|
else
|
|
{
|
|
status = FDSource_init ((FDSource *) *pps, pss, pss->rpipe[0]);
|
|
}
|
|
break;
|
|
case BUF_SRC:
|
|
*pps = (Source *) malloc(sizeof(BufSource));
|
|
if (*pps == NULL)
|
|
{
|
|
DBG (DL_MAJOR_ERROR, "failed to allocate BufSource");
|
|
status = SANE_STATUS_NO_MEM;
|
|
}
|
|
else
|
|
{
|
|
status = BufSource_init ((BufSource *) *pps,
|
|
pss,
|
|
pss->buf,
|
|
pss->read_bytes);
|
|
}
|
|
break;
|
|
default:
|
|
DBG (DL_MAJOR_ERROR, "illegal base source type %d", st);
|
|
break;
|
|
}
|
|
return status;
|
|
}
|
|
|
|
/**********************************************************************/
|
|
|
|
/* The transformer sources */
|
|
|
|
#define TX_SOURCE_GUTS \
|
|
SOURCE_GUTS;\
|
|
Source *psub /* sub-source */
|
|
|
|
typedef struct
|
|
{
|
|
TX_SOURCE_GUTS;
|
|
} TxSource;
|
|
|
|
static SANE_Int TxSource_remaining (Source *pself)
|
|
{
|
|
TxSource *ps = (TxSource *) pself;
|
|
return ps->psub->remaining(ps->psub);
|
|
}
|
|
|
|
static SANE_Int TxSource_bytesPerLine (Source *pself)
|
|
{
|
|
TxSource *ps = (TxSource *) pself;
|
|
return ps->psub->bytesPerLine(ps->psub);
|
|
}
|
|
|
|
static SANE_Int TxSource_pixelsPerLine (Source *pself)
|
|
{
|
|
TxSource *ps = (TxSource *) pself;
|
|
return ps->psub->pixelsPerLine(ps->psub);
|
|
}
|
|
|
|
static SANE_Status TxSource_get (Source *pself, SANE_Byte *pbuf, SANE_Int *plen)
|
|
{
|
|
TxSource *ps = (TxSource *) pself;
|
|
return ps->psub->get(ps->psub, pbuf, plen);
|
|
}
|
|
|
|
static SANE_Status TxSource_done (Source *pself)
|
|
{
|
|
TxSource *ps = (TxSource *) pself;
|
|
SANE_Status status = ps->psub->done(ps->psub);
|
|
free(ps->psub);
|
|
ps->psub = NULL;
|
|
return status;
|
|
}
|
|
|
|
static SANE_Status TxSource_init (TxSource *pself,
|
|
SnapScan_Scanner *pss,
|
|
SourceRemaining remaining,
|
|
SourceBytesPerLine bytesPerLine,
|
|
SourcePixelsPerLine pixelsPerLine,
|
|
SourceGet get,
|
|
SourceDone done,
|
|
Source *psub)
|
|
{
|
|
SANE_Status status = Source_init((Source *) pself,
|
|
pss,
|
|
remaining,
|
|
bytesPerLine,
|
|
pixelsPerLine,
|
|
get,
|
|
done);
|
|
if (status == SANE_STATUS_GOOD)
|
|
pself->psub = psub;
|
|
return status;
|
|
}
|
|
|
|
/* The expander makes three-channel, one-bit, raw scanner data into
|
|
8-bit data. It is used to support the bilevel colour scanning mode */
|
|
|
|
typedef struct
|
|
{
|
|
TX_SOURCE_GUTS;
|
|
SANE_Byte *ch_buf; /* channel buffer */
|
|
SANE_Int ch_size; /* channel buffer size = #bytes in a channel */
|
|
SANE_Int ch_ndata; /* actual #bytes in channel buffer */
|
|
SANE_Int ch_pos; /* position in buffer */
|
|
SANE_Int bit; /* current bit */
|
|
SANE_Int last_bit; /* current last bit (counting down) */
|
|
SANE_Int last_last_bit; /* last bit in the last byte of the channel */
|
|
} Expander;
|
|
|
|
static SANE_Int Expander_remaining (Source *pself)
|
|
{
|
|
Expander *ps = (Expander *) pself;
|
|
SANE_Int sub_remaining = TxSource_remaining(pself);
|
|
SANE_Int sub_bits_per_channel = TxSource_pixelsPerLine(pself);
|
|
SANE_Int whole_channels = sub_remaining/ps->ch_size;
|
|
SANE_Int result = whole_channels*sub_bits_per_channel;
|
|
|
|
if (ps->ch_pos < ps->ch_size)
|
|
{
|
|
SANE_Int bits_covered = MAX((ps->ch_pos - 1)*8, 0) + 7 - ps->bit;
|
|
result += sub_bits_per_channel - bits_covered;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
static SANE_Int Expander_bytesPerLine (Source *pself)
|
|
{
|
|
return TxSource_pixelsPerLine(pself)*3;
|
|
}
|
|
|
|
static SANE_Status Expander_get (Source *pself, SANE_Byte *pbuf, SANE_Int *plen)
|
|
{
|
|
Expander *ps = (Expander *) pself;
|
|
SANE_Status status = SANE_STATUS_GOOD;
|
|
SANE_Int remaining = *plen;
|
|
|
|
while (remaining > 0
|
|
&&
|
|
pself->remaining(pself) > 0 &&
|
|
!cancelRead)
|
|
{
|
|
if (ps->ch_pos == ps->ch_ndata)
|
|
{
|
|
/* we need more data; try to get the remainder of the current
|
|
channel, or else the next channel */
|
|
SANE_Int ndata = ps->ch_size - ps->ch_ndata;
|
|
if (ndata == 0)
|
|
{
|
|
ps->ch_ndata = 0;
|
|
ps->ch_pos = 0;
|
|
ndata = ps->ch_size;
|
|
}
|
|
status = TxSource_get(pself, ps->ch_buf + ps->ch_pos, &ndata);
|
|
if (status != SANE_STATUS_GOOD)
|
|
break;
|
|
if (ndata == 0)
|
|
break;
|
|
ps->ch_ndata += ndata;
|
|
if (ps->ch_pos == (ps->ch_size - 1))
|
|
ps->last_bit = ps->last_last_bit;
|
|
else
|
|
ps->last_bit = 0;
|
|
ps->bit = 7;
|
|
}
|
|
*pbuf = ((ps->ch_buf[ps->ch_pos] >> ps->bit) & 0x01) ? 0xFF : 0x00;
|
|
pbuf++;
|
|
remaining--;
|
|
|
|
if (ps->bit == ps->last_bit)
|
|
{
|
|
ps->bit = 7;
|
|
ps->ch_pos++;
|
|
if (ps->ch_pos == (ps->ch_size - 1))
|
|
ps->last_bit = ps->last_last_bit;
|
|
else
|
|
ps->last_bit = 0;
|
|
}
|
|
else
|
|
{
|
|
ps->bit--;
|
|
}
|
|
}
|
|
|
|
*plen -= remaining;
|
|
return status;
|
|
}
|
|
|
|
static SANE_Status Expander_done (Source *pself)
|
|
{
|
|
Expander *ps = (Expander *) pself;
|
|
SANE_Status status = TxSource_done(pself);
|
|
free(ps->ch_buf);
|
|
ps->ch_buf = NULL;
|
|
ps->ch_size = 0;
|
|
ps->ch_pos = 0;
|
|
return status;
|
|
}
|
|
|
|
static SANE_Status Expander_init (Expander *pself,
|
|
SnapScan_Scanner *pss,
|
|
Source *psub)
|
|
{
|
|
SANE_Status status = TxSource_init((TxSource *) pself,
|
|
pss,
|
|
Expander_remaining,
|
|
Expander_bytesPerLine,
|
|
TxSource_pixelsPerLine,
|
|
Expander_get,
|
|
Expander_done,
|
|
psub);
|
|
if (status == SANE_STATUS_GOOD)
|
|
{
|
|
pself->ch_size = TxSource_bytesPerLine((Source *) pself)/3;
|
|
pself->ch_buf = (SANE_Byte *) malloc(pself->ch_size);
|
|
if (pself->ch_buf == NULL)
|
|
{
|
|
DBG (DL_MAJOR_ERROR,
|
|
"%s: couldn't allocate channel buffer.\n",
|
|
__FUNCTION__);
|
|
status = SANE_STATUS_NO_MEM;
|
|
}
|
|
else
|
|
{
|
|
pself->ch_ndata = 0;
|
|
pself->ch_pos = 0;
|
|
pself->last_last_bit = pself->pixelsPerLine((Source *) pself)%8;
|
|
if (pself->last_last_bit == 0)
|
|
pself->last_last_bit = 7;
|
|
pself->last_last_bit = 7 - pself->last_last_bit;
|
|
pself->bit = 7;
|
|
if (pself->ch_size > 1)
|
|
pself->last_bit = 0;
|
|
else
|
|
pself->last_bit = pself->last_last_bit;
|
|
}
|
|
}
|
|
return status;
|
|
}
|
|
|
|
static SANE_Status create_Expander (SnapScan_Scanner *pss,
|
|
Source *psub,
|
|
Source **pps)
|
|
{
|
|
SANE_Status status = SANE_STATUS_GOOD;
|
|
*pps = (Source *) malloc(sizeof(Expander));
|
|
if (*pps == NULL)
|
|
{
|
|
DBG (DL_MAJOR_ERROR,
|
|
"%s: failed to allocate Expander.\n",
|
|
__FUNCTION__);
|
|
status = SANE_STATUS_NO_MEM;
|
|
}
|
|
else
|
|
{
|
|
status = Expander_init ((Expander *) *pps, pss, psub);
|
|
}
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
This filter implements a fix for scanners that have some columns
|
|
of pixels offset. Currently it only shifts every other column
|
|
starting with the first one down ch_offset pixels.
|
|
|
|
The Deinterlacer detects if data is in SANE RGB frame format (3 bytes/pixel)
|
|
or in Grayscale (1 byte/pixel).
|
|
|
|
The first ch_offset lines of data in the output are fudged so that even indexed
|
|
add odd indexed pixels will have the same value. This is necessary because
|
|
the real pixel values of the columns that are shifted down are not
|
|
in the data for the first ch_offset lines. A better way to handle this would be to
|
|
scan in ch_offset extra lines of data, but I haven't figured out how to do this
|
|
yet.
|
|
|
|
*/
|
|
|
|
typedef struct
|
|
{
|
|
TX_SOURCE_GUTS;
|
|
SANE_Byte *ch_buf; /* channel buffer */
|
|
SANE_Int ch_size; /* channel buffer size */
|
|
SANE_Int ch_line_size; /* size of one line */
|
|
SANE_Int ch_ndata; /* actual #bytes in channel buffer */
|
|
SANE_Int ch_pos; /* position in buffer */
|
|
SANE_Int ch_bytes_per_pixel;
|
|
SANE_Bool ch_lineart;
|
|
SANE_Int ch_offset; /* The number of lines to be shifted */
|
|
SANE_Bool ch_past_init; /* flag indicating if we have enough data to shift pixels down */
|
|
SANE_Bool ch_shift_even; /* flag indicating wether even or odd pixels are shifted */
|
|
} Deinterlacer;
|
|
|
|
static SANE_Int Deinterlacer_remaining (Source *pself)
|
|
{
|
|
Deinterlacer *ps = (Deinterlacer *) pself;
|
|
SANE_Int result = TxSource_remaining(pself);
|
|
result += ps->ch_ndata - ps->ch_pos;
|
|
return result;
|
|
}
|
|
|
|
static SANE_Status Deinterlacer_get (Source *pself, SANE_Byte *pbuf, SANE_Int *plen)
|
|
{
|
|
Deinterlacer *ps = (Deinterlacer *) pself;
|
|
SANE_Status status = SANE_STATUS_GOOD;
|
|
SANE_Int remaining = *plen;
|
|
SANE_Int org_len = *plen;
|
|
char *me = "Deinterlacer_get";
|
|
|
|
DBG(DL_DATA_TRACE, "%s: remaining=%d, pself->remaining=%d, ch_ndata=%d, ch_pos=%d\n",
|
|
me, remaining, pself->remaining(pself), ps->ch_ndata, ps->ch_pos);
|
|
|
|
while (remaining > 0
|
|
&&
|
|
pself->remaining(pself) > 0 &&
|
|
!cancelRead)
|
|
{
|
|
if (ps->ch_pos % (ps->ch_line_size) == ps->ch_ndata % (ps->ch_line_size) )
|
|
{
|
|
/* we need more data; try to get the remainder of the current
|
|
line, or else the next line */
|
|
SANE_Int ndata = (ps->ch_line_size) - ps->ch_ndata % (ps->ch_line_size);
|
|
if (ps->ch_pos >= ps->ch_size)
|
|
{
|
|
/* wrap to the beginning of the buffer if we need to */
|
|
ps->ch_ndata = 0;
|
|
ps->ch_pos = 0;
|
|
ndata = ps->ch_line_size;
|
|
}
|
|
status = TxSource_get(pself, ps->ch_buf + ps->ch_pos, &ndata);
|
|
if (status != SANE_STATUS_GOOD)
|
|
break;
|
|
if (ndata == 0)
|
|
break;
|
|
ps->ch_ndata += ndata;
|
|
}
|
|
/* Handle special lineart mode: Valid pixels need to be masked */
|
|
if (ps->ch_lineart)
|
|
{
|
|
if (ps->ch_past_init)
|
|
{
|
|
if (ps->ch_shift_even)
|
|
{
|
|
/* Even columns need to be shifted, i.e. bits 1,3,5,7 -> 0xaa */
|
|
/* use valid pixels from this line and shifted pixels from ch_size lines back */
|
|
*pbuf = (ps->ch_buf[ps->ch_pos] & 0x55) |
|
|
(ps->ch_buf[(ps->ch_pos + (ps->ch_line_size)) % ps->ch_size] & 0xaa);
|
|
}
|
|
else
|
|
{
|
|
/* Odd columns need to be shifted, i.e. bits 0,2,4,6 -> 0x55 */
|
|
*pbuf = (ps->ch_buf[ps->ch_pos] & 0xaa) |
|
|
(ps->ch_buf[(ps->ch_pos + (ps->ch_line_size)) % ps->ch_size] & 0x55);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* not enough data. duplicate pixel values from previous column */
|
|
if (ps->ch_shift_even)
|
|
{
|
|
/* bits 0,2,4,6 contain valid data -> 0x55 */
|
|
SANE_Byte valid_pixel = ps->ch_buf[ps->ch_pos] & 0x55;
|
|
*pbuf = valid_pixel | (valid_pixel >> 1);
|
|
}
|
|
else
|
|
{
|
|
|
|
/* bits 1,3,5,7 contain valid data -> 0xaa */
|
|
SANE_Byte valid_pixel = ps->ch_buf[ps->ch_pos] & 0xaa;
|
|
*pbuf = valid_pixel | (valid_pixel << 1);
|
|
}
|
|
}
|
|
}
|
|
else /* colour / grayscale mode */
|
|
{
|
|
if ((ps->ch_shift_even && ((ps->ch_pos/ps->ch_bytes_per_pixel) % 2 == 0)) ||
|
|
(!ps->ch_shift_even && ((ps->ch_pos/ps->ch_bytes_per_pixel) % 2 == 1)))
|
|
{
|
|
/* the even indexed pixels need to be shifted down */
|
|
if (ps->ch_past_init){
|
|
/* We need to use data 4 lines back */
|
|
/* So we just go one forward and it will wrap around to 4 back. */
|
|
*pbuf = ps->ch_buf[(ps->ch_pos + (ps->ch_line_size)) % ps->ch_size];
|
|
}else{
|
|
/* Use data from the next pixel for even indexed pixels
|
|
if we are on the first few lines.
|
|
TODO: also we will overread the buffer if the buffer read ended
|
|
on the first pixel. */
|
|
if (ps->ch_pos % (ps->ch_line_size) == 0 )
|
|
*pbuf = ps->ch_buf[ps->ch_pos+ps->ch_bytes_per_pixel];
|
|
else
|
|
*pbuf = ps->ch_buf[ps->ch_pos-ps->ch_bytes_per_pixel];
|
|
}
|
|
}else{
|
|
/* odd indexed pixels are okay */
|
|
*pbuf = ps->ch_buf[ps->ch_pos];
|
|
}
|
|
}
|
|
/* set the flag so we know we have enough data to start shifting columns */
|
|
if (ps->ch_pos >= ps->ch_line_size * ps->ch_offset)
|
|
ps->ch_past_init = SANE_TRUE;
|
|
|
|
pbuf++;
|
|
remaining--;
|
|
ps->ch_pos++;
|
|
}
|
|
|
|
*plen -= remaining;
|
|
|
|
DBG(DL_DATA_TRACE,
|
|
"%s: Request=%d, remaining=%d, read=%d, TXSource_rem=%d, bytes_rem=%lu\n",
|
|
me,
|
|
org_len,
|
|
pself->remaining(pself),
|
|
*plen,
|
|
TxSource_remaining(pself),
|
|
(u_long) ps->pss->bytes_remaining);
|
|
return status;
|
|
}
|
|
|
|
static SANE_Status Deinterlacer_done (Source *pself)
|
|
{
|
|
Deinterlacer *ps = (Deinterlacer *) pself;
|
|
SANE_Status status = TxSource_done(pself);
|
|
free(ps->ch_buf);
|
|
ps->ch_buf = NULL;
|
|
ps->ch_size = 0;
|
|
ps->ch_line_size = 0;
|
|
ps->ch_pos = 0;
|
|
return status;
|
|
}
|
|
|
|
static SANE_Status Deinterlacer_init (Deinterlacer *pself,
|
|
SnapScan_Scanner *pss,
|
|
Source *psub)
|
|
{
|
|
SANE_Status status = TxSource_init((TxSource *) pself,
|
|
pss,
|
|
Deinterlacer_remaining,
|
|
TxSource_bytesPerLine,
|
|
TxSource_pixelsPerLine,
|
|
Deinterlacer_get,
|
|
Deinterlacer_done,
|
|
psub);
|
|
if (status == SANE_STATUS_GOOD)
|
|
{
|
|
pself->ch_shift_even = SANE_TRUE;
|
|
switch (pss->pdev->model)
|
|
{
|
|
case PERFECTION3490:
|
|
pself->ch_offset = 8;
|
|
if ((actual_mode(pss) == MD_GREYSCALE) || (actual_mode(pss) == MD_LINEART))
|
|
pself->ch_shift_even = SANE_FALSE;
|
|
break;
|
|
case PERFECTION2480:
|
|
default:
|
|
pself->ch_offset = 4;
|
|
break;
|
|
}
|
|
pself->ch_line_size = TxSource_bytesPerLine((Source *) pself);
|
|
/* We need at least ch_offset+1 lines of buffer in order
|
|
to shift up ch_offset pixels. */
|
|
pself->ch_size = pself->ch_line_size * (pself->ch_offset + 1);
|
|
pself->ch_buf = (SANE_Byte *) malloc(pself->ch_size);
|
|
if (pself->ch_buf == NULL)
|
|
{
|
|
DBG (DL_MAJOR_ERROR,
|
|
"%s: couldn't allocate channel buffer.\n",
|
|
__FUNCTION__);
|
|
status = SANE_STATUS_NO_MEM;
|
|
}
|
|
else
|
|
{
|
|
pself->ch_ndata = 0;
|
|
pself->ch_pos = 0;
|
|
pself->ch_past_init = SANE_FALSE;
|
|
if ((actual_mode(pss) == MD_GREYSCALE) || (actual_mode(pss) == MD_LINEART))
|
|
pself->ch_bytes_per_pixel = 1;
|
|
else
|
|
pself->ch_bytes_per_pixel = 3;
|
|
if (pss->bpp_scan == 16)
|
|
pself->ch_bytes_per_pixel *= 2;
|
|
}
|
|
pself->ch_lineart = (actual_mode(pss) == MD_LINEART);
|
|
}
|
|
return status;
|
|
}
|
|
|
|
static SANE_Status create_Deinterlacer (SnapScan_Scanner *pss,
|
|
Source *psub,
|
|
Source **pps)
|
|
{
|
|
SANE_Status status = SANE_STATUS_GOOD;
|
|
*pps = (Source *) malloc(sizeof(Deinterlacer));
|
|
if (*pps == NULL)
|
|
{
|
|
DBG (DL_MAJOR_ERROR,
|
|
"%s: failed to allocate Deinterlacer.\n",
|
|
__FUNCTION__);
|
|
status = SANE_STATUS_NO_MEM;
|
|
}
|
|
else
|
|
{
|
|
status = Deinterlacer_init ((Deinterlacer *) *pps, pss, psub);
|
|
}
|
|
return status;
|
|
}
|
|
|
|
/* ----------------------------------------------------- */
|
|
|
|
/* the RGB router assumes 8-bit RGB data arranged in contiguous
|
|
channels, possibly with R-G and R-B offsets, and rearranges the
|
|
data into SANE RGB frame format */
|
|
|
|
typedef struct
|
|
{
|
|
TX_SOURCE_GUTS;
|
|
SANE_Byte *cbuf; /* circular line buffer */
|
|
SANE_Byte *xbuf; /* single line buffer */
|
|
SANE_Int pos; /* current position in xbuf */
|
|
SANE_Int cb_size; /* size of the circular buffer */
|
|
SANE_Int cb_line_size;/* size of a line in the circular buffer */
|
|
SANE_Int cb_start; /* start of valid data in the circular buffer */
|
|
SANE_Int cb_finish; /* finish of valid data, for next read */
|
|
SANE_Int ch_offset[3];/* offset in cbuf */
|
|
SANE_Int round_req;
|
|
SANE_Int round_read;
|
|
} RGBRouter;
|
|
|
|
static void put_int16r (int n, u_char *p)
|
|
{
|
|
p[0] = (n & 0x00ff);
|
|
p[1] = (n & 0xff00) >> 8;
|
|
}
|
|
|
|
|
|
static SANE_Int RGBRouter_remaining (Source *pself)
|
|
{
|
|
RGBRouter *ps = (RGBRouter *) pself;
|
|
SANE_Int remaining;
|
|
if (ps->round_req == ps->cb_size)
|
|
remaining = TxSource_remaining(pself) - ps->cb_size + ps->cb_line_size;
|
|
else
|
|
remaining = TxSource_remaining(pself) + ps->cb_line_size - ps->pos;
|
|
return (remaining);
|
|
}
|
|
|
|
static SANE_Status RGBRouter_get (Source *pself,
|
|
SANE_Byte *pbuf,
|
|
SANE_Int *plen)
|
|
{
|
|
RGBRouter *ps = (RGBRouter *) pself;
|
|
SANE_Status status = SANE_STATUS_GOOD;
|
|
SANE_Int remaining = *plen;
|
|
SANE_Byte *s;
|
|
SANE_Int i, t;
|
|
SANE_Int r, g, b;
|
|
SANE_Int run_req;
|
|
SANE_Int org_len = *plen;
|
|
char *me = "RGBRouter_get";
|
|
|
|
while (remaining > 0 && pself->remaining(pself) > 0 && !cancelRead)
|
|
{
|
|
DBG(DL_DATA_TRACE, "%s: remaining=%d, pself->remaining=%d, round_req=%d, cb_size=%d\n",
|
|
me, remaining, pself->remaining(pself), ps->round_req, ps->cb_size);
|
|
/* Check if there is no valid data left from previous get */
|
|
if (ps->pos >= ps->cb_line_size)
|
|
{
|
|
/* Try to get more data. either one line or
|
|
full buffer (first time) */
|
|
do
|
|
{
|
|
run_req = ps->round_req - ps->round_read;
|
|
status = TxSource_get (pself,
|
|
ps->cbuf + ps->cb_start + ps->round_read,
|
|
&run_req);
|
|
if (status != SANE_STATUS_GOOD || run_req==0)
|
|
{
|
|
*plen -= remaining;
|
|
if ( *plen > 0 )
|
|
DBG(DL_DATA_TRACE, "%s: request=%d, read=%d\n",
|
|
me, org_len, *plen);
|
|
return status;
|
|
}
|
|
ps->round_read += run_req;
|
|
}
|
|
while ((ps->round_req > ps->round_read) && !cancelRead);
|
|
|
|
/* route RGB */
|
|
ps->cb_start = (ps->cb_start + ps->round_read)%ps->cb_size;
|
|
s = ps->xbuf;
|
|
r = (ps->cb_start + ps->ch_offset[0])%ps->cb_size;
|
|
g = (ps->cb_start + ps->ch_offset[1])%ps->cb_size;
|
|
b = (ps->cb_start + ps->ch_offset[2])%ps->cb_size;
|
|
for (i = 0; i < ps->cb_line_size/3; i++)
|
|
{
|
|
if (pself->pss->bpp_scan == 8)
|
|
{
|
|
*s++ = ps->cbuf[r++];
|
|
*s++ = ps->cbuf[g++];
|
|
*s++ = ps->cbuf[b++];
|
|
}
|
|
else if (pself->pss->pdev->model == SCANWIT2720S)
|
|
{
|
|
t = (((ps->cbuf[r+1] << 8) | ps->cbuf[r]) & 0xfff) << 4;
|
|
put_int16r (t, s);
|
|
s += 2;
|
|
r += 2;
|
|
t = (((ps->cbuf[g+1] << 8) | ps->cbuf[g]) & 0xfff) << 4;
|
|
put_int16r (t, s);
|
|
s += 2;
|
|
g += 2;
|
|
t = (((ps->cbuf[b+1] << 8) | ps->cbuf[b]) & 0xfff) << 4;
|
|
put_int16r (t, s);
|
|
s += 2;
|
|
b += 2;
|
|
i++;
|
|
}
|
|
else
|
|
{
|
|
*s++ = ps->cbuf[r++];
|
|
*s++ = ps->cbuf[r++];
|
|
*s++ = ps->cbuf[g++];
|
|
*s++ = ps->cbuf[g++];
|
|
*s++ = ps->cbuf[b++];
|
|
*s++ = ps->cbuf[b++];
|
|
i++;
|
|
}
|
|
}
|
|
|
|
/* end of reading & offsetiing whole line data;
|
|
reset valid position */
|
|
ps->pos = 0;
|
|
|
|
/* prepare for next round */
|
|
ps->round_req = ps->cb_line_size;
|
|
ps->round_read =0;
|
|
}
|
|
|
|
/* Repack the whole scan line and copy to caller's buffer */
|
|
while (remaining > 0 && ps->pos < ps->cb_line_size)
|
|
{
|
|
*pbuf++ = ps->xbuf[ps->pos++];
|
|
remaining--;
|
|
}
|
|
}
|
|
*plen -= remaining;
|
|
DBG(DL_DATA_TRACE,
|
|
"%s: Request=%d, remaining=%d, read=%d, TXSource_rem=%d, bytes_rem=%lu\n",
|
|
me,
|
|
org_len,
|
|
pself->remaining(pself),
|
|
*plen,
|
|
TxSource_remaining(pself),
|
|
(u_long) ps->pss->bytes_remaining);
|
|
return status;
|
|
}
|
|
|
|
static SANE_Status RGBRouter_done (Source *pself)
|
|
{
|
|
RGBRouter *ps = (RGBRouter *) pself;
|
|
SANE_Status status = TxSource_done(pself);
|
|
|
|
free(ps->cbuf);
|
|
free(ps->xbuf);
|
|
ps->cbuf = NULL;
|
|
ps->cb_start = -1;
|
|
ps->pos = 0;
|
|
return status;
|
|
}
|
|
|
|
static SANE_Status RGBRouter_init (RGBRouter *pself,
|
|
SnapScan_Scanner *pss,
|
|
Source *psub)
|
|
{
|
|
SANE_Status status = TxSource_init((TxSource *) pself,
|
|
pss,
|
|
RGBRouter_remaining,
|
|
TxSource_bytesPerLine,
|
|
TxSource_pixelsPerLine,
|
|
RGBRouter_get,
|
|
RGBRouter_done,
|
|
psub);
|
|
if (status == SANE_STATUS_GOOD)
|
|
{
|
|
SANE_Int lines_in_buffer = 0;
|
|
|
|
/* Size the buffer to accomodate the necessary number of scan
|
|
lines to cater for the offset between R, G and B */
|
|
lines_in_buffer = pss->chroma + 1;
|
|
pself->cb_line_size = pself->bytesPerLine((Source *) pself);
|
|
pself->cb_size = pself->cb_line_size*lines_in_buffer;
|
|
pself->pos = pself->cb_line_size;
|
|
|
|
pself->round_req = pself->cb_size;
|
|
pself->round_read = 0;
|
|
|
|
pself->cbuf = (SANE_Byte *) malloc(pself->cb_size);
|
|
pself->xbuf = (SANE_Byte *) malloc(pself->cb_line_size);
|
|
if (pself->cbuf == NULL || pself->xbuf == NULL)
|
|
{
|
|
DBG (DL_MAJOR_ERROR,
|
|
"%s: failed to allocate circular buffer.\n",
|
|
__FUNCTION__);
|
|
status = SANE_STATUS_NO_MEM;
|
|
}
|
|
else
|
|
{
|
|
SANE_Int ch;
|
|
|
|
pself->cb_start = 0;
|
|
for (ch = 0; ch < 3; ch++)
|
|
{
|
|
pself->ch_offset[ch] =
|
|
pss->chroma_offset[ch] * pself->cb_line_size
|
|
+ ch * (pself->cb_line_size / 3);
|
|
}
|
|
}
|
|
DBG(DL_MINOR_INFO, "RGBRouter_init: buf_size: %d x %d = %d\n",
|
|
pself->cb_line_size, lines_in_buffer, pself->cb_size);
|
|
DBG(DL_MINOR_INFO, "RGBRouter_init: buf offset R:%d G:%d B:%d\n",
|
|
pself->ch_offset[0], pself->ch_offset[1],pself->ch_offset[2]);
|
|
}
|
|
return status;
|
|
}
|
|
|
|
static SANE_Status create_RGBRouter (SnapScan_Scanner *pss,
|
|
Source *psub,
|
|
Source **pps)
|
|
{
|
|
static char me[] = "create_RGBRouter";
|
|
SANE_Status status = SANE_STATUS_GOOD;
|
|
|
|
DBG (DL_CALL_TRACE, "%s\n", me);
|
|
*pps = (Source *) malloc(sizeof(RGBRouter));
|
|
if (*pps == NULL)
|
|
{
|
|
DBG (DL_MAJOR_ERROR, "%s: failed to allocate RGBRouter.\n",
|
|
__FUNCTION__);
|
|
status = SANE_STATUS_NO_MEM;
|
|
}
|
|
else
|
|
{
|
|
status = RGBRouter_init ((RGBRouter *) *pps, pss, psub);
|
|
}
|
|
return status;
|
|
}
|
|
|
|
/* An Inverter is used to invert the bits in a lineart image */
|
|
|
|
typedef struct
|
|
{
|
|
TX_SOURCE_GUTS;
|
|
} Inverter;
|
|
|
|
static SANE_Status Inverter_get (Source *pself, SANE_Byte *pbuf, SANE_Int *plen)
|
|
{
|
|
SANE_Status status = TxSource_get (pself, pbuf, plen);
|
|
if (status == SANE_STATUS_GOOD)
|
|
{
|
|
int i;
|
|
for (i = 0; i < *plen; i++)
|
|
pbuf[i] ^= 0xFF;
|
|
}
|
|
return status;
|
|
}
|
|
|
|
static SANE_Status Inverter_init (Inverter *pself,
|
|
SnapScan_Scanner *pss,
|
|
Source *psub)
|
|
{
|
|
return TxSource_init ((TxSource *) pself,
|
|
pss,
|
|
TxSource_remaining,
|
|
TxSource_bytesPerLine,
|
|
TxSource_pixelsPerLine,
|
|
Inverter_get,
|
|
TxSource_done,
|
|
psub);
|
|
}
|
|
|
|
static SANE_Status create_Inverter (SnapScan_Scanner *pss,
|
|
Source *psub,
|
|
Source **pps)
|
|
{
|
|
SANE_Status status = SANE_STATUS_GOOD;
|
|
*pps = (Source *) malloc(sizeof(Inverter));
|
|
if (*pps == NULL)
|
|
{
|
|
DBG (DL_MAJOR_ERROR, "%s: failed to allocate Inverter.\n",
|
|
__FUNCTION__);
|
|
status = SANE_STATUS_NO_MEM;
|
|
}
|
|
else
|
|
{
|
|
status = Inverter_init ((Inverter *) *pps, pss, psub);
|
|
}
|
|
return status;
|
|
}
|
|
|
|
/* Source chain creation */
|
|
|
|
static SANE_Status create_source_chain (SnapScan_Scanner *pss,
|
|
BaseSourceType bst,
|
|
Source **pps)
|
|
{
|
|
static char me[] = "create_source_chain";
|
|
SANE_Status status = create_base_source (pss, bst, pps);
|
|
|
|
DBG (DL_CALL_TRACE, "%s\n", me);
|
|
if (status == SANE_STATUS_GOOD)
|
|
{
|
|
SnapScan_Mode mode = actual_mode(pss);
|
|
switch (mode)
|
|
{
|
|
case MD_COLOUR:
|
|
status = create_RGBRouter (pss, *pps, pps);
|
|
/* We only have the interlace probelms on
|
|
some scanners like the Epson Perfection 2480/2580
|
|
at 2400 dpi. */
|
|
if (status == SANE_STATUS_GOOD &&
|
|
((pss->pdev->model == PERFECTION2480 && pss->res == 2400) ||
|
|
(pss->pdev->model == PERFECTION3490 && pss->res == 3200) ||
|
|
(pss->pdev->model == PRISA5000E && pss->res == 1200)))
|
|
status = create_Deinterlacer (pss, *pps, pps);
|
|
break;
|
|
case MD_BILEVELCOLOUR:
|
|
status = create_Expander (pss, *pps, pps);
|
|
if (status == SANE_STATUS_GOOD)
|
|
status = create_RGBRouter (pss, *pps, pps);
|
|
if (status == SANE_STATUS_GOOD &&
|
|
((pss->pdev->model == PERFECTION2480 && pss->res == 2400) ||
|
|
(pss->pdev->model == PERFECTION3490 && pss->res == 3200) ||
|
|
(pss->pdev->model == PRISA5000E && pss->res == 1200)))
|
|
status = create_Deinterlacer (pss, *pps, pps);
|
|
break;
|
|
case MD_GREYSCALE:
|
|
if ((pss->pdev->model == PERFECTION2480 && pss->res == 2400) ||
|
|
(pss->pdev->model == PERFECTION3490 && pss->res == 3200) ||
|
|
(pss->pdev->model == PRISA5000E && pss->res == 1200))
|
|
status = create_Deinterlacer (pss, *pps, pps);
|
|
break;
|
|
case MD_LINEART:
|
|
/* The SnapScan creates a negative image by
|
|
default... so for the user interface to make sense,
|
|
the internal meaning of "negative" is reversed */
|
|
if (pss->negative == SANE_FALSE)
|
|
status = create_Inverter (pss, *pps, pps);
|
|
if (pss->pdev->model == PERFECTION3490 && pss->res == 3200)
|
|
status = create_Deinterlacer (pss, *pps, pps);
|
|
break;
|
|
default:
|
|
DBG (DL_MAJOR_ERROR, "%s: bad mode value %d (internal error)\n",
|
|
__FUNCTION__, mode);
|
|
status = SANE_STATUS_INVAL;
|
|
break;
|
|
}
|
|
}
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
* $Log$
|
|
* Revision 1.21 2005/12/02 19:12:54 oliver-guest
|
|
* Another fix for lineart mode for the Epson 3490 @ 3200 DPI
|
|
*
|
|
* Revision 1.20 2005/11/28 19:28:29 oliver-guest
|
|
* Fix for lineart mode of Epson 3490 @ 3200 DPI
|
|
*
|
|
* Revision 1.19 2005/11/25 17:24:48 oliver-guest
|
|
* Fix for Epson 3490 @ 3200 DPI for grayscale and lineart mode
|
|
*
|
|
* Revision 1.18 2005/11/17 23:47:11 oliver-guest
|
|
* Revert previous 'fix', disable 2400 dpi for Epson 3490, use 1600 dpi instead
|
|
*
|
|
* Revision 1.17 2005/11/17 23:32:23 oliver-guest
|
|
* Fixes for Epson 3490 @ 2400 DPI
|
|
*
|
|
* Revision 1.16 2005/11/10 19:42:02 oliver-guest
|
|
* Added deinterlacing for Epson 3490
|
|
*
|
|
* Revision 1.15 2005/10/31 21:08:47 oliver-guest
|
|
* Distinguish between Benq 5000/5000E/5000U
|
|
*
|
|
* Revision 1.14 2005/10/13 22:43:30 oliver-guest
|
|
* Fixes for 16 bit scan mode from Simon Munton
|
|
*
|
|
* Revision 1.13 2005/10/11 18:47:07 oliver-guest
|
|
* Fixes for Epson 3490 and 16 bit scan mode
|
|
*
|
|
* Revision 1.12 2004/11/14 19:26:38 oliver-guest
|
|
* Applied patch from Julien Blache to change ch_past_init from SANE_Int to SANE_Bool
|
|
*
|
|
* Revision 1.11 2004/11/09 23:17:38 oliver-guest
|
|
* First implementation of deinterlacer for Epson scanners at high resolutions (thanks to Brad Johnson)
|
|
*
|
|
* Revision 1.10 2004/10/03 17:34:36 hmg-guest
|
|
* 64 bit platform fixes (bug #300799).
|
|
*
|
|
* Revision 1.9 2004/04/09 16:18:37 oliver-guest
|
|
* Fix initialization of FDSource.bytes_remaining
|
|
*
|
|
* Revision 1.8 2004/04/09 11:59:02 oliver-guest
|
|
* Fixes for pthread implementation
|
|
*
|
|
* Revision 1.7 2004/04/08 21:53:10 oliver-guest
|
|
* Use sanei_thread in snapscan backend
|
|
*
|
|
* Revision 1.6 2001/12/17 22:51:49 oliverschwartz
|
|
* Update to snapscan-20011212 (snapscan 1.4.3)
|
|
*
|
|
* Revision 1.18 2001/12/12 19:44:59 oliverschwartz
|
|
* Clean up CVS log
|
|
*
|
|
* Revision 1.17 2001/11/27 23:16:17 oliverschwartz
|
|
* - Fix color alignment for SnapScan 600
|
|
* - Added documentation in snapscan-sources.c
|
|
* - Guard against TL_X < BR_X and TL_Y < BR_Y
|
|
*
|
|
* Revision 1.16 2001/10/08 18:22:02 oliverschwartz
|
|
* - Disable quality calibration for Acer Vuego 310F
|
|
* - Use sanei_scsi_max_request_size as scanner buffer size
|
|
* for SCSI devices
|
|
* - Added new devices to snapscan.desc
|
|
*
|
|
* Revision 1.15 2001/09/28 15:56:51 oliverschwartz
|
|
* - fix hanging for SNAPSCAN300 / VUEGO 310
|
|
*
|
|
* Revision 1.14 2001/09/28 13:39:16 oliverschwartz
|
|
* - Added "Snapscan 300" ID string
|
|
* - cleanup
|
|
* - more debugging messages in snapscan-sources.c
|
|
*
|
|
* Revision 1.13 2001/09/18 15:01:07 oliverschwartz
|
|
* - Read scanner id string again after firmware upload
|
|
* to indentify correct model
|
|
* - Make firmware upload work for AGFA scanners
|
|
* - Change copyright notice
|
|
*
|
|
* Revision 1.12 2001/09/09 18:06:32 oliverschwartz
|
|
* add changes from Acer (new models; automatic firmware upload for USB scanners); fix distorted colour scans after greyscale scans (call set_window only in sane_start); code cleanup
|
|
*
|
|
* Revision 1.11 2001/04/13 13:12:18 oliverschwartz
|
|
* use absolute_max as expected_read_bytes for PRISA620S
|
|
*
|
|
* Revision 1.10 2001/04/10 11:04:31 sable
|
|
* Adding support for snapscan e40 an e50 thanks to Giuseppe Tanzilli
|
|
*
|
|
* Revision 1.9 2001/03/17 22:53:21 sable
|
|
* Applying Mikael Magnusson patch concerning Gamma correction
|
|
* Support for 1212U_2
|
|
*
|
|
* Revision 1.8 2000/11/28 03:55:07 cbagwell
|
|
* Reverting a fix to RGBRouter_remaining to original fix. This allows
|
|
* most scanners to scan at 600 dpi by ignoring insufficent data in
|
|
* the RGB circular buffer and always returning size = 1 in those cases.
|
|
* This should probably be fixed at a higher level.
|
|
*
|
|
* Revision 1.7 2000/11/20 01:02:42 cbagwell
|
|
* Updates so that USB will continue reading when it receives an EAGAIN error.
|
|
* Also, changed RGBRouter_remaining to not be able to return a negative
|
|
* value.
|
|
*
|
|
* Revision 1.6 2000/11/04 01:53:58 cbagwell
|
|
* Commiting some needed USB updates. Added extra test logic to detect
|
|
* bad bytes_expected values. Just to help debug faster on scanners
|
|
* that tickle the bug.
|
|
*
|
|
* Revision 1.5 2000/10/30 22:32:20 sable
|
|
* Support for vuego310s vuego610s and 1236s
|
|
*
|
|
* Revision 1.4 2000/10/28 14:16:10 sable
|
|
* Bug correction for SnapScan310
|
|
*
|
|
* Revision 1.3 2000/10/28 14:06:35 sable
|
|
* Add support for Acer300f
|
|
*
|
|
* Revision 1.2 2000/10/13 03:50:27 cbagwell
|
|
* Updating to source from SANE 1.0.3. Calling this versin 1.1
|
|
* */
|