diff options
Diffstat (limited to 'backend/u12-image.c')
-rw-r--r-- | backend/u12-image.c | 908 |
1 files changed, 908 insertions, 0 deletions
diff --git a/backend/u12-image.c b/backend/u12-image.c new file mode 100644 index 0000000..1d9acda --- /dev/null +++ b/backend/u12-image.c @@ -0,0 +1,908 @@ +/* @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 ..........................................................*/ |