1 /* @file plustek-pp_map.c
2  * @brief functions to create and manipulate lookup tables.
3  *
4  * based on sources acquired from Plustek Inc.
5  * Copyright (C) 1998 Plustek Inc.
6  * Copyright (C) 2000-2004 Gerhard Jaeger <gerhard@gjaeger.de>
7  * also based on the work done by Rick Bronson
8  *
9  * History:
10  * - 0.30 - initial version
11  * - 0.31 - brightness and contrast is working (see mapAdjust)
12  * - 0.32 - no changes
13  * - 0.33 - disabled a few functions
14  * - 0.34 - added new dither matrix for checking
15  * - 0.35 - no changes
16  * - 0.36 - activated Dithermap 1
17  *        - removed some unused functions
18  *        - added additional SCANDEF_Inverse check to MapSetupDither()
19  *        - fixed the double inversion bug, the map always compensates
20  *        - the scanner hw-settings
21  * - 0.37 - code cleanup
22  * - 0.38 - added P12 stuff
23  * - 0.39 - no changes
24  * - 0.40 - no changes
25  * - 0.41 - no changes
26  * - 0.42 - made MapAdjust global
27  *        - changed include names
28  * - 0.43 - cleanup, removed floating point stuff
29  * .
30  * <hr>
31  * This file is part of the SANE package.
32  *
33  * This program is free software; you can redistribute it and/or
34  * modify it under the terms of the GNU General Public License as
35  * published by the Free Software Foundation; either version 2 of the
36  * License, or (at your option) any later version.
37  *
38  * This program is distributed in the hope that it will be useful, but
39  * WITHOUT ANY WARRANTY; without even the implied warranty of
40  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
41  * General Public License for more details.
42  *
43  * You should have received a copy of the GNU General Public License
44  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
45  *
46  * As a special exception, the authors of SANE give permission for
47  * additional uses of the libraries contained in this release of SANE.
48  *
49  * The exception is that, if you link a SANE library with other files
50  * to produce an executable, this does not by itself cause the
51  * resulting executable to be covered by the GNU General Public
52  * License.  Your use of that executable is in no way restricted on
53  * account of linking the SANE library code into it.
54  *
55  * This exception does not, however, invalidate any other reasons why
56  * the executable file might be covered by the GNU General Public
57  * License.
58  *
59  * If you submit changes to SANE to the maintainers to be included in
60  * a subsequent release, you agree by submitting the changes that
61  * those changes may be distributed with this exception intact.
62  *
63  * If you write modifications of your own for SANE, it is your choice
64  * whether to permit this exception to apply to your modifications.
65  * If you do not wish that, delete this exception notice.
66  * <hr>
67  */
68 #include "plustek-pp_scan.h"
69 
70 /*************************** local vars **************************************/
71 
72 /*WORK:
73  *    create other thresholds for the dither maps
74  */
75 static Byte mapDitherMatrix0[_DITHERSIZE] =
76 {
77      0, 32, 8,  40, 2,  34, 10, 42,
78     48, 16, 56, 24, 50, 18, 58, 26,
79     12, 44, 4,  36, 14, 46, 6,  38,
80     60, 28, 52, 20, 62, 30, 54, 22,
81      3, 35, 11, 43, 1,  33, 9,  41,
82     51, 19, 59, 27, 49, 17, 57, 25,
83     15, 47, 7,  39, 13, 45, 5,  37,
84 	63, 31, 55, 23, 61, 29, 53, 21
85 };
86 
87 static Byte mapDitherMatrix1[_DITHERSIZE] =
88 {
89      2, 60, 16, 56,  3, 57, 13, 53,
90     34, 18, 48, 32, 35, 19, 45, 29,
91     10, 50,  6, 63, 11, 51,  7, 61,
92     42, 26, 38, 22, 43, 27, 39, 23,
93      4, 58, 14, 54,  1, 59, 15, 55,
94     36, 20, 46, 30, 33, 17, 47, 31,
95     12, 52,  8, 62,  9, 49,  5, 63,
96     44, 28, 40, 24, 41, 25, 37, 21
97 };
98 
99 /*************************** local functions *********************************/
100 
101 /** set the selected dither maps...
102  */
mapSetDitherMap( pScanData ps )103 static void mapSetDitherMap( pScanData ps )
104 {
105 	ULong  i;
106 	pUChar pDitherSource;
107 	pUChar pDither = ps->a_bDitherPattern;
108 
109 	if( 0 == ps->DataInf.wDither ) {
110 		DBG( DBG_LOW, "Using Dithermatrix 0\n" );
111 		pDitherSource = mapDitherMatrix0;
112 	} else {
113 		DBG( DBG_LOW, "Using Dithermatrix 1\n" );
114 		pDitherSource = mapDitherMatrix1;
115 	}
116 
117 	for( i = 0; i < _DITHERSIZE; i++ ) {
118 		pDither[i] = pDitherSource[i];
119 	}
120 }
121 
122 /** nothing more to say
123  */
mapInvertMap( pScanData ps )124 static void mapInvertMap( pScanData ps )
125 {
126 	pULong pdw;
127     ULong  dw, size;
128 
129 	DBG( DBG_LOW, "mapInvertMap()\n" );
130 
131 	if( _IS_ASIC98(ps->sCaps.AsicID)) {
132 		size = 4096;
133 	} else {
134 		size = 256;
135     }
136 
137     for (pdw = (pULong)ps->a_bMapTable, dw = size * 3 / 4; dw; dw--, pdw++) {
138 		*pdw = ~(*pdw);
139 	}
140 }
141 
142 /** as the name says...
143  */
mapInvertDitherMap( pScanData ps )144 static void mapInvertDitherMap( pScanData ps )
145 {
146 	if( ps->DataInf.dwScanFlag & SCANDEF_Inverse ) {
147 
148 		ULong  dw;
149 		pULong pDither = (pULong)ps->a_bDitherPattern;
150 
151 		DBG( DBG_LOW, "mapInvertDitherMap()\n" );
152 
153 		mapInvertMap( ps );
154 		for (dw = 0; dw < 16; dw++) {
155 	    	pDither[dw] = ~pDither[dw];
156 		}
157     }
158 }
159 
160 /** build linear map...
161  */
mapBuildLinearMap( pScanData ps )162 static void mapBuildLinearMap( pScanData ps )
163 {
164 	ULong i;
165 
166 	DBG( DBG_LOW, "mapBuildLinearMap()\n" );
167 
168 	if( _IS_ASIC98(ps->sCaps.AsicID)) {
169 
170 		for( i = 0; i < 4096; i++ ) {
171 			ps->a_bMapTable[i] 	    = (UChar)(i >> 4);
172 			ps->a_bMapTable[4096+i] = (UChar)(i >> 4);
173 			ps->a_bMapTable[8192+i] = (UChar)(i >> 4);
174 		}
175 
176 	} else {
177 
178 		for( i = 0; i < 256; i++ ) {
179 			ps->a_bMapTable[i] 	   = (UChar)(i & 0xff);
180 			ps->a_bMapTable[256+i] = (UChar)(i & 0xff);
181 			ps->a_bMapTable[512+i] = (UChar)(i & 0xff);
182 		}
183 	}
184 }
185 
186 /************************ exported functions *********************************/
187 
188 /** create a mapping table
189  *  in the original code this map will be created by the TWAIN application
190  *  and the is being downloaded to the driver, as I don't have the code
191  *  we have to try to build up such a table here
192  */
MapInitialize( pScanData ps )193 _LOC void MapInitialize( pScanData ps )
194 {
195 	mapBuildLinearMap( ps );
196 	MapAdjust( ps, _MAP_MASTER );
197 }
198 
199 /** setup dither maps
200  */
MapSetupDither( pScanData ps )201 _LOC void MapSetupDither( pScanData ps )
202 {
203 	DBG( DBG_LOW, "MapSetupDither() - %u\n", ps->DataInf.wAppDataType );
204 
205 	if( COLOR_HALFTONE == ps->DataInf.wAppDataType ) {
206 
207 		mapSetDitherMap( ps );
208 	    if (ps->DataInf.dwScanFlag & SCANDEF_Inverse)
209 			mapInvertDitherMap( ps );
210 	}
211 }
212 
213 /** adjust according to brightness and contrast
214  */
MapAdjust( pScanData ps, int which )215 _LOC void MapAdjust( pScanData ps, int which )
216 {
217 	ULong  i, tabLen, dw;
218 	ULong *pdw;
219 	long   b, c, tmp;
220 
221 	DBG( DBG_LOW, "MapAdjust(%u)\n", which );
222 
223 	if( _IS_ASIC98(ps->sCaps.AsicID)) {
224 		tabLen = 4096;
225 	} else {
226 		tabLen = 256;
227 	}
228 
229 	/* adjust brightness (b) and contrast (c) using the function:
230 	 * s'(x,y) = (s(x,y) + b) * c
231 	 * b = [-127, 127]
232 	 * c = [0,2]
233 	 */
234 
235 	/* scale brightness and contrast...
236 	 */
237 	b = ps->wBrightness * 192;
238 	c = ps->wContrast   + 100;
239 
240 	DBG( DBG_LOW, "brightness   = %i -> %i\n", ps->wBrightness, (UChar)(b/100));
241 	DBG( DBG_LOW, "contrast*100 = %i -> %i\n", ps->wContrast, (int)(c));
242 
243 	for( i = 0; i < tabLen; i++ ) {
244 
245 		if((_MAP_MASTER == which) || (_MAP_RED == which)) {
246 			tmp = ((((long)ps->a_bMapTable[i] * 100) + b) *c ) / 10000;
247 			if( tmp < 0 )   tmp = 0;
248 			if( tmp > 255 ) tmp = 255;
249 			ps->a_bMapTable[i] = (UChar)tmp;
250 		}
251 
252 		if((_MAP_MASTER == which) || (_MAP_GREEN == which)) {
253 			tmp = ((((long)ps->a_bMapTable[tabLen+i] * 100) + b) * c) / 10000;
254 			if( tmp < 0 )   tmp = 0;
255 			if( tmp > 255 ) tmp = 255;
256 			ps->a_bMapTable[tabLen+i] = (UChar)tmp;
257     	}
258 
259 		if((_MAP_MASTER == which) || (_MAP_BLUE == which)) {
260 			tmp = ((((long)ps->a_bMapTable[tabLen*2+i] * 100) + b) * c) / 10000;
261 			if( tmp < 0 )   tmp = 0;
262 			if( tmp > 255 ) tmp = 255;
263 			ps->a_bMapTable[tabLen*2+i] = (UChar)tmp;
264 		}
265 	}
266 
267     if( ps->DataInf.dwScanFlag & SCANDEF_Negative ) {
268 		DBG( DBG_LOW, "inverting...\n" );
269 
270 		if((_MAP_MASTER == which) || (_MAP_RED == which)) {
271 
272 			DBG( DBG_LOW, "inverting RED map\n" );
273 
274 			pdw = (pULong)ps->a_bMapTable;
275 
276 		    for( dw = tabLen / 4; dw; dw--, pdw++ )
277 				*pdw = ~(*pdw);
278     	}
279 
280 		if((_MAP_MASTER == which) || (_MAP_GREEN == which)) {
281 
282 			DBG( DBG_LOW, "inverting GREEN map\n" );
283 
284 			pdw = (pULong)&ps->a_bMapTable[tabLen];
285 
286 		    for( dw = tabLen / 4; dw; dw--, pdw++ )
287 				*pdw = ~(*pdw);
288     	}
289 
290 		if((_MAP_MASTER == which) || (_MAP_BLUE == which)) {
291 
292 			DBG( DBG_LOW, "inverting BLUE map\n" );
293 
294 			pdw = (pULong)&ps->a_bMapTable[tabLen*2];
295 
296 		    for( dw = tabLen / 4; dw; dw--, pdw++ )
297 				*pdw = ~(*pdw);
298     	}
299 	}
300 }
301 
302 /* END PLUSTEK-PP_MAP.C .....................................................*/
303