update emoji autocorrect entries from po-files
[LibreOffice.git] / vcl / source / gdi / bitmap3.cxx
blobf5f6c3257d09205b934bd3779d4bbe534823bbc6
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <math.h>
21 #include <stdlib.h>
23 #include <vcl/bmpacc.hxx>
24 #include <vcl/bitmapex.hxx>
25 #include <vcl/bitmap.hxx>
26 #include <vcl/bitmapscalesuper.hxx>
27 #include <vcl/opengl/OpenGLHelper.hxx>
29 #include <boost/scoped_array.hpp>
31 #include <impbmp.hxx>
32 #include <impoct.hxx>
33 #include <impvect.hxx>
35 #include "octree.hxx"
37 #define RGB15( _def_cR, _def_cG, _def_cB ) (((sal_uLong)(_def_cR)<<10UL)|((sal_uLong)(_def_cG)<<5UL)|(sal_uLong)(_def_cB))
38 #define GAMMA( _def_cVal, _def_InvGamma ) ((sal_uInt8)MinMax(FRound(pow( _def_cVal/255.0,_def_InvGamma)*255.0),0L,255L))
40 #define CALC_ERRORS \
41 nTemp = p1T[nX++] >> 12; \
42 nBErr = MinMax( nTemp, 0, 255 ); \
43 nBErr = nBErr - FloydIndexMap[ nBC = FloydMap[nBErr] ]; \
44 nTemp = p1T[nX++] >> 12; \
45 nGErr = MinMax( nTemp, 0, 255 ); \
46 nGErr = nGErr - FloydIndexMap[ nGC = FloydMap[nGErr] ]; \
47 nTemp = p1T[nX] >> 12; \
48 nRErr = MinMax( nTemp, 0, 255 ); \
49 nRErr = nRErr - FloydIndexMap[ nRC = FloydMap[nRErr] ];
51 #define CALC_TABLES3 \
52 p2T[nX++] += FloydError3[nBErr]; \
53 p2T[nX++] += FloydError3[nGErr]; \
54 p2T[nX++] += FloydError3[nRErr];
56 #define CALC_TABLES5 \
57 p2T[nX++] += FloydError5[nBErr]; \
58 p2T[nX++] += FloydError5[nGErr]; \
59 p2T[nX++] += FloydError5[nRErr];
61 #define CALC_TABLES7 \
62 p1T[++nX] += FloydError7[nBErr]; \
63 p2T[nX++] += FloydError1[nBErr]; \
64 p1T[nX] += FloydError7[nGErr]; \
65 p2T[nX++] += FloydError1[nGErr]; \
66 p1T[nX] += FloydError7[nRErr]; \
67 p2T[nX] += FloydError1[nRErr];
69 const extern sal_uLong nVCLRLut[ 6 ] = { 16, 17, 18, 19, 20, 21 };
70 const extern sal_uLong nVCLGLut[ 6 ] = { 0, 6, 12, 18, 24, 30 };
71 const extern sal_uLong nVCLBLut[ 6 ] = { 0, 36, 72, 108, 144, 180 };
73 const extern sal_uLong nVCLDitherLut[ 256 ] =
75 0, 49152, 12288, 61440, 3072, 52224, 15360, 64512, 768, 49920, 13056,
76 62208, 3840, 52992, 16128, 65280, 32768, 16384, 45056, 28672, 35840, 19456,
77 48128, 31744, 33536, 17152, 45824, 29440, 36608, 20224, 48896, 32512, 8192,
78 57344, 4096, 53248, 11264, 60416, 7168, 56320, 8960, 58112, 4864, 54016,
79 12032, 61184, 7936, 57088, 40960, 24576, 36864, 20480, 44032, 27648, 39936,
80 23552, 41728, 25344, 37632, 21248, 44800, 28416, 40704, 24320, 2048, 51200,
81 14336, 63488, 1024, 50176, 13312, 62464, 2816, 51968, 15104, 64256, 1792,
82 50944, 14080, 63232, 34816, 18432, 47104, 30720, 33792, 17408, 46080, 29696,
83 35584, 19200, 47872, 31488, 34560, 18176, 46848, 30464, 10240, 59392, 6144,
84 55296, 9216, 58368, 5120, 54272, 11008, 60160, 6912, 56064, 9984, 59136,
85 5888, 55040, 43008, 26624, 38912, 22528, 41984, 25600, 37888, 21504, 43776,
86 27392, 39680, 23296, 42752, 26368, 38656, 22272, 512, 49664, 12800, 61952,
87 3584, 52736, 15872, 65024, 256, 49408, 12544, 61696, 3328, 52480, 15616,
88 64768, 33280, 16896, 45568, 29184, 36352, 19968, 48640, 32256, 33024, 16640,
89 45312, 28928, 36096, 19712, 48384, 32000, 8704, 57856, 4608, 53760, 11776,
90 60928, 7680, 56832, 8448, 57600, 4352, 53504, 11520, 60672, 7424, 56576,
91 41472, 25088, 37376, 20992, 44544, 28160, 40448, 24064, 41216, 24832, 37120,
92 20736, 44288, 27904, 40192, 23808, 2560, 51712, 14848, 64000, 1536, 50688,
93 13824, 62976, 2304, 51456, 14592, 63744, 1280, 50432, 13568, 62720, 35328,
94 18944, 47616, 31232, 34304, 17920, 46592, 30208, 35072, 18688, 47360, 30976,
95 34048, 17664, 46336, 29952, 10752, 59904, 6656, 55808, 9728, 58880, 5632,
96 54784, 10496, 59648, 6400, 55552, 9472, 58624, 5376, 54528, 43520, 27136,
97 39424, 23040, 42496, 26112, 38400, 22016, 43264, 26880, 39168, 22784, 42240,
98 25856, 38144, 21760
101 const extern sal_uLong nVCLLut[ 256 ] =
103 0, 1286, 2572, 3858, 5144, 6430, 7716, 9002,
104 10288, 11574, 12860, 14146, 15432, 16718, 18004, 19290,
105 20576, 21862, 23148, 24434, 25720, 27006, 28292, 29578,
106 30864, 32150, 33436, 34722, 36008, 37294, 38580, 39866,
107 41152, 42438, 43724, 45010, 46296, 47582, 48868, 50154,
108 51440, 52726, 54012, 55298, 56584, 57870, 59156, 60442,
109 61728, 63014, 64300, 65586, 66872, 68158, 69444, 70730,
110 72016, 73302, 74588, 75874, 77160, 78446, 79732, 81018,
111 82304, 83590, 84876, 86162, 87448, 88734, 90020, 91306,
112 92592, 93878, 95164, 96450, 97736, 99022,100308,101594,
113 102880,104166,105452,106738,108024,109310,110596,111882,
114 113168,114454,115740,117026,118312,119598,120884,122170,
115 123456,124742,126028,127314,128600,129886,131172,132458,
116 133744,135030,136316,137602,138888,140174,141460,142746,
117 144032,145318,146604,147890,149176,150462,151748,153034,
118 154320,155606,156892,158178,159464,160750,162036,163322,
119 164608,165894,167180,168466,169752,171038,172324,173610,
120 174896,176182,177468,178754,180040,181326,182612,183898,
121 185184,186470,187756,189042,190328,191614,192900,194186,
122 195472,196758,198044,199330,200616,201902,203188,204474,
123 205760,207046,208332,209618,210904,212190,213476,214762,
124 216048,217334,218620,219906,221192,222478,223764,225050,
125 226336,227622,228908,230194,231480,232766,234052,235338,
126 236624,237910,239196,240482,241768,243054,244340,245626,
127 246912,248198,249484,250770,252056,253342,254628,255914,
128 257200,258486,259772,261058,262344,263630,264916,266202,
129 267488,268774,270060,271346,272632,273918,275204,276490,
130 277776,279062,280348,281634,282920,284206,285492,286778,
131 288064,289350,290636,291922,293208,294494,295780,297066,
132 298352,299638,300924,302210,303496,304782,306068,307354,
133 308640,309926,311212,312498,313784,315070,316356,317642,
134 318928,320214,321500,322786,324072,325358,326644,327930
137 const long FloydMap[256] =
139 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
140 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1,
141 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
142 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
143 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2,
144 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
145 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
146 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
147 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
148 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
149 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
150 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
151 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
152 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
153 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
154 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
157 const long FloydError1[61] =
159 -7680, -7424, -7168, -6912, -6656, -6400, -6144,
160 -5888, -5632, -5376, -5120, -4864, -4608, -4352,
161 -4096, -3840, -3584, -3328, -3072, -2816, -2560,
162 -2304, -2048, -1792, -1536, -1280, -1024, -768,
163 -512, -256, 0, 256, 512, 768, 1024, 1280, 1536,
164 1792, 2048, 2304, 2560, 2816, 3072, 3328, 3584,
165 3840, 4096, 4352, 4608, 4864, 5120, 5376, 5632,
166 5888, 6144, 6400, 6656, 6912, 7168, 7424, 7680
169 const long FloydError3[61] =
171 -23040, -22272, -21504, -20736, -19968, -19200,
172 -18432, -17664, -16896, -16128, -15360, -14592,
173 -13824, -13056, -12288, -11520, -10752, -9984,
174 -9216, -8448, -7680, -6912, -6144, -5376, -4608,
175 -3840, -3072, -2304, -1536, -768, 0, 768, 1536,
176 2304, 3072, 3840, 4608, 5376, 6144, 6912, 7680,
177 8448, 9216, 9984, 10752, 11520, 12288, 13056,
178 13824, 14592, 15360, 16128, 16896, 17664, 18432,
179 19200, 19968, 20736, 21504, 22272, 23040
182 const long FloydError5[61] =
184 -38400, -37120, -35840, -34560, -33280, -32000,
185 -30720, -29440, -28160, -26880, -25600, -24320,
186 -23040, -21760, -20480, -19200, -17920, -16640,
187 -15360, -14080, -12800, -11520, -10240, -8960,
188 -7680, -6400, -5120, -3840, -2560, -1280, 0,
189 1280, 2560, 3840, 5120, 6400, 7680, 8960, 10240,
190 11520, 12800, 14080, 15360, 16640, 17920, 19200,
191 20480, 21760, 23040, 24320, 25600, 26880, 28160,
192 29440, 30720, 32000, 33280, 34560, 35840, 37120,
193 38400
196 const long FloydError7[61] =
198 -53760, -51968, -50176, -48384, -46592, -44800,
199 -43008, -41216, -39424, -37632, -35840, -34048,
200 -32256, -30464, -28672, -26880, -25088, -23296,
201 -21504, -19712, -17920, -16128, -14336, -12544,
202 -10752, -8960, -7168, -5376, -3584, -1792, 0,
203 1792, 3584, 5376, 7168, 8960, 10752, 12544, 14336,
204 16128, 17920, 19712, 21504, 23296, 25088, 26880,
205 28672, 30464, 32256, 34048, 35840, 37632, 39424,
206 41216, 43008, 44800, 46592, 48384, 50176, 51968,
207 53760
210 const long FloydIndexMap[6] =
212 -30, 21, 72, 123, 174, 225
215 void ImplCreateDitherMatrix( sal_uInt8 (*pDitherMatrix)[16][16] )
217 const double fVal = 3.125;
218 const double fVal16 = fVal / 16.;
219 const double fValScale = 254.;
220 sal_uInt16 pMtx[ 16 ][ 16 ];
221 sal_uInt16 nMax = 0;
222 static const sal_uInt8 pMagic[4][4] = { { 0, 14, 3, 13, },
223 {11, 5, 8, 6, },
224 {12, 2, 15, 1, },
225 {7, 9, 4, 10 } };
227 // Build MagicSquare
228 for ( long i = 0; i < 4; i++ )
229 for ( long j = 0; j < 4; j++ )
230 for ( long k = 0; k < 4; k++ )
231 for ( long l = 0; l < 4; l++ )
233 pMtx[ (k<<2) + i][(l<<2 ) + j ] = (sal_uInt16) ( 0.5 + pMagic[i][j]*fVal + pMagic[k][l]*fVal16 );
234 nMax = std::max ( pMtx[ (k<<2) + i][(l<<2 ) + j], nMax );
237 // Scale to interval [0;254]
238 double tmp = fValScale / nMax;
239 for ( long i = 0; i < 16; i++ )
240 for( long j = 0; j < 16; j++ )
241 (*pDitherMatrix)[i][j] = (sal_uInt8) ( tmp * pMtx[i][j] );
244 bool Bitmap::Convert( BmpConversion eConversion )
246 const sal_uInt16 nBitCount = GetBitCount ();
247 bool bRet = false;
249 switch( eConversion )
251 case( BMP_CONVERSION_1BIT_THRESHOLD ):
252 bRet = ImplMakeMono( 128 );
253 break;
255 case( BMP_CONVERSION_1BIT_MATRIX ):
256 bRet = ImplMakeMonoDither();
257 break;
259 case( BMP_CONVERSION_4BIT_GREYS ):
260 bRet = ImplMakeGreyscales( 16 );
261 break;
263 case( BMP_CONVERSION_4BIT_COLORS ):
265 if( nBitCount < 4 )
266 bRet = ImplConvertUp( 4, NULL );
267 else if( nBitCount > 4 )
268 bRet = ImplConvertDown( 4, NULL );
269 else
270 bRet = true;
272 break;
274 case( BMP_CONVERSION_4BIT_TRANS ):
276 Color aTrans( BMP_COL_TRANS );
278 if( nBitCount < 4 )
279 bRet = ImplConvertUp( 4, &aTrans );
280 else
281 bRet = ImplConvertDown( 4, &aTrans );
283 break;
285 case( BMP_CONVERSION_8BIT_GREYS ):
286 bRet = ImplMakeGreyscales( 256 );
287 break;
289 case( BMP_CONVERSION_8BIT_COLORS ):
291 if( nBitCount < 8 )
292 bRet = ImplConvertUp( 8 );
293 else if( nBitCount > 8 )
294 bRet = ImplConvertDown( 8 );
295 else
296 bRet = true;
298 break;
300 case( BMP_CONVERSION_8BIT_TRANS ):
302 Color aTrans( BMP_COL_TRANS );
304 if( nBitCount < 8 )
305 bRet = ImplConvertUp( 8, &aTrans );
306 else
307 bRet = ImplConvertDown( 8, &aTrans );
309 break;
311 case( BMP_CONVERSION_24BIT ):
313 if( nBitCount < 24 )
314 bRet = ImplConvertUp( 24, NULL );
315 else
316 bRet = true;
318 break;
320 case( BMP_CONVERSION_GHOSTED ):
321 bRet = ImplConvertGhosted();
322 break;
324 default:
325 OSL_FAIL( "Bitmap::Convert(): Unsupported conversion" );
326 break;
329 return bRet;
332 bool Bitmap::ImplMakeMono( sal_uInt8 cThreshold )
334 BitmapReadAccess* pReadAcc = AcquireReadAccess();
335 bool bRet = false;
337 if( pReadAcc )
339 Bitmap aNewBmp( GetSizePixel(), 1 );
340 BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess();
342 if( pWriteAcc )
344 const BitmapColor aBlack( pWriteAcc->GetBestMatchingColor( Color( COL_BLACK ) ) );
345 const BitmapColor aWhite( pWriteAcc->GetBestMatchingColor( Color( COL_WHITE ) ) );
346 const long nWidth = pWriteAcc->Width();
347 const long nHeight = pWriteAcc->Height();
349 if( pReadAcc->HasPalette() )
351 for( long nY = 0L; nY < nHeight; nY++ )
353 for( long nX = 0L; nX < nWidth; nX++ )
355 const sal_uInt8 cIndex = pReadAcc->GetPixelIndex( nY, nX );
356 if( pReadAcc->GetPaletteColor( cIndex ).GetLuminance() >=
357 cThreshold )
359 pWriteAcc->SetPixel( nY, nX, aWhite );
361 else
362 pWriteAcc->SetPixel( nY, nX, aBlack );
366 else
368 for( long nY = 0L; nY < nHeight; nY++ )
370 for( long nX = 0L; nX < nWidth; nX++ )
372 if( pReadAcc->GetPixel( nY, nX ).GetLuminance() >=
373 cThreshold )
375 pWriteAcc->SetPixel( nY, nX, aWhite );
377 else
378 pWriteAcc->SetPixel( nY, nX, aBlack );
383 ReleaseAccess( pWriteAcc );
384 bRet = true;
387 ReleaseAccess( pReadAcc );
389 if( bRet )
391 const MapMode aMap( maPrefMapMode );
392 const Size aSize( maPrefSize );
394 *this = aNewBmp;
396 maPrefMapMode = aMap;
397 maPrefSize = aSize;
401 return bRet;
404 bool Bitmap::ImplMakeMonoDither()
406 BitmapReadAccess* pReadAcc = AcquireReadAccess();
407 bool bRet = false;
409 if( pReadAcc )
411 Bitmap aNewBmp( GetSizePixel(), 1 );
412 BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess();
414 if( pWriteAcc )
416 const BitmapColor aBlack( pWriteAcc->GetBestMatchingColor( Color( COL_BLACK ) ) );
417 const BitmapColor aWhite( pWriteAcc->GetBestMatchingColor( Color( COL_WHITE ) ) );
418 const long nWidth = pWriteAcc->Width();
419 const long nHeight = pWriteAcc->Height();
420 sal_uInt8 pDitherMatrix[ 16 ][ 16 ];
422 ImplCreateDitherMatrix( &pDitherMatrix );
424 if( pReadAcc->HasPalette() )
426 for( long nY = 0L; nY < nHeight; nY++ )
428 for( long nX = 0L, nModY = nY % 16; nX < nWidth; nX++ )
430 const sal_uInt8 cIndex = pReadAcc->GetPixelIndex( nY, nX );
431 if( pReadAcc->GetPaletteColor( cIndex ).GetLuminance() >
432 pDitherMatrix[ nModY ][ nX % 16 ] )
434 pWriteAcc->SetPixel( nY, nX, aWhite );
436 else
437 pWriteAcc->SetPixel( nY, nX, aBlack );
441 else
443 for( long nY = 0L; nY < nHeight; nY++ )
445 for( long nX = 0L, nModY = nY % 16; nX < nWidth; nX++ )
447 if( pReadAcc->GetPixel( nY, nX ).GetLuminance() >
448 pDitherMatrix[ nModY ][ nX % 16 ] )
450 pWriteAcc->SetPixel( nY, nX, aWhite );
452 else
453 pWriteAcc->SetPixel( nY, nX, aBlack );
458 ReleaseAccess( pWriteAcc );
459 bRet = true;
462 ReleaseAccess( pReadAcc );
464 if( bRet )
466 const MapMode aMap( maPrefMapMode );
467 const Size aSize( maPrefSize );
469 *this = aNewBmp;
471 maPrefMapMode = aMap;
472 maPrefSize = aSize;
476 return bRet;
479 bool Bitmap::ImplMakeGreyscales( sal_uInt16 nGreys )
481 DBG_ASSERT( nGreys == 16 || nGreys == 256, "Only 16 or 256 greyscales are supported!" );
483 BitmapReadAccess* pReadAcc = AcquireReadAccess();
484 bool bRet = false;
486 if( pReadAcc )
488 const BitmapPalette& rPal = GetGreyPalette( nGreys );
489 sal_uLong nShift = ( ( nGreys == 16 ) ? 4UL : 0UL );
490 bool bPalDiffers = !pReadAcc->HasPalette() || ( rPal.GetEntryCount() != pReadAcc->GetPaletteEntryCount() );
492 if( !bPalDiffers )
493 bPalDiffers = ( (BitmapPalette&) rPal != pReadAcc->GetPalette() );
495 if( bPalDiffers )
497 Bitmap aNewBmp( GetSizePixel(), ( nGreys == 16 ) ? 4 : 8, &rPal );
498 BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess();
500 if( pWriteAcc )
502 const long nWidth = pWriteAcc->Width();
503 const long nHeight = pWriteAcc->Height();
505 if( pReadAcc->HasPalette() )
507 for( long nY = 0L; nY < nHeight; nY++ )
509 for( long nX = 0L; nX < nWidth; nX++ )
511 const sal_uInt8 cIndex = pReadAcc->GetPixelIndex( nY, nX );
512 pWriteAcc->SetPixelIndex( nY, nX,
513 (pReadAcc->GetPaletteColor( cIndex ).GetLuminance() >> nShift) );
517 else if( pReadAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_BGR &&
518 pWriteAcc->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL )
520 nShift += 8;
522 for( long nY = 0L; nY < nHeight; nY++ )
524 Scanline pReadScan = pReadAcc->GetScanline( nY );
525 Scanline pWriteScan = pWriteAcc->GetScanline( nY );
527 for( long nX = 0L; nX < nWidth; nX++ )
529 const sal_uLong nB = *pReadScan++;
530 const sal_uLong nG = *pReadScan++;
531 const sal_uLong nR = *pReadScan++;
533 *pWriteScan++ = (sal_uInt8) ( ( nB * 28UL + nG * 151UL + nR * 77UL ) >> nShift );
537 else if( pReadAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_RGB &&
538 pWriteAcc->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL )
540 nShift += 8;
542 for( long nY = 0L; nY < nHeight; nY++ )
544 Scanline pReadScan = pReadAcc->GetScanline( nY );
545 Scanline pWriteScan = pWriteAcc->GetScanline( nY );
547 for( long nX = 0L; nX < nWidth; nX++ )
549 const sal_uLong nR = *pReadScan++;
550 const sal_uLong nG = *pReadScan++;
551 const sal_uLong nB = *pReadScan++;
553 *pWriteScan++ = (sal_uInt8) ( ( nB * 28UL + nG * 151UL + nR * 77UL ) >> nShift );
557 else
559 for( long nY = 0L; nY < nHeight; nY++ )
560 for( long nX = 0L; nX < nWidth; nX++ )
561 pWriteAcc->SetPixelIndex( nY, nX, (pReadAcc->GetPixel( nY, nX ) ).GetLuminance() >> nShift );
564 ReleaseAccess( pWriteAcc );
565 bRet = true;
568 ReleaseAccess( pReadAcc );
570 if( bRet )
572 const MapMode aMap( maPrefMapMode );
573 const Size aSize( maPrefSize );
575 *this = aNewBmp;
577 maPrefMapMode = aMap;
578 maPrefSize = aSize;
581 else
583 ReleaseAccess( pReadAcc );
584 bRet = true;
588 return bRet;
591 bool Bitmap::ImplConvertUp(sal_uInt16 nBitCount, Color* pExtColor)
593 DBG_ASSERT( nBitCount > GetBitCount(), "New BitCount must be greater!" );
595 Bitmap::ScopedReadAccess pReadAcc(*this);
596 bool bRet = false;
598 if (pReadAcc)
600 BitmapPalette aPalette;
601 Bitmap aNewBmp(GetSizePixel(), nBitCount, pReadAcc->HasPalette() ? &pReadAcc->GetPalette() : &aPalette);
602 Bitmap::ScopedWriteAccess pWriteAcc(aNewBmp);
604 if (pWriteAcc)
606 const long nWidth = pWriteAcc->Width();
607 const long nHeight = pWriteAcc->Height();
609 if (pWriteAcc->HasPalette())
611 const sal_uInt16 nOldCount = 1 << GetBitCount();
612 const BitmapPalette& rOldPalette = pReadAcc->GetPalette();
614 aPalette.SetEntryCount(1 << nBitCount);
616 for (sal_uInt16 i = 0; i < nOldCount; i++)
617 aPalette[i] = rOldPalette[i];
619 if (pExtColor)
620 aPalette[aPalette.GetEntryCount() - 1] = *pExtColor;
622 pWriteAcc->SetPalette(aPalette);
624 for (long nY = 0L; nY < nHeight; nY++)
626 for (long nX = 0L; nX < nWidth; nX++)
628 pWriteAcc->SetPixel(nY, nX, pReadAcc->GetPixel(nY, nX));
632 else
634 if (pReadAcc->HasPalette())
636 for (long nY = 0L; nY < nHeight; nY++)
638 for (long nX = 0L; nX < nWidth; nX++)
640 pWriteAcc->SetPixel(nY, nX, pReadAcc->GetPaletteColor(pReadAcc->GetPixelIndex(nY, nX)));
644 else
646 for (long nY = 0L; nY < nHeight; nY++)
648 for (long nX = 0L; nX < nWidth; nX++)
650 pWriteAcc->SetPixel(nY, nX, pReadAcc->GetPixel(nY, nX));
655 bRet = true;
658 if (bRet)
660 const MapMode aMap(maPrefMapMode);
661 const Size aSize(maPrefSize);
663 *this = aNewBmp;
665 maPrefMapMode = aMap;
666 maPrefSize = aSize;
670 return bRet;
673 bool Bitmap::ImplConvertDown(sal_uInt16 nBitCount, Color* pExtColor)
675 DBG_ASSERT(nBitCount <= GetBitCount(), "New BitCount must be lower ( or equal when pExtColor is set )!");
677 Bitmap::ScopedReadAccess pReadAcc(*this);
678 bool bRet = false;
680 if (pReadAcc)
682 BitmapPalette aPalette;
683 Bitmap aNewBmp(GetSizePixel(), nBitCount, &aPalette);
684 Bitmap::ScopedWriteAccess pWriteAcc(aNewBmp);
686 if (pWriteAcc)
688 const sal_uInt16 nCount = 1 << nBitCount;
689 const long nWidth = pWriteAcc->Width();
690 const long nWidth1 = nWidth - 1L;
691 const long nHeight = pWriteAcc->Height();
692 Octree aOctree(*pReadAcc, pExtColor ? (nCount - 1) : nCount);
693 aPalette = aOctree.GetPalette();
694 InverseColorMap aColorMap(aPalette);
695 BitmapColor aColor;
696 ImpErrorQuad aErrQuad;
697 std::vector<ImpErrorQuad> pErrQuad1(nWidth);
698 std::vector<ImpErrorQuad> pErrQuad2(nWidth);
699 ImpErrorQuad* pQLine1 = pErrQuad1.data();
700 ImpErrorQuad* pQLine2 = NULL;
701 long nYTmp = 0L;
702 sal_uInt8 cIndex;
703 bool bQ1 = true;
705 if (pExtColor)
707 aPalette.SetEntryCount(aPalette.GetEntryCount() + 1);
708 aPalette[aPalette.GetEntryCount() - 1] = *pExtColor;
711 // set Black/White always, if we have enough space
712 if (aPalette.GetEntryCount() < (nCount - 1))
714 aPalette.SetEntryCount(aPalette.GetEntryCount() + 2);
715 aPalette[aPalette.GetEntryCount() - 2] = Color(COL_BLACK);
716 aPalette[aPalette.GetEntryCount() - 1] = Color(COL_WHITE);
719 pWriteAcc->SetPalette(aPalette);
721 for (long nY = 0L; nY < std::min(nHeight, 2L); nY++, nYTmp++)
723 pQLine2 = !nY ? pErrQuad1.data() : pErrQuad2.data();
724 for (long nX = 0L; nX < nWidth; nX++)
726 if (pReadAcc->HasPalette())
727 pQLine2[nX] = pReadAcc->GetPaletteColor(pReadAcc->GetPixelIndex(nYTmp, nX));
728 else
729 pQLine2[nX] = pReadAcc->GetPixel(nYTmp, nX);
733 for (long nY = 0L; nY < nHeight; nY++, nYTmp++)
735 // first pixel in the line
736 cIndex = (sal_uInt8) aColorMap.GetBestPaletteIndex(pQLine1[0].ImplGetColor());
737 pWriteAcc->SetPixelIndex(nY, 0, cIndex);
739 long nX;
740 for (nX = 1L; nX < nWidth1; nX++)
742 aColor = pQLine1[nX].ImplGetColor();
743 cIndex = static_cast<sal_uInt8>(aColorMap.GetBestPaletteIndex(aColor));
744 aErrQuad = (ImpErrorQuad(aColor) -= pWriteAcc->GetPaletteColor(cIndex));
745 pQLine1[++nX].ImplAddColorError7(aErrQuad);
746 pQLine2[nX--].ImplAddColorError1(aErrQuad);
747 pQLine2[nX--].ImplAddColorError5(aErrQuad);
748 pQLine2[nX++].ImplAddColorError3(aErrQuad);
749 pWriteAcc->SetPixelIndex(nY, nX, cIndex);
752 // Last RowPixel
753 if (nX < nWidth)
755 cIndex = static_cast<sal_uInt8>(aColorMap.GetBestPaletteIndex(pQLine1[nWidth1].ImplGetColor()));
756 pWriteAcc->SetPixelIndex(nY, nX, cIndex);
759 // Refill/copy row buffer
760 pQLine1 = pQLine2;
761 pQLine2 = (bQ1 = !bQ1) ? pErrQuad2.data() : pErrQuad1.data();
763 if (nYTmp < nHeight)
765 for (nX = 0L; nX < nWidth; nX++)
767 if (pReadAcc->HasPalette())
768 pQLine2[nX] = pReadAcc->GetPaletteColor(pReadAcc->GetPixelIndex(nYTmp, nX));
769 else
770 pQLine2[nX] = pReadAcc->GetPixel(nYTmp, nX);
775 bRet = true;
778 if(bRet)
780 const MapMode aMap(maPrefMapMode);
781 const Size aSize(maPrefSize);
783 *this = aNewBmp;
785 maPrefMapMode = aMap;
786 maPrefSize = aSize;
790 return bRet;
793 bool Bitmap::ImplConvertGhosted()
795 Bitmap aNewBmp;
796 BitmapReadAccess* pR = AcquireReadAccess();
797 bool bRet = false;
799 if( pR )
801 if( pR->HasPalette() )
803 BitmapPalette aNewPal( pR->GetPaletteEntryCount() );
805 for( long i = 0, nCount = aNewPal.GetEntryCount(); i < nCount; i++ )
807 const BitmapColor& rOld = pR->GetPaletteColor( (sal_uInt16) i );
808 aNewPal[ (sal_uInt16) i ] = BitmapColor( ( rOld.GetRed() >> 1 ) | 0x80,
809 ( rOld.GetGreen() >> 1 ) | 0x80,
810 ( rOld.GetBlue() >> 1 ) | 0x80 );
813 aNewBmp = Bitmap( GetSizePixel(), GetBitCount(), &aNewPal );
814 BitmapWriteAccess* pW = aNewBmp.AcquireWriteAccess();
816 if( pW )
818 pW->CopyBuffer( *pR );
819 ReleaseAccess( pW );
820 bRet = true;
823 else
825 aNewBmp = Bitmap( GetSizePixel(), 24 );
827 BitmapWriteAccess* pW = aNewBmp.AcquireWriteAccess();
829 if( pW )
831 const long nWidth = pR->Width(), nHeight = pR->Height();
833 for( long nY = 0; nY < nHeight; nY++ )
835 for( long nX = 0; nX < nWidth; nX++ )
837 const BitmapColor aOld( pR->GetPixel( nY, nX ) );
838 pW->SetPixel( nY, nX, BitmapColor( ( aOld.GetRed() >> 1 ) | 0x80,
839 ( aOld.GetGreen() >> 1 ) | 0x80,
840 ( aOld.GetBlue() >> 1 ) | 0x80 ) );
845 ReleaseAccess( pW );
846 bRet = true;
850 ReleaseAccess( pR );
853 if( bRet )
855 const MapMode aMap( maPrefMapMode );
856 const Size aSize( maPrefSize );
858 *this = aNewBmp;
860 maPrefMapMode = aMap;
861 maPrefSize = aSize;
864 return bRet;
867 bool Bitmap::Scale( const double& rScaleX, const double& rScaleY, BmpScaleFlag nScaleFlag )
869 if(basegfx::fTools::equalZero(rScaleX) || basegfx::fTools::equalZero(rScaleY))
871 // no scale
872 return true;
875 if(basegfx::fTools::equal(rScaleX, 1.0) && basegfx::fTools::equal(rScaleY, 1.0))
877 // no scale
878 return true;
881 const sal_uInt16 nStartCount(GetBitCount());
883 if( mpImpBmp )
885 // implementation specific scaling
886 ImpBitmap* pImpBmp = new ImpBitmap;
888 if( pImpBmp->ImplCreate( *mpImpBmp ) && pImpBmp->ImplScale( rScaleX, rScaleY, nScaleFlag ) )
890 ImplSetImpBitmap( pImpBmp );
891 SAL_INFO( "vcl.opengl", "Ref count: " << mpImpBmp->ImplGetRefCount() );
892 maPrefMapMode = MapMode( MAP_PIXEL );
893 maPrefSize = pImpBmp->ImplGetSize();
894 return true;
896 else
898 delete pImpBmp;
902 //fdo#33455
904 //If we start with a 1 bit image, then after scaling it in any mode except
905 //BmpScaleFlag::Fast we have a 24bit image which is perfectly correct, but we
906 //are going to down-shift it to mono again and Bitmap::ImplMakeMono just
907 //has "Bitmap aNewBmp( GetSizePixel(), 1 );" to create a 1 bit bitmap which
908 //will default to black/white and the colors mapped to which ever is closer
909 //to black/white
911 //So the easiest thing to do to retain the colors of 1 bit bitmaps is to
912 //just use the fast scale rather than attempting to count unique colors in
913 //the other converters and pass all the info down through
914 //Bitmap::ImplMakeMono
915 if (nStartCount == 1 && nScaleFlag != BmpScaleFlag::NONE)
916 nScaleFlag = BmpScaleFlag::Fast;
918 bool bRetval(false);
920 switch(nScaleFlag)
922 case BmpScaleFlag::NONE :
924 bRetval = false;
925 break;
927 case BmpScaleFlag::Fast :
929 bRetval = ImplScaleFast( rScaleX, rScaleY );
930 break;
932 case BmpScaleFlag::Interpolate :
934 bRetval = ImplScaleInterpolate( rScaleX, rScaleY );
935 break;
937 case BmpScaleFlag::Super:
938 case BmpScaleFlag::Default:
940 if (GetSizePixel().Width() < 2 || GetSizePixel().Height() < 2)
942 // fallback to ImplScaleFast
943 bRetval = ImplScaleFast( rScaleX, rScaleY );
945 else
947 BitmapScaleSuper aScaleSuper(rScaleX, rScaleY);
948 bRetval = aScaleSuper.filter(*this);
950 break;
952 case BmpScaleFlag::Lanczos :
953 case BmpScaleFlag::BestQuality:
955 const Lanczos3Kernel kernel;
957 bRetval = ImplScaleConvolution( rScaleX, rScaleY, kernel );
958 break;
960 case BmpScaleFlag::BiCubic :
962 const BicubicKernel kernel;
964 bRetval = ImplScaleConvolution( rScaleX, rScaleY, kernel );
965 break;
967 case BmpScaleFlag::BiLinear :
969 const BilinearKernel kernel;
971 bRetval = ImplScaleConvolution( rScaleX, rScaleY, kernel );
972 break;
974 case BmpScaleFlag::Box :
976 const BoxKernel kernel;
978 bRetval = ImplScaleConvolution( rScaleX, rScaleY, kernel );
979 break;
983 OSL_ENSURE(!bRetval || nStartCount == GetBitCount(), "Bitmap::Scale has changed the ColorDepth, this should *not* happen (!)");
984 return bRetval;
987 bool Bitmap::Scale( const Size& rNewSize, BmpScaleFlag nScaleFlag )
989 const Size aSize( GetSizePixel() );
990 bool bRet;
992 if( aSize.Width() && aSize.Height() )
994 bRet = Scale( (double) rNewSize.Width() / aSize.Width(),
995 (double) rNewSize.Height() / aSize.Height(),
996 nScaleFlag );
998 else
999 bRet = true;
1001 return bRet;
1004 bool Bitmap::HasFastScale()
1006 return OpenGLHelper::isVCLOpenGLEnabled();
1009 void Bitmap::AdaptBitCount(Bitmap& rNew) const
1011 ImplAdaptBitCount(rNew);
1014 void Bitmap::ImplAdaptBitCount(Bitmap& rNew) const
1016 // aNew is the result of some operation; adapt it's BitCount to the original (this)
1017 if(GetBitCount() != rNew.GetBitCount())
1019 switch(GetBitCount())
1021 case 1:
1023 rNew.Convert(BMP_CONVERSION_1BIT_THRESHOLD);
1024 break;
1026 case 4:
1028 if(HasGreyPalette())
1030 rNew.Convert(BMP_CONVERSION_4BIT_GREYS);
1032 else
1034 rNew.Convert(BMP_CONVERSION_4BIT_COLORS);
1036 break;
1038 case 8:
1040 if(HasGreyPalette())
1042 rNew.Convert(BMP_CONVERSION_8BIT_GREYS);
1044 else
1046 rNew.Convert(BMP_CONVERSION_8BIT_COLORS);
1048 break;
1050 case 24:
1052 rNew.Convert(BMP_CONVERSION_24BIT);
1053 break;
1055 default:
1057 OSL_ENSURE(false, "BitDepth adaption failed (!)");
1058 break;
1064 bool Bitmap::ImplScaleFast( const double& rScaleX, const double& rScaleY )
1066 const Size aSizePix( GetSizePixel() );
1067 const long nNewWidth = FRound( aSizePix.Width() * rScaleX );
1068 const long nNewHeight = FRound( aSizePix.Height() * rScaleY );
1069 bool bRet = false;
1071 if( nNewWidth && nNewHeight )
1073 BitmapReadAccess* pReadAcc = AcquireReadAccess();
1075 if(pReadAcc)
1077 Bitmap aNewBmp( Size( nNewWidth, nNewHeight ), GetBitCount(), &pReadAcc->GetPalette() );
1078 BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess();
1080 if( pWriteAcc )
1082 const long nScanlineSize = pWriteAcc->GetScanlineSize();
1083 const long nNewWidth1 = nNewWidth - 1L;
1084 const long nNewHeight1 = nNewHeight - 1L;
1086 if( nNewWidth1 && nNewHeight1 )
1088 const double nWidth = pReadAcc->Width();
1089 const double nHeight = pReadAcc->Height();
1090 boost::scoped_array<long> pLutX(new long[ nNewWidth ]);
1091 boost::scoped_array<long> pLutY(new long[ nNewHeight ]);
1093 for( long nX = 0L; nX < nNewWidth; nX++ )
1094 pLutX[ nX ] = long(nX * nWidth / nNewWidth);
1096 for( long nY = 0L; nY < nNewHeight; nY++ )
1097 pLutY[ nY ] = long(nY * nHeight / nNewHeight);
1099 long nActY = 0L;
1100 while( nActY < nNewHeight )
1102 long nMapY = pLutY[ nActY ];
1104 for( long nX = 0L; nX < nNewWidth; nX++ )
1105 pWriteAcc->SetPixel( nActY, nX, pReadAcc->GetPixel( nMapY , pLutX[ nX ] ) );
1107 while( ( nActY < nNewHeight1 ) && ( pLutY[ nActY + 1 ] == nMapY ) )
1109 memcpy( pWriteAcc->GetScanline( nActY + 1L ),
1110 pWriteAcc->GetScanline( nActY ), nScanlineSize );
1111 nActY++;
1113 nActY++;
1116 bRet = true;
1117 ReleaseAccess( pWriteAcc );
1120 ReleaseAccess( pReadAcc );
1122 if( bRet )
1123 ImplAssignWithSize( aNewBmp );
1127 return bRet;
1130 bool Bitmap::ImplScaleInterpolate( const double& rScaleX, const double& rScaleY )
1132 const Size aSizePix( GetSizePixel() );
1133 const long nNewWidth = FRound( aSizePix.Width() * rScaleX );
1134 const long nNewHeight = FRound( aSizePix.Height() * rScaleY );
1135 bool bRet = false;
1137 if( ( nNewWidth > 1L ) && ( nNewHeight > 1L ) )
1139 BitmapReadAccess* pReadAcc = AcquireReadAccess();
1140 if( pReadAcc )
1142 long nWidth = pReadAcc->Width();
1143 long nHeight = pReadAcc->Height();
1144 Bitmap aNewBmp( Size( nNewWidth, nHeight ), 24 );
1145 BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess();
1147 if( pWriteAcc )
1149 const long nNewWidth1 = nNewWidth - 1L;
1150 const long nWidth1 = pReadAcc->Width() - 1L;
1151 const double fRevScaleX = (double) nWidth1 / nNewWidth1;
1153 boost::scoped_array<long> pLutInt(new long[ nNewWidth ]);
1154 boost::scoped_array<long> pLutFrac(new long[ nNewWidth ]);
1156 for( long nX = 0L, nTemp = nWidth - 2L; nX < nNewWidth; nX++ )
1158 double fTemp = nX * fRevScaleX;
1159 pLutInt[ nX ] = MinMax( (long) fTemp, 0, nTemp );
1160 fTemp -= pLutInt[ nX ];
1161 pLutFrac[ nX ] = (long) ( fTemp * 1024. );
1164 for( long nY = 0L; nY < nHeight; nY++ )
1166 if( 1 == nWidth )
1168 BitmapColor aCol0;
1169 if( pReadAcc->HasPalette() )
1171 aCol0 = pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nY, 0 ) );
1173 else
1175 aCol0 = pReadAcc->GetPixel( nY, 0 );
1178 for( long nX = 0L; nX < nNewWidth; nX++ )
1180 pWriteAcc->SetPixel( nY, nX, aCol0 );
1183 else
1185 for( long nX = 0L; nX < nNewWidth; nX++ )
1187 long nTemp = pLutInt[ nX ];
1189 BitmapColor aCol0, aCol1;
1190 if( pReadAcc->HasPalette() )
1192 aCol0 = pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nY, nTemp++ ) );
1193 aCol1 = pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nY, nTemp ) );
1195 else
1197 aCol0 = pReadAcc->GetPixel( nY, nTemp++ );
1198 aCol1 = pReadAcc->GetPixel( nY, nTemp );
1201 nTemp = pLutFrac[ nX ];
1203 long lXR0 = aCol0.GetRed();
1204 long lXG0 = aCol0.GetGreen();
1205 long lXB0 = aCol0.GetBlue();
1206 long lXR1 = aCol1.GetRed() - lXR0;
1207 long lXG1 = aCol1.GetGreen() - lXG0;
1208 long lXB1 = aCol1.GetBlue() - lXB0;
1210 aCol0.SetRed( (sal_uInt8) ( ( lXR1 * nTemp + ( lXR0 << 10 ) ) >> 10 ) );
1211 aCol0.SetGreen( (sal_uInt8) ( ( lXG1 * nTemp + ( lXG0 << 10 ) ) >> 10 ) );
1212 aCol0.SetBlue( (sal_uInt8) ( ( lXB1 * nTemp + ( lXB0 << 10 ) ) >> 10 ) );
1214 pWriteAcc->SetPixel( nY, nX, aCol0 );
1219 bRet = true;
1222 ReleaseAccess( pReadAcc );
1223 ReleaseAccess( pWriteAcc );
1225 if( bRet )
1227 bRet = false;
1228 const Bitmap aOriginal(*this);
1229 *this = aNewBmp;
1230 aNewBmp = Bitmap( Size( nNewWidth, nNewHeight ), 24 );
1231 pReadAcc = AcquireReadAccess();
1232 pWriteAcc = aNewBmp.AcquireWriteAccess();
1234 if( pReadAcc && pWriteAcc )
1236 const long nNewHeight1 = nNewHeight - 1L;
1237 const long nHeight1 = pReadAcc->Height() - 1L;
1238 const double fRevScaleY = (double) nHeight1 / nNewHeight1;
1240 boost::scoped_array<long> pLutInt(new long[ nNewHeight ]);
1241 boost::scoped_array<long> pLutFrac(new long[ nNewHeight ]);
1243 for( long nY = 0L, nTemp = nHeight - 2L; nY < nNewHeight; nY++ )
1245 double fTemp = nY * fRevScaleY;
1246 pLutInt[ nY ] = MinMax( (long) fTemp, 0, nTemp );
1247 fTemp -= pLutInt[ nY ];
1248 pLutFrac[ nY ] = (long) ( fTemp * 1024. );
1251 // after 1st step, bitmap *is* 24bit format (see above)
1252 OSL_ENSURE(!pReadAcc->HasPalette(), "OOps, somehow ImplScaleInterpolate in-between format has palette, should not happen (!)");
1254 for( long nX = 0L; nX < nNewWidth; nX++ )
1256 if( 1 == nHeight )
1258 BitmapColor aCol0 = pReadAcc->GetPixel( 0, nX );
1260 for( long nY = 0L; nY < nNewHeight; nY++ )
1262 pWriteAcc->SetPixel( nY, nX, aCol0 );
1265 else
1267 for( long nY = 0L; nY < nNewHeight; nY++ )
1269 long nTemp = pLutInt[ nY ];
1271 BitmapColor aCol0 = pReadAcc->GetPixel( nTemp++, nX );
1272 BitmapColor aCol1 = pReadAcc->GetPixel( nTemp, nX );
1274 nTemp = pLutFrac[ nY ];
1276 long lXR0 = aCol0.GetRed();
1277 long lXG0 = aCol0.GetGreen();
1278 long lXB0 = aCol0.GetBlue();
1279 long lXR1 = aCol1.GetRed() - lXR0;
1280 long lXG1 = aCol1.GetGreen() - lXG0;
1281 long lXB1 = aCol1.GetBlue() - lXB0;
1283 aCol0.SetRed( (sal_uInt8) ( ( lXR1 * nTemp + ( lXR0 << 10 ) ) >> 10 ) );
1284 aCol0.SetGreen( (sal_uInt8) ( ( lXG1 * nTemp + ( lXG0 << 10 ) ) >> 10 ) );
1285 aCol0.SetBlue( (sal_uInt8) ( ( lXB1 * nTemp + ( lXB0 << 10 ) ) >> 10 ) );
1287 pWriteAcc->SetPixel( nY, nX, aCol0 );
1292 bRet = true;
1295 ReleaseAccess( pReadAcc );
1296 ReleaseAccess( pWriteAcc );
1298 if( bRet )
1300 aOriginal.ImplAdaptBitCount(aNewBmp);
1301 *this = aNewBmp;
1307 if( !bRet )
1309 bRet = ImplScaleFast( rScaleX, rScaleY );
1312 return bRet;
1315 namespace
1317 void ImplCalculateContributions(
1318 const sal_uInt32 aSourceSize,
1319 const sal_uInt32 aDestinationSize,
1320 sal_uInt32& aNumberOfContributions,
1321 double*& pWeights,
1322 sal_uInt32*& pPixels,
1323 sal_uInt32*& pCount,
1324 const Kernel& aKernel)
1326 const double fSamplingRadius(aKernel.GetWidth());
1327 const double fScale(aDestinationSize / static_cast< double >(aSourceSize));
1328 const double fScaledRadius((fScale < 1.0) ? fSamplingRadius / fScale : fSamplingRadius);
1329 const double fFilterFactor((fScale < 1.0) ? fScale : 1.0);
1331 aNumberOfContributions = (static_cast< sal_uInt32 >(fabs(ceil(fScaledRadius))) * 2) + 1;
1332 const sal_uInt32 nAllocSize(aDestinationSize * aNumberOfContributions);
1333 pWeights = new double[nAllocSize];
1334 pPixels = new sal_uInt32[nAllocSize];
1335 pCount = new sal_uInt32[aDestinationSize];
1337 for(sal_uInt32 i(0); i < aDestinationSize; i++)
1339 const sal_uInt32 aIndex(i * aNumberOfContributions);
1340 const double aCenter(i / fScale);
1341 const sal_Int32 aLeft(static_cast< sal_Int32 >(floor(aCenter - fScaledRadius)));
1342 const sal_Int32 aRight(static_cast< sal_Int32 >(ceil(aCenter + fScaledRadius)));
1343 sal_uInt32 aCurrentCount(0);
1345 for(sal_Int32 j(aLeft); j <= aRight; j++)
1347 const double aWeight(aKernel.Calculate(fFilterFactor * (aCenter - static_cast< double>(j))));
1349 // Reduce calculations with ignoring weights of 0.0
1350 if(fabs(aWeight) < 0.0001)
1352 continue;
1355 // Handling on edges
1356 const sal_uInt32 aPixelIndex(MinMax(j, 0, aSourceSize - 1));
1357 const sal_uInt32 nIndex(aIndex + aCurrentCount);
1359 pWeights[nIndex] = aWeight;
1360 pPixels[nIndex] = aPixelIndex;
1362 aCurrentCount++;
1365 pCount[i] = aCurrentCount;
1369 bool ImplScaleConvolutionHor(
1370 Bitmap& rSource,
1371 Bitmap& rTarget,
1372 const double& rScaleX,
1373 const Kernel& aKernel)
1375 // Do horizontal filtering
1376 OSL_ENSURE(rScaleX > 0.0, "Error in scaling: Mirror given in non-mirror-capable method (!)");
1377 const sal_uInt32 nWidth(rSource.GetSizePixel().Width());
1378 const sal_uInt32 nNewWidth(FRound(nWidth * rScaleX));
1380 if(nWidth == nNewWidth)
1382 return true;
1385 BitmapReadAccess* pReadAcc = rSource.AcquireReadAccess();
1387 if(pReadAcc)
1389 double* pWeights = 0;
1390 sal_uInt32* pPixels = 0;
1391 sal_uInt32* pCount = 0;
1392 sal_uInt32 aNumberOfContributions(0);
1394 const sal_uInt32 nHeight(rSource.GetSizePixel().Height());
1395 ImplCalculateContributions(nWidth, nNewWidth, aNumberOfContributions, pWeights, pPixels, pCount, aKernel);
1396 rTarget = Bitmap(Size(nNewWidth, nHeight), 24);
1397 BitmapWriteAccess* pWriteAcc = rTarget.AcquireWriteAccess();
1398 bool bResult(0 != pWriteAcc);
1400 if(bResult)
1402 for(sal_uInt32 y(0); y < nHeight; y++)
1404 for(sal_uInt32 x(0); x < nNewWidth; x++)
1406 const sal_uInt32 aBaseIndex(x * aNumberOfContributions);
1407 double aSum(0.0);
1408 double aValueRed(0.0);
1409 double aValueGreen(0.0);
1410 double aValueBlue(0.0);
1412 for(sal_uInt32 j(0); j < pCount[x]; j++)
1414 const sal_uInt32 aIndex(aBaseIndex + j);
1415 const double aWeight(pWeights[aIndex]);
1416 BitmapColor aColor;
1418 aSum += aWeight;
1420 if(pReadAcc->HasPalette())
1422 aColor = pReadAcc->GetPaletteColor(pReadAcc->GetPixelIndex(y, pPixels[aIndex]));
1424 else
1426 aColor = pReadAcc->GetPixel(y, pPixels[aIndex]);
1429 aValueRed += aWeight * aColor.GetRed();
1430 aValueGreen += aWeight * aColor.GetGreen();
1431 aValueBlue += aWeight * aColor.GetBlue();
1434 const BitmapColor aResultColor(
1435 static_cast< sal_uInt8 >(MinMax(static_cast< sal_Int32 >(aValueRed / aSum), 0, 255)),
1436 static_cast< sal_uInt8 >(MinMax(static_cast< sal_Int32 >(aValueGreen / aSum), 0, 255)),
1437 static_cast< sal_uInt8 >(MinMax(static_cast< sal_Int32 >(aValueBlue / aSum), 0, 255)));
1439 pWriteAcc->SetPixel(y, x, aResultColor);
1443 Bitmap::ReleaseAccess(pWriteAcc);
1446 Bitmap::ReleaseAccess(pReadAcc);
1447 delete[] pWeights;
1448 delete[] pCount;
1449 delete[] pPixels;
1451 if(bResult)
1453 return true;
1457 return false;
1460 bool ImplScaleConvolutionVer(
1461 Bitmap& rSource,
1462 Bitmap& rTarget,
1463 const double& rScaleY,
1464 const Kernel& aKernel)
1466 // Do vertical filtering
1467 OSL_ENSURE(rScaleY > 0.0, "Error in scaling: Mirror given in non-mirror-capable method (!)");
1468 const sal_uInt32 nHeight(rSource.GetSizePixel().Height());
1469 const sal_uInt32 nNewHeight(FRound(nHeight * rScaleY));
1471 if(nHeight == nNewHeight)
1473 return true;
1476 BitmapReadAccess* pReadAcc = rSource.AcquireReadAccess();
1478 if(pReadAcc)
1480 double* pWeights = 0;
1481 sal_uInt32* pPixels = 0;
1482 sal_uInt32* pCount = 0;
1483 sal_uInt32 aNumberOfContributions(0);
1485 const sal_uInt32 nWidth(rSource.GetSizePixel().Width());
1486 ImplCalculateContributions(nHeight, nNewHeight, aNumberOfContributions, pWeights, pPixels, pCount, aKernel);
1487 rTarget = Bitmap(Size(nWidth, nNewHeight), 24);
1488 BitmapWriteAccess* pWriteAcc = rTarget.AcquireWriteAccess();
1489 bool bResult(0 != pWriteAcc);
1491 if(pWriteAcc)
1493 for(sal_uInt32 x(0); x < nWidth; x++)
1495 for(sal_uInt32 y(0); y < nNewHeight; y++)
1497 const sal_uInt32 aBaseIndex(y * aNumberOfContributions);
1498 double aSum(0.0);
1499 double aValueRed(0.0);
1500 double aValueGreen(0.0);
1501 double aValueBlue(0.0);
1503 for(sal_uInt32 j(0); j < pCount[y]; j++)
1505 const sal_uInt32 aIndex(aBaseIndex + j);
1506 const double aWeight(pWeights[aIndex]);
1507 BitmapColor aColor;
1509 aSum += aWeight;
1511 if(pReadAcc->HasPalette())
1513 aColor = pReadAcc->GetPaletteColor(pReadAcc->GetPixelIndex(pPixels[aIndex], x));
1515 else
1517 aColor = pReadAcc->GetPixel(pPixels[aIndex], x);
1520 aValueRed += aWeight * aColor.GetRed();
1521 aValueGreen += aWeight * aColor.GetGreen();
1522 aValueBlue += aWeight * aColor.GetBlue();
1525 const BitmapColor aResultColor(
1526 static_cast< sal_uInt8 >(MinMax(static_cast< sal_Int32 >(aValueRed / aSum), 0, 255)),
1527 static_cast< sal_uInt8 >(MinMax(static_cast< sal_Int32 >(aValueGreen / aSum), 0, 255)),
1528 static_cast< sal_uInt8 >(MinMax(static_cast< sal_Int32 >(aValueBlue / aSum), 0, 255)));
1530 if(pWriteAcc->HasPalette())
1532 pWriteAcc->SetPixelIndex(y, x, static_cast< sal_uInt8 >(pWriteAcc->GetBestPaletteIndex(aResultColor)));
1534 else
1536 pWriteAcc->SetPixel(y, x, aResultColor);
1542 Bitmap::ReleaseAccess(pWriteAcc);
1543 Bitmap::ReleaseAccess(pReadAcc);
1545 delete[] pWeights;
1546 delete[] pCount;
1547 delete[] pPixels;
1549 if(bResult)
1551 return true;
1555 return false;
1559 // #i121233# Added BmpScaleFlag::Lanczos, BmpScaleFlag::BiCubic, BmpScaleFlag::BiLinear and
1560 // BmpScaleFlag::Box derived from the original commit from Tomas Vajngerl (see
1561 // bugzilla task for deitails) Thanks!
1562 bool Bitmap::ImplScaleConvolution(
1563 const double& rScaleX,
1564 const double& rScaleY,
1565 const Kernel& aKernel)
1567 const bool bMirrorHor(rScaleX < 0.0);
1568 const bool bMirrorVer(rScaleY < 0.0);
1569 const double fScaleX(bMirrorHor ? -rScaleX : rScaleX);
1570 const double fScaleY(bMirrorVer ? -rScaleY : rScaleY);
1571 const sal_uInt32 nWidth(GetSizePixel().Width());
1572 const sal_uInt32 nHeight(GetSizePixel().Height());
1573 const sal_uInt32 nNewWidth(FRound(nWidth * fScaleX));
1574 const sal_uInt32 nNewHeight(FRound(nHeight * fScaleY));
1575 const bool bScaleHor(nWidth != nNewWidth);
1576 const bool bScaleVer(nHeight != nNewHeight);
1577 const bool bMirror(bMirrorHor || bMirrorVer);
1579 if(!bMirror && !bScaleHor && !bScaleVer)
1581 return true;
1584 bool bResult(true);
1585 BmpMirrorFlags nMirrorFlags(BmpMirrorFlags::NONE);
1586 bool bMirrorAfter(false);
1588 if(bMirror)
1590 if(bMirrorHor)
1592 nMirrorFlags |= BmpMirrorFlags::Horizontal;
1595 if(bMirrorVer)
1597 nMirrorFlags |= BmpMirrorFlags::Vertical;
1600 const sal_uInt32 nStartSize(nWidth * nHeight);
1601 const sal_uInt32 nEndSize(nNewWidth * nNewHeight);
1603 bMirrorAfter = nStartSize > nEndSize;
1605 if(!bMirrorAfter)
1607 bResult = Mirror(nMirrorFlags);
1611 Bitmap aResult;
1613 if(bResult)
1615 const sal_uInt32 nInBetweenSizeHorFirst(nHeight * nNewWidth);
1616 const sal_uInt32 nInBetweenSizeVerFirst(nNewHeight * nWidth);
1617 Bitmap aSource(*this);
1619 if(nInBetweenSizeHorFirst < nInBetweenSizeVerFirst)
1621 if(bScaleHor)
1623 bResult = ImplScaleConvolutionHor(aSource, aResult, fScaleX, aKernel);
1626 if(bResult && bScaleVer)
1628 if(bScaleHor)
1630 // copy partial result, independent of color depth
1631 aSource = aResult;
1634 bResult = ImplScaleConvolutionVer(aSource, aResult, fScaleY, aKernel);
1637 else
1639 if(bScaleVer)
1641 bResult = ImplScaleConvolutionVer(aSource, aResult, fScaleY, aKernel);
1644 if(bResult && bScaleHor)
1646 if(bScaleVer)
1648 // copy partial result, independent of color depth
1649 aSource = aResult;
1652 bResult = ImplScaleConvolutionHor(aSource, aResult, fScaleX, aKernel);
1657 if(bResult && bMirrorAfter)
1659 bResult = aResult.Mirror(nMirrorFlags);
1662 if(bResult)
1664 ImplAdaptBitCount(aResult);
1665 *this = aResult;
1668 return bResult;
1671 bool Bitmap::Dither( BmpDitherFlags nDitherFlags )
1673 bool bRet = false;
1675 const Size aSizePix( GetSizePixel() );
1677 if( aSizePix.Width() == 1 || aSizePix.Height() == 1 )
1678 bRet = true;
1679 else if( nDitherFlags & BmpDitherFlags::Matrix )
1680 bRet = ImplDitherMatrix();
1681 else if( nDitherFlags & BmpDitherFlags::Floyd )
1682 bRet = ImplDitherFloyd();
1683 else if( ( nDitherFlags & BmpDitherFlags::Floyd16 ) && ( GetBitCount() == 24 ) )
1684 bRet = ImplDitherFloyd16();
1686 return bRet;
1689 bool Bitmap::ImplDitherMatrix()
1691 BitmapReadAccess* pReadAcc = AcquireReadAccess();
1692 Bitmap aNewBmp( GetSizePixel(), 8 );
1693 BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess();
1694 bool bRet = false;
1696 if( pReadAcc && pWriteAcc )
1698 const sal_uLong nWidth = pReadAcc->Width();
1699 const sal_uLong nHeight = pReadAcc->Height();
1700 BitmapColor aIndex( (sal_uInt8) 0 );
1702 if( pReadAcc->HasPalette() )
1704 for( sal_uLong nY = 0UL; nY < nHeight; nY++ )
1706 for( sal_uLong nX = 0UL, nModY = ( nY & 0x0FUL ) << 4UL; nX < nWidth; nX++ )
1708 const BitmapColor aCol( pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nY, nX ) ) );
1709 const sal_uLong nD = nVCLDitherLut[ nModY + ( nX & 0x0FUL ) ];
1710 const sal_uLong nR = ( nVCLLut[ aCol.GetRed() ] + nD ) >> 16UL;
1711 const sal_uLong nG = ( nVCLLut[ aCol.GetGreen() ] + nD ) >> 16UL;
1712 const sal_uLong nB = ( nVCLLut[ aCol.GetBlue() ] + nD ) >> 16UL;
1714 aIndex.SetIndex( (sal_uInt8) ( nVCLRLut[ nR ] + nVCLGLut[ nG ] + nVCLBLut[ nB ] ) );
1715 pWriteAcc->SetPixel( nY, nX, aIndex );
1719 else
1721 for( sal_uLong nY = 0UL; nY < nHeight; nY++ )
1723 for( sal_uLong nX = 0UL, nModY = ( nY & 0x0FUL ) << 4UL; nX < nWidth; nX++ )
1725 const BitmapColor aCol( pReadAcc->GetPixel( nY, nX ) );
1726 const sal_uLong nD = nVCLDitherLut[ nModY + ( nX & 0x0FUL ) ];
1727 const sal_uLong nR = ( nVCLLut[ aCol.GetRed() ] + nD ) >> 16UL;
1728 const sal_uLong nG = ( nVCLLut[ aCol.GetGreen() ] + nD ) >> 16UL;
1729 const sal_uLong nB = ( nVCLLut[ aCol.GetBlue() ] + nD ) >> 16UL;
1731 aIndex.SetIndex( (sal_uInt8) ( nVCLRLut[ nR ] + nVCLGLut[ nG ] + nVCLBLut[ nB ] ) );
1732 pWriteAcc->SetPixel( nY, nX, aIndex );
1737 bRet = true;
1740 ReleaseAccess( pReadAcc );
1741 ReleaseAccess( pWriteAcc );
1743 if( bRet )
1745 const MapMode aMap( maPrefMapMode );
1746 const Size aSize( maPrefSize );
1748 *this = aNewBmp;
1750 maPrefMapMode = aMap;
1751 maPrefSize = aSize;
1754 return bRet;
1757 bool Bitmap::ImplDitherFloyd()
1759 const Size aSize( GetSizePixel() );
1760 bool bRet = false;
1762 if( ( aSize.Width() > 3 ) && ( aSize.Height() > 2 ) )
1764 BitmapReadAccess* pReadAcc = AcquireReadAccess();
1765 Bitmap aNewBmp( GetSizePixel(), 8 );
1766 BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess();
1768 if( pReadAcc && pWriteAcc )
1770 BitmapColor aColor;
1771 long nWidth = pReadAcc->Width();
1772 long nWidth1 = nWidth - 1L;
1773 long nHeight = pReadAcc->Height();
1774 long nX;
1775 long nW = nWidth * 3L;
1776 long nW2 = nW - 3L;
1777 long nRErr, nGErr, nBErr;
1778 long nRC, nGC, nBC;
1779 boost::scoped_array<long> p1(new long[ nW ]);
1780 boost::scoped_array<long> p2(new long[ nW ]);
1781 long* p1T = p1.get();
1782 long* p2T = p2.get();
1783 long* pTmp;
1784 bool bPal = pReadAcc->HasPalette();
1786 pTmp = p2T;
1788 if( bPal )
1790 for( long nZ = 0; nZ < nWidth; nZ++ )
1792 aColor = pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( 0, nZ ) );
1794 *pTmp++ = (long) aColor.GetBlue() << 12;
1795 *pTmp++ = (long) aColor.GetGreen() << 12;
1796 *pTmp++ = (long) aColor.GetRed() << 12;
1799 else
1801 for( long nZ = 0; nZ < nWidth; nZ++ )
1803 aColor = pReadAcc->GetPixel( 0, nZ );
1805 *pTmp++ = (long) aColor.GetBlue() << 12;
1806 *pTmp++ = (long) aColor.GetGreen() << 12;
1807 *pTmp++ = (long) aColor.GetRed() << 12;
1811 for( long nY = 1, nYAcc = 0L; nY <= nHeight; nY++, nYAcc++ )
1813 pTmp = p1T;
1814 p1T = p2T;
1815 p2T = pTmp;
1817 if( nY < nHeight )
1819 if( bPal )
1821 for( long nZ = 0; nZ < nWidth; nZ++ )
1823 aColor = pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nY, nZ ) );
1825 *pTmp++ = (long) aColor.GetBlue() << 12;
1826 *pTmp++ = (long) aColor.GetGreen() << 12;
1827 *pTmp++ = (long) aColor.GetRed() << 12;
1830 else
1832 for( long nZ = 0; nZ < nWidth; nZ++ )
1834 aColor = pReadAcc->GetPixel( nY, nZ );
1836 *pTmp++ = (long) aColor.GetBlue() << 12;
1837 *pTmp++ = (long) aColor.GetGreen() << 12;
1838 *pTmp++ = (long) aColor.GetRed() << 12;
1843 // Examine first Pixel separately
1844 nX = 0;
1845 long nTemp;
1846 CALC_ERRORS;
1847 CALC_TABLES7;
1848 nX -= 5;
1849 CALC_TABLES5;
1850 pWriteAcc->SetPixelIndex( nYAcc, 0, static_cast<sal_uInt8>(nVCLBLut[ nBC ] + nVCLGLut[nGC ] + nVCLRLut[nRC ]) );
1852 // Get middle Pixels using a loop
1853 long nXAcc;
1854 for ( nX = 3L, nXAcc = 1L; nX < nW2; nXAcc++ )
1856 CALC_ERRORS;
1857 CALC_TABLES7;
1858 nX -= 8;
1859 CALC_TABLES3;
1860 CALC_TABLES5;
1861 pWriteAcc->SetPixelIndex( nYAcc, nXAcc, static_cast<sal_uInt8>(nVCLBLut[ nBC ] + nVCLGLut[nGC ] + nVCLRLut[nRC ]) );
1864 // Treat last Pixel separately
1865 CALC_ERRORS;
1866 nX -= 5;
1867 CALC_TABLES3;
1868 CALC_TABLES5;
1869 pWriteAcc->SetPixelIndex( nYAcc, nWidth1, static_cast<sal_uInt8>(nVCLBLut[ nBC ] + nVCLGLut[nGC ] + nVCLRLut[nRC ]) );
1872 bRet = true;
1875 ReleaseAccess( pReadAcc );
1876 ReleaseAccess( pWriteAcc );
1878 if( bRet )
1880 const MapMode aMap( maPrefMapMode );
1881 const Size aPrefSize( maPrefSize );
1883 *this = aNewBmp;
1885 maPrefMapMode = aMap;
1886 maPrefSize = aPrefSize;
1890 return bRet;
1893 bool Bitmap::ImplDitherFloyd16()
1895 BitmapReadAccess* pReadAcc = AcquireReadAccess();
1896 Bitmap aNewBmp( GetSizePixel(), 24 );
1897 BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess();
1898 bool bRet = false;
1900 if( pReadAcc && pWriteAcc )
1902 const long nWidth = pWriteAcc->Width();
1903 const long nWidth1 = nWidth - 1L;
1904 const long nHeight = pWriteAcc->Height();
1905 BitmapColor aColor;
1906 BitmapColor aBestCol;
1907 ImpErrorQuad aErrQuad;
1908 boost::scoped_array<ImpErrorQuad> pErrQuad1(new ImpErrorQuad[ nWidth ]);
1909 boost::scoped_array<ImpErrorQuad> pErrQuad2(new ImpErrorQuad[ nWidth ]);
1910 ImpErrorQuad* pQLine1 = pErrQuad1.get();
1911 ImpErrorQuad* pQLine2 = 0;
1912 long nYTmp = 0L;
1913 bool bQ1 = true;
1915 for( long nY = 0L; nY < std::min( nHeight, 2L ); nY++, nYTmp++ )
1917 pQLine2 = !nY ? pErrQuad1.get() : pErrQuad2.get();
1918 for( long nX = 0L; nX < nWidth; nX++ )
1919 pQLine2[ nX ] = pReadAcc->GetPixel( nYTmp, nX );
1922 for( long nY = 0L; nY < nHeight; nY++, nYTmp++ )
1924 // First RowPixel
1925 aBestCol = pQLine1[ 0 ].ImplGetColor();
1926 aBestCol.SetRed( ( aBestCol.GetRed() & 248 ) | 7 );
1927 aBestCol.SetGreen( ( aBestCol.GetGreen() & 248 ) | 7 );
1928 aBestCol.SetBlue( ( aBestCol.GetBlue() & 248 ) | 7 );
1929 pWriteAcc->SetPixel( nY, 0, aBestCol );
1931 long nX;
1932 for( nX = 1L; nX < nWidth1; nX++ )
1934 aColor = pQLine1[ nX ].ImplGetColor();
1935 aBestCol.SetRed( ( aColor.GetRed() & 248 ) | 7 );
1936 aBestCol.SetGreen( ( aColor.GetGreen() & 248 ) | 7 );
1937 aBestCol.SetBlue( ( aColor.GetBlue() & 248 ) | 7 );
1938 aErrQuad = ( ImpErrorQuad( aColor ) -= aBestCol );
1939 pQLine1[ ++nX ].ImplAddColorError7( aErrQuad );
1940 pQLine2[ nX-- ].ImplAddColorError1( aErrQuad );
1941 pQLine2[ nX-- ].ImplAddColorError5( aErrQuad );
1942 pQLine2[ nX++ ].ImplAddColorError3( aErrQuad );
1943 pWriteAcc->SetPixel( nY, nX, aBestCol );
1946 // Last RowPixel
1947 aBestCol = pQLine1[ nWidth1 ].ImplGetColor();
1948 aBestCol.SetRed( ( aBestCol.GetRed() & 248 ) | 7 );
1949 aBestCol.SetGreen( ( aBestCol.GetGreen() & 248 ) | 7 );
1950 aBestCol.SetBlue( ( aBestCol.GetBlue() & 248 ) | 7 );
1951 pWriteAcc->SetPixel( nY, nX, aBestCol );
1953 // Refill/copy row buffer
1954 pQLine1 = pQLine2;
1955 pQLine2 = ( bQ1 = !bQ1 ) ? pErrQuad2.get() : pErrQuad1.get();
1957 if( nYTmp < nHeight )
1958 for( nX = 0L; nX < nWidth; nX++ )
1959 pQLine2[ nX ] = pReadAcc->GetPixel( nYTmp, nX );
1962 bRet = true;
1965 ReleaseAccess( pReadAcc );
1966 ReleaseAccess( pWriteAcc );
1968 if( bRet )
1970 const MapMode aMap( maPrefMapMode );
1971 const Size aSize( maPrefSize );
1973 *this = aNewBmp;
1975 maPrefMapMode = aMap;
1976 maPrefSize = aSize;
1979 return bRet;
1982 bool Bitmap::ReduceColors( sal_uInt16 nColorCount, BmpReduce eReduce )
1984 bool bRet;
1986 if( GetColorCount() <= (sal_uLong) nColorCount )
1987 bRet = true;
1988 else if( nColorCount )
1990 if( BMP_REDUCE_SIMPLE == eReduce )
1991 bRet = ImplReduceSimple( nColorCount );
1992 else if( BMP_REDUCE_POPULAR == eReduce )
1993 bRet = ImplReducePopular( nColorCount );
1994 else
1995 bRet = ImplReduceMedian( nColorCount );
1997 else
1998 bRet = false;
2000 return bRet;
2003 bool Bitmap::ImplReduceSimple( sal_uInt16 nColorCount )
2005 Bitmap aNewBmp;
2006 BitmapReadAccess* pRAcc = AcquireReadAccess();
2007 const sal_uInt16 nColCount = std::min( nColorCount, (sal_uInt16) 256 );
2008 sal_uInt16 nBitCount;
2009 bool bRet = false;
2011 if( nColCount <= 2 )
2012 nBitCount = 1;
2013 else if( nColCount <= 16 )
2014 nBitCount = 4;
2015 else
2016 nBitCount = 8;
2018 if( pRAcc )
2020 Octree aOct( *pRAcc, nColCount );
2021 const BitmapPalette& rPal = aOct.GetPalette();
2022 BitmapWriteAccess* pWAcc;
2024 aNewBmp = Bitmap( GetSizePixel(), nBitCount, &rPal );
2025 pWAcc = aNewBmp.AcquireWriteAccess();
2027 if( pWAcc )
2029 const long nWidth = pRAcc->Width();
2030 const long nHeight = pRAcc->Height();
2032 if( pRAcc->HasPalette() )
2034 for( long nY = 0L; nY < nHeight; nY++ )
2035 for( long nX =0L; nX < nWidth; nX++ )
2036 pWAcc->SetPixelIndex( nY, nX, static_cast<sal_uInt8>(aOct.GetBestPaletteIndex( pRAcc->GetPaletteColor( pRAcc->GetPixelIndex( nY, nX ) ))) );
2038 else
2040 for( long nY = 0L; nY < nHeight; nY++ )
2041 for( long nX =0L; nX < nWidth; nX++ )
2042 pWAcc->SetPixelIndex( nY, nX, static_cast<sal_uInt8>(aOct.GetBestPaletteIndex( pRAcc->GetPixel( nY, nX ) )) );
2045 ReleaseAccess( pWAcc );
2046 bRet = true;
2049 ReleaseAccess( pRAcc );
2052 if( bRet )
2054 const MapMode aMap( maPrefMapMode );
2055 const Size aSize( maPrefSize );
2057 *this = aNewBmp;
2058 maPrefMapMode = aMap;
2059 maPrefSize = aSize;
2062 return bRet;
2065 struct PopularColorCount
2067 sal_uInt32 mnIndex;
2068 sal_uInt32 mnCount;
2071 extern "C" int SAL_CALL ImplPopularCmpFnc( const void* p1, const void* p2 )
2073 int nRet;
2075 if( static_cast<PopularColorCount const *>(p1)->mnCount < static_cast<PopularColorCount const *>(p2)->mnCount )
2076 nRet = 1;
2077 else if( static_cast<PopularColorCount const *>(p1)->mnCount == static_cast<PopularColorCount const *>(p2)->mnCount )
2078 nRet = 0;
2079 else
2080 nRet = -1;
2082 return nRet;
2085 bool Bitmap::ImplReducePopular( sal_uInt16 nColCount )
2087 BitmapReadAccess* pRAcc = AcquireReadAccess();
2088 sal_uInt16 nBitCount;
2089 bool bRet = false;
2091 if( nColCount > 256 )
2092 nColCount = 256;
2094 if( nColCount < 17 )
2095 nBitCount = 4;
2096 else
2097 nBitCount = 8;
2099 if( pRAcc )
2101 const sal_uInt32 nValidBits = 4;
2102 const sal_uInt32 nRightShiftBits = 8 - nValidBits;
2103 const sal_uInt32 nLeftShiftBits1 = nValidBits;
2104 const sal_uInt32 nLeftShiftBits2 = nValidBits << 1;
2105 const sal_uInt32 nColorsPerComponent = 1 << nValidBits;
2106 const sal_uInt32 nColorOffset = 256 / nColorsPerComponent;
2107 const sal_uInt32 nTotalColors = nColorsPerComponent * nColorsPerComponent * nColorsPerComponent;
2108 const long nWidth = pRAcc->Width();
2109 const long nHeight = pRAcc->Height();
2110 boost::scoped_array<PopularColorCount> pCountTable(new PopularColorCount[ nTotalColors ]);
2112 memset( pCountTable.get(), 0, nTotalColors * sizeof( PopularColorCount ) );
2114 for( long nR = 0, nIndex = 0; nR < 256; nR += nColorOffset )
2116 for( long nG = 0; nG < 256; nG += nColorOffset )
2118 for( long nB = 0; nB < 256; nB += nColorOffset )
2120 pCountTable[ nIndex ].mnIndex = nIndex;
2121 nIndex++;
2126 if( pRAcc->HasPalette() )
2128 for( long nY = 0L; nY < nHeight; nY++ )
2130 for( long nX = 0L; nX < nWidth; nX++ )
2132 const BitmapColor& rCol = pRAcc->GetPaletteColor( pRAcc->GetPixelIndex( nY, nX ) );
2133 pCountTable[ ( ( ( (sal_uInt32) rCol.GetRed() ) >> nRightShiftBits ) << nLeftShiftBits2 ) |
2134 ( ( ( (sal_uInt32) rCol.GetGreen() ) >> nRightShiftBits ) << nLeftShiftBits1 ) |
2135 ( ( (sal_uInt32) rCol.GetBlue() ) >> nRightShiftBits ) ].mnCount++;
2139 else
2141 for( long nY = 0L; nY < nHeight; nY++ )
2143 for( long nX = 0L; nX < nWidth; nX++ )
2145 const BitmapColor aCol( pRAcc->GetPixel( nY, nX ) );
2146 pCountTable[ ( ( ( (sal_uInt32) aCol.GetRed() ) >> nRightShiftBits ) << nLeftShiftBits2 ) |
2147 ( ( ( (sal_uInt32) aCol.GetGreen() ) >> nRightShiftBits ) << nLeftShiftBits1 ) |
2148 ( ( (sal_uInt32) aCol.GetBlue() ) >> nRightShiftBits ) ].mnCount++;
2153 BitmapPalette aNewPal( nColCount );
2155 qsort( pCountTable.get(), nTotalColors, sizeof( PopularColorCount ), ImplPopularCmpFnc );
2157 for( sal_uInt16 n = 0; n < nColCount; n++ )
2159 const PopularColorCount& rPop = pCountTable[ n ];
2160 aNewPal[ n ] = BitmapColor( (sal_uInt8) ( ( rPop.mnIndex >> nLeftShiftBits2 ) << nRightShiftBits ),
2161 (sal_uInt8) ( ( ( rPop.mnIndex >> nLeftShiftBits1 ) & ( nColorsPerComponent - 1 ) ) << nRightShiftBits ),
2162 (sal_uInt8) ( ( rPop.mnIndex & ( nColorsPerComponent - 1 ) ) << nRightShiftBits ) );
2165 Bitmap aNewBmp( GetSizePixel(), nBitCount, &aNewPal );
2166 BitmapWriteAccess* pWAcc = aNewBmp.AcquireWriteAccess();
2168 if( pWAcc )
2170 BitmapColor aDstCol( (sal_uInt8) 0 );
2171 boost::scoped_array<sal_uInt8> pIndexMap(new sal_uInt8[ nTotalColors ]);
2173 for( long nR = 0, nIndex = 0; nR < 256; nR += nColorOffset )
2174 for( long nG = 0; nG < 256; nG += nColorOffset )
2175 for( long nB = 0; nB < 256; nB += nColorOffset )
2176 pIndexMap[ nIndex++ ] = (sal_uInt8) aNewPal.GetBestIndex( BitmapColor( (sal_uInt8) nR, (sal_uInt8) nG, (sal_uInt8) nB ) );
2178 if( pRAcc->HasPalette() )
2180 for( long nY = 0L; nY < nHeight; nY++ )
2182 for( long nX = 0L; nX < nWidth; nX++ )
2184 const BitmapColor& rCol = pRAcc->GetPaletteColor( pRAcc->GetPixelIndex( nY, nX ) );
2185 aDstCol.SetIndex( pIndexMap[ ( ( ( (sal_uInt32) rCol.GetRed() ) >> nRightShiftBits ) << nLeftShiftBits2 ) |
2186 ( ( ( (sal_uInt32) rCol.GetGreen() ) >> nRightShiftBits ) << nLeftShiftBits1 ) |
2187 ( ( (sal_uInt32) rCol.GetBlue() ) >> nRightShiftBits ) ] );
2188 pWAcc->SetPixel( nY, nX, aDstCol );
2192 else
2194 for( long nY = 0L; nY < nHeight; nY++ )
2196 for( long nX = 0L; nX < nWidth; nX++ )
2198 const BitmapColor aCol( pRAcc->GetPixel( nY, nX ) );
2199 aDstCol.SetIndex( pIndexMap[ ( ( ( (sal_uInt32) aCol.GetRed() ) >> nRightShiftBits ) << nLeftShiftBits2 ) |
2200 ( ( ( (sal_uInt32) aCol.GetGreen() ) >> nRightShiftBits ) << nLeftShiftBits1 ) |
2201 ( ( (sal_uInt32) aCol.GetBlue() ) >> nRightShiftBits ) ] );
2202 pWAcc->SetPixel( nY, nX, aDstCol );
2207 ReleaseAccess( pWAcc );
2208 bRet = true;
2211 pCountTable.reset();
2212 ReleaseAccess( pRAcc );
2214 if( bRet )
2216 const MapMode aMap( maPrefMapMode );
2217 const Size aSize( maPrefSize );
2219 *this = aNewBmp;
2220 maPrefMapMode = aMap;
2221 maPrefSize = aSize;
2225 return bRet;
2228 bool Bitmap::ImplReduceMedian( sal_uInt16 nColCount )
2230 BitmapReadAccess* pRAcc = AcquireReadAccess();
2231 sal_uInt16 nBitCount;
2232 bool bRet = false;
2234 if( nColCount < 17 )
2235 nBitCount = 4;
2236 else if( nColCount < 257 )
2237 nBitCount = 8;
2238 else
2240 OSL_FAIL( "Bitmap::ImplReduceMedian(): invalid color count!" );
2241 nBitCount = 8;
2242 nColCount = 256;
2245 if( pRAcc )
2247 Bitmap aNewBmp( GetSizePixel(), nBitCount );
2248 BitmapWriteAccess* pWAcc = aNewBmp.AcquireWriteAccess();
2250 if( pWAcc )
2252 const sal_uLong nSize = 32768UL * sizeof( sal_uLong );
2253 sal_uLong* pColBuf = static_cast<sal_uLong*>(rtl_allocateMemory( nSize ));
2254 const long nWidth = pWAcc->Width();
2255 const long nHeight = pWAcc->Height();
2256 long nIndex = 0L;
2258 memset( pColBuf, 0, nSize );
2260 // create Buffer
2261 if( pRAcc->HasPalette() )
2263 for( long nY = 0L; nY < nHeight; nY++ )
2265 for( long nX = 0L; nX < nWidth; nX++ )
2267 const BitmapColor& rCol = pRAcc->GetPaletteColor( pRAcc->GetPixelIndex( nY, nX ) );
2268 pColBuf[ RGB15( rCol.GetRed() >> 3, rCol.GetGreen() >> 3, rCol.GetBlue() >> 3 ) ]++;
2272 else
2274 for( long nY = 0L; nY < nHeight; nY++ )
2276 for( long nX = 0L; nX < nWidth; nX++ )
2278 const BitmapColor aCol( pRAcc->GetPixel( nY, nX ) );
2279 pColBuf[ RGB15( aCol.GetRed() >> 3, aCol.GetGreen() >> 3, aCol.GetBlue() >> 3 ) ]++;
2284 // create palette via median cut
2285 BitmapPalette aPal( pWAcc->GetPaletteEntryCount() );
2286 ImplMedianCut( pColBuf, aPal, 0, 31, 0, 31, 0, 31,
2287 nColCount, nWidth * nHeight, nIndex );
2289 // do mapping of colors to palette
2290 InverseColorMap aMap( aPal );
2291 pWAcc->SetPalette( aPal );
2292 for( long nY = 0L; nY < nHeight; nY++ )
2293 for( long nX = 0L; nX < nWidth; nX++ )
2294 pWAcc->SetPixelIndex( nY, nX, static_cast<sal_uInt8>( aMap.GetBestPaletteIndex( pRAcc->GetColor( nY, nX ) )) );
2296 rtl_freeMemory( pColBuf );
2297 ReleaseAccess( pWAcc );
2298 bRet = true;
2301 ReleaseAccess( pRAcc );
2303 if( bRet )
2305 const MapMode aMap( maPrefMapMode );
2306 const Size aSize( maPrefSize );
2308 *this = aNewBmp;
2309 maPrefMapMode = aMap;
2310 maPrefSize = aSize;
2314 return bRet;
2317 void Bitmap::ImplMedianCut( sal_uLong* pColBuf, BitmapPalette& rPal,
2318 long nR1, long nR2, long nG1, long nG2, long nB1, long nB2,
2319 long nColors, long nPixels, long& rIndex )
2321 if( !nPixels )
2322 return;
2324 BitmapColor aCol;
2325 const long nRLen = nR2 - nR1;
2326 const long nGLen = nG2 - nG1;
2327 const long nBLen = nB2 - nB1;
2328 sal_uLong* pBuf = pColBuf;
2330 if( !nRLen && !nGLen && !nBLen )
2332 if( pBuf[ RGB15( nR1, nG1, nB1 ) ] )
2334 aCol.SetRed( (sal_uInt8) ( nR1 << 3 ) );
2335 aCol.SetGreen( (sal_uInt8) ( nG1 << 3 ) );
2336 aCol.SetBlue( (sal_uInt8) ( nB1 << 3 ) );
2337 rPal[ (sal_uInt16) rIndex++ ] = aCol;
2340 else
2342 if( 1 == nColors || 1 == nPixels )
2344 long nPixSum = 0, nRSum = 0, nGSum = 0, nBSum = 0;
2346 for( long nR = nR1; nR <= nR2; nR++ )
2348 for( long nG = nG1; nG <= nG2; nG++ )
2350 for( long nB = nB1; nB <= nB2; nB++ )
2352 nPixSum = pBuf[ RGB15( nR, nG, nB ) ];
2354 if( nPixSum )
2356 nRSum += nR * nPixSum;
2357 nGSum += nG * nPixSum;
2358 nBSum += nB * nPixSum;
2364 aCol.SetRed( (sal_uInt8) ( ( nRSum / nPixels ) << 3 ) );
2365 aCol.SetGreen( (sal_uInt8) ( ( nGSum / nPixels ) << 3 ) );
2366 aCol.SetBlue( (sal_uInt8) ( ( nBSum / nPixels ) << 3 ) );
2367 rPal[ (sal_uInt16) rIndex++ ] = aCol;
2369 else
2371 const long nTest = ( nPixels >> 1 );
2372 long nPixOld = 0;
2373 long nPixNew = 0;
2375 if( nBLen > nGLen && nBLen > nRLen )
2377 long nB = nB1 - 1;
2379 while( nPixNew < nTest )
2381 nB++, nPixOld = nPixNew;
2382 for( long nR = nR1; nR <= nR2; nR++ )
2383 for( long nG = nG1; nG <= nG2; nG++ )
2384 nPixNew += pBuf[ RGB15( nR, nG, nB ) ];
2387 if( nB < nB2 )
2389 ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG2, nB1, nB, nColors >> 1, nPixNew, rIndex );
2390 ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG2, nB + 1, nB2, nColors >> 1, nPixels - nPixNew, rIndex );
2392 else
2394 ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG2, nB1, nB - 1, nColors >> 1, nPixOld, rIndex );
2395 ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG2, nB, nB2, nColors >> 1, nPixels - nPixOld, rIndex );
2398 else if( nGLen > nRLen )
2400 long nG = nG1 - 1;
2402 while( nPixNew < nTest )
2404 nG++, nPixOld = nPixNew;
2405 for( long nR = nR1; nR <= nR2; nR++ )
2406 for( long nB = nB1; nB <= nB2; nB++ )
2407 nPixNew += pBuf[ RGB15( nR, nG, nB ) ];
2410 if( nG < nG2 )
2412 ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG, nB1, nB2, nColors >> 1, nPixNew, rIndex );
2413 ImplMedianCut( pBuf, rPal, nR1, nR2, nG + 1, nG2, nB1, nB2, nColors >> 1, nPixels - nPixNew, rIndex );
2415 else
2417 ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG - 1, nB1, nB2, nColors >> 1, nPixOld, rIndex );
2418 ImplMedianCut( pBuf, rPal, nR1, nR2, nG, nG2, nB1, nB2, nColors >> 1, nPixels - nPixOld, rIndex );
2421 else
2423 long nR = nR1 - 1;
2425 while( nPixNew < nTest )
2427 nR++, nPixOld = nPixNew;
2428 for( long nG = nG1; nG <= nG2; nG++ )
2429 for( long nB = nB1; nB <= nB2; nB++ )
2430 nPixNew += pBuf[ RGB15( nR, nG, nB ) ];
2433 if( nR < nR2 )
2435 ImplMedianCut( pBuf, rPal, nR1, nR, nG1, nG2, nB1, nB2, nColors >> 1, nPixNew, rIndex );
2436 ImplMedianCut( pBuf, rPal, nR1 + 1, nR2, nG1, nG2, nB1, nB2, nColors >> 1, nPixels - nPixNew, rIndex );
2438 else
2440 ImplMedianCut( pBuf, rPal, nR1, nR - 1, nG1, nG2, nB1, nB2, nColors >> 1, nPixOld, rIndex );
2441 ImplMedianCut( pBuf, rPal, nR, nR2, nG1, nG2, nB1, nB2, nColors >> 1, nPixels - nPixOld, rIndex );
2448 bool Bitmap::Vectorize( tools::PolyPolygon& rPolyPoly, BmpVectorizeFlags nFlags, const Link<>* pProgress )
2450 return ImplVectorizer::ImplVectorize( *this, rPolyPoly, nFlags, pProgress );
2453 bool Bitmap::Vectorize( GDIMetaFile& rMtf, sal_uInt8 cReduce, BmpVectorizeFlags nFlags, const Link<>* pProgress )
2455 return ImplVectorizer::ImplVectorize( *this, rMtf, cReduce, nFlags, pProgress );
2458 bool Bitmap::Adjust( short nLuminancePercent, short nContrastPercent,
2459 short nChannelRPercent, short nChannelGPercent, short nChannelBPercent,
2460 double fGamma, bool bInvert, bool msoBrightness )
2462 bool bRet = false;
2464 // nothing to do => return quickly
2465 if( !nLuminancePercent && !nContrastPercent &&
2466 !nChannelRPercent && !nChannelGPercent && !nChannelBPercent &&
2467 ( fGamma == 1.0 ) && !bInvert )
2469 bRet = true;
2471 else
2473 BitmapWriteAccess* pAcc = AcquireWriteAccess();
2475 if( pAcc )
2477 BitmapColor aCol;
2478 const long nW = pAcc->Width();
2479 const long nH = pAcc->Height();
2480 boost::scoped_array<sal_uInt8> cMapR(new sal_uInt8[ 256 ]);
2481 boost::scoped_array<sal_uInt8> cMapG(new sal_uInt8[ 256 ]);
2482 boost::scoped_array<sal_uInt8> cMapB(new sal_uInt8[ 256 ]);
2483 double fM, fROff, fGOff, fBOff, fOff;
2485 // calculate slope
2486 if( nContrastPercent >= 0 )
2487 fM = 128.0 / ( 128.0 - 1.27 * MinMax( nContrastPercent, 0L, 100L ) );
2488 else
2489 fM = ( 128.0 + 1.27 * MinMax( nContrastPercent, -100L, 0L ) ) / 128.0;
2491 if(!msoBrightness)
2492 // total offset = luminance offset + contrast offset
2493 fOff = MinMax( nLuminancePercent, -100L, 100L ) * 2.55 + 128.0 - fM * 128.0;
2494 else
2495 fOff = MinMax( nLuminancePercent, -100L, 100L ) * 2.55;
2497 // channel offset = channel offset + total offset
2498 fROff = nChannelRPercent * 2.55 + fOff;
2499 fGOff = nChannelGPercent * 2.55 + fOff;
2500 fBOff = nChannelBPercent * 2.55 + fOff;
2502 // calculate gamma value
2503 fGamma = ( fGamma <= 0.0 || fGamma > 10.0 ) ? 1.0 : ( 1.0 / fGamma );
2504 const bool bGamma = ( fGamma != 1.0 );
2506 // create mapping table
2507 for( long nX = 0L; nX < 256L; nX++ )
2509 if(!msoBrightness)
2511 cMapR[ nX ] = (sal_uInt8) MinMax( FRound( nX * fM + fROff ), 0L, 255L );
2512 cMapG[ nX ] = (sal_uInt8) MinMax( FRound( nX * fM + fGOff ), 0L, 255L );
2513 cMapB[ nX ] = (sal_uInt8) MinMax( FRound( nX * fM + fBOff ), 0L, 255L );
2515 else
2517 // LO simply uses (in a somewhat optimized form) "newcolor = (oldcolor-128)*contrast+brightness+128"
2518 // as the formula, i.e. contrast first, brightness afterwards. MSOffice, for whatever weird reason,
2519 // use neither first, but apparently it applies half of brightness before contrast and half afterwards.
2520 cMapR[ nX ] = (sal_uInt8) MinMax( FRound( (nX+fROff/2-128) * fM + 128 + fROff/2 ), 0L, 255L );
2521 cMapG[ nX ] = (sal_uInt8) MinMax( FRound( (nX+fGOff/2-128) * fM + 128 + fGOff/2 ), 0L, 255L );
2522 cMapB[ nX ] = (sal_uInt8) MinMax( FRound( (nX+fBOff/2-128) * fM + 128 + fBOff/2 ), 0L, 255L );
2524 if( bGamma )
2526 cMapR[ nX ] = GAMMA( cMapR[ nX ], fGamma );
2527 cMapG[ nX ] = GAMMA( cMapG[ nX ], fGamma );
2528 cMapB[ nX ] = GAMMA( cMapB[ nX ], fGamma );
2531 if( bInvert )
2533 cMapR[ nX ] = ~cMapR[ nX ];
2534 cMapG[ nX ] = ~cMapG[ nX ];
2535 cMapB[ nX ] = ~cMapB[ nX ];
2539 // do modifying
2540 if( pAcc->HasPalette() )
2542 BitmapColor aNewCol;
2544 for( sal_uInt16 i = 0, nCount = pAcc->GetPaletteEntryCount(); i < nCount; i++ )
2546 const BitmapColor& rCol = pAcc->GetPaletteColor( i );
2547 aNewCol.SetRed( cMapR[ rCol.GetRed() ] );
2548 aNewCol.SetGreen( cMapG[ rCol.GetGreen() ] );
2549 aNewCol.SetBlue( cMapB[ rCol.GetBlue() ] );
2550 pAcc->SetPaletteColor( i, aNewCol );
2553 else if( pAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_BGR )
2555 for( long nY = 0L; nY < nH; nY++ )
2557 Scanline pScan = pAcc->GetScanline( nY );
2559 for( long nX = 0L; nX < nW; nX++ )
2561 *pScan = cMapB[ *pScan ]; pScan++;
2562 *pScan = cMapG[ *pScan ]; pScan++;
2563 *pScan = cMapR[ *pScan ]; pScan++;
2567 else if( pAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_RGB )
2569 for( long nY = 0L; nY < nH; nY++ )
2571 Scanline pScan = pAcc->GetScanline( nY );
2573 for( long nX = 0L; nX < nW; nX++ )
2575 *pScan = cMapR[ *pScan ]; pScan++;
2576 *pScan = cMapG[ *pScan ]; pScan++;
2577 *pScan = cMapB[ *pScan ]; pScan++;
2581 else
2583 for( long nY = 0L; nY < nH; nY++ )
2585 for( long nX = 0L; nX < nW; nX++ )
2587 aCol = pAcc->GetPixel( nY, nX );
2588 aCol.SetRed( cMapR[ aCol.GetRed() ] );
2589 aCol.SetGreen( cMapG[ aCol.GetGreen() ] );
2590 aCol.SetBlue( cMapB[ aCol.GetBlue() ] );
2591 pAcc->SetPixel( nY, nX, aCol );
2596 ReleaseAccess( pAcc );
2597 bRet = true;
2601 return bRet;
2604 bool Bitmap::ImplConvolutionPass(Bitmap& aNewBitmap, BitmapReadAccess* pReadAcc, int aNumberOfContributions, double* pWeights, int* pPixels, int* pCount)
2606 BitmapWriteAccess* pWriteAcc = aNewBitmap.AcquireWriteAccess();
2608 if (!pReadAcc || !pWriteAcc)
2609 return false;
2611 const int nHeight = GetSizePixel().Height();
2612 assert(GetSizePixel().Height() == aNewBitmap.GetSizePixel().Width());
2613 const int nWidth = GetSizePixel().Width();
2614 assert(GetSizePixel().Width() == aNewBitmap.GetSizePixel().Height());
2616 BitmapColor aColor;
2617 double aValueRed, aValueGreen, aValueBlue;
2618 double aSum, aWeight;
2619 int aBaseIndex, aIndex;
2621 for (int nSourceY = 0; nSourceY < nHeight; ++nSourceY)
2623 for (int nSourceX = 0; nSourceX < nWidth; ++nSourceX)
2625 aBaseIndex = nSourceX * aNumberOfContributions;
2626 aSum = aValueRed = aValueGreen = aValueBlue = 0.0;
2628 for (int j = 0; j < pCount[nSourceX]; ++j)
2630 aIndex = aBaseIndex + j;
2631 aSum += aWeight = pWeights[ aIndex ];
2633 aColor = pReadAcc->GetColor(nSourceY, pPixels[aIndex]);
2635 aValueRed += aWeight * aColor.GetRed();
2636 aValueGreen += aWeight * aColor.GetGreen();
2637 aValueBlue += aWeight * aColor.GetBlue();
2640 BitmapColor aResultColor(
2641 (sal_uInt8) MinMax( aValueRed / aSum, 0, 255 ),
2642 (sal_uInt8) MinMax( aValueGreen / aSum, 0, 255 ),
2643 (sal_uInt8) MinMax( aValueBlue / aSum, 0, 255 ) );
2645 int nDestX = nSourceY;
2646 int nDestY = nSourceX;
2648 pWriteAcc->SetPixel(nDestY, nDestX, aResultColor);
2651 ReleaseAccess( pWriteAcc );
2652 return true;
2655 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */