diff options
author | Jörg Frings-Fürst <debian@jff-webhosting.net> | 2014-10-06 14:00:40 +0200 |
---|---|---|
committer | Jörg Frings-Fürst <debian@jff-webhosting.net> | 2014-10-06 14:00:40 +0200 |
commit | 6e9c41a892ed0e0da326e0278b3221ce3f5713b8 (patch) | |
tree | 2e301d871bbeeb44aa57ff9cc070fcf3be484487 /backend/plustek-usbimg.c |
Initial import of sane-backends version 1.0.24-1.2
Diffstat (limited to 'backend/plustek-usbimg.c')
-rw-r--r-- | backend/plustek-usbimg.c | 1984 |
1 files changed, 1984 insertions, 0 deletions
diff --git a/backend/plustek-usbimg.c b/backend/plustek-usbimg.c new file mode 100644 index 0000000..41c0207 --- /dev/null +++ b/backend/plustek-usbimg.c @@ -0,0 +1,1984 @@ +/*............................................................................. + * Project : SANE library for Plustek flatbed scanners. + *............................................................................. + */ + +/** @file plustek-usbimg.c + * @brief Image processing functions for copying and scaling image lines. + * + * Based on sources acquired from Plustek Inc.<br> + * Copyright (C) 2001-2007 Gerhard Jaeger <gerhard@gjaeger.de> + * + * History: + * - 0.40 - starting version of the USB support + * - 0.41 - fixed the 14bit problem for LM9831 devices + * - 0.42 - no changes + * - 0.43 - no changes + * - 0.44 - added CIS parts and dumpPic function + * - 0.45 - added gray scaling functions for CIS devices + * - fixed usb_GrayScale16 function + * - fixed a bug in usb_ColorScale16_2 function + * - fixed endless loop bug + * - fixed a bug in usb_GrayScalePseudo16 function + * - fixed a bug in usb_GrayDuplicatePseudo16 function + * - removed the scaler stuff for CIS devices + * - 0.46 - minor fixes + * - 0.47 - added big-endian/little endian stuff + * - 0.48 - fixed usb_ColorDuplicateGray16() and + * usb_ColorScaleGray16() + * - added usb_BWScaleFromColor() and usb_BWDuplicateFromColor() + * - cleanup + * - 0.49 - a_bRegs is now part of the device structure + * - 0.50 - cleanup + * - 0.51 - added usb_ColorDuplicateGray16_2(), usb_ColorScaleGray16_2() + * usb_BWScaleFromColor_2() and usb_BWDuplicateFromColor_2() + * - 0.52 - cleanup + * . + * <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> + */ + +#define _SCALER 1000 + +static u_char bShift, Shift; +static u_short wSum, Mask; + +/* + */ +static u_char BitTable[8] = { + 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 +}; + +static u_char BitsReverseTable[256] = { + 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, + 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, + 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, + 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, + 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, + 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, + 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, + 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, + 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, + 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, + 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, + 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, + 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, + 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, + 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, + 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, + 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, + 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, + 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, + 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, + 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, + 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, + 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, + 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, + 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, + 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, + 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, + 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, + 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, + 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, + 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, + 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff +}; + +/************************ some helper functions ******************************/ + +static void ReverseBits( int b, u_char **pTar, int *iByte, int *iWeightSum, + int iSrcWeight, int iTarWeight, int cMax ) +{ + int bit; + + cMax = (1 << cMax); + if(iSrcWeight == iTarWeight) { + for( bit = 1; bit < cMax; bit <<= 1) { + *iByte <<= 1; + if(b & bit) + *iByte |= 1; + if(*iByte >= 0x100) { + **pTar++ = (u_char)*iByte; + *iByte = 1; + } + } + } else { + for( bit = 1; bit < cMax; bit <<= 1 ) { + + *iWeightSum += iTarWeight; + while(*iWeightSum >= iSrcWeight) + { + *iWeightSum -= iSrcWeight; + *iByte <<= 1; + if(b & bit) + *iByte |= 1; + if(*iByte >= 0x100) + { + **pTar++ = (u_char)*iByte; + *iByte = 1; + } + } + } + } +} + +static void usb_ReverseBitStream( u_char *pSrc, u_char *pTar, int iPixels, + int iBufSize, int iSrcWeight/* = 0*/, + int iTarWeight/* = 0*/, int iPadBit/* = 1*/) +{ + int i; + int iByte = 1; + int cBytes = iPixels / 8; + int cBits = iPixels % 8; + u_char bPad = iPadBit? 0xff: 0; + u_char *pTarget = pTar; + int iWeightSum = 0; + + if(iSrcWeight == iTarWeight) { + if(cBits) + { + int cShift = 8 - cBits; + for(i = cBytes, pSrc = pSrc + cBytes - 1; i > 0; i--, pSrc--, pTar++) + *pTar = BitsReverseTable[(u_char)((*pSrc << cBits) | (*(pSrc+1) >> cShift))]; + ReverseBits(*(pSrc+1) >> cShift, &pTar, &iByte, &iWeightSum, iSrcWeight, iTarWeight, cBits); + } + else /* byte boundary */ + { + for(i = cBytes, pSrc = pSrc + cBytes - 1; i > 0; i--, pSrc--, pTar++) + *pTar = BitsReverseTable[*pSrc]; + } + } + else /* To shrink or enlarge */ + { + if(cBits) { + int cShift = 8 - cBits; + for(i = cBytes, pSrc = pSrc + cBytes - 1; i > 0; i--, pSrc--) + ReverseBits((*pSrc << cBits) | (*(pSrc+1) >> cShift), &pTar, &iByte, &iWeightSum, iSrcWeight, iTarWeight, 8); + ReverseBits(*(pSrc+1) >> cShift, &pTar, &iByte, &iWeightSum, iSrcWeight, iTarWeight, cBits); + } + else /* byte boundary */ + { + for(i = cBytes, pSrc = pSrc + cBytes - 1; i > 0; i--, pSrc--) + ReverseBits(*pSrc, &pTar, &iByte, &iWeightSum, iSrcWeight, iTarWeight, 8); + } + } + + if(iByte != 1) { + while(iByte < 0x100) + { + iByte <<= 1; + iByte |= iPadBit; + } + *pTar++ = (u_char)iByte; + } + + cBytes = (int)(pTar - pTarget); + + for(i = iBufSize - cBytes; i > 0; i--, pTar++) + *pTar = bPad; +} + +/** + */ +static void usb_AverageColorByte( Plustek_Device *dev ) +{ + u_long dw; + ScanDef *scan = &dev->scanning; + + if((scan->sParam.bSource == SOURCE_Negative || + scan->sParam.bSource == SOURCE_Transparency) && + scan->sParam.PhyDpi.x > 800) { + + for (dw = 0; dw < (scan->sParam.Size.dwPhyPixels - 1); dw++) + { + scan->Red.pcb[dw].a_bColor[0] = + (u_char)(((u_short)scan->Red.pcb[dw].a_bColor[0] + + (u_short)scan->Red.pcb[dw + 1].a_bColor[0]) / 2); + + scan->Green.pcb[dw].a_bColor[0] = + (u_char)(((u_short)scan->Green.pcb[dw].a_bColor[0] + + (u_short)scan->Green.pcb[dw + 1].a_bColor[0]) / 2); + + scan->Blue.pcb[dw].a_bColor[0] = + (u_char)(((u_short)scan->Blue.pcb[dw].a_bColor[0] + + (u_short)scan->Blue.pcb[dw + 1].a_bColor[0]) / 2); + } + } +} + +/** + */ +static void usb_AverageColorWord( Plustek_Device *dev ) +{ + u_char ls = 2; + u_long dw; + ScanDef *scan = &dev->scanning; + + if((scan->sParam.bSource == SOURCE_Negative || + scan->sParam.bSource == SOURCE_Transparency) && + scan->sParam.PhyDpi.x > 800) { + + scan->Red.pcw[0].Colors[0] = _HILO2WORD(scan->Red.pcw[0].HiLo[0]) >> ls; + scan->Green.pcw[0].Colors[0] = _HILO2WORD(scan->Green.pcw[0].HiLo[0]) >> ls; + scan->Blue.pcw[0].Colors[0] = _HILO2WORD(scan->Blue.pcw[0].HiLo[0]) >> ls; + + for (dw = 0; dw < (scan->sParam.Size.dwPhyPixels - 1); dw++) + { + scan->Red.pcw[dw + 1].Colors[0] = _HILO2WORD(scan->Red.pcw[dw + 1].HiLo[0]) >> ls; + scan->Green.pcw[dw + 1].Colors[0] = _HILO2WORD(scan->Green.pcw[dw + 1].HiLo[0]) >> ls; + scan->Blue.pcw[dw + 1].Colors[0] = _HILO2WORD(scan->Blue.pcw[dw + 1].HiLo[0]) >> ls; + + scan->Red.pcw[dw].Colors[0] = (u_short)(((u_long)scan->Red.pcw[dw].Colors[0] + + (u_long)scan->Red.pcw[dw + 1].Colors[0]) / 2); + scan->Green.pcw[dw].Colors[0] = (u_short)(((u_long)scan->Green.pcw[dw].Colors[0] + + (u_long)scan->Green.pcw[dw + 1].Colors[0]) / 2); + scan->Blue.pcw[dw].Colors[0] = (u_short)(((u_long)scan->Blue.pcw[dw].Colors[0] + + (u_long)scan->Blue.pcw[dw + 1].Colors[0]) / 2); + + scan->Red.pcw[dw].Colors[0] = _HILO2WORD(scan->Red.pcw[dw].HiLo[0]) << ls; + scan->Green.pcw[dw].Colors[0] = _HILO2WORD(scan->Green.pcw[dw].HiLo[0]) << ls; + scan->Blue.pcw[dw].Colors[0] = _HILO2WORD(scan->Blue.pcw[dw].HiLo[0]) << ls; + } + + scan->Red.pcw[dw].Colors[0] = _HILO2WORD(scan->Red.pcw[dw].HiLo[0]) << ls; + scan->Green.pcw[dw].Colors[0] = _HILO2WORD(scan->Green.pcw[dw].HiLo[0]) << ls; + scan->Blue.pcw[dw].Colors[0] = _HILO2WORD(scan->Blue.pcw[dw].HiLo[0]) << ls; + } +} + +/** + */ +static void usb_AverageGrayByte( Plustek_Device *dev ) +{ + u_long dw; + ScanDef *scan = &dev->scanning; + + if((scan->sParam.bSource == SOURCE_Negative || + scan->sParam.bSource == SOURCE_Transparency) && + scan->sParam.PhyDpi.x > 800) + { + for (dw = 0; dw < (scan->sParam.Size.dwPhyPixels - 1); dw++) + scan->Green.pb[dw] = (u_char)(((u_short)scan->Green.pb[dw]+ + (u_short)scan->Green.pb[dw+1]) / 2); + } +} + +/** + */ +static void usb_AverageGrayWord( Plustek_Device *dev ) +{ + u_long dw; + ScanDef *scan = &dev->scanning; + + if((scan->sParam.bSource == SOURCE_Negative || + scan->sParam.bSource == SOURCE_Transparency) && + scan->sParam.PhyDpi.x > 800) + { + scan->Green.pw[0] = _HILO2WORD(scan->Green.philo[0]) >> 2; + + for (dw = 0; dw < (scan->sParam.Size.dwPhyPixels - 1); dw++) + { + scan->Green.pw[dw + 1] = _HILO2WORD(scan->Green.philo[dw+1]) >> 2; + scan->Green.pw[dw] = (u_short)(((u_long)scan->Green.pw[dw]+ + (u_long)scan->Green.pw[dw+1]) / 2); + scan->Green.pw[dw] = _HILO2WORD(scan->Green.philo[dw]) << 2; + } + + scan->Green.pw[dw] = _HILO2WORD(scan->Green.philo[dw]) << 2; + } +} + +/** + * returns the zoom value, used for our scaling algorithm (DDA algo + * digital differential analyzer). + */ +static int usb_GetScaler( ScanDef *scan ) +{ + double ratio; + + ratio = (double)scan->sParam.UserDpi.x/ + (double)scan->sParam.PhyDpi.x; + + return (int)(1.0/ratio * _SCALER); +} + +/******************************* the copy functions **************************/ + +/** do a simple memcopy from scan-buffer to user buffer + */ +static void usb_ColorDuplicate8( Plustek_Device *dev ) +{ + int next; + u_long dw, pixels; + ScanDef *scan = &dev->scanning; + + usb_AverageColorByte( dev ); + + if( scan->sParam.bSource == SOURCE_ADF ) { + next = -1; + pixels = scan->sParam.Size.dwPixels - 1; + } else { + next = 1; + pixels = 0; + } + + for( dw = 0; dw < scan->sParam.Size.dwPixels; dw++, pixels += next ) { + + scan->UserBuf.pb_rgb[pixels].Red = scan->Red.pcb[dw].a_bColor[0]; + scan->UserBuf.pb_rgb[pixels].Green = scan->Green.pcb[dw].a_bColor[0]; + scan->UserBuf.pb_rgb[pixels].Blue = scan->Blue.pcb[dw].a_bColor[0]; + } +} + +/** reorder from rgb line to rgb pixel (CIS scanner) + */ +static void usb_ColorDuplicate8_2( Plustek_Device *dev ) +{ + int next; + u_long dw, pixels; + ScanDef *scan = &dev->scanning; + + if( scan->sParam.bSource == SOURCE_ADF ) { + next = -1; + pixels = scan->sParam.Size.dwPixels - 1; + } else { + next = 1; + pixels = 0; + } + + for( dw = 0; dw < scan->sParam.Size.dwPixels; dw++, pixels += next ) { + + scan->UserBuf.pb_rgb[pixels].Red = (u_char)scan->Red.pb[dw]; + scan->UserBuf.pb_rgb[pixels].Green = (u_char)scan->Green.pb[dw]; + scan->UserBuf.pb_rgb[pixels].Blue = (u_char)scan->Blue.pb[dw]; + } +} + +/** + */ +static void usb_ColorDuplicate16( Plustek_Device *dev ) +{ + int next; + u_char ls; + u_long dw, pixels; + ScanDef *scan = &dev->scanning; + SANE_Bool swap = usb_HostSwap(); + + usb_AverageColorWord( dev ); + + if( scan->sParam.bSource == SOURCE_ADF ) { + next = -1; + pixels = scan->sParam.Size.dwPixels - 1; + } else { + next = 1; + pixels = 0; + } + + if( scan->dwFlag & SCANFLAG_RightAlign ) + ls = Shift; + else + ls = 0; + + for (dw = 0; dw < scan->sParam.Size.dwPixels; dw++, pixels += next) { + + if( swap ) { + scan->UserBuf.pw_rgb[pixels].Red = + _HILO2WORD(scan->Red.pcw[dw].HiLo[0]) >> ls; + scan->UserBuf.pw_rgb[pixels].Green = + _HILO2WORD(scan->Green.pcw[dw].HiLo[0]) >> ls; + scan->UserBuf.pw_rgb[pixels].Blue = + _HILO2WORD(scan->Blue.pcw[dw].HiLo[0]) >> ls; + } else { + scan->UserBuf.pw_rgb[pixels].Red = scan->Red.pw[dw] >> ls; + scan->UserBuf.pw_rgb[pixels].Green= scan->Green.pw[dw] >> ls; + scan->UserBuf.pw_rgb[pixels].Blue = scan->Blue.pw[dw] >> ls; + } + } +} + +/** + */ +static void usb_ColorDuplicate16_2( Plustek_Device *dev ) +{ + int next; + u_char ls; + HiLoDef tmp; + u_long dw, pixels; + ScanDef *scan = &dev->scanning; + SANE_Bool swap = usb_HostSwap(); + + usb_AverageColorWord( dev ); + + if( scan->sParam.bSource == SOURCE_ADF ) { + next = -1; + pixels = scan->sParam.Size.dwPixels - 1; + } else { + next = 1; + pixels = 0; + } + + if( scan->dwFlag & SCANFLAG_RightAlign ) + ls = Shift; + else + ls = 0; + + for( dw = 0; dw < scan->sParam.Size.dwPixels; dw++, pixels += next) { + + if( swap ) { + tmp = *((HiLoDef*)&scan->Red.pw[dw]); + scan->UserBuf.pw_rgb[pixels].Red = _HILO2WORD(tmp) >> ls; + + tmp = *((HiLoDef*)&scan->Green.pw[dw]); + scan->UserBuf.pw_rgb[pixels].Green = _HILO2WORD(tmp) >> ls; + + tmp = *((HiLoDef*)&scan->Blue.pw[dw]); + scan->UserBuf.pw_rgb[pixels].Blue = _HILO2WORD(tmp) >> ls; + + } else { + + scan->UserBuf.pw_rgb[pixels].Red = scan->Red.pw[dw] >> ls; + scan->UserBuf.pw_rgb[pixels].Green = scan->Green.pw[dw] >> ls; + scan->UserBuf.pw_rgb[pixels].Blue = scan->Blue.pw[dw] >> ls; + } + } +} + +/** + */ +static void usb_ColorDuplicatePseudo16( Plustek_Device *dev ) +{ + int next; + u_short wR, wG, wB; + u_long dw, pixels; + ScanDef *scan = &dev->scanning; + + usb_AverageColorByte( dev ); + + if (scan->sParam.bSource == SOURCE_ADF) { + next = -1; + pixels = scan->sParam.Size.dwPixels - 1; + } else { + next = 1; + pixels = 0; + } + + wR = (u_short)scan->Red.pcb[0].a_bColor[0]; + wG = (u_short)scan->Green.pcb[0].a_bColor[0]; + wB = (u_short)scan->Blue.pcb[0].a_bColor[0]; + + for (dw = 0; dw < scan->sParam.Size.dwPixels; dw++, pixels += next) { + + scan->UserBuf.pw_rgb[pixels].Red = + (wR + scan->Red.pcb[dw].a_bColor[0]) << bShift; + scan->UserBuf.pw_rgb[pixels].Green = + (wG + scan->Green.pcb[dw].a_bColor[0]) << bShift; + scan->UserBuf.pw_rgb[pixels].Blue = + (wB + scan->Blue.pcb[dw].a_bColor[0]) << bShift; + + wR = (u_short)scan->Red.pcb[dw].a_bColor[0]; + wG = (u_short)scan->Green.pcb[dw].a_bColor[0]; + wB = (u_short)scan->Blue.pcb[dw].a_bColor[0]; + } +} + +/** + */ +static void usb_ColorDuplicateGray( Plustek_Device *dev ) +{ + int next; + u_long dw, pixels; + ScanDef *scan = &dev->scanning; + + usb_AverageColorByte( dev ); + + if (scan->sParam.bSource == SOURCE_ADF) { + next = -1; + pixels = scan->sParam.Size.dwPixels - 1; + } else { + next = 1; + pixels = 0; + } + + switch(scan->fGrayFromColor) { + + case 1: + for (dw = 0; dw < scan->sParam.Size.dwPixels; dw++, pixels += next) + scan->UserBuf.pb[pixels] = scan->Red.pcb[dw].a_bColor[0]; + break; + case 2: + for (dw = 0; dw < scan->sParam.Size.dwPixels; dw++, pixels += next) + scan->UserBuf.pb[pixels] = scan->Green.pcb[dw].a_bColor[0]; + break; + case 3: + for (dw = 0; dw < scan->sParam.Size.dwPixels; dw++, pixels += next) + scan->UserBuf.pb[pixels] = scan->Blue.pcb[dw].a_bColor[0]; + break; + } +} + +/** + */ +static void usb_ColorDuplicateGray_2( Plustek_Device *dev ) +{ + int next; + u_long dw, pixels; + ScanDef *scan = &dev->scanning; + + usb_AverageColorByte( dev ); + + if (scan->sParam.bSource == SOURCE_ADF) { + next = -1; + pixels = scan->sParam.Size.dwPixels - 1; + } else { + next = 1; + pixels = 0; + } + + switch(scan->fGrayFromColor) + { + case 1: + for (dw = 0; dw < scan->sParam.Size.dwPixels; dw++, pixels += next) + scan->UserBuf.pb[pixels] = scan->Red.pb[dw]; + break; + case 3: + for (dw = 0; dw < scan->sParam.Size.dwPixels; dw++, pixels += next) + scan->UserBuf.pb[pixels] = scan->Blue.pb[dw]; + break; + default: + for (dw = 0; dw < scan->sParam.Size.dwPixels; dw++, pixels += next) + scan->UserBuf.pb[pixels] = scan->Green.pb[dw]; + break; + } +} + +/** + */ +static void usb_ColorDuplicateGray16( Plustek_Device *dev ) +{ + int next; + u_char ls; + u_long dw, pixels; + ScanDef *scan = &dev->scanning; + SANE_Bool swap = usb_HostSwap(); + + usb_AverageColorWord( dev ); + + if (scan->sParam.bSource == SOURCE_ADF) { + next = -1; + pixels = scan->sParam.Size.dwPixels - 1; + } else { + next = 1; + pixels = 0; + } + if( scan->dwFlag & SCANFLAG_RightAlign ) + ls = Shift; + else + ls = 0; + + switch(scan->fGrayFromColor) { + + case 1: + if( swap ) { + for (dw = 0; dw < scan->sParam.Size.dwPixels; dw++, pixels += next) + scan->UserBuf.pw[pixels] = + _HILO2WORD(scan->Red.pcw[dw].HiLo[0]) >> ls; + } else { + for (dw = 0; dw < scan->sParam.Size.dwPixels; dw++, pixels += next) + scan->UserBuf.pw[pixels] = scan->Red.pw[dw] >> ls; + } + break; + case 2: + if( swap ) { + for (dw = 0; dw < scan->sParam.Size.dwPixels; dw++, pixels += next) + scan->UserBuf.pw[pixels] = + _HILO2WORD(scan->Green.pcw[dw].HiLo[0]) >> ls; + } else { + for (dw = 0; dw < scan->sParam.Size.dwPixels; dw++, pixels += next) + scan->UserBuf.pw[pixels] = scan->Green.pw[dw] >> ls; + } + break; + case 3: + if( swap ) { + for (dw = 0; dw < scan->sParam.Size.dwPixels; dw++, pixels += next) + scan->UserBuf.pw[pixels] = + _HILO2WORD(scan->Blue.pcw[dw].HiLo[0]) >> ls; + } else { + for (dw = 0; dw < scan->sParam.Size.dwPixels; dw++, pixels += next) + scan->UserBuf.pw[pixels] = scan->Blue.pw[dw] >> ls; + } + break; + } +} + +/** + */ +static void usb_ColorDuplicateGray16_2( Plustek_Device *dev ) +{ + int next; + u_char ls; + u_long dw, pixels; + HiLoDef tmp; + ScanDef *scan = &dev->scanning; + SANE_Bool swap = usb_HostSwap(); + + usb_AverageColorWord( dev ); + + if (scan->sParam.bSource == SOURCE_ADF) { + next = -1; + pixels = scan->sParam.Size.dwPixels - 1; + } else { + next = 1; + pixels = 0; + } + if( scan->dwFlag & SCANFLAG_RightAlign ) + ls = Shift; + else + ls = 0; + + switch(scan->fGrayFromColor) { + case 1: + if( swap ) { + for (dw = 0; dw < scan->sParam.Size.dwPixels; dw++, pixels += next) { + tmp = *((HiLoDef*)&scan->Red.pw[dw]); + scan->UserBuf.pw[pixels] = _HILO2WORD(tmp) >> ls; + } + } else { + for (dw = 0; dw < scan->sParam.Size.dwPixels; dw++, pixels += next) { + scan->UserBuf.pw[pixels] = scan->Red.pw[dw] >> ls; + } + } + break; + case 2: + if( swap ) { + for (dw = 0; dw < scan->sParam.Size.dwPixels; dw++, pixels += next) { + tmp = *((HiLoDef*)&scan->Green.pw[dw]); + scan->UserBuf.pw[pixels] = _HILO2WORD(tmp) >> ls; + } + } else { + for (dw = 0; dw < scan->sParam.Size.dwPixels; dw++, pixels += next) { + scan->UserBuf.pw[pixels] = scan->Green.pw[dw] >> ls; + } + } + break; + case 3: + if( swap ) { + for (dw = 0; dw < scan->sParam.Size.dwPixels; dw++, pixels += next) { + tmp = *((HiLoDef*)&scan->Blue.pw[dw]); + scan->UserBuf.pw[pixels] = _HILO2WORD(tmp) >> ls; + } + } else { + for (dw = 0; dw < scan->sParam.Size.dwPixels; dw++, pixels += next) { + scan->UserBuf.pw[pixels] = scan->Blue.pw[dw] >> ls; + } + } + break; + } +} + +/** + */ +static void usb_GrayDuplicate8( Plustek_Device *dev ) +{ + u_char *dest, *src; + u_long pixels; + ScanDef *scan = &dev->scanning; + + usb_AverageGrayByte( dev ); + + if( scan->sParam.bSource == SOURCE_ADF ) { + + pixels = scan->sParam.Size.dwPixels; + src = scan->Green.pb; + dest = scan->UserBuf.pb + pixels - 1; + + for(; pixels; pixels--, src++, dest--) + *dest = *src; + } else { + memcpy( scan->UserBuf.pb, scan->Green.pb, scan->sParam.Size.dwBytes ); + } +} + +/** + */ +static void usb_GrayDuplicate16( Plustek_Device *dev ) +{ + int next; + u_char ls; + u_short *dest; + u_long pixels; + HiLoDef *pwm; + ScanDef *scan = &dev->scanning; + SANE_Bool swap = usb_HostSwap(); + + usb_AverageGrayWord( dev ); + + if( scan->sParam.bSource == SOURCE_ADF ) { + next = -1; + dest = scan->UserBuf.pw + scan->sParam.Size.dwPixels - 1; + } else { + next = 1; + dest = scan->UserBuf.pw; + } + + if( scan->dwFlag & SCANFLAG_RightAlign ) + ls = Shift; + else + ls = 0; + + pwm = scan->Green.philo; + for( pixels=scan->sParam.Size.dwPixels; pixels--; pwm++, dest += next ) { + if( swap ) + *dest = (_PHILO2WORD(pwm)) >> ls; + else + *dest = (_PLOHI2WORD(pwm)) >> ls; + } +} + +/** + */ +static void usb_GrayDuplicatePseudo16( Plustek_Device *dev ) +{ + u_char *src; + int next; + u_short g; + u_short *dest; + u_long pixels; + ScanDef *scan = &dev->scanning; + + usb_AverageGrayByte( dev ); + + if (scan->sParam.bSource == SOURCE_ADF) { + next = -1; + dest = scan->UserBuf.pw + scan->sParam.Size.dwPixels - 1; + } else { + next = 1; + dest = scan->UserBuf.pw; + } + + src = scan->Green.pb; + g = (u_short)*src; + + for( pixels=scan->sParam.Size.dwPixels; pixels--; src++, dest += next ) { + + *dest = (g + *src) << bShift; + g = (u_short)*src; + } +} + +/** copy binary data to the user buffer + */ +static void usb_BWDuplicate( Plustek_Device *dev ) +{ + ScanDef *scan = &dev->scanning; + + if(scan->sParam.bSource == SOURCE_ADF) + { + usb_ReverseBitStream( scan->Green.pb, scan->UserBuf.pb, + scan->sParam.Size.dwValidPixels, + scan->dwBytesLine, 0, 0, 1 ); + } else { + memcpy( scan->UserBuf.pb, scan->Green.pb, scan->sParam.Size.dwBytes ); + } +} + +/** generate binary data from one of the three color inputs according to the + * value in fGrayFromColor (CCD version) + */ +static void usb_BWDuplicateFromColor( Plustek_Device *dev ) +{ + int next; + u_char d, s, *dest; + u_short j; + u_long pixels; + ColorByteDef *src; + ScanDef *scan = &dev->scanning; + + if( scan->sParam.bSource == SOURCE_ADF ) { + dest = scan->UserBuf.pb + scan->sParam.Size.dwPixels - 1; + next = -1; + } else { + dest = scan->UserBuf.pb; + next = 1; + } + + switch(scan->fGrayFromColor) { + case 1: src = scan->Red.pcb; break; + case 3: src = scan->Blue.pcb; break; + default: src = scan->Green.pcb; break; + } + + d = j = 0; + for( pixels = scan->sParam.Size.dwPixels; pixels; pixels--, src++ ) { + + s = src->a_bColor[0]; + if( s != 0 ) + d |= BitTable[j]; + j++; + if( j == 8 ) { + *dest = d; + dest += next; + + d = j = 0; + } + } +} + +/** generate binary data from one of the three color inputs according to the + * value in fGrayFromColor (CIS version) + */ +static void usb_BWDuplicateFromColor_2( Plustek_Device *dev ) +{ + int next; + u_char d, *dest, *src; + u_short j; + u_long pixels; + ScanDef *scan = &dev->scanning; + + if( scan->sParam.bSource == SOURCE_ADF ) { + dest = scan->UserBuf.pb + scan->sParam.Size.dwPixels - 1; + next = -1; + } else { + dest = scan->UserBuf.pb; + next = 1; + } + + switch(scan->fGrayFromColor) { + case 1: src = scan->Red.pb; break; + case 3: src = scan->Blue.pb; break; + default: src = scan->Green.pb; break; + } + + d = j = 0; + for( pixels = scan->sParam.Size.dwPixels; pixels; pixels--, src++ ) { + + if( *src != 0 ) + d |= BitTable[j]; + j++; + if( j == 8 ) { + *dest = d; + dest += next; + + d = j = 0; + } + } +} + +/************************** the scaling functions ****************************/ + +/** + */ +static void usb_ColorScaleGray( Plustek_Device *dev ) +{ + int izoom, ddax, next; + u_long dw, pixels; + ColorByteDef *src; + ScanDef *scan = &dev->scanning; + + usb_AverageColorByte( dev ); + + dw = scan->sParam.Size.dwPixels; + + if( scan->sParam.bSource == SOURCE_ADF ) { + next = -1; + pixels = scan->sParam.Size.dwPixels - 1; + } else { + next = 1; + pixels = 0; + } + + switch(scan->fGrayFromColor) { + case 1: src = scan->Red.pcb; break; + case 3: src = scan->Blue.pcb; break; + default: src = scan->Green.pcb; break; + } + + izoom = usb_GetScaler( scan ); + + for( ddax = 0; dw; src++ ) { + + ddax -= _SCALER; + while((ddax < 0) && (dw > 0)) { + + scan->UserBuf.pb[pixels] = src->a_bColor[0]; + + pixels += next; + ddax += izoom; + dw--; + } + } +} + +/** + */ +static void usb_ColorScaleGray_2( Plustek_Device *dev ) +{ + u_char *src; + int izoom, ddax, next; + u_long dw, pixels; + ScanDef *scan = &dev->scanning; + + usb_AverageColorByte( dev ); + + dw = scan->sParam.Size.dwPixels; + + if( scan->sParam.bSource == SOURCE_ADF ) { + next = -1; + pixels = scan->sParam.Size.dwPixels - 1; + } else { + next = 1; + pixels = 0; + } + + switch(scan->fGrayFromColor) { + case 1: src = scan->Red.pb; break; + case 3: src = scan->Blue.pb; break; + default: src = scan->Green.pb; break; + } + + izoom = usb_GetScaler( scan ); + + for( ddax = 0; dw; src++ ) { + + ddax -= _SCALER; + while((ddax < 0) && (dw > 0)) { + + scan->UserBuf.pb[pixels] = *src; + + pixels += next; + ddax += izoom; + dw--; + } + } +} + +/** + */ +static void usb_ColorScaleGray16( Plustek_Device *dev ) +{ + u_char ls; + int izoom, ddax, next; + u_long dw, pixels, bitsput; + SANE_Bool swap = usb_HostSwap(); + ScanDef *scan = &dev->scanning; + + usb_AverageColorByte( dev ); + + dw = scan->sParam.Size.dwPixels; + + if( scan->sParam.bSource == SOURCE_ADF ) { + next = -1; + pixels = scan->sParam.Size.dwPixels - 1; + } else { + next = 1; + pixels = 0; + } + + izoom = usb_GetScaler( scan ); + + if( scan->dwFlag & SCANFLAG_RightAlign ) + ls = Shift; + else + ls = 0; + + switch( scan->fGrayFromColor ) { + + case 1: + for( bitsput = 0, ddax = 0; dw; bitsput++ ) { + + ddax -= _SCALER; + + while((ddax < 0) && (dw > 0)) { + if( swap ) { + scan->UserBuf.pw[pixels] = + _HILO2WORD(scan->Red.pcw[bitsput].HiLo[0]) >> ls; + } else { + scan->UserBuf.pw[pixels] = scan->Red.pw[bitsput] >> ls; + } + pixels += next; + ddax += izoom; + dw--; + } + } + break; + + case 2: + for( bitsput = 0, ddax = 0; dw; bitsput++ ) { + + ddax -= _SCALER; + + while((ddax < 0) && (dw > 0)) { + if( swap ) { + scan->UserBuf.pw[pixels] = + _HILO2WORD(scan->Green.pcw[bitsput].HiLo[0]) >> ls; + } else { + scan->UserBuf.pw[pixels] = scan->Green.pw[bitsput] >> ls; + } + pixels += next; + ddax += izoom; + dw--; + } + } + break; + + case 3: + for( bitsput = 0, ddax = 0; dw; bitsput++ ) { + + ddax -= _SCALER; + + while((ddax < 0) && (dw > 0)) { + if( swap ) { + scan->UserBuf.pw[pixels] = + _HILO2WORD(scan->Blue.pcw[bitsput].HiLo[0]) >> ls; + } else { + scan->UserBuf.pw[pixels] = scan->Blue.pw[bitsput] >> ls; + } + pixels += next; + ddax += izoom; + dw--; + } + } + break; + } +} + +/** + */ +static void usb_ColorScaleGray16_2( Plustek_Device *dev ) +{ + u_char ls; + int izoom, ddax, next; + u_long dw, pixels, bitsput; + HiLoDef tmp; + SANE_Bool swap = usb_HostSwap(); + ScanDef *scan = &dev->scanning; + + usb_AverageColorByte( dev ); + + dw = scan->sParam.Size.dwPixels; + + if( scan->sParam.bSource == SOURCE_ADF ) { + next = -1; + pixels = scan->sParam.Size.dwPixels - 1; + } else { + next = 1; + pixels = 0; + } + + izoom = usb_GetScaler( scan ); + + if( scan->dwFlag & SCANFLAG_RightAlign ) + ls = Shift; + else + ls = 0; + + switch( scan->fGrayFromColor ) { + + case 1: + for( bitsput = 0, ddax = 0; dw; bitsput++ ) { + + ddax -= _SCALER; + + while((ddax < 0) && (dw > 0)) { + if( swap ) { + tmp = *((HiLoDef*)&scan->Red.pw[bitsput]); + scan->UserBuf.pw[pixels] = _HILO2WORD(tmp) >> ls; + } else { + scan->UserBuf.pw[pixels] = scan->Red.pw[dw] >> ls; + } + pixels += next; + ddax += izoom; + dw--; + } + } + break; + + case 2: + for( bitsput = 0, ddax = 0; dw; bitsput++ ) { + + ddax -= _SCALER; + + while((ddax < 0) && (dw > 0)) { + if( swap ) { + tmp = *((HiLoDef*)&scan->Green.pw[bitsput]); + scan->UserBuf.pw[pixels] = _HILO2WORD(tmp) >> ls; + } else { + scan->UserBuf.pw[pixels] = scan->Green.pw[bitsput] >> ls; + } + pixels += next; + ddax += izoom; + dw--; + } + } + break; + + case 3: + for( bitsput = 0, ddax = 0; dw; bitsput++ ) { + + ddax -= _SCALER; + + while((ddax < 0) && (dw > 0)) { + if( swap ) { + tmp = *((HiLoDef*)&scan->Blue.pw[bitsput]); + scan->UserBuf.pw[pixels] = _HILO2WORD(tmp) >> ls; + } else { + scan->UserBuf.pw[pixels] = scan->Blue.pw[bitsput] >> ls; + } + pixels += next; + ddax += izoom; + dw--; + } + } + break; + } +} + +/** here we copy and scale from scanner world to user world... + */ +static void usb_ColorScale8( Plustek_Device *dev ) +{ + int izoom, ddax, next; + u_long dw, pixels, bitsput; + ScanDef *scan = &dev->scanning; + + usb_AverageColorByte( dev ); + + dw = scan->sParam.Size.dwPixels; + + if( scan->sParam.bSource == SOURCE_ADF ) { + next = -1; + pixels = scan->sParam.Size.dwPixels - 1; + } else { + next = 1; + pixels = 0; + } + + izoom = usb_GetScaler( scan ); + + for( bitsput = 0, ddax = 0; dw; bitsput++ ) { + + ddax -= _SCALER; + + while((ddax < 0) && (dw > 0)) { + + scan->UserBuf.pb_rgb[pixels].Red = + scan->Red.pcb[bitsput].a_bColor[0]; + scan->UserBuf.pb_rgb[pixels].Green = + scan->Green.pcb[bitsput].a_bColor[0]; + scan->UserBuf.pb_rgb[pixels].Blue = + scan->Blue.pcb[bitsput].a_bColor[0]; + pixels += next; + ddax += izoom; + dw--; + } + } +} + +static void usb_ColorScale8_2( Plustek_Device *dev ) +{ + int izoom, ddax, next; + u_long dw, pixels, bitsput; + ScanDef *scan = &dev->scanning; + + dw = scan->sParam.Size.dwPixels; + + if( scan->sParam.bSource == SOURCE_ADF ) { + next = -1; + pixels = scan->sParam.Size.dwPixels - 1; + } else { + next = 1; + pixels = 0; + } + + izoom = usb_GetScaler( scan ); + + for( bitsput = 0, ddax = 0; dw; bitsput++ ) { + + ddax -= _SCALER; + + while((ddax < 0) && (dw > 0)) { + + scan->UserBuf.pb_rgb[pixels].Red = scan->Red.pb[bitsput]; + scan->UserBuf.pb_rgb[pixels].Green = scan->Green.pb[bitsput]; + scan->UserBuf.pb_rgb[pixels].Blue = scan->Blue.pb[bitsput]; + + pixels += next; + ddax += izoom; + dw--; + } + } +} + +/** + */ +static void usb_ColorScale16( Plustek_Device *dev ) +{ + u_char ls; + int izoom, ddax, next; + u_long dw, pixels, bitsput; + SANE_Bool swap = usb_HostSwap(); + ScanDef *scan = &dev->scanning; + + usb_AverageColorWord( dev ); + + dw = scan->sParam.Size.dwPixels; + + if( scan->sParam.bSource == SOURCE_ADF ) { + next = -1; + pixels = scan->sParam.Size.dwPixels - 1; + } else { + next = 1; + pixels = 0; + } + + izoom = usb_GetScaler( scan ); + + if( scan->dwFlag & SCANFLAG_RightAlign ) + ls = Shift; + else + ls = 0; + + for( bitsput = 0, ddax = 0; dw; bitsput++ ) { + + ddax -= _SCALER; + + while((ddax < 0) && (dw > 0)) { + + if( swap ) { + + scan->UserBuf.pw_rgb[pixels].Red = + _HILO2WORD(scan->Red.pcw[bitsput].HiLo[0]) >> ls; + + scan->UserBuf.pw_rgb[pixels].Green = + _HILO2WORD(scan->Green.pcw[bitsput].HiLo[0]) >> ls; + + scan->UserBuf.pw_rgb[pixels].Blue = + _HILO2WORD(scan->Blue.pcw[bitsput].HiLo[0]) >> ls; + + } else { + + scan->UserBuf.pw_rgb[pixels].Red = scan->Red.pw[bitsput]>>ls; + scan->UserBuf.pw_rgb[pixels].Green = scan->Green.pw[bitsput] >> ls; + scan->UserBuf.pw_rgb[pixels].Blue = scan->Blue.pw[bitsput] >> ls; + } + pixels += next; + ddax += izoom; + dw--; + } + } +} + +/** + */ +static void usb_ColorScale16_2( Plustek_Device *dev ) +{ + u_char ls; + HiLoDef tmp; + int izoom, ddax, next; + u_long dw, pixels, bitsput; + SANE_Bool swap = usb_HostSwap(); + ScanDef *scan = &dev->scanning; + + usb_AverageColorWord( dev ); + + dw = scan->sParam.Size.dwPixels; + + if( scan->sParam.bSource == SOURCE_ADF ) { + next = -1; + pixels = scan->sParam.Size.dwPixels - 1; + } else { + next = 1; + pixels = 0; + } + + izoom = usb_GetScaler( scan ); + + if( scan->dwFlag & SCANFLAG_RightAlign ) + ls = Shift; + else + ls = 0; + + for( bitsput = 0, ddax = 0; dw; bitsput++ ) { + + ddax -= _SCALER; + + while((ddax < 0) && (dw > 0)) { + + if( swap ) { + + tmp = *((HiLoDef*)&scan->Red.pw[bitsput]); + scan->UserBuf.pw_rgb[pixels].Red = _HILO2WORD(tmp) >> ls; + + tmp = *((HiLoDef*)&scan->Green.pw[bitsput]); + scan->UserBuf.pw_rgb[pixels].Green = _HILO2WORD(tmp) >> ls; + + tmp = *((HiLoDef*)&scan->Blue.pw[bitsput]); + scan->UserBuf.pw_rgb[pixels].Blue = _HILO2WORD(tmp) >> ls; + + } else { + + scan->UserBuf.pw_rgb[pixels].Red = scan->Red.pw[bitsput] >> ls; + scan->UserBuf.pw_rgb[pixels].Green = scan->Green.pw[bitsput] >> ls; + scan->UserBuf.pw_rgb[pixels].Blue = scan->Blue.pw[bitsput] >> ls; + } + pixels += next; + ddax += izoom; + dw--; + } + } +} + +/** + */ +static void usb_ColorScalePseudo16( Plustek_Device *dev ) +{ + int izoom, ddax, next; + u_short wR, wG, wB; + u_long dw, pixels, bitsput; + ScanDef *scan = &dev->scanning; + + usb_AverageColorByte( dev ); + + dw = scan->sParam.Size.dwPixels; + + if( scan->sParam.bSource == SOURCE_ADF ) { + next = -1; + pixels = scan->sParam.Size.dwPixels - 1; + } else { + next = 1; + pixels = 0; + } + + izoom = usb_GetScaler( scan ); + + wR = (u_short)scan->Red.pcb[0].a_bColor[0]; + wG = (u_short)scan->Green.pcb[0].a_bColor[1]; + wB = (u_short)scan->Blue.pcb[0].a_bColor[2]; + + for( bitsput = 0, ddax = 0; dw; bitsput++ ) { + + ddax -= _SCALER; + + while((ddax < 0) && (dw > 0)) { + + scan->UserBuf.pw_rgb[pixels].Red = + (wR + scan->Red.pcb[bitsput].a_bColor[0]) << bShift; + + scan->UserBuf.pw_rgb[pixels].Green = + (wG + scan->Green.pcb[bitsput].a_bColor[0]) << bShift; + + scan->UserBuf.pw_rgb[pixels].Blue = + (wB + scan->Blue.pcb[bitsput].a_bColor[0]) << bShift; + + pixels += next; + ddax += izoom; + dw--; + } + + wR = (u_short)scan->Red.pcb[bitsput].a_bColor[0]; + wG = (u_short)scan->Green.pcb[bitsput].a_bColor[0]; + wB = (u_short)scan->Blue.pcb[bitsput].a_bColor[0]; + } +} + +/** + */ +static void usb_BWScale( Plustek_Device *dev ) +{ + u_char tmp, *dest, *src; + int izoom, ddax; + u_long i, dw; + ScanDef *scan = &dev->scanning; + + src = scan->Green.pb; + if( scan->sParam.bSource == SOURCE_ADF ) { + int iSum = wSum; + usb_ReverseBitStream(scan->Green.pb, scan->UserBuf.pb, + scan->sParam.Size.dwValidPixels, + scan->dwBytesLine, scan->sParam.PhyDpi.x, + scan->sParam.UserDpi.x, 1 ); + wSum = iSum; + return; + } else { + dest = scan->UserBuf.pb; + } + + izoom = usb_GetScaler( scan ); + + memset( dest, 0, scan->dwBytesLine ); + ddax = 0; + dw = 0; + + for( i = 0; i < scan->sParam.Size.dwValidPixels; i++ ) { + + ddax -= _SCALER; + + while( ddax < 0 ) { + + tmp = src[(i>>3)]; + + if((dw>>3) < scan->sParam.Size.dwValidPixels ) { + + if( 0 != (tmp &= (1 << ((~(i & 0x7))&0x7)))) + dest[dw>>3] |= (1 << ((~(dw & 0x7))&0x7)); + } + dw++; + ddax += izoom; + } + } +} + +/** + */ +static void usb_BWScaleFromColor( Plustek_Device *dev ) +{ + u_char d, s, *dest; + u_short j; + u_long pixels; + int izoom, ddax, next; + ColorByteDef *src; + ScanDef *scan = &dev->scanning; + + if (scan->sParam.bSource == SOURCE_ADF) { + dest = scan->UserBuf.pb + scan->sParam.Size.dwPixels - 1; + next = -1; + } else { + dest = scan->UserBuf.pb; + next = 1; + } + + /* setup the source buffer */ + switch(scan->fGrayFromColor) { + case 1: src = scan->Red.pcb; break; + case 3: src = scan->Blue.pcb; break; + default: src = scan->Green.pcb; break; + } + + izoom = usb_GetScaler( scan ); + ddax = 0; + + d = j = 0; + for( pixels = scan->sParam.Size.dwPixels; pixels; src++ ) { + + ddax -= _SCALER; + + while((ddax < 0) && (pixels > 0)) { + + s = src->a_bColor[0]; + if( s != 0 ) + d |= BitTable[j]; + j++; + if( j == 8 ) { + *dest = d; + dest += next; + d = j = 0; + } + ddax += izoom; + pixels--; + } + } +} + +/** + */ +static void usb_BWScaleFromColor_2( Plustek_Device *dev ) +{ + u_char d, *dest, *src; + u_short j; + u_long pixels; + int izoom, ddax, next; + ScanDef *scan = &dev->scanning; + + if (scan->sParam.bSource == SOURCE_ADF) { + dest = scan->UserBuf.pb + scan->sParam.Size.dwPixels - 1; + next = -1; + } else { + dest = scan->UserBuf.pb; + next = 1; + } + + /* setup the source buffer */ + switch(scan->fGrayFromColor) { + case 1: src = scan->Red.pb; break; + case 3: src = scan->Blue.pb; break; + default: src = scan->Green.pb; break; + } + + izoom = usb_GetScaler( scan ); + ddax = 0; + + d = j = 0; + for( pixels = scan->sParam.Size.dwPixels; pixels; src++ ) { + + ddax -= _SCALER; + + while((ddax < 0) && (pixels > 0)) { + + if( *src != 0 ) + d |= BitTable[j]; + j++; + if( j == 8 ) { + *dest = d; + dest += next; + d = j = 0; + } + ddax += izoom; + pixels--; + } + } +} + +/** + */ +static void usb_GrayScale8( Plustek_Device *dev ) +{ + u_char *dest, *src; + int izoom, ddax, next; + u_long pixels; + ScanDef *scan = &dev->scanning; + + usb_AverageGrayByte( dev ); + + src = scan->Green.pb; + if( scan->sParam.bSource == SOURCE_ADF ) { + dest = scan->UserBuf.pb + scan->sParam.Size.dwPixels - 1; + next = -1; + } else { + dest = scan->UserBuf.pb; + next = 1; + } + + izoom = usb_GetScaler( scan ); + ddax = 0; + + for( pixels = scan->sParam.Size.dwPixels; pixels; src++ ) { + + ddax -= _SCALER; + + while((ddax < 0) && (pixels > 0)) { + + *dest = *src; + dest += next; + ddax += izoom; + pixels--; + } + } +} + +/** + */ +static void usb_GrayScale16( Plustek_Device *dev ) +{ + u_char ls; + int izoom, ddax, next; + u_short *dest; + u_long pixels; + HiLoDef *pwm; + ScanDef *scan = &dev->scanning; + SANE_Bool swap = usb_HostSwap(); + + usb_AverageGrayWord( dev); + + pwm = scan->Green.philo; + wSum = scan->sParam.PhyDpi.x; + + if( scan->sParam.bSource == SOURCE_ADF ) { + next = -1; + dest = scan->UserBuf.pw + scan->sParam.Size.dwPixels - 1; + } else { + next = 1; + dest = scan->UserBuf.pw; + } + + izoom = usb_GetScaler( scan ); + ddax = 0; + + if( scan->dwFlag & SCANFLAG_RightAlign ) + ls = Shift; + else + ls = 0; + + for( pixels = scan->sParam.Size.dwPixels; pixels; pwm++ ) { + + ddax -= _SCALER; + + while((ddax < 0) && (pixels > 0)) { + + if( swap ) + *dest = _PHILO2WORD(pwm) >> ls; + else + *dest = _PLOHI2WORD(pwm) >> ls; + + dest += next; + ddax += izoom; + pixels--; + } + } +} + +/** + */ +static void usb_GrayScalePseudo16( Plustek_Device *dev ) +{ + u_char *src; + int izoom, ddax, next; + u_short *dest, g; + u_long pixels; + ScanDef *scan = &dev->scanning; + + usb_AverageGrayByte( dev ); + + if( scan->sParam.bSource == SOURCE_ADF ) { + next = -1; + dest = scan->UserBuf.pw + scan->sParam.Size.dwPixels - 1; + } else { + next = 1; + dest = scan->UserBuf.pw; + } + + src = scan->Green.pb; + g = (u_short)*src; + + izoom = usb_GetScaler( scan ); + ddax = 0; + + for( pixels = scan->sParam.Size.dwPixels; pixels; src++ ) { + + ddax -= _SCALER; + + while((ddax < 0) && (pixels > 0)) { + + *dest = (g + *src) << bShift; + dest += next; + ddax += izoom; + pixels--; + } + g = (u_short)*src; + } +} + +/** function to select the apropriate pixel copy function + */ +static void usb_GetImageProc( Plustek_Device *dev ) +{ + ScanDef *scan = &dev->scanning; + DCapsDef *sc = &dev->usbDev.Caps; + HWDef *hw = &dev->usbDev.HwSetting; + + bShift = 0; + + if( scan->sParam.UserDpi.x != scan->sParam.PhyDpi.x ) { + + /* Pixel scaling... */ + switch( scan->sParam.bDataType ) { + + case SCANDATATYPE_Color: + if (scan->sParam.bBitDepth > 8) { + + if( usb_IsCISDevice(dev)){ + scan->pfnProcess = usb_ColorScale16_2; + DBG( _DBG_INFO, "ImageProc is: ColorScale16_2\n" ); + } else { + scan->pfnProcess = usb_ColorScale16; + DBG( _DBG_INFO, "ImageProc is: ColorScale16\n" ); + } + if (scan->fGrayFromColor) { + if( usb_IsCISDevice(dev)){ + scan->pfnProcess = usb_ColorScaleGray16_2; + DBG( _DBG_INFO, "ImageProc is: ColorScaleGray16_2\n" ); + } else { + scan->pfnProcess = usb_ColorScaleGray16; + DBG( _DBG_INFO, "ImageProc is: ColorScaleGray16\n" ); + } + } + } else if (scan->dwFlag & SCANFLAG_Pseudo48) { + scan->pfnProcess = usb_ColorScalePseudo16; + DBG( _DBG_INFO, "ImageProc is: ColorScalePseudo16\n" ); + + } else if (scan->fGrayFromColor) { + + if( usb_IsCISDevice(dev)){ + if (scan->fGrayFromColor > 7 ) { + scan->pfnProcess = usb_BWScaleFromColor_2; + DBG( _DBG_INFO, "ImageProc is: BWScaleFromColor_2\n" ); + } else { + scan->pfnProcess = usb_ColorScaleGray_2; + DBG( _DBG_INFO, "ImageProc is: ColorScaleGray_2\n" ); + } + } else { + if (scan->fGrayFromColor > 7 ) { + scan->pfnProcess = usb_BWScaleFromColor; + DBG( _DBG_INFO, "ImageProc is: BWScaleFromColor\n" ); + } else { + scan->pfnProcess = usb_ColorScaleGray; + DBG( _DBG_INFO, "ImageProc is: ColorScaleGray\n" ); + } + } + } else { + + if( usb_IsCISDevice(dev)){ + scan->pfnProcess = usb_ColorScale8_2; + DBG( _DBG_INFO, "ImageProc is: ColorScale8_2\n" ); + } else { + scan->pfnProcess = usb_ColorScale8; + DBG( _DBG_INFO, "ImageProc is: ColorScale8\n" ); + } + } + break; + + case SCANDATATYPE_Gray: + if (scan->sParam.bBitDepth > 8) { + scan->pfnProcess = usb_GrayScale16; + DBG( _DBG_INFO, "ImageProc is: GrayScale16\n" ); + } else { + + if (scan->dwFlag & SCANFLAG_Pseudo48) { + scan->pfnProcess = usb_GrayScalePseudo16; + DBG( _DBG_INFO, "ImageProc is: GrayScalePseudo16\n" ); + } else { + scan->pfnProcess = usb_GrayScale8; + DBG( _DBG_INFO, "ImageProc is: GrayScale8\n" ); + } + } + break; + + default: + scan->pfnProcess = usb_BWScale; + DBG( _DBG_INFO, "ImageProc is: BWScale\n" ); + break; + } + + } else { + + /* Pixel copy */ + switch( scan->sParam.bDataType ) { + + case SCANDATATYPE_Color: + if (scan->sParam.bBitDepth > 8) { + if( usb_IsCISDevice(dev)){ + scan->pfnProcess = usb_ColorDuplicate16_2; + DBG( _DBG_INFO, "ImageProc is: ColorDuplicate16_2\n" ); + } else { + scan->pfnProcess = usb_ColorDuplicate16; + DBG( _DBG_INFO, "ImageProc is: ColorDuplicate16\n" ); + } + if (scan->fGrayFromColor) { + if( usb_IsCISDevice(dev)){ + scan->pfnProcess = usb_ColorDuplicateGray16_2; + DBG( _DBG_INFO, "ImageProc is: ColorDuplicateGray16_2\n" ); + } else { + scan->pfnProcess = usb_ColorDuplicateGray16; + DBG( _DBG_INFO, "ImageProc is: ColorDuplicateGray16\n" ); + } + } + } else if (scan->dwFlag & SCANFLAG_Pseudo48) { + scan->pfnProcess = usb_ColorDuplicatePseudo16; + DBG( _DBG_INFO, "ImageProc is: ColorDuplicatePseudo16\n" ); + } else if (scan->fGrayFromColor) { + if( usb_IsCISDevice(dev)){ + if (scan->fGrayFromColor > 7 ) { + scan->pfnProcess = usb_BWDuplicateFromColor_2; + DBG( _DBG_INFO, "ImageProc is: BWDuplicateFromColor_2\n" ); + } else { + scan->pfnProcess = usb_ColorDuplicateGray_2; + DBG( _DBG_INFO, "ImageProc is: ColorDuplicateGray_2\n" ); + } + } else { + if (scan->fGrayFromColor > 7 ) { + scan->pfnProcess = usb_BWDuplicateFromColor; + DBG( _DBG_INFO, "ImageProc is: BWDuplicateFromColor\n" ); + } else { + scan->pfnProcess = usb_ColorDuplicateGray; + DBG( _DBG_INFO, "ImageProc is: ColorDuplicateGray\n" ); + } + } + } else { + if( usb_IsCISDevice(dev)){ + scan->pfnProcess = usb_ColorDuplicate8_2; + DBG( _DBG_INFO, "ImageProc is: ColorDuplicate8_2\n" ); + } else { + scan->pfnProcess = usb_ColorDuplicate8; + DBG( _DBG_INFO, "ImageProc is: ColorDuplicate8\n" ); + } + } + break; + + case SCANDATATYPE_Gray: + if (scan->sParam.bBitDepth > 8) { + scan->pfnProcess = usb_GrayDuplicate16; + DBG( _DBG_INFO, "ImageProc is: GrayDuplicate16\n" ); + } else { + if (scan->dwFlag & SCANFLAG_Pseudo48) { + scan->pfnProcess = usb_GrayDuplicatePseudo16; + DBG( _DBG_INFO, "ImageProc is: GrayDuplicatePseudo16\n" ); + } else { + scan->pfnProcess = usb_GrayDuplicate8; + DBG( _DBG_INFO, "ImageProc is: GrayDuplicate8\n" ); + } + } + break; + + default: + scan->pfnProcess = usb_BWDuplicate; + DBG( _DBG_INFO, "ImageProc is: BWDuplicate\n" ); + break; + } + } + + if( scan->sParam.bBitDepth == 8 ) { + + if( scan->dwFlag & SCANFLAG_Pseudo48 ) { + if( scan->dwFlag & SCANFLAG_RightAlign ) { + bShift = 5; + } else { + + /* this should fix the Bearpaw/U12 discrepancy + * in general the fix is needed, but not for the U12 + * why? - no idea! + */ + if(_WAF_BSHIFT7_BUG == (_WAF_BSHIFT7_BUG & sc->workaroundFlag)) + bShift = 0; /* Holger Bischof 16.12.2001 */ + else + bShift = 7; + } + DBG( _DBG_INFO, "bShift adjusted: %u\n", bShift ); + } + } + + if( _LM9833 == hw->chip ) { + Shift = 0; + Mask = 0xFFFF; + } else { + Shift = 2; + Mask = 0xFFFC; + } +} + +/** + * here we read the image data into our intermediate buffer (in the NT version + * the function was implemented as thread) + */ +static SANE_Int usb_ReadData( Plustek_Device *dev ) +{ + u_long dw, dwRet, dwBytes, pl; + ScanDef *scan = &dev->scanning; + HWDef *hw = &dev->usbDev.HwSetting; + + DBG( _DBG_READ, "usb_ReadData()\n" ); + + pl = dev->usbDev.a_bRegs[0x4e] * hw->wDRAMSize/128; + + while( scan->sParam.Size.dwTotalBytes ) { + + if( usb_IsEscPressed()) { + DBG( _DBG_INFO, "usb_ReadData() - Cancel detected...\n" ); + return 0; + } + + if( scan->sParam.Size.dwTotalBytes > scan->dwBytesScanBuf ) + dw = scan->dwBytesScanBuf; + else + dw = scan->sParam.Size.dwTotalBytes; + + scan->sParam.Size.dwTotalBytes -= dw; + + if(!scan->sParam.Size.dwTotalBytes && dw < (pl * 1024)) + { + if(!(dev->usbDev.a_bRegs[0x4e] = (u_char)ceil((double)dw / + (4.0 * hw->wDRAMSize)))) { + dev->usbDev.a_bRegs[0x4e] = 1; + } + dev->usbDev.a_bRegs[0x4f] = 0; + + sanei_lm983x_write( dev->fd, 0x4e, &dev->usbDev.a_bRegs[0x4e], 2, SANE_TRUE ); + } + + while( scan->bLinesToSkip ) { + + DBG( _DBG_READ, "Skipping %u lines\n", scan->bLinesToSkip ); + + dwBytes = scan->bLinesToSkip * scan->sParam.Size.dwPhyBytes; + + if (dwBytes > scan->dwBytesScanBuf) { + + dwBytes = scan->dwBytesScanBuf; + scan->bLinesToSkip -= scan->dwLinesScanBuf; + } else { + scan->bLinesToSkip = 0; + } + + if( !usb_ScanReadImage( dev, scan->pbGetDataBuf, dwBytes )) + return 0; + } + + if( usb_ScanReadImage( dev, scan->pbGetDataBuf, dw )) { + + dumpPic("plustek-pic.raw", scan->pbGetDataBuf, dw, 0); + + if( scan->dwLinesDiscard ) { + + DBG(_DBG_READ, "Discarding %lu lines\n", scan->dwLinesDiscard); + + dwRet = dw / scan->sParam.Size.dwPhyBytes; + + if (scan->dwLinesDiscard > dwRet) { + scan->dwLinesDiscard -= dwRet; + dwRet = 0; + } else { + dwRet -= scan->dwLinesDiscard; + scan->dwLinesDiscard = 0; + } + } else { + + dwRet = dw / scan->sParam.Size.dwPhyBytes; + } + + scan->pbGetDataBuf += scan->dwBytesScanBuf; + if( scan->pbGetDataBuf >= scan->pbScanBufEnd ) { + scan->pbGetDataBuf = scan->pbScanBufBegin; + } + + if( dwRet ) + return dwRet; + } + } + return 0; +} + +/* END PLUSTEK-USBIMG.C .....................................................*/ |