kopia lustrzana https://gitlab.com/sane-project/backends
909 wiersze
26 KiB
C
909 wiersze
26 KiB
C
/* @file u12_image.c
|
|
* @brief functions to convert scanner data into image data
|
|
*
|
|
* based on sources acquired from Plustek Inc.
|
|
* Copyright (c) 2003-2004 Gerhard Jaeger <gerhard@gjaeger.de>
|
|
*
|
|
* History:
|
|
* - 0.01 - initial version
|
|
* - 0.02 - fixed fnColor42() to return 16bit values instead of
|
|
* only 12bit (this is the maximum the scanner can)
|
|
* - added scaling function u12image_ScaleX()
|
|
* .
|
|
* <hr>
|
|
* 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.
|
|
* <hr>
|
|
*/
|
|
|
|
/*************************** local vars **************************************/
|
|
|
|
static u_short wPreviewScanned = 0;
|
|
|
|
static ExpXStepDef negScan[5] = {
|
|
{128, 8}, {96, 12}, {96, 24}, {96, 48}, {96, 96}
|
|
};
|
|
|
|
static ExpXStepDef posScan[5] = {
|
|
{128, 8}, {96, 12}, {96, 24}, {96, 48}, {96, 96}
|
|
};
|
|
|
|
static ExpXStepDef nmlScan[5] = {
|
|
{160, 10}, {96, 12}, {96, 24}, {96, 48}, {96, 96},
|
|
};
|
|
|
|
/*************************** local functions *********************************/
|
|
|
|
/**
|
|
*/
|
|
static SANE_Bool fnReadToDriver( U12_Device *dev )
|
|
{
|
|
dev->regs.RD_ModeControl = _ModeFifoBSel;
|
|
u12io_ReadMonoData( dev, dev->scan.BufPut.blue.bp,
|
|
dev->DataInf.dwAsicBytesPerPlane );
|
|
|
|
dev->regs.RD_ModeControl = _ModeFifoGSel;
|
|
u12io_ReadMonoData( dev, dev->scan.BufPut.green.bp,
|
|
dev->DataInf.dwAsicBytesPerPlane );
|
|
|
|
if( dev->scan.gd_gk.wGreenKeep )
|
|
dev->scan.gd_gk.wGreenKeep--;
|
|
else {
|
|
dev->scan.BufPut.green.bp += dev->DataInf.dwAsicBytesPerPlane;
|
|
|
|
if( dev->scan.BufPut.green.bp >= dev->scan.BufEnd.green.bp )
|
|
dev->scan.BufPut.green.bp = dev->scan.BufBegin.green.bp;
|
|
}
|
|
|
|
dev->regs.RD_ModeControl = _ModeFifoRSel;
|
|
u12io_ReadMonoData( dev, dev->scan.BufPut.red.bp,
|
|
dev->DataInf.dwAsicBytesPerPlane );
|
|
|
|
dev->scan.BufPut.red.bp += dev->DataInf.dwAsicBytesPerPlane;
|
|
if( dev->scan.BufPut.red.bp >= dev->scan.BufEnd.red.bp )
|
|
dev->scan.BufPut.red.bp = dev->scan.BufBegin.red.bp;
|
|
|
|
if( dev->scan.bd_rk.wRedKeep ) {
|
|
dev->scan.bd_rk.wRedKeep--;
|
|
return SANE_FALSE;
|
|
|
|
} else {
|
|
|
|
dev->scan.BufData.green.bp = dev->scan.BufGet.green.bp;
|
|
dev->scan.BufData.red.bp = dev->scan.BufGet.red.bp;
|
|
dev->scan.BufData.blue.bp = dev->scan.BufGet.blue.bp;
|
|
|
|
dev->scan.BufGet.red.bp += dev->DataInf.dwAsicBytesPerPlane;
|
|
dev->scan.BufGet.green.bp += dev->DataInf.dwAsicBytesPerPlane;
|
|
|
|
if( dev->scan.BufGet.red.bp >= dev->scan.BufEnd.red.bp )
|
|
dev->scan.BufGet.red.bp = dev->scan.BufBegin.red.bp;
|
|
|
|
if( dev->scan.BufGet.green.bp >= dev->scan.BufEnd.green.bp )
|
|
dev->scan.BufGet.green.bp = dev->scan.BufBegin.green.bp;
|
|
|
|
return SANE_TRUE;
|
|
}
|
|
}
|
|
|
|
/**
|
|
*/
|
|
static SANE_Bool fnReadOutScanner( U12_Device *dev )
|
|
{
|
|
if( dev->scan.bd_rk.wBlueDiscard ) {
|
|
|
|
dev->scan.bd_rk.wBlueDiscard--;
|
|
dev->regs.RD_ModeControl = _ModeFifoBSel;
|
|
|
|
u12io_ReadMonoData( dev, dev->bufs.b1.pReadBuf,
|
|
dev->DataInf.dwAsicBytesPerPlane );
|
|
|
|
if( dev->scan.gd_gk.wGreenDiscard ) {
|
|
dev->scan.gd_gk.wGreenDiscard--;
|
|
|
|
dev->regs.RD_ModeControl = _ModeFifoGSel;
|
|
u12io_ReadMonoData( dev, dev->bufs.b1.pReadBuf,
|
|
dev->DataInf.dwAsicBytesPerPlane );
|
|
}
|
|
return SANE_FALSE;
|
|
|
|
} else {
|
|
u12io_ReadColorData( dev, dev->bufs.b1.pReadBuf,
|
|
dev->DataInf.dwAsicBytesPerPlane );
|
|
return SANE_TRUE;
|
|
}
|
|
}
|
|
|
|
/** some sampling functions
|
|
*/
|
|
static SANE_Bool fnEveryLine( U12_Device *dev )
|
|
{
|
|
_VAR_NOT_USED( dev );
|
|
return SANE_TRUE;
|
|
}
|
|
|
|
static SANE_Bool fnSampleLines( U12_Device *dev )
|
|
{
|
|
dev->DataInf.wYSum += dev->DataInf.xyAppDpi.y;
|
|
|
|
if( dev->DataInf.wYSum >= dev->DataInf.xyPhyDpi.y ) {
|
|
dev->DataInf.wYSum -= dev->DataInf.xyPhyDpi.y;
|
|
return SANE_TRUE;
|
|
}
|
|
return SANE_FALSE;
|
|
}
|
|
|
|
static SANE_Bool fnSamplePreview( U12_Device *dev )
|
|
{
|
|
dev->DataInf.wYSum += wPreviewScanned;
|
|
if( dev->DataInf.wYSum >= 150 ) {
|
|
|
|
dev->DataInf.wYSum -= 150;
|
|
return SANE_TRUE;
|
|
}
|
|
|
|
return SANE_FALSE;
|
|
}
|
|
|
|
/** this function is used when
|
|
* - the data type is B/W or GrayScale.
|
|
* - the required horizontal resolution doesn't exceed the optic spec.
|
|
* - the required vertical resolution exceeds the optic spec.
|
|
*/
|
|
static void fnDataDirect( U12_Device *dev, void *src, void *dest, u_long len )
|
|
{
|
|
_VAR_NOT_USED( dev );
|
|
memcpy( dest, src, len );
|
|
}
|
|
|
|
/** merges the color planes to pixels style without enlarge operation.
|
|
*/
|
|
static void fnColorDirect( U12_Device *dev, void *pb, void *img, u_long len )
|
|
{
|
|
SANE_Byte *src;
|
|
RGBByteDef *dest;
|
|
|
|
src = (SANE_Byte*)img;
|
|
dest = (RGBByteDef*)pb;
|
|
|
|
for ( len = dev->DataInf.dwAsicPixelsPerPlane; len; len--, src++, dest++) {
|
|
|
|
dest->Red = *src;
|
|
dest->Green = src[dev->DataInf.dwAsicPixelsPerPlane];
|
|
dest->Blue = src[dev->DataInf.dwAsicPixelsPerPlane*2];
|
|
}
|
|
}
|
|
|
|
/** merges the color planes to pixels style without enlarge operation.
|
|
* The scanner returns the pixel data in Motorola-Format, so we have to swap
|
|
* (at least on x86)
|
|
*/
|
|
static void fnColor42( U12_Device *dev, void *pb, void *img, u_long len )
|
|
{
|
|
u_short *src;
|
|
RGBUShortDef *dest;
|
|
|
|
register u_long i;
|
|
|
|
_VAR_NOT_USED( len );
|
|
src = (u_short*)img;
|
|
dest = (RGBUShortDef*)pb;
|
|
|
|
for ( i = dev->DataInf.dwAsicPixelsPerPlane; i; i--, src++, dest++) {
|
|
|
|
dest->Red = (*src) << 4;
|
|
dest->Green = (src[dev->DataInf.dwAsicPixelsPerPlane]) << 4;
|
|
dest->Blue = (src[dev->DataInf.dwAsicPixelsPerPlane * 2]) << 4;
|
|
}
|
|
}
|
|
|
|
/**
|
|
*/
|
|
static void u12image_SetupScanStateVariables( U12_Device *dev, u_long index )
|
|
{
|
|
DataType var;
|
|
|
|
DBG( _DBG_INFO, "u12image_SetupScanStateVariables(%lu)\n", index );
|
|
dev->scan.dpiIdx = index;
|
|
|
|
if(!(dev->DataInf.dwScanFlag & _SCANDEF_TPA)) {
|
|
|
|
dev->shade.wExposure = nmlScan[index].exposureTime;
|
|
dev->shade.wXStep = nmlScan[index].xStepTime;
|
|
|
|
if( dev->shade.intermediate & _ScanMode_AverageOut ) {
|
|
dev->shade.wExposure >>= 1;
|
|
dev->shade.wXStep >>= 1;
|
|
}
|
|
} else {
|
|
if( dev->DataInf.dwScanFlag & _SCANDEF_Transparency ) {
|
|
dev->shade.wExposure = posScan[index].exposureTime;
|
|
dev->shade.wXStep = posScan[index].xStepTime;
|
|
} else {
|
|
dev->shade.wExposure = dev->scan.negScan[index].exposureTime;
|
|
dev->shade.wXStep = dev->scan.negScan[index].xStepTime;
|
|
}
|
|
}
|
|
dev->scan.dwInterval = 1;
|
|
|
|
if( dev->DataInf.wPhyDataType == COLOR_BW )
|
|
var.dwValue = 0;
|
|
else {
|
|
if( dev->DataInf.wPhyDataType == COLOR_256GRAY )
|
|
var.dwValue = 2500;
|
|
else
|
|
var.dwValue = 3200;
|
|
}
|
|
|
|
/* for small size/descreen */
|
|
if((dev->DataInf.xyAppDpi.y >= 300) && var.dwValue &&
|
|
(dev->DataInf.dwAsicBytesPerPlane <= var.dwValue)) {
|
|
dev->scan.dwInterval <<= 1;
|
|
}
|
|
|
|
if( var.dwValue && dev->DataInf.dwAsicBytesPerPlane > var.dwValue ) {
|
|
if((var.dwValue << 1) > dev->DataInf.dwAsicBytesPerPlane)
|
|
dev->scan.dwInterval <<= 1;
|
|
else
|
|
if((var.dwValue << 2) > dev->DataInf.dwAsicBytesPerPlane)
|
|
dev->scan.dwInterval <<= 2;
|
|
else
|
|
dev->scan.dwInterval <<= 3;
|
|
}
|
|
|
|
if( dev->DataInf.wPhyDataType >= COLOR_TRUE24 ) {
|
|
|
|
if( dev->DataInf.xyPhyDpi.y > 75U ) {
|
|
if( dev->f0_8_16 ) {
|
|
dev->scan.gd_gk.wGreenDiscard = dev->DataInf.xyPhyDpi.y / 75U;
|
|
} else {
|
|
dev->scan.gd_gk.wGreenDiscard = dev->DataInf.xyPhyDpi.y / 150U;
|
|
}
|
|
} else {
|
|
dev->scan.gd_gk.wGreenDiscard = 1;
|
|
}
|
|
|
|
dev->scan.bd_rk.wBlueDiscard = dev->scan.gd_gk.wGreenDiscard << 1;
|
|
} else {
|
|
dev->scan.bd_rk.wBlueDiscard = dev->scan.gd_gk.wGreenDiscard = 0;
|
|
}
|
|
}
|
|
|
|
/** limit the resolution
|
|
*/
|
|
static u_short
|
|
u12image_GetPhysDPI( U12_Device *dev, ImgDef *img, SANE_Bool fDpiX )
|
|
{
|
|
if( fDpiX ) {
|
|
|
|
if( img->xyDpi.x > dev->dpi_max_x )
|
|
return dev->dpi_max_x;
|
|
else
|
|
return img->xyDpi.x;
|
|
|
|
} else {
|
|
|
|
if( img->xyDpi.y > dev->dpi_max_y )
|
|
return dev->dpi_max_y;
|
|
else
|
|
return img->xyDpi.y;
|
|
}
|
|
}
|
|
|
|
/** calculate the image properties according to the scanmode
|
|
* set all internally needed information
|
|
*/
|
|
static void u12image_GetImageInfo( U12_Device *dev, ImgDef *image )
|
|
{
|
|
DBG( _DBG_INFO, "u12image_GetImageInfo()\n" );
|
|
|
|
dev->DataInf.xyPhyDpi.x = u12image_GetPhysDPI(dev, image, SANE_TRUE );
|
|
dev->DataInf.xyPhyDpi.y = u12image_GetPhysDPI(dev, image, SANE_FALSE);
|
|
|
|
DBG( _DBG_INFO, "* xyPhyDpi.x = %u, xyPhyDpi.y = %u\n",
|
|
dev->DataInf.xyPhyDpi.x, dev->DataInf.xyPhyDpi.y );
|
|
|
|
DBG( _DBG_INFO, "* crArea.x = %u, crArea.y = %u\n",
|
|
image->crArea.x, image->crArea.y );
|
|
|
|
DBG( _DBG_INFO, "* crArea.cx = %u, crArea.cy = %u\n",
|
|
image->crArea.cx, image->crArea.cy );
|
|
|
|
dev->DataInf.xyRatio = (double)dev->DataInf.xyPhyDpi.y/
|
|
(double)dev->DataInf.xyPhyDpi.x;
|
|
|
|
dev->DataInf.dwAppLinesPerArea = (u_long)image->crArea.cy *
|
|
image->xyDpi.y / _MEASURE_BASE;
|
|
|
|
dev->DataInf.dwAppPixelsPerLine = (u_long)image->crArea.cx *
|
|
image->xyDpi.x / _MEASURE_BASE;
|
|
|
|
dev->DataInf.dwPhysBytesPerLine = (u_long)image->crArea.cx *
|
|
dev->DataInf.xyPhyDpi.x / _MEASURE_BASE;
|
|
|
|
if( image->wDataType <= COLOR_BW ) {
|
|
dev->DataInf.dwAsicPixelsPerPlane =
|
|
(dev->DataInf.dwAppPixelsPerLine+7UL) & 0xfffffff8UL;
|
|
dev->DataInf.dwAppPhyBytesPerLine =
|
|
dev->DataInf.dwAppBytesPerLine =
|
|
dev->DataInf.dwAsicBytesPerLine =
|
|
dev->DataInf.dwAsicBytesPerPlane = dev->DataInf.dwAsicPixelsPerPlane>>3;
|
|
} else {
|
|
dev->DataInf.dwAsicBytesPerPlane =
|
|
dev->DataInf.dwAsicPixelsPerPlane = dev->DataInf.dwAppPixelsPerLine;
|
|
}
|
|
|
|
if( COLOR_TRUE42 == image->wDataType ) {
|
|
dev->DataInf.dwAsicBytesPerPlane *= 2;
|
|
}
|
|
|
|
switch( image->wDataType ) {
|
|
|
|
case COLOR_BW:
|
|
dev->scan.DataProcess = fnDataDirect;
|
|
dev->DataInf.wPhyDataType = COLOR_BW;
|
|
dev->shade.intermediate = _ScanMode_Mono;
|
|
break;
|
|
|
|
case COLOR_256GRAY:
|
|
dev->scan.DataProcess = fnDataDirect;
|
|
dev->DataInf.dwAsicBytesPerLine =
|
|
dev->DataInf.dwAppPhyBytesPerLine = dev->DataInf.dwAppPixelsPerLine;
|
|
dev->DataInf.wPhyDataType = COLOR_256GRAY;
|
|
dev->shade.intermediate = _ScanMode_Mono;
|
|
break;
|
|
|
|
case COLOR_TRUE24:
|
|
dev->scan.DataProcess = fnColorDirect;
|
|
dev->DataInf.dwAsicBytesPerLine =
|
|
dev->DataInf.dwAppPhyBytesPerLine = dev->DataInf.dwAppPixelsPerLine * 3;
|
|
dev->DataInf.wPhyDataType = COLOR_TRUE24;
|
|
dev->shade.intermediate = _ScanMode_Color;
|
|
break;
|
|
|
|
case COLOR_TRUE42:
|
|
dev->scan.DataProcess = fnColor42;
|
|
dev->DataInf.dwAsicBytesPerLine =
|
|
dev->DataInf.dwAppPhyBytesPerLine = dev->DataInf.dwAppPixelsPerLine * 6;
|
|
dev->DataInf.wPhyDataType = COLOR_TRUE42;
|
|
dev->shade.intermediate = _ScanMode_Color;
|
|
break;
|
|
}
|
|
|
|
/* raus mit einem von beiden!!!!*/
|
|
dev->DataInf.dwAppBytesPerLine = dev->DataInf.dwAppPhyBytesPerLine;
|
|
|
|
DBG( _DBG_INFO, "AppLinesPerArea = %lu\n", dev->DataInf.dwAppLinesPerArea );
|
|
DBG( _DBG_INFO, "AppPixelsPerLine = %lu\n", dev->DataInf.dwAppPixelsPerLine );
|
|
DBG( _DBG_INFO, "AppPhyBytesPerLine = %lu\n", dev->DataInf.dwAppPhyBytesPerLine );
|
|
DBG( _DBG_INFO, "AppBytesPerLine = %lu\n", dev->DataInf.dwAppBytesPerLine );
|
|
DBG( _DBG_INFO, "AsicPixelsPerPlane = %lu\n", dev->DataInf.dwAsicPixelsPerPlane );
|
|
DBG( _DBG_INFO, "AsicBytesPerPlane = %lu\n", dev->DataInf.dwAsicBytesPerPlane );
|
|
DBG( _DBG_INFO, "AsicBytesPerLine = %lu\n", dev->DataInf.dwAsicBytesPerLine );
|
|
DBG( _DBG_INFO, "Physical Bytes = %lu\n", dev->DataInf.dwPhysBytesPerLine );
|
|
}
|
|
|
|
/**
|
|
*/
|
|
static int imageSetupScanSettings( U12_Device *dev, ImgDef *img )
|
|
{
|
|
u_short brightness;
|
|
|
|
DBG( _DBG_INFO, "imageSetupScanSettings()\n" );
|
|
|
|
dev->DataInf.dwScanFlag = img->dwFlag;
|
|
dev->DataInf.crImage = img->crArea;
|
|
|
|
DBG( _DBG_INFO,"* DataInf.dwScanFlag = 0x%08lx\n",dev->DataInf.dwScanFlag);
|
|
|
|
dev->DataInf.crImage.x <<= 1;
|
|
|
|
dev->DataInf.xyAppDpi = img->xyDpi;
|
|
dev->DataInf.wAppDataType = img->wDataType;
|
|
|
|
u12image_GetImageInfo( dev, img );
|
|
|
|
dev->scan.lBufferAdjust = (long)dev->DataInf.dwAppBytesPerLine;
|
|
|
|
DBG( _DBG_INFO, "* Scan settings:\n" );
|
|
DBG( _DBG_INFO, "* ImageInfo: (x=%u,y=%u,dx=%u,dy=%u)\n",
|
|
dev->DataInf.crImage.x, dev->DataInf.crImage.y,
|
|
dev->DataInf.crImage.cx, dev->DataInf.crImage.cy );
|
|
|
|
/*
|
|
* 0 _DEF_BW_THRESHOLD 255
|
|
* +-------------------------+--------------------------------+
|
|
* |<------- Black --------->|<----------- White ------------>|
|
|
* So, if user wish to make image darker, the threshold value should be
|
|
* higher than _defBwThreshold, otherwise it should lower than the
|
|
* _DefBwThreshold.
|
|
* Darker = _DEF_BW_THRESHOLD + White * Input / 127;
|
|
* Input < 0, and White = 255 - _DEF_BW_THRESHOLD, so
|
|
* = _DEF_BW_THRESHOLD - (255 - _DEF_BW_THRESHOLD) * Input / 127;
|
|
* The brighter is the same idea.
|
|
*/
|
|
|
|
/* CHECK: We have now two methods for setting the brightness...
|
|
*/
|
|
DBG( _DBG_INFO, "* brightness = %i\n", dev->DataInf.siBrightness );
|
|
if ( dev->DataInf.siBrightness < 0) {
|
|
brightness = (u_short)(_DEF_BW_THRESHOLD -
|
|
(255 - _DEF_BW_THRESHOLD) * dev->DataInf.siBrightness /127);
|
|
} else {
|
|
brightness = (u_short)(_DEF_BW_THRESHOLD -
|
|
_DEF_BW_THRESHOLD * dev->DataInf.siBrightness /127);
|
|
}
|
|
|
|
dev->regs.RD_ThresholdControl = brightness;
|
|
DBG( _DBG_INFO, "* RD_ThresholdControl = %i\n", brightness );
|
|
return 0;
|
|
}
|
|
|
|
/** PrepareScanningVariables() !!!
|
|
*/
|
|
static SANE_Status u12image_SetupScanSettings( U12_Device *dev, ImgDef *img )
|
|
{
|
|
DBG( _DBG_INFO, "u12image_SetupScanSettings()\n" );
|
|
|
|
wPreviewScanned = 0;
|
|
dev->scan.dpiIdx = 0;
|
|
dev->scan.negScan = negScan;
|
|
|
|
imageSetupScanSettings( dev, img );
|
|
|
|
if( !(dev->DataInf.dwScanFlag & _SCANDEF_TPA )) {
|
|
|
|
dev->scan.dwScanOrigin = dev->adj.upNormal * 4 + _RFT_SCANNING_ORG;
|
|
|
|
} else if( dev->DataInf.dwScanFlag & _SCANDEF_Transparency) {
|
|
|
|
dev->scan.dwScanOrigin = dev->adj.upPositive * 4 + _POS_SCANNING_ORG;
|
|
} else {
|
|
dev->scan.dwScanOrigin = dev->adj.upNegative * 4 + _NEG_SCANNING_ORG;
|
|
}
|
|
dev->scan.dwScanOrigin += 64 /*dev->dwModelOriginY*/;
|
|
|
|
if( dev->DataInf.xyAppDpi.y <= 75 ) {
|
|
|
|
if( dev->DataInf.dwScanFlag & _SCANDEF_PREVIEW ) {
|
|
|
|
dev->scan.bDiscardAll = 0;
|
|
dev->DataInf.xyPhyDpi.y = 150;
|
|
dev->shade.intermediate |= _ScanMode_AverageOut;
|
|
u12image_SetupScanStateVariables( dev, 1 );
|
|
dev->scan.gd_gk.wGreenDiscard = 0;
|
|
|
|
if( dev->DataInf.xyAppDpi.y >= 38 )
|
|
dev->scan.bd_rk.wBlueDiscard = 1;
|
|
else
|
|
dev->scan.bd_rk.wBlueDiscard = 0;
|
|
|
|
if( dev->DataInf.wPhyDataType >= COLOR_256GRAY ) {
|
|
dev->shade.wXStep = 6;
|
|
dev->shade.wExposure = 8 * dev->shade.wXStep;
|
|
}
|
|
} else {
|
|
if(!(dev->DataInf.dwScanFlag & _SCANDEF_TPA) &&
|
|
(dev->DataInf.xyAppDpi.y <= 50) &&
|
|
(dev->DataInf.wPhyDataType >= COLOR_TRUE24)) {
|
|
dev->shade.intermediate |= _ScanMode_AverageOut;
|
|
}
|
|
|
|
if((dev->DataInf.wPhyDataType<COLOR_TRUE24) || dev->f0_8_16 ||
|
|
(dev->shade.intermediate & _ScanMode_AverageOut)) {
|
|
|
|
dev->scan.bDiscardAll = 1;
|
|
dev->DataInf.xyPhyDpi.y = 75;
|
|
u12image_SetupScanStateVariables( dev, 0 );
|
|
} else {
|
|
dev->scan.bDiscardAll = 2;
|
|
dev->DataInf.xyPhyDpi.y = 150;
|
|
u12image_SetupScanStateVariables( dev, 1 );
|
|
}
|
|
}
|
|
} else {
|
|
if( dev->DataInf.xyAppDpi.y <= 150 ) {
|
|
|
|
dev->scan.bDiscardAll = 2;
|
|
dev->DataInf.xyPhyDpi.y = 150;
|
|
u12image_SetupScanStateVariables( dev, 1 );
|
|
|
|
} else if( dev->DataInf.xyAppDpi.y <= 300 ) {
|
|
|
|
dev->scan.bDiscardAll = 4;
|
|
dev->DataInf.xyPhyDpi.y = 300;
|
|
u12image_SetupScanStateVariables( dev, 2 );
|
|
|
|
} else if( dev->DataInf.xyAppDpi.y <= 600 ) {
|
|
|
|
dev->scan.bDiscardAll = 8;
|
|
dev->DataInf.xyPhyDpi.y = 600;
|
|
u12image_SetupScanStateVariables( dev, 3 );
|
|
|
|
} else {
|
|
|
|
dev->scan.bDiscardAll = 16;
|
|
dev->DataInf.xyPhyDpi.y = 1200;
|
|
u12image_SetupScanStateVariables( dev, 4 );
|
|
}
|
|
}
|
|
|
|
/* ------- lines to sample or not? ------- */
|
|
if( dev->DataInf.xyAppDpi.y == dev->DataInf.xyPhyDpi.y ) {
|
|
DBG( _DBG_INFO, "* Sample every line\n" );
|
|
dev->scan.DoSample = fnEveryLine;
|
|
} else {
|
|
if( dev->DataInf.dwScanFlag & _SCANDEF_PREVIEW ) {
|
|
|
|
DBG( _DBG_INFO, "* Sample preview\n" );
|
|
dev->scan.DoSample = fnSamplePreview;
|
|
dev->DataInf.wYSum = 150;
|
|
|
|
if( dev->DataInf.xyAppDpi.y >= 38 )
|
|
wPreviewScanned = dev->DataInf.xyAppDpi.y * 2;
|
|
else if( dev->DataInf.xyAppDpi.y >= 19 )
|
|
wPreviewScanned = dev->DataInf.xyAppDpi.y * 4;
|
|
else
|
|
wPreviewScanned = dev->DataInf.xyAppDpi.y * 8;
|
|
} else {
|
|
|
|
DBG( _DBG_INFO, "* Sample lines (%u - %u)...\n",
|
|
dev->DataInf.xyPhyDpi.y, dev->DataInf.xyAppDpi.y );
|
|
dev->scan.DoSample = fnSampleLines;
|
|
dev->DataInf.wYSum = dev->DataInf.xyPhyDpi.y - dev->DataInf.xyAppDpi.y;
|
|
}
|
|
}
|
|
|
|
/* now assign the buffer pointers for image aquisition
|
|
*/
|
|
dev->scan.p48BitBuf.pb = NULL;
|
|
|
|
if( dev->DataInf.wPhyDataType >= COLOR_TRUE24 ) {
|
|
|
|
u_long r, g, b;
|
|
|
|
r = (u_long)_SIZE_REDFIFO /
|
|
dev->DataInf.dwAsicBytesPerPlane - dev->scan.bd_rk.wRedKeep;
|
|
g = (u_long)_SIZE_GREENFIFO /
|
|
dev->DataInf.dwAsicBytesPerPlane - dev->scan.gd_gk.wGreenKeep;
|
|
|
|
if((int)r < 16 || (int)g < 16) {
|
|
|
|
b = (u_long)(dev->scan.bd_rk.wRedKeep +
|
|
dev->scan.gd_gk.wGreenKeep + 2U) *
|
|
dev->DataInf.dwAsicBytesPerPlane;
|
|
|
|
DBG( _DBG_INFO, "48Bit buffer request: "
|
|
"len=%lu bytes, available=%lu\n", b, _SIZE_TOTAL_BUF_TPA );
|
|
|
|
if( b > _SIZE_TOTAL_BUF_TPA ) {
|
|
DBG( _DBG_ERROR, "Not that much FIFO memory available!\n" );
|
|
return SANE_STATUS_NO_MEM;
|
|
}
|
|
|
|
dev->scan.p48BitBuf.pb = dev->bufs.b1.pReadBuf;
|
|
}
|
|
}
|
|
|
|
if( dev->scan.p48BitBuf.pb ){
|
|
dev->scan.DataRead = fnReadToDriver;
|
|
dev->scan.BufGet.red.bp =
|
|
dev->scan.BufPut.red.bp =
|
|
dev->scan.BufBegin.red.bp = dev->scan.p48BitBuf.pb;
|
|
dev->scan.BufEnd.red.bp =
|
|
dev->scan.BufBegin.green.bp =
|
|
dev->scan.BufGet.green.bp =
|
|
dev->scan.BufPut.green.bp = dev->scan.p48BitBuf.pb +
|
|
dev->DataInf.dwAsicBytesPerLine *
|
|
(dev->scan.bd_rk.wRedKeep + 1U);
|
|
|
|
dev->scan.BufEnd.green.bp = dev->scan.BufBegin.green.bp +
|
|
dev->DataInf.dwAsicBytesPerLine *
|
|
(dev->scan.gd_gk.wGreenKeep + 1U);
|
|
dev->scan.BufPut.blue.bp =
|
|
dev->scan.BufGet.blue.bp = dev->bufs.b1.pReadBuf +
|
|
dev->DataInf.dwAsicBytesPerLine * 2;
|
|
} else {
|
|
dev->scan.DataRead = fnReadOutScanner;
|
|
dev->scan.BufPut.red.bp = dev->bufs.b1.pReadBuf;
|
|
dev->scan.BufData.green.bp =
|
|
dev->scan.BufPut.green.bp = dev->scan.BufPut.red.bp +
|
|
dev->DataInf.dwAsicBytesPerLine;
|
|
dev->scan.BufPut.blue.bp = dev->scan.BufPut.green.bp +
|
|
dev->DataInf.dwAsicBytesPerLine;
|
|
|
|
dev->scan.BufData.red.bp = dev->scan.BufPut.red.bp;
|
|
dev->scan.BufData.blue.bp = dev->scan.BufPut.blue.bp;
|
|
}
|
|
|
|
/* CHECK: maybe remove this stuff */
|
|
#if 0
|
|
if( ps->DataInf.dwScanFlag & _SCANDEF_Transparency) {
|
|
posScan[1].exposureTime = 96;
|
|
posScan[1].xStepTime = 12;
|
|
posScan[2].exposureTime = 96;
|
|
posScan[2].xStepTime = 24;
|
|
posScan[3].exposureTime = 96;
|
|
posScan[3].xStepTime = 48;
|
|
posScan[4].exposureTime = 96;
|
|
posScan[4].xStepTime = 96;
|
|
|
|
/* Reset shading Exposure Time & xStep Time */
|
|
ps->Shade.wExposure = posScan[ps->Scan.dpiIdx].exposureTime;
|
|
ps->Shade.wXStep = posScan[ps->Scan.dpiIdx].xStepTime;
|
|
}
|
|
else if( ps->DataInf.dwScanFlag & _SCANDEF_Negative) {
|
|
ps->Scan.negScan[1].exposureTime = 96;
|
|
ps->Scan.negScan[1].xStepTime = 12;
|
|
ps->Scan.negScan[2].exposureTime = 96;
|
|
ps->Scan.negScan[2].xStepTime = 24;
|
|
ps->Scan.negScan[3].exposureTime = 96;
|
|
ps->Scan.negScan[3].xStepTime = 48;
|
|
ps->Scan.negScan[4].exposureTime = 96;
|
|
ps->Scan.negScan[4].xStepTime = 96;
|
|
|
|
/* Reset shading Exposure Time & xStep Time */
|
|
ps->Shade.wExposure = ps->Scan.negScan[ps->Scan.dpiIdx].exposureTime;
|
|
ps->Shade.wXStep = ps->Scan.negScan[ps->Scan.dpiIdx].xStepTime;
|
|
}
|
|
#endif
|
|
return SANE_STATUS_GOOD;
|
|
}
|
|
|
|
/**
|
|
*/
|
|
static SANE_Bool u12image_DataIsReady( U12_Device *dev, void* buf )
|
|
{
|
|
DBG( _DBG_READ, "* DataIsReady()\n" );
|
|
|
|
if( dev->scan.bDiscardAll ) {
|
|
dev->scan.bDiscardAll--;
|
|
|
|
if( dev->DataInf.wPhyDataType <= COLOR_256GRAY ) {
|
|
dev->regs.RD_ModeControl = _ModeFifoGSel;
|
|
u12io_ReadMonoData( dev, dev->bufs.b1.pReadBuf,
|
|
dev->DataInf.dwAsicBytesPerPlane );
|
|
} else {
|
|
u12io_ReadColorData( dev, dev->bufs.b1.pReadBuf,
|
|
dev->DataInf.dwAsicBytesPerPlane );
|
|
}
|
|
return SANE_FALSE;
|
|
}
|
|
|
|
if( dev->DataInf.wPhyDataType <= COLOR_256GRAY ) {
|
|
|
|
dev->regs.RD_ModeControl = _ModeFifoGSel;
|
|
u12io_ReadMonoData( dev, buf, dev->DataInf.dwAsicBytesPerPlane );
|
|
|
|
} else {
|
|
|
|
if( !dev->scan.DataRead( dev )) {
|
|
return SANE_FALSE;
|
|
}
|
|
}
|
|
|
|
if( dev->scan.DoSample( dev )) {
|
|
|
|
/* direct is done here without copying...*/
|
|
if( fnDataDirect != dev->scan.DataProcess ) {
|
|
(*dev->scan.DataProcess)(dev, buf, (void*)(dev->scan.BufPut.red.bp),
|
|
dev->DataInf.dwAppPhyBytesPerLine);
|
|
}
|
|
return SANE_TRUE;
|
|
}
|
|
return SANE_FALSE;
|
|
}
|
|
|
|
/**
|
|
*/
|
|
static SANE_Status u12image_ReadOneImageLine( U12_Device *dev, void* buf )
|
|
{
|
|
SANE_Byte b, state;
|
|
TimerDef timer, t2;
|
|
|
|
DBG( _DBG_READ, "u12image_ReadOneImageLine()\n" );
|
|
|
|
u12io_StartTimer( &timer, _LINE_TIMEOUT );
|
|
u12io_StartTimer( &t2, _SECOND*2 );
|
|
do {
|
|
|
|
state = u12io_GetScanState( dev );
|
|
dev->scan.bNowScanState = (state & _SCANSTATE_MASK);
|
|
|
|
if( state & _SCANSTATE_STOP ) {
|
|
|
|
DBG( _DBG_READ, "* SCANSTATE_STOP\n" );
|
|
u12motor_ModuleForwardBackward( dev );
|
|
|
|
if( u12io_GetFifoLength( dev ) >= dev->scan.dwMinReadFifo )
|
|
if( u12image_DataIsReady( dev, buf ))
|
|
return SANE_STATUS_GOOD;
|
|
|
|
} else {
|
|
|
|
dev->scan.bModuleState = _MotorInNormalState;
|
|
b = dev->scan.bNowScanState - dev->scan.oldScanState;
|
|
|
|
if((char) b < 0)
|
|
b += _NUMBER_OF_SCANSTEPS;
|
|
|
|
if( b >= dev->scan.bRefresh ) {
|
|
|
|
u12io_RegisterToScanner( dev, REG_REFRESHSCANSTATE );
|
|
dev->scan.oldScanState = u12io_GetScanState( dev );
|
|
dev->scan.oldScanState &= _SCANSTATE_MASK;
|
|
}
|
|
|
|
if( u12io_GetFifoLength( dev ) >= dev->scan.dwMaxReadFifo ) {
|
|
|
|
if( u12image_DataIsReady( dev, buf ))
|
|
return SANE_STATUS_GOOD;
|
|
}
|
|
else {
|
|
|
|
b = dev->scan.bNowScanState - dev->scan.oldScanState;
|
|
|
|
if((char) b < 0)
|
|
b += _NUMBER_OF_SCANSTEPS;
|
|
|
|
if( b >= dev->scan.bRefresh ) {
|
|
|
|
u12io_RegisterToScanner( dev, REG_REFRESHSCANSTATE );
|
|
dev->scan.oldScanState = u12io_GetScanState( dev );
|
|
dev->scan.oldScanState &= _SCANSTATE_MASK;
|
|
}
|
|
|
|
if( u12io_GetFifoLength( dev ) >= dev->scan.dwMinReadFifo ) {
|
|
if( u12image_DataIsReady( dev, buf ))
|
|
return SANE_STATUS_GOOD;
|
|
}
|
|
}
|
|
}
|
|
|
|
} while( !u12io_CheckTimer( &timer ));
|
|
|
|
DBG( _DBG_ERROR, "Timeout - Scanner malfunction !!\n" );
|
|
u12motor_ToHomePosition( dev, SANE_TRUE );
|
|
|
|
/* timed out, scanner malfunction */
|
|
return SANE_STATUS_IO_ERROR;
|
|
}
|
|
|
|
/**
|
|
*/
|
|
static void u12image_PrepareScaling( U12_Device *dev )
|
|
{
|
|
int step;
|
|
double ratio;
|
|
|
|
dev->scaleBuf = NULL;
|
|
DBG( _DBG_INFO, "APP-DPIX=%u, MAX-DPIX=%u\n",
|
|
dev->DataInf.xyAppDpi.x, dev->dpi_max_x );
|
|
|
|
if( dev->DataInf.xyAppDpi.x > dev->dpi_max_x ) {
|
|
|
|
dev->scaleBuf = malloc( dev->DataInf.dwAppBytesPerLine );
|
|
|
|
ratio = (double)dev->DataInf.xyAppDpi.x/(double)dev->dpi_max_x;
|
|
dev->scaleIzoom = (int)(1.0/ratio * 1000);
|
|
|
|
switch( dev->DataInf.wAppDataType ) {
|
|
|
|
case COLOR_BW : step = 0; break;
|
|
case COLOR_256GRAY : step = 1; break;
|
|
case COLOR_TRUE24 : step = 3; break;
|
|
case COLOR_TRUE42 : step = 6; break;
|
|
default : step = 99; break;
|
|
}
|
|
dev->scaleStep = step;
|
|
|
|
DBG( _DBG_INFO, "u12image_PrepareScaling: izoom=%i, step=%u\n",
|
|
dev->scaleIzoom, step );
|
|
} else {
|
|
|
|
DBG( _DBG_INFO, "u12image_PrepareScaling: DISABLED\n" );
|
|
}
|
|
}
|
|
|
|
/** scaling picture data in x-direction, using a DDA algorithm
|
|
* (digital differential analyzer).
|
|
*/
|
|
static void u12image_ScaleX( U12_Device *dev, SANE_Byte *ib, SANE_Byte *ob )
|
|
{
|
|
SANE_Byte tmp;
|
|
int ddax;
|
|
u_long i, j, x;
|
|
|
|
/* when not supported, only copy the data */
|
|
if( 99 == dev->scaleStep ) {
|
|
memcpy( ob, ib, dev->DataInf.dwAppBytesPerLine );
|
|
return;
|
|
}
|
|
|
|
/* now scale... */
|
|
if( 0 == dev->scaleStep ) {
|
|
|
|
/* binary scaling */
|
|
ddax = 0;
|
|
x = 0;
|
|
memset( ob, 0, dev->DataInf.dwAppBytesPerLine );
|
|
|
|
for( i = 0; i < dev->DataInf.dwPhysBytesPerLine*8; i++ ) {
|
|
|
|
ddax -= 1000;
|
|
|
|
while( ddax < 0 ) {
|
|
|
|
tmp = ib[(i>>3)];
|
|
|
|
if((x>>3) < dev->DataInf.dwAppBytesPerLine ) {
|
|
if( 0 != (tmp &= (1 << ((~(i & 0x7))&0x7))))
|
|
ob[x>>3] |= (1 << ((~(x & 0x7))&0x7));
|
|
}
|
|
x++;
|
|
ddax += dev->scaleIzoom;
|
|
}
|
|
}
|
|
|
|
} else {
|
|
|
|
/* color and gray scaling */
|
|
ddax = 0;
|
|
x = 0;
|
|
for( i = 0; i < dev->DataInf.dwPhysBytesPerLine*dev->scaleStep;
|
|
i+=dev->scaleStep ) {
|
|
|
|
ddax -= 1000;
|
|
|
|
while( ddax < 0 ) {
|
|
|
|
for( j = 0; j < (u_long)dev->scaleStep; j++ ) {
|
|
|
|
if((x+j) < dev->DataInf.dwAppBytesPerLine ) {
|
|
ob[x+j] = ib[i+j];
|
|
}
|
|
}
|
|
x += dev->scaleStep;
|
|
ddax += dev->scaleIzoom;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* END U12_IMAGE.C ..........................................................*/
|