/* @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 * * 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() * . *
* 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. *
*/ /*************************** 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.wPhyDataTypef0_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 ..........................................................*/