merge the formfield patch from ooo-build
[ooovba.git] / vcl / source / gdi / bitmap3.cxx
blobc480c038c3631493490ad8decd88b300218c0683
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: bitmap3.cxx,v $
10 * $Revision: 1.12 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_vcl.hxx"
34 #include <stdlib.h>
35 #include <vcl/bmpacc.hxx>
36 #include <vcl/impoct.hxx>
37 #include <vcl/octree.hxx>
38 #include <impvect.hxx>
39 #include <vcl/bitmapex.hxx>
40 #include <vcl/bitmap.hxx>
42 // -----------
43 // - Defines -
44 // -----------
46 #define RGB15( _def_cR, _def_cG, _def_cB ) (((ULONG)(_def_cR)<<10UL)|((ULONG)(_def_cG)<<5UL)|(ULONG)(_def_cB))
47 #define GAMMA( _def_cVal, _def_InvGamma ) ((BYTE)MinMax(FRound(pow( _def_cVal/255.0,_def_InvGamma)*255.0),0L,255L))
49 #define CALC_ERRORS \
50 nTemp = p1T[nX++] >> 12; \
51 nBErr = MinMax( nTemp, 0, 255 ); \
52 nBErr = nBErr - FloydIndexMap[ nBC = FloydMap[nBErr] ]; \
53 nTemp = p1T[nX++] >> 12; \
54 nGErr = MinMax( nTemp, 0, 255 ); \
55 nGErr = nGErr - FloydIndexMap[ nGC = FloydMap[nGErr] ]; \
56 nTemp = p1T[nX] >> 12; \
57 nRErr = MinMax( nTemp, 0, 255 ); \
58 nRErr = nRErr - FloydIndexMap[ nRC = FloydMap[nRErr] ];
60 #define CALC_TABLES3 \
61 p2T[nX++] += FloydError3[nBErr]; \
62 p2T[nX++] += FloydError3[nGErr]; \
63 p2T[nX++] += FloydError3[nRErr];
65 #define CALC_TABLES5 \
66 p2T[nX++] += FloydError5[nBErr]; \
67 p2T[nX++] += FloydError5[nGErr]; \
68 p2T[nX++] += FloydError5[nRErr];
70 #define CALC_TABLES7 \
71 p1T[++nX] += FloydError7[nBErr]; \
72 p2T[nX++] += FloydError1[nBErr]; \
73 p1T[nX] += FloydError7[nGErr]; \
74 p2T[nX++] += FloydError1[nGErr]; \
75 p1T[nX] += FloydError7[nRErr]; \
76 p2T[nX] += FloydError1[nRErr];
78 // -----------
79 // - Statics -
80 // -----------
82 ULONG nVCLRLut[ 6 ] = { 16, 17, 18, 19, 20, 21 };
83 ULONG nVCLGLut[ 6 ] = { 0, 6, 12, 18, 24, 30 };
84 ULONG nVCLBLut[ 6 ] = { 0, 36, 72, 108, 144, 180 };
86 // ------------------------------------------------------------------------
88 ULONG nVCLDitherLut[ 256 ] =
90 0, 49152, 12288, 61440, 3072, 52224, 15360, 64512, 768, 49920, 13056,
91 62208, 3840, 52992, 16128, 65280, 32768, 16384, 45056, 28672, 35840, 19456,
92 48128, 31744, 33536, 17152, 45824, 29440, 36608, 20224, 48896, 32512, 8192,
93 57344, 4096, 53248, 11264, 60416, 7168, 56320, 8960, 58112, 4864, 54016,
94 12032, 61184, 7936, 57088, 40960, 24576, 36864, 20480, 44032, 27648, 39936,
95 23552, 41728, 25344, 37632, 21248, 44800, 28416, 40704, 24320, 2048, 51200,
96 14336, 63488, 1024, 50176, 13312, 62464, 2816, 51968, 15104, 64256, 1792,
97 50944, 14080, 63232, 34816, 18432, 47104, 30720, 33792, 17408, 46080, 29696,
98 35584, 19200, 47872, 31488, 34560, 18176, 46848, 30464, 10240, 59392, 6144,
99 55296, 9216, 58368, 5120, 54272, 11008, 60160, 6912, 56064, 9984, 59136,
100 5888, 55040, 43008, 26624, 38912, 22528, 41984, 25600, 37888, 21504, 43776,
101 27392, 39680, 23296, 42752, 26368, 38656, 22272, 512, 49664, 12800, 61952,
102 3584, 52736, 15872, 65024, 256, 49408, 12544, 61696, 3328, 52480, 15616,
103 64768, 33280, 16896, 45568, 29184, 36352, 19968, 48640, 32256, 33024, 16640,
104 45312, 28928, 36096, 19712, 48384, 32000, 8704, 57856, 4608, 53760, 11776,
105 60928, 7680, 56832, 8448, 57600, 4352, 53504, 11520, 60672, 7424, 56576,
106 41472, 25088, 37376, 20992, 44544, 28160, 40448, 24064, 41216, 24832, 37120,
107 20736, 44288, 27904, 40192, 23808, 2560, 51712, 14848, 64000, 1536, 50688,
108 13824, 62976, 2304, 51456, 14592, 63744, 1280, 50432, 13568, 62720, 35328,
109 18944, 47616, 31232, 34304, 17920, 46592, 30208, 35072, 18688, 47360, 30976,
110 34048, 17664, 46336, 29952, 10752, 59904, 6656, 55808, 9728, 58880, 5632,
111 54784, 10496, 59648, 6400, 55552, 9472, 58624, 5376, 54528, 43520, 27136,
112 39424, 23040, 42496, 26112, 38400, 22016, 43264, 26880, 39168, 22784, 42240,
113 25856, 38144, 21760
116 // ------------------------------------------------------------------------
118 ULONG nVCLLut[ 256 ] =
120 0, 1286, 2572, 3858, 5144, 6430, 7716, 9002,
121 10288, 11574, 12860, 14146, 15432, 16718, 18004, 19290,
122 20576, 21862, 23148, 24434, 25720, 27006, 28292, 29578,
123 30864, 32150, 33436, 34722, 36008, 37294, 38580, 39866,
124 41152, 42438, 43724, 45010, 46296, 47582, 48868, 50154,
125 51440, 52726, 54012, 55298, 56584, 57870, 59156, 60442,
126 61728, 63014, 64300, 65586, 66872, 68158, 69444, 70730,
127 72016, 73302, 74588, 75874, 77160, 78446, 79732, 81018,
128 82304, 83590, 84876, 86162, 87448, 88734, 90020, 91306,
129 92592, 93878, 95164, 96450, 97736, 99022,100308,101594,
130 102880,104166,105452,106738,108024,109310,110596,111882,
131 113168,114454,115740,117026,118312,119598,120884,122170,
132 123456,124742,126028,127314,128600,129886,131172,132458,
133 133744,135030,136316,137602,138888,140174,141460,142746,
134 144032,145318,146604,147890,149176,150462,151748,153034,
135 154320,155606,156892,158178,159464,160750,162036,163322,
136 164608,165894,167180,168466,169752,171038,172324,173610,
137 174896,176182,177468,178754,180040,181326,182612,183898,
138 185184,186470,187756,189042,190328,191614,192900,194186,
139 195472,196758,198044,199330,200616,201902,203188,204474,
140 205760,207046,208332,209618,210904,212190,213476,214762,
141 216048,217334,218620,219906,221192,222478,223764,225050,
142 226336,227622,228908,230194,231480,232766,234052,235338,
143 236624,237910,239196,240482,241768,243054,244340,245626,
144 246912,248198,249484,250770,252056,253342,254628,255914,
145 257200,258486,259772,261058,262344,263630,264916,266202,
146 267488,268774,270060,271346,272632,273918,275204,276490,
147 277776,279062,280348,281634,282920,284206,285492,286778,
148 288064,289350,290636,291922,293208,294494,295780,297066,
149 298352,299638,300924,302210,303496,304782,306068,307354,
150 308640,309926,311212,312498,313784,315070,316356,317642,
151 318928,320214,321500,322786,324072,325358,326644,327930
154 // ------------------------------------------------------------------------
156 long FloydMap[256] =
158 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
159 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1,
160 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
161 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
162 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2,
163 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
164 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
165 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
166 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
167 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
168 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
169 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
170 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
171 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
172 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
173 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
176 // ------------------------------------------------------------------------
178 long FloydError1[61] =
180 -7680, -7424, -7168, -6912, -6656, -6400, -6144,
181 -5888, -5632, -5376, -5120, -4864, -4608, -4352,
182 -4096, -3840, -3584, -3328, -3072, -2816, -2560,
183 -2304, -2048, -1792, -1536, -1280, -1024, -768,
184 -512, -256, 0, 256, 512, 768, 1024, 1280, 1536,
185 1792, 2048, 2304, 2560, 2816, 3072, 3328, 3584,
186 3840, 4096, 4352, 4608, 4864, 5120, 5376, 5632,
187 5888, 6144, 6400, 6656, 6912, 7168, 7424, 7680
190 // ------------------------------------------------------------------------
192 long FloydError3[61] =
194 -23040, -22272, -21504, -20736, -19968, -19200,
195 -18432, -17664, -16896, -16128, -15360, -14592,
196 -13824, -13056, -12288, -11520, -10752, -9984,
197 -9216, -8448, -7680, -6912, -6144, -5376, -4608,
198 -3840, -3072, -2304, -1536, -768, 0, 768, 1536,
199 2304, 3072, 3840, 4608, 5376, 6144, 6912, 7680,
200 8448, 9216, 9984, 10752, 11520, 12288, 13056,
201 13824, 14592, 15360, 16128, 16896, 17664, 18432,
202 19200, 19968, 20736, 21504, 22272, 23040
205 // ------------------------------------------------------------------------
207 long FloydError5[61] =
209 -38400, -37120, -35840, -34560, -33280, -32000,
210 -30720, -29440, -28160, -26880, -25600, -24320,
211 -23040, -21760, -20480, -19200, -17920, -16640,
212 -15360, -14080, -12800, -11520, -10240, -8960,
213 -7680, -6400, -5120, -3840, -2560, -1280, 0,
214 1280, 2560, 3840, 5120, 6400, 7680, 8960, 10240,
215 11520, 12800, 14080, 15360, 16640, 17920, 19200,
216 20480, 21760, 23040, 24320, 25600, 26880, 28160,
217 29440, 30720, 32000, 33280, 34560, 35840, 37120,
218 38400
221 // ------------------------------------------------------------------------
223 long FloydError7[61] =
225 -53760, -51968, -50176, -48384, -46592, -44800,
226 -43008, -41216, -39424, -37632, -35840, -34048,
227 -32256, -30464, -28672, -26880, -25088, -23296,
228 -21504, -19712, -17920, -16128, -14336, -12544,
229 -10752, -8960, -7168, -5376, -3584, -1792, 0,
230 1792, 3584, 5376, 7168, 8960, 10752, 12544, 14336,
231 16128, 17920, 19712, 21504, 23296, 25088, 26880,
232 28672, 30464, 32256, 34048, 35840, 37632, 39424,
233 41216, 43008, 44800, 46592, 48384, 50176, 51968,
234 53760
237 // ------------------------------------------------------------------------
239 long FloydIndexMap[6] =
241 -30, 21, 72, 123, 174, 225
244 // --------------------------
245 // - ImplCreateDitherMatrix -
246 // --------------------------
248 void ImplCreateDitherMatrix( BYTE (*pDitherMatrix)[16][16] )
250 double fVal = 3.125;
251 const double fVal16 = fVal / 16.;
252 long i, j, k, l;
253 USHORT pMtx[ 16 ][ 16 ];
254 USHORT nMax = 0;
255 static BYTE pMagic[4][4] = { { 0, 14, 3, 13, },
256 {11, 5, 8, 6, },
257 {12, 2, 15, 1, },
258 {7, 9, 4, 10 } };
260 // MagicSquare aufbauen
261 for ( i = 0; i < 4; i++ )
262 for ( j = 0; j < 4; j++ )
263 for ( k = 0; k < 4; k++ )
264 for ( l = 0; l < 4; l++ )
265 nMax = Max ( pMtx[ (k<<2) + i][(l<<2 ) + j] =
266 (USHORT) ( 0.5 + pMagic[i][j]*fVal + pMagic[k][l]*fVal16 ), nMax );
268 // auf Intervall [0;254] skalieren
269 for ( i = 0, fVal = 254. / nMax; i < 16; i++ )
270 for( j = 0; j < 16; j++ )
271 (*pDitherMatrix)[i][j] = (BYTE) ( fVal * pMtx[i][j] );
274 // ----------
275 // - Bitmap -
276 // ----------
278 BOOL Bitmap::Convert( BmpConversion eConversion )
280 const USHORT nBitCount = GetBitCount();
281 BOOL bRet = FALSE;
283 switch( eConversion )
285 case( BMP_CONVERSION_1BIT_THRESHOLD ):
286 bRet = ImplMakeMono( 128 );
287 break;
289 case( BMP_CONVERSION_1BIT_MATRIX ):
290 bRet = ImplMakeMonoDither();
291 break;
293 case( BMP_CONVERSION_4BIT_GREYS ):
294 bRet = ImplMakeGreyscales( 16 );
295 break;
297 case( BMP_CONVERSION_4BIT_COLORS ):
299 if( nBitCount < 4 )
300 bRet = ImplConvertUp( 4, NULL );
301 else if( nBitCount > 4 )
302 bRet = ImplConvertDown( 4, NULL );
303 else
304 bRet = TRUE;
306 break;
308 case( BMP_CONVERSION_4BIT_TRANS ):
310 Color aTrans( BMP_COL_TRANS );
312 if( nBitCount < 4 )
313 bRet = ImplConvertUp( 4, &aTrans );
314 else
315 bRet = ImplConvertDown( 4, &aTrans );
317 break;
319 case( BMP_CONVERSION_8BIT_GREYS ):
320 bRet = ImplMakeGreyscales( 256 );
321 break;
323 case( BMP_CONVERSION_8BIT_COLORS ):
325 if( nBitCount < 8 )
326 bRet = ImplConvertUp( 8 );
327 else if( nBitCount > 8 )
328 bRet = ImplConvertDown( 8 );
329 else
330 bRet = TRUE;
332 break;
334 case( BMP_CONVERSION_8BIT_TRANS ):
336 Color aTrans( BMP_COL_TRANS );
338 if( nBitCount < 8 )
339 bRet = ImplConvertUp( 8, &aTrans );
340 else
341 bRet = ImplConvertDown( 8, &aTrans );
343 break;
345 case( BMP_CONVERSION_24BIT ):
347 if( nBitCount < 24 )
348 bRet = ImplConvertUp( 24, FALSE );
349 else
350 bRet = TRUE;
352 break;
354 case( BMP_CONVERSION_GHOSTED ):
355 bRet = ImplConvertGhosted();
356 break;
358 default:
359 DBG_ERROR( "Bitmap::Convert(): Unsupported conversion" );
360 break;
363 return bRet;
366 // ------------------------------------------------------------------------
368 BOOL Bitmap::ImplMakeMono( BYTE cThreshold )
370 BitmapReadAccess* pReadAcc = AcquireReadAccess();
371 BOOL bRet = FALSE;
373 if( pReadAcc )
375 Bitmap aNewBmp( GetSizePixel(), 1 );
376 BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess();
378 if( pWriteAcc )
380 const BitmapColor aBlack( pWriteAcc->GetBestMatchingColor( Color( COL_BLACK ) ) );
381 const BitmapColor aWhite( pWriteAcc->GetBestMatchingColor( Color( COL_WHITE ) ) );
382 const long nWidth = pWriteAcc->Width();
383 const long nHeight = pWriteAcc->Height();
385 if( pReadAcc->HasPalette() )
387 for( long nY = 0L; nY < nHeight; nY++ )
389 for( long nX = 0L; nX < nWidth; nX++ )
391 if( pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nY, nX ) ).GetLuminance() >=
392 cThreshold )
394 pWriteAcc->SetPixel( nY, nX, aWhite );
396 else
397 pWriteAcc->SetPixel( nY, nX, aBlack );
401 else
403 for( long nY = 0L; nY < nHeight; nY++ )
405 for( long nX = 0L; nX < nWidth; nX++ )
407 if( pReadAcc->GetPixel( nY, nX ).GetLuminance() >=
408 cThreshold )
410 pWriteAcc->SetPixel( nY, nX, aWhite );
412 else
413 pWriteAcc->SetPixel( nY, nX, aBlack );
418 aNewBmp.ReleaseAccess( pWriteAcc );
419 bRet = TRUE;
422 ReleaseAccess( pReadAcc );
424 if( bRet )
426 const MapMode aMap( maPrefMapMode );
427 const Size aSize( maPrefSize );
429 *this = aNewBmp;
431 maPrefMapMode = aMap;
432 maPrefSize = aSize;
436 return bRet;
439 // ------------------------------------------------------------------------
441 BOOL Bitmap::ImplMakeMonoDither()
443 BitmapReadAccess* pReadAcc = AcquireReadAccess();
444 BOOL bRet = FALSE;
446 if( pReadAcc )
448 Bitmap aNewBmp( GetSizePixel(), 1 );
449 BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess();
451 if( pWriteAcc )
453 const BitmapColor aBlack( pWriteAcc->GetBestMatchingColor( Color( COL_BLACK ) ) );
454 const BitmapColor aWhite( pWriteAcc->GetBestMatchingColor( Color( COL_WHITE ) ) );
455 const long nWidth = pWriteAcc->Width();
456 const long nHeight = pWriteAcc->Height();
457 BYTE pDitherMatrix[ 16 ][ 16 ];
459 ImplCreateDitherMatrix( &pDitherMatrix );
461 if( pReadAcc->HasPalette() )
463 for( long nY = 0L; nY < nHeight; nY++ )
465 for( long nX = 0L, nModY = nY % 16; nX < nWidth; nX++ )
467 if( pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nY, nX ) ).GetLuminance() >
468 pDitherMatrix[ nModY ][ nX % 16 ] )
470 pWriteAcc->SetPixel( nY, nX, aWhite );
472 else
473 pWriteAcc->SetPixel( nY, nX, aBlack );
477 else
479 for( long nY = 0L; nY < nHeight; nY++ )
481 for( long nX = 0L, nModY = nY % 16; nX < nWidth; nX++ )
483 if( pReadAcc->GetPixel( nY, nX ).GetLuminance() >
484 pDitherMatrix[ nModY ][ nX % 16 ] )
486 pWriteAcc->SetPixel( nY, nX, aWhite );
488 else
489 pWriteAcc->SetPixel( nY, nX, aBlack );
494 aNewBmp.ReleaseAccess( pWriteAcc );
495 bRet = TRUE;
498 ReleaseAccess( pReadAcc );
500 if( bRet )
502 const MapMode aMap( maPrefMapMode );
503 const Size aSize( maPrefSize );
505 *this = aNewBmp;
507 maPrefMapMode = aMap;
508 maPrefSize = aSize;
512 return bRet;
515 // ------------------------------------------------------------------------
517 BOOL Bitmap::ImplMakeGreyscales( USHORT nGreys )
519 DBG_ASSERT( nGreys == 16 || nGreys == 256, "Only 16 or 256 greyscales are supported!" );
521 BitmapReadAccess* pReadAcc = AcquireReadAccess();
522 BOOL bRet = FALSE;
524 if( pReadAcc )
526 const BitmapPalette& rPal = GetGreyPalette( nGreys );
527 ULONG nShift = ( ( nGreys == 16 ) ? 4UL : 0UL );
528 BOOL bPalDiffers = !pReadAcc->HasPalette() || ( rPal.GetEntryCount() != pReadAcc->GetPaletteEntryCount() );
530 if( !bPalDiffers )
531 bPalDiffers = ( (BitmapPalette&) rPal != pReadAcc->GetPalette() );
533 if( bPalDiffers )
535 Bitmap aNewBmp( GetSizePixel(), ( nGreys == 16 ) ? 4 : 8, &rPal );
536 BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess();
538 if( pWriteAcc )
540 const long nWidth = pWriteAcc->Width();
541 const long nHeight = pWriteAcc->Height();
543 if( pReadAcc->HasPalette() )
545 for( long nY = 0L; nY < nHeight; nY++ )
547 for( long nX = 0L; nX < nWidth; nX++ )
549 pWriteAcc->SetPixel( nY, nX,
550 (BYTE) ( pReadAcc->GetPaletteColor(
551 pReadAcc->GetPixel( nY, nX ) ).GetLuminance() >> nShift ) );
555 else if( pReadAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_BGR &&
556 pWriteAcc->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL )
558 nShift += 8;
560 for( long nY = 0L; nY < nHeight; nY++ )
562 Scanline pReadScan = pReadAcc->GetScanline( nY );
563 Scanline pWriteScan = pWriteAcc->GetScanline( nY );
565 for( long nX = 0L; nX < nWidth; nX++ )
567 const ULONG nB = *pReadScan++;
568 const ULONG nG = *pReadScan++;
569 const ULONG nR = *pReadScan++;
571 *pWriteScan++ = (BYTE) ( ( nB * 28UL + nG * 151UL + nR * 77UL ) >> nShift );
575 else if( pReadAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_RGB &&
576 pWriteAcc->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL )
578 nShift += 8;
580 for( long nY = 0L; nY < nHeight; nY++ )
582 Scanline pReadScan = pReadAcc->GetScanline( nY );
583 Scanline pWriteScan = pWriteAcc->GetScanline( nY );
585 for( long nX = 0L; nX < nWidth; nX++ )
587 const ULONG nR = *pReadScan++;
588 const ULONG nG = *pReadScan++;
589 const ULONG nB = *pReadScan++;
591 *pWriteScan++ = (BYTE) ( ( nB * 28UL + nG * 151UL + nR * 77UL ) >> nShift );
595 else
597 for( long nY = 0L; nY < nHeight; nY++ )
598 for( long nX = 0L; nX < nWidth; nX++ )
599 pWriteAcc->SetPixel( nY, nX, sal::static_int_cast<BYTE>(( pReadAcc->GetPixel( nY, nX ) ).GetLuminance() >> nShift) );
602 aNewBmp.ReleaseAccess( pWriteAcc );
603 bRet = TRUE;
606 ReleaseAccess( pReadAcc );
608 if( bRet )
610 const MapMode aMap( maPrefMapMode );
611 const Size aSize( maPrefSize );
613 *this = aNewBmp;
615 maPrefMapMode = aMap;
616 maPrefSize = aSize;
619 else
621 ReleaseAccess( pReadAcc );
622 bRet = TRUE;
626 return bRet;
629 // ------------------------------------------------------------------------
631 BOOL Bitmap::ImplConvertUp( USHORT nBitCount, Color* pExtColor )
633 DBG_ASSERT( nBitCount > GetBitCount(), "New BitCount must be greater!" );
635 BitmapReadAccess* pReadAcc = AcquireReadAccess();
636 BOOL bRet = FALSE;
638 if( pReadAcc )
640 BitmapPalette aPal;
641 Bitmap aNewBmp( GetSizePixel(), nBitCount, pReadAcc->HasPalette() ? &pReadAcc->GetPalette() : &aPal );
642 BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess();
644 if( pWriteAcc )
646 const long nWidth = pWriteAcc->Width();
647 const long nHeight = pWriteAcc->Height();
649 if( pWriteAcc->HasPalette() )
651 const USHORT nOldCount = 1 << GetBitCount();
652 const BitmapPalette& rOldPal = pReadAcc->GetPalette();
654 aPal.SetEntryCount( 1 << nBitCount );
656 for( USHORT i = 0; i < nOldCount; i++ )
657 aPal[ i ] = rOldPal[ i ];
659 if( pExtColor )
660 aPal[ aPal.GetEntryCount() - 1 ] = *pExtColor;
662 pWriteAcc->SetPalette( aPal );
664 for( long nY = 0L; nY < nHeight; nY++ )
665 for( long nX = 0L; nX < nWidth; nX++ )
666 pWriteAcc->SetPixel( nY, nX, pReadAcc->GetPixel( nY, nX ) );
668 else
670 if( pReadAcc->HasPalette() )
672 for( long nY = 0L; nY < nHeight; nY++ )
673 for( long nX = 0L; nX < nWidth; nX++ )
674 pWriteAcc->SetPixel( nY, nX, pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nY, nX ) ) );
676 else
678 for( long nY = 0L; nY < nHeight; nY++ )
679 for( long nX = 0L; nX < nWidth; nX++ )
680 pWriteAcc->SetPixel( nY, nX, pReadAcc->GetPixel( nY, nX ) );
684 aNewBmp.ReleaseAccess( pWriteAcc );
685 bRet = TRUE;
688 ReleaseAccess( pReadAcc );
690 if( bRet )
692 const MapMode aMap( maPrefMapMode );
693 const Size aSize( maPrefSize );
695 *this = aNewBmp;
697 maPrefMapMode = aMap;
698 maPrefSize = aSize;
702 return bRet;
705 // ------------------------------------------------------------------------
707 BOOL Bitmap::ImplConvertDown( USHORT nBitCount, Color* pExtColor )
709 DBG_ASSERT( nBitCount <= GetBitCount(), "New BitCount must be lower ( or equal when pExtColor is set )!" );
711 BitmapReadAccess* pReadAcc = AcquireReadAccess();
712 BOOL bRet = FALSE;
714 if( pReadAcc )
716 BitmapPalette aPal;
717 Bitmap aNewBmp( GetSizePixel(), nBitCount, &aPal );
718 BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess();
720 if( pWriteAcc )
722 const USHORT nCount = 1 << nBitCount;
723 const long nWidth = pWriteAcc->Width();
724 const long nWidth1 = nWidth - 1L;
725 const long nHeight = pWriteAcc->Height();
726 Octree aOctree( *pReadAcc, pExtColor ? ( nCount - 1 ) : nCount );
727 InverseColorMap aColorMap( aPal = aOctree.GetPalette() );
728 BitmapColor aColor;
729 ImpErrorQuad aErrQuad;
730 ImpErrorQuad* pErrQuad1 = new ImpErrorQuad[ nWidth ];
731 ImpErrorQuad* pErrQuad2 = new ImpErrorQuad[ nWidth ];
732 ImpErrorQuad* pQLine1 = pErrQuad1;
733 ImpErrorQuad* pQLine2 = 0;
734 long nX, nY;
735 long nYTmp = 0L;
736 BYTE cIndex;
737 BOOL bQ1 = TRUE;
739 if( pExtColor )
741 aPal.SetEntryCount( aPal.GetEntryCount() + 1 );
742 aPal[ aPal.GetEntryCount() - 1 ] = *pExtColor;
745 // set Black/White always, if we have enough space
746 if( aPal.GetEntryCount() < ( nCount - 1 ) )
748 aPal.SetEntryCount( aPal.GetEntryCount() + 2 );
749 aPal[ aPal.GetEntryCount() - 2 ] = Color( COL_BLACK );
750 aPal[ aPal.GetEntryCount() - 1 ] = Color( COL_WHITE );
753 pWriteAcc->SetPalette( aPal );
755 for( nY = 0L; nY < Min( nHeight, 2L ); nY++, nYTmp++ )
757 for( nX = 0L, pQLine2 = !nY ? pErrQuad1 : pErrQuad2; nX < nWidth; nX++ )
759 if( pReadAcc->HasPalette() )
760 pQLine2[ nX ] = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nYTmp, nX ) );
761 else
762 pQLine2[ nX ] = pReadAcc->GetPixel( nYTmp, nX );
766 for( nY = 0L; nY < nHeight; nY++, nYTmp++ )
768 // erstes ZeilenPixel
769 cIndex = (BYTE) aColorMap.GetBestPaletteIndex( pQLine1[ 0 ].ImplGetColor() );
770 pWriteAcc->SetPixel( nY, 0, cIndex );
772 for( nX = 1L; nX < nWidth1; nX++ )
774 cIndex = (BYTE) aColorMap.GetBestPaletteIndex( aColor = pQLine1[ nX ].ImplGetColor() );
775 aErrQuad = ( ImpErrorQuad( aColor ) -= pWriteAcc->GetPaletteColor( cIndex ) );
776 pQLine1[ ++nX ].ImplAddColorError7( aErrQuad );
777 pQLine2[ nX-- ].ImplAddColorError1( aErrQuad );
778 pQLine2[ nX-- ].ImplAddColorError5( aErrQuad );
779 pQLine2[ nX++ ].ImplAddColorError3( aErrQuad );
780 pWriteAcc->SetPixel( nY, nX, cIndex );
783 // letztes ZeilenPixel
784 if( nX < nWidth )
786 cIndex = (BYTE) aColorMap.GetBestPaletteIndex( pQLine1[ nWidth1 ].ImplGetColor() );
787 pWriteAcc->SetPixel( nY, nX, cIndex );
790 // Zeilenpuffer neu fuellen/kopieren
791 pQLine1 = pQLine2;
792 pQLine2 = ( bQ1 = !bQ1 ) != FALSE ? pErrQuad2 : pErrQuad1;
794 if( nYTmp < nHeight )
796 for( nX = 0L; nX < nWidth; nX++ )
798 if( pReadAcc->HasPalette() )
799 pQLine2[ nX ] = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nYTmp, nX ) );
800 else
801 pQLine2[ nX ] = pReadAcc->GetPixel( nYTmp, nX );
806 // Zeilenpuffer zerstoeren
807 delete[] pErrQuad1;
808 delete[] pErrQuad2;
810 aNewBmp.ReleaseAccess( pWriteAcc );
811 bRet = TRUE;
814 ReleaseAccess( pReadAcc );
816 if( bRet )
818 const MapMode aMap( maPrefMapMode );
819 const Size aSize( maPrefSize );
821 *this = aNewBmp;
823 maPrefMapMode = aMap;
824 maPrefSize = aSize;
828 return bRet;
831 // ------------------------------------------------------------------------
833 BOOL Bitmap::ImplConvertGhosted()
835 Bitmap aNewBmp;
836 BitmapReadAccess* pR = AcquireReadAccess();
837 BOOL bRet = FALSE;
839 if( pR )
841 if( pR->HasPalette() )
843 BitmapPalette aNewPal( pR->GetPaletteEntryCount() );
845 for( long i = 0, nCount = aNewPal.GetEntryCount(); i < nCount; i++ )
847 const BitmapColor& rOld = pR->GetPaletteColor( (USHORT) i );
848 aNewPal[ (USHORT) i ] = BitmapColor( ( rOld.GetRed() >> 1 ) | 0x80,
849 ( rOld.GetGreen() >> 1 ) | 0x80,
850 ( rOld.GetBlue() >> 1 ) | 0x80 );
853 aNewBmp = Bitmap( GetSizePixel(), GetBitCount(), &aNewPal );
854 BitmapWriteAccess* pW = aNewBmp.AcquireWriteAccess();
856 if( pW )
858 pW->CopyBuffer( *pR );
859 aNewBmp.ReleaseAccess( pW );
860 bRet = TRUE;
863 else
865 aNewBmp = Bitmap( GetSizePixel(), 24 );
867 BitmapWriteAccess* pW = aNewBmp.AcquireWriteAccess();
869 if( pW )
871 const long nWidth = pR->Width(), nHeight = pR->Height();
873 for( long nY = 0; nY < nHeight; nY++ )
875 for( long nX = 0; nX < nWidth; nX++ )
877 const BitmapColor aOld( pR->GetPixel( nY, nX ) );
878 pW->SetPixel( nY, nX, BitmapColor( ( aOld.GetRed() >> 1 ) | 0x80,
879 ( aOld.GetGreen() >> 1 ) | 0x80,
880 ( aOld.GetBlue() >> 1 ) | 0x80 ) );
885 aNewBmp.ReleaseAccess( pW );
886 bRet = TRUE;
890 ReleaseAccess( pR );
893 if( bRet )
895 const MapMode aMap( maPrefMapMode );
896 const Size aSize( maPrefSize );
898 *this = aNewBmp;
900 maPrefMapMode = aMap;
901 maPrefSize = aSize;
904 return bRet;
907 // ------------------------------------------------------------------------
909 BOOL Bitmap::Scale( const double& rScaleX, const double& rScaleY, ULONG nScaleFlag )
911 BOOL bRet;
913 if( ( rScaleX != 1.0 ) || ( rScaleY != 1.0 ) )
915 if( BMP_SCALE_FAST == nScaleFlag )
916 bRet = ImplScaleFast( rScaleX, rScaleY );
917 else if( BMP_SCALE_INTERPOLATE == nScaleFlag )
918 bRet = ImplScaleInterpolate( rScaleX, rScaleY );
919 else
920 bRet = FALSE;
922 else
923 bRet = TRUE;
925 return bRet;
928 // ------------------------------------------------------------------------
930 BOOL Bitmap::Scale( const Size& rNewSize, ULONG nScaleFlag )
932 const Size aSize( GetSizePixel() );
933 BOOL bRet;
935 if( aSize.Width() && aSize.Height() )
937 bRet = Scale( (double) rNewSize.Width() / aSize.Width(),
938 (double) rNewSize.Height() / aSize.Height(),
939 nScaleFlag );
941 else
942 bRet = TRUE;
944 return bRet;
947 // ------------------------------------------------------------------------
949 BOOL Bitmap::ImplScaleFast( const double& rScaleX, const double& rScaleY )
951 const Size aSizePix( GetSizePixel() );
952 const long nNewWidth = FRound( aSizePix.Width() * rScaleX );
953 const long nNewHeight = FRound( aSizePix.Height() * rScaleY );
954 BOOL bRet = FALSE;
956 if( nNewWidth && nNewHeight )
958 BitmapReadAccess* pReadAcc = AcquireReadAccess();
959 Bitmap aNewBmp( Size( nNewWidth, nNewHeight ), GetBitCount(), &pReadAcc->GetPalette() );
960 BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess();
962 if( pReadAcc && pWriteAcc )
964 const long nScanlineSize = pWriteAcc->GetScanlineSize();
965 const long nNewWidth1 = nNewWidth - 1L;
966 const long nNewHeight1 = nNewHeight - 1L;
967 const long nWidth1 = pReadAcc->Width() - 1L;
968 const long nHeight1 = pReadAcc->Height() - 1L;
969 long* pLutX = new long[ nNewWidth ];
970 long* pLutY = new long[ nNewHeight ];
971 long nX, nY, nMapY, nActY = 0L;
973 if( nNewWidth1 && nNewHeight1 )
975 for( nX = 0L; nX < nNewWidth; nX++ )
976 pLutX[ nX ] = nX * nWidth1 / nNewWidth1;
978 for( nY = 0L; nY < nNewHeight; nY++ )
979 pLutY[ nY ] = nY * nHeight1 / nNewHeight1;
981 while( nActY < nNewHeight )
983 nMapY = pLutY[ nActY ];
985 for( nX = 0L; nX < nNewWidth; nX++ )
986 pWriteAcc->SetPixel( nActY, nX, pReadAcc->GetPixel( nMapY , pLutX[ nX ] ) );
988 while( ( nActY < nNewHeight1 ) && ( pLutY[ nActY + 1 ] == nMapY ) )
990 memcpy( pWriteAcc->GetScanline( nActY + 1L ),
991 pWriteAcc->GetScanline( nActY ), nScanlineSize );
992 nActY++;
995 nActY++;
998 bRet = TRUE;
1001 delete[] pLutX;
1002 delete[] pLutY;
1005 ReleaseAccess( pReadAcc );
1006 aNewBmp.ReleaseAccess( pWriteAcc );
1008 if( bRet )
1009 ImplAssignWithSize( aNewBmp );
1012 return bRet;
1015 // ------------------------------------------------------------------------
1017 BOOL Bitmap::ImplScaleInterpolate( const double& rScaleX, const double& rScaleY )
1019 const Size aSizePix( GetSizePixel() );
1020 const long nNewWidth = FRound( aSizePix.Width() * rScaleX );
1021 const long nNewHeight = FRound( aSizePix.Height() * rScaleY );
1022 BOOL bRet = FALSE;
1024 if( ( nNewWidth > 1L ) && ( nNewHeight > 1L ) )
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;
1040 if( pReadAcc && pWriteAcc )
1042 const long nNewWidth1 = nNewWidth - 1L;
1043 const long nWidth1 = pReadAcc->Width() - 1L;
1044 const double fRevScaleX = (double) nWidth1 / nNewWidth1;
1046 pLutInt = new long[ nNewWidth ];
1047 pLutFrac = new long[ nNewWidth ];
1049 for( nX = 0L, nTemp = nWidth - 2L; nX < nNewWidth; nX++ )
1051 fTemp = nX * fRevScaleX;
1052 pLutInt[ nX ] = MinMax( (long) fTemp, 0, nTemp );
1053 fTemp -= pLutInt[ nX ];
1054 pLutFrac[ nX ] = (long) ( fTemp * 1024. );
1057 if( pReadAcc->HasPalette() )
1059 for( nY = 0L; nY < nHeight; nY++ )
1061 if( 1 == nWidth )
1063 aCol0 = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nY, 0 ) );
1065 for( nX = 0L; nX < nNewWidth; nX++ )
1066 pWriteAcc->SetPixel( nY, nX, aCol0 );
1068 else
1070 for( nX = 0L; nX < nNewWidth; nX++ )
1072 nTemp = pLutInt[ nX ];
1074 aCol0 = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nY, nTemp++ ) );
1075 aCol1 = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nY, nTemp ) );
1077 nTemp = pLutFrac[ nX ];
1079 lXR1 = aCol1.GetRed() - ( lXR0 = aCol0.GetRed() );
1080 lXG1 = aCol1.GetGreen() - ( lXG0 = aCol0.GetGreen() );
1081 lXB1 = aCol1.GetBlue() - ( lXB0 = aCol0.GetBlue() );
1083 aCol0.SetRed( (BYTE) ( ( lXR1 * nTemp + ( lXR0 << 10 ) ) >> 10 ) );
1084 aCol0.SetGreen( (BYTE) ( ( lXG1 * nTemp + ( lXG0 << 10 ) ) >> 10 ) );
1085 aCol0.SetBlue( (BYTE) ( ( lXB1 * nTemp + ( lXB0 << 10 ) ) >> 10 ) );
1087 pWriteAcc->SetPixel( nY, nX, aCol0 );
1092 else
1094 for( nY = 0L; nY < nHeight; nY++ )
1096 if( 1 == nWidth )
1098 aCol0 = pReadAcc->GetPixel( nY, 0 );
1100 for( nX = 0L; nX < nNewWidth; nX++ )
1101 pWriteAcc->SetPixel( nY, nX, aCol0 );
1103 else
1105 for( nX = 0L; nX < nNewWidth; nX++ )
1107 nTemp = pLutInt[ nX ];
1109 aCol0 = pReadAcc->GetPixel( nY, nTemp++ );
1110 aCol1 = pReadAcc->GetPixel( nY, nTemp );
1112 nTemp = pLutFrac[ nX ];
1114 lXR1 = aCol1.GetRed() - ( lXR0 = aCol0.GetRed() );
1115 lXG1 = aCol1.GetGreen() - ( lXG0 = aCol0.GetGreen() );
1116 lXB1 = aCol1.GetBlue() - ( lXB0 = aCol0.GetBlue() );
1118 aCol0.SetRed( (BYTE) ( ( lXR1 * nTemp + ( lXR0 << 10 ) ) >> 10 ) );
1119 aCol0.SetGreen( (BYTE) ( ( lXG1 * nTemp + ( lXG0 << 10 ) ) >> 10 ) );
1120 aCol0.SetBlue( (BYTE) ( ( lXB1 * nTemp + ( lXB0 << 10 ) ) >> 10 ) );
1122 pWriteAcc->SetPixel( nY, nX, aCol0 );
1128 delete[] pLutInt;
1129 delete[] pLutFrac;
1130 bRet = TRUE;
1133 ReleaseAccess( pReadAcc );
1134 aNewBmp.ReleaseAccess( pWriteAcc );
1136 if( bRet )
1138 bRet = FALSE;
1139 ImplAssignWithSize( aNewBmp );
1140 pReadAcc = AcquireReadAccess();
1141 aNewBmp = Bitmap( Size( nNewWidth, nNewHeight ), 24 );
1142 pWriteAcc = aNewBmp.AcquireWriteAccess();
1144 if( pReadAcc && pWriteAcc )
1146 const long nNewHeight1 = nNewHeight - 1L;
1147 const long nHeight1 = pReadAcc->Height() - 1L;
1148 const double fRevScaleY = (double) nHeight1 / nNewHeight1;
1150 pLutInt = new long[ nNewHeight ];
1151 pLutFrac = new long[ nNewHeight ];
1153 for( nY = 0L, nTemp = nHeight - 2L; nY < nNewHeight; nY++ )
1155 fTemp = nY * fRevScaleY;
1156 pLutInt[ nY ] = MinMax( (long) fTemp, 0, nTemp );
1157 fTemp -= pLutInt[ nY ];
1158 pLutFrac[ nY ] = (long) ( fTemp * 1024. );
1161 if( pReadAcc->HasPalette() )
1163 for( nX = 0L; nX < nNewWidth; nX++ )
1165 if( 1 == nHeight )
1167 aCol0 = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( 0, nX ) );
1169 for( nY = 0L; nY < nNewHeight; nY++ )
1170 pWriteAcc->SetPixel( nY, nX, aCol0 );
1172 else
1174 for( nY = 0L; nY < nNewHeight; nY++ )
1176 nTemp = pLutInt[ nY ];
1178 aCol0 = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nTemp++, nX ) );
1179 aCol1 = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nTemp, nX ) );
1181 nTemp = pLutFrac[ nY ];
1183 lXR1 = aCol1.GetRed() - ( lXR0 = aCol0.GetRed() );
1184 lXG1 = aCol1.GetGreen() - ( lXG0 = aCol0.GetGreen() );
1185 lXB1 = aCol1.GetBlue() - ( lXB0 = aCol0.GetBlue() );
1187 aCol0.SetRed( (BYTE) ( ( lXR1 * nTemp + ( lXR0 << 10 ) ) >> 10 ) );
1188 aCol0.SetGreen( (BYTE) ( ( lXG1 * nTemp + ( lXG0 << 10 ) ) >> 10 ) );
1189 aCol0.SetBlue( (BYTE) ( ( lXB1 * nTemp + ( lXB0 << 10 ) ) >> 10 ) );
1191 pWriteAcc->SetPixel( nY, nX, aCol0 );
1196 else
1198 for( nX = 0L; nX < nNewWidth; nX++ )
1200 if( 1 == nHeight )
1202 aCol0 = pReadAcc->GetPixel( 0, nX );
1204 for( nY = 0L; nY < nNewHeight; nY++ )
1205 pWriteAcc->SetPixel( nY, nX, aCol0 );
1207 else
1209 for( nY = 0L; nY < nNewHeight; nY++ )
1211 nTemp = pLutInt[ nY ];
1213 aCol0 = pReadAcc->GetPixel( nTemp++, nX );
1214 aCol1 = pReadAcc->GetPixel( nTemp, nX );
1216 nTemp = pLutFrac[ nY ];
1218 lXR1 = aCol1.GetRed() - ( lXR0 = aCol0.GetRed() );
1219 lXG1 = aCol1.GetGreen() - ( lXG0 = aCol0.GetGreen() );
1220 lXB1 = aCol1.GetBlue() - ( lXB0 = aCol0.GetBlue() );
1222 aCol0.SetRed( (BYTE) ( ( lXR1 * nTemp + ( lXR0 << 10 ) ) >> 10 ) );
1223 aCol0.SetGreen( (BYTE) ( ( lXG1 * nTemp + ( lXG0 << 10 ) ) >> 10 ) );
1224 aCol0.SetBlue( (BYTE) ( ( lXB1 * nTemp + ( lXB0 << 10 ) ) >> 10 ) );
1226 pWriteAcc->SetPixel( nY, nX, aCol0 );
1232 delete[] pLutInt;
1233 delete[] pLutFrac;
1234 bRet = TRUE;
1237 ReleaseAccess( pReadAcc );
1238 aNewBmp.ReleaseAccess( pWriteAcc );
1240 if( bRet )
1241 ImplAssignWithSize( aNewBmp );
1245 if( !bRet )
1246 bRet = ImplScaleFast( rScaleX, rScaleY );
1248 return bRet;
1251 // ------------------------------------------------------------------------
1253 BOOL Bitmap::Dither( ULONG nDitherFlags )
1255 BOOL bRet = FALSE;
1257 const Size aSizePix( GetSizePixel() );
1259 if( aSizePix.Width() == 1 || aSizePix.Height() == 1 )
1260 bRet = 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();
1268 return bRet;
1271 // ------------------------------------------------------------------------
1273 BOOL Bitmap::ImplDitherMatrix()
1275 BitmapReadAccess* pReadAcc = AcquireReadAccess();
1276 Bitmap aNewBmp( GetSizePixel(), 8 );
1277 BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess();
1278 BOOL bRet = FALSE;
1280 if( pReadAcc && pWriteAcc )
1282 const ULONG nWidth = pReadAcc->Width();
1283 const ULONG nHeight = pReadAcc->Height();
1284 BitmapColor aIndex( (BYTE) 0 );
1286 if( pReadAcc->HasPalette() )
1288 for( ULONG nY = 0UL; nY < nHeight; nY++ )
1290 for( ULONG nX = 0UL, nModY = ( nY & 0x0FUL ) << 4UL; nX < nWidth; nX++ )
1292 const BitmapColor aCol( pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nY, nX ) ) );
1293 const ULONG nD = nVCLDitherLut[ nModY + ( nX & 0x0FUL ) ];
1294 const ULONG nR = ( nVCLLut[ aCol.GetRed() ] + nD ) >> 16UL;
1295 const ULONG nG = ( nVCLLut[ aCol.GetGreen() ] + nD ) >> 16UL;
1296 const ULONG nB = ( nVCLLut[ aCol.GetBlue() ] + nD ) >> 16UL;
1298 aIndex.SetIndex( (BYTE) ( nVCLRLut[ nR ] + nVCLGLut[ nG ] + nVCLBLut[ nB ] ) );
1299 pWriteAcc->SetPixel( nY, nX, aIndex );
1303 else
1305 for( ULONG nY = 0UL; nY < nHeight; nY++ )
1307 for( ULONG nX = 0UL, nModY = ( nY & 0x0FUL ) << 4UL; nX < nWidth; nX++ )
1309 const BitmapColor aCol( pReadAcc->GetPixel( nY, nX ) );
1310 const ULONG nD = nVCLDitherLut[ nModY + ( nX & 0x0FUL ) ];
1311 const ULONG nR = ( nVCLLut[ aCol.GetRed() ] + nD ) >> 16UL;
1312 const ULONG nG = ( nVCLLut[ aCol.GetGreen() ] + nD ) >> 16UL;
1313 const ULONG nB = ( nVCLLut[ aCol.GetBlue() ] + nD ) >> 16UL;
1315 aIndex.SetIndex( (BYTE) ( nVCLRLut[ nR ] + nVCLGLut[ nG ] + nVCLBLut[ nB ] ) );
1316 pWriteAcc->SetPixel( nY, nX, aIndex );
1321 bRet = TRUE;
1324 ReleaseAccess( pReadAcc );
1325 aNewBmp.ReleaseAccess( pWriteAcc );
1327 if( bRet )
1329 const MapMode aMap( maPrefMapMode );
1330 const Size aSize( maPrefSize );
1332 *this = aNewBmp;
1334 maPrefMapMode = aMap;
1335 maPrefSize = aSize;
1338 return bRet;
1341 // ------------------------------------------------------------------------
1343 BOOL Bitmap::ImplDitherFloyd()
1345 const Size aSize( GetSizePixel() );
1346 BOOL bRet = FALSE;
1348 if( ( aSize.Width() > 3 ) && ( aSize.Height() > 2 ) )
1350 BitmapReadAccess* pReadAcc = AcquireReadAccess();
1351 Bitmap aNewBmp( GetSizePixel(), 8 );
1352 BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess();
1354 if( pReadAcc && pWriteAcc )
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 BOOL bPal = pReadAcc->HasPalette();
1374 pTmp = p2T;
1376 if( bPal )
1378 for( nZ = 0; nZ < nWidth; nZ++ )
1380 aColor = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( 0, nZ ) );
1382 *pTmp++ = (long) aColor.GetBlue() << 12;
1383 *pTmp++ = (long) aColor.GetGreen() << 12;
1384 *pTmp++ = (long) aColor.GetRed() << 12;
1387 else
1389 for( nZ = 0; nZ < nWidth; nZ++ )
1391 aColor = pReadAcc->GetPixel( 0, nZ );
1393 *pTmp++ = (long) aColor.GetBlue() << 12;
1394 *pTmp++ = (long) aColor.GetGreen() << 12;
1395 *pTmp++ = (long) aColor.GetRed() << 12;
1399 for( long nY = 1, nYAcc = 0L; nY <= nHeight; nY++, nYAcc++ )
1401 pTmp = p1T;
1402 p1T = p2T;
1403 p2T = pTmp;
1405 if( nY < nHeight )
1407 if( bPal )
1409 for( nZ = 0; nZ < nWidth; nZ++ )
1411 aColor = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nY, nZ ) );
1413 *pTmp++ = (long) aColor.GetBlue() << 12;
1414 *pTmp++ = (long) aColor.GetGreen() << 12;
1415 *pTmp++ = (long) aColor.GetRed() << 12;
1418 else
1420 for( nZ = 0; nZ < nWidth; nZ++ )
1422 aColor = pReadAcc->GetPixel( nY, nZ );
1424 *pTmp++ = (long) aColor.GetBlue() << 12;
1425 *pTmp++ = (long) aColor.GetGreen() << 12;
1426 *pTmp++ = (long) aColor.GetRed() << 12;
1431 // erstes Pixel gesondert betrachten
1432 nX = 0;
1433 CALC_ERRORS;
1434 CALC_TABLES7;
1435 nX -= 5;
1436 CALC_TABLES5;
1437 pWriteAcc->SetPixel( nYAcc, 0, BitmapColor( (BYTE) ( nVCLBLut[ nBC ] + nVCLGLut[nGC ] + nVCLRLut[nRC ] ) ) );
1439 // mittlere Pixel ueber Schleife
1440 long nXAcc;
1441 for ( nX = 3L, nXAcc = 1L; nX < nW2; nXAcc++ )
1443 CALC_ERRORS;
1444 CALC_TABLES7;
1445 nX -= 8;
1446 CALC_TABLES3;
1447 CALC_TABLES5;
1448 pWriteAcc->SetPixel( nYAcc, nXAcc, BitmapColor( (BYTE) ( nVCLBLut[ nBC ] + nVCLGLut[nGC ] + nVCLRLut[nRC ] ) ) );
1451 // letztes Pixel gesondert betrachten
1452 CALC_ERRORS;
1453 nX -= 5;
1454 CALC_TABLES3;
1455 CALC_TABLES5;
1456 pWriteAcc->SetPixel( nYAcc, nWidth1, BitmapColor( (BYTE) ( nVCLBLut[ nBC ] + nVCLGLut[nGC ] + nVCLRLut[nRC ] ) ) );
1459 delete[] p1;
1460 delete[] p2;
1461 bRet = TRUE;
1464 ReleaseAccess( pReadAcc );
1465 aNewBmp.ReleaseAccess( pWriteAcc );
1467 if( bRet )
1469 const MapMode aMap( maPrefMapMode );
1470 const Size aPrefSize( maPrefSize );
1472 *this = aNewBmp;
1474 maPrefMapMode = aMap;
1475 maPrefSize = aPrefSize;
1479 return bRet;
1482 // ------------------------------------------------------------------------
1484 BOOL Bitmap::ImplDitherFloyd16()
1486 BitmapReadAccess* pReadAcc = AcquireReadAccess();
1487 Bitmap aNewBmp( GetSizePixel(), 24 );
1488 BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess();
1489 BOOL bRet = FALSE;
1491 if( pReadAcc && pWriteAcc )
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 BOOL bQ1 = TRUE;
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 );
1511 for( nY = 0L; nY < nHeight; nY++, nYTmp++ )
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 );
1520 for( nX = 1L; nX < nWidth1; nX++ )
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 );
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 );
1541 // Zeilenpuffer neu fuellen/kopieren
1542 pQLine1 = pQLine2;
1543 pQLine2 = ( bQ1 = !bQ1 ) != FALSE ? pErrQuad2 : pErrQuad1;
1545 if( nYTmp < nHeight )
1546 for( nX = 0L; nX < nWidth; nX++ )
1547 pQLine2[ nX ] = pReadAcc->GetPixel( nYTmp, nX );
1550 // Zeilenpuffer zerstoeren
1551 delete[] pErrQuad1;
1552 delete[] pErrQuad2;
1553 bRet = TRUE;
1556 ReleaseAccess( pReadAcc );
1557 aNewBmp.ReleaseAccess( pWriteAcc );
1559 if( bRet )
1561 const MapMode aMap( maPrefMapMode );
1562 const Size aSize( maPrefSize );
1564 *this = aNewBmp;
1566 maPrefMapMode = aMap;
1567 maPrefSize = aSize;
1570 return bRet;
1573 // ------------------------------------------------------------------------
1575 BOOL Bitmap::ReduceColors( USHORT nColorCount, BmpReduce eReduce )
1577 BOOL bRet;
1579 if( GetColorCount() <= (ULONG) nColorCount )
1580 bRet = TRUE;
1581 else if( nColorCount )
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 );
1590 else
1591 bRet = FALSE;
1593 return bRet;
1596 // ------------------------------------------------------------------------
1598 BOOL Bitmap::ImplReduceSimple( USHORT nColorCount )
1600 Bitmap aNewBmp;
1601 BitmapReadAccess* pRAcc = AcquireReadAccess();
1602 const USHORT nColCount = Min( nColorCount, (USHORT) 256 );
1603 USHORT nBitCount;
1604 BOOL bRet = FALSE;
1606 if( nColCount <= 2 )
1607 nBitCount = 1;
1608 else if( nColCount <= 16 )
1609 nBitCount = 4;
1610 else
1611 nBitCount = 8;
1613 if( pRAcc )
1615 Octree aOct( *pRAcc, nColCount );
1616 const BitmapPalette& rPal = aOct.GetPalette();
1617 BitmapWriteAccess* pWAcc;
1619 aNewBmp = Bitmap( GetSizePixel(), nBitCount, &rPal );
1620 pWAcc = aNewBmp.AcquireWriteAccess();
1622 if( pWAcc )
1624 const long nWidth = pRAcc->Width();
1625 const long nHeight = pRAcc->Height();
1627 if( pRAcc->HasPalette() )
1629 for( long nY = 0L; nY < nHeight; nY++ )
1630 for( long nX =0L; nX < nWidth; nX++ )
1631 pWAcc->SetPixel( nY, nX, (BYTE) aOct.GetBestPaletteIndex( pRAcc->GetPaletteColor( pRAcc->GetPixel( nY, nX ) ) ) );
1633 else
1635 for( long nY = 0L; nY < nHeight; nY++ )
1636 for( long nX =0L; nX < nWidth; nX++ )
1637 pWAcc->SetPixel( nY, nX, (BYTE) aOct.GetBestPaletteIndex( pRAcc->GetPixel( nY, nX ) ) );
1640 aNewBmp.ReleaseAccess( pWAcc );
1641 bRet = TRUE;
1644 ReleaseAccess( pRAcc );
1647 if( bRet )
1649 const MapMode aMap( maPrefMapMode );
1650 const Size aSize( maPrefSize );
1652 *this = aNewBmp;
1653 maPrefMapMode = aMap;
1654 maPrefSize = aSize;
1657 return bRet;
1660 // ------------------------------------------------------------------------
1662 struct PopularColorCount
1664 sal_uInt32 mnIndex;
1665 sal_uInt32 mnCount;
1668 // ------------------------------------------------------------------------
1670 extern "C" int __LOADONCALLAPI ImplPopularCmpFnc( const void* p1, const void* p2 )
1672 int nRet;
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;
1681 return nRet;
1684 // ------------------------------------------------------------------------
1686 BOOL Bitmap::ImplReducePopular( USHORT nColCount )
1688 BitmapReadAccess* pRAcc = AcquireReadAccess();
1689 USHORT nBitCount;
1690 BOOL bRet = FALSE;
1692 if( nColCount > 256 )
1693 nColCount = 256;
1695 if( nColCount < 17 )
1696 nBitCount = 4;
1697 else
1698 nBitCount = 8;
1700 if( pRAcc )
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;
1714 rtl_zeroMemory( pCountTable, nTotalColors * sizeof( PopularColorCount ) );
1716 for( nR = 0, nIndex = 0; nR < 256; nR += nColorOffset )
1718 for( nG = 0; nG < 256; nG += nColorOffset )
1720 for( nB = 0; nB < 256; nB += nColorOffset )
1722 pCountTable[ nIndex ].mnIndex = nIndex;
1723 nIndex++;
1728 if( pRAcc->HasPalette() )
1730 for( nY = 0L; nY < nHeight; nY++ )
1732 for( nX = 0L; nX < nWidth; nX++ )
1734 const BitmapColor& rCol = pRAcc->GetPaletteColor( pRAcc->GetPixel( nY, nX ) );
1735 pCountTable[ ( ( ( (sal_uInt32) rCol.GetRed() ) >> nRightShiftBits ) << nLeftShiftBits2 ) |
1736 ( ( ( (sal_uInt32) rCol.GetGreen() ) >> nRightShiftBits ) << nLeftShiftBits1 ) |
1737 ( ( (sal_uInt32) rCol.GetBlue() ) >> nRightShiftBits ) ].mnCount++;
1741 else
1743 for( nY = 0L; nY < nHeight; nY++ )
1745 for( nX = 0L; nX < nWidth; nX++ )
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++;
1755 BitmapPalette aNewPal( nColCount );
1757 qsort( pCountTable, nTotalColors, sizeof( PopularColorCount ), ImplPopularCmpFnc );
1759 for( USHORT n = 0; n < nColCount; n++ )
1761 const PopularColorCount& rPop = pCountTable[ n ];
1762 aNewPal[ n ] = BitmapColor( (BYTE) ( ( rPop.mnIndex >> nLeftShiftBits2 ) << nRightShiftBits ),
1763 (BYTE) ( ( ( rPop.mnIndex >> nLeftShiftBits1 ) & ( nColorsPerComponent - 1 ) ) << nRightShiftBits ),
1764 (BYTE) ( ( rPop.mnIndex & ( nColorsPerComponent - 1 ) ) << nRightShiftBits ) );
1767 Bitmap aNewBmp( GetSizePixel(), nBitCount, &aNewPal );
1768 BitmapWriteAccess* pWAcc = aNewBmp.AcquireWriteAccess();
1770 if( pWAcc )
1772 BitmapColor aDstCol( (BYTE) 0 );
1773 BYTE* pIndexMap = new BYTE[ nTotalColors ];
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++ ] = (BYTE) aNewPal.GetBestIndex( BitmapColor( (BYTE) nR, (BYTE) nG, (BYTE) nB ) );
1780 if( pRAcc->HasPalette() )
1782 for( nY = 0L; nY < nHeight; nY++ )
1784 for( nX = 0L; nX < nWidth; nX++ )
1786 const BitmapColor& rCol = pRAcc->GetPaletteColor( pRAcc->GetPixel( 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 );
1794 else
1796 for( nY = 0L; nY < nHeight; nY++ )
1798 for( nX = 0L; nX < nWidth; nX++ )
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 );
1809 delete[] pIndexMap;
1810 aNewBmp.ReleaseAccess( pWAcc );
1811 bRet = TRUE;
1814 delete[] pCountTable;
1815 ReleaseAccess( pRAcc );
1817 if( bRet )
1819 const MapMode aMap( maPrefMapMode );
1820 const Size aSize( maPrefSize );
1822 *this = aNewBmp;
1823 maPrefMapMode = aMap;
1824 maPrefSize = aSize;
1828 return bRet;
1831 // ------------------------------------------------------------------------
1833 BOOL Bitmap::ImplReduceMedian( USHORT nColCount )
1835 BitmapReadAccess* pRAcc = AcquireReadAccess();
1836 USHORT nBitCount;
1837 BOOL bRet = FALSE;
1839 if( nColCount < 17 )
1840 nBitCount = 4;
1841 else if( nColCount < 257 )
1842 nBitCount = 8;
1843 else
1845 DBG_ERROR( "Bitmap::ImplReduceMedian(): invalid color count!" );
1846 nBitCount = 8;
1847 nColCount = 256;
1850 if( pRAcc )
1852 Bitmap aNewBmp( GetSizePixel(), nBitCount );
1853 BitmapWriteAccess* pWAcc = aNewBmp.AcquireWriteAccess();
1855 if( pWAcc )
1857 const ULONG nSize = 32768UL * sizeof( ULONG );
1858 ULONG* pColBuf = (ULONG*) rtl_allocateMemory( nSize );
1859 const long nWidth = pWAcc->Width();
1860 const long nHeight = pWAcc->Height();
1861 long nIndex = 0L;
1863 memset( (HPBYTE) pColBuf, 0, nSize );
1865 // create Buffer
1866 if( pRAcc->HasPalette() )
1868 for( long nY = 0L; nY < nHeight; nY++ )
1870 for( long nX = 0L; nX < nWidth; nX++ )
1872 const BitmapColor& rCol = pRAcc->GetPaletteColor( pRAcc->GetPixel( nY, nX ) );
1873 pColBuf[ RGB15( rCol.GetRed() >> 3, rCol.GetGreen() >> 3, rCol.GetBlue() >> 3 ) ]++;
1877 else
1879 for( long nY = 0L; nY < nHeight; nY++ )
1881 for( long nX = 0L; nX < nWidth; nX++ )
1883 const BitmapColor aCol( pRAcc->GetPixel( nY, nX ) );
1884 pColBuf[ RGB15( aCol.GetRed() >> 3, aCol.GetGreen() >> 3, aCol.GetBlue() >> 3 ) ]++;
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 );
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->SetPixel( nY, nX, (BYTE) aMap.GetBestPaletteIndex( pRAcc->GetColor( nY, nX ) ) );
1901 rtl_freeMemory( pColBuf );
1902 aNewBmp.ReleaseAccess( pWAcc );
1903 bRet = TRUE;
1906 ReleaseAccess( pRAcc );
1908 if( bRet )
1910 const MapMode aMap( maPrefMapMode );
1911 const Size aSize( maPrefSize );
1913 *this = aNewBmp;
1914 maPrefMapMode = aMap;
1915 maPrefSize = aSize;
1919 return bRet;
1922 // ------------------------------------------------------------------------
1924 void Bitmap::ImplMedianCut( ULONG* pColBuf, BitmapPalette& rPal,
1925 long nR1, long nR2, long nG1, long nG2, long nB1, long nB2,
1926 long nColors, long nPixels, long& rIndex )
1928 if( !nPixels )
1929 return;
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 ULONG* pBuf = pColBuf;
1938 if( !nRLen && !nGLen && !nBLen )
1940 if( pBuf[ RGB15( nR1, nG1, nB1 ) ] )
1942 aCol.SetRed( (BYTE) ( nR1 << 3 ) );
1943 aCol.SetGreen( (BYTE) ( nG1 << 3 ) );
1944 aCol.SetBlue( (BYTE) ( nB1 << 3 ) );
1945 rPal[ (USHORT) rIndex++ ] = aCol;
1948 else
1950 if( 1 == nColors || 1 == nPixels )
1952 long nPixSum = 0, nRSum = 0, nGSum = 0, nBSum = 0;
1954 for( nR = nR1; nR <= nR2; nR++ )
1956 for( nG = nG1; nG <= nG2; nG++ )
1958 for( nB = nB1; nB <= nB2; nB++ )
1960 nPixSum = pBuf[ RGB15( nR, nG, nB ) ];
1962 if( nPixSum )
1964 nRSum += nR * nPixSum;
1965 nGSum += nG * nPixSum;
1966 nBSum += nB * nPixSum;
1972 aCol.SetRed( (BYTE) ( ( nRSum / nPixels ) << 3 ) );
1973 aCol.SetGreen( (BYTE) ( ( nGSum / nPixels ) << 3 ) );
1974 aCol.SetBlue( (BYTE) ( ( nBSum / nPixels ) << 3 ) );
1975 rPal[ (USHORT) rIndex++ ] = aCol;
1977 else
1979 const long nTest = ( nPixels >> 1 );
1980 long nPixOld = 0;
1981 long nPixNew = 0;
1983 if( nBLen > nGLen && nBLen > nRLen )
1985 nB = nB1 - 1;
1987 while( nPixNew < nTest )
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 ) ];
1995 if( nB < nB2 )
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 );
2000 else
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 );
2006 else if( nGLen > nRLen )
2008 nG = nG1 - 1;
2010 while( nPixNew < nTest )
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 ) ];
2018 if( nG < nG2 )
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 );
2023 else
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 );
2029 else
2031 nR = nR1 - 1;
2033 while( nPixNew < nTest )
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 ) ];
2041 if( nR < nR2 )
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 );
2046 else
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 );
2056 // ------------------------------------------------------------------------
2058 BOOL Bitmap::Vectorize( PolyPolygon& rPolyPoly, ULONG nFlags, const Link* pProgress )
2060 return ImplVectorizer().ImplVectorize( *this, rPolyPoly, nFlags, pProgress );
2063 // ------------------------------------------------------------------------
2065 BOOL Bitmap::Vectorize( GDIMetaFile& rMtf, BYTE cReduce, ULONG nFlags, const Link* pProgress )
2067 return ImplVectorizer().ImplVectorize( *this, rMtf, cReduce, nFlags, pProgress );
2070 // ------------------------------------------------------------------------
2072 BOOL Bitmap::Adjust( short nLuminancePercent, short nContrastPercent,
2073 short nChannelRPercent, short nChannelGPercent, short nChannelBPercent,
2074 double fGamma, BOOL bInvert )
2076 BOOL bRet = FALSE;
2078 // nothing to do => return quickly
2079 if( !nLuminancePercent && !nContrastPercent &&
2080 !nChannelRPercent && !nChannelGPercent && !nChannelBPercent &&
2081 ( fGamma == 1.0 ) && !bInvert )
2083 bRet = TRUE;
2085 else
2087 BitmapWriteAccess* pAcc = AcquireWriteAccess();
2089 if( pAcc )
2091 BitmapColor aCol;
2092 const long nW = pAcc->Width();
2093 const long nH = pAcc->Height();
2094 BYTE* cMapR = new BYTE[ 256 ];
2095 BYTE* cMapG = new BYTE[ 256 ];
2096 BYTE* cMapB = new BYTE[ 256 ];
2097 long nX, nY;
2098 double fM, fROff, fGOff, fBOff, fOff;
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;
2106 // total offset = luminance offset + contrast offset
2107 fOff = MinMax( nLuminancePercent, -100L, 100L ) * 2.55 + 128.0 - fM * 128.0;
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;
2114 // calculate gamma value
2115 fGamma = ( fGamma <= 0.0 || fGamma > 10.0 ) ? 1.0 : ( 1.0 / fGamma );
2116 const BOOL bGamma = ( fGamma != 1.0 );
2118 // create mapping table
2119 for( nX = 0L; nX < 256L; nX++ )
2121 cMapR[ nX ] = (BYTE) MinMax( FRound( nX * fM + fROff ), 0L, 255L );
2122 cMapG[ nX ] = (BYTE) MinMax( FRound( nX * fM + fGOff ), 0L, 255L );
2123 cMapB[ nX ] = (BYTE) MinMax( FRound( nX * fM + fBOff ), 0L, 255L );
2125 if( bGamma )
2127 cMapR[ nX ] = GAMMA( cMapR[ nX ], fGamma );
2128 cMapG[ nX ] = GAMMA( cMapG[ nX ], fGamma );
2129 cMapB[ nX ] = GAMMA( cMapB[ nX ], fGamma );
2132 if( bInvert )
2134 cMapR[ nX ] = ~cMapR[ nX ];
2135 cMapG[ nX ] = ~cMapG[ nX ];
2136 cMapB[ nX ] = ~cMapB[ nX ];
2140 // do modifying
2141 if( pAcc->HasPalette() )
2143 BitmapColor aNewCol;
2145 for( USHORT i = 0, nCount = pAcc->GetPaletteEntryCount(); i < nCount; i++ )
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 );
2154 else if( pAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_BGR )
2156 for( nY = 0L; nY < nH; nY++ )
2158 Scanline pScan = pAcc->GetScanline( nY );
2160 for( nX = 0L; nX < nW; nX++ )
2162 *pScan = cMapB[ *pScan ]; pScan++;
2163 *pScan = cMapG[ *pScan ]; pScan++;
2164 *pScan = cMapR[ *pScan ]; pScan++;
2168 else if( pAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_RGB )
2170 for( nY = 0L; nY < nH; nY++ )
2172 Scanline pScan = pAcc->GetScanline( nY );
2174 for( nX = 0L; nX < nW; nX++ )
2176 *pScan = cMapR[ *pScan ]; pScan++;
2177 *pScan = cMapG[ *pScan ]; pScan++;
2178 *pScan = cMapB[ *pScan ]; pScan++;
2182 else
2184 for( nY = 0L; nY < nH; nY++ )
2186 for( nX = 0L; nX < nW; nX++ )
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 );
2197 delete[] cMapR;
2198 delete[] cMapG;
2199 delete[] cMapB;
2200 ReleaseAccess( pAcc );
2201 bRet = TRUE;
2205 return bRet;