xref: /aoo42x/main/vcl/source/gdi/bitmap3.cxx (revision 9f62ea84)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_vcl.hxx"
26 
27 #include <stdlib.h>
28 
29 #include <vcl/bmpacc.hxx>
30 #include <vcl/octree.hxx>
31 #include <vcl/bitmapex.hxx>
32 #include <vcl/bitmap.hxx>
33 
34 #include <impoct.hxx>
35 #include <impvect.hxx>
36 
37 // -----------
38 // - Defines -
39 // -----------
40 
41 #define RGB15( _def_cR, _def_cG, _def_cB )	(((sal_uLong)(_def_cR)<<10UL)|((sal_uLong)(_def_cG)<<5UL)|(sal_uLong)(_def_cB))
42 #define GAMMA( _def_cVal, _def_InvGamma )	((sal_uInt8)MinMax(FRound(pow( _def_cVal/255.0,_def_InvGamma)*255.0),0L,255L))
43 
44 #define CALC_ERRORS																\
45 						nTemp   = p1T[nX++] >> 12;								\
46 						nBErr = MinMax( nTemp, 0, 255 );						\
47 						nBErr = nBErr - FloydIndexMap[ nBC = FloydMap[nBErr] ];	\
48 						nTemp   = p1T[nX++] >> 12;								\
49 						nGErr = MinMax( nTemp, 0, 255 );						\
50 						nGErr = nGErr - FloydIndexMap[ nGC = FloydMap[nGErr] ];	\
51 						nTemp   = p1T[nX] >> 12;								\
52 						nRErr = MinMax( nTemp, 0, 255 );						\
53 						nRErr = nRErr - FloydIndexMap[ nRC = FloydMap[nRErr] ];
54 
55 #define CALC_TABLES3										\
56 						p2T[nX++] += FloydError3[nBErr];	\
57 						p2T[nX++] += FloydError3[nGErr];	\
58 						p2T[nX++] += FloydError3[nRErr];
59 
60 #define CALC_TABLES5										\
61 						p2T[nX++] += FloydError5[nBErr];	\
62 						p2T[nX++] += FloydError5[nGErr];	\
63 						p2T[nX++] += FloydError5[nRErr];
64 
65 #define CALC_TABLES7										\
66 						p1T[++nX] += FloydError7[nBErr];	\
67 						p2T[nX++] += FloydError1[nBErr];	\
68 						p1T[nX] += FloydError7[nGErr];		\
69 						p2T[nX++] += FloydError1[nGErr];	\
70 						p1T[nX] += FloydError7[nRErr];		\
71 						p2T[nX] += FloydError1[nRErr];
72 
73 // -----------
74 // - Statics -
75 // -----------
76 
77 sal_uLong nVCLRLut[ 6 ] = { 16, 17, 18, 19, 20, 21 };
78 sal_uLong nVCLGLut[ 6 ] = { 0, 6, 12, 18, 24, 30 };
79 sal_uLong nVCLBLut[ 6 ] = { 0, 36, 72, 108, 144, 180 };
80 
81 // ------------------------------------------------------------------------
82 
83 sal_uLong nVCLDitherLut[ 256 ] =
84 {
85        0, 49152, 12288, 61440,  3072, 52224, 15360, 64512,   768, 49920, 13056,
86    62208,  3840, 52992, 16128, 65280, 32768, 16384, 45056, 28672, 35840, 19456,
87    48128, 31744, 33536, 17152, 45824, 29440, 36608, 20224, 48896, 32512, 8192,
88    57344,  4096, 53248, 11264, 60416,  7168, 56320,  8960, 58112,  4864, 54016,
89    12032, 61184,  7936, 57088, 40960, 24576, 36864, 20480, 44032, 27648, 39936,
90    23552, 41728, 25344, 37632, 21248, 44800, 28416, 40704, 24320, 2048, 51200,
91    14336, 63488,  1024, 50176, 13312, 62464,  2816, 51968, 15104, 64256,  1792,
92    50944, 14080, 63232, 34816, 18432, 47104, 30720, 33792, 17408, 46080, 29696,
93    35584, 19200, 47872, 31488, 34560, 18176, 46848, 30464, 10240, 59392,  6144,
94    55296,  9216, 58368,  5120, 54272, 11008, 60160,  6912, 56064,  9984, 59136,
95     5888, 55040, 43008, 26624, 38912, 22528, 41984, 25600, 37888, 21504, 43776,
96    27392, 39680, 23296, 42752, 26368, 38656, 22272,   512, 49664, 12800, 61952,
97     3584, 52736, 15872, 65024,   256, 49408, 12544, 61696,  3328, 52480, 15616,
98    64768, 33280, 16896, 45568, 29184, 36352, 19968, 48640, 32256, 33024, 16640,
99    45312, 28928, 36096, 19712, 48384, 32000,  8704, 57856,  4608, 53760, 11776,
100    60928,  7680, 56832,  8448, 57600,  4352, 53504, 11520, 60672,  7424, 56576,
101    41472, 25088, 37376, 20992, 44544, 28160, 40448, 24064, 41216, 24832, 37120,
102    20736, 44288, 27904, 40192, 23808,  2560, 51712, 14848, 64000,  1536, 50688,
103    13824, 62976,  2304, 51456, 14592, 63744,  1280, 50432, 13568, 62720, 35328,
104    18944, 47616, 31232, 34304, 17920, 46592, 30208, 35072, 18688, 47360, 30976,
105    34048, 17664, 46336, 29952, 10752, 59904,  6656, 55808,  9728, 58880,  5632,
106    54784, 10496, 59648,  6400, 55552,  9472, 58624,  5376, 54528, 43520, 27136,
107    39424, 23040, 42496, 26112, 38400, 22016, 43264, 26880, 39168, 22784, 42240,
108    25856, 38144, 21760
109 };
110 
111 // ------------------------------------------------------------------------
112 
113 sal_uLong nVCLLut[ 256 ] =
114 {
115          0,  1286,  2572,  3858,  5144,  6430,  7716,  9002,
116      10288, 11574, 12860, 14146, 15432, 16718, 18004, 19290,
117      20576, 21862, 23148, 24434, 25720, 27006, 28292, 29578,
118      30864, 32150, 33436, 34722, 36008, 37294, 38580, 39866,
119      41152, 42438, 43724, 45010, 46296, 47582, 48868, 50154,
120      51440, 52726, 54012, 55298, 56584, 57870, 59156, 60442,
121      61728, 63014, 64300, 65586, 66872, 68158, 69444, 70730,
122      72016, 73302, 74588, 75874, 77160, 78446, 79732, 81018,
123      82304, 83590, 84876, 86162, 87448, 88734, 90020, 91306,
124      92592, 93878, 95164, 96450, 97736, 99022,100308,101594,
125     102880,104166,105452,106738,108024,109310,110596,111882,
126     113168,114454,115740,117026,118312,119598,120884,122170,
127     123456,124742,126028,127314,128600,129886,131172,132458,
128     133744,135030,136316,137602,138888,140174,141460,142746,
129     144032,145318,146604,147890,149176,150462,151748,153034,
130     154320,155606,156892,158178,159464,160750,162036,163322,
131     164608,165894,167180,168466,169752,171038,172324,173610,
132     174896,176182,177468,178754,180040,181326,182612,183898,
133     185184,186470,187756,189042,190328,191614,192900,194186,
134     195472,196758,198044,199330,200616,201902,203188,204474,
135     205760,207046,208332,209618,210904,212190,213476,214762,
136     216048,217334,218620,219906,221192,222478,223764,225050,
137     226336,227622,228908,230194,231480,232766,234052,235338,
138     236624,237910,239196,240482,241768,243054,244340,245626,
139     246912,248198,249484,250770,252056,253342,254628,255914,
140     257200,258486,259772,261058,262344,263630,264916,266202,
141     267488,268774,270060,271346,272632,273918,275204,276490,
142     277776,279062,280348,281634,282920,284206,285492,286778,
143     288064,289350,290636,291922,293208,294494,295780,297066,
144     298352,299638,300924,302210,303496,304782,306068,307354,
145     308640,309926,311212,312498,313784,315070,316356,317642,
146     318928,320214,321500,322786,324072,325358,326644,327930
147 };
148 
149 // ------------------------------------------------------------------------
150 
151 long FloydMap[256] =
152 {
153     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
154     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1,
155     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
156     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
157     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2,
158     2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
159     2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
160     2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
161     3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
162     3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
163     3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
164     3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
165     4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
166     4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
167     4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
168     5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
169 };
170 
171 // ------------------------------------------------------------------------
172 
173 long FloydError1[61] =
174 {
175     -7680, -7424, -7168, -6912, -6656, -6400, -6144,
176     -5888, -5632, -5376, -5120, -4864, -4608, -4352,
177     -4096, -3840, -3584, -3328, -3072, -2816, -2560,
178     -2304, -2048, -1792, -1536, -1280, -1024, -768,
179     -512, -256, 0, 256, 512, 768, 1024, 1280, 1536,
180     1792, 2048, 2304, 2560, 2816, 3072, 3328, 3584,
181     3840, 4096, 4352, 4608, 4864, 5120, 5376, 5632,
182     5888, 6144, 6400, 6656, 6912, 7168, 7424, 7680
183 };
184 
185 // ------------------------------------------------------------------------
186 
187 long FloydError3[61] =
188 {
189     -23040, -22272, -21504, -20736, -19968, -19200,
190     -18432, -17664, -16896, -16128, -15360, -14592,
191     -13824, -13056, -12288, -11520, -10752, -9984,
192     -9216, -8448, -7680, -6912, -6144, -5376, -4608,
193     -3840, -3072, -2304, -1536, -768, 0, 768, 1536,
194     2304, 3072, 3840, 4608, 5376, 6144, 6912, 7680,
195     8448, 9216, 9984, 10752, 11520, 12288, 13056,
196     13824, 14592, 15360, 16128, 16896, 17664, 18432,
197     19200, 19968, 20736, 21504, 22272, 23040
198 };
199 
200 // ------------------------------------------------------------------------
201 
202 long FloydError5[61] =
203 {
204     -38400, -37120, -35840, -34560, -33280, -32000,
205     -30720, -29440, -28160, -26880, -25600, -24320,
206     -23040, -21760, -20480, -19200, -17920, -16640,
207     -15360, -14080, -12800, -11520, -10240, -8960,
208     -7680, -6400, -5120, -3840, -2560, -1280,   0,
209     1280, 2560, 3840, 5120, 6400, 7680, 8960, 10240,
210     11520, 12800, 14080, 15360, 16640, 17920, 19200,
211     20480, 21760, 23040, 24320, 25600, 26880, 28160,
212     29440, 30720, 32000, 33280, 34560, 35840, 37120,
213     38400
214 };
215 
216 // ------------------------------------------------------------------------
217 
218 long FloydError7[61] =
219 {
220     -53760, -51968, -50176, -48384, -46592, -44800,
221     -43008, -41216, -39424, -37632, -35840, -34048,
222     -32256, -30464, -28672, -26880, -25088, -23296,
223     -21504, -19712, -17920, -16128, -14336, -12544,
224     -10752, -8960, -7168, -5376, -3584, -1792,  0,
225     1792, 3584, 5376, 7168, 8960, 10752, 12544, 14336,
226     16128, 17920, 19712, 21504, 23296, 25088, 26880,
227     28672, 30464, 32256, 34048, 35840, 37632, 39424,
228     41216, 43008, 44800, 46592, 48384, 50176, 51968,
229     53760
230 };
231 
232 // ------------------------------------------------------------------------
233 
234 long FloydIndexMap[6] =
235 {
236     -30,  21, 72, 123, 174, 225
237 };
238 
239 // --------------------------
240 // - ImplCreateDitherMatrix -
241 // --------------------------
242 
243 void ImplCreateDitherMatrix( sal_uInt8 (*pDitherMatrix)[16][16] )
244 {
245 	double			fVal = 3.125;
246 	const double	fVal16 = fVal / 16.;
247 	long			i, j, k, l;
248 	sal_uInt16			pMtx[ 16 ][ 16 ];
249 	sal_uInt16			nMax = 0;
250 	static sal_uInt8 	pMagic[4][4] = { { 0, 14,  3, 13, },
251                                      {11,  5,  8,  6, },
252                                      {12,  2, 15,  1, },
253                                      {7,   9,  4, 10 } };
254 
255 	// MagicSquare aufbauen
256 	for ( i = 0; i < 4; i++ )
257 	   for ( j = 0; j < 4; j++ )
258 		   for ( k = 0; k < 4; k++ )
259 				for ( l = 0; l < 4; l++ )
260 					nMax = Max ( pMtx[ (k<<2) + i][(l<<2 ) + j] =
261 					(sal_uInt16) ( 0.5 + pMagic[i][j]*fVal + pMagic[k][l]*fVal16 ), nMax );
262 
263 	// auf Intervall [0;254] skalieren
264 	for ( i = 0, fVal = 254. / nMax; i < 16; i++ )
265 		for( j = 0; j < 16; j++ )
266 			(*pDitherMatrix)[i][j] = (sal_uInt8) ( fVal * pMtx[i][j] );
267 }
268 
269 // ----------
270 // - Bitmap -
271 // ----------
272 
273 sal_Bool Bitmap::Convert( BmpConversion eConversion )
274 {
275 	const sal_uInt16	nBitCount = GetBitCount();
276 	sal_Bool			bRet = sal_False;
277 
278 	switch( eConversion )
279 	{
280 		case( BMP_CONVERSION_1BIT_THRESHOLD ):
281 			bRet = ImplMakeMono( 128 );
282 		break;
283 
284 		case( BMP_CONVERSION_1BIT_MATRIX ):
285 			bRet = ImplMakeMonoDither();
286 		break;
287 
288 		case( BMP_CONVERSION_4BIT_GREYS ):
289 			bRet = ImplMakeGreyscales( 16 );
290 		break;
291 
292 		case( BMP_CONVERSION_4BIT_COLORS ):
293 		{
294 			if( nBitCount < 4 )
295 				bRet = ImplConvertUp( 4, NULL );
296 			else if( nBitCount > 4 )
297 				bRet = ImplConvertDown( 4, NULL );
298 			else
299 				bRet = sal_True;
300 		}
301 		break;
302 
303 		case( BMP_CONVERSION_4BIT_TRANS ):
304 		{
305 			Color aTrans( BMP_COL_TRANS );
306 
307 			if( nBitCount < 4 )
308 				bRet = ImplConvertUp( 4, &aTrans );
309 			else
310 				bRet = ImplConvertDown( 4, &aTrans );
311 		}
312 		break;
313 
314 		case( BMP_CONVERSION_8BIT_GREYS ):
315 			bRet = ImplMakeGreyscales( 256 );
316 		break;
317 
318 		case( BMP_CONVERSION_8BIT_COLORS ):
319 		{
320 			if( nBitCount < 8 )
321 				bRet = ImplConvertUp( 8 );
322 			else if( nBitCount > 8 )
323 				bRet = ImplConvertDown( 8 );
324 			else
325 				bRet = sal_True;
326 		}
327 		break;
328 
329 		case( BMP_CONVERSION_8BIT_TRANS ):
330 		{
331 			Color aTrans( BMP_COL_TRANS );
332 
333 			if( nBitCount < 8 )
334 				bRet = ImplConvertUp( 8, &aTrans );
335 			else
336 				bRet = ImplConvertDown( 8, &aTrans );
337 		}
338 		break;
339 
340 		case( BMP_CONVERSION_24BIT ):
341 		{
342 			if( nBitCount < 24 )
343 				bRet = ImplConvertUp( 24, sal_False );
344 			else
345 				bRet = sal_True;
346 		}
347 		break;
348 
349 		case( BMP_CONVERSION_GHOSTED ):
350 			bRet = ImplConvertGhosted();
351 		break;
352 
353 		default:
354 			DBG_ERROR( "Bitmap::Convert(): Unsupported conversion" );
355 		break;
356 	}
357 
358 	return bRet;
359 }
360 
361 // ------------------------------------------------------------------------
362 
363 sal_Bool Bitmap::ImplMakeMono( sal_uInt8 cThreshold )
364 {
365 	BitmapReadAccess*	pReadAcc = AcquireReadAccess();
366 	sal_Bool				bRet = sal_False;
367 
368 	if( pReadAcc )
369 	{
370 		Bitmap				aNewBmp( GetSizePixel(), 1 );
371 		BitmapWriteAccess*	pWriteAcc = aNewBmp.AcquireWriteAccess();
372 
373 		if( pWriteAcc )
374 		{
375 			const BitmapColor	aBlack( pWriteAcc->GetBestMatchingColor( Color( COL_BLACK ) ) );
376 			const BitmapColor	aWhite( pWriteAcc->GetBestMatchingColor( Color( COL_WHITE ) ) );
377 			const long			nWidth = pWriteAcc->Width();
378 			const long			nHeight = pWriteAcc->Height();
379 
380 			if( pReadAcc->HasPalette() )
381 			{
382 				for( long nY = 0L; nY < nHeight; nY++ )
383 				{
384 					for( long nX = 0L; nX < nWidth; nX++ )
385 					{
386 						if( pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nY, nX ) ).GetLuminance() >=
387 							cThreshold )
388 						{
389 							pWriteAcc->SetPixel( nY, nX, aWhite );
390 						}
391 						else
392 							pWriteAcc->SetPixel( nY, nX, aBlack );
393 					}
394 				}
395 			}
396 			else
397 			{
398 				for( long nY = 0L; nY < nHeight; nY++ )
399 				{
400 					for( long nX = 0L; nX < nWidth; nX++ )
401 					{
402 						if( pReadAcc->GetPixel( nY, nX ).GetLuminance() >=
403 							cThreshold )
404 						{
405 							pWriteAcc->SetPixel( nY, nX, aWhite );
406 						}
407 						else
408 							pWriteAcc->SetPixel( nY, nX, aBlack );
409 					}
410 				}
411 			}
412 
413 			aNewBmp.ReleaseAccess( pWriteAcc );
414 			bRet = sal_True;
415 		}
416 
417 		ReleaseAccess( pReadAcc );
418 
419 		if( bRet )
420 		{
421 			const MapMode	aMap( maPrefMapMode );
422 			const Size		aSize( maPrefSize );
423 
424 			*this = aNewBmp;
425 
426 			maPrefMapMode = aMap;
427 			maPrefSize = aSize;
428 		}
429 	}
430 
431 	return bRet;
432 }
433 
434 // ------------------------------------------------------------------------
435 
436 sal_Bool Bitmap::ImplMakeMonoDither()
437 {
438 	BitmapReadAccess*	pReadAcc = AcquireReadAccess();
439 	sal_Bool				bRet = sal_False;
440 
441 	if( pReadAcc )
442 	{
443 		Bitmap				aNewBmp( GetSizePixel(), 1 );
444 		BitmapWriteAccess*	pWriteAcc = aNewBmp.AcquireWriteAccess();
445 
446 		if( pWriteAcc )
447 		{
448 			const BitmapColor	aBlack( pWriteAcc->GetBestMatchingColor( Color( COL_BLACK ) ) );
449 			const BitmapColor	aWhite( pWriteAcc->GetBestMatchingColor( Color( COL_WHITE ) ) );
450 			const long			nWidth = pWriteAcc->Width();
451 			const long			nHeight = pWriteAcc->Height();
452 			sal_uInt8				pDitherMatrix[ 16 ][ 16 ];
453 
454 			ImplCreateDitherMatrix( &pDitherMatrix );
455 
456 			if( pReadAcc->HasPalette() )
457 			{
458 				for( long nY = 0L; nY < nHeight; nY++ )
459 				{
460 					for( long nX = 0L, nModY = nY % 16; nX < nWidth; nX++ )
461 					{
462 						if( pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nY, nX ) ).GetLuminance() >
463 							pDitherMatrix[ nModY ][ nX % 16 ] )
464 						{
465 							pWriteAcc->SetPixel( nY, nX, aWhite );
466 						}
467 						else
468 							pWriteAcc->SetPixel( nY, nX, aBlack );
469 					}
470 				}
471 			}
472 			else
473 			{
474 				for( long nY = 0L; nY < nHeight; nY++ )
475 				{
476 					for( long nX = 0L, nModY = nY % 16; nX < nWidth; nX++ )
477 					{
478 						if( pReadAcc->GetPixel( nY, nX ).GetLuminance() >
479 							pDitherMatrix[ nModY ][ nX % 16 ]  )
480 						{
481 							pWriteAcc->SetPixel( nY, nX, aWhite );
482 						}
483 						else
484 							pWriteAcc->SetPixel( nY, nX, aBlack );
485 					}
486 				}
487 			}
488 
489 			aNewBmp.ReleaseAccess( pWriteAcc );
490 			bRet = sal_True;
491 		}
492 
493 		ReleaseAccess( pReadAcc );
494 
495 		if( bRet )
496 		{
497 			const MapMode	aMap( maPrefMapMode );
498 			const Size		aSize( maPrefSize );
499 
500 			*this = aNewBmp;
501 
502 			maPrefMapMode = aMap;
503 			maPrefSize = aSize;
504 		}
505 	}
506 
507 	return bRet;
508 }
509 
510 // ------------------------------------------------------------------------
511 
512 sal_Bool Bitmap::ImplMakeGreyscales( sal_uInt16 nGreys )
513 {
514 	DBG_ASSERT( nGreys == 16 || nGreys == 256, "Only 16 or 256 greyscales are supported!" );
515 
516 	BitmapReadAccess*	pReadAcc = AcquireReadAccess();
517 	sal_Bool				bRet = sal_False;
518 
519 	if( pReadAcc )
520 	{
521 		const BitmapPalette&	rPal = GetGreyPalette( nGreys );
522 		sal_uLong 					nShift = ( ( nGreys == 16 ) ? 4UL : 0UL );
523 		sal_Bool					bPalDiffers = !pReadAcc->HasPalette() || ( rPal.GetEntryCount() != pReadAcc->GetPaletteEntryCount() );
524 
525 		if( !bPalDiffers )
526 			bPalDiffers = ( (BitmapPalette&) rPal != pReadAcc->GetPalette() );
527 
528 		if( bPalDiffers )
529 		{
530 			Bitmap				aNewBmp( GetSizePixel(), ( nGreys == 16 ) ? 4 : 8, &rPal );
531 			BitmapWriteAccess*	pWriteAcc = aNewBmp.AcquireWriteAccess();
532 
533 			if( pWriteAcc )
534 			{
535 				const long	nWidth = pWriteAcc->Width();
536 				const long	nHeight = pWriteAcc->Height();
537 
538 				if( pReadAcc->HasPalette() )
539 				{
540 					for( long nY = 0L; nY < nHeight; nY++ )
541 					{
542 						for( long nX = 0L; nX < nWidth; nX++ )
543 						{
544 							pWriteAcc->SetPixel( nY, nX,
545 								(sal_uInt8) ( pReadAcc->GetPaletteColor(
546 									pReadAcc->GetPixel( nY, nX ) ).GetLuminance() >> nShift ) );
547 						}
548 					}
549 				}
550 				else if( pReadAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_BGR &&
551 						 pWriteAcc->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL )
552 				{
553 					nShift += 8;
554 
555 					for( long nY = 0L; nY < nHeight; nY++ )
556 					{
557 						Scanline pReadScan = pReadAcc->GetScanline( nY );
558 						Scanline pWriteScan = pWriteAcc->GetScanline( nY );
559 
560 						for( long nX = 0L; nX < nWidth; nX++ )
561 						{
562 							const sal_uLong nB = *pReadScan++;
563 							const sal_uLong nG = *pReadScan++;
564 							const sal_uLong nR = *pReadScan++;
565 
566 							*pWriteScan++ = (sal_uInt8) ( ( nB * 28UL + nG * 151UL + nR * 77UL ) >> nShift );
567 						}
568 					}
569 				}
570 				else if( pReadAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_RGB &&
571 						 pWriteAcc->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL )
572 				{
573 					nShift += 8;
574 
575 					for( long nY = 0L; nY < nHeight; nY++ )
576 					{
577 						Scanline pReadScan = pReadAcc->GetScanline( nY );
578 						Scanline pWriteScan = pWriteAcc->GetScanline( nY );
579 
580 						for( long nX = 0L; nX < nWidth; nX++ )
581 						{
582 							const sal_uLong nR = *pReadScan++;
583 							const sal_uLong nG = *pReadScan++;
584 							const sal_uLong nB = *pReadScan++;
585 
586 							*pWriteScan++ = (sal_uInt8) ( ( nB * 28UL + nG * 151UL + nR * 77UL ) >> nShift );
587 						}
588 					}
589 				}
590 				else
591 				{
592 					for( long nY = 0L; nY < nHeight; nY++ )
593 						for( long nX = 0L; nX < nWidth; nX++ )
594 							pWriteAcc->SetPixel( nY, nX, sal::static_int_cast<sal_uInt8>(( pReadAcc->GetPixel( nY, nX ) ).GetLuminance() >> nShift) );
595 				}
596 
597 				aNewBmp.ReleaseAccess( pWriteAcc );
598 				bRet = sal_True;
599 			}
600 
601 			ReleaseAccess( pReadAcc );
602 
603 			if( bRet )
604 			{
605 				const MapMode	aMap( maPrefMapMode );
606 				const Size		aSize( maPrefSize );
607 
608 				*this = aNewBmp;
609 
610 				maPrefMapMode = aMap;
611 				maPrefSize = aSize;
612 			}
613 		}
614 		else
615 		{
616 			ReleaseAccess( pReadAcc );
617 			bRet = sal_True;
618 		}
619 	}
620 
621 	return bRet;
622 }
623 
624 // ------------------------------------------------------------------------
625 
626 sal_Bool Bitmap::ImplConvertUp( sal_uInt16 nBitCount, Color* pExtColor )
627 {
628 	DBG_ASSERT( nBitCount > GetBitCount(), "New BitCount must be greater!" );
629 
630 	BitmapReadAccess*	pReadAcc = AcquireReadAccess();
631 	sal_Bool				bRet = sal_False;
632 
633 	if( pReadAcc )
634 	{
635 		BitmapPalette		aPal;
636 		Bitmap				aNewBmp( GetSizePixel(), nBitCount, pReadAcc->HasPalette() ? &pReadAcc->GetPalette() : &aPal );
637 		BitmapWriteAccess*	pWriteAcc = aNewBmp.AcquireWriteAccess();
638 
639 		if( pWriteAcc )
640 		{
641 			const long	nWidth = pWriteAcc->Width();
642 			const long	nHeight = pWriteAcc->Height();
643 
644 			if( pWriteAcc->HasPalette() )
645 			{
646 				const sal_uInt16			nOldCount = 1 << GetBitCount();
647 				const BitmapPalette&	rOldPal = pReadAcc->GetPalette();
648 
649 				aPal.SetEntryCount( 1 << nBitCount );
650 
651 				for( sal_uInt16 i = 0; i < nOldCount; i++ )
652 					aPal[ i ] = rOldPal[ i ];
653 
654 				if( pExtColor )
655 					aPal[ aPal.GetEntryCount() - 1 ] = *pExtColor;
656 
657 				pWriteAcc->SetPalette( aPal );
658 
659 				for( long nY = 0L; nY < nHeight; nY++ )
660 					for( long nX = 0L; nX < nWidth; nX++ )
661 						pWriteAcc->SetPixel( nY, nX, pReadAcc->GetPixel( nY, nX ) );
662 			}
663 			else
664 			{
665 				if( pReadAcc->HasPalette() )
666 				{
667 					for( long nY = 0L; nY < nHeight; nY++ )
668 						for( long nX = 0L; nX < nWidth; nX++ )
669 							pWriteAcc->SetPixel( nY, nX, pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nY, nX ) ) );
670 				}
671 				else
672 				{
673 					for( long nY = 0L; nY < nHeight; nY++ )
674 						for( long nX = 0L; nX < nWidth; nX++ )
675 							pWriteAcc->SetPixel( nY, nX, pReadAcc->GetPixel( nY, nX ) );
676 				}
677 			}
678 
679 			aNewBmp.ReleaseAccess( pWriteAcc );
680 			bRet = sal_True;
681 		}
682 
683 		ReleaseAccess( pReadAcc );
684 
685 		if( bRet )
686 		{
687 			const MapMode	aMap( maPrefMapMode );
688 			const Size		aSize( maPrefSize );
689 
690 			*this = aNewBmp;
691 
692 			maPrefMapMode = aMap;
693 			maPrefSize = aSize;
694 		}
695 	}
696 
697 	return bRet;
698 }
699 
700 // ------------------------------------------------------------------------
701 
702 sal_Bool Bitmap::ImplConvertDown( sal_uInt16 nBitCount, Color* pExtColor )
703 {
704 	DBG_ASSERT( nBitCount <= GetBitCount(), "New BitCount must be lower ( or equal when pExtColor is set )!" );
705 
706 	BitmapReadAccess*	pReadAcc = AcquireReadAccess();
707 	sal_Bool				bRet = sal_False;
708 
709 	if( pReadAcc )
710 	{
711 		BitmapPalette		aPal;
712 		Bitmap				aNewBmp( GetSizePixel(), nBitCount, &aPal );
713 		BitmapWriteAccess*	pWriteAcc = aNewBmp.AcquireWriteAccess();
714 
715 		if( pWriteAcc )
716 		{
717 			const sal_uInt16	nCount = 1 << nBitCount;
718 			const long		nWidth = pWriteAcc->Width();
719 			const long		nWidth1 = nWidth - 1L;
720 			const long		nHeight = pWriteAcc->Height();
721 			Octree			aOctree( *pReadAcc, pExtColor ? ( nCount - 1 ) : nCount );
722 			InverseColorMap aColorMap( aPal = aOctree.GetPalette() );
723 			BitmapColor 	aColor;
724 			ImpErrorQuad	aErrQuad;
725 			ImpErrorQuad*	pErrQuad1 = new ImpErrorQuad[ nWidth ];
726 			ImpErrorQuad*	pErrQuad2 = new ImpErrorQuad[ nWidth ];
727 			ImpErrorQuad*	pQLine1 = pErrQuad1;
728 			ImpErrorQuad*	pQLine2 = 0;
729 			long			nX, nY;
730 			long			nYTmp = 0L;
731 			sal_uInt8			cIndex;
732 			sal_Bool			bQ1 = sal_True;
733 
734 			if( pExtColor )
735 			{
736 				aPal.SetEntryCount( aPal.GetEntryCount() + 1 );
737 				aPal[ aPal.GetEntryCount() - 1 ] = *pExtColor;
738 			}
739 
740 			// set Black/White always, if we have enough space
741 			if( aPal.GetEntryCount() < ( nCount - 1 ) )
742 			{
743 				aPal.SetEntryCount( aPal.GetEntryCount() + 2 );
744 				aPal[ aPal.GetEntryCount() - 2 ] = Color( COL_BLACK );
745 				aPal[ aPal.GetEntryCount() - 1 ] = Color( COL_WHITE );
746 			}
747 
748 			pWriteAcc->SetPalette( aPal );
749 
750 			for( nY = 0L; nY < Min( nHeight, 2L ); nY++, nYTmp++ )
751 			{
752 				for( nX = 0L, pQLine2 = !nY ? pErrQuad1 : pErrQuad2; nX < nWidth; nX++ )
753 				{
754 					if( pReadAcc->HasPalette() )
755 						pQLine2[ nX ] = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nYTmp, nX ) );
756 					else
757 						pQLine2[ nX ] = pReadAcc->GetPixel( nYTmp, nX );
758 				}
759 			}
760 
761 			for( nY = 0L; nY < nHeight; nY++, nYTmp++ )
762 			{
763 				// erstes ZeilenPixel
764 				cIndex = (sal_uInt8) aColorMap.GetBestPaletteIndex( pQLine1[ 0 ].ImplGetColor() );
765 				pWriteAcc->SetPixel( nY, 0, cIndex );
766 
767 				for( nX = 1L; nX < nWidth1; nX++ )
768 				{
769 					cIndex = (sal_uInt8) aColorMap.GetBestPaletteIndex( aColor = pQLine1[ nX ].ImplGetColor() );
770 					aErrQuad = ( ImpErrorQuad( aColor ) -= pWriteAcc->GetPaletteColor( cIndex ) );
771 					pQLine1[ ++nX ].ImplAddColorError7( aErrQuad );
772 					pQLine2[ nX-- ].ImplAddColorError1( aErrQuad );
773 					pQLine2[ nX-- ].ImplAddColorError5( aErrQuad );
774 					pQLine2[ nX++ ].ImplAddColorError3( aErrQuad );
775 					pWriteAcc->SetPixel( nY, nX, cIndex );
776 				}
777 
778 				// letztes ZeilenPixel
779                 if( nX < nWidth )
780                 {
781 				    cIndex = (sal_uInt8) aColorMap.GetBestPaletteIndex( pQLine1[ nWidth1 ].ImplGetColor() );
782 				    pWriteAcc->SetPixel( nY, nX, cIndex );
783                 }
784 
785 				// Zeilenpuffer neu fuellen/kopieren
786 				pQLine1 = pQLine2;
787 				pQLine2 = ( bQ1 = !bQ1 ) != sal_False ? pErrQuad2 : pErrQuad1;
788 
789 				if( nYTmp < nHeight )
790 				{
791 					for( nX = 0L; nX < nWidth; nX++ )
792 					{
793 						if( pReadAcc->HasPalette() )
794 								pQLine2[ nX ] = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nYTmp, nX ) );
795 						else
796 							pQLine2[ nX ] = pReadAcc->GetPixel( nYTmp, nX );
797 					}
798 				}
799 			}
800 
801 			// Zeilenpuffer zerstoeren
802 			delete[] pErrQuad1;
803 			delete[] pErrQuad2;
804 
805 			aNewBmp.ReleaseAccess( pWriteAcc );
806 			bRet = sal_True;
807 		}
808 
809 		ReleaseAccess( pReadAcc );
810 
811 		if( bRet )
812 		{
813 			const MapMode	aMap( maPrefMapMode );
814 			const Size		aSize( maPrefSize );
815 
816 			*this = aNewBmp;
817 
818 			maPrefMapMode = aMap;
819 			maPrefSize = aSize;
820 		}
821 	}
822 
823 	return bRet;
824 }
825 
826 // ------------------------------------------------------------------------
827 
828 sal_Bool Bitmap::ImplConvertGhosted()
829 {
830 	Bitmap				aNewBmp;
831 	BitmapReadAccess*	pR = AcquireReadAccess();
832 	sal_Bool				bRet = sal_False;
833 
834 	if( pR )
835 	{
836 		if( pR->HasPalette() )
837 		{
838 			BitmapPalette aNewPal( pR->GetPaletteEntryCount() );
839 
840 			for( long i = 0, nCount = aNewPal.GetEntryCount(); i < nCount; i++ )
841 			{
842 				const BitmapColor& rOld = pR->GetPaletteColor( (sal_uInt16) i );
843 				aNewPal[ (sal_uInt16) i ] = BitmapColor( ( rOld.GetRed() >> 1 ) | 0x80,
844 													 ( rOld.GetGreen() >> 1 ) | 0x80,
845 													 ( rOld.GetBlue() >> 1 ) | 0x80 );
846 			}
847 
848 			aNewBmp = Bitmap( GetSizePixel(), GetBitCount(), &aNewPal );
849 			BitmapWriteAccess* pW = aNewBmp.AcquireWriteAccess();
850 
851 			if( pW )
852 			{
853 				pW->CopyBuffer( *pR );
854 				aNewBmp.ReleaseAccess( pW );
855 				bRet = sal_True;
856 			}
857 		}
858 		else
859 		{
860 			aNewBmp = Bitmap( GetSizePixel(), 24 );
861 
862 			BitmapWriteAccess* pW = aNewBmp.AcquireWriteAccess();
863 
864 			if( pW )
865 			{
866 				const long nWidth = pR->Width(), nHeight = pR->Height();
867 
868 				for( long nY = 0; nY < nHeight; nY++ )
869 				{
870 					for( long nX = 0; nX < nWidth; nX++ )
871 					{
872 						const BitmapColor aOld( pR->GetPixel( nY, nX ) );
873 						pW->SetPixel( nY, nX, BitmapColor( ( aOld.GetRed() >> 1 ) | 0x80,
874 														   ( aOld.GetGreen() >> 1 ) | 0x80,
875 														   ( aOld.GetBlue() >> 1 ) | 0x80 ) );
876 
877 					}
878 				}
879 
880 				aNewBmp.ReleaseAccess( pW );
881 				bRet = sal_True;
882 			}
883 		}
884 
885 		ReleaseAccess( pR );
886 	}
887 
888 	if( bRet )
889 	{
890 		const MapMode	aMap( maPrefMapMode );
891 		const Size		aSize( maPrefSize );
892 
893 		*this = aNewBmp;
894 
895 		maPrefMapMode = aMap;
896 		maPrefSize = aSize;
897 	}
898 
899 	return bRet;
900 }
901 
902 // ------------------------------------------------------------------------
903 
904 sal_Bool Bitmap::Scale( const double& rScaleX, const double& rScaleY, sal_uLong nScaleFlag )
905 {
906 	sal_Bool bRet;
907 
908 	if( ( rScaleX != 1.0 ) || ( rScaleY != 1.0 ) )
909 	{
910 		if( BMP_SCALE_FAST == nScaleFlag )
911 			bRet = ImplScaleFast( rScaleX, rScaleY );
912 		else if( BMP_SCALE_INTERPOLATE == nScaleFlag )
913 			bRet = ImplScaleInterpolate( rScaleX, rScaleY );
914 		else
915 			bRet = sal_False;
916 	}
917 	else
918 		bRet = sal_True;
919 
920 	return bRet;
921 }
922 
923 // ------------------------------------------------------------------------
924 
925 sal_Bool Bitmap::Scale( const Size& rNewSize, sal_uLong nScaleFlag )
926 {
927 	const Size	aSize( GetSizePixel() );
928 	sal_Bool		bRet;
929 
930 	if( aSize.Width() && aSize.Height() )
931 	{
932 		bRet = Scale( (double) rNewSize.Width() / aSize.Width(),
933 					  (double) rNewSize.Height() / aSize.Height(),
934 					  nScaleFlag );
935 	}
936 	else
937 		bRet = sal_True;
938 
939 	return bRet;
940 }
941 
942 // ------------------------------------------------------------------------
943 
944 sal_Bool Bitmap::ImplScaleFast( const double& rScaleX, const double& rScaleY )
945 {
946 	const Size	aSizePix( GetSizePixel() );
947 	const long	nNewWidth = FRound( aSizePix.Width() * rScaleX );
948 	const long	nNewHeight = FRound( aSizePix.Height() * rScaleY );
949 	sal_Bool		bRet = sal_False;
950 
951 	if( nNewWidth && nNewHeight )
952 	{
953 		BitmapReadAccess*	pReadAcc = AcquireReadAccess();
954 		Bitmap				aNewBmp( Size( nNewWidth, nNewHeight ), GetBitCount(), &pReadAcc->GetPalette() );
955 		BitmapWriteAccess*	pWriteAcc = aNewBmp.AcquireWriteAccess();
956 
957 		if( pReadAcc && pWriteAcc )
958 		{
959 			const long	nScanlineSize = pWriteAcc->GetScanlineSize();
960 			const long	nNewWidth1 = nNewWidth - 1L;
961 			const long	nNewHeight1 = nNewHeight - 1L;
962 			const long	nWidth = pReadAcc->Width();
963 			const long	nHeight = pReadAcc->Height();
964 			long*		pLutX = new long[ nNewWidth ];
965 			long*		pLutY = new long[ nNewHeight ];
966 			long		nX, nY, nMapY, nActY = 0L;
967 
968 			if( nNewWidth1 && nNewHeight1 )
969 			{
970 				for( nX = 0L; nX < nNewWidth; nX++ )
971 					pLutX[ nX ] = nX * nWidth / nNewWidth;
972 
973 				for( nY = 0L; nY < nNewHeight; nY++ )
974 					pLutY[ nY ] = nY * nHeight / nNewHeight;
975 
976 				while( nActY < nNewHeight )
977 				{
978 					nMapY = pLutY[ nActY ];
979 
980 					for( nX = 0L; nX < nNewWidth; nX++ )
981 						pWriteAcc->SetPixel( nActY, nX, pReadAcc->GetPixel( nMapY , pLutX[ nX ] ) );
982 
983 					while( ( nActY < nNewHeight1 ) && ( pLutY[ nActY + 1 ] == nMapY ) )
984 					{
985 						memcpy( pWriteAcc->GetScanline( nActY + 1L ),
986 								 pWriteAcc->GetScanline( nActY ), nScanlineSize );
987 						nActY++;
988 					}
989 
990 					nActY++;
991 				}
992 
993 				bRet = sal_True;
994 			}
995 
996 			delete[] pLutX;
997 			delete[] pLutY;
998 		}
999 
1000 		ReleaseAccess( pReadAcc );
1001 		aNewBmp.ReleaseAccess( pWriteAcc );
1002 
1003 		if( bRet )
1004 			ImplAssignWithSize( aNewBmp );
1005 	}
1006 
1007 	return bRet;
1008 }
1009 
1010 // ------------------------------------------------------------------------
1011 
1012 sal_Bool Bitmap::ImplScaleInterpolate( const double& rScaleX, const double& rScaleY )
1013 {
1014 	const Size	aSizePix( GetSizePixel() );
1015 	const long	nNewWidth = FRound( aSizePix.Width() * rScaleX );
1016 	const long	nNewHeight = FRound( aSizePix.Height() * rScaleY );
1017 	sal_Bool		bRet = sal_False;
1018 
1019 	if( ( nNewWidth > 1L ) && ( nNewHeight > 1L ) )
1020 	{
1021 		BitmapColor 		aCol0;
1022 		BitmapColor 		aCol1;
1023 		BitmapReadAccess*	pReadAcc = AcquireReadAccess();
1024 		long				nWidth = pReadAcc->Width();
1025 		long				nHeight = pReadAcc->Height();
1026 		Bitmap				aNewBmp( Size( nNewWidth, nHeight ), 24 );
1027 		BitmapWriteAccess*	pWriteAcc = aNewBmp.AcquireWriteAccess();
1028 		long*				pLutInt;
1029 		long*				pLutFrac;
1030 		long				nX, nY;
1031 		long				lXB0, lXB1, lXG0, lXG1, lXR0, lXR1;
1032 		double				fTemp;
1033 		long				nTemp;
1034 
1035 		if( pReadAcc && pWriteAcc )
1036 		{
1037 			const long		nNewWidth1 = nNewWidth - 1L;
1038 			const long		nWidth1 = pReadAcc->Width() - 1L;
1039 			const double	fRevScaleX = (double) nWidth1 / nNewWidth1;
1040 
1041 			pLutInt = new long[ nNewWidth ];
1042 			pLutFrac = new long[ nNewWidth ];
1043 
1044 			for( nX = 0L, nTemp = nWidth - 2L; nX < nNewWidth; nX++ )
1045 			{
1046 				fTemp = nX * fRevScaleX;
1047 				pLutInt[ nX ] = MinMax( (long) fTemp, 0, nTemp );
1048 				fTemp -= pLutInt[ nX ];
1049 				pLutFrac[ nX ] = (long) ( fTemp * 1024. );
1050 			}
1051 
1052 			if( pReadAcc->HasPalette() )
1053 			{
1054 				for( nY = 0L; nY < nHeight; nY++ )
1055 				{
1056 					if( 1 == nWidth )
1057 					{
1058 						aCol0 = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nY, 0 ) );
1059 
1060 						for( nX = 0L; nX < nNewWidth; nX++ )
1061 							pWriteAcc->SetPixel( nY, nX, aCol0 );
1062 					}
1063 					else
1064 					{
1065 						for( nX = 0L; nX < nNewWidth; nX++ )
1066 						{
1067 							nTemp = pLutInt[ nX ];
1068 
1069 							aCol0 = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nY, nTemp++ ) );
1070 							aCol1 = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nY, nTemp ) );
1071 
1072 							nTemp = pLutFrac[ nX ];
1073 
1074 							lXR1 = aCol1.GetRed() - ( lXR0 = aCol0.GetRed() );
1075 							lXG1 = aCol1.GetGreen() - ( lXG0 = aCol0.GetGreen() );
1076 							lXB1 = aCol1.GetBlue() - ( lXB0 = aCol0.GetBlue() );
1077 
1078 							aCol0.SetRed( (sal_uInt8) ( ( lXR1 * nTemp + ( lXR0 << 10 ) ) >> 10 ) );
1079 							aCol0.SetGreen( (sal_uInt8) ( ( lXG1 * nTemp + ( lXG0 << 10 ) ) >> 10 ) );
1080 							aCol0.SetBlue( (sal_uInt8) ( ( lXB1 * nTemp + ( lXB0 << 10 ) ) >> 10 ) );
1081 
1082 							pWriteAcc->SetPixel( nY, nX, aCol0 );
1083 						}
1084 					}
1085 				}
1086 			}
1087 			else
1088 			{
1089 				for( nY = 0L; nY < nHeight; nY++ )
1090 				{
1091 					if( 1 == nWidth )
1092 					{
1093 						aCol0 = pReadAcc->GetPixel( nY, 0 );
1094 
1095 						for( nX = 0L; nX < nNewWidth; nX++ )
1096 							pWriteAcc->SetPixel( nY, nX, aCol0 );
1097 					}
1098 					else
1099 					{
1100 						for( nX = 0L; nX < nNewWidth; nX++ )
1101 						{
1102 							nTemp = pLutInt[ nX ];
1103 
1104 							aCol0 = pReadAcc->GetPixel( nY, nTemp++ );
1105 							aCol1 = pReadAcc->GetPixel( nY, nTemp );
1106 
1107 							nTemp = pLutFrac[ nX ];
1108 
1109 							lXR1 = aCol1.GetRed() - ( lXR0 = aCol0.GetRed() );
1110 							lXG1 = aCol1.GetGreen() - ( lXG0 = aCol0.GetGreen() );
1111 							lXB1 = aCol1.GetBlue() - ( lXB0 = aCol0.GetBlue() );
1112 
1113 							aCol0.SetRed( (sal_uInt8) ( ( lXR1 * nTemp + ( lXR0 << 10 ) ) >> 10 ) );
1114 							aCol0.SetGreen( (sal_uInt8) ( ( lXG1 * nTemp + ( lXG0 << 10 ) ) >> 10 ) );
1115 							aCol0.SetBlue( (sal_uInt8) ( ( lXB1 * nTemp + ( lXB0 << 10 ) ) >> 10 ) );
1116 
1117 							pWriteAcc->SetPixel( nY, nX, aCol0 );
1118 						}
1119 					}
1120 				}
1121 			}
1122 
1123 			delete[] pLutInt;
1124 			delete[] pLutFrac;
1125 			bRet = sal_True;
1126 		}
1127 
1128 		ReleaseAccess( pReadAcc );
1129 		aNewBmp.ReleaseAccess( pWriteAcc );
1130 
1131 		if( bRet )
1132 		{
1133 			bRet = sal_False;
1134 			ImplAssignWithSize( aNewBmp );
1135 			pReadAcc = AcquireReadAccess();
1136 			aNewBmp = Bitmap( Size( nNewWidth, nNewHeight ), 24 );
1137 			pWriteAcc = aNewBmp.AcquireWriteAccess();
1138 
1139 			if( pReadAcc && pWriteAcc )
1140 			{
1141 				const long		nNewHeight1 = nNewHeight - 1L;
1142 				const long		nHeight1 = pReadAcc->Height() - 1L;
1143 				const double	fRevScaleY = (double) nHeight1 / nNewHeight1;
1144 
1145 				pLutInt = new long[ nNewHeight ];
1146 				pLutFrac = new long[ nNewHeight ];
1147 
1148 				for( nY = 0L, nTemp = nHeight - 2L; nY < nNewHeight; nY++ )
1149 				{
1150 					fTemp = nY * fRevScaleY;
1151 					pLutInt[ nY ] = MinMax( (long) fTemp, 0, nTemp );
1152 					fTemp -= pLutInt[ nY ];
1153 					pLutFrac[ nY ] = (long) ( fTemp * 1024. );
1154 				}
1155 
1156 				if( pReadAcc->HasPalette() )
1157 				{
1158 					for( nX = 0L; nX < nNewWidth; nX++ )
1159 					{
1160 						if( 1 == nHeight )
1161 						{
1162 							aCol0 = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( 0, nX ) );
1163 
1164 							for( nY = 0L; nY < nNewHeight; nY++ )
1165 								pWriteAcc->SetPixel( nY, nX, aCol0 );
1166 						}
1167 						else
1168 						{
1169 							for( nY = 0L; nY < nNewHeight; nY++ )
1170 							{
1171 								nTemp = pLutInt[ nY ];
1172 
1173 								aCol0 = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nTemp++, nX ) );
1174 								aCol1 = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nTemp, nX ) );
1175 
1176 								nTemp = pLutFrac[ nY ];
1177 
1178 								lXR1 = aCol1.GetRed() - ( lXR0 = aCol0.GetRed() );
1179 								lXG1 = aCol1.GetGreen() - ( lXG0 = aCol0.GetGreen() );
1180 								lXB1 = aCol1.GetBlue() - ( lXB0 = aCol0.GetBlue() );
1181 
1182 								aCol0.SetRed( (sal_uInt8) ( ( lXR1 * nTemp + ( lXR0 << 10 ) ) >> 10 ) );
1183 								aCol0.SetGreen( (sal_uInt8) ( ( lXG1 * nTemp + ( lXG0 << 10 ) ) >> 10 ) );
1184 								aCol0.SetBlue( (sal_uInt8) ( ( lXB1 * nTemp + ( lXB0 << 10 ) ) >> 10 ) );
1185 
1186 								pWriteAcc->SetPixel( nY, nX, aCol0 );
1187 							}
1188 						}
1189 					}
1190 				}
1191 				else
1192 				{
1193 					for( nX = 0L; nX < nNewWidth; nX++ )
1194 					{
1195 						if( 1 == nHeight )
1196 						{
1197 							aCol0 = pReadAcc->GetPixel( 0, nX );
1198 
1199 							for( nY = 0L; nY < nNewHeight; nY++ )
1200 								pWriteAcc->SetPixel( nY, nX, aCol0 );
1201 						}
1202 						else
1203 						{
1204 							for( nY = 0L; nY < nNewHeight; nY++ )
1205 							{
1206 								nTemp = pLutInt[ nY ];
1207 
1208 								aCol0 = pReadAcc->GetPixel( nTemp++, nX );
1209 								aCol1 = pReadAcc->GetPixel( nTemp, nX );
1210 
1211 								nTemp = pLutFrac[ nY ];
1212 
1213 								lXR1 = aCol1.GetRed() - ( lXR0 = aCol0.GetRed() );
1214 								lXG1 = aCol1.GetGreen() - ( lXG0 = aCol0.GetGreen() );
1215 								lXB1 = aCol1.GetBlue() - ( lXB0 = aCol0.GetBlue() );
1216 
1217 								aCol0.SetRed( (sal_uInt8) ( ( lXR1 * nTemp + ( lXR0 << 10 ) ) >> 10 ) );
1218 								aCol0.SetGreen( (sal_uInt8) ( ( lXG1 * nTemp + ( lXG0 << 10 ) ) >> 10 ) );
1219 								aCol0.SetBlue( (sal_uInt8) ( ( lXB1 * nTemp + ( lXB0 << 10 ) ) >> 10 ) );
1220 
1221 								pWriteAcc->SetPixel( nY, nX, aCol0 );
1222 							}
1223 						}
1224 					}
1225 				}
1226 
1227 				delete[] pLutInt;
1228 				delete[] pLutFrac;
1229 				bRet = sal_True;
1230 			}
1231 
1232 			ReleaseAccess( pReadAcc );
1233 			aNewBmp.ReleaseAccess( pWriteAcc );
1234 
1235 			if( bRet )
1236 				ImplAssignWithSize( aNewBmp );
1237 		}
1238 	}
1239 
1240 	if( !bRet )
1241 		bRet = ImplScaleFast( rScaleX, rScaleY );
1242 
1243 	return bRet;
1244 }
1245 
1246 // ------------------------------------------------------------------------
1247 
1248 sal_Bool Bitmap::Dither( sal_uLong nDitherFlags )
1249 {
1250 	sal_Bool bRet = sal_False;
1251 
1252 	const Size aSizePix( GetSizePixel() );
1253 
1254 	if( aSizePix.Width() == 1 || aSizePix.Height() == 1 )
1255 		bRet = sal_True;
1256 	else if( nDitherFlags & BMP_DITHER_MATRIX )
1257 		bRet = ImplDitherMatrix();
1258 	else if( nDitherFlags & BMP_DITHER_FLOYD )
1259 		bRet = ImplDitherFloyd();
1260 	else if( ( nDitherFlags & BMP_DITHER_FLOYD_16 ) && ( GetBitCount() == 24 ) )
1261 		bRet = ImplDitherFloyd16();
1262 
1263 	return bRet;
1264 }
1265 
1266 // ------------------------------------------------------------------------
1267 
1268 sal_Bool Bitmap::ImplDitherMatrix()
1269 {
1270 	BitmapReadAccess*	pReadAcc = AcquireReadAccess();
1271 	Bitmap				aNewBmp( GetSizePixel(), 8 );
1272 	BitmapWriteAccess*	pWriteAcc = aNewBmp.AcquireWriteAccess();
1273 	sal_Bool				bRet = sal_False;
1274 
1275 	if( pReadAcc && pWriteAcc )
1276 	{
1277 		const sal_uLong	nWidth = pReadAcc->Width();
1278 		const sal_uLong	nHeight = pReadAcc->Height();
1279 		BitmapColor	aIndex( (sal_uInt8) 0 );
1280 
1281 		if( pReadAcc->HasPalette() )
1282 		{
1283 			for( sal_uLong nY = 0UL; nY < nHeight; nY++ )
1284 			{
1285 				for( sal_uLong nX = 0UL, nModY = ( nY & 0x0FUL ) << 4UL; nX < nWidth; nX++ )
1286 				{
1287 					const BitmapColor	aCol( pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nY, nX ) ) );
1288 					const sal_uLong			nD = nVCLDitherLut[ nModY + ( nX & 0x0FUL ) ];
1289 					const sal_uLong			nR = ( nVCLLut[ aCol.GetRed() ] + nD ) >> 16UL;
1290 					const sal_uLong			nG = ( nVCLLut[ aCol.GetGreen() ] + nD ) >> 16UL;
1291 					const sal_uLong			nB = ( nVCLLut[ aCol.GetBlue() ] + nD ) >> 16UL;
1292 
1293 					aIndex.SetIndex( (sal_uInt8) ( nVCLRLut[ nR ] + nVCLGLut[ nG ] + nVCLBLut[ nB ] ) );
1294 					pWriteAcc->SetPixel( nY, nX, aIndex );
1295 				}
1296 			}
1297 		}
1298 		else
1299 		{
1300 			for( sal_uLong nY = 0UL; nY < nHeight; nY++ )
1301 			{
1302 				for( sal_uLong nX = 0UL, nModY = ( nY & 0x0FUL ) << 4UL; nX < nWidth; nX++ )
1303 				{
1304 					const BitmapColor	aCol( pReadAcc->GetPixel( nY, nX ) );
1305 					const sal_uLong			nD = nVCLDitherLut[ nModY + ( nX & 0x0FUL ) ];
1306 					const sal_uLong			nR = ( nVCLLut[ aCol.GetRed() ] + nD ) >> 16UL;
1307 					const sal_uLong			nG = ( nVCLLut[ aCol.GetGreen() ] + nD ) >> 16UL;
1308 					const sal_uLong			nB = ( nVCLLut[ aCol.GetBlue() ] + nD ) >> 16UL;
1309 
1310 					aIndex.SetIndex( (sal_uInt8) ( nVCLRLut[ nR ] + nVCLGLut[ nG ] + nVCLBLut[ nB ] ) );
1311 					pWriteAcc->SetPixel( nY, nX, aIndex );
1312 				}
1313 			}
1314 		}
1315 
1316 		bRet = sal_True;
1317 	}
1318 
1319 	ReleaseAccess( pReadAcc );
1320 	aNewBmp.ReleaseAccess( pWriteAcc );
1321 
1322 	if( bRet )
1323 	{
1324 		const MapMode	aMap( maPrefMapMode );
1325 		const Size		aSize( maPrefSize );
1326 
1327 		*this = aNewBmp;
1328 
1329 		maPrefMapMode = aMap;
1330 		maPrefSize = aSize;
1331 	}
1332 
1333 	return bRet;
1334 }
1335 
1336 // ------------------------------------------------------------------------
1337 
1338 sal_Bool Bitmap::ImplDitherFloyd()
1339 {
1340 	const Size	aSize( GetSizePixel() );
1341 	sal_Bool		bRet = sal_False;
1342 
1343 	if( ( aSize.Width() > 3 ) && ( aSize.Height() > 2 ) )
1344 	{
1345 		BitmapReadAccess*	pReadAcc = AcquireReadAccess();
1346 		Bitmap				aNewBmp( GetSizePixel(), 8 );
1347 		BitmapWriteAccess*	pWriteAcc = aNewBmp.AcquireWriteAccess();
1348 
1349 		if( pReadAcc && pWriteAcc )
1350 		{
1351 			BitmapColor	aColor;
1352 			long		nWidth = pReadAcc->Width();
1353 			long		nWidth1 = nWidth - 1L;
1354 			long		nHeight = pReadAcc->Height();
1355 			long		nX;
1356 			long		nW = nWidth * 3L;
1357 			long		nW2 = nW - 3L;
1358 			long		nRErr, nGErr, nBErr;
1359 			long		nRC, nGC, nBC;
1360 			long		nTemp;
1361 			long		nZ;
1362 			long*		p1 = new long[ nW ];
1363 			long*		p2 = new long[ nW ];
1364 			long*		p1T = p1;
1365 			long*		p2T = p2;
1366 			long*		pTmp;
1367 			sal_Bool		bPal = pReadAcc->HasPalette();
1368 
1369 			pTmp = p2T;
1370 
1371 			if( bPal )
1372 			{
1373 				for( nZ = 0; nZ < nWidth; nZ++ )
1374 				{
1375 					aColor = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( 0, nZ ) );
1376 
1377 					*pTmp++ = (long) aColor.GetBlue() << 12;
1378 					*pTmp++ = (long) aColor.GetGreen() << 12;
1379 					*pTmp++ = (long) aColor.GetRed() << 12;
1380 				}
1381 			}
1382 			else
1383 			{
1384 				for( nZ = 0; nZ < nWidth; nZ++ )
1385 				{
1386 					aColor = pReadAcc->GetPixel( 0, nZ );
1387 
1388 					*pTmp++ = (long) aColor.GetBlue() << 12;
1389 					*pTmp++ = (long) aColor.GetGreen() << 12;
1390 					*pTmp++ = (long) aColor.GetRed() << 12;
1391 				}
1392 			}
1393 
1394 			for( long nY = 1, nYAcc = 0L; nY <= nHeight; nY++, nYAcc++ )
1395 			{
1396 				pTmp = p1T;
1397 				p1T = p2T;
1398 				p2T = pTmp;
1399 
1400 				if( nY < nHeight )
1401 				{
1402 					if( bPal )
1403 					{
1404 						for( nZ = 0; nZ < nWidth; nZ++ )
1405 						{
1406 							aColor = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nY, nZ ) );
1407 
1408 							*pTmp++ = (long) aColor.GetBlue() << 12;
1409 							*pTmp++ = (long) aColor.GetGreen() << 12;
1410 							*pTmp++ = (long) aColor.GetRed() << 12;
1411 						}
1412 					}
1413 					else
1414 					{
1415 						for( nZ = 0; nZ < nWidth; nZ++ )
1416 						{
1417 							aColor = pReadAcc->GetPixel( nY, nZ );
1418 
1419 							*pTmp++ = (long) aColor.GetBlue() << 12;
1420 							*pTmp++ = (long) aColor.GetGreen() << 12;
1421 							*pTmp++ = (long) aColor.GetRed() << 12;
1422 						}
1423 					}
1424 				}
1425 
1426 				// erstes Pixel gesondert betrachten
1427 				nX = 0;
1428 				CALC_ERRORS;
1429 				CALC_TABLES7;
1430 				nX -= 5;
1431 				CALC_TABLES5;
1432 				pWriteAcc->SetPixel( nYAcc, 0, BitmapColor( (sal_uInt8) ( nVCLBLut[ nBC ] + nVCLGLut[nGC ] + nVCLRLut[nRC ] ) ) );
1433 
1434 				// mittlere Pixel ueber Schleife
1435 				long nXAcc;
1436 				for ( nX = 3L, nXAcc = 1L; nX < nW2; nXAcc++ )
1437 				{
1438 					CALC_ERRORS;
1439 					CALC_TABLES7;
1440 					nX -= 8;
1441 					CALC_TABLES3;
1442 					CALC_TABLES5;
1443 					pWriteAcc->SetPixel( nYAcc, nXAcc, BitmapColor( (sal_uInt8) ( nVCLBLut[ nBC ] + nVCLGLut[nGC ] + nVCLRLut[nRC ] ) ) );
1444 				}
1445 
1446 				// letztes Pixel gesondert betrachten
1447 				CALC_ERRORS;
1448 				nX -= 5;
1449 				CALC_TABLES3;
1450 				CALC_TABLES5;
1451 				pWriteAcc->SetPixel( nYAcc, nWidth1, BitmapColor( (sal_uInt8) ( nVCLBLut[ nBC ] + nVCLGLut[nGC ] + nVCLRLut[nRC ] ) ) );
1452 			}
1453 
1454 			delete[] p1;
1455 			delete[] p2;
1456 			bRet = sal_True;
1457 		}
1458 
1459 		ReleaseAccess( pReadAcc );
1460 		aNewBmp.ReleaseAccess( pWriteAcc );
1461 
1462 		if( bRet )
1463 		{
1464 			const MapMode	aMap( maPrefMapMode );
1465 			const Size		aPrefSize( maPrefSize );
1466 
1467 			*this = aNewBmp;
1468 
1469 			maPrefMapMode = aMap;
1470 			maPrefSize = aPrefSize;
1471 		}
1472 	}
1473 
1474 	return bRet;
1475 }
1476 
1477 // ------------------------------------------------------------------------
1478 
1479 sal_Bool Bitmap::ImplDitherFloyd16()
1480 {
1481 	BitmapReadAccess*	pReadAcc = AcquireReadAccess();
1482 	Bitmap				aNewBmp( GetSizePixel(), 24 );
1483 	BitmapWriteAccess*	pWriteAcc = aNewBmp.AcquireWriteAccess();
1484 	sal_Bool				bRet = sal_False;
1485 
1486 	if( pReadAcc && pWriteAcc )
1487 	{
1488 		const long		nWidth = pWriteAcc->Width();
1489 		const long		nWidth1 = nWidth - 1L;
1490 		const long		nHeight = pWriteAcc->Height();
1491 		BitmapColor 	aColor;
1492 		BitmapColor		aBestCol;
1493 		ImpErrorQuad	aErrQuad;
1494 		ImpErrorQuad*	pErrQuad1 = new ImpErrorQuad[ nWidth ];
1495 		ImpErrorQuad*	pErrQuad2 = new ImpErrorQuad[ nWidth ];
1496 		ImpErrorQuad*	pQLine1 = pErrQuad1;
1497 		ImpErrorQuad*	pQLine2 = 0;
1498 		long			nX, nY;
1499 		long			nYTmp = 0L;
1500 		sal_Bool			bQ1 = sal_True;
1501 
1502 		for( nY = 0L; nY < Min( nHeight, 2L ); nY++, nYTmp++ )
1503 			for( nX = 0L, pQLine2 = !nY ? pErrQuad1 : pErrQuad2; nX < nWidth; nX++ )
1504 				pQLine2[ nX ] = pReadAcc->GetPixel( nYTmp, nX );
1505 
1506 		for( nY = 0L; nY < nHeight; nY++, nYTmp++ )
1507 		{
1508 			// erstes ZeilenPixel
1509 			aBestCol = pQLine1[ 0 ].ImplGetColor();
1510 			aBestCol.SetRed( ( aBestCol.GetRed() & 248 ) | 7 );
1511 			aBestCol.SetGreen( ( aBestCol.GetGreen() & 248 ) | 7 );
1512 			aBestCol.SetBlue( ( aBestCol.GetBlue() & 248 ) | 7 );
1513 			pWriteAcc->SetPixel( nY, 0, aBestCol );
1514 
1515 			for( nX = 1L; nX < nWidth1; nX++ )
1516 			{
1517 				aColor = pQLine1[ nX ].ImplGetColor();
1518 				aBestCol.SetRed( ( aColor.GetRed() & 248 ) | 7 );
1519 				aBestCol.SetGreen( ( aColor.GetGreen() & 248 ) | 7 );
1520 				aBestCol.SetBlue( ( aColor.GetBlue() & 248 ) | 7 );
1521 				aErrQuad = ( ImpErrorQuad( aColor ) -= aBestCol );
1522 				pQLine1[ ++nX ].ImplAddColorError7( aErrQuad );
1523 				pQLine2[ nX-- ].ImplAddColorError1( aErrQuad );
1524 				pQLine2[ nX-- ].ImplAddColorError5( aErrQuad );
1525 				pQLine2[ nX++ ].ImplAddColorError3( aErrQuad );
1526 				pWriteAcc->SetPixel( nY, nX, aBestCol );
1527 			}
1528 
1529 			// letztes ZeilenPixel
1530 			aBestCol = pQLine1[ nWidth1 ].ImplGetColor();
1531 			aBestCol.SetRed( ( aBestCol.GetRed() & 248 ) | 7 );
1532 			aBestCol.SetGreen( ( aBestCol.GetGreen() & 248 ) | 7 );
1533 			aBestCol.SetBlue( ( aBestCol.GetBlue() & 248 ) | 7 );
1534 			pWriteAcc->SetPixel( nY, nX, aBestCol );
1535 
1536 			// Zeilenpuffer neu fuellen/kopieren
1537 			pQLine1 = pQLine2;
1538 			pQLine2 = ( bQ1 = !bQ1 ) != sal_False ? pErrQuad2 : pErrQuad1;
1539 
1540 			if( nYTmp < nHeight )
1541 				for( nX = 0L; nX < nWidth; nX++ )
1542 					pQLine2[ nX ] = pReadAcc->GetPixel( nYTmp, nX );
1543 		}
1544 
1545 		// Zeilenpuffer zerstoeren
1546 		delete[] pErrQuad1;
1547 		delete[] pErrQuad2;
1548 		bRet = sal_True;
1549 	}
1550 
1551 	ReleaseAccess( pReadAcc );
1552 	aNewBmp.ReleaseAccess( pWriteAcc );
1553 
1554 	if( bRet )
1555 	{
1556 		const MapMode	aMap( maPrefMapMode );
1557 		const Size		aSize( maPrefSize );
1558 
1559 		*this = aNewBmp;
1560 
1561 		maPrefMapMode = aMap;
1562 		maPrefSize = aSize;
1563 	}
1564 
1565 	return bRet;
1566 }
1567 
1568 // ------------------------------------------------------------------------
1569 
1570 sal_Bool Bitmap::ReduceColors( sal_uInt16 nColorCount, BmpReduce eReduce )
1571 {
1572 	sal_Bool bRet;
1573 
1574 	if( GetColorCount() <= (sal_uLong) nColorCount )
1575 		bRet = sal_True;
1576 	else if( nColorCount )
1577 	{
1578 		if( BMP_REDUCE_SIMPLE == eReduce )
1579 			bRet = ImplReduceSimple( nColorCount );
1580 		else if( BMP_REDUCE_POPULAR == eReduce )
1581 			bRet = ImplReducePopular( nColorCount );
1582 		else
1583 			bRet = ImplReduceMedian( nColorCount );
1584 	}
1585 	else
1586 		bRet = sal_False;
1587 
1588 	return bRet;
1589 }
1590 
1591 // ------------------------------------------------------------------------
1592 
1593 sal_Bool Bitmap::ImplReduceSimple( sal_uInt16 nColorCount )
1594 {
1595 	Bitmap				aNewBmp;
1596 	BitmapReadAccess*	pRAcc = AcquireReadAccess();
1597 	const sal_uInt16		nColCount = Min( nColorCount, (sal_uInt16) 256 );
1598 	sal_uInt16				nBitCount;
1599 	sal_Bool				bRet = sal_False;
1600 
1601 	if( nColCount <= 2 )
1602 		nBitCount = 1;
1603 	else if( nColCount <= 16 )
1604 		nBitCount = 4;
1605 	else
1606 		nBitCount = 8;
1607 
1608 	if( pRAcc )
1609 	{
1610 		Octree					aOct( *pRAcc, nColCount );
1611 		const BitmapPalette&	rPal = aOct.GetPalette();
1612 		BitmapWriteAccess*		pWAcc;
1613 
1614 		aNewBmp = Bitmap( GetSizePixel(), nBitCount, &rPal );
1615 		pWAcc = aNewBmp.AcquireWriteAccess();
1616 
1617 		if( pWAcc )
1618 		{
1619 			const long nWidth = pRAcc->Width();
1620 			const long nHeight = pRAcc->Height();
1621 
1622 			if( pRAcc->HasPalette() )
1623 			{
1624 				for( long nY = 0L; nY < nHeight; nY++ )
1625 					for( long nX =0L; nX < nWidth; nX++ )
1626 						pWAcc->SetPixel( nY, nX, (sal_uInt8) aOct.GetBestPaletteIndex( pRAcc->GetPaletteColor( pRAcc->GetPixel( nY, nX ) ) ) );
1627 			}
1628 			else
1629 			{
1630 				for( long nY = 0L; nY < nHeight; nY++ )
1631 					for( long nX =0L; nX < nWidth; nX++ )
1632 						pWAcc->SetPixel( nY, nX, (sal_uInt8) aOct.GetBestPaletteIndex( pRAcc->GetPixel( nY, nX ) ) );
1633 			}
1634 
1635 			aNewBmp.ReleaseAccess( pWAcc );
1636 			bRet = sal_True;
1637 		}
1638 
1639 		ReleaseAccess( pRAcc );
1640 	}
1641 
1642 	if( bRet )
1643 	{
1644 		const MapMode	aMap( maPrefMapMode );
1645 		const Size		aSize( maPrefSize );
1646 
1647 		*this = aNewBmp;
1648 		maPrefMapMode = aMap;
1649 		maPrefSize = aSize;
1650 	}
1651 
1652 	return bRet;
1653 }
1654 
1655 // ------------------------------------------------------------------------
1656 
1657 struct PopularColorCount
1658 {
1659 	sal_uInt32	mnIndex;
1660 	sal_uInt32	mnCount;
1661 };
1662 
1663 // ------------------------------------------------------------------------
1664 
1665 extern "C" int __LOADONCALLAPI ImplPopularCmpFnc( const void* p1, const void* p2 )
1666 {
1667 	int nRet;
1668 
1669 	if( ( (PopularColorCount*) p1 )->mnCount < ( (PopularColorCount*) p2 )->mnCount )
1670 		nRet = 1;
1671 	else if( ( (PopularColorCount*) p1 )->mnCount == ( (PopularColorCount*) p2 )->mnCount )
1672 		nRet = 0;
1673 	else
1674 		nRet = -1;
1675 
1676 	return nRet;
1677 }
1678 
1679 // ------------------------------------------------------------------------
1680 
1681 sal_Bool Bitmap::ImplReducePopular( sal_uInt16 nColCount )
1682 {
1683 	BitmapReadAccess*	pRAcc = AcquireReadAccess();
1684 	sal_uInt16				nBitCount;
1685 	sal_Bool				bRet = sal_False;
1686 
1687 	if( nColCount > 256 )
1688 		nColCount = 256;
1689 
1690 	if( nColCount < 17 )
1691 		nBitCount = 4;
1692 	else
1693 		nBitCount = 8;
1694 
1695 	if( pRAcc )
1696 	{
1697 		const sal_uInt32	nValidBits = 4;
1698 		const sal_uInt32	nRightShiftBits = 8 - nValidBits;
1699 		const sal_uInt32	nLeftShiftBits1 = nValidBits;
1700 		const sal_uInt32	nLeftShiftBits2 = nValidBits << 1;
1701 		const sal_uInt32	nColorsPerComponent = 1 << nValidBits;
1702 		const sal_uInt32	nColorOffset = 256 / nColorsPerComponent;
1703 		const sal_uInt32	nTotalColors = nColorsPerComponent * nColorsPerComponent * nColorsPerComponent;
1704 		const long			nWidth = pRAcc->Width();
1705 		const long			nHeight = pRAcc->Height();
1706 		PopularColorCount*	pCountTable = new PopularColorCount[ nTotalColors ];
1707 		long				nX, nY, nR, nG, nB, nIndex;
1708 
1709 		rtl_zeroMemory( pCountTable, nTotalColors * sizeof( PopularColorCount ) );
1710 
1711 		for( nR = 0, nIndex = 0; nR < 256; nR += nColorOffset )
1712         {
1713 			for( nG = 0; nG < 256; nG += nColorOffset )
1714             {
1715 				for( nB = 0; nB < 256; nB += nColorOffset )
1716                 {
1717 					pCountTable[ nIndex ].mnIndex = nIndex;
1718                     nIndex++;
1719                 }
1720             }
1721         }
1722 
1723 		if( pRAcc->HasPalette() )
1724 		{
1725 			for( nY = 0L; nY < nHeight; nY++ )
1726 			{
1727 				for( nX = 0L; nX < nWidth; nX++ )
1728 				{
1729 					const BitmapColor& rCol = pRAcc->GetPaletteColor( pRAcc->GetPixel( nY, nX ) );
1730 					pCountTable[ ( ( ( (sal_uInt32) rCol.GetRed() ) >> nRightShiftBits ) << nLeftShiftBits2 ) |
1731 								 ( ( ( (sal_uInt32) rCol.GetGreen() ) >> nRightShiftBits ) << nLeftShiftBits1 ) |
1732 								 ( ( (sal_uInt32) rCol.GetBlue() ) >> nRightShiftBits ) ].mnCount++;
1733 				}
1734 			}
1735 		}
1736 		else
1737 		{
1738 			for( nY = 0L; nY < nHeight; nY++ )
1739 			{
1740 				for( nX = 0L; nX < nWidth; nX++ )
1741 				{
1742 					const BitmapColor aCol( pRAcc->GetPixel( nY, nX ) );
1743 					pCountTable[ ( ( ( (sal_uInt32) aCol.GetRed() ) >> nRightShiftBits ) << nLeftShiftBits2 ) |
1744 								 ( ( ( (sal_uInt32) aCol.GetGreen() ) >> nRightShiftBits ) << nLeftShiftBits1 ) |
1745 								 ( ( (sal_uInt32) aCol.GetBlue() ) >> nRightShiftBits ) ].mnCount++;
1746 				}
1747 			}
1748 		}
1749 
1750 		BitmapPalette aNewPal( nColCount );
1751 
1752 		qsort( pCountTable, nTotalColors, sizeof( PopularColorCount ), ImplPopularCmpFnc );
1753 
1754 		for( sal_uInt16 n = 0; n < nColCount; n++ )
1755 		{
1756 			const PopularColorCount& rPop = pCountTable[ n ];
1757 			aNewPal[ n ] = BitmapColor( (sal_uInt8) ( ( rPop.mnIndex >> nLeftShiftBits2 ) << nRightShiftBits ),
1758 										(sal_uInt8) ( ( ( rPop.mnIndex >> nLeftShiftBits1 ) & ( nColorsPerComponent - 1 ) ) << nRightShiftBits ),
1759 										(sal_uInt8) ( ( rPop.mnIndex & ( nColorsPerComponent - 1 ) ) << nRightShiftBits ) );
1760 		}
1761 
1762 		Bitmap				aNewBmp( GetSizePixel(), nBitCount, &aNewPal );
1763 		BitmapWriteAccess*	pWAcc = aNewBmp.AcquireWriteAccess();
1764 
1765 		if( pWAcc )
1766 		{
1767 			BitmapColor	aDstCol( (sal_uInt8) 0 );
1768 			sal_uInt8*		pIndexMap = new sal_uInt8[ nTotalColors ];
1769 
1770 			for( nR = 0, nIndex = 0; nR < 256; nR += nColorOffset )
1771 				for( nG = 0; nG < 256; nG += nColorOffset )
1772 					for( nB = 0; nB < 256; nB += nColorOffset )
1773 						pIndexMap[ nIndex++ ] = (sal_uInt8) aNewPal.GetBestIndex( BitmapColor( (sal_uInt8) nR, (sal_uInt8) nG, (sal_uInt8) nB ) );
1774 
1775 			if( pRAcc->HasPalette() )
1776 			{
1777 				for( nY = 0L; nY < nHeight; nY++ )
1778 				{
1779 					for( nX = 0L; nX < nWidth; nX++ )
1780 					{
1781 						const BitmapColor& rCol = pRAcc->GetPaletteColor( pRAcc->GetPixel( nY, nX ) );
1782 						aDstCol.SetIndex( pIndexMap[ ( ( ( (sal_uInt32) rCol.GetRed() ) >> nRightShiftBits ) << nLeftShiftBits2 ) |
1783 													 ( ( ( (sal_uInt32) rCol.GetGreen() ) >> nRightShiftBits ) << nLeftShiftBits1 ) |
1784 													 ( ( (sal_uInt32) rCol.GetBlue() ) >> nRightShiftBits ) ] );
1785 						pWAcc->SetPixel( nY, nX, aDstCol );
1786 					}
1787 				}
1788 			}
1789 			else
1790 			{
1791 				for( nY = 0L; nY < nHeight; nY++ )
1792 				{
1793 					for( nX = 0L; nX < nWidth; nX++ )
1794 					{
1795 						const BitmapColor aCol( pRAcc->GetPixel( nY, nX ) );
1796 						aDstCol.SetIndex( pIndexMap[ ( ( ( (sal_uInt32) aCol.GetRed() ) >> nRightShiftBits ) << nLeftShiftBits2 ) |
1797 													 ( ( ( (sal_uInt32) aCol.GetGreen() ) >> nRightShiftBits ) << nLeftShiftBits1 ) |
1798 													 ( ( (sal_uInt32) aCol.GetBlue() ) >> nRightShiftBits ) ] );
1799 						pWAcc->SetPixel( nY, nX, aDstCol );
1800 					}
1801 				}
1802 			}
1803 
1804 			delete[] pIndexMap;
1805 			aNewBmp.ReleaseAccess( pWAcc );
1806 			bRet = sal_True;
1807 		}
1808 
1809 		delete[] pCountTable;
1810 		ReleaseAccess( pRAcc );
1811 
1812 		if( bRet )
1813 		{
1814 			const MapMode	aMap( maPrefMapMode );
1815 			const Size		aSize( maPrefSize );
1816 
1817 			*this = aNewBmp;
1818 			maPrefMapMode = aMap;
1819 			maPrefSize = aSize;
1820 		}
1821 	}
1822 
1823 	return bRet;
1824 }
1825 
1826 // ------------------------------------------------------------------------
1827 
1828 sal_Bool Bitmap::ImplReduceMedian( sal_uInt16 nColCount )
1829 {
1830 	BitmapReadAccess*	pRAcc = AcquireReadAccess();
1831 	sal_uInt16				nBitCount;
1832 	sal_Bool				bRet = sal_False;
1833 
1834 	if( nColCount < 17 )
1835 		nBitCount = 4;
1836 	else if( nColCount < 257 )
1837 		nBitCount = 8;
1838 	else
1839 	{
1840 		DBG_ERROR( "Bitmap::ImplReduceMedian(): invalid color count!" );
1841 		nBitCount = 8;
1842 		nColCount = 256;
1843 	}
1844 
1845 	if( pRAcc )
1846 	{
1847 		Bitmap				aNewBmp( GetSizePixel(), nBitCount );
1848 		BitmapWriteAccess*	pWAcc = aNewBmp.AcquireWriteAccess();
1849 
1850 		if( pWAcc )
1851 		{
1852 			const sal_uLong	nSize = 32768UL * sizeof( sal_uLong );
1853 			sal_uLong*		pColBuf = (sal_uLong*) rtl_allocateMemory( nSize );
1854 			const long	nWidth = pWAcc->Width();
1855 			const long	nHeight = pWAcc->Height();
1856 			long		nIndex = 0L;
1857 
1858 			memset( (HPBYTE) pColBuf, 0, nSize );
1859 
1860 			// create Buffer
1861 			if( pRAcc->HasPalette() )
1862 			{
1863 				for( long nY = 0L; nY < nHeight; nY++ )
1864 				{
1865 					for( long nX = 0L; nX < nWidth; nX++ )
1866 					{
1867 						const BitmapColor& rCol = pRAcc->GetPaletteColor( pRAcc->GetPixel( nY, nX ) );
1868 						pColBuf[ RGB15( rCol.GetRed() >> 3, rCol.GetGreen() >> 3, rCol.GetBlue() >> 3 ) ]++;
1869 					}
1870 				}
1871 			}
1872 			else
1873 			{
1874 				for( long nY = 0L; nY < nHeight; nY++ )
1875 				{
1876 					for( long nX = 0L; nX < nWidth; nX++ )
1877 					{
1878 						const BitmapColor aCol( pRAcc->GetPixel( nY, nX ) );
1879 						pColBuf[ RGB15( aCol.GetRed() >> 3, aCol.GetGreen() >> 3, aCol.GetBlue() >> 3 ) ]++;
1880 					}
1881 				}
1882 			}
1883 
1884 			// create palette via median cut
1885 			BitmapPalette aPal( pWAcc->GetPaletteEntryCount() );
1886 			ImplMedianCut( pColBuf, aPal, 0, 31, 0, 31, 0, 31,
1887 						   nColCount, nWidth * nHeight, nIndex );
1888 
1889 			// do mapping of colors to palette
1890 			InverseColorMap aMap( aPal );
1891 			pWAcc->SetPalette( aPal );
1892 			for( long nY = 0L; nY < nHeight; nY++ )
1893 				for( long nX = 0L; nX < nWidth; nX++ )
1894 					pWAcc->SetPixel( nY, nX, (sal_uInt8) aMap.GetBestPaletteIndex( pRAcc->GetColor( nY, nX ) ) );
1895 
1896 			rtl_freeMemory( pColBuf );
1897 			aNewBmp.ReleaseAccess( pWAcc );
1898 			bRet = sal_True;
1899 		}
1900 
1901 		ReleaseAccess( pRAcc );
1902 
1903 		if( bRet )
1904 		{
1905 			const MapMode	aMap( maPrefMapMode );
1906 			const Size		aSize( maPrefSize );
1907 
1908 			*this = aNewBmp;
1909 			maPrefMapMode = aMap;
1910 			maPrefSize = aSize;
1911 		}
1912 	}
1913 
1914 	return bRet;
1915 }
1916 
1917 // ------------------------------------------------------------------------
1918 
1919 void Bitmap::ImplMedianCut( sal_uLong* pColBuf, BitmapPalette& rPal,
1920 							long nR1, long nR2, long nG1, long nG2, long nB1, long nB2,
1921 							long nColors, long nPixels, long& rIndex )
1922 {
1923 	if( !nPixels )
1924 		return;
1925 
1926 	BitmapColor	aCol;
1927 	const long	nRLen = nR2 - nR1;
1928 	const long	nGLen = nG2 - nG1;
1929 	const long	nBLen = nB2 - nB1;
1930 	long 		nR, nG, nB;
1931 	sal_uLong*		pBuf = pColBuf;
1932 
1933 	if( !nRLen && !nGLen && !nBLen )
1934 	{
1935 		if( pBuf[ RGB15( nR1, nG1, nB1 ) ] )
1936 		{
1937 			aCol.SetRed( (sal_uInt8) ( nR1 << 3 ) );
1938 			aCol.SetGreen( (sal_uInt8) ( nG1 << 3 ) );
1939 			aCol.SetBlue( (sal_uInt8) ( nB1 << 3 ) );
1940 			rPal[ (sal_uInt16) rIndex++ ] = aCol;
1941 		}
1942 	}
1943 	else
1944 	{
1945 		if( 1 == nColors || 1 == nPixels )
1946 		{
1947 			long nPixSum = 0, nRSum = 0, nGSum = 0, nBSum = 0;
1948 
1949 			for( nR = nR1; nR <= nR2; nR++ )
1950 			{
1951 				for( nG = nG1; nG <= nG2; nG++ )
1952 				{
1953 					for( nB = nB1; nB <= nB2; nB++ )
1954 					{
1955 						nPixSum = pBuf[ RGB15( nR, nG, nB ) ];
1956 
1957 						if( nPixSum )
1958 						{
1959 							nRSum += nR * nPixSum;
1960 							nGSum += nG * nPixSum;
1961 							nBSum += nB * nPixSum;
1962 						}
1963 					}
1964 				}
1965 			}
1966 
1967 			aCol.SetRed( (sal_uInt8) ( ( nRSum / nPixels ) << 3 ) );
1968 			aCol.SetGreen( (sal_uInt8) ( ( nGSum / nPixels ) << 3 ) );
1969 			aCol.SetBlue( (sal_uInt8) ( ( nBSum / nPixels ) << 3 ) );
1970 			rPal[ (sal_uInt16) rIndex++ ] = aCol;
1971 		}
1972 		else
1973 		{
1974 			const long	nTest = ( nPixels >> 1 );
1975 			long		nPixOld = 0;
1976 			long		nPixNew = 0;
1977 
1978 			if( nBLen > nGLen && nBLen > nRLen )
1979 			{
1980 				nB = nB1 - 1;
1981 
1982 				while( nPixNew < nTest )
1983 				{
1984 					nB++, nPixOld = nPixNew;
1985 					for( nR = nR1; nR <= nR2; nR++ )
1986 						for( nG = nG1; nG <= nG2; nG++ )
1987 							nPixNew += pBuf[ RGB15( nR, nG, nB ) ];
1988 				}
1989 
1990 				if( nB < nB2 )
1991 				{
1992 					ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG2, nB1, nB, nColors >> 1, nPixNew, rIndex );
1993 					ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG2, nB + 1, nB2, nColors >> 1, nPixels - nPixNew, rIndex );
1994 				}
1995 				else
1996 				{
1997 					ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG2, nB1, nB - 1, nColors >> 1, nPixOld, rIndex );
1998 					ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG2, nB, nB2, nColors >> 1, nPixels - nPixOld, rIndex );
1999 				}
2000 			}
2001 			else if( nGLen > nRLen )
2002 			{
2003 				nG = nG1 - 1;
2004 
2005 				while( nPixNew < nTest )
2006 				{
2007 					nG++, nPixOld = nPixNew;
2008 					for( nR = nR1; nR <= nR2; nR++ )
2009 						for( nB = nB1; nB <= nB2; nB++ )
2010 							nPixNew += pBuf[ RGB15( nR, nG, nB ) ];
2011 				}
2012 
2013 				if( nG < nG2 )
2014 				{
2015 					ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG, nB1, nB2, nColors >> 1, nPixNew, rIndex );
2016 					ImplMedianCut( pBuf, rPal, nR1, nR2, nG + 1, nG2, nB1, nB2, nColors >> 1, nPixels - nPixNew, rIndex );
2017 				}
2018 				else
2019 				{
2020 					ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG - 1, nB1, nB2, nColors >> 1, nPixOld, rIndex );
2021 					ImplMedianCut( pBuf, rPal, nR1, nR2, nG, nG2, nB1, nB2, nColors >> 1, nPixels - nPixOld, rIndex );
2022 				}
2023 			}
2024 			else
2025 			{
2026 				nR = nR1 - 1;
2027 
2028 				while( nPixNew < nTest )
2029 				{
2030 					nR++, nPixOld = nPixNew;
2031 					for( nG = nG1; nG <= nG2; nG++ )
2032 						for( nB = nB1; nB <= nB2; nB++ )
2033 							nPixNew += pBuf[ RGB15( nR, nG, nB ) ];
2034 				}
2035 
2036 				if( nR < nR2 )
2037 				{
2038 					ImplMedianCut( pBuf, rPal, nR1, nR, nG1, nG2, nB1, nB2, nColors >> 1, nPixNew, rIndex );
2039 					ImplMedianCut( pBuf, rPal, nR1 + 1, nR2, nG1, nG2, nB1, nB2, nColors >> 1, nPixels - nPixNew, rIndex );
2040 				}
2041 				else
2042 				{
2043 					ImplMedianCut( pBuf, rPal, nR1, nR - 1, nG1, nG2, nB1, nB2, nColors >> 1, nPixOld, rIndex );
2044 					ImplMedianCut( pBuf, rPal, nR, nR2, nG1, nG2, nB1, nB2, nColors >> 1, nPixels - nPixOld, rIndex );
2045 				}
2046 			}
2047 		}
2048 	}
2049 }
2050 
2051 // ------------------------------------------------------------------------
2052 
2053 sal_Bool Bitmap::Vectorize( PolyPolygon& rPolyPoly, sal_uLong nFlags, const Link* pProgress )
2054 {
2055 	return ImplVectorizer().ImplVectorize( *this, rPolyPoly, nFlags, pProgress );
2056 }
2057 
2058 // ------------------------------------------------------------------------
2059 
2060 sal_Bool Bitmap::Vectorize( GDIMetaFile& rMtf, sal_uInt8 cReduce, sal_uLong nFlags, const Link* pProgress )
2061 {
2062 	return ImplVectorizer().ImplVectorize( *this, rMtf, cReduce, nFlags, pProgress );
2063 }
2064 
2065 // ------------------------------------------------------------------------
2066 
2067 sal_Bool Bitmap::Adjust( short nLuminancePercent, short nContrastPercent,
2068 					 short nChannelRPercent, short nChannelGPercent, short nChannelBPercent,
2069 					 double fGamma, sal_Bool bInvert )
2070 {
2071 	sal_Bool bRet = sal_False;
2072 
2073 	// nothing to do => return quickly
2074 	if( !nLuminancePercent && !nContrastPercent &&
2075 		!nChannelRPercent && !nChannelGPercent && !nChannelBPercent &&
2076 		( fGamma == 1.0 ) && !bInvert )
2077 	{
2078 		bRet = sal_True;
2079 	}
2080 	else
2081 	{
2082 		BitmapWriteAccess* pAcc = AcquireWriteAccess();
2083 
2084 		if( pAcc )
2085 		{
2086 			BitmapColor		aCol;
2087 			const long		nW = pAcc->Width();
2088 			const long		nH = pAcc->Height();
2089 			sal_uInt8*			cMapR = new sal_uInt8[ 256 ];
2090 			sal_uInt8*			cMapG = new sal_uInt8[ 256 ];
2091 			sal_uInt8*			cMapB = new sal_uInt8[ 256 ];
2092 			long			nX, nY;
2093 			double			fM, fROff, fGOff, fBOff, fOff;
2094 
2095 			// calculate slope
2096 			if( nContrastPercent >= 0 )
2097 				fM = 128.0 / ( 128.0 - 1.27 * MinMax( nContrastPercent, 0L, 100L ) );
2098 			else
2099 				fM = ( 128.0 + 1.27 * MinMax( nContrastPercent, -100L, 0L ) ) / 128.0;
2100 
2101 			// total offset = luminance offset + contrast offset
2102 			fOff = MinMax( nLuminancePercent, -100L, 100L ) * 2.55 + 128.0 - fM * 128.0;
2103 
2104 			// channel offset = channel offset  + total offset
2105 			fROff = nChannelRPercent * 2.55 + fOff;
2106 			fGOff = nChannelGPercent * 2.55 + fOff;
2107 			fBOff = nChannelBPercent * 2.55 + fOff;
2108 
2109 			// calculate gamma value
2110 			fGamma = ( fGamma <= 0.0 || fGamma > 10.0 ) ? 1.0 : ( 1.0 / fGamma );
2111 			const sal_Bool bGamma = ( fGamma != 1.0 );
2112 
2113 			// create mapping table
2114 			for( nX = 0L; nX < 256L; nX++ )
2115 			{
2116 				cMapR[ nX ] = (sal_uInt8) MinMax( FRound( nX * fM + fROff ), 0L, 255L );
2117 				cMapG[ nX ] = (sal_uInt8) MinMax( FRound( nX * fM + fGOff ), 0L, 255L );
2118 				cMapB[ nX ] = (sal_uInt8) MinMax( FRound( nX * fM + fBOff ), 0L, 255L );
2119 
2120 				if( bGamma )
2121 				{
2122 					cMapR[ nX ] = GAMMA( cMapR[ nX ], fGamma );
2123 					cMapG[ nX ] = GAMMA( cMapG[ nX ], fGamma );
2124 					cMapB[ nX ] = GAMMA( cMapB[ nX ], fGamma );
2125 				}
2126 
2127 				if( bInvert )
2128 				{
2129 					cMapR[ nX ] = ~cMapR[ nX ];
2130 					cMapG[ nX ] = ~cMapG[ nX ];
2131 					cMapB[ nX ] = ~cMapB[ nX ];
2132 				}
2133 			}
2134 
2135 			// do modifying
2136 			if( pAcc->HasPalette() )
2137 			{
2138 				BitmapColor aNewCol;
2139 
2140 				for( sal_uInt16 i = 0, nCount = pAcc->GetPaletteEntryCount(); i < nCount; i++ )
2141 				{
2142 					const BitmapColor& rCol = pAcc->GetPaletteColor( i );
2143 					aNewCol.SetRed( cMapR[ rCol.GetRed() ] );
2144 					aNewCol.SetGreen( cMapG[ rCol.GetGreen() ] );
2145 					aNewCol.SetBlue( cMapB[ rCol.GetBlue() ] );
2146 					pAcc->SetPaletteColor( i, aNewCol );
2147 				}
2148 			}
2149 			else if( pAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_BGR )
2150 			{
2151 				for( nY = 0L; nY < nH; nY++ )
2152 				{
2153 					Scanline pScan = pAcc->GetScanline( nY );
2154 
2155 					for( nX = 0L; nX < nW; nX++ )
2156 					{
2157 						*pScan = cMapB[ *pScan ]; pScan++;
2158 						*pScan = cMapG[ *pScan ]; pScan++;
2159 						*pScan = cMapR[ *pScan ]; pScan++;
2160 					}
2161 				}
2162 			}
2163 			else if( pAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_RGB )
2164 			{
2165 				for( nY = 0L; nY < nH; nY++ )
2166 				{
2167 					Scanline pScan = pAcc->GetScanline( nY );
2168 
2169 					for( nX = 0L; nX < nW; nX++ )
2170 					{
2171 						*pScan = cMapR[ *pScan ]; pScan++;
2172 						*pScan = cMapG[ *pScan ]; pScan++;
2173 						*pScan = cMapB[ *pScan ]; pScan++;
2174 					}
2175 				}
2176 			}
2177 			else
2178 			{
2179 				for( nY = 0L; nY < nH; nY++ )
2180 				{
2181 					for( nX = 0L; nX < nW; nX++ )
2182 					{
2183 						aCol = pAcc->GetPixel( nY, nX );
2184 						aCol.SetRed( cMapR[ aCol.GetRed() ] );
2185 						aCol.SetGreen( cMapG[ aCol.GetGreen() ] );
2186 						aCol.SetBlue( cMapB[ aCol.GetBlue() ] );
2187 						pAcc->SetPixel( nY, nX, aCol );
2188 					}
2189 				}
2190 			}
2191 
2192 			delete[] cMapR;
2193 			delete[] cMapG;
2194 			delete[] cMapB;
2195 			ReleaseAccess( pAcc );
2196 			bRet = sal_True;
2197 		}
2198 	}
2199 
2200 	return bRet;
2201 }
2202