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 */
u12tpa_Reshading(U12_Device * dev)53 static 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 */
u12tpa_FindCenterPointer(U12_Device * dev)396 static 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