1 /* sane - Scanner Access Now Easy.
2
3 Copyright (C) 2005 Mustek.
4 Originally maintained by Mustek
5 Author:Jack Roy 2005.5.24
6
7 This file is part of the SANE package.
8
9 This program is free software; you can redistribute it and/or
10 modify it under the terms of the GNU General Public License as
11 published by the Free Software Foundation; either version 2 of the
12 License, or (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <https://www.gnu.org/licenses/>.
21
22 As a special exception, the authors of SANE give permission for
23 additional uses of the libraries contained in this release of SANE.
24
25 The exception is that, if you link a SANE library with other files
26 to produce an executable, this does not by itself cause the
27 resulting executable to be covered by the GNU General Public
28 License. Your use of that executable is in no way restricted on
29 account of linking the SANE library code into it.
30
31 This exception does not, however, invalidate any other reasons why
32 the executable file might be covered by the GNU General Public
33 License.
34
35 If you submit changes to SANE to the maintainers to be included in
36 a subsequent release, you agree by submitting the changes that
37 those changes may be distributed with this exception intact.
38
39 If you write modifications of your own for SANE, it is your choice
40 whether to permit this exception to apply to your modifications.
41 If you do not wish that, delete this exception notice.
42
43 This file implements a SANE backend for the Mustek BearPaw 2448 TA Pro
44 and similar USB2 scanners. */
45
46
47 /* forward declarations */
48 static SANE_Bool Transparent_Reset (void);
49 static SANE_Bool Transparent_ScanSuggest (PTARGETIMAGE pTarget, PSUGGESTSETTING pSuggest);
50 static SANE_Bool Transparent_SetupScan (COLORMODE ColorMode, unsigned short XDpi, unsigned short YDpi,
51 SANE_Bool isInvert, unsigned short X, unsigned short Y, unsigned short Width,
52 unsigned short Height);
53 static SANE_Bool Transparent_StopScan (void);
54 static SANE_Bool Transparent_GetRows (SANE_Byte * lpBlock, unsigned short * Rows, SANE_Bool isOrderInvert);
55 static SANE_Bool Transparent_AdjustAD (void);
56 static SANE_Bool Transparent_FindTopLeft (unsigned short * lpwStartX, unsigned short * lpwStartY);
57 static SANE_Bool Transparent_LineCalibration16Bits (unsigned short wTAShadingMinus);
58 static SANE_Bool Transparent_PrepareScan (void);
59
60
61 /*function description*/
62
63 /**********************************************************************
64 Author: Jack Date: 2005/05/13
65 Routine Description:
66 reset the scanner
67 Parameters:
68 none
69 Return value:
70 if operation is success
71 return TRUE
72 else
73 return FALSE
74 ***********************************************************************/
75 static SANE_Bool
Transparent_Reset()76 Transparent_Reset ()
77 {
78 DBG (DBG_FUNC, "Transparent_Reset: call in\n");
79
80 if (g_bOpened)
81 {
82 DBG (DBG_FUNC, "Transparent_Reset: scanner has been opened\n");
83 return FALSE;
84 }
85 if (SANE_STATUS_GOOD != Asic_Open (&g_chip, g_pDeviceFile))
86 {
87 DBG (DBG_FUNC, "Transparent_Reset: can not open scanner\n");
88 return FALSE;
89 }
90
91 if (SANE_STATUS_GOOD != Asic_Reset (&g_chip))
92 {
93 DBG (DBG_FUNC, "Reflective_Reset: Asic_Reset return error\n");
94 return FALSE;
95 }
96
97 if (SANE_STATUS_GOOD != Asic_SetSource (&g_chip, LS_POSITIVE))
98 {
99 DBG (DBG_FUNC, "Reflective_Reset: Asic_SetSource return error\n");
100 return FALSE;
101 }
102
103 if (SANE_STATUS_GOOD != Asic_TurnLamp (&g_chip, FALSE))
104 {
105 DBG (DBG_FUNC, "Reflective_Reset: Asic_TurnLamp return error\n");
106 return FALSE;
107 }
108
109 if (SANE_STATUS_GOOD != Asic_TurnTA (&g_chip, TRUE))
110 {
111 DBG (DBG_FUNC, "Reflective_Reset: Asic_TurnTA return error\n");
112 return FALSE;
113 }
114
115 if (SANE_STATUS_GOOD != Asic_Close (&g_chip))
116 {
117 DBG (DBG_FUNC, "Reflective_Reset: Asic_Close return error\n");
118 return FALSE;
119 }
120
121 g_Y = 0;
122 g_wLineartThreshold = 128;
123 g_dwTotalTotalXferLines = 0;
124 g_bFirstReadImage = TRUE;
125 g_pGammaTable = NULL;
126
127 DBG (DBG_FUNC, "Transparent_Reset: leave Transparent_Reset\n");
128 return TRUE;
129 }
130
131 /**********************************************************************
132 Author: Jack Date: 2005/05/13
133 Routine Description:
134 get suggest parameter of scanning
135 Parameters:
136 pTarget: the information of scanning
137 pSuggest: the suggest parameter of scanning
138 Return value:
139 if operation is success
140 return TRUE
141 else
142 return FALSE
143 ***********************************************************************/
144 static SANE_Bool
Transparent_ScanSuggest(PTARGETIMAGE pTarget,PSUGGESTSETTING pSuggest)145 Transparent_ScanSuggest (PTARGETIMAGE pTarget, PSUGGESTSETTING pSuggest)
146 {
147 unsigned short wMaxWidth, wMaxHeight;
148 int i;
149
150 DBG (DBG_FUNC, "Transparent_ScanSuggest: call in\n");
151
152 for (i = 0; s_wOpticalYDpi[i] != 0; i++)
153 {
154 if (s_wOpticalYDpi[i] <= pTarget->wDpi)
155 {
156 pSuggest->wYDpi = s_wOpticalYDpi[i];
157 break;
158 }
159 }
160 if (s_wOpticalYDpi[i] == 0)
161 {
162 i--;
163 pSuggest->wYDpi = s_wOpticalYDpi[i];
164 }
165
166 for (i = 0; s_wOpticalXDpi[i] != 0; i++)
167 {
168 if (s_wOpticalXDpi[i] <= pTarget->wDpi)
169 {
170 pSuggest->wXDpi = s_wOpticalXDpi[i];
171 break;
172 }
173 }
174 if (s_wOpticalXDpi[i] == 0)
175 {
176 i--;
177 pSuggest->wXDpi = s_wOpticalXDpi[i];
178 }
179
180 pSuggest->wX =
181 (unsigned short) (((unsigned int) (pTarget->wX) * (unsigned int) (pSuggest->wXDpi)) /
182 (unsigned int) (pTarget->wDpi));
183 pSuggest->wY =
184 (unsigned short) (((unsigned int) (pTarget->wY) * (unsigned int) (pSuggest->wYDpi)) /
185 (unsigned int) (pTarget->wDpi));
186 pSuggest->wWidth =
187 (unsigned short) (((unsigned int) (pTarget->wWidth) * (unsigned int) (pSuggest->wXDpi)) /
188 (unsigned int) (pTarget->wDpi));
189 pSuggest->wHeight =
190 (unsigned short) (((unsigned int) (pTarget->wHeight) * (unsigned int) (pSuggest->wYDpi)) /
191 (unsigned int) (pTarget->wDpi));
192
193 pSuggest->wWidth = (pSuggest->wWidth / 2) * 2;
194
195 if (pTarget->cmColorMode == CM_TEXT)
196 {
197 pSuggest->wWidth = ((pSuggest->wWidth + 7) >> 3) << 3;
198 if (pSuggest->wWidth < 8)
199 pSuggest->wWidth = 8;
200 }
201
202 g_Width = ((pSuggest->wWidth + 15) >> 4) << 4; /* Real Scan Width */
203 g_Height = pSuggest->wHeight;
204
205 wMaxWidth = (MAX_SCANNING_WIDTH * pSuggest->wXDpi) / 300;
206 wMaxHeight = (MAX_SCANNING_HEIGHT * pSuggest->wYDpi) / 300;
207
208 if (pTarget->cmColorMode == CM_TEXT)
209 wMaxWidth = (wMaxWidth >> 3) << 3;
210
211 if (pSuggest->wWidth > wMaxWidth)
212 pSuggest->wWidth = wMaxWidth;
213 if (pSuggest->wHeight > wMaxHeight)
214 pSuggest->wHeight = wMaxHeight;
215
216 if (pTarget->isOptimalSpeed)
217 {
218 DBG (DBG_FUNC, "Transparent_ScanSuggest: isOptimalSpeed is true\n");
219
220 switch (pTarget->cmColorMode)
221 {
222 case CM_RGB48:
223 pSuggest->cmScanMode = CM_RGB48;
224 pSuggest->dwBytesPerRow = (unsigned int) ((pSuggest->wWidth) * 6);
225 break;
226 case CM_RGB24:
227 pSuggest->cmScanMode = CM_RGB24ext;
228 pSuggest->dwBytesPerRow = (unsigned int) ((pSuggest->wWidth) * 3);
229 break;
230
231 case CM_GRAY16:
232 pSuggest->cmScanMode = CM_GRAY16ext;
233 pSuggest->dwBytesPerRow = (unsigned int) ((pSuggest->wWidth) * 2);
234 break;
235 case CM_GRAY8:
236 pSuggest->cmScanMode = CM_GRAY8ext;
237 pSuggest->dwBytesPerRow = (unsigned int) ((pSuggest->wWidth));
238 break;
239 case CM_TEXT:
240 pSuggest->cmScanMode = CM_TEXT;
241 pSuggest->dwBytesPerRow = (unsigned int) (pSuggest->wWidth) / 8;
242 break;
243 default:
244 break;
245 }
246 }
247 else
248 {
249 DBG (DBG_FUNC, "Transparent_ScanSuggest: isOptimalSpeed not true\n");
250
251 switch (pTarget->cmColorMode)
252 {
253 case CM_RGB48:
254 pSuggest->cmScanMode = CM_RGB48;
255 pSuggest->dwBytesPerRow = (unsigned int) ((pSuggest->wWidth) * 6);
256 break;
257 case CM_RGB24:
258 pSuggest->cmScanMode = CM_RGB24ext;
259 pSuggest->dwBytesPerRow = (unsigned int) ((pSuggest->wWidth) * 3);
260 break;
261 case CM_GRAY16:
262 pSuggest->cmScanMode = CM_GRAY16ext;
263 pSuggest->dwBytesPerRow = (unsigned int) ((pSuggest->wWidth) * 2);
264 break;
265 case CM_GRAY8:
266 pSuggest->cmScanMode = CM_GRAY8ext;
267 pSuggest->dwBytesPerRow = (unsigned int) ((pSuggest->wWidth));
268 break;
269 case CM_TEXT:
270 pSuggest->cmScanMode = CM_TEXT;
271 pSuggest->dwBytesPerRow = (unsigned int) (pSuggest->wWidth) / 8;
272 break;
273 default:
274 break;
275 }
276 }
277
278 DBG (DBG_FUNC, "Transparent_ScanSuggest: leave Transparent_ScanSuggest\n");
279 return TRUE;
280 }
281
282 /**********************************************************************
283 Author: Jack Date: 2005/05/13
284 Routine Description:
285 setup scanning process
286 Parameters:
287 ColorMode: ScanMode of Scanning, CM_RGB48, CM_GRAY and so on
288 XDpi: X Resolution
289 YDpi: Y Resolution
290 isInvert: the RGB order
291 X: X start coordinate
292 Y: Y start coordinate
293 Width: Width of Scan Image
294 Height: Height of Scan Image
295 Return value:
296 if the operation is success
297 return TRUE
298 else
299 return FALSE
300 ***********************************************************************/
301 static SANE_Bool
Transparent_SetupScan(COLORMODE ColorMode,unsigned short XDpi,unsigned short YDpi,SANE_Bool isInvert,unsigned short X,unsigned short Y,unsigned short Width,unsigned short Height)302 Transparent_SetupScan (COLORMODE ColorMode, unsigned short XDpi, unsigned short YDpi,
303 SANE_Bool isInvert, unsigned short X, unsigned short Y, unsigned short Width, unsigned short Height)
304 {
305 SANE_Bool hasTA;
306 unsigned short wTAShadingMinus = 0;
307
308 (void) isInvert;
309 DBG (DBG_FUNC, "Transparent_SetupScan: call in\n");
310
311 if (g_bOpened)
312 {
313 DBG (DBG_FUNC, "Transparent_SetupScan: scanner has been opened\n");
314 return FALSE;
315 }
316
317 if (!g_bPrepared)
318 {
319 DBG (DBG_FUNC, "Transparent_SetupScan: scanner not prepared\n");
320 return FALSE;
321 }
322
323 g_ScanMode = ColorMode;
324 g_XDpi = XDpi;
325 g_YDpi = YDpi;
326 g_SWWidth = Width;
327 g_SWHeight = Height;
328
329 switch (g_YDpi)
330 {
331 case 1200:
332 g_wPixelDistance = 4;
333 g_wLineDistance = 24;
334 g_Height += g_wPixelDistance;
335 break;
336 case 600:
337 g_wPixelDistance = 0;
338 g_wLineDistance = 12;
339 g_Height += g_wPixelDistance;
340 break;
341 case 300:
342 g_wPixelDistance = 0;
343 g_wLineDistance = 6;
344 break;
345 case 150:
346 g_wPixelDistance = 0;
347 g_wLineDistance = 3;
348 break;
349 case 75:
350 case 50:
351 g_wPixelDistance = 0;
352 g_wLineDistance = 1;
353 break;
354 default:
355 g_wLineDistance = 0;
356
357 }
358
359 DBG (DBG_FUNC, "Transparent_SetupScan: g_YDpi=%d\n", g_YDpi);
360 DBG (DBG_FUNC, "Transparent_SetupScan: g_wLineDistance=%d\n",
361 g_wLineDistance);
362 DBG (DBG_FUNC, "Transparent_SetupScan: g_wPixelDistance=%d\n",
363 g_wPixelDistance);
364
365 switch (g_ScanMode)
366 {
367 case CM_RGB48:
368 g_BytesPerRow = 6 * g_Width; /* ASIC limit : width must be 8x */
369 g_SWBytesPerRow = 6 * g_SWWidth; /* ASIC limit : width must be 8x */
370 g_bScanBits = 48;
371 g_Height += g_wLineDistance * 2;
372 break;
373 case CM_RGB24ext:
374 g_BytesPerRow = 3 * g_Width; /*ASIC limit : width must be 8x */
375 g_SWBytesPerRow = 3 * g_SWWidth;
376 g_bScanBits = 24;
377 g_Height += g_wLineDistance * 2;
378 break;
379 case CM_GRAY16ext:
380 g_BytesPerRow = 2 * g_Width; /* ASIC limit : width must be 8x */
381 g_SWBytesPerRow = 2 * g_SWWidth;
382 g_bScanBits = 16;
383 break;
384 case CM_GRAY8ext:
385 case CM_TEXT:
386 g_BytesPerRow = g_Width; /*ASIC limit : width must be 8x */
387 g_SWBytesPerRow = g_SWWidth;
388 g_bScanBits = 8;
389 break;
390 default:
391 break;
392 }
393
394 if (Asic_Open (&g_chip, g_pDeviceFile) != SANE_STATUS_GOOD)
395 {
396 DBG (DBG_FUNC, "Transparent_SetupScan: Asic_Open return error\n");
397 return FALSE;
398 }
399
400 g_bOpened = TRUE;
401
402 if (SANE_STATUS_GOOD != Asic_TurnLamp (&g_chip, FALSE))
403 {
404 DBG (DBG_FUNC, "Transparent_SetupScan: Asic_TurnLamp return error\n");
405 return FALSE;
406 }
407
408 if (Asic_IsTAConnected (&g_chip, &hasTA) != SANE_STATUS_GOOD)
409 {
410 DBG (DBG_FUNC,
411 "Transparent_SetupScan: Asic_IsTAConnected return error\n");
412 return FALSE;
413 }
414 if (!hasTA)
415 {
416 DBG (DBG_FUNC, "Transparent_SetupScan: no TA device\n");
417 return FALSE;
418 }
419
420 if (Asic_TurnTA (&g_chip, TRUE) != SANE_STATUS_GOOD)
421 {
422 DBG (DBG_FUNC, "Transparent_SetupScan: Asic_TurnTA return error\n");
423 return FALSE;
424 }
425
426 /* Begin Find Left&Top Side */
427 Asic_MotorMove (&g_chip, TRUE, TRAN_START_POS);
428
429 if (1200 == g_XDpi)
430 {
431 wTAShadingMinus = 1680;
432 g_XDpi = 600;
433 Transparent_AdjustAD ();
434 Transparent_FindTopLeft (&g_X, &g_Y);
435
436 g_XDpi = 1200;
437 Transparent_AdjustAD ();
438 }
439 else
440 {
441 wTAShadingMinus = 840;
442 Transparent_AdjustAD ();
443 Transparent_FindTopLeft (&g_X, &g_Y);
444 }
445
446 DBG (DBG_FUNC,
447 "Transparent_SetupScan: after find top and left g_X=%d, g_Y=%d\n", g_X,
448 g_Y);
449
450 if (1200 == g_XDpi)
451 {
452 g_X =
453 g_X * 1200 / FIND_LEFT_TOP_CALIBRATE_RESOLUTION + X * 1200 / g_XDpi;
454 }
455 else
456 {
457 if (75 == g_XDpi)
458 {
459 g_X = g_X + X * 600 / g_XDpi - 23;
460 }
461 else
462 {
463 g_X = g_X + X * 600 / g_XDpi;
464 }
465 }
466
467 DBG (DBG_FUNC,
468 "Transparent_SetupScan: before line calibration,g_X=%d,g_Y=%d\n", g_X,
469 g_Y);
470
471 Transparent_LineCalibration16Bits (wTAShadingMinus);
472
473 DBG (DBG_FUNC,
474 "Transparent_SetupScan: after Reflective_LineCalibration16Bits,g_X=%d,g_Y=%d\n",
475 g_X, g_Y);
476
477 DBG (DBG_FUNC,
478 "Transparent_SetupScan: g_bScanBits=%d, g_XDpi=%d, g_YDpi=%d, g_X=%d, g_Y=%d, g_Width=%d, g_Height=%d\n",
479 g_bScanBits, g_XDpi, g_YDpi, g_X, g_Y, g_Width, g_Height);
480
481 g_Y = Y * 1200 / g_YDpi + (300 - 40) + 189;
482 Asic_MotorMove (&g_chip, TRUE, g_Y - 360);
483 g_Y = 360;
484
485 Asic_SetWindow (&g_chip, g_bScanBits, g_XDpi, g_YDpi, g_X, g_Y, g_Width,
486 g_Height);
487
488 DBG (DBG_FUNC, "Transparent_SetupScan: leave Transparent_SetupScan\n");
489 return Transparent_PrepareScan ();
490 }
491
492 /**********************************************************************
493 Author: Jack Date: 2005/05/14
494 Routine Description:
495 Stop scan
496 Parameters:
497 none
498 Return value:
499 if operation is success
500 return TRUE
501 else
502 return FALSE
503 ***********************************************************************/
504 static SANE_Bool
Transparent_StopScan()505 Transparent_StopScan ()
506 {
507 DBG (DBG_FUNC, "Transparent_StopScan: call in\n");
508
509 if (!g_bOpened)
510 {
511 return FALSE;
512 }
513 if (!g_bPrepared)
514 {
515 return FALSE;
516 }
517
518 g_isCanceled = TRUE;
519
520 pthread_cancel (g_threadid_readimage);
521 pthread_join (g_threadid_readimage, NULL);
522
523 DBG (DBG_FUNC, "Transparent_StopScan: thread exit\n");
524
525 Asic_ScanStop (&g_chip);
526 Asic_Close (&g_chip);
527 g_bOpened = FALSE;
528
529 DBG (DBG_FUNC, "Transparent_StopScan: leave Transparent_StopScan\n");
530 return TRUE;
531 }
532
533 /**********************************************************************
534 Author: Jack Date: 2005/05/15
535 Routine Description:
536 Get the data of image
537 Parameters:
538 lpBlock: the data of image
539 Rows: the rows of image
540 isOrderInvert: the RGB order
541 Return value:
542 if the operation is success
543 return TRUE
544 else
545 return FALSE
546 ***********************************************************************/
547 static SANE_Bool
Transparent_GetRows(SANE_Byte * lpBlock,unsigned short * Rows,SANE_Bool isOrderInvert)548 Transparent_GetRows (SANE_Byte * lpBlock, unsigned short * Rows, SANE_Bool isOrderInvert)
549 {
550 DBG (DBG_FUNC, "Transparent_GetRows: call in\n");
551
552 if (!g_bOpened)
553 {
554 return FALSE;
555 }
556 if (!g_bPrepared)
557 {
558 return FALSE;
559 }
560
561 switch (g_ScanMode)
562 {
563 case CM_RGB48:
564 if (g_XDpi == 1200)
565 return MustScanner_GetRgb48BitLine1200DPI (lpBlock, isOrderInvert,
566 Rows);
567 else
568 return MustScanner_GetRgb48BitLine (lpBlock, isOrderInvert, Rows);
569
570 case CM_RGB24ext:
571 if (g_XDpi == 1200)
572 return MustScanner_GetRgb24BitLine1200DPI (lpBlock, isOrderInvert,
573 Rows);
574 else
575 return MustScanner_GetRgb24BitLine (lpBlock, isOrderInvert, Rows);
576
577 case CM_GRAY16ext:
578 if (g_XDpi == 1200)
579 return MustScanner_GetMono16BitLine1200DPI (lpBlock, isOrderInvert,
580 Rows);
581 else
582 return MustScanner_GetMono16BitLine (lpBlock, isOrderInvert, Rows);
583
584 case CM_GRAY8ext:
585 if (g_XDpi == 1200)
586 return MustScanner_GetMono8BitLine1200DPI (lpBlock, isOrderInvert,
587 Rows);
588 else
589 return MustScanner_GetMono8BitLine (lpBlock, isOrderInvert, Rows);
590
591 case CM_TEXT:
592 if (g_XDpi == 1200)
593 return MustScanner_GetMono1BitLine1200DPI (lpBlock, isOrderInvert,
594 Rows);
595 else
596 return MustScanner_GetMono1BitLine (lpBlock, isOrderInvert, Rows);
597 default:
598 return FALSE;
599 }
600 return FALSE;
601 }
602
603 /**********************************************************************
604 Author: Jack Date: 2005/05/13
605 Routine Description:
606 To adjust the value of offset gain of R/G/B
607 Parameters:
608 none
609 Return value:
610 if operation is success
611 return TRUE
612 else
613 return FALSE
614 ***********************************************************************/
615 static SANE_Bool
Transparent_AdjustAD()616 Transparent_AdjustAD ()
617 {
618 SANE_Byte * lpCalData;
619 unsigned short wCalWidth;
620 int nTimesOfCal;
621 unsigned short wMaxValueR, wMinValueR, wMaxValueG, wMinValueG, wMaxValueB, wMinValueB;
622 #if 0
623 float fRFactor = 1.0;
624 float fGFactor = 1.0;
625 float fBFactor = 1.0;
626 SANE_Byte bDarkMaxLevel;
627 SANE_Byte bDarkMinLevel;
628 SANE_Byte bLastMinR, bLastROffset, bROffsetUpperBound = 255, bROffsetLowerBound =
629 0;
630 SANE_Byte bLastMinG, bLastGOffset, bGOffsetUpperBound = 255, bGOffsetLowerBound =
631 0;
632 SANE_Byte bLastMinB, bLastBOffset, bBOffsetUpperBound = 255, bBOffsetLowerBound =
633 0;
634 #endif
635 unsigned short wAdjustADResolution;
636
637 DBG (DBG_FUNC, "Transparent_AdjustAD: call in\n");
638 if (!g_bOpened)
639 {
640 return FALSE;
641 }
642 if (!g_bPrepared)
643 {
644 return FALSE;
645 }
646
647
648 g_chip.AD.DirectionR = R_DIRECTION;
649 g_chip.AD.DirectionG = G_DIRECTION;
650 g_chip.AD.DirectionB = B_DIRECTION;
651 g_chip.AD.GainR = R_GAIN;
652 g_chip.AD.GainG = G_GAIN;
653 g_chip.AD.GainB = B_GAIN;
654 g_chip.AD.OffsetR = 159;
655 g_chip.AD.OffsetG = 50;
656 g_chip.AD.OffsetB = 45;
657
658 if (g_XDpi <= 600)
659 {
660 wAdjustADResolution = 600;
661 }
662 else
663 {
664 wAdjustADResolution = 1200;
665 }
666
667 wCalWidth = 10240;
668
669 lpCalData = (SANE_Byte *) malloc (sizeof (SANE_Byte) * wCalWidth * 3);
670 if (lpCalData == NULL)
671 {
672 return FALSE;
673 }
674
675 Asic_SetMotorType (&g_chip, FALSE, TRUE);
676
677 Asic_SetCalibrate (&g_chip, 24, wAdjustADResolution, wAdjustADResolution, 0,
678 0, wCalWidth, 1, FALSE);
679 MustScanner_PrepareCalculateMaxMin (wAdjustADResolution);
680 nTimesOfCal = 0;
681
682 #ifdef DEBUG_SAVE_IMAGE
683 Asic_SetAFEGainOffset (&g_chip);
684 Asic_ScanStart (&g_chip);
685 Asic_ReadCalibrationData (&g_chip, lpCalData, wCalWidth * 3, 24);
686 Asic_ScanStop (&g_chip);
687
688 FILE *stream = NULL;
689 SANE_Byte * lpBuf = (SANE_Byte *) malloc (50);
690 if (NULL == lpBuf)
691 {
692 DBG (DBG_FUNC,
693 "Transparent_AdjustAD: Leave Transparent_AdjustAD for malloc fail!\n");
694 return FALSE;
695 }
696 memset (lpBuf, 0, 50);
697 stream = fopen ("/root/AD(Tra).pnm", "wb+\n");
698 sprintf (lpBuf, "P6\n%d %d\n255\n", wCalWidth, 3);
699 fwrite (lpBuf, sizeof (SANE_Byte), strlen (lpBuf), stream);
700 fwrite (lpCalData, sizeof (SANE_Byte), wCalWidth * 3, stream);
701 fclose (stream);
702 free (lpBuf);
703 #endif
704
705 do
706 {
707 DBG (DBG_FUNC,
708 "Transparent_AdjustAD: run in first adjust offset do-while\n");
709 Asic_SetAFEGainOffset (&g_chip);
710 Asic_ScanStart (&g_chip);
711 Asic_ReadCalibrationData (&g_chip, lpCalData, wCalWidth * 3, 24);
712 Asic_ScanStop (&g_chip);
713
714 MustScanner_CalculateMaxMin (lpCalData, &wMaxValueR, &wMinValueR,
715 wAdjustADResolution);
716 MustScanner_CalculateMaxMin (lpCalData + wCalWidth, &wMaxValueG,
717 &wMinValueG, wAdjustADResolution);
718 MustScanner_CalculateMaxMin (lpCalData + wCalWidth * 2, &wMaxValueB,
719 &wMinValueB, wAdjustADResolution);
720
721 if (g_chip.AD.DirectionR == 0)
722 {
723 if (wMinValueR > 15)
724 {
725 if (g_chip.AD.OffsetR < 8)
726 g_chip.AD.DirectionR = 1;
727 else
728 g_chip.AD.OffsetR -= 8;
729 }
730 else if (wMinValueR < 5)
731 g_chip.AD.OffsetR += 8;
732 }
733 else
734 {
735 if (wMinValueR > 15)
736 g_chip.AD.OffsetR += 8;
737 else if (wMinValueR < 5)
738 g_chip.AD.OffsetR -= 8;
739 }
740
741 if (g_chip.AD.DirectionG == 0)
742 {
743 if (wMinValueG > 15)
744 {
745 if (g_chip.AD.OffsetG < 8)
746 g_chip.AD.DirectionG = 1;
747
748 else
749 g_chip.AD.OffsetG -= 8;
750 }
751 else if (wMinValueG < 5)
752 g_chip.AD.OffsetG += 8;
753 }
754 else
755 {
756 if (wMinValueG > 15)
757 g_chip.AD.OffsetG += 8;
758 else if (wMinValueG < 5)
759 g_chip.AD.OffsetG -= 8;
760 }
761
762 if (g_chip.AD.DirectionB == 0)
763 {
764 if (wMinValueB > 15)
765 {
766 if (g_chip.AD.OffsetB < 8)
767 g_chip.AD.DirectionB = 1;
768 else
769 g_chip.AD.OffsetB -= 8;
770 }
771 else if (wMinValueB < 5)
772 g_chip.AD.OffsetB += 8;
773 }
774 else
775 {
776 if (wMinValueB > 15)
777 g_chip.AD.OffsetB += 8;
778 else if (wMinValueB < 5)
779 g_chip.AD.OffsetB -= 8;
780 }
781
782 nTimesOfCal++;
783 if (nTimesOfCal > 10)
784 break;
785 }
786 while (wMinValueR > 15 || wMinValueR < 5
787 || wMinValueG > 15 || wMinValueG < 5
788 || wMinValueB > 15 || wMinValueB < 5);
789
790 g_chip.AD.GainR = 1 - (double) (wMaxValueR - wMinValueR) / 210 > 0 ?
791 (SANE_Byte) (((1 -
792 (double) (wMaxValueR - wMinValueR) / 210)) * 63 * 6 / 5) : 0;
793 g_chip.AD.GainG =
794 1 - (double) (wMaxValueG - wMinValueG) / 210 >
795 0 ? (SANE_Byte) (((1 - (double) (wMaxValueG - wMinValueG) / 210)) * 63 * 6 /
796 5) : 0;
797 g_chip.AD.GainB =
798 1 - (double) (wMaxValueB - wMinValueB) / 210 >
799 0 ? (SANE_Byte) (((1 - (double) (wMaxValueB - wMinValueB) / 210)) * 63 * 6 /
800 5) : 0;
801
802 if (g_chip.AD.GainR > 63)
803 g_chip.AD.GainR = 63;
804 if (g_chip.AD.GainG > 63)
805 g_chip.AD.GainG = 63;
806 if (g_chip.AD.GainB > 63)
807 g_chip.AD.GainB = 63;
808
809
810
811 nTimesOfCal = 0;
812 do
813 {
814 Asic_SetAFEGainOffset (&g_chip);
815 Asic_ScanStart (&g_chip);
816 Asic_ReadCalibrationData (&g_chip, lpCalData, wCalWidth * 3, 24);
817 Asic_ScanStop (&g_chip);
818
819 MustScanner_CalculateMaxMin (lpCalData, &wMaxValueR, &wMinValueR,
820 wAdjustADResolution);
821 MustScanner_CalculateMaxMin (lpCalData + wCalWidth, &wMaxValueG,
822 &wMinValueG, wAdjustADResolution);
823 MustScanner_CalculateMaxMin (lpCalData + wCalWidth * 2, &wMaxValueB,
824 &wMinValueB, wAdjustADResolution);
825
826 DBG (DBG_FUNC, "Transparent_AdjustAD: "
827 "RGain=%d, ROffset=%d, RDir=%d GGain=%d, GOffset=%d, GDir=%d BGain=%d, BOffset=%d, BDir=%d\n",
828 g_chip.AD.GainR, g_chip.AD.OffsetR, g_chip.AD.DirectionR,
829 g_chip.AD.GainG, g_chip.AD.OffsetG, g_chip.AD.DirectionG,
830 g_chip.AD.GainB, g_chip.AD.OffsetB, g_chip.AD.DirectionB);
831
832 DBG (DBG_FUNC, "Transparent_AdjustAD: "
833 "MaxR=%d, MinR=%d MaxG=%d, MinG=%d MaxB=%d, MinB=%d\n",
834 wMaxValueR, wMinValueR, wMaxValueG, wMinValueG, wMaxValueB,
835 wMinValueB);
836
837 /*R Channel */
838 if ((wMaxValueR - wMinValueR) > TRAN_MAX_LEVEL_RANGE)
839 {
840 if (g_chip.AD.GainR > 0)
841 g_chip.AD.GainR--;
842 }
843 else
844 {
845 if ((wMaxValueR - wMinValueR) < TRAN_MIN_LEVEL_RANGE)
846 {
847 if (wMaxValueR < TRAN_WHITE_MIN_LEVEL)
848 {
849 g_chip.AD.GainR++;
850 if (g_chip.AD.GainR > 63)
851 g_chip.AD.GainR = 63;
852 }
853 else
854 {
855 if (wMaxValueR > TRAN_WHITE_MAX_LEVEL)
856 {
857 if (g_chip.AD.GainR < 1)
858 g_chip.AD.GainR = 0;
859 else
860 g_chip.AD.GainR--;
861 }
862 else
863 {
864 if (g_chip.AD.GainR > 63)
865 g_chip.AD.GainR = 63;
866 else
867 g_chip.AD.GainR++;
868 }
869 }
870 }
871 else
872 {
873 if (wMaxValueR > TRAN_WHITE_MAX_LEVEL)
874 {
875 if (g_chip.AD.GainR < 1)
876 g_chip.AD.GainR = 0;
877 else
878 g_chip.AD.GainR--;
879 }
880
881 if (wMaxValueR < TRAN_WHITE_MIN_LEVEL)
882 {
883 if (g_chip.AD.GainR > 63)
884 g_chip.AD.GainR = 63;
885 else
886 g_chip.AD.GainR++;
887
888 }
889 }
890 }
891
892 /*G Channel */
893 if ((wMaxValueG - wMinValueG) > TRAN_MAX_LEVEL_RANGE)
894 {
895 if (g_chip.AD.GainG > 0)
896 g_chip.AD.GainG--;
897 }
898 else
899 {
900 if ((wMaxValueG - wMinValueG) < TRAN_MIN_LEVEL_RANGE)
901 {
902 if (wMaxValueG < TRAN_WHITE_MIN_LEVEL)
903 {
904 g_chip.AD.GainG++;
905 if (g_chip.AD.GainG > 63)
906 g_chip.AD.GainG = 63;
907 }
908 else
909 {
910 if (wMaxValueG > TRAN_WHITE_MAX_LEVEL)
911 {
912 if (g_chip.AD.GainG < 1)
913 g_chip.AD.GainG = 0;
914 else
915 g_chip.AD.GainG--;
916 }
917 else
918 {
919 if (g_chip.AD.GainG > 63)
920 g_chip.AD.GainG = 63;
921 else
922 g_chip.AD.GainG++;
923 }
924 }
925 }
926 else
927 {
928 if (wMaxValueG > TRAN_WHITE_MAX_LEVEL)
929 {
930 if (g_chip.AD.GainG < 1)
931 g_chip.AD.GainG = 0;
932 else
933 g_chip.AD.GainG--;
934 }
935
936 if (wMaxValueG < TRAN_WHITE_MIN_LEVEL)
937 {
938 if (g_chip.AD.GainG > 63)
939 g_chip.AD.GainG = 63;
940 else
941 g_chip.AD.GainG++;
942 }
943 }
944 }
945
946 /* B Channel */
947 if ((wMaxValueB - wMinValueB) > TRAN_MAX_LEVEL_RANGE)
948 {
949 if (g_chip.AD.GainB > 0)
950 g_chip.AD.GainB--;
951 }
952 else
953 {
954 if ((wMaxValueB - wMinValueB) < TRAN_MIN_LEVEL_RANGE)
955 {
956 if (wMaxValueB < TRAN_WHITE_MIN_LEVEL)
957 {
958 g_chip.AD.GainB++;
959 if (g_chip.AD.GainB > 63)
960 g_chip.AD.GainB = 63;
961 }
962 else
963 {
964 if (wMaxValueB > TRAN_WHITE_MAX_LEVEL)
965 {
966 if (g_chip.AD.GainB < 1)
967 g_chip.AD.GainB = 0;
968 else
969 g_chip.AD.GainB--;
970 }
971 else
972 {
973 if (g_chip.AD.GainB > 63)
974 g_chip.AD.GainB = 63;
975 else
976 g_chip.AD.GainB++;
977 }
978 }
979 }
980 else
981 {
982 if (wMaxValueB > TRAN_WHITE_MAX_LEVEL)
983 {
984 if (g_chip.AD.GainB < 1)
985 g_chip.AD.GainB = 0;
986 else
987 g_chip.AD.GainB--;
988 }
989
990 if (wMaxValueB < TRAN_WHITE_MIN_LEVEL)
991 {
992 if (g_chip.AD.GainB > 63)
993 g_chip.AD.GainB = 63;
994 else
995 g_chip.AD.GainB++;
996 }
997 }
998 }
999
1000 nTimesOfCal++;
1001 if (nTimesOfCal > 10)
1002 break;
1003 }
1004 while ((wMaxValueR - wMinValueR) > TRAN_MAX_LEVEL_RANGE
1005 || (wMaxValueR - wMinValueR) < TRAN_MIN_LEVEL_RANGE
1006 || (wMaxValueG - wMinValueG) > TRAN_MAX_LEVEL_RANGE
1007 || (wMaxValueG - wMinValueG) < TRAN_MIN_LEVEL_RANGE
1008 || (wMaxValueB - wMinValueB) > TRAN_MAX_LEVEL_RANGE
1009 || (wMaxValueB - wMinValueB) < TRAN_MIN_LEVEL_RANGE);
1010
1011 /* Adjust Offset 2nd */
1012 nTimesOfCal = 0;
1013 do
1014 {
1015 Asic_SetAFEGainOffset (&g_chip);
1016 Asic_ScanStart (&g_chip);
1017 Asic_ReadCalibrationData (&g_chip, lpCalData, wCalWidth * 3, 24);
1018 Asic_ScanStop (&g_chip);
1019
1020 MustScanner_CalculateMaxMin (lpCalData, &wMaxValueR, &wMinValueR,
1021 wAdjustADResolution);
1022 MustScanner_CalculateMaxMin (lpCalData + wCalWidth, &wMaxValueG,
1023 &wMinValueG, wAdjustADResolution);
1024 MustScanner_CalculateMaxMin (lpCalData + wCalWidth * 2, &wMaxValueB,
1025 &wMinValueB, wAdjustADResolution);
1026 DBG (DBG_FUNC,
1027 "Transparent_AdjustAD: "
1028 "RGain=%d, ROffset=%d, RDir=%d GGain=%d, GOffset=%d, GDir=%d BGain=%d, BOffset=%d, BDir=%d\n",
1029 g_chip.AD.GainR, g_chip.AD.OffsetR, g_chip.AD.DirectionR,
1030 g_chip.AD.GainG, g_chip.AD.OffsetG, g_chip.AD.DirectionG,
1031 g_chip.AD.GainB, g_chip.AD.OffsetB, g_chip.AD.DirectionB);
1032
1033 DBG (DBG_FUNC, "Transparent_AdjustAD: "
1034 "MaxR=%d, MinR=%d MaxG=%d, MinG=%d MaxB=%d, MinB=%d\n",
1035 wMaxValueR, wMinValueR, wMaxValueG, wMinValueG, wMaxValueB,
1036 wMinValueB);
1037
1038 if (g_chip.AD.DirectionR == 0)
1039 {
1040 if (wMinValueR > 20)
1041 {
1042 if (g_chip.AD.OffsetR < 8)
1043 g_chip.AD.DirectionR = 1;
1044 else
1045 g_chip.AD.OffsetR -= 8;
1046 }
1047 else if (wMinValueR < 10)
1048 g_chip.AD.OffsetR += 8;
1049 }
1050 else
1051 {
1052 if (wMinValueR > 20)
1053 g_chip.AD.OffsetR += 8;
1054 else if (wMinValueR < 10)
1055 g_chip.AD.OffsetR -= 8;
1056 }
1057
1058 if (g_chip.AD.DirectionG == 0)
1059 {
1060 if (wMinValueG > 20)
1061 {
1062 if (g_chip.AD.OffsetG < 8)
1063 g_chip.AD.DirectionG = 1;
1064 else
1065 g_chip.AD.OffsetG -= 8;
1066 }
1067 else if (wMinValueG < 10)
1068 g_chip.AD.OffsetG += 8;
1069 }
1070 else
1071 {
1072 if (wMinValueG > 20)
1073 g_chip.AD.OffsetG += 8;
1074 else if (wMinValueG < 10)
1075 g_chip.AD.OffsetG -= 8;
1076 }
1077
1078 if (g_chip.AD.DirectionB == 0)
1079 {
1080 if (wMinValueB > 20)
1081 {
1082 if (g_chip.AD.OffsetB < 8)
1083 g_chip.AD.DirectionB = 1;
1084 else
1085 g_chip.AD.OffsetB -= 8;
1086 }
1087 else if (wMinValueB < 10)
1088 g_chip.AD.OffsetB += 8;
1089 }
1090 else
1091 {
1092 if (wMinValueB > 20)
1093 g_chip.AD.OffsetB += 8;
1094 else if (wMinValueB < 10)
1095 g_chip.AD.OffsetB -= 8;
1096 }
1097
1098 nTimesOfCal++;
1099 if (nTimesOfCal > 8)
1100 break;
1101
1102 }
1103 while (wMinValueR > 20 || wMinValueR < 10
1104 || wMinValueG > 20 || wMinValueG < 10
1105 || wMinValueB > 20 || wMinValueB < 10);
1106
1107 DBG (DBG_FUNC, "Transparent_AdjustAD: leave Transparent_AdjustAD\n");
1108 free (lpCalData);
1109
1110 return TRUE;
1111 }
1112
1113 /**********************************************************************
1114 Author: Jack Date: 2005/05/14
1115 Routine Description:
1116 Find top and left side
1117 Parameters:
1118 lpwStartX: the left side
1119 lpwStartY: the top side
1120 Return value:
1121 if operation is success
1122 return TRUE
1123 else
1124 return FALSE
1125 ***********************************************************************/
1126 static SANE_Bool
Transparent_FindTopLeft(unsigned short * lpwStartX,unsigned short * lpwStartY)1127 Transparent_FindTopLeft (unsigned short * lpwStartX, unsigned short * lpwStartY)
1128 {
1129 unsigned short wCalWidth = TA_FIND_LEFT_TOP_WIDTH_IN_DIP;
1130 unsigned short wCalHeight = TA_FIND_LEFT_TOP_HEIGHT_IN_DIP;
1131
1132 int i, j;
1133 unsigned short wLeftSide;
1134 unsigned short wTopSide;
1135 int nScanBlock;
1136 SANE_Byte * lpCalData;
1137 unsigned int dwTotalSize;
1138 unsigned short wXResolution, wYResolution;
1139
1140 DBG (DBG_FUNC, "Transparent_FindTopLeft: call in\n");
1141 if (!g_bOpened)
1142 {
1143 DBG (DBG_FUNC, "Transparent_FindTopLeft: scanner not opened\n");
1144
1145 return FALSE;
1146 }
1147 if (!g_bPrepared)
1148 {
1149 DBG (DBG_FUNC, "Transparent_FindTopLeft: scanner not prepared\n");
1150 return FALSE;
1151 }
1152
1153 wXResolution = wYResolution = FIND_LEFT_TOP_CALIBRATE_RESOLUTION;
1154
1155
1156 lpCalData = (SANE_Byte *) malloc (sizeof (SANE_Byte) * wCalWidth * wCalHeight);
1157 if (lpCalData == NULL)
1158 {
1159 DBG (DBG_FUNC, "Transparent_FindTopLeft: lpCalData malloc fail\n");
1160 return FALSE;
1161 }
1162
1163 dwTotalSize = wCalWidth * wCalHeight;
1164 nScanBlock = (int) (dwTotalSize / g_dwCalibrationSize);
1165
1166 Asic_SetMotorType (&g_chip, TRUE, TRUE);
1167 Asic_SetCalibrate (&g_chip, 8, wXResolution, wYResolution, 0, 0, wCalWidth,
1168 wCalHeight, FALSE);
1169 Asic_SetAFEGainOffset (&g_chip);
1170 Asic_ScanStart (&g_chip);
1171
1172 for (i = 0; i < nScanBlock; i++)
1173 Asic_ReadCalibrationData (&g_chip, lpCalData + i * g_dwCalibrationSize,
1174 g_dwCalibrationSize, 8);
1175
1176 Asic_ReadCalibrationData (&g_chip,
1177 lpCalData + (nScanBlock) * g_dwCalibrationSize,
1178 (dwTotalSize - g_dwCalibrationSize * nScanBlock),
1179 8);
1180 Asic_ScanStop (&g_chip);
1181
1182
1183 #ifdef DEBUG_SAVE_IMAGE
1184 FILE *stream = NULL;
1185 SANE_Byte * lpBuf = (SANE_Byte *) malloc (50);
1186 if (NULL == lpBuf)
1187 {
1188 return FALSE;
1189 }
1190 memset (lpBuf, 0, 50);
1191 stream = fopen ("/root/bound(Tra).pnm", "wb+\n");
1192 sprintf (lpBuf, "P5\n%d %d\n255\n", wCalWidth, wCalHeight);
1193 fwrite (lpBuf, sizeof (SANE_Byte), strlen (lpBuf), stream);
1194 fwrite (lpCalData, sizeof (SANE_Byte), wCalWidth * wCalHeight, stream);
1195 fclose (stream);
1196 free (lpBuf);
1197 #endif
1198
1199 wLeftSide = 0;
1200 wTopSide = 0;
1201
1202 /* Find Left Side */
1203 for (i = (wCalWidth - 1); i > 0; i--)
1204 {
1205 wLeftSide = *(lpCalData + i);
1206 wLeftSide += *(lpCalData + wCalWidth * 2 + i);
1207 wLeftSide += *(lpCalData + wCalWidth * 4 + i);
1208 wLeftSide += *(lpCalData + wCalWidth * 6 + i);
1209 wLeftSide += *(lpCalData + wCalWidth * 8 + i);
1210 wLeftSide /= 5;
1211 if (wLeftSide < 60)
1212 {
1213 if (i == (wCalWidth - 1))
1214 {
1215 break;
1216 }
1217 *lpwStartX = i;
1218 break;
1219 }
1220 }
1221
1222 /* Find Top Side i=left side */
1223 for (j = 0; j < wCalHeight; j++)
1224 {
1225 wTopSide = *(lpCalData + wCalWidth * j + i + 2);
1226 wTopSide += *(lpCalData + wCalWidth * j + i + 4);
1227 wTopSide += *(lpCalData + wCalWidth * j + i + 6);
1228 wTopSide += *(lpCalData + wCalWidth * j + i + 8);
1229 wTopSide += *(lpCalData + wCalWidth * j + i + 10);
1230 wTopSide /= 5;
1231 if (wTopSide < 60)
1232 {
1233 if (j == 0)
1234 {
1235 break;
1236 }
1237 *lpwStartY = j;
1238 break;
1239 }
1240 }
1241
1242 if ((*lpwStartX < 2200) || (*lpwStartX > 2300))
1243 {
1244 *lpwStartX = 2260;
1245 }
1246
1247 if ((*lpwStartY < 100) || (*lpwStartY > 200))
1248 {
1249 *lpwStartY = 124;
1250 }
1251
1252
1253 Asic_MotorMove (&g_chip, FALSE,
1254 (wCalHeight - *lpwStartY) * 1200 / wYResolution + 300);
1255
1256 free (lpCalData);
1257
1258 DBG (DBG_FUNC,
1259 "Transparent_FindTopLeft: *lpwStartY = %d, *lpwStartX = %d\n",
1260 *lpwStartY, *lpwStartX);
1261 DBG (DBG_FUNC, "Transparent_FindTopLeft: leave Transparent_FindTopLeft\n");
1262 return TRUE;
1263 }
1264
1265 /**********************************************************************
1266 Author: Jack Date: 2005/05/15
1267 Routine Description:
1268 Get the calibration data
1269 Parameters:
1270 none
1271 Return value:
1272 if the operation is success
1273 return TRUE
1274 else
1275 return FALSE
1276 ***********************************************************************/
1277 static SANE_Bool
Transparent_LineCalibration16Bits(unsigned short wTAShadingMinus)1278 Transparent_LineCalibration16Bits (unsigned short wTAShadingMinus)
1279 {
1280
1281 unsigned short *lpWhiteShading;
1282 unsigned short *lpDarkShading;
1283 double wRWhiteLevel = 0;
1284 double wGWhiteLevel = 0;
1285 double wBWhiteLevel = 0;
1286 unsigned int dwRDarkLevel = 0;
1287 unsigned int dwGDarkLevel = 0;
1288 unsigned int dwBDarkLevel = 0;
1289 unsigned int dwREvenDarkLevel = 0;
1290 unsigned int dwGEvenDarkLevel = 0;
1291 unsigned int dwBEvenDarkLevel = 0;
1292 unsigned short * lpRWhiteSort;
1293 unsigned short * lpGWhiteSort;
1294 unsigned short * lpBWhiteSort;
1295 unsigned short * lpRDarkSort;
1296 unsigned short * lpGDarkSort;
1297 unsigned short * lpBDarkSort;
1298 int i, j;
1299
1300 SANE_Byte * lpWhiteData;
1301 SANE_Byte * lpDarkData;
1302 unsigned int dwWhiteTotalSize;
1303 unsigned int dwDarkTotalSize;
1304 unsigned short wCalHeight = LINE_CALIBRATION__16BITS_HEIGHT;
1305 unsigned short wCalWidth = g_Width;
1306
1307 DBG (DBG_FUNC, "Transparent_LineCalibration16Bits: call in\n");
1308 if (!g_bOpened)
1309 {
1310 DBG (DBG_FUNC,
1311 "Transparent_LineCalibration16Bits: scanner not opened\n");
1312 return FALSE;
1313 }
1314 if (!g_bPrepared)
1315 {
1316 DBG (DBG_FUNC,
1317 "Transparent_LineCalibration16Bits: scanner not prepared\n");
1318 return FALSE;
1319 }
1320
1321 if (g_XDpi < 600)
1322 {
1323 wTAShadingMinus = wTAShadingMinus * g_XDpi / 600;
1324 }
1325
1326 dwWhiteTotalSize = wCalWidth * wCalHeight * 3 * 2;
1327 dwDarkTotalSize = wCalWidth * wCalHeight * 3 * 2;
1328 lpWhiteData = (SANE_Byte *) malloc (sizeof (SANE_Byte) * dwWhiteTotalSize);
1329 lpDarkData = (SANE_Byte *) malloc (sizeof (SANE_Byte) * dwDarkTotalSize);
1330 if (lpWhiteData == NULL || lpDarkData == NULL)
1331 {
1332 DBG (DBG_FUNC,
1333 "Transparent_LineCalibration16Bits: lpWhiteData or lpDarkData malloc fail\n");
1334 return FALSE;
1335 }
1336
1337 /*Read white level data */
1338 Asic_SetMotorType (&g_chip, TRUE, TRUE);
1339 Asic_SetAFEGainOffset (&g_chip);
1340 Asic_SetCalibrate (&g_chip, 48, g_XDpi, g_YDpi, g_X, 0, wCalWidth,
1341 wCalHeight, TRUE);
1342 Asic_ScanStart (&g_chip);
1343
1344 /* Read Data */
1345 Asic_ReadCalibrationData (&g_chip, lpWhiteData, dwWhiteTotalSize, 8);
1346 Asic_ScanStop (&g_chip);
1347
1348
1349 /* Read dark level data */
1350 Asic_SetMotorType (&g_chip, FALSE, TRUE);
1351 Asic_SetAFEGainOffset (&g_chip);
1352 Asic_SetCalibrate (&g_chip, 48, g_XDpi, g_YDpi, g_X, 0, wCalWidth,
1353 wCalHeight, TRUE);
1354
1355 Asic_TurnLamp (&g_chip, FALSE);
1356 Asic_TurnTA (&g_chip, FALSE);
1357
1358 usleep (500000);
1359
1360 Asic_ScanStart (&g_chip);
1361 Asic_ReadCalibrationData (&g_chip, lpDarkData, dwDarkTotalSize, 8);
1362
1363 Asic_ScanStop (&g_chip);
1364
1365 Asic_TurnTA (&g_chip, TRUE);
1366
1367 #ifdef DEBUG_SAVE_IMAGE
1368 FILE *stream = NULL;
1369 SANE_Byte * lpBuf = (SANE_Byte *) malloc (50);
1370 if (NULL == lpBuf)
1371 {
1372 return FALSE;
1373 }
1374 memset (lpBuf, 0, 50);
1375 stream = fopen ("/root/whiteshading(Tra).pnm", "wb+\n");
1376 sprintf (lpBuf, "P6\n%d %d\n65535\n", wCalWidth, wCalHeight);
1377 fwrite (lpBuf, sizeof (SANE_Byte), strlen (lpBuf), stream);
1378 fwrite (lpWhiteData, sizeof (SANE_Byte), wCalWidth * wCalHeight * 3 * 2, stream);
1379 fclose (stream);
1380
1381 memset (lpBuf, 0, 50);
1382 stream = fopen ("/root/darkshading(Tra).pnm", "wb+\n");
1383 sprintf (lpBuf, "P6\n%d %d\n65535\n", wCalWidth, wCalHeight);
1384 fwrite (lpBuf, sizeof (SANE_Byte), strlen (lpBuf), stream);
1385 fwrite (lpDarkData, sizeof (SANE_Byte), wCalWidth * wCalHeight * 3 * 2, stream);
1386 fclose (stream);
1387 free (lpBuf);
1388 #endif
1389
1390 lpWhiteShading = (unsigned short *) malloc (sizeof (unsigned short) * wCalWidth * 3);
1391 lpDarkShading = (unsigned short *) malloc (sizeof (unsigned short) * wCalWidth * 3);
1392
1393 lpRWhiteSort = (unsigned short *) malloc (sizeof (unsigned short) * wCalHeight);
1394 lpGWhiteSort = (unsigned short *) malloc (sizeof (unsigned short) * wCalHeight);
1395 lpBWhiteSort = (unsigned short *) malloc (sizeof (unsigned short) * wCalHeight);
1396 lpRDarkSort = (unsigned short *) malloc (sizeof (unsigned short) * wCalHeight);
1397 lpGDarkSort = (unsigned short *) malloc (sizeof (unsigned short) * wCalHeight);
1398 lpBDarkSort = (unsigned short *) malloc (sizeof (unsigned short) * wCalHeight);
1399
1400 if (lpWhiteShading == NULL || lpDarkShading == NULL
1401 || lpRWhiteSort == NULL || lpGWhiteSort == NULL || lpBWhiteSort == NULL
1402 || lpRDarkSort == NULL || lpGDarkSort == NULL || lpBDarkSort == NULL)
1403 {
1404 DBG (DBG_FUNC, "Transparent_LineCalibration16Bits: malloc fail\n");
1405
1406 free (lpWhiteData);
1407 free (lpDarkData);
1408 return FALSE;
1409 }
1410
1411 DBG (DBG_FUNC,
1412 "Transparent_LineCalibration16Bits: wCalWidth = %d, wCalHeight = %d\n",
1413 wCalWidth, wCalHeight);
1414
1415 /* create dark level shading */
1416 dwRDarkLevel = 0;
1417 dwGDarkLevel = 0;
1418 dwBDarkLevel = 0;
1419 dwREvenDarkLevel = 0;
1420 dwGEvenDarkLevel = 0;
1421 dwBEvenDarkLevel = 0;
1422
1423 for (i = 0; i < wCalWidth; i++)
1424
1425 {
1426 for (j = 0; j < wCalHeight; j++)
1427 {
1428 lpRDarkSort[j] =
1429 (unsigned short) (*(lpDarkData + j * wCalWidth * 6 + i * 6 + 0));
1430 lpRDarkSort[j] +=
1431 (unsigned short) (*(lpDarkData + j * wCalWidth * 6 + i * 6 + 1) << 8);
1432
1433 lpGDarkSort[j] =
1434 (unsigned short) (*(lpDarkData + j * wCalWidth * 6 + i * 6 + 2));
1435 lpGDarkSort[j] +=
1436 (unsigned short) (*(lpDarkData + j * wCalWidth * 6 + i * 6 + 3) << 8);
1437
1438 lpBDarkSort[j] =
1439 (unsigned short) (*(lpDarkData + j * wCalWidth * 6 + i * 6 + 4));
1440 lpBDarkSort[j] +=
1441 (unsigned short) (*(lpDarkData + j * wCalWidth * 6 + i * 6 + 5) << 8);
1442 }
1443
1444 /* sum of dark level for all pixels */
1445 if (g_XDpi == 1200)
1446 {
1447 /* do dark shading table with mean */
1448 if (i % 2)
1449 {
1450 dwRDarkLevel +=
1451 (unsigned int) MustScanner_FiltLower (lpRDarkSort, wCalHeight, 20,
1452 30);
1453 dwGDarkLevel +=
1454 (unsigned int) MustScanner_FiltLower (lpGDarkSort, wCalHeight, 20,
1455 30);
1456 dwBDarkLevel +=
1457 (unsigned int) MustScanner_FiltLower (lpBDarkSort, wCalHeight, 20,
1458 30);
1459 }
1460 else
1461 {
1462 dwREvenDarkLevel +=
1463 (unsigned int) MustScanner_FiltLower (lpRDarkSort, wCalHeight, 20,
1464 30);
1465 dwGEvenDarkLevel +=
1466 (unsigned int) MustScanner_FiltLower (lpGDarkSort, wCalHeight, 20,
1467 30);
1468 dwBEvenDarkLevel +=
1469 (unsigned int) MustScanner_FiltLower (lpBDarkSort, wCalHeight, 20,
1470 30);
1471 }
1472 }
1473 else
1474 {
1475 dwRDarkLevel +=
1476 (unsigned int) MustScanner_FiltLower (lpRDarkSort, wCalHeight, 20, 30);
1477 dwGDarkLevel +=
1478 (unsigned int) MustScanner_FiltLower (lpGDarkSort, wCalHeight, 20, 30);
1479 dwBDarkLevel +=
1480 (unsigned int) MustScanner_FiltLower (lpBDarkSort, wCalHeight, 20, 30);
1481 }
1482 }
1483
1484 if (g_XDpi == 1200)
1485 {
1486 dwRDarkLevel = (unsigned int) (dwRDarkLevel / (wCalWidth / 2)) - 512;
1487 dwGDarkLevel = (unsigned int) (dwGDarkLevel / (wCalWidth / 2)) - 512;
1488 dwBDarkLevel = (unsigned int) (dwBDarkLevel / (wCalWidth / 2)) - 512;
1489
1490 dwREvenDarkLevel = (unsigned int) (dwREvenDarkLevel / (wCalWidth / 2)) - 512;
1491 dwGEvenDarkLevel = (unsigned int) (dwGEvenDarkLevel / (wCalWidth / 2)) - 512;
1492 dwBEvenDarkLevel = (unsigned int) (dwBEvenDarkLevel / (wCalWidth / 2)) - 512;
1493 }
1494 else
1495 {
1496 dwRDarkLevel = (unsigned int) (dwRDarkLevel / wCalWidth) - 512;
1497 dwGDarkLevel = (unsigned int) (dwGDarkLevel / wCalWidth) - 512;
1498 dwBDarkLevel = (unsigned int) (dwBDarkLevel / wCalWidth) - 512;
1499 }
1500
1501 /* Create white shading */
1502 for (i = 0; i < wCalWidth; i++)
1503 {
1504 wRWhiteLevel = 0;
1505 wGWhiteLevel = 0;
1506 wBWhiteLevel = 0;
1507
1508 for (j = 0; j < wCalHeight; j++)
1509 {
1510 lpRWhiteSort[j] =
1511 (unsigned short) (*(lpWhiteData + j * wCalWidth * 2 * 3 + i * 6 + 0));
1512 lpRWhiteSort[j] +=
1513 (unsigned short) (*(lpWhiteData + j * wCalWidth * 2 * 3 + i * 6 + 1) << 8);
1514
1515 lpGWhiteSort[j] =
1516 (unsigned short) (*(lpWhiteData + j * wCalWidth * 2 * 3 + i * 6 + 2));
1517 lpGWhiteSort[j] +=
1518 (unsigned short) (*(lpWhiteData + j * wCalWidth * 2 * 3 + i * 6 + 3) << 8);
1519
1520 lpBWhiteSort[j] =
1521 (unsigned short) (*(lpWhiteData + j * wCalWidth * 2 * 3 + i * 6 + 4));
1522 lpBWhiteSort[j] +=
1523 (unsigned short) (*(lpWhiteData + j * wCalWidth * 2 * 3 + i * 6 + 5) << 8);
1524 }
1525
1526 if (1200 == g_XDpi)
1527 {
1528 if (i % 2)
1529 {
1530 if (SS_Negative == g_ssScanSource)
1531 {
1532 *(lpDarkShading + i * 3 + 0) = (unsigned short) dwRDarkLevel;
1533 *(lpDarkShading + i * 3 + 1) = (unsigned short) dwGDarkLevel;
1534 *(lpDarkShading + i * 3 + 2) = (unsigned short) dwBDarkLevel;
1535 }
1536 else
1537 {
1538 *(lpDarkShading + i * 3 + 0) = (unsigned short) dwRDarkLevel;
1539 *(lpDarkShading + i * 3 + 1) = (unsigned short) (dwGDarkLevel * 0.78);
1540 *(lpDarkShading + i * 3 + 2) = (unsigned short) dwBDarkLevel;
1541 }
1542 }
1543 else
1544 {
1545 if (SS_Negative == g_ssScanSource)
1546 {
1547 *(lpDarkShading + i * 3 + 0) = (unsigned short) dwREvenDarkLevel;
1548 *(lpDarkShading + i * 3 + 1) = (unsigned short) dwGEvenDarkLevel;
1549 *(lpDarkShading + i * 3 + 2) = (unsigned short) dwBEvenDarkLevel;
1550 }
1551 else
1552 {
1553 *(lpDarkShading + i * 3 + 0) = (unsigned short) dwREvenDarkLevel;
1554 *(lpDarkShading + i * 3 + 1) =
1555 (unsigned short) (dwGEvenDarkLevel * 0.78);
1556 *(lpDarkShading + i * 3 + 2) = (unsigned short) dwBEvenDarkLevel;
1557 }
1558 }
1559 }
1560 else
1561 {
1562 if (SS_Negative == g_ssScanSource)
1563 {
1564 *(lpDarkShading + i * 3 + 0) = (unsigned short) dwRDarkLevel;
1565 *(lpDarkShading + i * 3 + 1) = (unsigned short) dwRDarkLevel;
1566 *(lpDarkShading + i * 3 + 2) = (unsigned short) dwRDarkLevel;
1567 }
1568 else
1569 {
1570 *(lpDarkShading + i * 3 + 0) = (unsigned short) dwRDarkLevel;
1571 *(lpDarkShading + i * 3 + 1) = (unsigned short) (dwRDarkLevel * 0.78);
1572 *(lpDarkShading + i * 3 + 2) = (unsigned short) dwRDarkLevel;
1573 }
1574 }
1575
1576 /* Create white shading */
1577 wRWhiteLevel =
1578 (double) (MustScanner_FiltLower (lpRWhiteSort, wCalHeight, 20, 30) -
1579 *(lpDarkShading + i * 3 + 0));
1580 wGWhiteLevel =
1581 (double) (MustScanner_FiltLower (lpGWhiteSort, wCalHeight, 20, 30) -
1582 *(lpDarkShading + i * 3 + 1));
1583 wBWhiteLevel =
1584 (double) (MustScanner_FiltLower (lpBWhiteSort, wCalHeight, 20, 30) -
1585 *(lpDarkShading + i * 3 + 2));
1586
1587 if (g_ssScanSource == SS_Negative)
1588 {
1589 if (wRWhiteLevel > 0)
1590 *(lpWhiteShading + i * 3 + 0) =
1591 (unsigned short) ((float) 65536 / wRWhiteLevel * 0x1000);
1592 else
1593 *(lpWhiteShading + i * 3 + 0) = 0x1000;
1594
1595 if (wGWhiteLevel > 0)
1596 *(lpWhiteShading + i * 3 + 1) =
1597 (unsigned short) ((float) (65536 * 1.5) / wGWhiteLevel * 0x1000);
1598 else
1599 *(lpWhiteShading + i * 3 + 1) = 0x1000;
1600
1601 if (wBWhiteLevel > 0)
1602 *(lpWhiteShading + i * 3 + 2) =
1603 (unsigned short) ((float) (65536 * 2.0) / wBWhiteLevel * 0x1000);
1604 else
1605 *(lpWhiteShading + i * 3 + 2) = 0x1000;
1606 }
1607 else
1608 {
1609 if (wRWhiteLevel > 0)
1610 *(lpWhiteShading + i * 3 + 0) =
1611 (unsigned short) ((float) 65536 / wRWhiteLevel * 0x1000);
1612 else
1613 *(lpWhiteShading + i * 3 + 0) = 0x1000;
1614
1615 if (wGWhiteLevel > 0)
1616 *(lpWhiteShading + i * 3 + 1) =
1617 (unsigned short) ((float) (65536 * 1.04) / wGWhiteLevel * 0x1000);
1618 else
1619 *(lpWhiteShading + i * 3 + 1) = 0x1000;
1620
1621 if (wBWhiteLevel > 0)
1622 *(lpWhiteShading + i * 3 + 2) =
1623 (unsigned short) ((float) 65536 / wBWhiteLevel * 0x1000);
1624 else
1625 *(lpWhiteShading + i * 3 + 2) = 0x1000;
1626 }
1627 }
1628
1629 free (lpWhiteData);
1630 free (lpDarkData);
1631 free (lpRWhiteSort);
1632 free (lpGWhiteSort);
1633 free (lpBWhiteSort);
1634 free (lpRDarkSort);
1635 free (lpGDarkSort);
1636 free (lpBDarkSort);
1637
1638 Asic_SetShadingTable (&g_chip, lpWhiteShading, lpDarkShading, g_XDpi,
1639 wCalWidth, 0);
1640
1641 free (lpWhiteShading);
1642 free (lpDarkShading);
1643
1644 DBG (DBG_FUNC,
1645 "Transparent_LineCalibration16Bits: leave Transparent_LineCalibration16Bits\n");
1646 return TRUE;
1647 }
1648
1649 /**********************************************************************
1650 Author: Jack Date: 2005/05/14
1651 Routine Description:
1652 Prepare scan image
1653 Parameters:
1654 none
1655 Return value:
1656 if operation is success
1657 return TRUE
1658 else
1659 return FALSE
1660 ***********************************************************************/
1661 static SANE_Bool
Transparent_PrepareScan()1662 Transparent_PrepareScan ()
1663 {
1664 DBG (DBG_FUNC, "Transparent_PrepareScan: call in\n");
1665
1666 g_wScanLinesPerBlock = g_dwBufferSize / g_BytesPerRow;
1667 g_wMaxScanLines = g_dwImageBufferSize / g_BytesPerRow;
1668 g_wMaxScanLines =
1669 (g_wMaxScanLines / g_wScanLinesPerBlock) * g_wScanLinesPerBlock;
1670 g_isCanceled = FALSE;
1671
1672 g_dwScannedTotalLines = 0;
1673 g_wReadedLines = 0;
1674 g_wtheReadyLines = 0;
1675 g_wReadImageLines = 0;
1676
1677 g_wReadyShadingLine = 0;
1678 g_wStartShadingLinePos = 0;
1679
1680 switch (g_ScanMode)
1681 {
1682
1683 case CM_RGB48:
1684
1685 g_wtheReadyLines = g_wLineDistance * 2 + g_wPixelDistance;
1686
1687 g_lpReadImageHead = (SANE_Byte *) malloc (g_dwImageBufferSize);
1688 if (g_lpReadImageHead == NULL)
1689 {
1690 DBG (DBG_FUNC, "Transparent_PrepareScan:malloc fail\n");
1691 return FALSE;
1692 }
1693 break;
1694
1695 case CM_RGB24ext:
1696 g_wtheReadyLines = g_wLineDistance * 2 + g_wPixelDistance;
1697 g_lpReadImageHead = (SANE_Byte *) malloc (g_dwImageBufferSize);
1698
1699 if (g_lpReadImageHead == NULL)
1700 {
1701 DBG (DBG_FUNC, "Transparent_PrepareScan:malloc fail\n");
1702 return FALSE;
1703 }
1704 break;
1705
1706 case CM_GRAY16ext:
1707 g_wtheReadyLines = g_wPixelDistance;
1708 g_lpReadImageHead = (SANE_Byte *) malloc (g_dwImageBufferSize);
1709 if (g_lpReadImageHead == NULL)
1710 {
1711 DBG (DBG_FUNC, "Transparent_PrepareScan:malloc fail\n");
1712 return FALSE;
1713 }
1714 break;
1715
1716 case CM_GRAY8ext:
1717 g_wtheReadyLines = g_wPixelDistance;
1718 g_lpReadImageHead = (SANE_Byte *) malloc (g_dwImageBufferSize);
1719 if (g_lpReadImageHead == NULL)
1720 {
1721 DBG (DBG_FUNC, "Transparent_PrepareScan:malloc fail\n");
1722 return FALSE;
1723 }
1724 break;
1725
1726 case CM_TEXT:
1727 g_wtheReadyLines = g_wPixelDistance;
1728 g_lpReadImageHead = (SANE_Byte *) malloc (g_dwImageBufferSize);
1729 if (g_lpReadImageHead == NULL)
1730 {
1731 DBG (DBG_FUNC, "Transparent_PrepareScan:malloc fail\n");
1732 return FALSE;
1733 }
1734 break;
1735 default:
1736 return FALSE;
1737 }
1738
1739 Asic_ScanStart (&g_chip);
1740
1741 DBG (DBG_FUNC, "Transparent_PrepareScan: leave Transparent_PrepareScan\n");
1742 return TRUE;
1743 } /* end of the file ScannerTransparent.c */
1744