• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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