sane-project-backends/backend/plustek-pp_image.c

1647 wiersze
50 KiB
C
Czysty Wina Historia

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/* @file plustek-pp_image.c
* @brief functions to convert scanner data into image data
*
* based on sources acquired from Plustek Inc.
* Copyright (C) 1998 Plustek Inc.
* Copyright (C) 2000-2013 Gerhard Jaeger <gerhard@gjaeger.de>
* also based on the work done by Rick Bronson
*
* History:
* - 0.30 - initial version
* - 0.31 - no changes
* - 0.32 - no changes
* - 0.33 - no changes
* - 0.34 - reactivated code in imageP96WaitLineData() to recover from
* losing data
* - 0.35 - no changes
* - 0.36 - removed comment
* - added wDither exchange to imageP9xSetupScanSettings
* - added fnHalftoneDirect1 which provides dithering by using random
* thresholds
* - removed the swapping behaviour for model OP_600 in
* fnP96ColorDirect() according to the Primax 4800 Direct tests
* - changes, due to define renaming
* - removed _ASIC_96001 specific stuff to invert colors
* - 0.37 - removed // comments
* - corrected output of 12bit/pixel
* - 0.38 - added P12 stuff
* - renamed WaitLineData functions to ReadOneImageLine
* - 0.39 - fixed a problem in imageP98003ReadOneImageLine, that causes
* these I/O timeouts...
* - 0.40 - no changes
* - 0.41 - no changes
* - 0.42 - fixed a problem for the 12bit modes for ASIC9800x based devices
* - changed include names
* - 0.43 - removed floating point stuff
* - cleanup
* - 0.44 - fix format string issues, as Long types default to int32_t
* now
* .
* <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, see <https://www.gnu.org/licenses/>.
*
* 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>
*/
#include "plustek-pp_scan.h"
/************************ local definitions **********************************/
#define _LINE_TIMEOUT (_SECOND * 5 ) /* max 5 second per line ! */
/*************************** local vars **************************************/
static UShort wPreviewScanned = 0;
static ExpXStepDef posScan[5] = {{128, 8}, {96, 12},
{96, 24}, {96, 48}, {96, 96}};
static ExpXStepDef negScan[5] = {{128, 8}, {96, 12},
{96, 24}, {96, 48}, {96, 96}};
static ExpXStepDef nmlScan[4][5] = {
{{160, 10}, {96, 12}, {96, 24}, {96, 48}, {96, 96}}, /* EPP */
{{160, 10}, {128, 16}, {128, 32}, {192, 96}, {192, 96}}, /* SPP */
{{160, 10}, {96, 12}, {96, 24}, {160, 80}, {160, 160}}, /* BPP */
{{160, 10}, {96, 12}, {96, 24}, {96, 48}, {96, 96}} /* ECP */
};
static ThreshDef xferSpeed[4] = {
{0, 3200, 2500}, {0, 1200, 800}, {0, 800, 1250}, {0, 3200, 2500}
};
/*************************** local functions *********************************/
/** return the correct DPI-value
* The ASIC 96001/3 models are limited to an optical resolution of 300 Dpi
* so it´s necessary to scale in X and Y direction (see scale.c)!
*/
static UShort imageGetPhysDPI( pScanData ps, pImgDef pImgInf, Bool fDpiX )
{
if( _IS_ASIC98(ps->sCaps.AsicID)) {
if (fDpiX) {
if (pImgInf->xyDpi.x > ps->LensInf.rDpiX.wPhyMax)
return ps->LensInf.rDpiX.wPhyMax;
else
return pImgInf->xyDpi.x;
} else {
if (pImgInf->xyDpi.y > ps->LensInf.rDpiY.wPhyMax)
return ps->LensInf.rDpiY.wPhyMax;
else
return pImgInf->xyDpi.y;
}
} else {
if (fDpiX) {
if (pImgInf->wDataType >= COLOR_TRUE24) {
if (pImgInf->xyDpi.x > ps->LensInf.rDpiX.wPhyMax)
return ps->LensInf.rDpiX.wPhyMax;
else
return pImgInf->xyDpi.x;
} else {
if (pImgInf->xyDpi.x > (ps->LensInf.rDpiX.wPhyMax * 2))
return (ps->LensInf.rDpiX.wPhyMax * 2);
else
return pImgInf->xyDpi.x;
}
} else {
if (pImgInf->wDataType >= COLOR_TRUE24 ) {
if (pImgInf->xyDpi.y > (ps->LensInf.rDpiY.wPhyMax / 2))
return (ps->LensInf.rDpiY.wPhyMax / 2);
else
return pImgInf->xyDpi.y;
} else {
if (pImgInf->xyDpi.y > ps->LensInf.rDpiY.wPhyMax)
return ps->LensInf.rDpiY.wPhyMax;
else
return pImgInf->xyDpi.y;
}
}
}
}
/*****************************************************************************
* Sampling stuff for ASIC 98003 *
*****************************************************************************/
static Bool fnEveryLines( pScanData ps )
{
_VAR_NOT_USED( ps );
return _TRUE;
}
static Bool fnSampleLines( pScanData ps )
{
ps->DataInf.wYSum += ps->DataInf.xyAppDpi.y;
if( ps->DataInf.wYSum >= ps->DataInf.xyPhyDpi.y ) {
ps->DataInf.wYSum -= ps->DataInf.xyPhyDpi.y;
return _TRUE;
}
return _FALSE;
}
static Bool fnSamplePreview( pScanData ps )
{
ps->DataInf.wYSum += wPreviewScanned;
if( ps->DataInf.wYSum >= 150 ) {
ps->DataInf.wYSum -= 150;
return _TRUE;
}
return _FALSE;
}
/*****************************************************************************
* Data Processing Routines *
*****************************************************************************/
static Bool fnReadToDriver( pScanData ps )
{
ps->AsicReg.RD_ModeControl = _ModeFifoBSel;
IOReadScannerImageData( ps, ps->Scan.BufPut.blue.bp,
ps->DataInf.dwAsicBytesPerPlane );
ps->AsicReg.RD_ModeControl = _ModeFifoGSel;
IOReadScannerImageData( ps, ps->Scan.BufPut.green.bp,
ps->DataInf.dwAsicBytesPerPlane );
if( ps->Scan.gd_gk.wGreenKeep )
ps->Scan.gd_gk.wGreenKeep--;
else {
ps->Scan.BufPut.green.bp += ps->DataInf.dwAsicBytesPerPlane;
if( ps->Scan.BufPut.green.bp >= ps->Scan.BufEnd.green.bp )
ps->Scan.BufPut.green.bp = ps->Scan.BufBegin.green.bp;
}
ps->AsicReg.RD_ModeControl = _ModeFifoRSel;
IOReadScannerImageData( ps, ps->Scan.BufPut.red.bp,
ps->DataInf.dwAsicBytesPerPlane );
ps->Scan.BufPut.red.bp += ps->DataInf.dwAsicBytesPerPlane;
if( ps->Scan.BufPut.red.bp >= ps->Scan.BufEnd.red.bp )
ps->Scan.BufPut.red.bp = ps->Scan.BufBegin.red.bp;
if( ps->Scan.bd_rk.wRedKeep ) {
ps->Scan.bd_rk.wRedKeep--;
return _FALSE;
} else {
ps->Scan.BufData.green.bp = ps->Scan.BufGet.green.bp;
if( ps->DataInf.dwScanFlag & SCANDEF_ColorBGROrder ) {
ps->Scan.BufData.red.bp = ps->Scan.BufGet.blue.bp;
ps->Scan.BufData.blue.bp = ps->Scan.BufGet.red.bp;
} else {
ps->Scan.BufData.red.bp = ps->Scan.BufGet.red.bp;
ps->Scan.BufData.blue.bp = ps->Scan.BufGet.blue.bp;
}
ps->Scan.BufGet.red.bp += ps->DataInf.dwAsicBytesPerPlane;
ps->Scan.BufGet.green.bp += ps->DataInf.dwAsicBytesPerPlane;
if( ps->Scan.BufGet.red.bp >= ps->Scan.BufEnd.red.bp )
ps->Scan.BufGet.red.bp = ps->Scan.BufBegin.red.bp;
if( ps->Scan.BufGet.green.bp >= ps->Scan.BufEnd.green.bp )
ps->Scan.BufGet.green.bp = ps->Scan.BufBegin.green.bp;
return _TRUE;
}
}
static Bool fnReadOutScanner( pScanData ps )
{
if( ps->Scan.bd_rk.wBlueDiscard ) {
ps->Scan.bd_rk.wBlueDiscard--;
ps->AsicReg.RD_ModeControl = _ModeFifoBSel;
IOReadScannerImageData( ps, ps->Bufs.b1.pReadBuf,
ps->DataInf.dwAsicBytesPerPlane );
if( ps->Scan.gd_gk.wGreenDiscard ) {
ps->Scan.gd_gk.wGreenDiscard--;
ps->AsicReg.RD_ModeControl = _ModeFifoGSel;
IOReadScannerImageData( ps, ps->Bufs.b1.pReadBuf,
ps->DataInf.dwAsicBytesPerPlane);
}
return _FALSE;
} else {
IOReadColorData( ps, ps->Bufs.b1.pReadBuf,
ps->DataInf.dwAsicBytesPerPlane );
return _TRUE;
}
}
/** Interpolates the gray data by using averaged the continuous pixels
*/
static void fnP96GrayDirect( pScanData ps, pVoid pBuf, pVoid pImg, ULong bl )
{
pUChar src, dest;
src = (pUChar)pImg;
dest = (pUChar)pBuf;
for (; bl; bl--, src++, dest++ )
*dest = ps->pbMapRed [*src];
}
/** This routine used in the condition:
* 1) The data type is B/W or GrayScale.
* 2) The required horizontal resolution doesn't exceed the optic spec.
* 3) The required vertical resolution exceeds the optic spec.
* So, the vertcal lines have to average with previous line to smooth the
* image.
*/
static void fnDataDirect( pScanData ps, pVoid pBuf, pVoid pImg, ULong bl )
{
_VAR_NOT_USED( ps );
memcpy( pBuf, pImg, bl );
}
/** According to dither matrix to convert the input gray scale data into
* one-bit data.
*/
static void fnHalftoneDirect0( pScanData ps, pVoid pb, pVoid pImg, ULong bL )
{
pUChar pDither, src, dest;
ULong dw;
src = (pUChar)pImg;
dest = (pUChar)pb;
pDither = &ps->a_bDitherPattern[ps->dwDitherIndex];
for( ; bL; bL--, dest++, pDither -= 8 ) {
for( dw = 8; dw; dw--, src++, pDither++ ) {
if( *src < *pDither ) {
*dest = (*dest << 1) | 0x01;
} else {
*dest <<= 1;
}
}
}
ps->dwDitherIndex = (ps->dwDitherIndex + 8) & 0x3f;
}
/** use random generator to make halftoning
*/
static void fnHalftoneDirect1( pScanData ps, pVoid pb, pVoid pImg, ULong bL )
{
pUChar src, dest;
UChar threshold;
ULong dw;
_VAR_NOT_USED( ps );
src = (pUChar)pImg;
dest = (pUChar)pb;
for (; bL; bL--, dest++ ) {
for (dw = 8; dw; dw--, src++ ) {
threshold = (UChar)MiscLongRand();
if (*src < threshold ) {
*dest = (*dest << 1) | 0x01;
} else {
*dest <<= 1;
}
}
}
}
/** Merges the color planes to pixels style without enlarge operation.
*/
static void fnP98ColorDirect( pScanData ps, pVoid pb, pVoid pImg, ULong bL )
{
pUChar src;
pRGBByteDef dest;
src = (pUChar)pImg;
dest = (pRGBByteDef)pb;
for ( bL = ps->DataInf.dwAsicPixelsPerPlane; bL; bL--, src++, dest++) {
dest->Red = *src;
dest->Green = src[ps->DataInf.dwAsicPixelsPerPlane];
dest->Blue = src[ps->DataInf.dwAsicPixelsPerPlane*2];
}
}
static void fnP96ColorDirect( pScanData ps, pVoid pb, pVoid pImg, ULong bL )
{
pUChar src;
pRGBByteDef dest;
src = (pUChar)pImg;
dest = (pRGBByteDef)pb;
for ( bL = ps->DataInf.dwAsicPixelsPerPlane; bL; bL--, dest++, src++) {
dest->Red =ps->pbMapRed[*src];
dest->Green=ps->pbMapGreen[src[ps->DataInf.dwAsicPixelsPerPlane]];
dest->Blue =ps->pbMapBlue[src[ps->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
*/
static void fnP98Color48( pScanData ps, pVoid pb, pVoid pImg, ULong bL )
{
pUShort src;
pRGBUShortDef dest;
register ULong i;
_VAR_NOT_USED( bL );
src = (pUShort)pImg;
dest = (pRGBUShortDef)pb;
for ( i = ps->DataInf.dwAsicPixelsPerPlane; i; i--, src++, dest++) {
dest->Red = *src;
dest->Green = src[ps->DataInf.dwAsicPixelsPerPlane];
dest->Blue = src[ps->DataInf.dwAsicPixelsPerPlane * 2];
}
}
/** prepare for scanning
*/
static int imageP98SetupScanSettings( pScanData ps, pScanInfo pInf )
{
UShort brightness;
DBG( DBG_LOW, "imageP98SetupScanSettings()\n" );
ps->DataInf.dwScanFlag = pInf->ImgDef.dwFlag;
ps->DataInf.dwVxdFlag = 0;
ps->DataInf.crImage = pInf->ImgDef.crArea;
/* AdjustOriginXByLens
* [NOTE]
* Here we just simply adjust it to double (600 DPI is two times of
* 300 DPI), but if this model is a multi-lens scanner, we should adjust
* it according to different lens.
*/
ps->DataInf.crImage.x <<= 1;
ps->DataInf.xyAppDpi = pInf->ImgDef.xyDpi;
ps->DataInf.siBrightness = pInf->siBrightness;
ps->DataInf.wDither = pInf->wDither;
ps->DataInf.wAppDataType = pInf->ImgDef.wDataType;
ps->GetImageInfo( ps, &pInf->ImgDef );
if (ps->DataInf.dwVxdFlag & _VF_DATATOUSERBUFFER) {
ps->Scan.DataProcess = fnDataDirect;
}
if (ps->DataInf.dwScanFlag & SCANDEF_BmpStyle) {
ps->Scan.lBufferAdjust = -(Long)ps->DataInf.dwAppBytesPerLine;
} else {
ps->Scan.lBufferAdjust = (Long)ps->DataInf.dwAppBytesPerLine;
}
DBG( DBG_LOW, "Scan settings:\n" );
DBG( DBG_LOW, "ImageInfo: (x=%u,y=%u,dx=%u,dy=%u)\n",
ps->DataInf.crImage.x, ps->DataInf.crImage.y,
ps->DataInf.crImage.cx, ps->DataInf.crImage.cy );
/*
* SetBwBrightness
* [NOTE]
*
* 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 = _DefBwThreshold + White * Input / 127;
* Input < 0, and White = 255 - _DefBwThreshold, so
* = _DefBwThreshold - (255 - _DefBwThreshold) * Input / 127;
* The brighter is the same idea.
*
* CHECK: it seems that the brightness only works for the binary mode !
*/
if( ps->DataInf.wPhyDataType != COLOR_BW ) {/* if not line art */
ps->wBrightness = pInf->siBrightness; /* use internal tables for */
ps->wContrast = pInf->siContrast; /* brightness and contrast */
pInf->siBrightness = 0; /* don't use asic for threshold */
}
/* CHECK: We have now two methods for setting the brightness...
*/
DBG( DBG_LOW, "brightness = %i\n", pInf->siBrightness );
if (ps->DataInf.siBrightness < 0) {
brightness = (UShort)(_DEF_BW_THRESHOLD -
(255 - _DEF_BW_THRESHOLD) * ps->DataInf.siBrightness /127);
} else {
brightness = (UShort)(_DEF_BW_THRESHOLD -
_DEF_BW_THRESHOLD * ps->DataInf.siBrightness /127);
}
ps->AsicReg.RD_ThresholdControl = brightness;
DBG( DBG_LOW, "1. brightness = %i\n", brightness );
if( ps->DataInf.siBrightness >= 0 ) {
brightness = (short)((long)(-(255 - _DEF_BW_THRESHOLD) *
ps->DataInf.siBrightness) / 127 + _DEF_BW_THRESHOLD);
} else {
brightness = (short)((long)(_DEF_BW_THRESHOLD *
ps->DataInf.siBrightness) / 127 + _DEF_BW_THRESHOLD);
}
brightness = (brightness ^ 0xff) & 0xff;
if( _ASIC_IS_98003 == ps->sCaps.AsicID ) {
ps->AsicReg.RD_ThresholdControl = brightness;
DBG( DBG_LOW, "2. brightness = %i\n", brightness );
}
ps->DataInf.pCurrentBuffer = ps->pScanBuffer1;
return _OK;
}
/**
*/
static void imageP98DoCopyBuffer( pScanData ps, pUChar pImage )
{
memcpy( ps->pFilterBuf, pImage, ps->DataInf.dwAsicBytesPerPlane );
ps->pFilterBuf += 5120;
if (ps->pFilterBuf >= ps->pEndBuf)
ps->pFilterBuf = ps->pProcessingBuf;
}
/**
*/
static Bool imageP98CopyToFilterBuffer( pScanData ps, pUChar pImage )
{
if (ps->fDoFilter) {
if (ps->fFilterFirstLine) {
imageP98DoCopyBuffer( ps, pImage );
imageP98DoCopyBuffer( ps, pImage );
ps->dwLinesFilter--;
return _FALSE;
} else {
imageP98DoCopyBuffer( ps, pImage );
if ((ps->dwLinesFilter--) == 0)
imageP98DoCopyBuffer( ps, pImage);
}
}
return _TRUE;
}
/**
*/
static void imageP98UnSharpCompare( pScanData ps, Byte Center,
Byte Neighbour, pLong pdwNewValue )
{
Byte b;
b = (Center >= Neighbour) ? Center - Neighbour : Neighbour - Center ;
if (b > ps->bOffsetFilter) {
*pdwNewValue -= (Long)Neighbour;
ps->dwDivFilter--;
}
}
/**
*/
static void imageP98DoFilter( pScanData ps, pUChar pPut )
{
ULong dw;
Long dwNewValue;
if (ps->fDoFilter && (ps->DataInf.xyAppDpi.x) >= 600UL) {
/* DoUnsharpMask(); */
for (dw = 0; dw < ps->DataInf.dwAsicBytesPerPlane - 2; dw++, pPut++) {
ps->dwDivFilter = ps->dwMul;
dwNewValue = ((ULong)ps->pGet2[dw+1]) * ps->dwMul;
imageP98UnSharpCompare( ps, ps->pGet2[dw+1], ps->pGet1[dw], &dwNewValue);
imageP98UnSharpCompare( ps, ps->pGet2[dw+1], ps->pGet1[dw+1], &dwNewValue);
imageP98UnSharpCompare( ps, ps->pGet2[dw+1], ps->pGet1[dw+2], &dwNewValue);
imageP98UnSharpCompare( ps, ps->pGet2[dw+1], ps->pGet2[dw], &dwNewValue);
imageP98UnSharpCompare( ps, ps->pGet2[dw+1], ps->pGet2[dw+2], &dwNewValue);
imageP98UnSharpCompare( ps, ps->pGet2[dw+1], ps->pGet3[dw], &dwNewValue);
imageP98UnSharpCompare( ps, ps->pGet2[dw+1], ps->pGet3[dw+1], &dwNewValue);
imageP98UnSharpCompare( ps, ps->pGet2[dw+1], ps->pGet3[dw+2], &dwNewValue);
if( dwNewValue > 0 ) {
if((dwNewValue /= ps->dwDivFilter) < 255) {
*pPut = (Byte) dwNewValue;
} else {
*pPut = 255;
}
} else {
*pPut = 0;
}
}
pPut = ps->pGet1;
ps->pGet1 = ps->pGet2;
ps->pGet2 = ps->pGet3;
ps->pGet3 = pPut;
}
}
/**
*/
static Bool imageP98DataIsReady( pScanData ps )
{
Byte b;
ps->Scan.fMotorBackward = _FALSE;
ps->bMoveDataOutFlag = _DataAfterRefreshState;
b = (ps->DataInf.wPhyDataType >= COLOR_TRUE24) ?
_BLUE_DATA_READY : _GREEN_DATA_READY;
while( _TRUE ) {
ps->dwColorRunIndex ++;
if(ps->pColorRunTable[ps->dwColorRunIndex] & b)
break;
}
if (b == _GREEN_DATA_READY) {
ps->AsicReg.RD_ModeControl = _ModeFifoGSel;
IOReadScannerImageData( ps, ps->DataInf.pCurrentBuffer,
ps->DataInf.dwAsicBytesPerPlane );
imageP98CopyToFilterBuffer( ps, ps->DataInf.pCurrentBuffer );
} else {
/* ReadColorImageData() */
if( ps->DataInf.dwScanFlag & SCANDEF_ColorBGROrder ) {
ps->AsicReg.RD_ModeControl = _ModeFifoRSel;
IOReadScannerImageData( ps, ps->pScanBuffer1 +
ps->DataInf.dwAsicBytesPerPlane * 2,
ps->DataInf.dwAsicBytesPerPlane );
ps->AsicReg.RD_ModeControl = _ModeFifoGSel;
IOReadScannerImageData( ps, ps->pScanBuffer1 +
ps->DataInf.dwAsicBytesPerPlane,
ps->DataInf.dwAsicBytesPerPlane );
ps->AsicReg.RD_ModeControl = _ModeFifoBSel;
IOReadScannerImageData( ps, ps->pScanBuffer1,
ps->DataInf.dwAsicBytesPerPlane );
} else {
IOReadColorData( ps, ps->pScanBuffer1,
ps->DataInf.dwAsicBytesPerPlane );
}
}
if (ps->fFilterFirstLine) {
ps->fFilterFirstLine = _FALSE;
return _TRUE;
}
imageP98DoFilter( ps, ps->DataInf.pCurrentBuffer );
(*ps->Scan.DataProcess)( ps, ps->Scan.bp.pMonoBuf,
ps->DataInf.pCurrentBuffer,
ps->DataInf.dwAppPhyBytesPerLine );
return _TRUE;
}
/** here we wait for one data-line
*/
static Bool imageP98001ReadOneImageLine( pScanData ps )
{
ULong dwFifoCounter;
TimerDef timer;
MiscStartTimer( &timer, _LINE_TIMEOUT );
do {
ps->Scan.bNowScanState = IOGetScanState( ps, _FALSE );
dwFifoCounter = IOReadFifoLength( ps );
if (!(ps->Scan.bNowScanState & _SCANSTATE_STOP) &&
(dwFifoCounter < ps->dwMaxReadFifoData)) {
if( ps->Scan.bOldScanState != ps->Scan.bNowScanState )
ps->UpdateDataCurrentReadLine( ps );
if( dwFifoCounter >= ps->Scan.dwMinReadFifo )
return imageP98DataIsReady( ps );
} else { /* ScanStateIsStop */
if (dwFifoCounter >= ps->dwSizeMustProcess)
return imageP98DataIsReady( ps );
ps->UpdateDataCurrentReadLine( ps );
if( dwFifoCounter >= ps->Scan.dwMinReadFifo )
return imageP98DataIsReady( ps );
}
_DODELAY(10); /* delay 10 ms */
} while (!MiscCheckTimer( &timer ));
DBG( DBG_HIGH, "Timeout - Scanner malfunction !!\n" );
MotorToHomePosition(ps);
/* timed out, scanner malfunction */
return _FALSE;
}
/** calculate the image properties according to the scanmode
*/
static void imageP98GetInfo( pScanData ps, pImgDef pImgInf )
{
DBG( DBG_LOW, "imageP98GetInfo()\n" );
ps->DataInf.xyPhyDpi.x = imageGetPhysDPI( ps, pImgInf, _TRUE );
ps->DataInf.xyPhyDpi.y = imageGetPhysDPI( ps, pImgInf, _FALSE );
DBG( DBG_LOW, "xyPhyDpi.x = %u, xyPhyDpi.y = %u\n",
ps->DataInf.xyPhyDpi.x, ps->DataInf.xyPhyDpi.y );
DBG( DBG_LOW, "crArea.x = %u, crArea.y = %u\n",
pImgInf->crArea.x, pImgInf->crArea.y );
DBG( DBG_LOW, "crArea.cx = %u, crArea.cy = %u\n",
pImgInf->crArea.cx, pImgInf->crArea.cy );
ps->DataInf.XYRatio = 1000 * ps->DataInf.xyPhyDpi.y/ps->DataInf.xyPhyDpi.x;
DBG( DBG_LOW, "xyDpi.x = %u, xyDpi.y = %u, XYRatio = %u\n",
pImgInf->xyDpi.x, pImgInf->xyDpi.y, ps->DataInf.XYRatio );
ps->DataInf.dwAppLinesPerArea = (ULong)pImgInf->crArea.cy *
pImgInf->xyDpi.y / _MEASURE_BASE;
ps->DataInf.dwAppPixelsPerLine = (ULong)pImgInf->crArea.cx *
pImgInf->xyDpi.x / _MEASURE_BASE;
ps->DataInf.dwPhysBytesPerLine = (ULong)pImgInf->crArea.cx *
ps->DataInf.xyPhyDpi.x / _MEASURE_BASE;
if( pImgInf->wDataType <= COLOR_HALFTONE ) {
ps->DataInf.dwAsicPixelsPerPlane = (ps->DataInf.dwAppPixelsPerLine+7UL)&
0xfffffff8UL;
ps->DataInf.dwAppPhyBytesPerLine =
ps->DataInf.dwAppBytesPerLine =
ps->DataInf.dwAsicBytesPerLine =
ps->DataInf.dwAsicBytesPerPlane = ps->DataInf.dwAsicPixelsPerPlane>>3;
} else {
ps->DataInf.dwAsicBytesPerPlane =
ps->DataInf.dwAsicPixelsPerPlane = ps->DataInf.dwAppPixelsPerLine;
}
if( COLOR_TRUE48 == pImgInf->wDataType ) {
ps->DataInf.dwAsicBytesPerPlane *= 2;
}
switch( pImgInf->wDataType ) {
case COLOR_BW:
ps->DataInf.dwVxdFlag |= _VF_DATATOUSERBUFFER;
ps->DataInf.wPhyDataType = COLOR_BW;
ps->Shade.bIntermediate = _ScanMode_Mono;
break;
case COLOR_HALFTONE:
if( ps->DataInf.wDither == 2 ) {
ps->Scan.DataProcess = fnHalftoneDirect1;
} else {
ps->Scan.DataProcess = fnHalftoneDirect0;
}
/*
* CHANGE: it seems, that we have to use the same settings as for 256GRAY
*/
ps->DataInf.dwAsicBytesPerPlane =
ps->DataInf.dwAsicPixelsPerPlane = ps->DataInf.dwAppPixelsPerLine;
ps->DataInf.wPhyDataType = COLOR_256GRAY;
ps->Shade.bIntermediate = _ScanMode_Mono;
break;
case COLOR_256GRAY:
ps->DataInf.dwVxdFlag |= _VF_DATATOUSERBUFFER;
ps->DataInf.dwAsicBytesPerLine =
ps->DataInf.dwAppPhyBytesPerLine = ps->DataInf.dwAppPixelsPerLine;
ps->DataInf.wPhyDataType = COLOR_256GRAY;
ps->Shade.bIntermediate = _ScanMode_Mono;
break;
case COLOR_TRUE24:
ps->Scan.DataProcess = fnP98ColorDirect;
ps->DataInf.dwAsicBytesPerLine =
ps->DataInf.dwAppPhyBytesPerLine = ps->DataInf.dwAppPixelsPerLine * 3;
ps->DataInf.wPhyDataType = COLOR_TRUE24;
ps->Shade.bIntermediate = _ScanMode_Color;
break;
case COLOR_TRUE48:
ps->Scan.DataProcess = fnP98Color48;
ps->DataInf.dwAsicBytesPerLine =
ps->DataInf.dwAppPhyBytesPerLine = ps->DataInf.dwAppPixelsPerLine * 6;
ps->DataInf.wPhyDataType = COLOR_TRUE48;
ps->Shade.bIntermediate = _ScanMode_Color;
break;
}
if (pImgInf->dwFlag & SCANDEF_BoundaryDWORD) {
ps->DataInf.dwAppBytesPerLine = (ps->DataInf.dwAppPhyBytesPerLine + 3) &
0xfffffffc;
} else {
if (pImgInf->dwFlag & SCANDEF_BoundaryWORD) {
ps->DataInf.dwAppBytesPerLine = (ps->DataInf.dwAppPhyBytesPerLine + 1) &
0xfffffffe;
} else {
ps->DataInf.dwAppBytesPerLine = ps->DataInf.dwAppPhyBytesPerLine;
}
}
DBG( DBG_LOW, "AppLinesPerArea = %u\n", ps->DataInf.dwAppLinesPerArea );
DBG( DBG_LOW, "AppPixelsPerLine = %u\n", ps->DataInf.dwAppPixelsPerLine );
DBG( DBG_LOW, "AppPhyBytesPerLine = %u\n", ps->DataInf.dwAppPhyBytesPerLine );
DBG( DBG_LOW, "AppBytesPerLine = %u\n", ps->DataInf.dwAppBytesPerLine );
DBG( DBG_LOW, "AsicPixelsPerPlane = %u\n", ps->DataInf.dwAsicPixelsPerPlane );
DBG( DBG_LOW, "AsicBytesPerPlane = %u\n", ps->DataInf.dwAsicBytesPerPlane );
DBG( DBG_LOW, "AsicBytesPerLine = %u\n", ps->DataInf.dwAsicBytesPerLine );
DBG( DBG_LOW, "Physical Bytes = %u\n", ps->DataInf.dwPhysBytesPerLine );
}
/**
*/
static void imageP96GetInfo( pScanData ps, pImgDef pImgInf )
{
DBG( DBG_LOW, "imageP96GetInfo()\n" );
ps->DataInf.xyPhyDpi.x = imageGetPhysDPI( ps, pImgInf, _TRUE );
ps->DataInf.xyPhyDpi.y = imageGetPhysDPI( ps, pImgInf, _FALSE );
DBG( DBG_LOW, "xyPhyDpi.x = %u, xyPhyDpi.y = %u\n",
ps->DataInf.xyPhyDpi.x, ps->DataInf.xyPhyDpi.y );
DBG( DBG_LOW, "crArea.x = %u, crArea.y = %u\n",
pImgInf->crArea.x, pImgInf->crArea.y );
DBG( DBG_LOW, "crArea.cx = %u, crArea.cy = %u\n",
pImgInf->crArea.cx, pImgInf->crArea.cy );
ps->DataInf.XYRatio = 1000 * ps->DataInf.xyPhyDpi.y/ps->DataInf.xyPhyDpi.x;
DBG( DBG_LOW, "xyDpi.x = %u, xyDpi.y = %u, XYRatio = %u\n",
pImgInf->xyDpi.x, pImgInf->xyDpi.y, ps->DataInf.XYRatio );
ps->DataInf.dwAppLinesPerArea = (ULong)pImgInf->crArea.cy *
pImgInf->xyDpi.y / _MEASURE_BASE;
ps->DataInf.dwAsicBytesPerPlane =
ps->DataInf.dwAsicPixelsPerPlane = (ULong)ps->DataInf.xyPhyDpi.x *
pImgInf->crArea.cx / _MEASURE_BASE;
ps->DataInf.dwAppPixelsPerLine = (ULong)pImgInf->crArea.cx *
pImgInf->xyDpi.x / _MEASURE_BASE;
ps->DataInf.dwPhysBytesPerLine = (ULong)pImgInf->crArea.cx *
ps->DataInf.xyPhyDpi.x / _MEASURE_BASE;
ps->DataInf.wPhyDataType = ps->DataInf.wAppDataType;
switch( pImgInf->wDataType ) {
case COLOR_BW:
ps->DataInf.dwAsicBytesPerPlane =
(ps->DataInf.dwAsicPixelsPerPlane + 7) >> 3;
ps->DataInf.dwAppPhyBytesPerLine =
(ps->DataInf.dwAppPixelsPerLine + 7) >> 3;
ps->DataInf.dwVxdFlag |= _VF_DATATOUSERBUFFER;
ps->Scan.DataProcess = fnDataDirect;
break;
case COLOR_HALFTONE:
ps->DataInf.dwAppPhyBytesPerLine =
(ps->DataInf.dwAsicPixelsPerPlane + 7) >> 3;
if( ps->DataInf.wDither == 2 ) {
ps->Scan.DataProcess = fnHalftoneDirect1;
} else {
ps->Scan.DataProcess = fnHalftoneDirect0;
}
ps->DataInf.wPhyDataType = COLOR_256GRAY;
break;
case COLOR_256GRAY:
ps->DataInf.dwAppPhyBytesPerLine = ps->DataInf.dwAppPixelsPerLine;
ps->Scan.DataProcess = fnP96GrayDirect;
break;
case COLOR_TRUE24:
#ifdef _A3I_EN
ps->Scan.DataProcess = fnP98ColorDirect;
#else
ps->Scan.DataProcess = fnP96ColorDirect;
#endif
ps->DataInf.dwAppPhyBytesPerLine = ps->DataInf.dwAppPixelsPerLine * 3;
}
if( pImgInf->dwFlag & SCANDEF_BoundaryDWORD ) {
ps->DataInf.dwAppBytesPerLine =
(ps->DataInf.dwAppPhyBytesPerLine + 3) & 0xfffffffc;
} else {
if ( pImgInf->dwFlag & SCANDEF_BoundaryWORD ) {
ps->DataInf.dwAppBytesPerLine =
(ps->DataInf.dwAppPhyBytesPerLine + 1) & 0xfffffffe;
} else {
ps->DataInf.dwAppBytesPerLine = ps->DataInf.dwAppPhyBytesPerLine;
}
}
if (ps->DataInf.wPhyDataType == COLOR_TRUE24)
ps->DataInf.dwAsicBytesPerLine = ps->DataInf.dwAsicBytesPerPlane * 3;
else
ps->DataInf.dwAsicBytesPerLine = ps->DataInf.dwAsicBytesPerPlane;
/* WORK: AsicBytesPerLine only used for ASIC_98001 based scanners - try to remove
** that, also try to remove redundant info
*/
DBG( DBG_LOW, "AppLinesPerArea = %u\n", ps->DataInf.dwAppLinesPerArea );
DBG( DBG_LOW, "AppPixelsPerLine = %u\n", ps->DataInf.dwAppPixelsPerLine );
DBG( DBG_LOW, "AppPhyBytesPerLine = %u\n", ps->DataInf.dwAppPhyBytesPerLine );
DBG( DBG_LOW, "AppBytesPerLine = %u\n", ps->DataInf.dwAppBytesPerLine );
DBG( DBG_LOW, "AsicPixelsPerPlane = %u\n", ps->DataInf.dwAsicPixelsPerPlane );
DBG( DBG_LOW, "AsicBytesPerPlane = %u\n", ps->DataInf.dwAsicBytesPerPlane );
DBG( DBG_LOW, "AsicBytesPerLine = %u\n", ps->DataInf.dwAsicBytesPerLine );
DBG( DBG_LOW, "Physical Bytes = %u\n", ps->DataInf.dwPhysBytesPerLine );
}
/** here we wait for one data-line
*/
static Bool imageP96ReadOneImageLine( pScanData ps )
{
Bool result = _FALSE;
Byte bData, bFifoCount;
TimerDef timer;
MiscStartTimer( &timer, _LINE_TIMEOUT);
do {
bFifoCount = IODataRegisterFromScanner( ps, ps->RegFifoOffset );
/* CHECK ps->bMoveDataOutFlag will never be set to _DataFromStopState !!!*/
#if 1
if ((bFifoCount < ps->bMinReadFifo) &&
(ps->bMoveDataOutFlag == _DataFromStopState)) {
bData = IOGetScanState( ps, _FALSE);
if (!(bData & _SCANSTATE_STOP)) {
if (bData < ps->bCurrentLineCount)
bData += _NUMBER_OF_SCANSTEPS;
if ((bData - ps->bCurrentLineCount) < _SCANSTATE_BYTES)
continue;
}
ps->bMoveDataOutFlag = _DataAfterRefreshState;
}
#endif
/*
// HEINER:A3I
// if( ps->bMoveDataOutFlag != _DataFromStopState )
// ps->UpdateDataCurrentReadLine( ps );
*/
if( bFifoCount >= ps->bMinReadFifo ) {
/* data is ready */
for (; !(*ps->pCurrentColorRunTable &
(ps->RedDataReady | ps->GreenDataReady | _BLUE_DATA_READY));
ps->pCurrentColorRunTable++);
#ifdef DEBUG
if( ps->pCurrentColorRunTable >
(ps->pColorRunTable+ps->BufferForColorRunTable))
DBG( DBG_LOW, "WARNING: pCurrentColorRunTab>pColorRunTable\n");
#endif
if (ps->DataInf.wPhyDataType == COLOR_TRUE24) {
/* read color planes (either R/G/B or R/B/G sequence that
* depends on COLOR CCD, see below
*/
if (*ps->pCurrentColorRunTable & ps->b1stColor) {
*ps->pCurrentColorRunTable &= ps->b1stMask;
IOReadScannerImageData (ps, ps->pPutBufR,
ps->DataInf.dwAsicBytesPerPlane);
ps->pPutBufR += ps->BufferSizePerModel;
if (ps->pPutBufR == ps->pEndBufR)
ps->pPutBufR = ps->pPrescan16;
} else
if (*ps->pCurrentColorRunTable & ps->b2ndColor) {
*ps->pCurrentColorRunTable &= ps->b2ndMask;
IOReadScannerImageData( ps, ps->pPutBufG,
ps->DataInf.dwAsicBytesPerPlane);
ps->pPutBufG += ps->BufferSizePerModel;
if (ps->pPutBufG == ps->pEndBufG)
ps->pPutBufG = ps->pPrescan8;
} else {
*ps->pCurrentColorRunTable &= ps->b3rdMask;
ps->pCurrentColorRunTable++; /* processed this step */
/* according to CCD type & image placement method to
* read third color into corresponding location.
* SONY CCD: Red, Green and Blue.
* TOSHIBA CCD: Red, Blue and Green.
* SCANDEF_BmpStyle: Blue, Green and Red, Otherwise
* Red, Green and Blue.
*/
if (ps->b3rdColor & ps->GreenDataReady) {
/* Green always in middle */
IOReadScannerImageData (ps,
ps->DataInf.pCurrentBuffer +
ps->DataInf.dwAsicBytesPerPlane,
ps->DataInf.dwAsicBytesPerPlane);
} else {
/* Blue depends the request style from caller */
if (ps->DataInf.dwScanFlag & SCANDEF_BmpStyle) {
/* BMP style, blue is the first one */
IOReadScannerImageData (ps,
ps->DataInf.pCurrentBuffer,
ps->DataInf.dwAsicBytesPerPlane);
} else {
/* Blue is the last one */
IOReadScannerImageData (ps, ps->DataInf.pCurrentBuffer +
ps->DataInf.dwAsicBytesPerPlane * 2,
ps->DataInf.dwAsicBytesPerPlane);
}
}
/* reassemble 3 color lines for separated RGB value */
if (ps->DataInf.dwScanFlag & SCANDEF_BmpStyle) {
/* BMP style, red is last one */
memcpy( ps->DataInf.pCurrentBuffer +
ps->DataInf.dwAsicBytesPerPlane * 2,
ps->pGetBufR, ps->DataInf.dwAsicBytesPerPlane);
} else {
/* Red is first one */
memcpy( ps->DataInf.pCurrentBuffer,
ps->pGetBufR, ps->DataInf.dwAsicBytesPerPlane );
}
if (ps->b2ndColor & ps->GreenDataReady) {
/* Green always in middle */
memcpy( ps->DataInf.pCurrentBuffer +
ps->DataInf.dwAsicBytesPerPlane,
ps->pGetBufG, ps->DataInf.dwAsicBytesPerPlane);
} else {
/* Blue depends the request style from caller */
if (ps->DataInf.dwScanFlag & SCANDEF_BmpStyle) {
/* BMP style, blue is the first one */
memcpy( ps->DataInf.pCurrentBuffer,
ps->pGetBufG,
ps->DataInf.dwAsicBytesPerPlane);
} else {
/* BMP style, blue is the last one */
memcpy( ps->DataInf.pCurrentBuffer +
ps->DataInf.dwAsicBytesPerPlane * 2,
ps->pGetBufG,
ps->DataInf.dwAsicBytesPerPlane );
}
}
/* Adjust the get pointers */
ps->pGetBufR += ps->BufferSizePerModel;
ps->pGetBufG += ps->BufferSizePerModel;
if (ps->pGetBufR == ps->pEndBufR)
ps->pGetBufR = ps->pPrescan16;
if (ps->pGetBufG == ps->pEndBufG)
ps->pGetBufG = ps->pPrescan8;
result = _TRUE; /* Line data in buffer */
break;
}
/* reset timer for new 10-second interval */
MiscStartTimer( &timer, (10 * _SECOND));
} else {
/* Gray Image */
*ps->pCurrentColorRunTable &= 0xf0; /* leave high nibble for debug */
ps->pCurrentColorRunTable++; /* this step has been processed */
IOReadScannerImageData( ps, ps->DataInf.pCurrentBuffer,
ps->DataInf.dwAsicBytesPerPlane );
result = _TRUE;
break;
}
}
/* HEINER:A3I */
if( ps->bMoveDataOutFlag != _DataFromStopState )
ps->UpdateDataCurrentReadLine( ps );
} while (!MiscCheckTimer( &timer));
if( _TRUE == result ) {
(*ps->Scan.DataProcess)( ps, ps->Scan.bp.pMonoBuf,
ps->DataInf.pCurrentBuffer,
ps->DataInf.dwAppPhyBytesPerLine );
return _TRUE;
}
DBG( DBG_HIGH, "Timeout - Scanner malfunction !!\n" );
MotorToHomePosition(ps);
return _FALSE;
}
/** prepare for scanning
*/
static int imageP96SetupScanSettings( pScanData ps, pScanInfo pInf )
{
DBG( DBG_LOW, "imageSetupP96ScanSettings()\n" );
ps->DataInf.dwVxdFlag = 0;
if (pInf->ImgDef.dwFlag & SCANDEF_BuildBwMap)
ps->DataInf.dwVxdFlag |= _VF_BUILDMAP;
ps->DataInf.dwScanFlag = pInf->ImgDef.dwFlag;
ps->DataInf.crImage = pInf->ImgDef.crArea;
/* scale according to DPI */
ps->DataInf.crImage.x *= ps->PhysicalDpi / _MEASURE_BASE;
ps->DataInf.crImage.cx *= ps->PhysicalDpi / _MEASURE_BASE;
if( ps->DataInf.dwScanFlag & SCANDEF_TPA ) {
ps->DataInf.crImage.x += _Transparency48OriginOffsetX;
ps->DataInf.crImage.y += _Transparency48OriginOffsetY;
}
ps->DataInf.xyAppDpi = pInf->ImgDef.xyDpi;
ps->DataInf.wAppDataType = pInf->ImgDef.wDataType;
ps->DataInf.wDither = pInf->wDither;
ps->GetImageInfo( ps, &pInf->ImgDef );
/* try to get brightness to work */
if (ps->DataInf.wPhyDataType != COLOR_BW) { /* if not line art */
ps->wBrightness = pInf->siBrightness; /* use internal tables for */
ps->wContrast = pInf->siContrast; /* brightness and contrast */
pInf->siBrightness = 0; /* don't use asic for threshold */
}
ps->DataInf.siBrightness = pInf->siBrightness;
if (ps->DataInf.dwScanFlag & SCANDEF_BmpStyle)
ps->Scan.lBufferAdjust = -(Long)ps->DataInf.dwAppBytesPerLine;
else
ps->Scan.lBufferAdjust = (Long)ps->DataInf.dwAppBytesPerLine;
if (ps->DataInf.siBrightness < 0)
ps->DataInf.siBrightness = 255 - (_DEF_BW_THRESHOLD *
ps->DataInf.siBrightness / 127 + _DEF_BW_THRESHOLD);
else
ps->DataInf.siBrightness = 255 - ((255 - _DEF_BW_THRESHOLD) *
ps->DataInf.siBrightness / 127 + _DEF_BW_THRESHOLD);
ps->AsicReg.RD_ThresholdControl = (Byte)ps->DataInf.siBrightness;
ps->DataInf.pCurrentBuffer = ps->pScanBuffer1;
return _OK;
}
/**
*/
static Bool imageP98003DataIsReady( pScanData ps )
{
pUChar pb;
if( ps->Scan.bDiscardAll ) {
ps->Scan.bDiscardAll--;
if( ps->DataInf.wPhyDataType <= COLOR_256GRAY ) {
ps->AsicReg.RD_ModeControl = _ModeFifoGSel;
IOReadScannerImageData( ps, ps->Bufs.b1.pReadBuf,
ps->DataInf.dwAsicBytesPerPlane );
} else {
IOReadColorData( ps, ps->Bufs.b1.pReadBuf,
ps->DataInf.dwAsicBytesPerPlane );
}
return _FALSE;
}
if( ps->DataInf.wPhyDataType <= COLOR_256GRAY ) {
ps->AsicReg.RD_ModeControl = _ModeFifoGSel;
pb = ps->Scan.bp.pMonoBuf;
/* use a larger buffer during halftone reads...*/
if( ps->DataInf.wAppDataType == COLOR_HALFTONE )
pb = ps->Scan.BufPut.red.bp;
IOReadScannerImageData( ps, pb, ps->DataInf.dwAsicBytesPerPlane );
} else {
if( !ps->Scan.DataRead( ps )) {
return _FALSE;
}
}
if( ps->Scan.DoSample( ps )) {
if( ps->Scan.dwLinesToRead == 1 &&
!(IOGetScanState( ps, _TRUE ) & _SCANSTATE_STOP))
IORegisterToScanner( ps, ps->RegRefreshScanState );
/* direct is done here without copying...*/
if( fnDataDirect != ps->Scan.DataProcess ) {
(*ps->Scan.DataProcess)(ps, (pVoid)(ps->Scan.bp.pMonoBuf ),
(pVoid)(ps->Scan.BufPut.red.bp),
ps->DataInf.dwAppPhyBytesPerLine);
}
return _TRUE;
}
return _FALSE;
}
/**
*/
static Bool imageP98003ReadOneImageLine( pScanData ps )
{
Byte b, state;
TimerDef timer, t2;
MiscStartTimer( &timer, _LINE_TIMEOUT );
MiscStartTimer( &t2, _SECOND*2 );
do {
state = IOGetScanState( ps, _TRUE );
ps->Scan.bNowScanState = (state & _SCANSTATE_MASK);
if( state & _SCANSTATE_STOP ) {
MotorP98003ModuleForwardBackward( ps );
if( IOReadFifoLength( ps ) >= ps->Scan.dwMinReadFifo )
if( imageP98003DataIsReady( ps ))
return _TRUE;
} else {
ps->Scan.bModuleState = _MotorInNormalState;
b = ps->Scan.bNowScanState - ps->Scan.bOldScanState;
if((char) b < 0)
b += _NUMBER_OF_SCANSTEPS;
if( b >= ps->Scan.bRefresh ) {
IORegisterToScanner( ps, ps->RegRefreshScanState );
ps->Scan.bOldScanState = IOGetScanState( ps, _TRUE );
ps->Scan.bOldScanState &= _SCANSTATE_MASK;
}
if( IOReadFifoLength( ps ) >= ps->Scan.dwMaxReadFifo ) {
if( imageP98003DataIsReady( ps ))
return _TRUE;
} else {
b = ps->Scan.bNowScanState - ps->Scan.bOldScanState;
if((char) b < 0)
b += _NUMBER_OF_SCANSTEPS;
if( b >= ps->Scan.bRefresh ) {
IORegisterToScanner( ps, ps->RegRefreshScanState );
ps->Scan.bOldScanState = IOGetScanState( ps, _TRUE );
ps->Scan.bOldScanState &= _SCANSTATE_MASK;
}
if( IOReadFifoLength( ps ) >= ps->Scan.dwMinReadFifo ) {
if( imageP98003DataIsReady( ps ))
return _TRUE;
}
}
}
_DODELAY(5); /* delay 5 ms */
} while( !MiscCheckTimer( &timer ));
DBG( DBG_HIGH,
"Timeout - Scanner malfunction !!\n" );
MotorToHomePosition(ps);
/* timed out, scanner malfunction */
return _FALSE;
}
/**
*/
static void imageP98003SetupScanStateVariables( pScanData ps, ULong index )
{
DataType var;
ps->Scan.dpiIdx = index;
if(!(ps->DataInf.dwScanFlag & SCANDEF_TPA)) {
if(((ps->IO.portMode == _PORT_BIDI) ||
(ps->IO.portMode == _PORT_SPP)) &&
(ps->DataInf.wPhyDataType > COLOR_TRUE24) &&
(ps->DataInf.xyAppDpi.y >= 600)) {
ps->Shade.wExposure = nmlScan[ps->IO.portMode][index].exposureTime;
ps->Shade.wXStep = nmlScan[ps->IO.portMode][index].xStepTime;
} else {
ps->Shade.wExposure = nmlScan[_PORT_EPP][index].exposureTime;
ps->Shade.wXStep = nmlScan[_PORT_EPP][index].xStepTime;
}
if( ps->Shade.bIntermediate & _ScanMode_AverageOut ) {
ps->Shade.wExposure >>= 1;
ps->Shade.wXStep >>= 1;
}
} else {
if( ps->DataInf.dwScanFlag & SCANDEF_Transparency ) {
ps->Shade.wExposure = posScan[index].exposureTime;
ps->Shade.wXStep = posScan[index].xStepTime;
} else {
ps->Shade.wExposure = ps->Scan.negScan[index].exposureTime;
ps->Shade.wXStep = ps->Scan.negScan[index].xStepTime;
}
}
ps->Scan.dwInterlace = 0;
ps->Scan.dwInterval = 1;
if( ps->DataInf.wPhyDataType == COLOR_BW )
var.dwValue = xferSpeed[ps->IO.portMode].thresholdBW;
else {
if( ps->DataInf.wPhyDataType == COLOR_256GRAY )
var.dwValue = xferSpeed[ps->IO.portMode].thresholdGray;
else
var.dwValue = xferSpeed[ps->IO.portMode].thresholdColor;
}
/* for small size/descreen */
if((ps->DataInf.xyAppDpi.y >= 300) && var.dwValue &&
(ps->DataInf.dwAsicBytesPerPlane <= var.dwValue)) {
ps->Scan.dwInterval <<= 1;
}
if( var.dwValue && ps->DataInf.dwAsicBytesPerPlane > var.dwValue ) {
if((var.dwValue << 1) > ps->DataInf.dwAsicBytesPerPlane)
ps->Scan.dwInterval <<= 1;
else
if((var.dwValue << 2) > ps->DataInf.dwAsicBytesPerPlane)
ps->Scan.dwInterval <<= 2;
else
ps->Scan.dwInterval <<= 3;
}
/* 48 bit/600 dpi/Bpp mode will scan failed */
if(((ps->IO.portMode == _PORT_BIDI) ||
(ps->IO.portMode == _PORT_SPP)) &&
(ps->DataInf.wPhyDataType > COLOR_TRUE24) &&
(ps->DataInf.xyAppDpi.y >= 600)) {
ps->Scan.dwInterval <<= 1;
}
if( ps->DataInf.wPhyDataType >= COLOR_TRUE24 ) {
if( ps->DataInf.xyPhyDpi.y > 75U ) {
if( ps->Device.f0_8_16 ) {
ps->Scan.gd_gk.wGreenDiscard = ps->DataInf.xyPhyDpi.y / 75U;
} else {
ps->Scan.gd_gk.wGreenDiscard = ps->DataInf.xyPhyDpi.y / 150U;
}
} else {
ps->Scan.gd_gk.wGreenDiscard = 1;
}
ps->Scan.bd_rk.wBlueDiscard = ps->Scan.gd_gk.wGreenDiscard << 1;
} else {
ps->Scan.bd_rk.wBlueDiscard = ps->Scan.gd_gk.wGreenDiscard = 0;
}
}
/** PrepareScanningVariables() !!!
*/
static int imageP98003SetupScanSettings( pScanData ps, pScanInfo pInf )
{
DBG( DBG_LOW, "imageP98003SetupScanSettings()\n" );
/* call the one for ASIC 98001 first */
imageP98SetupScanSettings( ps, pInf );
if( !(ps->DataInf.dwScanFlag & SCANDEF_TPA )) {
ps->Scan.dwScanOrigin = ps->Device.lUpNormal * 4 + _RFT_SCANNING_ORG;
} else if( ps->DataInf.dwScanFlag & SCANDEF_Transparency) {
ps->Scan.dwScanOrigin = ps->Device.lUpPositive * 4 +
_POS_SCANNING_ORG;
} else {
ps->Scan.dwScanOrigin = ps->Device.lUpNegative * 4 +
_NEG_SCANNING_ORG;
}
ps->Scan.dwScanOrigin += ps->Device.dwModelOriginY;
/* ------- Setup CCD Offset variables ------- */
if( ps->DataInf.xyAppDpi.y <= 75 ) {
if( ps->DataInf.dwVxdFlag & _VF_PREVIEW ) {
ps->Scan.bDiscardAll = 0;
ps->DataInf.xyPhyDpi.y = 150;
ps->Shade.bIntermediate |= _ScanMode_AverageOut;
imageP98003SetupScanStateVariables( ps, 1 );
ps->Scan.gd_gk.wGreenDiscard = 0;
if( ps->DataInf.xyAppDpi.y >= 38 )
ps->Scan.bd_rk.wBlueDiscard = 1;
else
ps->Scan.bd_rk.wBlueDiscard = 0;
if( ps->DataInf.wPhyDataType >= COLOR_256GRAY ) {
ps->Shade.wXStep = 6;
ps->Shade.wExposure = 8 * ps->Shade.wXStep;
}
} else {
if(!(ps->DataInf.dwScanFlag & SCANDEF_TPA) &&
(ps->DataInf.xyAppDpi.y <= 50) &&
(ps->DataInf.wPhyDataType >= COLOR_TRUE24)) {
ps->Shade.bIntermediate |= _ScanMode_AverageOut;
}
if((ps->DataInf.wPhyDataType<COLOR_TRUE24) || ps->Device.f0_8_16 ||
(ps->Shade.bIntermediate & _ScanMode_AverageOut)) {
ps->Scan.bDiscardAll = 1;
ps->DataInf.xyPhyDpi.y = 75;
imageP98003SetupScanStateVariables( ps, 0 );
} else {
ps->Scan.bDiscardAll = 2;
ps->DataInf.xyPhyDpi.y = 150;
imageP98003SetupScanStateVariables( ps, 1 );
}
}
} else {
if( ps->DataInf.xyAppDpi.y <= 150 ) {
ps->Scan.bDiscardAll = 2;
ps->DataInf.xyPhyDpi.y = 150;
imageP98003SetupScanStateVariables( ps, 1 );
} else if( ps->DataInf.xyAppDpi.y <= 300 ) {
ps->Scan.bDiscardAll = 4;
ps->DataInf.xyPhyDpi.y = 300;
imageP98003SetupScanStateVariables( ps, 2 );
} else if( ps->DataInf.xyAppDpi.y <= 600 ) {
ps->Scan.bDiscardAll = 8;
ps->DataInf.xyPhyDpi.y = 600;
imageP98003SetupScanStateVariables( ps, 3 );
} else {
ps->Scan.bDiscardAll = 16;
ps->DataInf.xyPhyDpi.y = 1200;
imageP98003SetupScanStateVariables( ps, 4 );
}
}
/* ------- Lines have to sample or not? ------- */
if( ps->DataInf.xyAppDpi.y == ps->DataInf.xyPhyDpi.y ) {
DBG( DBG_LOW, "Sample every line\n" );
ps->Scan.DoSample = fnEveryLines;
} else {
if( ps->DataInf.dwVxdFlag & _VF_PREVIEW ) {
DBG( DBG_LOW, "Sample preview\n" );
ps->Scan.DoSample = fnSamplePreview;
ps->DataInf.wYSum = 150;
if( ps->DataInf.xyAppDpi.y >= 38 )
wPreviewScanned = ps->DataInf.xyAppDpi.y * 2;
else if( ps->DataInf.xyAppDpi.y >= 19 )
wPreviewScanned = ps->DataInf.xyAppDpi.y * 4;
else
wPreviewScanned = ps->DataInf.xyAppDpi.y * 8;
} else {
DBG( DBG_LOW, "Sample lines (%u - %u)...\n",
ps->DataInf.xyPhyDpi.y, ps->DataInf.xyAppDpi.y );
ps->Scan.DoSample = fnSampleLines;
ps->DataInf.wYSum = ps->DataInf.xyPhyDpi.y - ps->DataInf.xyAppDpi.y;
}
}
/*
* now assign the buffer pointers for image acquisition
*/
ps->Scan.p48BitBuf.pb = NULL;
if( ps->DataInf.wPhyDataType >= COLOR_TRUE24 ) {
ULong r,g,b;
r = (ULong)_SIZE_REDFIFO /
ps->DataInf.dwAsicBytesPerPlane - ps->Scan.bd_rk.wRedKeep;
g = (ULong)_SIZE_GREENFIFO /
ps->DataInf.dwAsicBytesPerPlane - ps->Scan.gd_gk.wGreenKeep;
if((int)r < 16 || (int)g < 16) {
b = (ULong)(ps->Scan.bd_rk.wRedKeep +
ps->Scan.gd_gk.wGreenKeep + 2U) *
ps->DataInf.dwAsicBytesPerPlane;
DBG( DBG_LOW, "48Bit buffer request: len=%u bytes, available=%u\n",
b, ps->TotalBufferRequire );
if( b > ps->TotalBufferRequire )
return _E_NORESOURCE;
ps->Scan.p48BitBuf.pb = ps->Bufs.b1.pReadBuf;
}
}
if( ps->Scan.p48BitBuf.pb ){
ps->Scan.DataRead = fnReadToDriver;
ps->Scan.BufGet.red.bp =
ps->Scan.BufPut.red.bp =
ps->Scan.BufBegin.red.bp = ps->Scan.p48BitBuf.pb;
ps->Scan.BufEnd.red.bp =
ps->Scan.BufBegin.green.bp =
ps->Scan.BufGet.green.bp =
ps->Scan.BufPut.green.bp = ps->Scan.p48BitBuf.pb +
ps->DataInf.dwAsicBytesPerLine *
(ps->Scan.bd_rk.wRedKeep + 1U);
ps->Scan.BufEnd.green.bp = ps->Scan.BufBegin.green.bp +
ps->DataInf.dwAsicBytesPerLine *
(ps->Scan.gd_gk.wGreenKeep + 1U);
ps->Scan.BufPut.blue.bp =
ps->Scan.BufGet.blue.bp = ps->Bufs.b1.pReadBuf +
ps->DataInf.dwAsicBytesPerLine * 2;
} else {
ps->Scan.DataRead = fnReadOutScanner;
ps->Scan.BufPut.red.bp = ps->Bufs.b1.pReadBuf;
ps->Scan.BufData.green.bp =
ps->Scan.BufPut.green.bp = ps->Scan.BufPut.red.bp +
ps->DataInf.dwAsicBytesPerLine;
ps->Scan.BufPut.blue.bp = ps->Scan.BufPut.green.bp +
ps->DataInf.dwAsicBytesPerLine;
if( ps->DataInf.dwScanFlag & SCANDEF_ColorBGROrder ) {
ps->Scan.BufData.red.bp = ps->Scan.BufPut.blue.bp;
ps->Scan.BufData.blue.bp = ps->Scan.BufPut.red.bp;
} else {
ps->Scan.BufData.red.bp = ps->Scan.BufPut.red.bp;
ps->Scan.BufData.blue.bp = ps->Scan.BufPut.blue.bp;
}
}
/* CHECK: maybe remove this stuff */
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;
}
return _OK;
}
/************************ exported functions *********************************/
/**
*/
_LOC int ImageInitialize( pScanData ps )
{
DBG( DBG_HIGH, "ImageInitialize()\n" );
if( NULL == ps )
return _E_NULLPTR;
ps->Scan.dpiIdx = 0;
ps->Scan.negScan = negScan;
/*
* depending on the asic, we set some functions
*/
if( _ASIC_IS_98001 == ps->sCaps.AsicID ) {
ps->GetImageInfo = imageP98GetInfo;
ps->SetupScanSettings = imageP98SetupScanSettings;
ps->ReadOneImageLine = imageP98001ReadOneImageLine;
} else if( _ASIC_IS_98003 == ps->sCaps.AsicID ) {
ps->GetImageInfo = imageP98GetInfo;
ps->SetupScanSettings = imageP98003SetupScanSettings;
ps->ReadOneImageLine = imageP98003ReadOneImageLine;
} else if( _IS_ASIC96(ps->sCaps.AsicID)) {
ps->GetImageInfo = imageP96GetInfo;
ps->SetupScanSettings = imageP96SetupScanSettings;
ps->ReadOneImageLine = imageP96ReadOneImageLine;
} else {
DBG( DBG_HIGH , "NOT SUPPORTED ASIC !!!\n" );
return _E_NOSUPP;
}
return _OK;
}
/* END PLUSTEK-PP_IMAGE.C ...................................................*/