1/* @file u12-pp_tpa.c 2 * @brief Here we find some adjustments according to the scan source. 3 * 4 * based on sources acquired from Plustek Inc. 5 * Copyright (C) 2003-2004 Gerhard Jaeger <gerhard@gjaeger.de> 6 * 7 * History: 8 * - 0.01 - initial version 9 * - 0.02 - cleanup 10 * . 11 * <hr> 12 * This file is part of the SANE package. 13 * 14 * This program is free software; you can redistribute it and/or 15 * modify it under the terms of the GNU General Public License as 16 * published by the Free Software Foundation; either version 2 of the 17 * License, or (at your option) any later version. 18 * 19 * This program is distributed in the hope that it will be useful, but 20 * WITHOUT ANY WARRANTY; without even the implied warranty of 21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 22 * General Public License for more details. 23 * 24 * You should have received a copy of the GNU General Public License 25 * along with this program. If not, see <https://www.gnu.org/licenses/>. 26 * 27 * As a special exception, the authors of SANE give permission for 28 * additional uses of the libraries contained in this release of SANE. 29 * 30 * The exception is that, if you link a SANE library with other files 31 * to produce an executable, this does not by itself cause the 32 * resulting executable to be covered by the GNU General Public 33 * License. Your use of that executable is in no way restricted on 34 * account of linking the SANE library code into it. 35 * 36 * This exception does not, however, invalidate any other reasons why 37 * the executable file might be covered by the GNU General Public 38 * License. 39 * 40 * If you submit changes to SANE to the maintainers to be included in 41 * a subsequent release, you agree by submitting the changes that 42 * those changes may be distributed with this exception intact. 43 * 44 * If you write modifications of your own for SANE, it is your choice 45 * whether to permit this exception to apply to your modifications. 46 * If you do not wish that, delete this exception notice. 47 * <hr> 48 */ 49 50/** this function does some reshading, when scanning negatives on an ASIC 98003 51 * based scanner 52 */ 53static void u12tpa_Reshading( U12_Device *dev ) 54{ 55 SANE_Byte bHi[3], bHiLeft[3], bHiRight[3]; 56 u_long i, dwR, dwG, dwB, dwSum; 57 u_long dwIndex, dwIndexRight, dwIndexLeft; 58 DataPointer RedPtr, GreenPtr, BluePtr; 59 TimerDef timer; 60 61 DBG( _DBG_INFO, "u12tpa_Reshading()\n" ); 62 63 bHi[0] = bHi[1] = bHi[2] = 0; 64 65 dev->scan.negScan[1].exposureTime = 144; 66 dev->scan.negScan[1].xStepTime = 18; 67 dev->scan.negScan[2].exposureTime = 144; 68 dev->scan.negScan[2].xStepTime = 36; 69 dev->scan.negScan[3].exposureTime = 144; 70 dev->scan.negScan[3].xStepTime = 72; 71 dev->scan.negScan[4].exposureTime = 144; 72 dev->scan.negScan[4].xStepTime = 144; 73 74 dev->shade.wExposure = dev->scan.negScan[dev->scan.dpiIdx].exposureTime; 75 dev->shade.wXStep = dev->scan.negScan[dev->scan.dpiIdx].xStepTime; 76 77 u12io_StartTimer( &timer, _SECOND ); 78 79 u12io_ResetFifoLen(); 80 while(!(u12io_GetScanState( dev ) & _SCANSTATE_STOP) && 81 (!u12io_CheckTimer(&timer))); 82 u12io_DataToRegister( dev, REG_XSTEPTIME, 83 (SANE_Byte)(dev->regs.RD_LineControl >> 4)); 84 _DODELAY( 12 ); 85 u12motor_PositionYProc( dev, _NEG_SHADING_OFFS ); 86 87 u12io_DataToRegister( dev, REG_XSTEPTIME, dev->regs.RD_XStepTime ); 88 89 dev->regs.RD_ScanControl = _SCAN_BYTEMODE; 90 u12hw_SelectLampSource( dev ); 91 92 u12io_DataToRegister( dev, REG_LINECONTROL, _LOBYTE(dev->shade.wExposure)); 93 u12io_DataToRegister( dev, REG_XSTEPTIME, _LOBYTE(dev->shade.wXStep)); 94 95 dev->regs.RD_LineControl = _LOBYTE(dev->shade.wExposure); 96 dev->regs.RD_ExtLineControl = _HIBYTE(dev->shade.wExposure); 97 dev->regs.RD_XStepTime = (SANE_Byte)(dev->shade.wExposure); 98 dev->regs.RD_ModeControl = _ModeScan; 99 dev->regs.RD_Motor0Control = _FORWARD_MOTOR; 100 101 dev->regs.RD_Origin = (u_short)dev->scan.negBegin; 102 dev->regs.RD_Pixels = _NEG_PAGEWIDTH600; 103 104 memset( dev->scanStates, 0, _SCANSTATE_BYTES ); 105 106 /* put 9 scan states to make sure there are 8 lines available at least */ 107 for( i = 0; i <= 12; i++) 108 dev->scanStates[i] = 0x8f; 109 110 u12io_PutOnAllRegisters( dev ); 111 _DODELAY( 70 ); 112 113 /* prepare the buffers... */ 114 memset( dev->bufs.TpaBuf.pb, 0, _SIZE_TPA_DATA_BUF ); 115 116 RedPtr.pb = dev->bufs.b1.pShadingMap; 117 GreenPtr.pb = RedPtr.pb + _NEG_PAGEWIDTH600; 118 BluePtr.pb = GreenPtr.pb + _NEG_PAGEWIDTH600; 119 120 for( dwSum = 8; dwSum--; ) { 121 122 u12io_ReadOneShadingLine( dev, dev->bufs.b1.pShadingMap, _NEG_PAGEWIDTH600 ); 123 124 for( i = 0; i < _NEG_PAGEWIDTH600; i++) { 125 126 dev->bufs.TpaBuf.pusrgb[i].Red += RedPtr.pb[i]; 127 dev->bufs.TpaBuf.pusrgb[i].Green += GreenPtr.pb[i]; 128 dev->bufs.TpaBuf.pusrgb[i].Blue += BluePtr.pb[i]; 129 } 130 } 131 132 for( i = 0; i < (_NEG_PAGEWIDTH600 * 3UL); i++ ) 133 dev->bufs.TpaBuf.pb[i] = dev->bufs.TpaBuf.pw[i] >> 3; 134 135 RedPtr.pb = dev->bufs.TpaBuf.pb; 136 137 /* Convert RGB to gray scale (Brightness), and average 16 pixels */ 138 for( bHiRight[1] = 0, i = dwIndexRight = 0; 139 i < _NEG_PAGEWIDTH600 / 2; i += 16 ) { 140 bHiRight [0] = 141 (SANE_Byte)(((((u_long) RedPtr.pbrgb [i].Red + 142 (u_long) RedPtr.pbrgb[i + 1].Red + 143 (u_long) RedPtr.pbrgb[i + 2].Red + 144 (u_long) RedPtr.pbrgb[i + 3].Red + 145 (u_long) RedPtr.pbrgb[i + 4].Red + 146 (u_long) RedPtr.pbrgb[i + 5].Red + 147 (u_long) RedPtr.pbrgb[i + 6].Red + 148 (u_long) RedPtr.pbrgb[i + 7].Red + 149 (u_long) RedPtr.pbrgb[i + 8].Red + 150 (u_long) RedPtr.pbrgb[i + 9].Red + 151 (u_long) RedPtr.pbrgb[i + 10].Red + 152 (u_long) RedPtr.pbrgb[i + 11].Red + 153 (u_long) RedPtr.pbrgb[i + 12].Red + 154 (u_long) RedPtr.pbrgb[i + 13].Red + 155 (u_long) RedPtr.pbrgb[i + 14].Red + 156 (u_long) RedPtr.pbrgb[i + 15].Red) >> 4) * 30UL + 157 (((u_long) RedPtr.pbrgb[i].Green + 158 (u_long) RedPtr.pbrgb[i + 1].Green + 159 (u_long) RedPtr.pbrgb[i + 2].Green + 160 (u_long) RedPtr.pbrgb[i + 3].Green + 161 (u_long) RedPtr.pbrgb[i + 4].Green + 162 (u_long) RedPtr.pbrgb[i + 5].Green + 163 (u_long) RedPtr.pbrgb[i + 6].Green + 164 (u_long) RedPtr.pbrgb[i + 7].Green + 165 (u_long) RedPtr.pbrgb[i + 8].Green + 166 (u_long) RedPtr.pbrgb[i + 9].Green + 167 (u_long) RedPtr.pbrgb[i + 10].Green + 168 (u_long) RedPtr.pbrgb[i + 11].Green + 169 (u_long) RedPtr.pbrgb[i + 12].Green + 170 (u_long) RedPtr.pbrgb[i + 13].Green + 171 (u_long) RedPtr.pbrgb[i + 14].Green + 172 (u_long) RedPtr.pbrgb[i + 15].Green) >> 4) * 59UL + 173 (((u_long) RedPtr.pbrgb[i].Blue + 174 (u_long) RedPtr.pbrgb[i + 1].Blue + 175 (u_long) RedPtr.pbrgb[i + 2].Blue + 176 (u_long) RedPtr.pbrgb[i + 3].Blue + 177 (u_long) RedPtr.pbrgb[i + 4].Blue + 178 (u_long) RedPtr.pbrgb[i + 5].Blue + 179 (u_long) RedPtr.pbrgb[i + 6].Blue + 180 (u_long) RedPtr.pbrgb[i + 7].Blue + 181 (u_long) RedPtr.pbrgb[i + 8].Blue + 182 (u_long) RedPtr.pbrgb[i + 9].Blue + 183 (u_long) RedPtr.pbrgb[i + 10].Blue + 184 (u_long) RedPtr.pbrgb[i + 11].Blue + 185 (u_long) RedPtr.pbrgb[i + 12].Blue + 186 (u_long) RedPtr.pbrgb[i + 13].Blue + 187 (u_long) RedPtr.pbrgb[i + 14].Blue + 188 (u_long) RedPtr.pbrgb[i + 15].Blue) >> 4) * 11UL) / 100UL); 189 190 if( bHiRight[1] < bHiRight[0] ) { 191 bHiRight[1] = bHiRight[0]; 192 dwIndexRight = i; 193 } 194 } 195 196 /* Convert RGB to gray scale (Brightness), and average 16 pixels */ 197 for( bHiLeft[1] = 0, i = dwIndexLeft = _NEG_PAGEWIDTH / 2; 198 i < _NEG_PAGEWIDTH600; i += 16 ) { 199 bHiLeft [0] = 200 (SANE_Byte)(((((u_long) RedPtr.pbrgb[i].Red + 201 (u_long) RedPtr.pbrgb[i + 1].Red + 202 (u_long) RedPtr.pbrgb[i + 2].Red + 203 (u_long) RedPtr.pbrgb[i + 3].Red + 204 (u_long) RedPtr.pbrgb[i + 4].Red + 205 (u_long) RedPtr.pbrgb[i + 5].Red + 206 (u_long) RedPtr.pbrgb[i + 6].Red + 207 (u_long) RedPtr.pbrgb[i + 7].Red + 208 (u_long) RedPtr.pbrgb[i + 8].Red + 209 (u_long) RedPtr.pbrgb[i + 9].Red + 210 (u_long) RedPtr.pbrgb[i + 10].Red + 211 (u_long) RedPtr.pbrgb[i + 11].Red + 212 (u_long) RedPtr.pbrgb[i + 12].Red + 213 (u_long) RedPtr.pbrgb[i + 13].Red + 214 (u_long) RedPtr.pbrgb[i + 14].Red + 215 (u_long) RedPtr.pbrgb[i + 15].Red) >> 4) * 30UL + 216 (((u_long) RedPtr.pbrgb[i].Green + 217 (u_long) RedPtr.pbrgb[i + 1].Green + 218 (u_long) RedPtr.pbrgb[i + 2].Green + 219 (u_long) RedPtr.pbrgb[i + 3].Green + 220 (u_long) RedPtr.pbrgb[i + 4].Green + 221 (u_long) RedPtr.pbrgb[i + 5].Green + 222 (u_long) RedPtr.pbrgb[i + 6].Green + 223 (u_long) RedPtr.pbrgb[i + 7].Green + 224 (u_long) RedPtr.pbrgb[i + 8].Green + 225 (u_long) RedPtr.pbrgb[i + 9].Green + 226 (u_long) RedPtr.pbrgb[i + 10].Green + 227 (u_long) RedPtr.pbrgb[i + 11].Green + 228 (u_long) RedPtr.pbrgb[i + 12].Green + 229 (u_long) RedPtr.pbrgb[i + 13].Green + 230 (u_long) RedPtr.pbrgb[i + 14].Green + 231 (u_long) RedPtr.pbrgb[i + 15].Green) >> 4) * 59UL + 232 (((u_long) RedPtr.pbrgb[i].Blue + 233 (u_long) RedPtr.pbrgb[i + 1].Blue + 234 (u_long) RedPtr.pbrgb[i + 2].Blue + 235 (u_long) RedPtr.pbrgb[i + 3].Blue + 236 (u_long) RedPtr.pbrgb[i + 4].Blue + 237 (u_long) RedPtr.pbrgb[i + 5].Blue + 238 (u_long) RedPtr.pbrgb[i + 6].Blue + 239 (u_long) RedPtr.pbrgb[i + 7].Blue + 240 (u_long) RedPtr.pbrgb[i + 8].Blue + 241 (u_long) RedPtr.pbrgb[i + 9].Blue + 242 (u_long) RedPtr.pbrgb[i + 10].Blue + 243 (u_long) RedPtr.pbrgb[i + 11].Blue + 244 (u_long) RedPtr.pbrgb[i + 12].Blue + 245 (u_long) RedPtr.pbrgb[i + 13].Blue + 246 (u_long) RedPtr.pbrgb[i + 14].Blue + 247 (u_long) RedPtr.pbrgb[i + 15].Blue) >> 4) * 11UL) / 100UL); 248 249 if( bHiLeft[1] < bHiLeft[0] ) { 250 bHiLeft[1] = bHiLeft[0]; 251 dwIndexLeft = i; 252 } 253 } 254 255 if((bHiLeft[1] < 200) && (bHiRight[1] < 200)) { 256 257 if( bHiLeft[1] < bHiRight[1] ) 258 dwIndex = dwIndexRight; 259 else 260 dwIndex = dwIndexLeft; 261 } else { 262 if( bHiLeft[1] > 200 ) 263 dwIndex = dwIndexRight; 264 else 265 dwIndex = dwIndexLeft; 266 } 267 268 /* Get the hilight */ 269 RedPtr.pusrgb = dev->bufs.b2.pSumRGB + dwIndex + 270 dev->regs.RD_Origin + _SHADING_BEGINX; 271 272 for( dwR = dwG = dwB = 0, i = 16; i--; RedPtr.pusrgb++ ) { 273 dwR += RedPtr.pusrgb->Red; 274 dwG += RedPtr.pusrgb->Green; 275 dwB += RedPtr.pusrgb->Blue; 276 } 277 278 dwR >>= 8; 279 dwG >>= 8; 280 dwB >>= 8; 281 282 if( dwR > dwG && dwR > dwB ) 283 dev->shade.bGainHigh = (SANE_Byte)dwR; /* >> 4 for average, >> 4 to 8-bit */ 284 else { 285 if( dwG > dwR && dwG > dwB ) 286 dev->shade.bGainHigh = (SANE_Byte)dwG; 287 else 288 dev->shade.bGainHigh = (SANE_Byte)dwB; 289 } 290 291 dev->shade.bGainHigh = (SANE_Byte)(dev->shade.bGainHigh - 0x18); 292 dev->shade.bGainLow = (SANE_Byte)(dev->shade.bGainHigh - 0x10); 293 294 /* Reshading to get the new gain */ 295 dev->shade.Hilight.Colors.Red = 0; 296 dev->shade.Hilight.Colors.Green = 0; 297 dev->shade.Hilight.Colors.Blue = 0; 298 dev->shade.Gain.Colors.Red++; 299 dev->shade.Gain.Colors.Green++; 300 dev->shade.Gain.Colors.Blue++; 301 dev->shade.fStop = SANE_FALSE; 302 303 RedPtr.pb = dev->bufs.b1.pShadingMap + dwIndex; 304 GreenPtr.pb = RedPtr.pb + _NEG_PAGEWIDTH600; 305 BluePtr.pb = GreenPtr.pb + _NEG_PAGEWIDTH600; 306 307 for( i = 16; i-- && !dev->shade.fStop;) { 308 309 dev->shade.fStop = SANE_TRUE; 310 311 u12shading_FillToDAC( dev, &dev->RegDACGain, &dev->shade.Gain ); 312 313 u12io_DataToRegister( dev, REG_MODECONTROL, _ModeIdle ); 314 315 dev->regs.RD_ScanControl = _SCAN_BYTEMODE; 316 u12hw_SelectLampSource( dev ); 317 318 dev->regs.RD_ModeControl = _ModeScan; 319 dev->regs.RD_StepControl = _MOTOR0_SCANSTATE; 320 dev->regs.RD_Motor0Control = _FORWARD_MOTOR; 321 322 memset( dev->scanStates, 0, _SCANSTATE_BYTES ); 323 dev->scanStates[1] = 0x77; 324 325 u12io_PutOnAllRegisters( dev ); 326 _DODELAY( 50 ); 327 328 if(u12io_ReadOneShadingLine( dev, 329 dev->bufs.b1.pShadingMap,_NEG_PAGEWIDTH600)) { 330 331 bHi[0] = u12shading_SumGains( RedPtr.pb, 32 ); 332 bHi[1] = u12shading_SumGains( GreenPtr.pb, 32 ); 333 bHi[2] = u12shading_SumGains( BluePtr.pb, 32 ); 334 335 if( !bHi[0] || !bHi[1] || !bHi[2]) { 336 dev->shade.fStop = SANE_FALSE; 337 } else { 338 339 u12shading_AdjustGain( dev, _CHANNEL_RED, bHi[0] ); 340 u12shading_AdjustGain( dev, _CHANNEL_GREEN, bHi[1] ); 341 u12shading_AdjustGain( dev, _CHANNEL_BLUE, bHi[2] ); 342 } 343 } else { 344 dev->shade.fStop = SANE_FALSE; 345 } 346 } 347 348 u12shading_FillToDAC( dev, &dev->RegDACGain, &dev->shade.Gain ); 349 350 /* Set RGB Gain */ 351 if( dwR && dwG && dwB ) { 352 353 if(dev->CCDID == _CCD_3797 || dev->DACType == _DA_ESIC ) { 354 dev->shade.pCcdDac->GainResize.Colors.Red = 355 (u_short)((u_long)bHi[0] * 100UL / dwR); 356 dev->shade.pCcdDac->GainResize.Colors.Green = 357 (u_short)((u_long)bHi[1] * 100UL / dwG); 358 dev->shade.pCcdDac->GainResize.Colors.Blue = 359 (u_short)((u_long)bHi[2] * 100UL / dwB); 360 } else { 361 dev->shade.pCcdDac->GainResize.Colors.Red = 362 (u_short)((u_long)bHi[0] * 90UL / dwR); 363 dev->shade.pCcdDac->GainResize.Colors.Green = 364 (u_short)((u_long)bHi[1] * 77UL / dwG); 365 dev->shade.pCcdDac->GainResize.Colors.Blue = 366 (u_short)((u_long)bHi[2] * 73UL / dwB); 367 } 368 369 dev->shade.DarkOffset.Colors.Red += 370 (u_short)((dwR > bHi[0]) ? dwR - bHi[0] : 0); 371 dev->shade.DarkOffset.Colors.Green += 372 (u_short)((dwG > bHi[1]) ? dwG - bHi[1] : 0); 373 dev->shade.DarkOffset.Colors.Blue += 374 (u_short)((dwB > bHi[2]) ? dwB - bHi[2] : 0); 375 376 if( dev->DACType != _DA_ESIC && dev->CCDID != _CCD_3799 ) { 377 dev->shade.DarkOffset.Colors.Red = 378 (u_short)(dev->shade.DarkOffset.Colors.Red * 379 dev->shade.pCcdDac->GainResize.Colors.Red / 100UL); 380 dev->shade.DarkOffset.Colors.Green = 381 (u_short)(dev->shade.DarkOffset.Colors.Green * 382 dev->shade.pCcdDac->GainResize.Colors.Green / 100UL); 383 dev->shade.DarkOffset.Colors.Blue = 384 (u_short)(dev->shade.DarkOffset.Colors.Blue * 385 dev->shade.pCcdDac->GainResize.Colors.Blue / 100UL); 386 } 387 } 388 389 /* AdjustDark () */ 390 dev->regs.RD_Origin = _SHADING_BEGINX; 391 dev->regs.RD_Pixels = 5400; 392} 393 394/** perform some adjustments according to the source (normal, transparency etc) 395 */ 396static void u12tpa_FindCenterPointer( U12_Device *dev ) 397{ 398 u_long i; 399 u_long width; 400 u_long left; 401 u_long right; 402 RGBUShortDef *pwSum = dev->bufs.b2.pSumRGB; 403 404 if( dev->DataInf.dwScanFlag & _SCANDEF_Negative ) 405 width = _NEG_PAGEWIDTH600; 406 else 407 width = _NEG_PAGEWIDTH600 - 94; 408 409 /* 2.54 cm tolerance */ 410 left = _DATA_ORIGIN_X + _NEG_ORG_OFFSETX * 2 - 600; 411 right = _DATA_ORIGIN_X + _NEG_ORG_OFFSETX * 2 + 412 _NEG_PAGEWIDTH600 + 600; 413 414 for( i = 5400UL - left, pwSum = dev->bufs.b2.pSumRGB; i--; left++) 415 if( pwSum[left].Red > _NEG_EDGE_VALUE && 416 pwSum[left].Green > _NEG_EDGE_VALUE && 417 pwSum[left].Blue > _NEG_EDGE_VALUE) 418 break; 419 420 for( i = 5400UL - left, pwSum = dev->bufs.b2.pSumRGB; i--; right--) 421 if( pwSum[right].Red > _NEG_EDGE_VALUE && 422 pwSum[right].Green > _NEG_EDGE_VALUE && 423 pwSum[right].Blue > _NEG_EDGE_VALUE) 424 break; 425 426 if((right <= left) || ((right - left) < width)) { 427 if( dev->DataInf.dwScanFlag & _SCANDEF_Negative ) 428 dev->scan.negBegin = _DATA_ORIGIN_X + _NEG_ORG_OFFSETX * 2; 429 else 430 dev->scan.posBegin = _DATA_ORIGIN_X + _POS_ORG_OFFSETX * 2; 431 } else { 432 if( dev->DataInf.dwScanFlag & _SCANDEF_Negative ) 433 dev->scan.negBegin = (right + left) / 2UL - _NEG_PAGEWIDTH; 434 else 435 dev->scan.posBegin = (right + left) / 2UL - _POS_PAGEWIDTH; 436 } 437} 438 439/* END U12_TPA.C ............................................................*/ 440