xref: /trunk/main/vcl/source/gdi/bitmap3.cxx (revision 0f740837)
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         if ( !pReadAcc )
955             return sal_False;
956 
957 		Bitmap				aNewBmp( Size( nNewWidth, nNewHeight ), GetBitCount(), &pReadAcc->GetPalette() );
958 		BitmapWriteAccess*	pWriteAcc = aNewBmp.AcquireWriteAccess();
959 
960 		if( pWriteAcc )
961 		{
962 			const long	nScanlineSize = pWriteAcc->GetScanlineSize();
963 			const long	nNewWidth1 = nNewWidth - 1L;
964 			const long	nNewHeight1 = nNewHeight - 1L;
965 			const long	nWidth = pReadAcc->Width();
966 			const long	nHeight = pReadAcc->Height();
967 			long*		pLutX = new long[ nNewWidth ];
968 			long*		pLutY = new long[ nNewHeight ];
969 			long		nX, nY, nMapY, nActY = 0L;
970 
971 			if( nNewWidth1 && nNewHeight1 )
972 			{
973 				for( nX = 0L; nX < nNewWidth; nX++ )
974 					pLutX[ nX ] = nX * nWidth / nNewWidth;
975 
976 				for( nY = 0L; nY < nNewHeight; nY++ )
977 					pLutY[ nY ] = nY * nHeight / nNewHeight;
978 
979 				while( nActY < nNewHeight )
980 				{
981 					nMapY = pLutY[ nActY ];
982 
983 					for( nX = 0L; nX < nNewWidth; nX++ )
984 						pWriteAcc->SetPixel( nActY, nX, pReadAcc->GetPixel( nMapY , pLutX[ nX ] ) );
985 
986 					while( ( nActY < nNewHeight1 ) && ( pLutY[ nActY + 1 ] == nMapY ) )
987 					{
988 						memcpy( pWriteAcc->GetScanline( nActY + 1L ),
989 								 pWriteAcc->GetScanline( nActY ), nScanlineSize );
990 						nActY++;
991 					}
992 
993 					nActY++;
994 				}
995 
996 				bRet = sal_True;
997 			}
998 
999 			delete[] pLutX;
1000 			delete[] pLutY;
1001 		}
1002 
1003 		ReleaseAccess( pReadAcc );
1004 		aNewBmp.ReleaseAccess( pWriteAcc );
1005 
1006 		if( bRet )
1007 			ImplAssignWithSize( aNewBmp );
1008 	}
1009 
1010 	return bRet;
1011 }
1012 
1013 // ------------------------------------------------------------------------
1014 
1015 sal_Bool Bitmap::ImplScaleInterpolate( const double& rScaleX, const double& rScaleY )
1016 {
1017 	const Size	aSizePix( GetSizePixel() );
1018 	const long	nNewWidth = FRound( aSizePix.Width() * rScaleX );
1019 	const long	nNewHeight = FRound( aSizePix.Height() * rScaleY );
1020 	sal_Bool		bRet = sal_False;
1021 
1022 	if( ( nNewWidth > 1L ) && ( nNewHeight > 1L ) )
1023 	{
1024 		BitmapColor 		aCol0;
1025 		BitmapColor 		aCol1;
1026 		BitmapReadAccess*	pReadAcc = AcquireReadAccess();
1027 		long				nWidth = pReadAcc->Width();
1028 		long				nHeight = pReadAcc->Height();
1029 		Bitmap				aNewBmp( Size( nNewWidth, nHeight ), 24 );
1030 		BitmapWriteAccess*	pWriteAcc = aNewBmp.AcquireWriteAccess();
1031 		long*				pLutInt;
1032 		long*				pLutFrac;
1033 		long				nX, nY;
1034 		long				lXB0, lXB1, lXG0, lXG1, lXR0, lXR1;
1035 		double				fTemp;
1036 		long				nTemp;
1037 
1038 		if( pReadAcc && pWriteAcc )
1039 		{
1040 			const long		nNewWidth1 = nNewWidth - 1L;
1041 			const long		nWidth1 = pReadAcc->Width() - 1L;
1042 			const double	fRevScaleX = (double) nWidth1 / nNewWidth1;
1043 
1044 			pLutInt = new long[ nNewWidth ];
1045 			pLutFrac = new long[ nNewWidth ];
1046 
1047 			for( nX = 0L, nTemp = nWidth - 2L; nX < nNewWidth; nX++ )
1048 			{
1049 				fTemp = nX * fRevScaleX;
1050 				pLutInt[ nX ] = MinMax( (long) fTemp, 0, nTemp );
1051 				fTemp -= pLutInt[ nX ];
1052 				pLutFrac[ nX ] = (long) ( fTemp * 1024. );
1053 			}
1054 
1055 			if( pReadAcc->HasPalette() )
1056 			{
1057 				for( nY = 0L; nY < nHeight; nY++ )
1058 				{
1059 					if( 1 == nWidth )
1060 					{
1061 						aCol0 = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nY, 0 ) );
1062 
1063 						for( nX = 0L; nX < nNewWidth; nX++ )
1064 							pWriteAcc->SetPixel( nY, nX, aCol0 );
1065 					}
1066 					else
1067 					{
1068 						for( nX = 0L; nX < nNewWidth; nX++ )
1069 						{
1070 							nTemp = pLutInt[ nX ];
1071 
1072 							aCol0 = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nY, nTemp++ ) );
1073 							aCol1 = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nY, nTemp ) );
1074 
1075 							nTemp = pLutFrac[ nX ];
1076 
1077 							lXR1 = aCol1.GetRed() - ( lXR0 = aCol0.GetRed() );
1078 							lXG1 = aCol1.GetGreen() - ( lXG0 = aCol0.GetGreen() );
1079 							lXB1 = aCol1.GetBlue() - ( lXB0 = aCol0.GetBlue() );
1080 
1081 							aCol0.SetRed( (sal_uInt8) ( ( lXR1 * nTemp + ( lXR0 << 10 ) ) >> 10 ) );
1082 							aCol0.SetGreen( (sal_uInt8) ( ( lXG1 * nTemp + ( lXG0 << 10 ) ) >> 10 ) );
1083 							aCol0.SetBlue( (sal_uInt8) ( ( lXB1 * nTemp + ( lXB0 << 10 ) ) >> 10 ) );
1084 
1085 							pWriteAcc->SetPixel( nY, nX, aCol0 );
1086 						}
1087 					}
1088 				}
1089 			}
1090 			else
1091 			{
1092 				for( nY = 0L; nY < nHeight; nY++ )
1093 				{
1094 					if( 1 == nWidth )
1095 					{
1096 						aCol0 = pReadAcc->GetPixel( nY, 0 );
1097 
1098 						for( nX = 0L; nX < nNewWidth; nX++ )
1099 							pWriteAcc->SetPixel( nY, nX, aCol0 );
1100 					}
1101 					else
1102 					{
1103 						for( nX = 0L; nX < nNewWidth; nX++ )
1104 						{
1105 							nTemp = pLutInt[ nX ];
1106 
1107 							aCol0 = pReadAcc->GetPixel( nY, nTemp++ );
1108 							aCol1 = pReadAcc->GetPixel( nY, nTemp );
1109 
1110 							nTemp = pLutFrac[ nX ];
1111 
1112 							lXR1 = aCol1.GetRed() - ( lXR0 = aCol0.GetRed() );
1113 							lXG1 = aCol1.GetGreen() - ( lXG0 = aCol0.GetGreen() );
1114 							lXB1 = aCol1.GetBlue() - ( lXB0 = aCol0.GetBlue() );
1115 
1116 							aCol0.SetRed( (sal_uInt8) ( ( lXR1 * nTemp + ( lXR0 << 10 ) ) >> 10 ) );
1117 							aCol0.SetGreen( (sal_uInt8) ( ( lXG1 * nTemp + ( lXG0 << 10 ) ) >> 10 ) );
1118 							aCol0.SetBlue( (sal_uInt8) ( ( lXB1 * nTemp + ( lXB0 << 10 ) ) >> 10 ) );
1119 
1120 							pWriteAcc->SetPixel( nY, nX, aCol0 );
1121 						}
1122 					}
1123 				}
1124 			}
1125 
1126 			delete[] pLutInt;
1127 			delete[] pLutFrac;
1128 			bRet = sal_True;
1129 		}
1130 
1131 		ReleaseAccess( pReadAcc );
1132 		aNewBmp.ReleaseAccess( pWriteAcc );
1133 
1134 		if( bRet )
1135 		{
1136 			bRet = sal_False;
1137 			ImplAssignWithSize( aNewBmp );
1138 			pReadAcc = AcquireReadAccess();
1139 			aNewBmp = Bitmap( Size( nNewWidth, nNewHeight ), 24 );
1140 			pWriteAcc = aNewBmp.AcquireWriteAccess();
1141 
1142 			if( pReadAcc && pWriteAcc )
1143 			{
1144 				const long		nNewHeight1 = nNewHeight - 1L;
1145 				const long		nHeight1 = pReadAcc->Height() - 1L;
1146 				const double	fRevScaleY = (double) nHeight1 / nNewHeight1;
1147 
1148 				pLutInt = new long[ nNewHeight ];
1149 				pLutFrac = new long[ nNewHeight ];
1150 
1151 				for( nY = 0L, nTemp = nHeight - 2L; nY < nNewHeight; nY++ )
1152 				{
1153 					fTemp = nY * fRevScaleY;
1154 					pLutInt[ nY ] = MinMax( (long) fTemp, 0, nTemp );
1155 					fTemp -= pLutInt[ nY ];
1156 					pLutFrac[ nY ] = (long) ( fTemp * 1024. );
1157 				}
1158 
1159 				if( pReadAcc->HasPalette() )
1160 				{
1161 					for( nX = 0L; nX < nNewWidth; nX++ )
1162 					{
1163 						if( 1 == nHeight )
1164 						{
1165 							aCol0 = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( 0, nX ) );
1166 
1167 							for( nY = 0L; nY < nNewHeight; nY++ )
1168 								pWriteAcc->SetPixel( nY, nX, aCol0 );
1169 						}
1170 						else
1171 						{
1172 							for( nY = 0L; nY < nNewHeight; nY++ )
1173 							{
1174 								nTemp = pLutInt[ nY ];
1175 
1176 								aCol0 = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nTemp++, nX ) );
1177 								aCol1 = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nTemp, nX ) );
1178 
1179 								nTemp = pLutFrac[ nY ];
1180 
1181 								lXR1 = aCol1.GetRed() - ( lXR0 = aCol0.GetRed() );
1182 								lXG1 = aCol1.GetGreen() - ( lXG0 = aCol0.GetGreen() );
1183 								lXB1 = aCol1.GetBlue() - ( lXB0 = aCol0.GetBlue() );
1184 
1185 								aCol0.SetRed( (sal_uInt8) ( ( lXR1 * nTemp + ( lXR0 << 10 ) ) >> 10 ) );
1186 								aCol0.SetGreen( (sal_uInt8) ( ( lXG1 * nTemp + ( lXG0 << 10 ) ) >> 10 ) );
1187 								aCol0.SetBlue( (sal_uInt8) ( ( lXB1 * nTemp + ( lXB0 << 10 ) ) >> 10 ) );
1188 
1189 								pWriteAcc->SetPixel( nY, nX, aCol0 );
1190 							}
1191 						}
1192 					}
1193 				}
1194 				else
1195 				{
1196 					for( nX = 0L; nX < nNewWidth; nX++ )
1197 					{
1198 						if( 1 == nHeight )
1199 						{
1200 							aCol0 = pReadAcc->GetPixel( 0, nX );
1201 
1202 							for( nY = 0L; nY < nNewHeight; nY++ )
1203 								pWriteAcc->SetPixel( nY, nX, aCol0 );
1204 						}
1205 						else
1206 						{
1207 							for( nY = 0L; nY < nNewHeight; nY++ )
1208 							{
1209 								nTemp = pLutInt[ nY ];
1210 
1211 								aCol0 = pReadAcc->GetPixel( nTemp++, nX );
1212 								aCol1 = pReadAcc->GetPixel( nTemp, nX );
1213 
1214 								nTemp = pLutFrac[ nY ];
1215 
1216 								lXR1 = aCol1.GetRed() - ( lXR0 = aCol0.GetRed() );
1217 								lXG1 = aCol1.GetGreen() - ( lXG0 = aCol0.GetGreen() );
1218 								lXB1 = aCol1.GetBlue() - ( lXB0 = aCol0.GetBlue() );
1219 
1220 								aCol0.SetRed( (sal_uInt8) ( ( lXR1 * nTemp + ( lXR0 << 10 ) ) >> 10 ) );
1221 								aCol0.SetGreen( (sal_uInt8) ( ( lXG1 * nTemp + ( lXG0 << 10 ) ) >> 10 ) );
1222 								aCol0.SetBlue( (sal_uInt8) ( ( lXB1 * nTemp + ( lXB0 << 10 ) ) >> 10 ) );
1223 
1224 								pWriteAcc->SetPixel( nY, nX, aCol0 );
1225 							}
1226 						}
1227 					}
1228 				}
1229 
1230 				delete[] pLutInt;
1231 				delete[] pLutFrac;
1232 				bRet = sal_True;
1233 			}
1234 
1235 			ReleaseAccess( pReadAcc );
1236 			aNewBmp.ReleaseAccess( pWriteAcc );
1237 
1238 			if( bRet )
1239 				ImplAssignWithSize( aNewBmp );
1240 		}
1241 	}
1242 
1243 	if( !bRet )
1244 		bRet = ImplScaleFast( rScaleX, rScaleY );
1245 
1246 	return bRet;
1247 }
1248 
1249 // ------------------------------------------------------------------------
1250 
1251 sal_Bool Bitmap::Dither( sal_uLong nDitherFlags )
1252 {
1253 	sal_Bool bRet = sal_False;
1254 
1255 	const Size aSizePix( GetSizePixel() );
1256 
1257 	if( aSizePix.Width() == 1 || aSizePix.Height() == 1 )
1258 		bRet = sal_True;
1259 	else if( nDitherFlags & BMP_DITHER_MATRIX )
1260 		bRet = ImplDitherMatrix();
1261 	else if( nDitherFlags & BMP_DITHER_FLOYD )
1262 		bRet = ImplDitherFloyd();
1263 	else if( ( nDitherFlags & BMP_DITHER_FLOYD_16 ) && ( GetBitCount() == 24 ) )
1264 		bRet = ImplDitherFloyd16();
1265 
1266 	return bRet;
1267 }
1268 
1269 // ------------------------------------------------------------------------
1270 
1271 sal_Bool Bitmap::ImplDitherMatrix()
1272 {
1273 	BitmapReadAccess*	pReadAcc = AcquireReadAccess();
1274 	Bitmap				aNewBmp( GetSizePixel(), 8 );
1275 	BitmapWriteAccess*	pWriteAcc = aNewBmp.AcquireWriteAccess();
1276 	sal_Bool				bRet = sal_False;
1277 
1278 	if( pReadAcc && pWriteAcc )
1279 	{
1280 		const sal_uLong	nWidth = pReadAcc->Width();
1281 		const sal_uLong	nHeight = pReadAcc->Height();
1282 		BitmapColor	aIndex( (sal_uInt8) 0 );
1283 
1284 		if( pReadAcc->HasPalette() )
1285 		{
1286 			for( sal_uLong nY = 0UL; nY < nHeight; nY++ )
1287 			{
1288 				for( sal_uLong nX = 0UL, nModY = ( nY & 0x0FUL ) << 4UL; nX < nWidth; nX++ )
1289 				{
1290 					const BitmapColor	aCol( pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nY, nX ) ) );
1291 					const sal_uLong			nD = nVCLDitherLut[ nModY + ( nX & 0x0FUL ) ];
1292 					const sal_uLong			nR = ( nVCLLut[ aCol.GetRed() ] + nD ) >> 16UL;
1293 					const sal_uLong			nG = ( nVCLLut[ aCol.GetGreen() ] + nD ) >> 16UL;
1294 					const sal_uLong			nB = ( nVCLLut[ aCol.GetBlue() ] + nD ) >> 16UL;
1295 
1296 					aIndex.SetIndex( (sal_uInt8) ( nVCLRLut[ nR ] + nVCLGLut[ nG ] + nVCLBLut[ nB ] ) );
1297 					pWriteAcc->SetPixel( nY, nX, aIndex );
1298 				}
1299 			}
1300 		}
1301 		else
1302 		{
1303 			for( sal_uLong nY = 0UL; nY < nHeight; nY++ )
1304 			{
1305 				for( sal_uLong nX = 0UL, nModY = ( nY & 0x0FUL ) << 4UL; nX < nWidth; nX++ )
1306 				{
1307 					const BitmapColor	aCol( pReadAcc->GetPixel( nY, nX ) );
1308 					const sal_uLong			nD = nVCLDitherLut[ nModY + ( nX & 0x0FUL ) ];
1309 					const sal_uLong			nR = ( nVCLLut[ aCol.GetRed() ] + nD ) >> 16UL;
1310 					const sal_uLong			nG = ( nVCLLut[ aCol.GetGreen() ] + nD ) >> 16UL;
1311 					const sal_uLong			nB = ( nVCLLut[ aCol.GetBlue() ] + nD ) >> 16UL;
1312 
1313 					aIndex.SetIndex( (sal_uInt8) ( nVCLRLut[ nR ] + nVCLGLut[ nG ] + nVCLBLut[ nB ] ) );
1314 					pWriteAcc->SetPixel( nY, nX, aIndex );
1315 				}
1316 			}
1317 		}
1318 
1319 		bRet = sal_True;
1320 	}
1321 
1322 	ReleaseAccess( pReadAcc );
1323 	aNewBmp.ReleaseAccess( pWriteAcc );
1324 
1325 	if( bRet )
1326 	{
1327 		const MapMode	aMap( maPrefMapMode );
1328 		const Size		aSize( maPrefSize );
1329 
1330 		*this = aNewBmp;
1331 
1332 		maPrefMapMode = aMap;
1333 		maPrefSize = aSize;
1334 	}
1335 
1336 	return bRet;
1337 }
1338 
1339 // ------------------------------------------------------------------------
1340 
1341 sal_Bool Bitmap::ImplDitherFloyd()
1342 {
1343 	const Size	aSize( GetSizePixel() );
1344 	sal_Bool		bRet = sal_False;
1345 
1346 	if( ( aSize.Width() > 3 ) && ( aSize.Height() > 2 ) )
1347 	{
1348 		BitmapReadAccess*	pReadAcc = AcquireReadAccess();
1349 		Bitmap				aNewBmp( GetSizePixel(), 8 );
1350 		BitmapWriteAccess*	pWriteAcc = aNewBmp.AcquireWriteAccess();
1351 
1352 		if( pReadAcc && pWriteAcc )
1353 		{
1354 			BitmapColor	aColor;
1355 			long		nWidth = pReadAcc->Width();
1356 			long		nWidth1 = nWidth - 1L;
1357 			long		nHeight = pReadAcc->Height();
1358 			long		nX;
1359 			long		nW = nWidth * 3L;
1360 			long		nW2 = nW - 3L;
1361 			long		nRErr, nGErr, nBErr;
1362 			long		nRC, nGC, nBC;
1363 			long		nTemp;
1364 			long		nZ;
1365 			long*		p1 = new long[ nW ];
1366 			long*		p2 = new long[ nW ];
1367 			long*		p1T = p1;
1368 			long*		p2T = p2;
1369 			long*		pTmp;
1370 			sal_Bool		bPal = pReadAcc->HasPalette();
1371 
1372 			pTmp = p2T;
1373 
1374 			if( bPal )
1375 			{
1376 				for( nZ = 0; nZ < nWidth; nZ++ )
1377 				{
1378 					aColor = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( 0, nZ ) );
1379 
1380 					*pTmp++ = (long) aColor.GetBlue() << 12;
1381 					*pTmp++ = (long) aColor.GetGreen() << 12;
1382 					*pTmp++ = (long) aColor.GetRed() << 12;
1383 				}
1384 			}
1385 			else
1386 			{
1387 				for( nZ = 0; nZ < nWidth; nZ++ )
1388 				{
1389 					aColor = pReadAcc->GetPixel( 0, nZ );
1390 
1391 					*pTmp++ = (long) aColor.GetBlue() << 12;
1392 					*pTmp++ = (long) aColor.GetGreen() << 12;
1393 					*pTmp++ = (long) aColor.GetRed() << 12;
1394 				}
1395 			}
1396 
1397 			for( long nY = 1, nYAcc = 0L; nY <= nHeight; nY++, nYAcc++ )
1398 			{
1399 				pTmp = p1T;
1400 				p1T = p2T;
1401 				p2T = pTmp;
1402 
1403 				if( nY < nHeight )
1404 				{
1405 					if( bPal )
1406 					{
1407 						for( nZ = 0; nZ < nWidth; nZ++ )
1408 						{
1409 							aColor = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nY, nZ ) );
1410 
1411 							*pTmp++ = (long) aColor.GetBlue() << 12;
1412 							*pTmp++ = (long) aColor.GetGreen() << 12;
1413 							*pTmp++ = (long) aColor.GetRed() << 12;
1414 						}
1415 					}
1416 					else
1417 					{
1418 						for( nZ = 0; nZ < nWidth; nZ++ )
1419 						{
1420 							aColor = pReadAcc->GetPixel( nY, nZ );
1421 
1422 							*pTmp++ = (long) aColor.GetBlue() << 12;
1423 							*pTmp++ = (long) aColor.GetGreen() << 12;
1424 							*pTmp++ = (long) aColor.GetRed() << 12;
1425 						}
1426 					}
1427 				}
1428 
1429 				// erstes Pixel gesondert betrachten
1430 				nX = 0;
1431 				CALC_ERRORS;
1432 				CALC_TABLES7;
1433 				nX -= 5;
1434 				CALC_TABLES5;
1435 				pWriteAcc->SetPixel( nYAcc, 0, BitmapColor( (sal_uInt8) ( nVCLBLut[ nBC ] + nVCLGLut[nGC ] + nVCLRLut[nRC ] ) ) );
1436 
1437 				// mittlere Pixel ueber Schleife
1438 				long nXAcc;
1439 				for ( nX = 3L, nXAcc = 1L; nX < nW2; nXAcc++ )
1440 				{
1441 					CALC_ERRORS;
1442 					CALC_TABLES7;
1443 					nX -= 8;
1444 					CALC_TABLES3;
1445 					CALC_TABLES5;
1446 					pWriteAcc->SetPixel( nYAcc, nXAcc, BitmapColor( (sal_uInt8) ( nVCLBLut[ nBC ] + nVCLGLut[nGC ] + nVCLRLut[nRC ] ) ) );
1447 				}
1448 
1449 				// letztes Pixel gesondert betrachten
1450 				CALC_ERRORS;
1451 				nX -= 5;
1452 				CALC_TABLES3;
1453 				CALC_TABLES5;
1454 				pWriteAcc->SetPixel( nYAcc, nWidth1, BitmapColor( (sal_uInt8) ( nVCLBLut[ nBC ] + nVCLGLut[nGC ] + nVCLRLut[nRC ] ) ) );
1455 			}
1456 
1457 			delete[] p1;
1458 			delete[] p2;
1459 			bRet = sal_True;
1460 		}
1461 
1462 		ReleaseAccess( pReadAcc );
1463 		aNewBmp.ReleaseAccess( pWriteAcc );
1464 
1465 		if( bRet )
1466 		{
1467 			const MapMode	aMap( maPrefMapMode );
1468 			const Size		aPrefSize( maPrefSize );
1469 
1470 			*this = aNewBmp;
1471 
1472 			maPrefMapMode = aMap;
1473 			maPrefSize = aPrefSize;
1474 		}
1475 	}
1476 
1477 	return bRet;
1478 }
1479 
1480 // ------------------------------------------------------------------------
1481 
1482 sal_Bool Bitmap::ImplDitherFloyd16()
1483 {
1484 	BitmapReadAccess*	pReadAcc = AcquireReadAccess();
1485 	Bitmap				aNewBmp( GetSizePixel(), 24 );
1486 	BitmapWriteAccess*	pWriteAcc = aNewBmp.AcquireWriteAccess();
1487 	sal_Bool				bRet = sal_False;
1488 
1489 	if( pReadAcc && pWriteAcc )
1490 	{
1491 		const long		nWidth = pWriteAcc->Width();
1492 		const long		nWidth1 = nWidth - 1L;
1493 		const long		nHeight = pWriteAcc->Height();
1494 		BitmapColor 	aColor;
1495 		BitmapColor		aBestCol;
1496 		ImpErrorQuad	aErrQuad;
1497 		ImpErrorQuad*	pErrQuad1 = new ImpErrorQuad[ nWidth ];
1498 		ImpErrorQuad*	pErrQuad2 = new ImpErrorQuad[ nWidth ];
1499 		ImpErrorQuad*	pQLine1 = pErrQuad1;
1500 		ImpErrorQuad*	pQLine2 = 0;
1501 		long			nX, nY;
1502 		long			nYTmp = 0L;
1503 		sal_Bool			bQ1 = sal_True;
1504 
1505 		for( nY = 0L; nY < Min( nHeight, 2L ); nY++, nYTmp++ )
1506 			for( nX = 0L, pQLine2 = !nY ? pErrQuad1 : pErrQuad2; nX < nWidth; nX++ )
1507 				pQLine2[ nX ] = pReadAcc->GetPixel( nYTmp, nX );
1508 
1509 		for( nY = 0L; nY < nHeight; nY++, nYTmp++ )
1510 		{
1511 			// erstes ZeilenPixel
1512 			aBestCol = pQLine1[ 0 ].ImplGetColor();
1513 			aBestCol.SetRed( ( aBestCol.GetRed() & 248 ) | 7 );
1514 			aBestCol.SetGreen( ( aBestCol.GetGreen() & 248 ) | 7 );
1515 			aBestCol.SetBlue( ( aBestCol.GetBlue() & 248 ) | 7 );
1516 			pWriteAcc->SetPixel( nY, 0, aBestCol );
1517 
1518 			for( nX = 1L; nX < nWidth1; nX++ )
1519 			{
1520 				aColor = pQLine1[ nX ].ImplGetColor();
1521 				aBestCol.SetRed( ( aColor.GetRed() & 248 ) | 7 );
1522 				aBestCol.SetGreen( ( aColor.GetGreen() & 248 ) | 7 );
1523 				aBestCol.SetBlue( ( aColor.GetBlue() & 248 ) | 7 );
1524 				aErrQuad = ( ImpErrorQuad( aColor ) -= aBestCol );
1525 				pQLine1[ ++nX ].ImplAddColorError7( aErrQuad );
1526 				pQLine2[ nX-- ].ImplAddColorError1( aErrQuad );
1527 				pQLine2[ nX-- ].ImplAddColorError5( aErrQuad );
1528 				pQLine2[ nX++ ].ImplAddColorError3( aErrQuad );
1529 				pWriteAcc->SetPixel( nY, nX, aBestCol );
1530 			}
1531 
1532 			// letztes ZeilenPixel
1533 			aBestCol = pQLine1[ nWidth1 ].ImplGetColor();
1534 			aBestCol.SetRed( ( aBestCol.GetRed() & 248 ) | 7 );
1535 			aBestCol.SetGreen( ( aBestCol.GetGreen() & 248 ) | 7 );
1536 			aBestCol.SetBlue( ( aBestCol.GetBlue() & 248 ) | 7 );
1537 			pWriteAcc->SetPixel( nY, nX, aBestCol );
1538 
1539 			// Zeilenpuffer neu fuellen/kopieren
1540 			pQLine1 = pQLine2;
1541 			pQLine2 = ( bQ1 = !bQ1 ) != sal_False ? pErrQuad2 : pErrQuad1;
1542 
1543 			if( nYTmp < nHeight )
1544 				for( nX = 0L; nX < nWidth; nX++ )
1545 					pQLine2[ nX ] = pReadAcc->GetPixel( nYTmp, nX );
1546 		}
1547 
1548 		// Zeilenpuffer zerstoeren
1549 		delete[] pErrQuad1;
1550 		delete[] pErrQuad2;
1551 		bRet = sal_True;
1552 	}
1553 
1554 	ReleaseAccess( pReadAcc );
1555 	aNewBmp.ReleaseAccess( pWriteAcc );
1556 
1557 	if( bRet )
1558 	{
1559 		const MapMode	aMap( maPrefMapMode );
1560 		const Size		aSize( maPrefSize );
1561 
1562 		*this = aNewBmp;
1563 
1564 		maPrefMapMode = aMap;
1565 		maPrefSize = aSize;
1566 	}
1567 
1568 	return bRet;
1569 }
1570 
1571 // ------------------------------------------------------------------------
1572 
1573 sal_Bool Bitmap::ReduceColors( sal_uInt16 nColorCount, BmpReduce eReduce )
1574 {
1575 	sal_Bool bRet;
1576 
1577 	if( GetColorCount() <= (sal_uLong) nColorCount )
1578 		bRet = sal_True;
1579 	else if( nColorCount )
1580 	{
1581 		if( BMP_REDUCE_SIMPLE == eReduce )
1582 			bRet = ImplReduceSimple( nColorCount );
1583 		else if( BMP_REDUCE_POPULAR == eReduce )
1584 			bRet = ImplReducePopular( nColorCount );
1585 		else
1586 			bRet = ImplReduceMedian( nColorCount );
1587 	}
1588 	else
1589 		bRet = sal_False;
1590 
1591 	return bRet;
1592 }
1593 
1594 // ------------------------------------------------------------------------
1595 
1596 sal_Bool Bitmap::ImplReduceSimple( sal_uInt16 nColorCount )
1597 {
1598 	Bitmap				aNewBmp;
1599 	BitmapReadAccess*	pRAcc = AcquireReadAccess();
1600 	const sal_uInt16		nColCount = Min( nColorCount, (sal_uInt16) 256 );
1601 	sal_uInt16				nBitCount;
1602 	sal_Bool				bRet = sal_False;
1603 
1604 	if( nColCount <= 2 )
1605 		nBitCount = 1;
1606 	else if( nColCount <= 16 )
1607 		nBitCount = 4;
1608 	else
1609 		nBitCount = 8;
1610 
1611 	if( pRAcc )
1612 	{
1613 		Octree					aOct( *pRAcc, nColCount );
1614 		const BitmapPalette&	rPal = aOct.GetPalette();
1615 		BitmapWriteAccess*		pWAcc;
1616 
1617 		aNewBmp = Bitmap( GetSizePixel(), nBitCount, &rPal );
1618 		pWAcc = aNewBmp.AcquireWriteAccess();
1619 
1620 		if( pWAcc )
1621 		{
1622 			const long nWidth = pRAcc->Width();
1623 			const long nHeight = pRAcc->Height();
1624 
1625 			if( pRAcc->HasPalette() )
1626 			{
1627 				for( long nY = 0L; nY < nHeight; nY++ )
1628 					for( long nX =0L; nX < nWidth; nX++ )
1629 						pWAcc->SetPixel( nY, nX, (sal_uInt8) aOct.GetBestPaletteIndex( pRAcc->GetPaletteColor( pRAcc->GetPixel( nY, nX ) ) ) );
1630 			}
1631 			else
1632 			{
1633 				for( long nY = 0L; nY < nHeight; nY++ )
1634 					for( long nX =0L; nX < nWidth; nX++ )
1635 						pWAcc->SetPixel( nY, nX, (sal_uInt8) aOct.GetBestPaletteIndex( pRAcc->GetPixel( nY, nX ) ) );
1636 			}
1637 
1638 			aNewBmp.ReleaseAccess( pWAcc );
1639 			bRet = sal_True;
1640 		}
1641 
1642 		ReleaseAccess( pRAcc );
1643 	}
1644 
1645 	if( bRet )
1646 	{
1647 		const MapMode	aMap( maPrefMapMode );
1648 		const Size		aSize( maPrefSize );
1649 
1650 		*this = aNewBmp;
1651 		maPrefMapMode = aMap;
1652 		maPrefSize = aSize;
1653 	}
1654 
1655 	return bRet;
1656 }
1657 
1658 // ------------------------------------------------------------------------
1659 
1660 struct PopularColorCount
1661 {
1662 	sal_uInt32	mnIndex;
1663 	sal_uInt32	mnCount;
1664 };
1665 
1666 // ------------------------------------------------------------------------
1667 
1668 extern "C" int __LOADONCALLAPI ImplPopularCmpFnc( const void* p1, const void* p2 )
1669 {
1670 	int nRet;
1671 
1672 	if( ( (PopularColorCount*) p1 )->mnCount < ( (PopularColorCount*) p2 )->mnCount )
1673 		nRet = 1;
1674 	else if( ( (PopularColorCount*) p1 )->mnCount == ( (PopularColorCount*) p2 )->mnCount )
1675 		nRet = 0;
1676 	else
1677 		nRet = -1;
1678 
1679 	return nRet;
1680 }
1681 
1682 // ------------------------------------------------------------------------
1683 
1684 sal_Bool Bitmap::ImplReducePopular( sal_uInt16 nColCount )
1685 {
1686 	BitmapReadAccess*	pRAcc = AcquireReadAccess();
1687 	sal_uInt16				nBitCount;
1688 	sal_Bool				bRet = sal_False;
1689 
1690 	if( nColCount > 256 )
1691 		nColCount = 256;
1692 
1693 	if( nColCount < 17 )
1694 		nBitCount = 4;
1695 	else
1696 		nBitCount = 8;
1697 
1698 	if( pRAcc )
1699 	{
1700 		const sal_uInt32	nValidBits = 4;
1701 		const sal_uInt32	nRightShiftBits = 8 - nValidBits;
1702 		const sal_uInt32	nLeftShiftBits1 = nValidBits;
1703 		const sal_uInt32	nLeftShiftBits2 = nValidBits << 1;
1704 		const sal_uInt32	nColorsPerComponent = 1 << nValidBits;
1705 		const sal_uInt32	nColorOffset = 256 / nColorsPerComponent;
1706 		const sal_uInt32	nTotalColors = nColorsPerComponent * nColorsPerComponent * nColorsPerComponent;
1707 		const long			nWidth = pRAcc->Width();
1708 		const long			nHeight = pRAcc->Height();
1709 		PopularColorCount*	pCountTable = new PopularColorCount[ nTotalColors ];
1710 		long				nX, nY, nR, nG, nB, nIndex;
1711 
1712 		rtl_zeroMemory( pCountTable, nTotalColors * sizeof( PopularColorCount ) );
1713 
1714 		for( nR = 0, nIndex = 0; nR < 256; nR += nColorOffset )
1715         {
1716 			for( nG = 0; nG < 256; nG += nColorOffset )
1717             {
1718 				for( nB = 0; nB < 256; nB += nColorOffset )
1719                 {
1720 					pCountTable[ nIndex ].mnIndex = nIndex;
1721                     nIndex++;
1722                 }
1723             }
1724         }
1725 
1726 		if( pRAcc->HasPalette() )
1727 		{
1728 			for( nY = 0L; nY < nHeight; nY++ )
1729 			{
1730 				for( nX = 0L; nX < nWidth; nX++ )
1731 				{
1732 					const BitmapColor& rCol = pRAcc->GetPaletteColor( pRAcc->GetPixel( nY, nX ) );
1733 					pCountTable[ ( ( ( (sal_uInt32) rCol.GetRed() ) >> nRightShiftBits ) << nLeftShiftBits2 ) |
1734 								 ( ( ( (sal_uInt32) rCol.GetGreen() ) >> nRightShiftBits ) << nLeftShiftBits1 ) |
1735 								 ( ( (sal_uInt32) rCol.GetBlue() ) >> nRightShiftBits ) ].mnCount++;
1736 				}
1737 			}
1738 		}
1739 		else
1740 		{
1741 			for( nY = 0L; nY < nHeight; nY++ )
1742 			{
1743 				for( nX = 0L; nX < nWidth; nX++ )
1744 				{
1745 					const BitmapColor aCol( pRAcc->GetPixel( nY, nX ) );
1746 					pCountTable[ ( ( ( (sal_uInt32) aCol.GetRed() ) >> nRightShiftBits ) << nLeftShiftBits2 ) |
1747 								 ( ( ( (sal_uInt32) aCol.GetGreen() ) >> nRightShiftBits ) << nLeftShiftBits1 ) |
1748 								 ( ( (sal_uInt32) aCol.GetBlue() ) >> nRightShiftBits ) ].mnCount++;
1749 				}
1750 			}
1751 		}
1752 
1753 		BitmapPalette aNewPal( nColCount );
1754 
1755 		qsort( pCountTable, nTotalColors, sizeof( PopularColorCount ), ImplPopularCmpFnc );
1756 
1757 		for( sal_uInt16 n = 0; n < nColCount; n++ )
1758 		{
1759 			const PopularColorCount& rPop = pCountTable[ n ];
1760 			aNewPal[ n ] = BitmapColor( (sal_uInt8) ( ( rPop.mnIndex >> nLeftShiftBits2 ) << nRightShiftBits ),
1761 										(sal_uInt8) ( ( ( rPop.mnIndex >> nLeftShiftBits1 ) & ( nColorsPerComponent - 1 ) ) << nRightShiftBits ),
1762 										(sal_uInt8) ( ( rPop.mnIndex & ( nColorsPerComponent - 1 ) ) << nRightShiftBits ) );
1763 		}
1764 
1765 		Bitmap				aNewBmp( GetSizePixel(), nBitCount, &aNewPal );
1766 		BitmapWriteAccess*	pWAcc = aNewBmp.AcquireWriteAccess();
1767 
1768 		if( pWAcc )
1769 		{
1770 			BitmapColor	aDstCol( (sal_uInt8) 0 );
1771 			sal_uInt8*		pIndexMap = new sal_uInt8[ nTotalColors ];
1772 
1773 			for( nR = 0, nIndex = 0; nR < 256; nR += nColorOffset )
1774 				for( nG = 0; nG < 256; nG += nColorOffset )
1775 					for( nB = 0; nB < 256; nB += nColorOffset )
1776 						pIndexMap[ nIndex++ ] = (sal_uInt8) aNewPal.GetBestIndex( BitmapColor( (sal_uInt8) nR, (sal_uInt8) nG, (sal_uInt8) nB ) );
1777 
1778 			if( pRAcc->HasPalette() )
1779 			{
1780 				for( nY = 0L; nY < nHeight; nY++ )
1781 				{
1782 					for( nX = 0L; nX < nWidth; nX++ )
1783 					{
1784 						const BitmapColor& rCol = pRAcc->GetPaletteColor( pRAcc->GetPixel( nY, nX ) );
1785 						aDstCol.SetIndex( pIndexMap[ ( ( ( (sal_uInt32) rCol.GetRed() ) >> nRightShiftBits ) << nLeftShiftBits2 ) |
1786 													 ( ( ( (sal_uInt32) rCol.GetGreen() ) >> nRightShiftBits ) << nLeftShiftBits1 ) |
1787 													 ( ( (sal_uInt32) rCol.GetBlue() ) >> nRightShiftBits ) ] );
1788 						pWAcc->SetPixel( nY, nX, aDstCol );
1789 					}
1790 				}
1791 			}
1792 			else
1793 			{
1794 				for( nY = 0L; nY < nHeight; nY++ )
1795 				{
1796 					for( nX = 0L; nX < nWidth; nX++ )
1797 					{
1798 						const BitmapColor aCol( pRAcc->GetPixel( nY, nX ) );
1799 						aDstCol.SetIndex( pIndexMap[ ( ( ( (sal_uInt32) aCol.GetRed() ) >> nRightShiftBits ) << nLeftShiftBits2 ) |
1800 													 ( ( ( (sal_uInt32) aCol.GetGreen() ) >> nRightShiftBits ) << nLeftShiftBits1 ) |
1801 													 ( ( (sal_uInt32) aCol.GetBlue() ) >> nRightShiftBits ) ] );
1802 						pWAcc->SetPixel( nY, nX, aDstCol );
1803 					}
1804 				}
1805 			}
1806 
1807 			delete[] pIndexMap;
1808 			aNewBmp.ReleaseAccess( pWAcc );
1809 			bRet = sal_True;
1810 		}
1811 
1812 		delete[] pCountTable;
1813 		ReleaseAccess( pRAcc );
1814 
1815 		if( bRet )
1816 		{
1817 			const MapMode	aMap( maPrefMapMode );
1818 			const Size		aSize( maPrefSize );
1819 
1820 			*this = aNewBmp;
1821 			maPrefMapMode = aMap;
1822 			maPrefSize = aSize;
1823 		}
1824 	}
1825 
1826 	return bRet;
1827 }
1828 
1829 // ------------------------------------------------------------------------
1830 
1831 sal_Bool Bitmap::ImplReduceMedian( sal_uInt16 nColCount )
1832 {
1833 	BitmapReadAccess*	pRAcc = AcquireReadAccess();
1834 	sal_uInt16				nBitCount;
1835 	sal_Bool				bRet = sal_False;
1836 
1837 	if( nColCount < 17 )
1838 		nBitCount = 4;
1839 	else if( nColCount < 257 )
1840 		nBitCount = 8;
1841 	else
1842 	{
1843 		DBG_ERROR( "Bitmap::ImplReduceMedian(): invalid color count!" );
1844 		nBitCount = 8;
1845 		nColCount = 256;
1846 	}
1847 
1848 	if( pRAcc )
1849 	{
1850 		Bitmap				aNewBmp( GetSizePixel(), nBitCount );
1851 		BitmapWriteAccess*	pWAcc = aNewBmp.AcquireWriteAccess();
1852 
1853 		if( pWAcc )
1854 		{
1855 			const sal_uLong	nSize = 32768UL * sizeof( sal_uLong );
1856 			sal_uLong*		pColBuf = (sal_uLong*) rtl_allocateMemory( nSize );
1857 			const long	nWidth = pWAcc->Width();
1858 			const long	nHeight = pWAcc->Height();
1859 			long		nIndex = 0L;
1860 
1861 			memset( (HPBYTE) pColBuf, 0, nSize );
1862 
1863 			// create Buffer
1864 			if( pRAcc->HasPalette() )
1865 			{
1866 				for( long nY = 0L; nY < nHeight; nY++ )
1867 				{
1868 					for( long nX = 0L; nX < nWidth; nX++ )
1869 					{
1870 						const BitmapColor& rCol = pRAcc->GetPaletteColor( pRAcc->GetPixel( nY, nX ) );
1871 						pColBuf[ RGB15( rCol.GetRed() >> 3, rCol.GetGreen() >> 3, rCol.GetBlue() >> 3 ) ]++;
1872 					}
1873 				}
1874 			}
1875 			else
1876 			{
1877 				for( long nY = 0L; nY < nHeight; nY++ )
1878 				{
1879 					for( long nX = 0L; nX < nWidth; nX++ )
1880 					{
1881 						const BitmapColor aCol( pRAcc->GetPixel( nY, nX ) );
1882 						pColBuf[ RGB15( aCol.GetRed() >> 3, aCol.GetGreen() >> 3, aCol.GetBlue() >> 3 ) ]++;
1883 					}
1884 				}
1885 			}
1886 
1887 			// create palette via median cut
1888 			BitmapPalette aPal( pWAcc->GetPaletteEntryCount() );
1889 			ImplMedianCut( pColBuf, aPal, 0, 31, 0, 31, 0, 31,
1890 						   nColCount, nWidth * nHeight, nIndex );
1891 
1892 			// do mapping of colors to palette
1893 			InverseColorMap aMap( aPal );
1894 			pWAcc->SetPalette( aPal );
1895 			for( long nY = 0L; nY < nHeight; nY++ )
1896 				for( long nX = 0L; nX < nWidth; nX++ )
1897 					pWAcc->SetPixel( nY, nX, (sal_uInt8) aMap.GetBestPaletteIndex( pRAcc->GetColor( nY, nX ) ) );
1898 
1899 			rtl_freeMemory( pColBuf );
1900 			aNewBmp.ReleaseAccess( pWAcc );
1901 			bRet = sal_True;
1902 		}
1903 
1904 		ReleaseAccess( pRAcc );
1905 
1906 		if( bRet )
1907 		{
1908 			const MapMode	aMap( maPrefMapMode );
1909 			const Size		aSize( maPrefSize );
1910 
1911 			*this = aNewBmp;
1912 			maPrefMapMode = aMap;
1913 			maPrefSize = aSize;
1914 		}
1915 	}
1916 
1917 	return bRet;
1918 }
1919 
1920 // ------------------------------------------------------------------------
1921 
1922 void Bitmap::ImplMedianCut( sal_uLong* pColBuf, BitmapPalette& rPal,
1923 							long nR1, long nR2, long nG1, long nG2, long nB1, long nB2,
1924 							long nColors, long nPixels, long& rIndex )
1925 {
1926 	if( !nPixels )
1927 		return;
1928 
1929 	BitmapColor	aCol;
1930 	const long	nRLen = nR2 - nR1;
1931 	const long	nGLen = nG2 - nG1;
1932 	const long	nBLen = nB2 - nB1;
1933 	long 		nR, nG, nB;
1934 	sal_uLong*		pBuf = pColBuf;
1935 
1936 	if( !nRLen && !nGLen && !nBLen )
1937 	{
1938 		if( pBuf[ RGB15( nR1, nG1, nB1 ) ] )
1939 		{
1940 			aCol.SetRed( (sal_uInt8) ( nR1 << 3 ) );
1941 			aCol.SetGreen( (sal_uInt8) ( nG1 << 3 ) );
1942 			aCol.SetBlue( (sal_uInt8) ( nB1 << 3 ) );
1943 			rPal[ (sal_uInt16) rIndex++ ] = aCol;
1944 		}
1945 	}
1946 	else
1947 	{
1948 		if( 1 == nColors || 1 == nPixels )
1949 		{
1950 			long nPixSum = 0, nRSum = 0, nGSum = 0, nBSum = 0;
1951 
1952 			for( nR = nR1; nR <= nR2; nR++ )
1953 			{
1954 				for( nG = nG1; nG <= nG2; nG++ )
1955 				{
1956 					for( nB = nB1; nB <= nB2; nB++ )
1957 					{
1958 						nPixSum = pBuf[ RGB15( nR, nG, nB ) ];
1959 
1960 						if( nPixSum )
1961 						{
1962 							nRSum += nR * nPixSum;
1963 							nGSum += nG * nPixSum;
1964 							nBSum += nB * nPixSum;
1965 						}
1966 					}
1967 				}
1968 			}
1969 
1970 			aCol.SetRed( (sal_uInt8) ( ( nRSum / nPixels ) << 3 ) );
1971 			aCol.SetGreen( (sal_uInt8) ( ( nGSum / nPixels ) << 3 ) );
1972 			aCol.SetBlue( (sal_uInt8) ( ( nBSum / nPixels ) << 3 ) );
1973 			rPal[ (sal_uInt16) rIndex++ ] = aCol;
1974 		}
1975 		else
1976 		{
1977 			const long	nTest = ( nPixels >> 1 );
1978 			long		nPixOld = 0;
1979 			long		nPixNew = 0;
1980 
1981 			if( nBLen > nGLen && nBLen > nRLen )
1982 			{
1983 				nB = nB1 - 1;
1984 
1985 				while( nPixNew < nTest )
1986 				{
1987 					nB++, nPixOld = nPixNew;
1988 					for( nR = nR1; nR <= nR2; nR++ )
1989 						for( nG = nG1; nG <= nG2; nG++ )
1990 							nPixNew += pBuf[ RGB15( nR, nG, nB ) ];
1991 				}
1992 
1993 				if( nB < nB2 )
1994 				{
1995 					ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG2, nB1, nB, nColors >> 1, nPixNew, rIndex );
1996 					ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG2, nB + 1, nB2, nColors >> 1, nPixels - nPixNew, rIndex );
1997 				}
1998 				else
1999 				{
2000 					ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG2, nB1, nB - 1, nColors >> 1, nPixOld, rIndex );
2001 					ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG2, nB, nB2, nColors >> 1, nPixels - nPixOld, rIndex );
2002 				}
2003 			}
2004 			else if( nGLen > nRLen )
2005 			{
2006 				nG = nG1 - 1;
2007 
2008 				while( nPixNew < nTest )
2009 				{
2010 					nG++, nPixOld = nPixNew;
2011 					for( nR = nR1; nR <= nR2; nR++ )
2012 						for( nB = nB1; nB <= nB2; nB++ )
2013 							nPixNew += pBuf[ RGB15( nR, nG, nB ) ];
2014 				}
2015 
2016 				if( nG < nG2 )
2017 				{
2018 					ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG, nB1, nB2, nColors >> 1, nPixNew, rIndex );
2019 					ImplMedianCut( pBuf, rPal, nR1, nR2, nG + 1, nG2, nB1, nB2, nColors >> 1, nPixels - nPixNew, rIndex );
2020 				}
2021 				else
2022 				{
2023 					ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG - 1, nB1, nB2, nColors >> 1, nPixOld, rIndex );
2024 					ImplMedianCut( pBuf, rPal, nR1, nR2, nG, nG2, nB1, nB2, nColors >> 1, nPixels - nPixOld, rIndex );
2025 				}
2026 			}
2027 			else
2028 			{
2029 				nR = nR1 - 1;
2030 
2031 				while( nPixNew < nTest )
2032 				{
2033 					nR++, nPixOld = nPixNew;
2034 					for( nG = nG1; nG <= nG2; nG++ )
2035 						for( nB = nB1; nB <= nB2; nB++ )
2036 							nPixNew += pBuf[ RGB15( nR, nG, nB ) ];
2037 				}
2038 
2039 				if( nR < nR2 )
2040 				{
2041 					ImplMedianCut( pBuf, rPal, nR1, nR, nG1, nG2, nB1, nB2, nColors >> 1, nPixNew, rIndex );
2042 					ImplMedianCut( pBuf, rPal, nR1 + 1, nR2, nG1, nG2, nB1, nB2, nColors >> 1, nPixels - nPixNew, rIndex );
2043 				}
2044 				else
2045 				{
2046 					ImplMedianCut( pBuf, rPal, nR1, nR - 1, nG1, nG2, nB1, nB2, nColors >> 1, nPixOld, rIndex );
2047 					ImplMedianCut( pBuf, rPal, nR, nR2, nG1, nG2, nB1, nB2, nColors >> 1, nPixels - nPixOld, rIndex );
2048 				}
2049 			}
2050 		}
2051 	}
2052 }
2053 
2054 // ------------------------------------------------------------------------
2055 
2056 sal_Bool Bitmap::Vectorize( PolyPolygon& rPolyPoly, sal_uLong nFlags, const Link* pProgress )
2057 {
2058 	return ImplVectorizer().ImplVectorize( *this, rPolyPoly, nFlags, pProgress );
2059 }
2060 
2061 // ------------------------------------------------------------------------
2062 
2063 sal_Bool Bitmap::Vectorize( GDIMetaFile& rMtf, sal_uInt8 cReduce, sal_uLong nFlags, const Link* pProgress )
2064 {
2065 	return ImplVectorizer().ImplVectorize( *this, rMtf, cReduce, nFlags, pProgress );
2066 }
2067 
2068 // ------------------------------------------------------------------------
2069 
2070 sal_Bool Bitmap::Adjust( short nLuminancePercent, short nContrastPercent,
2071 					 short nChannelRPercent, short nChannelGPercent, short nChannelBPercent,
2072 					 double fGamma, sal_Bool bInvert )
2073 {
2074 	sal_Bool bRet = sal_False;
2075 
2076 	// nothing to do => return quickly
2077 	if( !nLuminancePercent && !nContrastPercent &&
2078 		!nChannelRPercent && !nChannelGPercent && !nChannelBPercent &&
2079 		( fGamma == 1.0 ) && !bInvert )
2080 	{
2081 		bRet = sal_True;
2082 	}
2083 	else
2084 	{
2085 		BitmapWriteAccess* pAcc = AcquireWriteAccess();
2086 
2087 		if( pAcc )
2088 		{
2089 			BitmapColor		aCol;
2090 			const long		nW = pAcc->Width();
2091 			const long		nH = pAcc->Height();
2092 			sal_uInt8*			cMapR = new sal_uInt8[ 256 ];
2093 			sal_uInt8*			cMapG = new sal_uInt8[ 256 ];
2094 			sal_uInt8*			cMapB = new sal_uInt8[ 256 ];
2095 			long			nX, nY;
2096 			double			fM, fROff, fGOff, fBOff, fOff;
2097 
2098 			// calculate slope
2099 			if( nContrastPercent >= 0 )
2100 				fM = 128.0 / ( 128.0 - 1.27 * MinMax( nContrastPercent, 0L, 100L ) );
2101 			else
2102 				fM = ( 128.0 + 1.27 * MinMax( nContrastPercent, -100L, 0L ) ) / 128.0;
2103 
2104 			// total offset = luminance offset + contrast offset
2105 			fOff = MinMax( nLuminancePercent, -100L, 100L ) * 2.55 + 128.0 - fM * 128.0;
2106 
2107 			// channel offset = channel offset  + total offset
2108 			fROff = nChannelRPercent * 2.55 + fOff;
2109 			fGOff = nChannelGPercent * 2.55 + fOff;
2110 			fBOff = nChannelBPercent * 2.55 + fOff;
2111 
2112 			// calculate gamma value
2113 			fGamma = ( fGamma <= 0.0 || fGamma > 10.0 ) ? 1.0 : ( 1.0 / fGamma );
2114 			const sal_Bool bGamma = ( fGamma != 1.0 );
2115 
2116 			// create mapping table
2117 			for( nX = 0L; nX < 256L; nX++ )
2118 			{
2119 				cMapR[ nX ] = (sal_uInt8) MinMax( FRound( nX * fM + fROff ), 0L, 255L );
2120 				cMapG[ nX ] = (sal_uInt8) MinMax( FRound( nX * fM + fGOff ), 0L, 255L );
2121 				cMapB[ nX ] = (sal_uInt8) MinMax( FRound( nX * fM + fBOff ), 0L, 255L );
2122 
2123 				if( bGamma )
2124 				{
2125 					cMapR[ nX ] = GAMMA( cMapR[ nX ], fGamma );
2126 					cMapG[ nX ] = GAMMA( cMapG[ nX ], fGamma );
2127 					cMapB[ nX ] = GAMMA( cMapB[ nX ], fGamma );
2128 				}
2129 
2130 				if( bInvert )
2131 				{
2132 					cMapR[ nX ] = ~cMapR[ nX ];
2133 					cMapG[ nX ] = ~cMapG[ nX ];
2134 					cMapB[ nX ] = ~cMapB[ nX ];
2135 				}
2136 			}
2137 
2138 			// do modifying
2139 			if( pAcc->HasPalette() )
2140 			{
2141 				BitmapColor aNewCol;
2142 
2143 				for( sal_uInt16 i = 0, nCount = pAcc->GetPaletteEntryCount(); i < nCount; i++ )
2144 				{
2145 					const BitmapColor& rCol = pAcc->GetPaletteColor( i );
2146 					aNewCol.SetRed( cMapR[ rCol.GetRed() ] );
2147 					aNewCol.SetGreen( cMapG[ rCol.GetGreen() ] );
2148 					aNewCol.SetBlue( cMapB[ rCol.GetBlue() ] );
2149 					pAcc->SetPaletteColor( i, aNewCol );
2150 				}
2151 			}
2152 			else if( pAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_BGR )
2153 			{
2154 				for( nY = 0L; nY < nH; nY++ )
2155 				{
2156 					Scanline pScan = pAcc->GetScanline( nY );
2157 
2158 					for( nX = 0L; nX < nW; nX++ )
2159 					{
2160 						*pScan = cMapB[ *pScan ]; pScan++;
2161 						*pScan = cMapG[ *pScan ]; pScan++;
2162 						*pScan = cMapR[ *pScan ]; pScan++;
2163 					}
2164 				}
2165 			}
2166 			else if( pAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_RGB )
2167 			{
2168 				for( nY = 0L; nY < nH; nY++ )
2169 				{
2170 					Scanline pScan = pAcc->GetScanline( nY );
2171 
2172 					for( nX = 0L; nX < nW; nX++ )
2173 					{
2174 						*pScan = cMapR[ *pScan ]; pScan++;
2175 						*pScan = cMapG[ *pScan ]; pScan++;
2176 						*pScan = cMapB[ *pScan ]; pScan++;
2177 					}
2178 				}
2179 			}
2180 			else
2181 			{
2182 				for( nY = 0L; nY < nH; nY++ )
2183 				{
2184 					for( nX = 0L; nX < nW; nX++ )
2185 					{
2186 						aCol = pAcc->GetPixel( nY, nX );
2187 						aCol.SetRed( cMapR[ aCol.GetRed() ] );
2188 						aCol.SetGreen( cMapG[ aCol.GetGreen() ] );
2189 						aCol.SetBlue( cMapB[ aCol.GetBlue() ] );
2190 						pAcc->SetPixel( nY, nX, aCol );
2191 					}
2192 				}
2193 			}
2194 
2195 			delete[] cMapR;
2196 			delete[] cMapG;
2197 			delete[] cMapB;
2198 			ReleaseAccess( pAcc );
2199 			bRet = sal_True;
2200 		}
2201 	}
2202 
2203 	return bRet;
2204 }
2205