First implementation of deinterlacer for Epson scanners at high resolutions (thanks to Brad Johnson)

merge-requests/1/head
Oliver Schwartz 2004-11-09 23:17:38 +00:00
rodzic 21840be6f1
commit d1e4cbcf4c
2 zmienionych plików z 209 dodań i 0 usunięć

Wyświetl plik

@ -1,3 +1,8 @@
2004-11-10 Oliver Schwartz <Oliver.Schwartz@gmx.de>
* snapscan-sources.c: First implementation of deinterlacer for epson
scanners at high resolutions (thanks to Brad Johnson)
2004-11-07 Henning Meier-Geinitz <henning@meier-geinitz.de>
* configure configure.in: Updated version. Enabled compilation

Wyświetl plik

@ -664,6 +664,192 @@ static SANE_Status create_Expander (SnapScan_Scanner *pss,
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 4 pixels.
The Deinterlacer detects if data is in SANE RGB frame format (3 bytes/pixel)
or in Grayscale (1 byte/pixel).
The first 4 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 4 lines. A better way to handle this would be to
scan in 4 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_ndata; /* actual #bytes in channel buffer */
SANE_Int ch_pos; /* position in buffer */
SANE_Int ch_past_init; /* flag indicating if we have enough data to shift pixels down */
SANE_Int ch_bytes_per_pixel;
} 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_size/5) == ps->ch_ndata % (ps->ch_size/5) )
{
/* we need more data; try to get the remainder of the current
line, or else the next line */
SANE_Int ndata = (ps->ch_size/5) - ps->ch_ndata % (ps->ch_size/5);
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_size /5;
}
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_bytes_per_pixel) % 2 == 0)
{
/* 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_size/5)) % 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_size/5) == 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_size /5 *4)
ps->ch_past_init = 1;
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_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)
{
/* We need at least 5 lines of buffer in order to shift up 4 pixels. */
pself->ch_size = TxSource_bytesPerLine((Source *) pself) *5;
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 = 0;
if (actual_mode(pss) == MD_GREYSCALE)
pself->ch_bytes_per_pixel = 1;
else
pself->ch_bytes_per_pixel = 3;
}
}
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 */
@ -935,14 +1121,29 @@ static SANE_Status create_source_chain (SnapScan_Scanner *pss,
{
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)
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)
status = create_Deinterlacer (pss, *pps, pps);
break;
case MD_GREYSCALE:
if (pss->pdev->model == PERFECTION2480 &&
pss->res == 2400)
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,
@ -962,6 +1163,9 @@ static SANE_Status create_source_chain (SnapScan_Scanner *pss,
/*
* $Log$
* 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).
*