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 */
75static 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
87static 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 */
103static 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 */
124static 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 */
144static 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 */
162static 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 */
193_LOC void MapInitialize( pScanData ps )
194{
195	mapBuildLinearMap( ps );
196	MapAdjust( ps, _MAP_MASTER );
197}
198
199/** setup dither maps
200 */
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 */
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