xref: /aoo41x/main/vcl/source/gdi/bitmap3.cxx (revision 87bc88d3)
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 						const sal_uInt8 cIndex = pReadAcc->GetPixelIndex( nY, nX );
387 						if( pReadAcc->GetPaletteColor( cIndex ).GetLuminance() >=
388 							cThreshold )
389 						{
390 							pWriteAcc->SetPixel( nY, nX, aWhite );
391 						}
392 						else
393 							pWriteAcc->SetPixel( nY, nX, aBlack );
394 					}
395 				}
396 			}
397 			else
398 			{
399 				for( long nY = 0L; nY < nHeight; nY++ )
400 				{
401 					for( long nX = 0L; nX < nWidth; nX++ )
402 					{
403 						if( pReadAcc->GetPixel( nY, nX ).GetLuminance() >=
404 							cThreshold )
405 						{
406 							pWriteAcc->SetPixel( nY, nX, aWhite );
407 						}
408 						else
409 							pWriteAcc->SetPixel( nY, nX, aBlack );
410 					}
411 				}
412 			}
413 
414 			aNewBmp.ReleaseAccess( pWriteAcc );
415 			bRet = sal_True;
416 		}
417 
418 		ReleaseAccess( pReadAcc );
419 
420 		if( bRet )
421 		{
422 			const MapMode	aMap( maPrefMapMode );
423 			const Size		aSize( maPrefSize );
424 
425 			*this = aNewBmp;
426 
427 			maPrefMapMode = aMap;
428 			maPrefSize = aSize;
429 		}
430 	}
431 
432 	return bRet;
433 }
434 
435 // ------------------------------------------------------------------------
436 
437 sal_Bool Bitmap::ImplMakeMonoDither()
438 {
439 	BitmapReadAccess*	pReadAcc = AcquireReadAccess();
440 	sal_Bool				bRet = sal_False;
441 
442 	if( pReadAcc )
443 	{
444 		Bitmap				aNewBmp( GetSizePixel(), 1 );
445 		BitmapWriteAccess*	pWriteAcc = aNewBmp.AcquireWriteAccess();
446 
447 		if( pWriteAcc )
448 		{
449 			const BitmapColor	aBlack( pWriteAcc->GetBestMatchingColor( Color( COL_BLACK ) ) );
450 			const BitmapColor	aWhite( pWriteAcc->GetBestMatchingColor( Color( COL_WHITE ) ) );
451 			const long			nWidth = pWriteAcc->Width();
452 			const long			nHeight = pWriteAcc->Height();
453 			sal_uInt8				pDitherMatrix[ 16 ][ 16 ];
454 
455 			ImplCreateDitherMatrix( &pDitherMatrix );
456 
457 			if( pReadAcc->HasPalette() )
458 			{
459 				for( long nY = 0L; nY < nHeight; nY++ )
460 				{
461 					for( long nX = 0L, nModY = nY % 16; nX < nWidth; nX++ )
462 					{
463 						const sal_uInt8 cIndex = pReadAcc->GetPixelIndex( nY, nX );
464 						if( pReadAcc->GetPaletteColor( cIndex ).GetLuminance() >
465 							pDitherMatrix[ nModY ][ nX % 16 ] )
466 						{
467 							pWriteAcc->SetPixel( nY, nX, aWhite );
468 						}
469 						else
470 							pWriteAcc->SetPixel( nY, nX, aBlack );
471 					}
472 				}
473 			}
474 			else
475 			{
476 				for( long nY = 0L; nY < nHeight; nY++ )
477 				{
478 					for( long nX = 0L, nModY = nY % 16; nX < nWidth; nX++ )
479 					{
480 						if( pReadAcc->GetPixel( nY, nX ).GetLuminance() >
481 							pDitherMatrix[ nModY ][ nX % 16 ]  )
482 						{
483 							pWriteAcc->SetPixel( nY, nX, aWhite );
484 						}
485 						else
486 							pWriteAcc->SetPixel( nY, nX, aBlack );
487 					}
488 				}
489 			}
490 
491 			aNewBmp.ReleaseAccess( pWriteAcc );
492 			bRet = sal_True;
493 		}
494 
495 		ReleaseAccess( pReadAcc );
496 
497 		if( bRet )
498 		{
499 			const MapMode	aMap( maPrefMapMode );
500 			const Size		aSize( maPrefSize );
501 
502 			*this = aNewBmp;
503 
504 			maPrefMapMode = aMap;
505 			maPrefSize = aSize;
506 		}
507 	}
508 
509 	return bRet;
510 }
511 
512 // ------------------------------------------------------------------------
513 
514 sal_Bool Bitmap::ImplMakeGreyscales( sal_uInt16 nGreys )
515 {
516 	DBG_ASSERT( nGreys == 16 || nGreys == 256, "Only 16 or 256 greyscales are supported!" );
517 
518 	BitmapReadAccess*	pReadAcc = AcquireReadAccess();
519 	sal_Bool				bRet = sal_False;
520 
521 	if( pReadAcc )
522 	{
523 		const BitmapPalette&	rPal = GetGreyPalette( nGreys );
524 		sal_uLong 					nShift = ( ( nGreys == 16 ) ? 4UL : 0UL );
525 		sal_Bool					bPalDiffers = !pReadAcc->HasPalette() || ( rPal.GetEntryCount() != pReadAcc->GetPaletteEntryCount() );
526 
527 		if( !bPalDiffers )
528 			bPalDiffers = ( (BitmapPalette&) rPal != pReadAcc->GetPalette() );
529 
530 		if( bPalDiffers )
531 		{
532 			Bitmap				aNewBmp( GetSizePixel(), ( nGreys == 16 ) ? 4 : 8, &rPal );
533 			BitmapWriteAccess*	pWriteAcc = aNewBmp.AcquireWriteAccess();
534 
535 			if( pWriteAcc )
536 			{
537 				const long	nWidth = pWriteAcc->Width();
538 				const long	nHeight = pWriteAcc->Height();
539 
540 				if( pReadAcc->HasPalette() )
541 				{
542 					for( long nY = 0L; nY < nHeight; nY++ )
543 					{
544 						for( long nX = 0L; nX < nWidth; nX++ )
545 						{
546 							const sal_uInt8 cIndex = pReadAcc->GetPixelIndex( nY, nX );
547 							pWriteAcc->SetPixelIndex( nY, nX,
548 								(pReadAcc->GetPaletteColor( cIndex ).GetLuminance() >> nShift) );
549 						}
550 					}
551 				}
552 				else if( pReadAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_BGR &&
553 						 pWriteAcc->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL )
554 				{
555 					nShift += 8;
556 
557 					for( long nY = 0L; nY < nHeight; nY++ )
558 					{
559 						Scanline pReadScan = pReadAcc->GetScanline( nY );
560 						Scanline pWriteScan = pWriteAcc->GetScanline( nY );
561 
562 						for( long nX = 0L; nX < nWidth; nX++ )
563 						{
564 							const sal_uLong nB = *pReadScan++;
565 							const sal_uLong nG = *pReadScan++;
566 							const sal_uLong nR = *pReadScan++;
567 
568 							*pWriteScan++ = (sal_uInt8) ( ( nB * 28UL + nG * 151UL + nR * 77UL ) >> nShift );
569 						}
570 					}
571 				}
572 				else if( pReadAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_RGB &&
573 						 pWriteAcc->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL )
574 				{
575 					nShift += 8;
576 
577 					for( long nY = 0L; nY < nHeight; nY++ )
578 					{
579 						Scanline pReadScan = pReadAcc->GetScanline( nY );
580 						Scanline pWriteScan = pWriteAcc->GetScanline( nY );
581 
582 						for( long nX = 0L; nX < nWidth; nX++ )
583 						{
584 							const sal_uLong nR = *pReadScan++;
585 							const sal_uLong nG = *pReadScan++;
586 							const sal_uLong nB = *pReadScan++;
587 
588 							*pWriteScan++ = (sal_uInt8) ( ( nB * 28UL + nG * 151UL + nR * 77UL ) >> nShift );
589 						}
590 					}
591 				}
592 				else
593 				{
594 					for( long nY = 0L; nY < nHeight; nY++ )
595 						for( long nX = 0L; nX < nWidth; nX++ )
596 							pWriteAcc->SetPixelIndex( nY, nX, (pReadAcc->GetPixel( nY, nX ) ).GetLuminance() >> nShift );
597 				}
598 
599 				aNewBmp.ReleaseAccess( pWriteAcc );
600 				bRet = sal_True;
601 			}
602 
603 			ReleaseAccess( pReadAcc );
604 
605 			if( bRet )
606 			{
607 				const MapMode	aMap( maPrefMapMode );
608 				const Size		aSize( maPrefSize );
609 
610 				*this = aNewBmp;
611 
612 				maPrefMapMode = aMap;
613 				maPrefSize = aSize;
614 			}
615 		}
616 		else
617 		{
618 			ReleaseAccess( pReadAcc );
619 			bRet = sal_True;
620 		}
621 	}
622 
623 	return bRet;
624 }
625 
626 // ------------------------------------------------------------------------
627 
628 sal_Bool Bitmap::ImplConvertUp( sal_uInt16 nBitCount, Color* pExtColor )
629 {
630 	DBG_ASSERT( nBitCount > GetBitCount(), "New BitCount must be greater!" );
631 
632 	BitmapReadAccess*	pReadAcc = AcquireReadAccess();
633 	sal_Bool				bRet = sal_False;
634 
635 	if( pReadAcc )
636 	{
637 		BitmapPalette		aPal;
638 		Bitmap				aNewBmp( GetSizePixel(), nBitCount, pReadAcc->HasPalette() ? &pReadAcc->GetPalette() : &aPal );
639 		BitmapWriteAccess*	pWriteAcc = aNewBmp.AcquireWriteAccess();
640 
641 		if( pWriteAcc )
642 		{
643 			const long	nWidth = pWriteAcc->Width();
644 			const long	nHeight = pWriteAcc->Height();
645 
646 			if( pWriteAcc->HasPalette() )
647 			{
648 				const sal_uInt16			nOldCount = 1 << GetBitCount();
649 				const BitmapPalette&	rOldPal = pReadAcc->GetPalette();
650 
651 				aPal.SetEntryCount( 1 << nBitCount );
652 
653 				for( sal_uInt16 i = 0; i < nOldCount; i++ )
654 					aPal[ i ] = rOldPal[ i ];
655 
656 				if( pExtColor )
657 					aPal[ aPal.GetEntryCount() - 1 ] = *pExtColor;
658 
659 				pWriteAcc->SetPalette( aPal );
660 
661 				for( long nY = 0L; nY < nHeight; nY++ )
662 					for( long nX = 0L; nX < nWidth; nX++ )
663 						pWriteAcc->SetPixel( nY, nX, pReadAcc->GetPixel( nY, nX ) );
664 			}
665 			else
666 			{
667 				if( pReadAcc->HasPalette() )
668 				{
669 					for( long nY = 0L; nY < nHeight; nY++ )
670 						for( long nX = 0L; nX < nWidth; nX++ )
671 							pWriteAcc->SetPixel( nY, nX, pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nY, nX ) ) );
672 				}
673 				else
674 				{
675 					for( long nY = 0L; nY < nHeight; nY++ )
676 						for( long nX = 0L; nX < nWidth; nX++ )
677 							pWriteAcc->SetPixel( nY, nX, pReadAcc->GetPixel( nY, nX ) );
678 				}
679 			}
680 
681 			aNewBmp.ReleaseAccess( pWriteAcc );
682 			bRet = sal_True;
683 		}
684 
685 		ReleaseAccess( pReadAcc );
686 
687 		if( bRet )
688 		{
689 			const MapMode	aMap( maPrefMapMode );
690 			const Size		aSize( maPrefSize );
691 
692 			*this = aNewBmp;
693 
694 			maPrefMapMode = aMap;
695 			maPrefSize = aSize;
696 		}
697 	}
698 
699 	return bRet;
700 }
701 
702 // ------------------------------------------------------------------------
703 
704 sal_Bool Bitmap::ImplConvertDown( sal_uInt16 nBitCount, Color* pExtColor )
705 {
706 	DBG_ASSERT( nBitCount <= GetBitCount(), "New BitCount must be lower ( or equal when pExtColor is set )!" );
707 
708 	BitmapReadAccess*	pReadAcc = AcquireReadAccess();
709 	sal_Bool				bRet = sal_False;
710 
711 	if( pReadAcc )
712 	{
713 		BitmapPalette		aPal;
714 		Bitmap				aNewBmp( GetSizePixel(), nBitCount, &aPal );
715 		BitmapWriteAccess*	pWriteAcc = aNewBmp.AcquireWriteAccess();
716 
717 		if( pWriteAcc )
718 		{
719 			const sal_uInt16	nCount = 1 << nBitCount;
720 			const long		nWidth = pWriteAcc->Width();
721 			const long		nWidth1 = nWidth - 1L;
722 			const long		nHeight = pWriteAcc->Height();
723 			Octree			aOctree( *pReadAcc, pExtColor ? ( nCount - 1 ) : nCount );
724 			InverseColorMap aColorMap( aPal = aOctree.GetPalette() );
725 			BitmapColor 	aColor;
726 			ImpErrorQuad	aErrQuad;
727 			ImpErrorQuad*	pErrQuad1 = new ImpErrorQuad[ nWidth ];
728 			ImpErrorQuad*	pErrQuad2 = new ImpErrorQuad[ nWidth ];
729 			ImpErrorQuad*	pQLine1 = pErrQuad1;
730 			ImpErrorQuad*	pQLine2 = 0;
731 			long			nX, nY;
732 			long			nYTmp = 0L;
733 			sal_uInt8			cIndex;
734 			sal_Bool			bQ1 = sal_True;
735 
736 			if( pExtColor )
737 			{
738 				aPal.SetEntryCount( aPal.GetEntryCount() + 1 );
739 				aPal[ aPal.GetEntryCount() - 1 ] = *pExtColor;
740 			}
741 
742 			// set Black/White always, if we have enough space
743 			if( aPal.GetEntryCount() < ( nCount - 1 ) )
744 			{
745 				aPal.SetEntryCount( aPal.GetEntryCount() + 2 );
746 				aPal[ aPal.GetEntryCount() - 2 ] = Color( COL_BLACK );
747 				aPal[ aPal.GetEntryCount() - 1 ] = Color( COL_WHITE );
748 			}
749 
750 			pWriteAcc->SetPalette( aPal );
751 
752 			for( nY = 0L; nY < Min( nHeight, 2L ); nY++, nYTmp++ )
753 			{
754 				for( nX = 0L, pQLine2 = !nY ? pErrQuad1 : pErrQuad2; nX < nWidth; nX++ )
755 				{
756 					if( pReadAcc->HasPalette() )
757 						pQLine2[ nX ] = pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nYTmp, nX ) );
758 					else
759 						pQLine2[ nX ] = pReadAcc->GetPixel( nYTmp, nX );
760 				}
761 			}
762 
763 			for( nY = 0L; nY < nHeight; nY++, nYTmp++ )
764 			{
765 				// first pixel in the line
766 				cIndex = (sal_uInt8) aColorMap.GetBestPaletteIndex( pQLine1[ 0 ].ImplGetColor() );
767 				pWriteAcc->SetPixelIndex( nY, 0, cIndex );
768 
769 				for( nX = 1L; nX < nWidth1; nX++ )
770 				{
771 					cIndex = (sal_uInt8) aColorMap.GetBestPaletteIndex( aColor = pQLine1[ nX ].ImplGetColor() );
772 					aErrQuad = ( ImpErrorQuad( aColor ) -= pWriteAcc->GetPaletteColor( cIndex ) );
773 					pQLine1[ ++nX ].ImplAddColorError7( aErrQuad );
774 					pQLine2[ nX-- ].ImplAddColorError1( aErrQuad );
775 					pQLine2[ nX-- ].ImplAddColorError5( aErrQuad );
776 					pQLine2[ nX++ ].ImplAddColorError3( aErrQuad );
777 					pWriteAcc->SetPixelIndex( nY, nX, cIndex );
778 				}
779 
780 				// letztes ZeilenPixel
781                 if( nX < nWidth )
782                 {
783 				    cIndex = (sal_uInt8) aColorMap.GetBestPaletteIndex( pQLine1[ nWidth1 ].ImplGetColor() );
784 				    pWriteAcc->SetPixelIndex( nY, nX, cIndex );
785                 }
786 
787 				// Zeilenpuffer neu fuellen/kopieren
788 				pQLine1 = pQLine2;
789 				pQLine2 = ( bQ1 = !bQ1 ) != sal_False ? pErrQuad2 : pErrQuad1;
790 
791 				if( nYTmp < nHeight )
792 				{
793 					for( nX = 0L; nX < nWidth; nX++ )
794 					{
795 						if( pReadAcc->HasPalette() )
796 							pQLine2[ nX ] = pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nYTmp, nX ) );
797 						else
798 							pQLine2[ nX ] = pReadAcc->GetPixel( nYTmp, nX );
799 					}
800 				}
801 			}
802 
803 			// Zeilenpuffer zerstoeren
804 			delete[] pErrQuad1;
805 			delete[] pErrQuad2;
806 
807 			aNewBmp.ReleaseAccess( pWriteAcc );
808 			bRet = sal_True;
809 		}
810 
811 		ReleaseAccess( pReadAcc );
812 
813 		if( bRet )
814 		{
815 			const MapMode	aMap( maPrefMapMode );
816 			const Size		aSize( maPrefSize );
817 
818 			*this = aNewBmp;
819 
820 			maPrefMapMode = aMap;
821 			maPrefSize = aSize;
822 		}
823 	}
824 
825 	return bRet;
826 }
827 
828 // ------------------------------------------------------------------------
829 
830 sal_Bool Bitmap::ImplConvertGhosted()
831 {
832 	Bitmap				aNewBmp;
833 	BitmapReadAccess*	pR = AcquireReadAccess();
834 	sal_Bool				bRet = sal_False;
835 
836 	if( pR )
837 	{
838 		if( pR->HasPalette() )
839 		{
840 			BitmapPalette aNewPal( pR->GetPaletteEntryCount() );
841 
842 			for( long i = 0, nCount = aNewPal.GetEntryCount(); i < nCount; i++ )
843 			{
844 				const BitmapColor& rOld = pR->GetPaletteColor( (sal_uInt16) i );
845 				aNewPal[ (sal_uInt16) i ] = BitmapColor( ( rOld.GetRed() >> 1 ) | 0x80,
846 													 ( rOld.GetGreen() >> 1 ) | 0x80,
847 													 ( rOld.GetBlue() >> 1 ) | 0x80 );
848 			}
849 
850 			aNewBmp = Bitmap( GetSizePixel(), GetBitCount(), &aNewPal );
851 			BitmapWriteAccess* pW = aNewBmp.AcquireWriteAccess();
852 
853 			if( pW )
854 			{
855 				pW->CopyBuffer( *pR );
856 				aNewBmp.ReleaseAccess( pW );
857 				bRet = sal_True;
858 			}
859 		}
860 		else
861 		{
862 			aNewBmp = Bitmap( GetSizePixel(), 24 );
863 
864 			BitmapWriteAccess* pW = aNewBmp.AcquireWriteAccess();
865 
866 			if( pW )
867 			{
868 				const long nWidth = pR->Width(), nHeight = pR->Height();
869 
870 				for( long nY = 0; nY < nHeight; nY++ )
871 				{
872 					for( long nX = 0; nX < nWidth; nX++ )
873 					{
874 						const BitmapColor aOld( pR->GetPixel( nY, nX ) );
875 						pW->SetPixel( nY, nX, BitmapColor( ( aOld.GetRed() >> 1 ) | 0x80,
876 														   ( aOld.GetGreen() >> 1 ) | 0x80,
877 														   ( aOld.GetBlue() >> 1 ) | 0x80 ) );
878 
879 					}
880 				}
881 
882 				aNewBmp.ReleaseAccess( pW );
883 				bRet = sal_True;
884 			}
885 		}
886 
887 		ReleaseAccess( pR );
888 	}
889 
890 	if( bRet )
891 	{
892 		const MapMode	aMap( maPrefMapMode );
893 		const Size		aSize( maPrefSize );
894 
895 		*this = aNewBmp;
896 
897 		maPrefMapMode = aMap;
898 		maPrefSize = aSize;
899 	}
900 
901 	return bRet;
902 }
903 
904 // ------------------------------------------------------------------------
905 
906 sal_Bool Bitmap::Scale( const double& rScaleX, const double& rScaleY, sal_uLong nScaleFlag )
907 {
908 	sal_Bool bRet;
909 
910 	if( ( rScaleX != 1.0 ) || ( rScaleY != 1.0 ) )
911 	{
912 		if( BMP_SCALE_FAST == nScaleFlag )
913 			bRet = ImplScaleFast( rScaleX, rScaleY );
914 		else if( BMP_SCALE_INTERPOLATE == nScaleFlag )
915 			bRet = ImplScaleInterpolate( rScaleX, rScaleY );
916 		else
917 			bRet = sal_False;
918 	}
919 	else
920 		bRet = sal_True;
921 
922 	return bRet;
923 }
924 
925 // ------------------------------------------------------------------------
926 
927 sal_Bool Bitmap::Scale( const Size& rNewSize, sal_uLong nScaleFlag )
928 {
929 	const Size	aSize( GetSizePixel() );
930 	sal_Bool		bRet;
931 
932 	if( aSize.Width() && aSize.Height() )
933 	{
934 		bRet = Scale( (double) rNewSize.Width() / aSize.Width(),
935 					  (double) rNewSize.Height() / aSize.Height(),
936 					  nScaleFlag );
937 	}
938 	else
939 		bRet = sal_True;
940 
941 	return bRet;
942 }
943 
944 // ------------------------------------------------------------------------
945 
946 sal_Bool Bitmap::ImplScaleFast( const double& rScaleX, const double& rScaleY )
947 {
948 	const Size	aSizePix( GetSizePixel() );
949 	const long	nNewWidth = FRound( aSizePix.Width() * rScaleX );
950 	const long	nNewHeight = FRound( aSizePix.Height() * rScaleY );
951 	sal_Bool		bRet = sal_False;
952 
953 	if( nNewWidth && nNewHeight )
954 	{
955 		BitmapReadAccess*	pReadAcc = AcquireReadAccess();
956         if ( !pReadAcc )
957             return sal_False;
958 
959 		Bitmap				aNewBmp( Size( nNewWidth, nNewHeight ), GetBitCount(), &pReadAcc->GetPalette() );
960 		BitmapWriteAccess*	pWriteAcc = aNewBmp.AcquireWriteAccess();
961 
962 		if( pWriteAcc )
963 		{
964 			const long	nScanlineSize = pWriteAcc->GetScanlineSize();
965 			const long	nNewWidth1 = nNewWidth - 1L;
966 			const long	nNewHeight1 = nNewHeight - 1L;
967 			const long	nWidth = pReadAcc->Width();
968 			const long	nHeight = pReadAcc->Height();
969 			long*		pLutX = new long[ nNewWidth ];
970 			long*		pLutY = new long[ nNewHeight ];
971 			long		nX, nY, nMapY, nActY = 0L;
972 
973 			if( nNewWidth1 && nNewHeight1 )
974 			{
975 				for( nX = 0L; nX < nNewWidth; nX++ )
976 					pLutX[ nX ] = nX * nWidth / nNewWidth;
977 
978 				for( nY = 0L; nY < nNewHeight; nY++ )
979 					pLutY[ nY ] = nY * nHeight / nNewHeight;
980 
981 				while( nActY < nNewHeight )
982 				{
983 					nMapY = pLutY[ nActY ];
984 
985 					for( nX = 0L; nX < nNewWidth; nX++ )
986 						pWriteAcc->SetPixel( nActY, nX, pReadAcc->GetPixel( nMapY , pLutX[ nX ] ) );
987 
988 					while( ( nActY < nNewHeight1 ) && ( pLutY[ nActY + 1 ] == nMapY ) )
989 					{
990 						memcpy( pWriteAcc->GetScanline( nActY + 1L ),
991 								 pWriteAcc->GetScanline( nActY ), nScanlineSize );
992 						nActY++;
993 					}
994 
995 					nActY++;
996 				}
997 
998 				bRet = sal_True;
999 			}
1000 
1001 			delete[] pLutX;
1002 			delete[] pLutY;
1003 		}
1004 
1005 		ReleaseAccess( pReadAcc );
1006 		aNewBmp.ReleaseAccess( pWriteAcc );
1007 
1008 		if( bRet )
1009 			ImplAssignWithSize( aNewBmp );
1010 	}
1011 
1012 	return bRet;
1013 }
1014 
1015 // ------------------------------------------------------------------------
1016 
1017 sal_Bool Bitmap::ImplScaleInterpolate( const double& rScaleX, const double& rScaleY )
1018 {
1019 	const Size	aSizePix( GetSizePixel() );
1020 	const long	nNewWidth = FRound( aSizePix.Width() * rScaleX );
1021 	const long	nNewHeight = FRound( aSizePix.Height() * rScaleY );
1022 	sal_Bool		bRet = sal_False;
1023 
1024 	if( ( nNewWidth > 1L ) && ( nNewHeight > 1L ) )
1025 	{
1026 		BitmapColor 		aCol0;
1027 		BitmapColor 		aCol1;
1028 		BitmapReadAccess*	pReadAcc = AcquireReadAccess();
1029 		long				nWidth = pReadAcc->Width();
1030 		long				nHeight = pReadAcc->Height();
1031 		Bitmap				aNewBmp( Size( nNewWidth, nHeight ), 24 );
1032 		BitmapWriteAccess*	pWriteAcc = aNewBmp.AcquireWriteAccess();
1033 		long*				pLutInt;
1034 		long*				pLutFrac;
1035 		long				nX, nY;
1036 		long				lXB0, lXB1, lXG0, lXG1, lXR0, lXR1;
1037 		double				fTemp;
1038 		long				nTemp;
1039 
1040 		if( pReadAcc && pWriteAcc )
1041 		{
1042 			const long		nNewWidth1 = nNewWidth - 1L;
1043 			const long		nWidth1 = pReadAcc->Width() - 1L;
1044 			const double	fRevScaleX = (double) nWidth1 / nNewWidth1;
1045 
1046 			pLutInt = new long[ nNewWidth ];
1047 			pLutFrac = new long[ nNewWidth ];
1048 
1049 			for( nX = 0L, nTemp = nWidth - 2L; nX < nNewWidth; nX++ )
1050 			{
1051 				fTemp = nX * fRevScaleX;
1052 				pLutInt[ nX ] = MinMax( (long) fTemp, 0, nTemp );
1053 				fTemp -= pLutInt[ nX ];
1054 				pLutFrac[ nX ] = (long) ( fTemp * 1024. );
1055 			}
1056 
1057 			if( pReadAcc->HasPalette() )
1058 			{
1059 				for( nY = 0L; nY < nHeight; nY++ )
1060 				{
1061 					if( 1 == nWidth )
1062 					{
1063 						aCol0 = pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nY, 0 ) );
1064 
1065 						for( nX = 0L; nX < nNewWidth; nX++ )
1066 							pWriteAcc->SetPixel( nY, nX, aCol0 );
1067 					}
1068 					else
1069 					{
1070 						for( nX = 0L; nX < nNewWidth; nX++ )
1071 						{
1072 							nTemp = pLutInt[ nX ];
1073 
1074 							aCol0 = pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nY, nTemp++ ) );
1075 							aCol1 = pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nY, nTemp ) );
1076 
1077 							nTemp = pLutFrac[ nX ];
1078 
1079 							lXR1 = aCol1.GetRed() - ( lXR0 = aCol0.GetRed() );
1080 							lXG1 = aCol1.GetGreen() - ( lXG0 = aCol0.GetGreen() );
1081 							lXB1 = aCol1.GetBlue() - ( lXB0 = aCol0.GetBlue() );
1082 
1083 							aCol0.SetRed( (sal_uInt8) ( ( lXR1 * nTemp + ( lXR0 << 10 ) ) >> 10 ) );
1084 							aCol0.SetGreen( (sal_uInt8) ( ( lXG1 * nTemp + ( lXG0 << 10 ) ) >> 10 ) );
1085 							aCol0.SetBlue( (sal_uInt8) ( ( lXB1 * nTemp + ( lXB0 << 10 ) ) >> 10 ) );
1086 
1087 							pWriteAcc->SetPixel( nY, nX, aCol0 );
1088 						}
1089 					}
1090 				}
1091 			}
1092 			else
1093 			{
1094 				for( nY = 0L; nY < nHeight; nY++ )
1095 				{
1096 					if( 1 == nWidth )
1097 					{
1098 						aCol0 = pReadAcc->GetPixel( nY, 0 );
1099 
1100 						for( nX = 0L; nX < nNewWidth; nX++ )
1101 							pWriteAcc->SetPixel( nY, nX, aCol0 );
1102 					}
1103 					else
1104 					{
1105 						for( nX = 0L; nX < nNewWidth; nX++ )
1106 						{
1107 							nTemp = pLutInt[ nX ];
1108 
1109 							aCol0 = pReadAcc->GetPixel( nY, nTemp++ );
1110 							aCol1 = pReadAcc->GetPixel( nY, nTemp );
1111 
1112 							nTemp = pLutFrac[ nX ];
1113 
1114 							lXR1 = aCol1.GetRed() - ( lXR0 = aCol0.GetRed() );
1115 							lXG1 = aCol1.GetGreen() - ( lXG0 = aCol0.GetGreen() );
1116 							lXB1 = aCol1.GetBlue() - ( lXB0 = aCol0.GetBlue() );
1117 
1118 							aCol0.SetRed( (sal_uInt8) ( ( lXR1 * nTemp + ( lXR0 << 10 ) ) >> 10 ) );
1119 							aCol0.SetGreen( (sal_uInt8) ( ( lXG1 * nTemp + ( lXG0 << 10 ) ) >> 10 ) );
1120 							aCol0.SetBlue( (sal_uInt8) ( ( lXB1 * nTemp + ( lXB0 << 10 ) ) >> 10 ) );
1121 
1122 							pWriteAcc->SetPixel( nY, nX, aCol0 );
1123 						}
1124 					}
1125 				}
1126 			}
1127 
1128 			delete[] pLutInt;
1129 			delete[] pLutFrac;
1130 			bRet = sal_True;
1131 		}
1132 
1133 		ReleaseAccess( pReadAcc );
1134 		aNewBmp.ReleaseAccess( pWriteAcc );
1135 
1136 		if( bRet )
1137 		{
1138 			bRet = sal_False;
1139 			ImplAssignWithSize( aNewBmp );
1140 			pReadAcc = AcquireReadAccess();
1141 			aNewBmp = Bitmap( Size( nNewWidth, nNewHeight ), 24 );
1142 			pWriteAcc = aNewBmp.AcquireWriteAccess();
1143 
1144 			if( pReadAcc && pWriteAcc )
1145 			{
1146 				const long		nNewHeight1 = nNewHeight - 1L;
1147 				const long		nHeight1 = pReadAcc->Height() - 1L;
1148 				const double	fRevScaleY = (double) nHeight1 / nNewHeight1;
1149 
1150 				pLutInt = new long[ nNewHeight ];
1151 				pLutFrac = new long[ nNewHeight ];
1152 
1153 				for( nY = 0L, nTemp = nHeight - 2L; nY < nNewHeight; nY++ )
1154 				{
1155 					fTemp = nY * fRevScaleY;
1156 					pLutInt[ nY ] = MinMax( (long) fTemp, 0, nTemp );
1157 					fTemp -= pLutInt[ nY ];
1158 					pLutFrac[ nY ] = (long) ( fTemp * 1024. );
1159 				}
1160 
1161 				if( pReadAcc->HasPalette() )
1162 				{
1163 					for( nX = 0L; nX < nNewWidth; nX++ )
1164 					{
1165 						if( 1 == nHeight )
1166 						{
1167 							aCol0 = pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( 0, nX ) );
1168 
1169 							for( nY = 0L; nY < nNewHeight; nY++ )
1170 								pWriteAcc->SetPixel( nY, nX, aCol0 );
1171 						}
1172 						else
1173 						{
1174 							for( nY = 0L; nY < nNewHeight; nY++ )
1175 							{
1176 								nTemp = pLutInt[ nY ];
1177 
1178 								aCol0 = pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nTemp++, nX ) );
1179 								aCol1 = pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nTemp, nX ) );
1180 
1181 								nTemp = pLutFrac[ nY ];
1182 
1183 								lXR1 = aCol1.GetRed() - ( lXR0 = aCol0.GetRed() );
1184 								lXG1 = aCol1.GetGreen() - ( lXG0 = aCol0.GetGreen() );
1185 								lXB1 = aCol1.GetBlue() - ( lXB0 = aCol0.GetBlue() );
1186 
1187 								aCol0.SetRed( (sal_uInt8) ( ( lXR1 * nTemp + ( lXR0 << 10 ) ) >> 10 ) );
1188 								aCol0.SetGreen( (sal_uInt8) ( ( lXG1 * nTemp + ( lXG0 << 10 ) ) >> 10 ) );
1189 								aCol0.SetBlue( (sal_uInt8) ( ( lXB1 * nTemp + ( lXB0 << 10 ) ) >> 10 ) );
1190 
1191 								pWriteAcc->SetPixel( nY, nX, aCol0 );
1192 							}
1193 						}
1194 					}
1195 				}
1196 				else
1197 				{
1198 					for( nX = 0L; nX < nNewWidth; nX++ )
1199 					{
1200 						if( 1 == nHeight )
1201 						{
1202 							aCol0 = pReadAcc->GetPixel( 0, nX );
1203 
1204 							for( nY = 0L; nY < nNewHeight; nY++ )
1205 								pWriteAcc->SetPixel( nY, nX, aCol0 );
1206 						}
1207 						else
1208 						{
1209 							for( nY = 0L; nY < nNewHeight; nY++ )
1210 							{
1211 								nTemp = pLutInt[ nY ];
1212 
1213 								aCol0 = pReadAcc->GetPixel( nTemp++, nX );
1214 								aCol1 = pReadAcc->GetPixel( nTemp, nX );
1215 
1216 								nTemp = pLutFrac[ nY ];
1217 
1218 								lXR1 = aCol1.GetRed() - ( lXR0 = aCol0.GetRed() );
1219 								lXG1 = aCol1.GetGreen() - ( lXG0 = aCol0.GetGreen() );
1220 								lXB1 = aCol1.GetBlue() - ( lXB0 = aCol0.GetBlue() );
1221 
1222 								aCol0.SetRed( (sal_uInt8) ( ( lXR1 * nTemp + ( lXR0 << 10 ) ) >> 10 ) );
1223 								aCol0.SetGreen( (sal_uInt8) ( ( lXG1 * nTemp + ( lXG0 << 10 ) ) >> 10 ) );
1224 								aCol0.SetBlue( (sal_uInt8) ( ( lXB1 * nTemp + ( lXB0 << 10 ) ) >> 10 ) );
1225 
1226 								pWriteAcc->SetPixel( nY, nX, aCol0 );
1227 							}
1228 						}
1229 					}
1230 				}
1231 
1232 				delete[] pLutInt;
1233 				delete[] pLutFrac;
1234 				bRet = sal_True;
1235 			}
1236 
1237 			ReleaseAccess( pReadAcc );
1238 			aNewBmp.ReleaseAccess( pWriteAcc );
1239 
1240 			if( bRet )
1241 				ImplAssignWithSize( aNewBmp );
1242 		}
1243 	}
1244 
1245 	if( !bRet )
1246 		bRet = ImplScaleFast( rScaleX, rScaleY );
1247 
1248 	return bRet;
1249 }
1250 
1251 // ------------------------------------------------------------------------
1252 
1253 sal_Bool Bitmap::Dither( sal_uLong nDitherFlags )
1254 {
1255 	sal_Bool bRet = sal_False;
1256 
1257 	const Size aSizePix( GetSizePixel() );
1258 
1259 	if( aSizePix.Width() == 1 || aSizePix.Height() == 1 )
1260 		bRet = sal_True;
1261 	else if( nDitherFlags & BMP_DITHER_MATRIX )
1262 		bRet = ImplDitherMatrix();
1263 	else if( nDitherFlags & BMP_DITHER_FLOYD )
1264 		bRet = ImplDitherFloyd();
1265 	else if( ( nDitherFlags & BMP_DITHER_FLOYD_16 ) && ( GetBitCount() == 24 ) )
1266 		bRet = ImplDitherFloyd16();
1267 
1268 	return bRet;
1269 }
1270 
1271 // ------------------------------------------------------------------------
1272 
1273 sal_Bool Bitmap::ImplDitherMatrix()
1274 {
1275 	BitmapReadAccess*	pReadAcc = AcquireReadAccess();
1276 	Bitmap				aNewBmp( GetSizePixel(), 8 );
1277 	BitmapWriteAccess*	pWriteAcc = aNewBmp.AcquireWriteAccess();
1278 	sal_Bool				bRet = sal_False;
1279 
1280 	if( pReadAcc && pWriteAcc )
1281 	{
1282 		const sal_uLong	nWidth = pReadAcc->Width();
1283 		const sal_uLong	nHeight = pReadAcc->Height();
1284 		BitmapColor	aIndex( (sal_uInt8) 0 );
1285 
1286 		if( pReadAcc->HasPalette() )
1287 		{
1288 			for( sal_uLong nY = 0UL; nY < nHeight; nY++ )
1289 			{
1290 				for( sal_uLong nX = 0UL, nModY = ( nY & 0x0FUL ) << 4UL; nX < nWidth; nX++ )
1291 				{
1292 					const BitmapColor	aCol( pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nY, nX ) ) );
1293 					const sal_uLong			nD = nVCLDitherLut[ nModY + ( nX & 0x0FUL ) ];
1294 					const sal_uLong			nR = ( nVCLLut[ aCol.GetRed() ] + nD ) >> 16UL;
1295 					const sal_uLong			nG = ( nVCLLut[ aCol.GetGreen() ] + nD ) >> 16UL;
1296 					const sal_uLong			nB = ( nVCLLut[ aCol.GetBlue() ] + nD ) >> 16UL;
1297 
1298 					aIndex.SetIndex( (sal_uInt8) ( nVCLRLut[ nR ] + nVCLGLut[ nG ] + nVCLBLut[ nB ] ) );
1299 					pWriteAcc->SetPixel( nY, nX, aIndex );
1300 				}
1301 			}
1302 		}
1303 		else
1304 		{
1305 			for( sal_uLong nY = 0UL; nY < nHeight; nY++ )
1306 			{
1307 				for( sal_uLong nX = 0UL, nModY = ( nY & 0x0FUL ) << 4UL; nX < nWidth; nX++ )
1308 				{
1309 					const BitmapColor	aCol( pReadAcc->GetPixel( nY, nX ) );
1310 					const sal_uLong			nD = nVCLDitherLut[ nModY + ( nX & 0x0FUL ) ];
1311 					const sal_uLong			nR = ( nVCLLut[ aCol.GetRed() ] + nD ) >> 16UL;
1312 					const sal_uLong			nG = ( nVCLLut[ aCol.GetGreen() ] + nD ) >> 16UL;
1313 					const sal_uLong			nB = ( nVCLLut[ aCol.GetBlue() ] + nD ) >> 16UL;
1314 
1315 					aIndex.SetIndex( (sal_uInt8) ( nVCLRLut[ nR ] + nVCLGLut[ nG ] + nVCLBLut[ nB ] ) );
1316 					pWriteAcc->SetPixel( nY, nX, aIndex );
1317 				}
1318 			}
1319 		}
1320 
1321 		bRet = sal_True;
1322 	}
1323 
1324 	ReleaseAccess( pReadAcc );
1325 	aNewBmp.ReleaseAccess( pWriteAcc );
1326 
1327 	if( bRet )
1328 	{
1329 		const MapMode	aMap( maPrefMapMode );
1330 		const Size		aSize( maPrefSize );
1331 
1332 		*this = aNewBmp;
1333 
1334 		maPrefMapMode = aMap;
1335 		maPrefSize = aSize;
1336 	}
1337 
1338 	return bRet;
1339 }
1340 
1341 // ------------------------------------------------------------------------
1342 
1343 sal_Bool Bitmap::ImplDitherFloyd()
1344 {
1345 	const Size	aSize( GetSizePixel() );
1346 	sal_Bool		bRet = sal_False;
1347 
1348 	if( ( aSize.Width() > 3 ) && ( aSize.Height() > 2 ) )
1349 	{
1350 		BitmapReadAccess*	pReadAcc = AcquireReadAccess();
1351 		Bitmap				aNewBmp( GetSizePixel(), 8 );
1352 		BitmapWriteAccess*	pWriteAcc = aNewBmp.AcquireWriteAccess();
1353 
1354 		if( pReadAcc && pWriteAcc )
1355 		{
1356 			BitmapColor	aColor;
1357 			long		nWidth = pReadAcc->Width();
1358 			long		nWidth1 = nWidth - 1L;
1359 			long		nHeight = pReadAcc->Height();
1360 			long		nX;
1361 			long		nW = nWidth * 3L;
1362 			long		nW2 = nW - 3L;
1363 			long		nRErr, nGErr, nBErr;
1364 			long		nRC, nGC, nBC;
1365 			long		nTemp;
1366 			long		nZ;
1367 			long*		p1 = new long[ nW ];
1368 			long*		p2 = new long[ nW ];
1369 			long*		p1T = p1;
1370 			long*		p2T = p2;
1371 			long*		pTmp;
1372 			sal_Bool		bPal = pReadAcc->HasPalette();
1373 
1374 			pTmp = p2T;
1375 
1376 			if( bPal )
1377 			{
1378 				for( nZ = 0; nZ < nWidth; nZ++ )
1379 				{
1380 					aColor = pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( 0, nZ ) );
1381 
1382 					*pTmp++ = (long) aColor.GetBlue() << 12;
1383 					*pTmp++ = (long) aColor.GetGreen() << 12;
1384 					*pTmp++ = (long) aColor.GetRed() << 12;
1385 				}
1386 			}
1387 			else
1388 			{
1389 				for( nZ = 0; nZ < nWidth; nZ++ )
1390 				{
1391 					aColor = pReadAcc->GetPixel( 0, nZ );
1392 
1393 					*pTmp++ = (long) aColor.GetBlue() << 12;
1394 					*pTmp++ = (long) aColor.GetGreen() << 12;
1395 					*pTmp++ = (long) aColor.GetRed() << 12;
1396 				}
1397 			}
1398 
1399 			for( long nY = 1, nYAcc = 0L; nY <= nHeight; nY++, nYAcc++ )
1400 			{
1401 				pTmp = p1T;
1402 				p1T = p2T;
1403 				p2T = pTmp;
1404 
1405 				if( nY < nHeight )
1406 				{
1407 					if( bPal )
1408 					{
1409 						for( nZ = 0; nZ < nWidth; nZ++ )
1410 						{
1411 							aColor = pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nY, nZ ) );
1412 
1413 							*pTmp++ = (long) aColor.GetBlue() << 12;
1414 							*pTmp++ = (long) aColor.GetGreen() << 12;
1415 							*pTmp++ = (long) aColor.GetRed() << 12;
1416 						}
1417 					}
1418 					else
1419 					{
1420 						for( nZ = 0; nZ < nWidth; nZ++ )
1421 						{
1422 							aColor = pReadAcc->GetPixel( nY, nZ );
1423 
1424 							*pTmp++ = (long) aColor.GetBlue() << 12;
1425 							*pTmp++ = (long) aColor.GetGreen() << 12;
1426 							*pTmp++ = (long) aColor.GetRed() << 12;
1427 						}
1428 					}
1429 				}
1430 
1431 				// erstes Pixel gesondert betrachten
1432 				nX = 0;
1433 				CALC_ERRORS;
1434 				CALC_TABLES7;
1435 				nX -= 5;
1436 				CALC_TABLES5;
1437 				pWriteAcc->SetPixelIndex( nYAcc, 0, static_cast<sal_uInt8>(nVCLBLut[ nBC ] + nVCLGLut[nGC ] + nVCLRLut[nRC ]) );
1438 
1439 				// mittlere Pixel ueber Schleife
1440 				long nXAcc;
1441 				for ( nX = 3L, nXAcc = 1L; nX < nW2; nXAcc++ )
1442 				{
1443 					CALC_ERRORS;
1444 					CALC_TABLES7;
1445 					nX -= 8;
1446 					CALC_TABLES3;
1447 					CALC_TABLES5;
1448 					pWriteAcc->SetPixelIndex( nYAcc, nXAcc, static_cast<sal_uInt8>(nVCLBLut[ nBC ] + nVCLGLut[nGC ] + nVCLRLut[nRC ]) );
1449 				}
1450 
1451 				// letztes Pixel gesondert betrachten
1452 				CALC_ERRORS;
1453 				nX -= 5;
1454 				CALC_TABLES3;
1455 				CALC_TABLES5;
1456 				pWriteAcc->SetPixelIndex( nYAcc, nWidth1, static_cast<sal_uInt8>(nVCLBLut[ nBC ] + nVCLGLut[nGC ] + nVCLRLut[nRC ]) );
1457 			}
1458 
1459 			delete[] p1;
1460 			delete[] p2;
1461 			bRet = sal_True;
1462 		}
1463 
1464 		ReleaseAccess( pReadAcc );
1465 		aNewBmp.ReleaseAccess( pWriteAcc );
1466 
1467 		if( bRet )
1468 		{
1469 			const MapMode	aMap( maPrefMapMode );
1470 			const Size		aPrefSize( maPrefSize );
1471 
1472 			*this = aNewBmp;
1473 
1474 			maPrefMapMode = aMap;
1475 			maPrefSize = aPrefSize;
1476 		}
1477 	}
1478 
1479 	return bRet;
1480 }
1481 
1482 // ------------------------------------------------------------------------
1483 
1484 sal_Bool Bitmap::ImplDitherFloyd16()
1485 {
1486 	BitmapReadAccess*	pReadAcc = AcquireReadAccess();
1487 	Bitmap				aNewBmp( GetSizePixel(), 24 );
1488 	BitmapWriteAccess*	pWriteAcc = aNewBmp.AcquireWriteAccess();
1489 	sal_Bool				bRet = sal_False;
1490 
1491 	if( pReadAcc && pWriteAcc )
1492 	{
1493 		const long		nWidth = pWriteAcc->Width();
1494 		const long		nWidth1 = nWidth - 1L;
1495 		const long		nHeight = pWriteAcc->Height();
1496 		BitmapColor 	aColor;
1497 		BitmapColor		aBestCol;
1498 		ImpErrorQuad	aErrQuad;
1499 		ImpErrorQuad*	pErrQuad1 = new ImpErrorQuad[ nWidth ];
1500 		ImpErrorQuad*	pErrQuad2 = new ImpErrorQuad[ nWidth ];
1501 		ImpErrorQuad*	pQLine1 = pErrQuad1;
1502 		ImpErrorQuad*	pQLine2 = 0;
1503 		long			nX, nY;
1504 		long			nYTmp = 0L;
1505 		sal_Bool			bQ1 = sal_True;
1506 
1507 		for( nY = 0L; nY < Min( nHeight, 2L ); nY++, nYTmp++ )
1508 			for( nX = 0L, pQLine2 = !nY ? pErrQuad1 : pErrQuad2; nX < nWidth; nX++ )
1509 				pQLine2[ nX ] = pReadAcc->GetPixel( nYTmp, nX );
1510 
1511 		for( nY = 0L; nY < nHeight; nY++, nYTmp++ )
1512 		{
1513 			// erstes ZeilenPixel
1514 			aBestCol = pQLine1[ 0 ].ImplGetColor();
1515 			aBestCol.SetRed( ( aBestCol.GetRed() & 248 ) | 7 );
1516 			aBestCol.SetGreen( ( aBestCol.GetGreen() & 248 ) | 7 );
1517 			aBestCol.SetBlue( ( aBestCol.GetBlue() & 248 ) | 7 );
1518 			pWriteAcc->SetPixel( nY, 0, aBestCol );
1519 
1520 			for( nX = 1L; nX < nWidth1; nX++ )
1521 			{
1522 				aColor = pQLine1[ nX ].ImplGetColor();
1523 				aBestCol.SetRed( ( aColor.GetRed() & 248 ) | 7 );
1524 				aBestCol.SetGreen( ( aColor.GetGreen() & 248 ) | 7 );
1525 				aBestCol.SetBlue( ( aColor.GetBlue() & 248 ) | 7 );
1526 				aErrQuad = ( ImpErrorQuad( aColor ) -= aBestCol );
1527 				pQLine1[ ++nX ].ImplAddColorError7( aErrQuad );
1528 				pQLine2[ nX-- ].ImplAddColorError1( aErrQuad );
1529 				pQLine2[ nX-- ].ImplAddColorError5( aErrQuad );
1530 				pQLine2[ nX++ ].ImplAddColorError3( aErrQuad );
1531 				pWriteAcc->SetPixel( nY, nX, aBestCol );
1532 			}
1533 
1534 			// letztes ZeilenPixel
1535 			aBestCol = pQLine1[ nWidth1 ].ImplGetColor();
1536 			aBestCol.SetRed( ( aBestCol.GetRed() & 248 ) | 7 );
1537 			aBestCol.SetGreen( ( aBestCol.GetGreen() & 248 ) | 7 );
1538 			aBestCol.SetBlue( ( aBestCol.GetBlue() & 248 ) | 7 );
1539 			pWriteAcc->SetPixel( nY, nX, aBestCol );
1540 
1541 			// Zeilenpuffer neu fuellen/kopieren
1542 			pQLine1 = pQLine2;
1543 			pQLine2 = ( bQ1 = !bQ1 ) != sal_False ? pErrQuad2 : pErrQuad1;
1544 
1545 			if( nYTmp < nHeight )
1546 				for( nX = 0L; nX < nWidth; nX++ )
1547 					pQLine2[ nX ] = pReadAcc->GetPixel( nYTmp, nX );
1548 		}
1549 
1550 		// Zeilenpuffer zerstoeren
1551 		delete[] pErrQuad1;
1552 		delete[] pErrQuad2;
1553 		bRet = sal_True;
1554 	}
1555 
1556 	ReleaseAccess( pReadAcc );
1557 	aNewBmp.ReleaseAccess( pWriteAcc );
1558 
1559 	if( bRet )
1560 	{
1561 		const MapMode	aMap( maPrefMapMode );
1562 		const Size		aSize( maPrefSize );
1563 
1564 		*this = aNewBmp;
1565 
1566 		maPrefMapMode = aMap;
1567 		maPrefSize = aSize;
1568 	}
1569 
1570 	return bRet;
1571 }
1572 
1573 // ------------------------------------------------------------------------
1574 
1575 sal_Bool Bitmap::ReduceColors( sal_uInt16 nColorCount, BmpReduce eReduce )
1576 {
1577 	sal_Bool bRet;
1578 
1579 	if( GetColorCount() <= (sal_uLong) nColorCount )
1580 		bRet = sal_True;
1581 	else if( nColorCount )
1582 	{
1583 		if( BMP_REDUCE_SIMPLE == eReduce )
1584 			bRet = ImplReduceSimple( nColorCount );
1585 		else if( BMP_REDUCE_POPULAR == eReduce )
1586 			bRet = ImplReducePopular( nColorCount );
1587 		else
1588 			bRet = ImplReduceMedian( nColorCount );
1589 	}
1590 	else
1591 		bRet = sal_False;
1592 
1593 	return bRet;
1594 }
1595 
1596 // ------------------------------------------------------------------------
1597 
1598 sal_Bool Bitmap::ImplReduceSimple( sal_uInt16 nColorCount )
1599 {
1600 	Bitmap				aNewBmp;
1601 	BitmapReadAccess*	pRAcc = AcquireReadAccess();
1602 	const sal_uInt16		nColCount = Min( nColorCount, (sal_uInt16) 256 );
1603 	sal_uInt16				nBitCount;
1604 	sal_Bool				bRet = sal_False;
1605 
1606 	if( nColCount <= 2 )
1607 		nBitCount = 1;
1608 	else if( nColCount <= 16 )
1609 		nBitCount = 4;
1610 	else
1611 		nBitCount = 8;
1612 
1613 	if( pRAcc )
1614 	{
1615 		Octree					aOct( *pRAcc, nColCount );
1616 		const BitmapPalette&	rPal = aOct.GetPalette();
1617 		BitmapWriteAccess*		pWAcc;
1618 
1619 		aNewBmp = Bitmap( GetSizePixel(), nBitCount, &rPal );
1620 		pWAcc = aNewBmp.AcquireWriteAccess();
1621 
1622 		if( pWAcc )
1623 		{
1624 			const long nWidth = pRAcc->Width();
1625 			const long nHeight = pRAcc->Height();
1626 
1627 			if( pRAcc->HasPalette() )
1628 			{
1629 				for( long nY = 0L; nY < nHeight; nY++ )
1630 					for( long nX =0L; nX < nWidth; nX++ )
1631 						pWAcc->SetPixelIndex( nY, nX, static_cast<sal_uInt8>(aOct.GetBestPaletteIndex( pRAcc->GetPaletteColor( pRAcc->GetPixelIndex( nY, nX ) ))) );
1632 			}
1633 			else
1634 			{
1635 				for( long nY = 0L; nY < nHeight; nY++ )
1636 					for( long nX =0L; nX < nWidth; nX++ )
1637 						pWAcc->SetPixelIndex( nY, nX, static_cast<sal_uInt8>(aOct.GetBestPaletteIndex( pRAcc->GetPixel( nY, nX ) )) );
1638 			}
1639 
1640 			aNewBmp.ReleaseAccess( pWAcc );
1641 			bRet = sal_True;
1642 		}
1643 
1644 		ReleaseAccess( pRAcc );
1645 	}
1646 
1647 	if( bRet )
1648 	{
1649 		const MapMode	aMap( maPrefMapMode );
1650 		const Size		aSize( maPrefSize );
1651 
1652 		*this = aNewBmp;
1653 		maPrefMapMode = aMap;
1654 		maPrefSize = aSize;
1655 	}
1656 
1657 	return bRet;
1658 }
1659 
1660 // ------------------------------------------------------------------------
1661 
1662 struct PopularColorCount
1663 {
1664 	sal_uInt32	mnIndex;
1665 	sal_uInt32	mnCount;
1666 };
1667 
1668 // ------------------------------------------------------------------------
1669 
1670 extern "C" int __LOADONCALLAPI ImplPopularCmpFnc( const void* p1, const void* p2 )
1671 {
1672 	int nRet;
1673 
1674 	if( ( (PopularColorCount*) p1 )->mnCount < ( (PopularColorCount*) p2 )->mnCount )
1675 		nRet = 1;
1676 	else if( ( (PopularColorCount*) p1 )->mnCount == ( (PopularColorCount*) p2 )->mnCount )
1677 		nRet = 0;
1678 	else
1679 		nRet = -1;
1680 
1681 	return nRet;
1682 }
1683 
1684 // ------------------------------------------------------------------------
1685 
1686 sal_Bool Bitmap::ImplReducePopular( sal_uInt16 nColCount )
1687 {
1688 	BitmapReadAccess*	pRAcc = AcquireReadAccess();
1689 	sal_uInt16				nBitCount;
1690 	sal_Bool				bRet = sal_False;
1691 
1692 	if( nColCount > 256 )
1693 		nColCount = 256;
1694 
1695 	if( nColCount < 17 )
1696 		nBitCount = 4;
1697 	else
1698 		nBitCount = 8;
1699 
1700 	if( pRAcc )
1701 	{
1702 		const sal_uInt32	nValidBits = 4;
1703 		const sal_uInt32	nRightShiftBits = 8 - nValidBits;
1704 		const sal_uInt32	nLeftShiftBits1 = nValidBits;
1705 		const sal_uInt32	nLeftShiftBits2 = nValidBits << 1;
1706 		const sal_uInt32	nColorsPerComponent = 1 << nValidBits;
1707 		const sal_uInt32	nColorOffset = 256 / nColorsPerComponent;
1708 		const sal_uInt32	nTotalColors = nColorsPerComponent * nColorsPerComponent * nColorsPerComponent;
1709 		const long			nWidth = pRAcc->Width();
1710 		const long			nHeight = pRAcc->Height();
1711 		PopularColorCount*	pCountTable = new PopularColorCount[ nTotalColors ];
1712 		long				nX, nY, nR, nG, nB, nIndex;
1713 
1714 		rtl_zeroMemory( pCountTable, nTotalColors * sizeof( PopularColorCount ) );
1715 
1716 		for( nR = 0, nIndex = 0; nR < 256; nR += nColorOffset )
1717         {
1718 			for( nG = 0; nG < 256; nG += nColorOffset )
1719             {
1720 				for( nB = 0; nB < 256; nB += nColorOffset )
1721                 {
1722 					pCountTable[ nIndex ].mnIndex = nIndex;
1723                     nIndex++;
1724                 }
1725             }
1726         }
1727 
1728 		if( pRAcc->HasPalette() )
1729 		{
1730 			for( nY = 0L; nY < nHeight; nY++ )
1731 			{
1732 				for( nX = 0L; nX < nWidth; nX++ )
1733 				{
1734 					const BitmapColor& rCol = pRAcc->GetPaletteColor( pRAcc->GetPixelIndex( nY, nX ) );
1735 					pCountTable[ ( ( ( (sal_uInt32) rCol.GetRed() ) >> nRightShiftBits ) << nLeftShiftBits2 ) |
1736 								 ( ( ( (sal_uInt32) rCol.GetGreen() ) >> nRightShiftBits ) << nLeftShiftBits1 ) |
1737 								 ( ( (sal_uInt32) rCol.GetBlue() ) >> nRightShiftBits ) ].mnCount++;
1738 				}
1739 			}
1740 		}
1741 		else
1742 		{
1743 			for( nY = 0L; nY < nHeight; nY++ )
1744 			{
1745 				for( nX = 0L; nX < nWidth; nX++ )
1746 				{
1747 					const BitmapColor aCol( pRAcc->GetPixel( nY, nX ) );
1748 					pCountTable[ ( ( ( (sal_uInt32) aCol.GetRed() ) >> nRightShiftBits ) << nLeftShiftBits2 ) |
1749 								 ( ( ( (sal_uInt32) aCol.GetGreen() ) >> nRightShiftBits ) << nLeftShiftBits1 ) |
1750 								 ( ( (sal_uInt32) aCol.GetBlue() ) >> nRightShiftBits ) ].mnCount++;
1751 				}
1752 			}
1753 		}
1754 
1755 		BitmapPalette aNewPal( nColCount );
1756 
1757 		qsort( pCountTable, nTotalColors, sizeof( PopularColorCount ), ImplPopularCmpFnc );
1758 
1759 		for( sal_uInt16 n = 0; n < nColCount; n++ )
1760 		{
1761 			const PopularColorCount& rPop = pCountTable[ n ];
1762 			aNewPal[ n ] = BitmapColor( (sal_uInt8) ( ( rPop.mnIndex >> nLeftShiftBits2 ) << nRightShiftBits ),
1763 										(sal_uInt8) ( ( ( rPop.mnIndex >> nLeftShiftBits1 ) & ( nColorsPerComponent - 1 ) ) << nRightShiftBits ),
1764 										(sal_uInt8) ( ( rPop.mnIndex & ( nColorsPerComponent - 1 ) ) << nRightShiftBits ) );
1765 		}
1766 
1767 		Bitmap				aNewBmp( GetSizePixel(), nBitCount, &aNewPal );
1768 		BitmapWriteAccess*	pWAcc = aNewBmp.AcquireWriteAccess();
1769 
1770 		if( pWAcc )
1771 		{
1772 			BitmapColor	aDstCol( (sal_uInt8) 0 );
1773 			sal_uInt8*		pIndexMap = new sal_uInt8[ nTotalColors ];
1774 
1775 			for( nR = 0, nIndex = 0; nR < 256; nR += nColorOffset )
1776 				for( nG = 0; nG < 256; nG += nColorOffset )
1777 					for( nB = 0; nB < 256; nB += nColorOffset )
1778 						pIndexMap[ nIndex++ ] = (sal_uInt8) aNewPal.GetBestIndex( BitmapColor( (sal_uInt8) nR, (sal_uInt8) nG, (sal_uInt8) nB ) );
1779 
1780 			if( pRAcc->HasPalette() )
1781 			{
1782 				for( nY = 0L; nY < nHeight; nY++ )
1783 				{
1784 					for( nX = 0L; nX < nWidth; nX++ )
1785 					{
1786 						const BitmapColor& rCol = pRAcc->GetPaletteColor( pRAcc->GetPixelIndex( nY, nX ) );
1787 						aDstCol.SetIndex( pIndexMap[ ( ( ( (sal_uInt32) rCol.GetRed() ) >> nRightShiftBits ) << nLeftShiftBits2 ) |
1788 													 ( ( ( (sal_uInt32) rCol.GetGreen() ) >> nRightShiftBits ) << nLeftShiftBits1 ) |
1789 													 ( ( (sal_uInt32) rCol.GetBlue() ) >> nRightShiftBits ) ] );
1790 						pWAcc->SetPixel( nY, nX, aDstCol );
1791 					}
1792 				}
1793 			}
1794 			else
1795 			{
1796 				for( nY = 0L; nY < nHeight; nY++ )
1797 				{
1798 					for( nX = 0L; nX < nWidth; nX++ )
1799 					{
1800 						const BitmapColor aCol( pRAcc->GetPixel( nY, nX ) );
1801 						aDstCol.SetIndex( pIndexMap[ ( ( ( (sal_uInt32) aCol.GetRed() ) >> nRightShiftBits ) << nLeftShiftBits2 ) |
1802 													 ( ( ( (sal_uInt32) aCol.GetGreen() ) >> nRightShiftBits ) << nLeftShiftBits1 ) |
1803 													 ( ( (sal_uInt32) aCol.GetBlue() ) >> nRightShiftBits ) ] );
1804 						pWAcc->SetPixel( nY, nX, aDstCol );
1805 					}
1806 				}
1807 			}
1808 
1809 			delete[] pIndexMap;
1810 			aNewBmp.ReleaseAccess( pWAcc );
1811 			bRet = sal_True;
1812 		}
1813 
1814 		delete[] pCountTable;
1815 		ReleaseAccess( pRAcc );
1816 
1817 		if( bRet )
1818 		{
1819 			const MapMode	aMap( maPrefMapMode );
1820 			const Size		aSize( maPrefSize );
1821 
1822 			*this = aNewBmp;
1823 			maPrefMapMode = aMap;
1824 			maPrefSize = aSize;
1825 		}
1826 	}
1827 
1828 	return bRet;
1829 }
1830 
1831 // ------------------------------------------------------------------------
1832 
1833 sal_Bool Bitmap::ImplReduceMedian( sal_uInt16 nColCount )
1834 {
1835 	BitmapReadAccess*	pRAcc = AcquireReadAccess();
1836 	sal_uInt16				nBitCount;
1837 	sal_Bool				bRet = sal_False;
1838 
1839 	if( nColCount < 17 )
1840 		nBitCount = 4;
1841 	else if( nColCount < 257 )
1842 		nBitCount = 8;
1843 	else
1844 	{
1845 		DBG_ERROR( "Bitmap::ImplReduceMedian(): invalid color count!" );
1846 		nBitCount = 8;
1847 		nColCount = 256;
1848 	}
1849 
1850 	if( pRAcc )
1851 	{
1852 		Bitmap				aNewBmp( GetSizePixel(), nBitCount );
1853 		BitmapWriteAccess*	pWAcc = aNewBmp.AcquireWriteAccess();
1854 
1855 		if( pWAcc )
1856 		{
1857 			const sal_uLong	nSize = 32768UL * sizeof( sal_uLong );
1858 			sal_uLong*		pColBuf = (sal_uLong*) rtl_allocateMemory( nSize );
1859 			const long	nWidth = pWAcc->Width();
1860 			const long	nHeight = pWAcc->Height();
1861 			long		nIndex = 0L;
1862 
1863 			memset( (HPBYTE) pColBuf, 0, nSize );
1864 
1865 			// create Buffer
1866 			if( pRAcc->HasPalette() )
1867 			{
1868 				for( long nY = 0L; nY < nHeight; nY++ )
1869 				{
1870 					for( long nX = 0L; nX < nWidth; nX++ )
1871 					{
1872 						const BitmapColor& rCol = pRAcc->GetPaletteColor( pRAcc->GetPixelIndex( nY, nX ) );
1873 						pColBuf[ RGB15( rCol.GetRed() >> 3, rCol.GetGreen() >> 3, rCol.GetBlue() >> 3 ) ]++;
1874 					}
1875 				}
1876 			}
1877 			else
1878 			{
1879 				for( long nY = 0L; nY < nHeight; nY++ )
1880 				{
1881 					for( long nX = 0L; nX < nWidth; nX++ )
1882 					{
1883 						const BitmapColor aCol( pRAcc->GetPixel( nY, nX ) );
1884 						pColBuf[ RGB15( aCol.GetRed() >> 3, aCol.GetGreen() >> 3, aCol.GetBlue() >> 3 ) ]++;
1885 					}
1886 				}
1887 			}
1888 
1889 			// create palette via median cut
1890 			BitmapPalette aPal( pWAcc->GetPaletteEntryCount() );
1891 			ImplMedianCut( pColBuf, aPal, 0, 31, 0, 31, 0, 31,
1892 						   nColCount, nWidth * nHeight, nIndex );
1893 
1894 			// do mapping of colors to palette
1895 			InverseColorMap aMap( aPal );
1896 			pWAcc->SetPalette( aPal );
1897 			for( long nY = 0L; nY < nHeight; nY++ )
1898 				for( long nX = 0L; nX < nWidth; nX++ )
1899 					pWAcc->SetPixelIndex( nY, nX, static_cast<sal_uInt8>( aMap.GetBestPaletteIndex( pRAcc->GetColor( nY, nX ) )) );
1900 
1901 			rtl_freeMemory( pColBuf );
1902 			aNewBmp.ReleaseAccess( pWAcc );
1903 			bRet = sal_True;
1904 		}
1905 
1906 		ReleaseAccess( pRAcc );
1907 
1908 		if( bRet )
1909 		{
1910 			const MapMode	aMap( maPrefMapMode );
1911 			const Size		aSize( maPrefSize );
1912 
1913 			*this = aNewBmp;
1914 			maPrefMapMode = aMap;
1915 			maPrefSize = aSize;
1916 		}
1917 	}
1918 
1919 	return bRet;
1920 }
1921 
1922 // ------------------------------------------------------------------------
1923 
1924 void Bitmap::ImplMedianCut( sal_uLong* pColBuf, BitmapPalette& rPal,
1925 							long nR1, long nR2, long nG1, long nG2, long nB1, long nB2,
1926 							long nColors, long nPixels, long& rIndex )
1927 {
1928 	if( !nPixels )
1929 		return;
1930 
1931 	BitmapColor	aCol;
1932 	const long	nRLen = nR2 - nR1;
1933 	const long	nGLen = nG2 - nG1;
1934 	const long	nBLen = nB2 - nB1;
1935 	long 		nR, nG, nB;
1936 	sal_uLong*		pBuf = pColBuf;
1937 
1938 	if( !nRLen && !nGLen && !nBLen )
1939 	{
1940 		if( pBuf[ RGB15( nR1, nG1, nB1 ) ] )
1941 		{
1942 			aCol.SetRed( (sal_uInt8) ( nR1 << 3 ) );
1943 			aCol.SetGreen( (sal_uInt8) ( nG1 << 3 ) );
1944 			aCol.SetBlue( (sal_uInt8) ( nB1 << 3 ) );
1945 			rPal[ (sal_uInt16) rIndex++ ] = aCol;
1946 		}
1947 	}
1948 	else
1949 	{
1950 		if( 1 == nColors || 1 == nPixels )
1951 		{
1952 			long nPixSum = 0, nRSum = 0, nGSum = 0, nBSum = 0;
1953 
1954 			for( nR = nR1; nR <= nR2; nR++ )
1955 			{
1956 				for( nG = nG1; nG <= nG2; nG++ )
1957 				{
1958 					for( nB = nB1; nB <= nB2; nB++ )
1959 					{
1960 						nPixSum = pBuf[ RGB15( nR, nG, nB ) ];
1961 
1962 						if( nPixSum )
1963 						{
1964 							nRSum += nR * nPixSum;
1965 							nGSum += nG * nPixSum;
1966 							nBSum += nB * nPixSum;
1967 						}
1968 					}
1969 				}
1970 			}
1971 
1972 			aCol.SetRed( (sal_uInt8) ( ( nRSum / nPixels ) << 3 ) );
1973 			aCol.SetGreen( (sal_uInt8) ( ( nGSum / nPixels ) << 3 ) );
1974 			aCol.SetBlue( (sal_uInt8) ( ( nBSum / nPixels ) << 3 ) );
1975 			rPal[ (sal_uInt16) rIndex++ ] = aCol;
1976 		}
1977 		else
1978 		{
1979 			const long	nTest = ( nPixels >> 1 );
1980 			long		nPixOld = 0;
1981 			long		nPixNew = 0;
1982 
1983 			if( nBLen > nGLen && nBLen > nRLen )
1984 			{
1985 				nB = nB1 - 1;
1986 
1987 				while( nPixNew < nTest )
1988 				{
1989 					nB++, nPixOld = nPixNew;
1990 					for( nR = nR1; nR <= nR2; nR++ )
1991 						for( nG = nG1; nG <= nG2; nG++ )
1992 							nPixNew += pBuf[ RGB15( nR, nG, nB ) ];
1993 				}
1994 
1995 				if( nB < nB2 )
1996 				{
1997 					ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG2, nB1, nB, nColors >> 1, nPixNew, rIndex );
1998 					ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG2, nB + 1, nB2, nColors >> 1, nPixels - nPixNew, rIndex );
1999 				}
2000 				else
2001 				{
2002 					ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG2, nB1, nB - 1, nColors >> 1, nPixOld, rIndex );
2003 					ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG2, nB, nB2, nColors >> 1, nPixels - nPixOld, rIndex );
2004 				}
2005 			}
2006 			else if( nGLen > nRLen )
2007 			{
2008 				nG = nG1 - 1;
2009 
2010 				while( nPixNew < nTest )
2011 				{
2012 					nG++, nPixOld = nPixNew;
2013 					for( nR = nR1; nR <= nR2; nR++ )
2014 						for( nB = nB1; nB <= nB2; nB++ )
2015 							nPixNew += pBuf[ RGB15( nR, nG, nB ) ];
2016 				}
2017 
2018 				if( nG < nG2 )
2019 				{
2020 					ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG, nB1, nB2, nColors >> 1, nPixNew, rIndex );
2021 					ImplMedianCut( pBuf, rPal, nR1, nR2, nG + 1, nG2, nB1, nB2, nColors >> 1, nPixels - nPixNew, rIndex );
2022 				}
2023 				else
2024 				{
2025 					ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG - 1, nB1, nB2, nColors >> 1, nPixOld, rIndex );
2026 					ImplMedianCut( pBuf, rPal, nR1, nR2, nG, nG2, nB1, nB2, nColors >> 1, nPixels - nPixOld, rIndex );
2027 				}
2028 			}
2029 			else
2030 			{
2031 				nR = nR1 - 1;
2032 
2033 				while( nPixNew < nTest )
2034 				{
2035 					nR++, nPixOld = nPixNew;
2036 					for( nG = nG1; nG <= nG2; nG++ )
2037 						for( nB = nB1; nB <= nB2; nB++ )
2038 							nPixNew += pBuf[ RGB15( nR, nG, nB ) ];
2039 				}
2040 
2041 				if( nR < nR2 )
2042 				{
2043 					ImplMedianCut( pBuf, rPal, nR1, nR, nG1, nG2, nB1, nB2, nColors >> 1, nPixNew, rIndex );
2044 					ImplMedianCut( pBuf, rPal, nR1 + 1, nR2, nG1, nG2, nB1, nB2, nColors >> 1, nPixels - nPixNew, rIndex );
2045 				}
2046 				else
2047 				{
2048 					ImplMedianCut( pBuf, rPal, nR1, nR - 1, nG1, nG2, nB1, nB2, nColors >> 1, nPixOld, rIndex );
2049 					ImplMedianCut( pBuf, rPal, nR, nR2, nG1, nG2, nB1, nB2, nColors >> 1, nPixels - nPixOld, rIndex );
2050 				}
2051 			}
2052 		}
2053 	}
2054 }
2055 
2056 // ------------------------------------------------------------------------
2057 
2058 sal_Bool Bitmap::Vectorize( PolyPolygon& rPolyPoly, sal_uLong nFlags, const Link* pProgress )
2059 {
2060 	return ImplVectorizer().ImplVectorize( *this, rPolyPoly, nFlags, pProgress );
2061 }
2062 
2063 // ------------------------------------------------------------------------
2064 
2065 sal_Bool Bitmap::Vectorize( GDIMetaFile& rMtf, sal_uInt8 cReduce, sal_uLong nFlags, const Link* pProgress )
2066 {
2067 	return ImplVectorizer().ImplVectorize( *this, rMtf, cReduce, nFlags, pProgress );
2068 }
2069 
2070 // ------------------------------------------------------------------------
2071 
2072 sal_Bool Bitmap::Adjust( short nLuminancePercent, short nContrastPercent,
2073 					 short nChannelRPercent, short nChannelGPercent, short nChannelBPercent,
2074 					 double fGamma, sal_Bool bInvert )
2075 {
2076 	sal_Bool bRet = sal_False;
2077 
2078 	// nothing to do => return quickly
2079 	if( !nLuminancePercent && !nContrastPercent &&
2080 		!nChannelRPercent && !nChannelGPercent && !nChannelBPercent &&
2081 		( fGamma == 1.0 ) && !bInvert )
2082 	{
2083 		bRet = sal_True;
2084 	}
2085 	else
2086 	{
2087 		BitmapWriteAccess* pAcc = AcquireWriteAccess();
2088 
2089 		if( pAcc )
2090 		{
2091 			BitmapColor		aCol;
2092 			const long		nW = pAcc->Width();
2093 			const long		nH = pAcc->Height();
2094 			sal_uInt8*			cMapR = new sal_uInt8[ 256 ];
2095 			sal_uInt8*			cMapG = new sal_uInt8[ 256 ];
2096 			sal_uInt8*			cMapB = new sal_uInt8[ 256 ];
2097 			long			nX, nY;
2098 			double			fM, fROff, fGOff, fBOff, fOff;
2099 
2100 			// calculate slope
2101 			if( nContrastPercent >= 0 )
2102 				fM = 128.0 / ( 128.0 - 1.27 * MinMax( nContrastPercent, 0L, 100L ) );
2103 			else
2104 				fM = ( 128.0 + 1.27 * MinMax( nContrastPercent, -100L, 0L ) ) / 128.0;
2105 
2106 			// total offset = luminance offset + contrast offset
2107 			fOff = MinMax( nLuminancePercent, -100L, 100L ) * 2.55 + 128.0 - fM * 128.0;
2108 
2109 			// channel offset = channel offset  + total offset
2110 			fROff = nChannelRPercent * 2.55 + fOff;
2111 			fGOff = nChannelGPercent * 2.55 + fOff;
2112 			fBOff = nChannelBPercent * 2.55 + fOff;
2113 
2114 			// calculate gamma value
2115 			fGamma = ( fGamma <= 0.0 || fGamma > 10.0 ) ? 1.0 : ( 1.0 / fGamma );
2116 			const sal_Bool bGamma = ( fGamma != 1.0 );
2117 
2118 			// create mapping table
2119 			for( nX = 0L; nX < 256L; nX++ )
2120 			{
2121 				cMapR[ nX ] = (sal_uInt8) MinMax( FRound( nX * fM + fROff ), 0L, 255L );
2122 				cMapG[ nX ] = (sal_uInt8) MinMax( FRound( nX * fM + fGOff ), 0L, 255L );
2123 				cMapB[ nX ] = (sal_uInt8) MinMax( FRound( nX * fM + fBOff ), 0L, 255L );
2124 
2125 				if( bGamma )
2126 				{
2127 					cMapR[ nX ] = GAMMA( cMapR[ nX ], fGamma );
2128 					cMapG[ nX ] = GAMMA( cMapG[ nX ], fGamma );
2129 					cMapB[ nX ] = GAMMA( cMapB[ nX ], fGamma );
2130 				}
2131 
2132 				if( bInvert )
2133 				{
2134 					cMapR[ nX ] = ~cMapR[ nX ];
2135 					cMapG[ nX ] = ~cMapG[ nX ];
2136 					cMapB[ nX ] = ~cMapB[ nX ];
2137 				}
2138 			}
2139 
2140 			// do modifying
2141 			if( pAcc->HasPalette() )
2142 			{
2143 				BitmapColor aNewCol;
2144 
2145 				for( sal_uInt16 i = 0, nCount = pAcc->GetPaletteEntryCount(); i < nCount; i++ )
2146 				{
2147 					const BitmapColor& rCol = pAcc->GetPaletteColor( i );
2148 					aNewCol.SetRed( cMapR[ rCol.GetRed() ] );
2149 					aNewCol.SetGreen( cMapG[ rCol.GetGreen() ] );
2150 					aNewCol.SetBlue( cMapB[ rCol.GetBlue() ] );
2151 					pAcc->SetPaletteColor( i, aNewCol );
2152 				}
2153 			}
2154 			else if( pAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_BGR )
2155 			{
2156 				for( nY = 0L; nY < nH; nY++ )
2157 				{
2158 					Scanline pScan = pAcc->GetScanline( nY );
2159 
2160 					for( nX = 0L; nX < nW; nX++ )
2161 					{
2162 						*pScan = cMapB[ *pScan ]; pScan++;
2163 						*pScan = cMapG[ *pScan ]; pScan++;
2164 						*pScan = cMapR[ *pScan ]; pScan++;
2165 					}
2166 				}
2167 			}
2168 			else if( pAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_RGB )
2169 			{
2170 				for( nY = 0L; nY < nH; nY++ )
2171 				{
2172 					Scanline pScan = pAcc->GetScanline( nY );
2173 
2174 					for( nX = 0L; nX < nW; nX++ )
2175 					{
2176 						*pScan = cMapR[ *pScan ]; pScan++;
2177 						*pScan = cMapG[ *pScan ]; pScan++;
2178 						*pScan = cMapB[ *pScan ]; pScan++;
2179 					}
2180 				}
2181 			}
2182 			else
2183 			{
2184 				for( nY = 0L; nY < nH; nY++ )
2185 				{
2186 					for( nX = 0L; nX < nW; nX++ )
2187 					{
2188 						aCol = pAcc->GetPixel( nY, nX );
2189 						aCol.SetRed( cMapR[ aCol.GetRed() ] );
2190 						aCol.SetGreen( cMapG[ aCol.GetGreen() ] );
2191 						aCol.SetBlue( cMapB[ aCol.GetBlue() ] );
2192 						pAcc->SetPixel( nY, nX, aCol );
2193 					}
2194 				}
2195 			}
2196 
2197 			delete[] cMapR;
2198 			delete[] cMapG;
2199 			delete[] cMapB;
2200 			ReleaseAccess( pAcc );
2201 			bRet = sal_True;
2202 		}
2203 	}
2204 
2205 	return bRet;
2206 }
2207