1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 // MARKER(update_precomp.py): autogen include statement, do not remove 25 #include "precompiled_vcl.hxx" 26 27 #include <stdlib.h> 28 29 #include <vcl/bmpacc.hxx> 30 #include <vcl/octree.hxx> 31 #include <vcl/bitmapex.hxx> 32 #include <vcl/bitmap.hxx> 33 34 #include <impoct.hxx> 35 #include <impvect.hxx> 36 37 // ----------- 38 // - Defines - 39 // ----------- 40 41 #define RGB15( _def_cR, _def_cG, _def_cB ) (((sal_uLong)(_def_cR)<<10UL)|((sal_uLong)(_def_cG)<<5UL)|(sal_uLong)(_def_cB)) 42 #define GAMMA( _def_cVal, _def_InvGamma ) ((sal_uInt8)MinMax(FRound(pow( _def_cVal/255.0,_def_InvGamma)*255.0),0L,255L)) 43 #define MAP( cVal0, cVal1, nFrac ) ((sal_uInt8)((((long)(cVal0)<<7L)+nFrac*((long)(cVal1)-(cVal0)))>>7L)) 44 45 #define CALC_ERRORS \ 46 nTemp = p1T[nX++] >> 12; \ 47 nBErr = MinMax( nTemp, 0, 255 ); \ 48 nBErr = nBErr - FloydIndexMap[ nBC = FloydMap[nBErr] ]; \ 49 nTemp = p1T[nX++] >> 12; \ 50 nGErr = MinMax( nTemp, 0, 255 ); \ 51 nGErr = nGErr - FloydIndexMap[ nGC = FloydMap[nGErr] ]; \ 52 nTemp = p1T[nX] >> 12; \ 53 nRErr = MinMax( nTemp, 0, 255 ); \ 54 nRErr = nRErr - FloydIndexMap[ nRC = FloydMap[nRErr] ]; 55 56 #define CALC_TABLES3 \ 57 p2T[nX++] += FloydError3[nBErr]; \ 58 p2T[nX++] += FloydError3[nGErr]; \ 59 p2T[nX++] += FloydError3[nRErr]; 60 61 #define CALC_TABLES5 \ 62 p2T[nX++] += FloydError5[nBErr]; \ 63 p2T[nX++] += FloydError5[nGErr]; \ 64 p2T[nX++] += FloydError5[nRErr]; 65 66 #define CALC_TABLES7 \ 67 p1T[++nX] += FloydError7[nBErr]; \ 68 p2T[nX++] += FloydError1[nBErr]; \ 69 p1T[nX] += FloydError7[nGErr]; \ 70 p2T[nX++] += FloydError1[nGErr]; \ 71 p1T[nX] += FloydError7[nRErr]; \ 72 p2T[nX] += FloydError1[nRErr]; 73 74 // ----------- 75 // - Statics - 76 // ----------- 77 78 sal_uLong nVCLRLut[ 6 ] = { 16, 17, 18, 19, 20, 21 }; 79 sal_uLong nVCLGLut[ 6 ] = { 0, 6, 12, 18, 24, 30 }; 80 sal_uLong nVCLBLut[ 6 ] = { 0, 36, 72, 108, 144, 180 }; 81 82 // ------------------------------------------------------------------------ 83 84 sal_uLong nVCLDitherLut[ 256 ] = 85 { 86 0, 49152, 12288, 61440, 3072, 52224, 15360, 64512, 768, 49920, 13056, 87 62208, 3840, 52992, 16128, 65280, 32768, 16384, 45056, 28672, 35840, 19456, 88 48128, 31744, 33536, 17152, 45824, 29440, 36608, 20224, 48896, 32512, 8192, 89 57344, 4096, 53248, 11264, 60416, 7168, 56320, 8960, 58112, 4864, 54016, 90 12032, 61184, 7936, 57088, 40960, 24576, 36864, 20480, 44032, 27648, 39936, 91 23552, 41728, 25344, 37632, 21248, 44800, 28416, 40704, 24320, 2048, 51200, 92 14336, 63488, 1024, 50176, 13312, 62464, 2816, 51968, 15104, 64256, 1792, 93 50944, 14080, 63232, 34816, 18432, 47104, 30720, 33792, 17408, 46080, 29696, 94 35584, 19200, 47872, 31488, 34560, 18176, 46848, 30464, 10240, 59392, 6144, 95 55296, 9216, 58368, 5120, 54272, 11008, 60160, 6912, 56064, 9984, 59136, 96 5888, 55040, 43008, 26624, 38912, 22528, 41984, 25600, 37888, 21504, 43776, 97 27392, 39680, 23296, 42752, 26368, 38656, 22272, 512, 49664, 12800, 61952, 98 3584, 52736, 15872, 65024, 256, 49408, 12544, 61696, 3328, 52480, 15616, 99 64768, 33280, 16896, 45568, 29184, 36352, 19968, 48640, 32256, 33024, 16640, 100 45312, 28928, 36096, 19712, 48384, 32000, 8704, 57856, 4608, 53760, 11776, 101 60928, 7680, 56832, 8448, 57600, 4352, 53504, 11520, 60672, 7424, 56576, 102 41472, 25088, 37376, 20992, 44544, 28160, 40448, 24064, 41216, 24832, 37120, 103 20736, 44288, 27904, 40192, 23808, 2560, 51712, 14848, 64000, 1536, 50688, 104 13824, 62976, 2304, 51456, 14592, 63744, 1280, 50432, 13568, 62720, 35328, 105 18944, 47616, 31232, 34304, 17920, 46592, 30208, 35072, 18688, 47360, 30976, 106 34048, 17664, 46336, 29952, 10752, 59904, 6656, 55808, 9728, 58880, 5632, 107 54784, 10496, 59648, 6400, 55552, 9472, 58624, 5376, 54528, 43520, 27136, 108 39424, 23040, 42496, 26112, 38400, 22016, 43264, 26880, 39168, 22784, 42240, 109 25856, 38144, 21760 110 }; 111 112 // ------------------------------------------------------------------------ 113 114 sal_uLong nVCLLut[ 256 ] = 115 { 116 0, 1286, 2572, 3858, 5144, 6430, 7716, 9002, 117 10288, 11574, 12860, 14146, 15432, 16718, 18004, 19290, 118 20576, 21862, 23148, 24434, 25720, 27006, 28292, 29578, 119 30864, 32150, 33436, 34722, 36008, 37294, 38580, 39866, 120 41152, 42438, 43724, 45010, 46296, 47582, 48868, 50154, 121 51440, 52726, 54012, 55298, 56584, 57870, 59156, 60442, 122 61728, 63014, 64300, 65586, 66872, 68158, 69444, 70730, 123 72016, 73302, 74588, 75874, 77160, 78446, 79732, 81018, 124 82304, 83590, 84876, 86162, 87448, 88734, 90020, 91306, 125 92592, 93878, 95164, 96450, 97736, 99022,100308,101594, 126 102880,104166,105452,106738,108024,109310,110596,111882, 127 113168,114454,115740,117026,118312,119598,120884,122170, 128 123456,124742,126028,127314,128600,129886,131172,132458, 129 133744,135030,136316,137602,138888,140174,141460,142746, 130 144032,145318,146604,147890,149176,150462,151748,153034, 131 154320,155606,156892,158178,159464,160750,162036,163322, 132 164608,165894,167180,168466,169752,171038,172324,173610, 133 174896,176182,177468,178754,180040,181326,182612,183898, 134 185184,186470,187756,189042,190328,191614,192900,194186, 135 195472,196758,198044,199330,200616,201902,203188,204474, 136 205760,207046,208332,209618,210904,212190,213476,214762, 137 216048,217334,218620,219906,221192,222478,223764,225050, 138 226336,227622,228908,230194,231480,232766,234052,235338, 139 236624,237910,239196,240482,241768,243054,244340,245626, 140 246912,248198,249484,250770,252056,253342,254628,255914, 141 257200,258486,259772,261058,262344,263630,264916,266202, 142 267488,268774,270060,271346,272632,273918,275204,276490, 143 277776,279062,280348,281634,282920,284206,285492,286778, 144 288064,289350,290636,291922,293208,294494,295780,297066, 145 298352,299638,300924,302210,303496,304782,306068,307354, 146 308640,309926,311212,312498,313784,315070,316356,317642, 147 318928,320214,321500,322786,324072,325358,326644,327930 148 }; 149 150 // ------------------------------------------------------------------------ 151 152 long FloydMap[256] = 153 { 154 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 155 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 156 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 157 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 158 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 159 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 160 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 161 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 162 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 163 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 164 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 165 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 166 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 167 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 168 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 169 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 170 }; 171 172 // ------------------------------------------------------------------------ 173 174 long FloydError1[61] = 175 { 176 -7680, -7424, -7168, -6912, -6656, -6400, -6144, 177 -5888, -5632, -5376, -5120, -4864, -4608, -4352, 178 -4096, -3840, -3584, -3328, -3072, -2816, -2560, 179 -2304, -2048, -1792, -1536, -1280, -1024, -768, 180 -512, -256, 0, 256, 512, 768, 1024, 1280, 1536, 181 1792, 2048, 2304, 2560, 2816, 3072, 3328, 3584, 182 3840, 4096, 4352, 4608, 4864, 5120, 5376, 5632, 183 5888, 6144, 6400, 6656, 6912, 7168, 7424, 7680 184 }; 185 186 // ------------------------------------------------------------------------ 187 188 long FloydError3[61] = 189 { 190 -23040, -22272, -21504, -20736, -19968, -19200, 191 -18432, -17664, -16896, -16128, -15360, -14592, 192 -13824, -13056, -12288, -11520, -10752, -9984, 193 -9216, -8448, -7680, -6912, -6144, -5376, -4608, 194 -3840, -3072, -2304, -1536, -768, 0, 768, 1536, 195 2304, 3072, 3840, 4608, 5376, 6144, 6912, 7680, 196 8448, 9216, 9984, 10752, 11520, 12288, 13056, 197 13824, 14592, 15360, 16128, 16896, 17664, 18432, 198 19200, 19968, 20736, 21504, 22272, 23040 199 }; 200 201 // ------------------------------------------------------------------------ 202 203 long FloydError5[61] = 204 { 205 -38400, -37120, -35840, -34560, -33280, -32000, 206 -30720, -29440, -28160, -26880, -25600, -24320, 207 -23040, -21760, -20480, -19200, -17920, -16640, 208 -15360, -14080, -12800, -11520, -10240, -8960, 209 -7680, -6400, -5120, -3840, -2560, -1280, 0, 210 1280, 2560, 3840, 5120, 6400, 7680, 8960, 10240, 211 11520, 12800, 14080, 15360, 16640, 17920, 19200, 212 20480, 21760, 23040, 24320, 25600, 26880, 28160, 213 29440, 30720, 32000, 33280, 34560, 35840, 37120, 214 38400 215 }; 216 217 // ------------------------------------------------------------------------ 218 219 long FloydError7[61] = 220 { 221 -53760, -51968, -50176, -48384, -46592, -44800, 222 -43008, -41216, -39424, -37632, -35840, -34048, 223 -32256, -30464, -28672, -26880, -25088, -23296, 224 -21504, -19712, -17920, -16128, -14336, -12544, 225 -10752, -8960, -7168, -5376, -3584, -1792, 0, 226 1792, 3584, 5376, 7168, 8960, 10752, 12544, 14336, 227 16128, 17920, 19712, 21504, 23296, 25088, 26880, 228 28672, 30464, 32256, 34048, 35840, 37632, 39424, 229 41216, 43008, 44800, 46592, 48384, 50176, 51968, 230 53760 231 }; 232 233 // ------------------------------------------------------------------------ 234 235 long FloydIndexMap[6] = 236 { 237 -30, 21, 72, 123, 174, 225 238 }; 239 240 // -------------------------- 241 // - ImplCreateDitherMatrix - 242 // -------------------------- 243 244 void ImplCreateDitherMatrix( sal_uInt8 (*pDitherMatrix)[16][16] ) 245 { 246 double fVal = 3.125; 247 const double fVal16 = fVal / 16.; 248 long i, j, k, l; 249 sal_uInt16 pMtx[ 16 ][ 16 ]; 250 sal_uInt16 nMax = 0; 251 static sal_uInt8 pMagic[4][4] = { { 0, 14, 3, 13, }, 252 {11, 5, 8, 6, }, 253 {12, 2, 15, 1, }, 254 {7, 9, 4, 10 } }; 255 256 // MagicSquare aufbauen 257 for ( i = 0; i < 4; i++ ) 258 for ( j = 0; j < 4; j++ ) 259 for ( k = 0; k < 4; k++ ) 260 for ( l = 0; l < 4; l++ ) 261 nMax = Max ( pMtx[ (k<<2) + i][(l<<2 ) + j] = 262 (sal_uInt16) ( 0.5 + pMagic[i][j]*fVal + pMagic[k][l]*fVal16 ), nMax ); 263 264 // auf Intervall [0;254] skalieren 265 for ( i = 0, fVal = 254. / nMax; i < 16; i++ ) 266 for( j = 0; j < 16; j++ ) 267 (*pDitherMatrix)[i][j] = (sal_uInt8) ( fVal * pMtx[i][j] ); 268 } 269 270 // ---------- 271 // - Bitmap - 272 // ---------- 273 274 sal_Bool Bitmap::Convert( BmpConversion eConversion ) 275 { 276 const sal_uInt16 nBitCount = GetBitCount(); 277 sal_Bool bRet = sal_False; 278 279 switch( eConversion ) 280 { 281 case( BMP_CONVERSION_1BIT_THRESHOLD ): 282 bRet = ImplMakeMono( 128 ); 283 break; 284 285 case( BMP_CONVERSION_1BIT_MATRIX ): 286 bRet = ImplMakeMonoDither(); 287 break; 288 289 case( BMP_CONVERSION_4BIT_GREYS ): 290 bRet = ImplMakeGreyscales( 16 ); 291 break; 292 293 case( BMP_CONVERSION_4BIT_COLORS ): 294 { 295 if( nBitCount < 4 ) 296 bRet = ImplConvertUp( 4, NULL ); 297 else if( nBitCount > 4 ) 298 bRet = ImplConvertDown( 4, NULL ); 299 else 300 bRet = sal_True; 301 } 302 break; 303 304 case( BMP_CONVERSION_4BIT_TRANS ): 305 { 306 Color aTrans( BMP_COL_TRANS ); 307 308 if( nBitCount < 4 ) 309 bRet = ImplConvertUp( 4, &aTrans ); 310 else 311 bRet = ImplConvertDown( 4, &aTrans ); 312 } 313 break; 314 315 case( BMP_CONVERSION_8BIT_GREYS ): 316 bRet = ImplMakeGreyscales( 256 ); 317 break; 318 319 case( BMP_CONVERSION_8BIT_COLORS ): 320 { 321 if( nBitCount < 8 ) 322 bRet = ImplConvertUp( 8 ); 323 else if( nBitCount > 8 ) 324 bRet = ImplConvertDown( 8 ); 325 else 326 bRet = sal_True; 327 } 328 break; 329 330 case( BMP_CONVERSION_8BIT_TRANS ): 331 { 332 Color aTrans( BMP_COL_TRANS ); 333 334 if( nBitCount < 8 ) 335 bRet = ImplConvertUp( 8, &aTrans ); 336 else 337 bRet = ImplConvertDown( 8, &aTrans ); 338 } 339 break; 340 341 case( BMP_CONVERSION_24BIT ): 342 { 343 if( nBitCount < 24 ) 344 bRet = ImplConvertUp( 24, sal_False ); 345 else 346 bRet = sal_True; 347 } 348 break; 349 350 case( BMP_CONVERSION_GHOSTED ): 351 bRet = ImplConvertGhosted(); 352 break; 353 354 default: 355 DBG_ERROR( "Bitmap::Convert(): Unsupported conversion" ); 356 break; 357 } 358 359 return bRet; 360 } 361 362 // ------------------------------------------------------------------------ 363 364 sal_Bool Bitmap::ImplMakeMono( sal_uInt8 cThreshold ) 365 { 366 BitmapReadAccess* pReadAcc = AcquireReadAccess(); 367 sal_Bool bRet = sal_False; 368 369 if( pReadAcc ) 370 { 371 Bitmap aNewBmp( GetSizePixel(), 1 ); 372 BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess(); 373 374 if( pWriteAcc ) 375 { 376 const BitmapColor aBlack( pWriteAcc->GetBestMatchingColor( Color( COL_BLACK ) ) ); 377 const BitmapColor aWhite( pWriteAcc->GetBestMatchingColor( Color( COL_WHITE ) ) ); 378 const long nWidth = pWriteAcc->Width(); 379 const long nHeight = pWriteAcc->Height(); 380 381 if( pReadAcc->HasPalette() ) 382 { 383 for( long nY = 0L; nY < nHeight; nY++ ) 384 { 385 for( long nX = 0L; nX < nWidth; nX++ ) 386 { 387 const sal_uInt8 cIndex = pReadAcc->GetPixelIndex( nY, nX ); 388 if( pReadAcc->GetPaletteColor( cIndex ).GetLuminance() >= 389 cThreshold ) 390 { 391 pWriteAcc->SetPixel( nY, nX, aWhite ); 392 } 393 else 394 pWriteAcc->SetPixel( nY, nX, aBlack ); 395 } 396 } 397 } 398 else 399 { 400 for( long nY = 0L; nY < nHeight; nY++ ) 401 { 402 for( long nX = 0L; nX < nWidth; nX++ ) 403 { 404 if( pReadAcc->GetPixel( nY, nX ).GetLuminance() >= 405 cThreshold ) 406 { 407 pWriteAcc->SetPixel( nY, nX, aWhite ); 408 } 409 else 410 pWriteAcc->SetPixel( nY, nX, aBlack ); 411 } 412 } 413 } 414 415 aNewBmp.ReleaseAccess( pWriteAcc ); 416 bRet = sal_True; 417 } 418 419 ReleaseAccess( pReadAcc ); 420 421 if( bRet ) 422 { 423 const MapMode aMap( maPrefMapMode ); 424 const Size aSize( maPrefSize ); 425 426 *this = aNewBmp; 427 428 maPrefMapMode = aMap; 429 maPrefSize = aSize; 430 } 431 } 432 433 return bRet; 434 } 435 436 // ------------------------------------------------------------------------ 437 438 sal_Bool Bitmap::ImplMakeMonoDither() 439 { 440 BitmapReadAccess* pReadAcc = AcquireReadAccess(); 441 sal_Bool bRet = sal_False; 442 443 if( pReadAcc ) 444 { 445 Bitmap aNewBmp( GetSizePixel(), 1 ); 446 BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess(); 447 448 if( pWriteAcc ) 449 { 450 const BitmapColor aBlack( pWriteAcc->GetBestMatchingColor( Color( COL_BLACK ) ) ); 451 const BitmapColor aWhite( pWriteAcc->GetBestMatchingColor( Color( COL_WHITE ) ) ); 452 const long nWidth = pWriteAcc->Width(); 453 const long nHeight = pWriteAcc->Height(); 454 sal_uInt8 pDitherMatrix[ 16 ][ 16 ]; 455 456 ImplCreateDitherMatrix( &pDitherMatrix ); 457 458 if( pReadAcc->HasPalette() ) 459 { 460 for( long nY = 0L; nY < nHeight; nY++ ) 461 { 462 for( long nX = 0L, nModY = nY % 16; nX < nWidth; nX++ ) 463 { 464 const sal_uInt8 cIndex = pReadAcc->GetPixelIndex( nY, nX ); 465 if( pReadAcc->GetPaletteColor( cIndex ).GetLuminance() > 466 pDitherMatrix[ nModY ][ nX % 16 ] ) 467 { 468 pWriteAcc->SetPixel( nY, nX, aWhite ); 469 } 470 else 471 pWriteAcc->SetPixel( nY, nX, aBlack ); 472 } 473 } 474 } 475 else 476 { 477 for( long nY = 0L; nY < nHeight; nY++ ) 478 { 479 for( long nX = 0L, nModY = nY % 16; nX < nWidth; nX++ ) 480 { 481 if( pReadAcc->GetPixel( nY, nX ).GetLuminance() > 482 pDitherMatrix[ nModY ][ nX % 16 ] ) 483 { 484 pWriteAcc->SetPixel( nY, nX, aWhite ); 485 } 486 else 487 pWriteAcc->SetPixel( nY, nX, aBlack ); 488 } 489 } 490 } 491 492 aNewBmp.ReleaseAccess( pWriteAcc ); 493 bRet = sal_True; 494 } 495 496 ReleaseAccess( pReadAcc ); 497 498 if( bRet ) 499 { 500 const MapMode aMap( maPrefMapMode ); 501 const Size aSize( maPrefSize ); 502 503 *this = aNewBmp; 504 505 maPrefMapMode = aMap; 506 maPrefSize = aSize; 507 } 508 } 509 510 return bRet; 511 } 512 513 // ------------------------------------------------------------------------ 514 515 sal_Bool Bitmap::ImplMakeGreyscales( sal_uInt16 nGreys ) 516 { 517 DBG_ASSERT( nGreys == 16 || nGreys == 256, "Only 16 or 256 greyscales are supported!" ); 518 519 BitmapReadAccess* pReadAcc = AcquireReadAccess(); 520 sal_Bool bRet = sal_False; 521 522 if( pReadAcc ) 523 { 524 const BitmapPalette& rPal = GetGreyPalette( nGreys ); 525 sal_uLong nShift = ( ( nGreys == 16 ) ? 4UL : 0UL ); 526 sal_Bool bPalDiffers = !pReadAcc->HasPalette() || ( rPal.GetEntryCount() != pReadAcc->GetPaletteEntryCount() ); 527 528 if( !bPalDiffers ) 529 bPalDiffers = ( (BitmapPalette&) rPal != pReadAcc->GetPalette() ); 530 531 if( bPalDiffers ) 532 { 533 Bitmap aNewBmp( GetSizePixel(), ( nGreys == 16 ) ? 4 : 8, &rPal ); 534 BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess(); 535 536 if( pWriteAcc ) 537 { 538 const long nWidth = pWriteAcc->Width(); 539 const long nHeight = pWriteAcc->Height(); 540 541 if( pReadAcc->HasPalette() ) 542 { 543 for( long nY = 0L; nY < nHeight; nY++ ) 544 { 545 for( long nX = 0L; nX < nWidth; nX++ ) 546 { 547 const sal_uInt8 cIndex = pReadAcc->GetPixelIndex( nY, nX ); 548 pWriteAcc->SetPixelIndex( nY, nX, 549 (pReadAcc->GetPaletteColor( cIndex ).GetLuminance() >> nShift) ); 550 } 551 } 552 } 553 else if( pReadAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_BGR && 554 pWriteAcc->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL ) 555 { 556 nShift += 8; 557 558 for( long nY = 0L; nY < nHeight; nY++ ) 559 { 560 Scanline pReadScan = pReadAcc->GetScanline( nY ); 561 Scanline pWriteScan = pWriteAcc->GetScanline( nY ); 562 563 for( long nX = 0L; nX < nWidth; nX++ ) 564 { 565 const sal_uLong nB = *pReadScan++; 566 const sal_uLong nG = *pReadScan++; 567 const sal_uLong nR = *pReadScan++; 568 569 *pWriteScan++ = (sal_uInt8) ( ( nB * 28UL + nG * 151UL + nR * 77UL ) >> nShift ); 570 } 571 } 572 } 573 else if( pReadAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_RGB && 574 pWriteAcc->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL ) 575 { 576 nShift += 8; 577 578 for( long nY = 0L; nY < nHeight; nY++ ) 579 { 580 Scanline pReadScan = pReadAcc->GetScanline( nY ); 581 Scanline pWriteScan = pWriteAcc->GetScanline( nY ); 582 583 for( long nX = 0L; nX < nWidth; nX++ ) 584 { 585 const sal_uLong nR = *pReadScan++; 586 const sal_uLong nG = *pReadScan++; 587 const sal_uLong nB = *pReadScan++; 588 589 *pWriteScan++ = (sal_uInt8) ( ( nB * 28UL + nG * 151UL + nR * 77UL ) >> nShift ); 590 } 591 } 592 } 593 else 594 { 595 for( long nY = 0L; nY < nHeight; nY++ ) 596 for( long nX = 0L; nX < nWidth; nX++ ) 597 pWriteAcc->SetPixelIndex( nY, nX, (pReadAcc->GetPixel( nY, nX ) ).GetLuminance() >> nShift ); 598 } 599 600 aNewBmp.ReleaseAccess( pWriteAcc ); 601 bRet = sal_True; 602 } 603 604 ReleaseAccess( pReadAcc ); 605 606 if( bRet ) 607 { 608 const MapMode aMap( maPrefMapMode ); 609 const Size aSize( maPrefSize ); 610 611 *this = aNewBmp; 612 613 maPrefMapMode = aMap; 614 maPrefSize = aSize; 615 } 616 } 617 else 618 { 619 ReleaseAccess( pReadAcc ); 620 bRet = sal_True; 621 } 622 } 623 624 return bRet; 625 } 626 627 // ------------------------------------------------------------------------ 628 629 sal_Bool Bitmap::ImplConvertUp( sal_uInt16 nBitCount, Color* pExtColor ) 630 { 631 DBG_ASSERT( nBitCount > GetBitCount(), "New BitCount must be greater!" ); 632 633 BitmapReadAccess* pReadAcc = AcquireReadAccess(); 634 sal_Bool bRet = sal_False; 635 636 if( pReadAcc ) 637 { 638 BitmapPalette aPal; 639 Bitmap aNewBmp( GetSizePixel(), nBitCount, pReadAcc->HasPalette() ? &pReadAcc->GetPalette() : &aPal ); 640 BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess(); 641 642 if( pWriteAcc ) 643 { 644 const long nWidth = pWriteAcc->Width(); 645 const long nHeight = pWriteAcc->Height(); 646 647 if( pWriteAcc->HasPalette() ) 648 { 649 const sal_uInt16 nOldCount = 1 << GetBitCount(); 650 const BitmapPalette& rOldPal = pReadAcc->GetPalette(); 651 652 aPal.SetEntryCount( 1 << nBitCount ); 653 654 for( sal_uInt16 i = 0; i < nOldCount; i++ ) 655 aPal[ i ] = rOldPal[ i ]; 656 657 if( pExtColor ) 658 aPal[ aPal.GetEntryCount() - 1 ] = *pExtColor; 659 660 pWriteAcc->SetPalette( aPal ); 661 662 for( long nY = 0L; nY < nHeight; nY++ ) 663 for( long nX = 0L; nX < nWidth; nX++ ) 664 pWriteAcc->SetPixel( nY, nX, pReadAcc->GetPixel( nY, nX ) ); 665 } 666 else 667 { 668 if( pReadAcc->HasPalette() ) 669 { 670 for( long nY = 0L; nY < nHeight; nY++ ) 671 for( long nX = 0L; nX < nWidth; nX++ ) 672 pWriteAcc->SetPixel( nY, nX, pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nY, nX ) ) ); 673 } 674 else 675 { 676 for( long nY = 0L; nY < nHeight; nY++ ) 677 for( long nX = 0L; nX < nWidth; nX++ ) 678 pWriteAcc->SetPixel( nY, nX, pReadAcc->GetPixel( nY, nX ) ); 679 } 680 } 681 682 aNewBmp.ReleaseAccess( pWriteAcc ); 683 bRet = sal_True; 684 } 685 686 ReleaseAccess( pReadAcc ); 687 688 if( bRet ) 689 { 690 const MapMode aMap( maPrefMapMode ); 691 const Size aSize( maPrefSize ); 692 693 *this = aNewBmp; 694 695 maPrefMapMode = aMap; 696 maPrefSize = aSize; 697 } 698 } 699 700 return bRet; 701 } 702 703 // ------------------------------------------------------------------------ 704 705 sal_Bool Bitmap::ImplConvertDown( sal_uInt16 nBitCount, Color* pExtColor ) 706 { 707 DBG_ASSERT( nBitCount <= GetBitCount(), "New BitCount must be lower ( or equal when pExtColor is set )!" ); 708 709 BitmapReadAccess* pReadAcc = AcquireReadAccess(); 710 sal_Bool bRet = sal_False; 711 712 if( pReadAcc ) 713 { 714 BitmapPalette aPal; 715 Bitmap aNewBmp( GetSizePixel(), nBitCount, &aPal ); 716 BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess(); 717 718 if( pWriteAcc ) 719 { 720 const sal_uInt16 nCount = 1 << nBitCount; 721 const long nWidth = pWriteAcc->Width(); 722 const long nWidth1 = nWidth - 1L; 723 const long nHeight = pWriteAcc->Height(); 724 Octree aOctree( *pReadAcc, pExtColor ? ( nCount - 1 ) : nCount ); 725 InverseColorMap aColorMap( aPal = aOctree.GetPalette() ); 726 BitmapColor aColor; 727 ImpErrorQuad aErrQuad; 728 ImpErrorQuad* pErrQuad1 = new ImpErrorQuad[ nWidth ]; 729 ImpErrorQuad* pErrQuad2 = new ImpErrorQuad[ nWidth ]; 730 ImpErrorQuad* pQLine1 = pErrQuad1; 731 ImpErrorQuad* pQLine2 = 0; 732 long nX, nY; 733 long nYTmp = 0L; 734 sal_uInt8 cIndex; 735 sal_Bool bQ1 = sal_True; 736 737 if( pExtColor ) 738 { 739 aPal.SetEntryCount( aPal.GetEntryCount() + 1 ); 740 aPal[ aPal.GetEntryCount() - 1 ] = *pExtColor; 741 } 742 743 // set Black/White always, if we have enough space 744 if( aPal.GetEntryCount() < ( nCount - 1 ) ) 745 { 746 aPal.SetEntryCount( aPal.GetEntryCount() + 2 ); 747 aPal[ aPal.GetEntryCount() - 2 ] = Color( COL_BLACK ); 748 aPal[ aPal.GetEntryCount() - 1 ] = Color( COL_WHITE ); 749 } 750 751 pWriteAcc->SetPalette( aPal ); 752 753 for( nY = 0L; nY < Min( nHeight, 2L ); nY++, nYTmp++ ) 754 { 755 for( nX = 0L, pQLine2 = !nY ? pErrQuad1 : pErrQuad2; nX < nWidth; nX++ ) 756 { 757 if( pReadAcc->HasPalette() ) 758 pQLine2[ nX ] = pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nYTmp, nX ) ); 759 else 760 pQLine2[ nX ] = pReadAcc->GetPixel( nYTmp, nX ); 761 } 762 } 763 764 for( nY = 0L; nY < nHeight; nY++, nYTmp++ ) 765 { 766 // first pixel in the line 767 cIndex = (sal_uInt8) aColorMap.GetBestPaletteIndex( pQLine1[ 0 ].ImplGetColor() ); 768 pWriteAcc->SetPixelIndex( nY, 0, cIndex ); 769 770 for( nX = 1L; nX < nWidth1; nX++ ) 771 { 772 cIndex = (sal_uInt8) aColorMap.GetBestPaletteIndex( aColor = pQLine1[ nX ].ImplGetColor() ); 773 aErrQuad = ( ImpErrorQuad( aColor ) -= pWriteAcc->GetPaletteColor( cIndex ) ); 774 pQLine1[ ++nX ].ImplAddColorError7( aErrQuad ); 775 pQLine2[ nX-- ].ImplAddColorError1( aErrQuad ); 776 pQLine2[ nX-- ].ImplAddColorError5( aErrQuad ); 777 pQLine2[ nX++ ].ImplAddColorError3( aErrQuad ); 778 pWriteAcc->SetPixelIndex( nY, nX, cIndex ); 779 } 780 781 // letztes ZeilenPixel 782 if( nX < nWidth ) 783 { 784 cIndex = (sal_uInt8) aColorMap.GetBestPaletteIndex( pQLine1[ nWidth1 ].ImplGetColor() ); 785 pWriteAcc->SetPixelIndex( nY, nX, cIndex ); 786 } 787 788 // Zeilenpuffer neu fuellen/kopieren 789 pQLine1 = pQLine2; 790 pQLine2 = ( bQ1 = !bQ1 ) != sal_False ? pErrQuad2 : pErrQuad1; 791 792 if( nYTmp < nHeight ) 793 { 794 for( nX = 0L; nX < nWidth; nX++ ) 795 { 796 if( pReadAcc->HasPalette() ) 797 pQLine2[ nX ] = pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nYTmp, nX ) ); 798 else 799 pQLine2[ nX ] = pReadAcc->GetPixel( nYTmp, nX ); 800 } 801 } 802 } 803 804 // Zeilenpuffer zerstoeren 805 delete[] pErrQuad1; 806 delete[] pErrQuad2; 807 808 aNewBmp.ReleaseAccess( pWriteAcc ); 809 bRet = sal_True; 810 } 811 812 ReleaseAccess( pReadAcc ); 813 814 if( bRet ) 815 { 816 const MapMode aMap( maPrefMapMode ); 817 const Size aSize( maPrefSize ); 818 819 *this = aNewBmp; 820 821 maPrefMapMode = aMap; 822 maPrefSize = aSize; 823 } 824 } 825 826 return bRet; 827 } 828 829 // ------------------------------------------------------------------------ 830 831 sal_Bool Bitmap::ImplConvertGhosted() 832 { 833 Bitmap aNewBmp; 834 BitmapReadAccess* pR = AcquireReadAccess(); 835 sal_Bool bRet = sal_False; 836 837 if( pR ) 838 { 839 if( pR->HasPalette() ) 840 { 841 BitmapPalette aNewPal( pR->GetPaletteEntryCount() ); 842 843 for( long i = 0, nCount = aNewPal.GetEntryCount(); i < nCount; i++ ) 844 { 845 const BitmapColor& rOld = pR->GetPaletteColor( (sal_uInt16) i ); 846 aNewPal[ (sal_uInt16) i ] = BitmapColor( ( rOld.GetRed() >> 1 ) | 0x80, 847 ( rOld.GetGreen() >> 1 ) | 0x80, 848 ( rOld.GetBlue() >> 1 ) | 0x80 ); 849 } 850 851 aNewBmp = Bitmap( GetSizePixel(), GetBitCount(), &aNewPal ); 852 BitmapWriteAccess* pW = aNewBmp.AcquireWriteAccess(); 853 854 if( pW ) 855 { 856 pW->CopyBuffer( *pR ); 857 aNewBmp.ReleaseAccess( pW ); 858 bRet = sal_True; 859 } 860 } 861 else 862 { 863 aNewBmp = Bitmap( GetSizePixel(), 24 ); 864 865 BitmapWriteAccess* pW = aNewBmp.AcquireWriteAccess(); 866 867 if( pW ) 868 { 869 const long nWidth = pR->Width(), nHeight = pR->Height(); 870 871 for( long nY = 0; nY < nHeight; nY++ ) 872 { 873 for( long nX = 0; nX < nWidth; nX++ ) 874 { 875 const BitmapColor aOld( pR->GetPixel( nY, nX ) ); 876 pW->SetPixel( nY, nX, BitmapColor( ( aOld.GetRed() >> 1 ) | 0x80, 877 ( aOld.GetGreen() >> 1 ) | 0x80, 878 ( aOld.GetBlue() >> 1 ) | 0x80 ) ); 879 880 } 881 } 882 883 aNewBmp.ReleaseAccess( pW ); 884 bRet = sal_True; 885 } 886 } 887 888 ReleaseAccess( pR ); 889 } 890 891 if( bRet ) 892 { 893 const MapMode aMap( maPrefMapMode ); 894 const Size aSize( maPrefSize ); 895 896 *this = aNewBmp; 897 898 maPrefMapMode = aMap; 899 maPrefSize = aSize; 900 } 901 902 return bRet; 903 } 904 905 // ------------------------------------------------------------------------ 906 907 sal_Bool Bitmap::Scale( const double& rScaleX, const double& rScaleY, sal_uLong nScaleFlag ) 908 { 909 bool bRetval(false); 910 911 #ifdef DBG_UTIL 912 // #121233# allow to test the different scalers in debug build with source 913 // level debugger (change nNumber to desired action) 914 static sal_uInt16 nNumber(0); 915 const sal_uInt16 nStartCount(GetBitCount()); 916 917 switch(nNumber) 918 { 919 case 0 : break; 920 case 1: nScaleFlag = BMP_SCALE_FAST; break; 921 case 2: nScaleFlag = BMP_SCALE_INTERPOLATE; break; 922 case 3: nScaleFlag = BMP_SCALE_SUPER; break; 923 case 4: nScaleFlag = BMP_SCALE_LANCZOS; break; 924 case 5: nScaleFlag = BMP_SCALE_BICUBIC; break; 925 case 6: nScaleFlag = BMP_SCALE_BILINEAR; break; 926 case 7: nScaleFlag = BMP_SCALE_BOX; break; 927 case 8: nScaleFlag = BMP_SCALE_BESTQUALITY; break; 928 case 9: nScaleFlag = BMP_SCALE_FASTESTINTERPOLATE; break; 929 } 930 #endif // DBG_UTIL 931 932 if(basegfx::fTools::equalZero(rScaleX) && basegfx::fTools::equalZero(rScaleY)) 933 { 934 // no scale 935 bRetval = true; 936 } 937 else 938 { 939 if(BMP_SCALE_BESTQUALITY == nScaleFlag) 940 { 941 // Use LANCZOS when best quality is requested 942 nScaleFlag = BMP_SCALE_LANCZOS; 943 } 944 else if(BMP_SCALE_FASTESTINTERPOLATE == nScaleFlag) 945 { 946 // Use BMP_SCALE_SUPER when speed is requested, but not worst quality 947 nScaleFlag = BMP_SCALE_SUPER; 948 } 949 950 switch(nScaleFlag) 951 { 952 default: 953 case BMP_SCALE_NONE : 954 { 955 bRetval = false; 956 break; 957 } 958 case BMP_SCALE_FAST : 959 { 960 bRetval = ImplScaleFast( rScaleX, rScaleY ); 961 break; 962 } 963 case BMP_SCALE_INTERPOLATE : 964 { 965 bRetval = ImplScaleInterpolate( rScaleX, rScaleY ); 966 break; 967 } 968 case BMP_SCALE_SUPER : 969 { 970 if(GetSizePixel().Width() < 2 || GetSizePixel().Height() < 2) 971 { 972 // fallback to ImplScaleFast 973 bRetval = ImplScaleFast( rScaleX, rScaleY ); 974 } 975 else 976 { 977 // #121233# use method from symphony 978 bRetval = ImplScaleSuper( rScaleX, rScaleY ); 979 } 980 break; 981 } 982 case BMP_SCALE_LANCZOS : 983 { 984 const Lanczos3Kernel kernel; 985 986 bRetval = ImplScaleConvolution( rScaleX, rScaleY, kernel); 987 break; 988 } 989 case BMP_SCALE_BICUBIC : 990 { 991 const BicubicKernel kernel; 992 993 bRetval = ImplScaleConvolution( rScaleX, rScaleY, kernel ); 994 break; 995 } 996 case BMP_SCALE_BILINEAR : 997 { 998 const BilinearKernel kernel; 999 1000 bRetval = ImplScaleConvolution( rScaleX, rScaleY, kernel ); 1001 break; 1002 } 1003 case BMP_SCALE_BOX : 1004 { 1005 const BoxKernel kernel; 1006 1007 bRetval = ImplScaleConvolution( rScaleX, rScaleY, kernel ); 1008 break; 1009 } 1010 } 1011 } 1012 1013 #ifdef DBG_UTIL 1014 if(bRetval && nStartCount != GetBitCount()) 1015 { 1016 OSL_ENSURE(false, "Bitmap::Scale has changed the ColorDepth, this should *not* happen (!)"); 1017 } 1018 #endif 1019 1020 return bRetval; 1021 } 1022 1023 // ------------------------------------------------------------------------ 1024 1025 sal_Bool Bitmap::Scale( const Size& rNewSize, sal_uLong nScaleFlag ) 1026 { 1027 const Size aSize( GetSizePixel() ); 1028 sal_Bool bRet; 1029 1030 if( aSize.Width() && aSize.Height() ) 1031 { 1032 bRet = Scale( (double) rNewSize.Width() / aSize.Width(), 1033 (double) rNewSize.Height() / aSize.Height(), 1034 nScaleFlag ); 1035 } 1036 else 1037 bRet = sal_True; 1038 1039 return bRet; 1040 } 1041 1042 // ------------------------------------------------------------------------ 1043 1044 void Bitmap::AdaptBitCount(Bitmap& rNew) const 1045 { 1046 ImplAdaptBitCount(rNew); 1047 } 1048 1049 // ------------------------------------------------------------------------ 1050 1051 void Bitmap::ImplAdaptBitCount(Bitmap& rNew) const 1052 { 1053 // aNew is the result of some operation; adapt it's BitCount to the original (this) 1054 if(GetBitCount() != rNew.GetBitCount()) 1055 { 1056 switch(GetBitCount()) 1057 { 1058 case 1: 1059 { 1060 rNew.Convert(BMP_CONVERSION_1BIT_THRESHOLD); 1061 break; 1062 } 1063 case 4: 1064 { 1065 if(HasGreyPalette()) 1066 { 1067 rNew.Convert(BMP_CONVERSION_4BIT_GREYS); 1068 } 1069 else 1070 { 1071 rNew.Convert(BMP_CONVERSION_4BIT_COLORS); 1072 } 1073 break; 1074 } 1075 case 8: 1076 { 1077 if(HasGreyPalette()) 1078 { 1079 rNew.Convert(BMP_CONVERSION_8BIT_GREYS); 1080 } 1081 else 1082 { 1083 rNew.Convert(BMP_CONVERSION_8BIT_COLORS); 1084 } 1085 break; 1086 } 1087 case 24: 1088 { 1089 rNew.Convert(BMP_CONVERSION_24BIT); 1090 break; 1091 } 1092 default: 1093 { 1094 OSL_ENSURE(false, "BitDepth adaption failed (!)"); 1095 break; 1096 } 1097 } 1098 } 1099 } 1100 1101 // ------------------------------------------------------------------------ 1102 1103 sal_Bool Bitmap::ImplScaleFast( const double& rScaleX, const double& rScaleY ) 1104 { 1105 const Size aSizePix( GetSizePixel() ); 1106 const long nNewWidth = FRound( aSizePix.Width() * rScaleX ); 1107 const long nNewHeight = FRound( aSizePix.Height() * rScaleY ); 1108 sal_Bool bRet = sal_False; 1109 1110 if( nNewWidth && nNewHeight ) 1111 { 1112 BitmapReadAccess* pReadAcc = AcquireReadAccess(); 1113 if ( !pReadAcc ) 1114 return sal_False; 1115 1116 Bitmap aNewBmp( Size( nNewWidth, nNewHeight ), GetBitCount(), &pReadAcc->GetPalette() ); 1117 BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess(); 1118 1119 if( pWriteAcc ) 1120 { 1121 const long nScanlineSize = pWriteAcc->GetScanlineSize(); 1122 const long nNewWidth1 = nNewWidth - 1L; 1123 const long nNewHeight1 = nNewHeight - 1L; 1124 const long nWidth = pReadAcc->Width(); 1125 const long nHeight = pReadAcc->Height(); 1126 long* pLutX = new long[ nNewWidth ]; 1127 long* pLutY = new long[ nNewHeight ]; 1128 long nX, nY, nMapY, nActY = 0L; 1129 1130 if( nNewWidth1 && nNewHeight1 ) 1131 { 1132 for( nX = 0L; nX < nNewWidth; nX++ ) 1133 pLutX[ nX ] = nX * nWidth / nNewWidth; 1134 1135 for( nY = 0L; nY < nNewHeight; nY++ ) 1136 pLutY[ nY ] = nY * nHeight / nNewHeight; 1137 1138 while( nActY < nNewHeight ) 1139 { 1140 nMapY = pLutY[ nActY ]; 1141 1142 for( nX = 0L; nX < nNewWidth; nX++ ) 1143 pWriteAcc->SetPixel( nActY, nX, pReadAcc->GetPixel( nMapY , pLutX[ nX ] ) ); 1144 1145 while( ( nActY < nNewHeight1 ) && ( pLutY[ nActY + 1 ] == nMapY ) ) 1146 { 1147 memcpy( pWriteAcc->GetScanline( nActY + 1L ), 1148 pWriteAcc->GetScanline( nActY ), nScanlineSize ); 1149 nActY++; 1150 } 1151 1152 nActY++; 1153 } 1154 1155 bRet = sal_True; 1156 } 1157 1158 delete[] pLutX; 1159 delete[] pLutY; 1160 } 1161 1162 ReleaseAccess( pReadAcc ); 1163 aNewBmp.ReleaseAccess( pWriteAcc ); 1164 1165 if( bRet ) 1166 ImplAssignWithSize( aNewBmp ); 1167 } 1168 1169 return bRet; 1170 } 1171 1172 // ------------------------------------------------------------------------ 1173 1174 sal_Bool Bitmap::ImplScaleInterpolate( const double& rScaleX, const double& rScaleY ) 1175 { 1176 const Size aSizePix( GetSizePixel() ); 1177 const long nNewWidth = FRound( aSizePix.Width() * rScaleX ); 1178 const long nNewHeight = FRound( aSizePix.Height() * rScaleY ); 1179 sal_Bool bRet = sal_False; 1180 1181 if( ( nNewWidth > 1L ) && ( nNewHeight > 1L ) ) 1182 { 1183 BitmapColor aCol0; 1184 BitmapColor aCol1; 1185 BitmapReadAccess* pReadAcc = AcquireReadAccess(); 1186 long nWidth = pReadAcc->Width(); 1187 long nHeight = pReadAcc->Height(); 1188 Bitmap aNewBmp( Size( nNewWidth, nHeight ), 24 ); 1189 BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess(); 1190 long* pLutInt; 1191 long* pLutFrac; 1192 long nX, nY; 1193 long lXB0, lXB1, lXG0, lXG1, lXR0, lXR1; 1194 double fTemp; 1195 long nTemp; 1196 1197 if( pReadAcc && pWriteAcc ) 1198 { 1199 const long nNewWidth1 = nNewWidth - 1L; 1200 const long nWidth1 = pReadAcc->Width() - 1L; 1201 const double fRevScaleX = (double) nWidth1 / nNewWidth1; 1202 1203 pLutInt = new long[ nNewWidth ]; 1204 pLutFrac = new long[ nNewWidth ]; 1205 1206 for( nX = 0L, nTemp = nWidth - 2L; nX < nNewWidth; nX++ ) 1207 { 1208 fTemp = nX * fRevScaleX; 1209 pLutInt[ nX ] = MinMax( (long) fTemp, 0, nTemp ); 1210 fTemp -= pLutInt[ nX ]; 1211 pLutFrac[ nX ] = (long) ( fTemp * 1024. ); 1212 } 1213 1214 for( nY = 0L; nY < nHeight; nY++ ) 1215 { 1216 if( 1 == nWidth ) 1217 { 1218 if( pReadAcc->HasPalette() ) 1219 { 1220 aCol0 = pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nY, 0 ) ); 1221 } 1222 else 1223 { 1224 aCol0 = pReadAcc->GetPixel( nY, 0 ); 1225 } 1226 1227 for( nX = 0L; nX < nNewWidth; nX++ ) 1228 { 1229 pWriteAcc->SetPixel( nY, nX, aCol0 ); 1230 } 1231 } 1232 else 1233 { 1234 for( nX = 0L; nX < nNewWidth; nX++ ) 1235 { 1236 nTemp = pLutInt[ nX ]; 1237 1238 if( pReadAcc->HasPalette() ) 1239 { 1240 aCol0 = pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nY, nTemp++ ) ); 1241 aCol1 = pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nY, nTemp ) ); 1242 } 1243 else 1244 { 1245 aCol0 = pReadAcc->GetPixel( nY, nTemp++ ); 1246 aCol1 = pReadAcc->GetPixel( nY, nTemp ); 1247 } 1248 1249 nTemp = pLutFrac[ nX ]; 1250 1251 lXR1 = aCol1.GetRed() - ( lXR0 = aCol0.GetRed() ); 1252 lXG1 = aCol1.GetGreen() - ( lXG0 = aCol0.GetGreen() ); 1253 lXB1 = aCol1.GetBlue() - ( lXB0 = aCol0.GetBlue() ); 1254 1255 aCol0.SetRed( (sal_uInt8) ( ( lXR1 * nTemp + ( lXR0 << 10 ) ) >> 10 ) ); 1256 aCol0.SetGreen( (sal_uInt8) ( ( lXG1 * nTemp + ( lXG0 << 10 ) ) >> 10 ) ); 1257 aCol0.SetBlue( (sal_uInt8) ( ( lXB1 * nTemp + ( lXB0 << 10 ) ) >> 10 ) ); 1258 1259 pWriteAcc->SetPixel( nY, nX, aCol0 ); 1260 } 1261 } 1262 } 1263 1264 delete[] pLutInt; 1265 delete[] pLutFrac; 1266 bRet = sal_True; 1267 } 1268 1269 ReleaseAccess( pReadAcc ); 1270 aNewBmp.ReleaseAccess( pWriteAcc ); 1271 1272 if( bRet ) 1273 { 1274 bRet = sal_False; 1275 const Bitmap aOriginal(*this); 1276 *this = aNewBmp; 1277 aNewBmp = Bitmap( Size( nNewWidth, nNewHeight ), 24 ); 1278 pReadAcc = AcquireReadAccess(); 1279 pWriteAcc = aNewBmp.AcquireWriteAccess(); 1280 1281 if( pReadAcc && pWriteAcc ) 1282 { 1283 const long nNewHeight1 = nNewHeight - 1L; 1284 const long nHeight1 = pReadAcc->Height() - 1L; 1285 const double fRevScaleY = (double) nHeight1 / nNewHeight1; 1286 1287 pLutInt = new long[ nNewHeight ]; 1288 pLutFrac = new long[ nNewHeight ]; 1289 1290 for( nY = 0L, nTemp = nHeight - 2L; nY < nNewHeight; nY++ ) 1291 { 1292 fTemp = nY * fRevScaleY; 1293 pLutInt[ nY ] = MinMax( (long) fTemp, 0, nTemp ); 1294 fTemp -= pLutInt[ nY ]; 1295 pLutFrac[ nY ] = (long) ( fTemp * 1024. ); 1296 } 1297 1298 // after 1st step, bitmap *is* 24bit format (see above) 1299 OSL_ENSURE(!pReadAcc->HasPalette(), "OOps, somehow ImplScaleInterpolate in-between format has palette, should not happen (!)"); 1300 1301 for( nX = 0L; nX < nNewWidth; nX++ ) 1302 { 1303 if( 1 == nHeight ) 1304 { 1305 aCol0 = pReadAcc->GetPixel( 0, nX ); 1306 1307 for( nY = 0L; nY < nNewHeight; nY++ ) 1308 { 1309 pWriteAcc->SetPixel( nY, nX, aCol0 ); 1310 } 1311 } 1312 else 1313 { 1314 for( nY = 0L; nY < nNewHeight; nY++ ) 1315 { 1316 nTemp = pLutInt[ nY ]; 1317 1318 aCol0 = pReadAcc->GetPixel( nTemp++, nX ); 1319 aCol1 = pReadAcc->GetPixel( nTemp, nX ); 1320 1321 nTemp = pLutFrac[ nY ]; 1322 1323 lXR1 = aCol1.GetRed() - ( lXR0 = aCol0.GetRed() ); 1324 lXG1 = aCol1.GetGreen() - ( lXG0 = aCol0.GetGreen() ); 1325 lXB1 = aCol1.GetBlue() - ( lXB0 = aCol0.GetBlue() ); 1326 1327 aCol0.SetRed( (sal_uInt8) ( ( lXR1 * nTemp + ( lXR0 << 10 ) ) >> 10 ) ); 1328 aCol0.SetGreen( (sal_uInt8) ( ( lXG1 * nTemp + ( lXG0 << 10 ) ) >> 10 ) ); 1329 aCol0.SetBlue( (sal_uInt8) ( ( lXB1 * nTemp + ( lXB0 << 10 ) ) >> 10 ) ); 1330 1331 pWriteAcc->SetPixel( nY, nX, aCol0 ); 1332 } 1333 } 1334 } 1335 1336 delete[] pLutInt; 1337 delete[] pLutFrac; 1338 bRet = sal_True; 1339 } 1340 1341 ReleaseAccess( pReadAcc ); 1342 aNewBmp.ReleaseAccess( pWriteAcc ); 1343 1344 if( bRet ) 1345 { 1346 aOriginal.ImplAdaptBitCount(aNewBmp); 1347 *this = aNewBmp; 1348 } 1349 } 1350 } 1351 1352 if( !bRet ) 1353 { 1354 bRet = ImplScaleFast( rScaleX, rScaleY ); 1355 } 1356 1357 return bRet; 1358 } 1359 1360 // ------------------------------------------------------------------------ 1361 // #121233# Added BMP_SCALE_SUPER from symphony code 1362 1363 sal_Bool Bitmap::ImplScaleSuper( 1364 const double& rScaleX, 1365 const double& rScaleY ) 1366 { 1367 const Size aSizePix( GetSizePixel() ); 1368 bool bHMirr = ( rScaleX < 0 ); 1369 bool bVMirr = ( rScaleY < 0 ); 1370 double scaleX = bHMirr ? -rScaleX : rScaleX; 1371 double scaleY = bVMirr ? -rScaleY : rScaleY; 1372 const long nDstW = FRound( aSizePix.Width() * scaleX ); 1373 const long nDstH = FRound( aSizePix.Height() * scaleY ); 1374 const double fScaleThresh = 0.6; 1375 bool bRet = false; 1376 1377 if( ( nDstW > 1L ) && ( nDstH > 1L ) ) 1378 { 1379 BitmapColor aCol0, aCol1, aColRes; 1380 BitmapReadAccess* pAcc = AcquireReadAccess(); 1381 long nW = pAcc->Width() ; 1382 long nH = pAcc->Height() ; 1383 Bitmap aOutBmp( Size( nDstW, nDstH ), 24 ); 1384 BitmapWriteAccess* pWAcc = aOutBmp.AcquireWriteAccess(); 1385 long* pMapIX = new long[ nDstW ]; 1386 long* pMapIY = new long[ nDstH ]; 1387 long* pMapFX = new long[ nDstW ]; 1388 long* pMapFY = new long[ nDstH ]; 1389 long nX, nY, nXDst, nYDst;; 1390 double fTemp; 1391 long nTemp , nTempX, nTempY, nTempFX, nTempFY; 1392 sal_uInt8 cR0, cG0, cB0, cR1, cG1, cB1; 1393 long nStartX = 0 , nStartY = 0; 1394 long nEndX = nDstW - 1L; 1395 long nEndY = nDstH - 1L; 1396 long nMax = 1 << 7L; 1397 1398 if( pAcc && pWAcc ) 1399 { 1400 const double fRevScaleX = ( nDstW > 1L ) ? ( (double) ( nW - 1 ) / ( nDstW - 1 ) ) : 0.0; 1401 const double fRevScaleY = ( nDstH > 1L ) ? ( (double) ( nH - 1 ) / ( nDstH - 1 ) ) : 0.0; 1402 1403 // create horizontal mapping table 1404 for( nX = 0L, nTempX = nW - 1L, nTemp = nW - 2L; nX < nDstW; nX++ ) 1405 { 1406 fTemp = nX * fRevScaleX; 1407 1408 if( bHMirr ) 1409 fTemp = nTempX - fTemp; 1410 1411 pMapFX[ nX ] = (long) ( ( fTemp - ( pMapIX[ nX ] = MinMax( (long) fTemp, 0, nTemp ) ) ) * 128. ); 1412 } 1413 1414 // create vertical mapping table 1415 for( nY = 0L, nTempY = nH - 1L, nTemp = nH - 2L; nY < nDstH; nY++ ) 1416 { 1417 fTemp = nY * fRevScaleY; 1418 1419 if( bVMirr ) 1420 fTemp = nTempY - fTemp; 1421 1422 pMapFY[ nY ] = (long) ( ( fTemp - ( pMapIY[ nY ] = MinMax( (long) fTemp, 0, nTemp ) ) ) * 128. ); 1423 } 1424 1425 if( pAcc->HasPalette() ) 1426 { 1427 if( pAcc->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL ) 1428 { 1429 if( scaleX >= fScaleThresh && scaleY >= fScaleThresh ) 1430 { 1431 Scanline pLine0, pLine1; 1432 1433 for( nY = nStartY, nYDst = 0L; nY <= nEndY; nY++, nYDst++ ) 1434 { 1435 nTempY = pMapIY[ nY ]; nTempFY = pMapFY[ nY ]; 1436 pLine0 = pAcc->GetScanline( nTempY ); 1437 pLine1 = pAcc->GetScanline( ++nTempY ); 1438 1439 for( nX = nStartX, nXDst = 0L; nX <= nEndX; nX++ ) 1440 { 1441 nTempX = pMapIX[ nX ]; nTempFX = pMapFX[ nX ]; 1442 1443 const BitmapColor& rCol0 = pAcc->GetPaletteColor( pLine0[ nTempX ] ); 1444 const BitmapColor& rCol2 = pAcc->GetPaletteColor( pLine1[ nTempX ] ); 1445 const BitmapColor& rCol1 = pAcc->GetPaletteColor( pLine0[ ++nTempX ] ); 1446 const BitmapColor& rCol3 = pAcc->GetPaletteColor( pLine1[ nTempX ] ); 1447 1448 cR0 = MAP( rCol0.GetRed(), rCol1.GetRed(), nTempFX ); 1449 cG0 = MAP( rCol0.GetGreen(), rCol1.GetGreen(), nTempFX ); 1450 cB0 = MAP( rCol0.GetBlue(), rCol1.GetBlue(), nTempFX ); 1451 1452 cR1 = MAP( rCol2.GetRed(), rCol3.GetRed(), nTempFX ); 1453 cG1 = MAP( rCol2.GetGreen(), rCol3.GetGreen(), nTempFX ); 1454 cB1 = MAP( rCol2.GetBlue(), rCol3.GetBlue(), nTempFX ); 1455 1456 aColRes.SetRed( MAP( cR0, cR1, nTempFY ) ); 1457 aColRes.SetGreen( MAP( cG0, cG1, nTempFY ) ); 1458 aColRes.SetBlue( MAP( cB0, cB1, nTempFY ) ); 1459 pWAcc->SetPixel( nYDst, nXDst++, aColRes ); 1460 } 1461 } 1462 } 1463 else 1464 { 1465 Scanline pTmpY; 1466 long nSumR, nSumG, nSumB,nLineStart , nLineRange, nRowStart , nRowRange ; 1467 long nLeft, nRight, nTop, nBottom, nWeightX, nWeightY ; 1468 long nSumRowR ,nSumRowG,nSumRowB, nTotalWeightX, nTotalWeightY; 1469 1470 for( nY = nStartY , nYDst = 0L; nY <= nEndY; nY++, nYDst++ ) 1471 { 1472 nTop = bVMirr ? ( nY + 1 ) : nY; 1473 nBottom = bVMirr ? nY : ( nY + 1 ) ; 1474 1475 if( nY ==nEndY ) 1476 { 1477 nLineStart = pMapIY[ nY ]; 1478 nLineRange = 0; 1479 } 1480 else 1481 { 1482 nLineStart = pMapIY[ nTop ] ; 1483 nLineRange = ( pMapIY[ nBottom ] == pMapIY[ nTop ] ) ? 1 :( pMapIY[ nBottom ] - pMapIY[ nTop ] ); 1484 } 1485 1486 for( nX = nStartX , nXDst = 0L; nX <= nEndX; nX++ ) 1487 { 1488 nLeft = bHMirr ? ( nX + 1 ) : nX; 1489 nRight = bHMirr ? nX : ( nX + 1 ) ; 1490 1491 if( nX == nEndX ) 1492 { 1493 nRowStart = pMapIX[ nX ]; 1494 nRowRange = 0; 1495 } 1496 else 1497 { 1498 nRowStart = pMapIX[ nLeft ]; 1499 nRowRange = ( pMapIX[ nRight ] == pMapIX[ nLeft ] )? 1 : ( pMapIX[ nRight ] - pMapIX[ nLeft ] ); 1500 } 1501 1502 nSumR = nSumG = nSumB = 0; 1503 nTotalWeightY = 0; 1504 1505 for(int i = 0; i<= nLineRange; i++) 1506 { 1507 pTmpY = pAcc->GetScanline( nLineStart + i ); 1508 nSumRowR = nSumRowG = nSumRowB = 0; 1509 nTotalWeightX = 0; 1510 1511 for(int j = 0; j <= nRowRange; j++) 1512 { 1513 const BitmapColor& rCol = pAcc->GetPaletteColor( pTmpY[ nRowStart + j ] ); 1514 1515 if(nX == nEndX ) 1516 { 1517 nSumRowB += rCol.GetBlue() << 7L; 1518 nSumRowG += rCol.GetGreen() << 7L; 1519 nSumRowR += rCol.GetRed() << 7L; 1520 nTotalWeightX += 1 << 7L; 1521 } 1522 else if( j == 0 ) 1523 { 1524 nWeightX = (nMax- pMapFX[ nLeft ]) ; 1525 nSumRowB += ( nWeightX *rCol.GetBlue()) ; 1526 nSumRowG += ( nWeightX *rCol.GetGreen()) ; 1527 nSumRowR += ( nWeightX *rCol.GetRed()) ; 1528 nTotalWeightX += nWeightX; 1529 } 1530 else if ( nRowRange == j ) 1531 { 1532 nWeightX = pMapFX[ nRight ] ; 1533 nSumRowB += ( nWeightX *rCol.GetBlue() ); 1534 nSumRowG += ( nWeightX *rCol.GetGreen() ); 1535 nSumRowR += ( nWeightX *rCol.GetRed() ); 1536 nTotalWeightX += nWeightX; 1537 } 1538 else 1539 { 1540 nSumRowB += rCol.GetBlue() << 7L; 1541 nSumRowG += rCol.GetGreen() << 7L; 1542 nSumRowR += rCol.GetRed() << 7L; 1543 nTotalWeightX += 1 << 7L; 1544 } 1545 } 1546 1547 if( nY == nEndY ) 1548 nWeightY = nMax; 1549 else if( i == 0 ) 1550 nWeightY = nMax - pMapFY[ nTop ]; 1551 else if( nLineRange == 1 ) 1552 nWeightY = pMapFY[ nTop ]; 1553 else if ( nLineRange == i ) 1554 nWeightY = pMapFY[ nBottom ]; 1555 else 1556 nWeightY = nMax; 1557 1558 nWeightY = nWeightY ; 1559 nSumB += nWeightY * ( nSumRowB / nTotalWeightX ); 1560 nSumG += nWeightY * ( nSumRowG / nTotalWeightX ); 1561 nSumR += nWeightY * ( nSumRowR / nTotalWeightX ); 1562 nTotalWeightY += nWeightY; 1563 } 1564 1565 aColRes.SetRed( ( sal_uInt8 ) (( nSumR / nTotalWeightY ) )); 1566 aColRes.SetGreen( ( sal_uInt8 ) (( nSumG / nTotalWeightY) )); 1567 aColRes.SetBlue( ( sal_uInt8 ) (( nSumB / nTotalWeightY ) )); 1568 pWAcc->SetPixel( nYDst, nXDst++, aColRes ); 1569 1570 } 1571 } 1572 } 1573 } 1574 else 1575 { 1576 if( scaleX >= fScaleThresh && scaleY >= fScaleThresh ) 1577 { 1578 for( nY = nStartY, nYDst = 0L; nY <= nEndY; nY++, nYDst++ ) 1579 { 1580 nTempY = pMapIY[ nY ], nTempFY = pMapFY[ nY ]; 1581 1582 for( nX = nStartX, nXDst = 0L; nX <= nEndX; nX++ ) 1583 { 1584 nTempX = pMapIX[ nX ]; nTempFX = pMapFX[ nX ]; 1585 1586 aCol0 = pAcc->GetPaletteColor( pAcc->GetPixelIndex( nTempY, nTempX ) ); 1587 aCol1 = pAcc->GetPaletteColor( pAcc->GetPixelIndex( nTempY, ++nTempX ) ); 1588 cR0 = MAP( aCol0.GetRed(), aCol1.GetRed(), nTempFX ); 1589 cG0 = MAP( aCol0.GetGreen(), aCol1.GetGreen(), nTempFX ); 1590 cB0 = MAP( aCol0.GetBlue(), aCol1.GetBlue(), nTempFX ); 1591 1592 aCol1 = pAcc->GetPaletteColor( pAcc->GetPixelIndex( ++nTempY, nTempX ) ); 1593 aCol0 = pAcc->GetPaletteColor( pAcc->GetPixelIndex( nTempY--, --nTempX ) ); 1594 cR1 = MAP( aCol0.GetRed(), aCol1.GetRed(), nTempFX ); 1595 cG1 = MAP( aCol0.GetGreen(), aCol1.GetGreen(), nTempFX ); 1596 cB1 = MAP( aCol0.GetBlue(), aCol1.GetBlue(), nTempFX ); 1597 1598 aColRes.SetRed( MAP( cR0, cR1, nTempFY ) ); 1599 aColRes.SetGreen( MAP( cG0, cG1, nTempFY ) ); 1600 aColRes.SetBlue( MAP( cB0, cB1, nTempFY ) ); 1601 pWAcc->SetPixel( nYDst, nXDst++, aColRes ); 1602 } 1603 } 1604 1605 } 1606 else 1607 { 1608 long nSumR, nSumG, nSumB,nLineStart , nLineRange, nRowStart , nRowRange ; 1609 long nLeft, nRight, nTop, nBottom, nWeightX, nWeightY ; 1610 long nSumRowR ,nSumRowG,nSumRowB, nTotalWeightX, nTotalWeightY; 1611 1612 for( nY = nStartY , nYDst = 0L; nY <= nEndY; nY++, nYDst++ ) 1613 { 1614 nTop = bVMirr ? ( nY + 1 ) : nY; 1615 nBottom = bVMirr ? nY : ( nY + 1 ) ; 1616 1617 if( nY ==nEndY ) 1618 { 1619 nLineStart = pMapIY[ nY ]; 1620 nLineRange = 0; 1621 } 1622 else 1623 { 1624 nLineStart = pMapIY[ nTop ] ; 1625 nLineRange = ( pMapIY[ nBottom ] == pMapIY[ nTop ] ) ? 1 :( pMapIY[ nBottom ] - pMapIY[ nTop ] ); 1626 } 1627 1628 for( nX = nStartX , nXDst = 0L; nX <= nEndX; nX++ ) 1629 { 1630 nLeft = bHMirr ? ( nX + 1 ) : nX; 1631 nRight = bHMirr ? nX : ( nX + 1 ) ; 1632 1633 if( nX == nEndX ) 1634 { 1635 nRowStart = pMapIX[ nX ]; 1636 nRowRange = 0; 1637 } 1638 else 1639 { 1640 nRowStart = pMapIX[ nLeft ]; 1641 nRowRange = ( pMapIX[ nRight ] == pMapIX[ nLeft ] )? 1 : ( pMapIX[ nRight ] - pMapIX[ nLeft ] ); 1642 } 1643 1644 nSumR = nSumG = nSumB = 0; 1645 nTotalWeightY = 0; 1646 1647 for(int i = 0; i<= nLineRange; i++) 1648 { 1649 nSumRowR = nSumRowG = nSumRowB = 0; 1650 nTotalWeightX = 0; 1651 1652 for(int j = 0; j <= nRowRange; j++) 1653 { 1654 aCol0 = pAcc->GetPaletteColor ( pAcc->GetPixelIndex( nLineStart + i, nRowStart + j ) ); 1655 1656 if(nX == nEndX ) 1657 { 1658 1659 nSumRowB += aCol0.GetBlue() << 7L; 1660 nSumRowG += aCol0.GetGreen() << 7L; 1661 nSumRowR += aCol0.GetRed() << 7L; 1662 nTotalWeightX += 1 << 7L; 1663 } 1664 else if( j == 0 ) 1665 { 1666 1667 nWeightX = (nMax- pMapFX[ nLeft ]) ; 1668 nSumRowB += ( nWeightX *aCol0.GetBlue()) ; 1669 nSumRowG += ( nWeightX *aCol0.GetGreen()) ; 1670 nSumRowR += ( nWeightX *aCol0.GetRed()) ; 1671 nTotalWeightX += nWeightX; 1672 } 1673 else if ( nRowRange == j ) 1674 { 1675 1676 nWeightX = pMapFX[ nRight ] ; 1677 nSumRowB += ( nWeightX *aCol0.GetBlue() ); 1678 nSumRowG += ( nWeightX *aCol0.GetGreen() ); 1679 nSumRowR += ( nWeightX *aCol0.GetRed() ); 1680 nTotalWeightX += nWeightX; 1681 } 1682 else 1683 { 1684 1685 nSumRowB += aCol0.GetBlue() << 7L; 1686 nSumRowG += aCol0.GetGreen() << 7L; 1687 nSumRowR += aCol0.GetRed() << 7L; 1688 nTotalWeightX += 1 << 7L; 1689 } 1690 } 1691 1692 if( nY == nEndY ) 1693 nWeightY = nMax; 1694 else if( i == 0 ) 1695 nWeightY = nMax - pMapFY[ nTop ]; 1696 else if( nLineRange == 1 ) 1697 nWeightY = pMapFY[ nTop ]; 1698 else if ( nLineRange == i ) 1699 nWeightY = pMapFY[ nBottom ]; 1700 else 1701 nWeightY = nMax; 1702 1703 nWeightY = nWeightY ; 1704 nSumB += nWeightY * ( nSumRowB / nTotalWeightX ); 1705 nSumG += nWeightY * ( nSumRowG / nTotalWeightX ); 1706 nSumR += nWeightY * ( nSumRowR / nTotalWeightX ); 1707 nTotalWeightY += nWeightY; 1708 } 1709 1710 aColRes.SetRed( ( sal_uInt8 ) (( nSumR / nTotalWeightY ) )); 1711 aColRes.SetGreen( ( sal_uInt8 ) (( nSumG / nTotalWeightY) )); 1712 aColRes.SetBlue( ( sal_uInt8 ) (( nSumB / nTotalWeightY ) )); 1713 pWAcc->SetPixel( nYDst, nXDst++, aColRes ); 1714 } 1715 } 1716 } 1717 } 1718 } 1719 else 1720 { 1721 if( pAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_BGR ) 1722 { 1723 if( scaleX >= fScaleThresh && scaleY >= fScaleThresh ) 1724 { 1725 Scanline pLine0, pLine1, pTmp0, pTmp1; 1726 long nOff; 1727 1728 for( nY = nStartY, nYDst = 0L; nY <= nEndY; nY++, nYDst++ ) 1729 { 1730 nTempY = pMapIY[ nY ]; nTempFY = pMapFY[ nY ]; 1731 pLine0 = pAcc->GetScanline( nTempY ); 1732 pLine1 = pAcc->GetScanline( ++nTempY ); 1733 1734 for( nX = nStartX, nXDst = 0L; nX <= nEndX; nX++ ) 1735 { 1736 nOff = 3L * ( nTempX = pMapIX[ nX ] ); 1737 nTempFX = pMapFX[ nX ]; 1738 1739 pTmp1 = ( pTmp0 = pLine0 + nOff ) + 3L; 1740 cB0 = MAP( *pTmp0, *pTmp1, nTempFX ); pTmp0++; pTmp1++; 1741 cG0 = MAP( *pTmp0, *pTmp1, nTempFX ); pTmp0++; pTmp1++; 1742 cR0 = MAP( *pTmp0, *pTmp1, nTempFX ); 1743 1744 pTmp1 = ( pTmp0 = pLine1 + nOff ) + 3L; 1745 cB1 = MAP( *pTmp0, *pTmp1, nTempFX ); pTmp0++; pTmp1++; 1746 cG1 = MAP( *pTmp0, *pTmp1, nTempFX ); pTmp0++; pTmp1++; 1747 cR1 = MAP( *pTmp0, *pTmp1, nTempFX ); 1748 1749 aColRes.SetRed( MAP( cR0, cR1, nTempFY ) ); 1750 aColRes.SetGreen( MAP( cG0, cG1, nTempFY ) ); 1751 aColRes.SetBlue( MAP( cB0, cB1, nTempFY ) ); 1752 pWAcc->SetPixel( nYDst, nXDst++, aColRes ); 1753 } 1754 } 1755 } 1756 else 1757 { 1758 Scanline pTmpY, pTmpX; 1759 long nSumR, nSumG, nSumB,nLineStart , nLineRange, nRowStart , nRowRange ; 1760 long nLeft, nRight, nTop, nBottom, nWeightX, nWeightY ; 1761 long nSumRowR ,nSumRowG,nSumRowB, nTotalWeightX, nTotalWeightY; 1762 1763 for( nY = nStartY , nYDst = 0L; nY <= nEndY; nY++, nYDst++ ) 1764 { 1765 nTop = bVMirr ? ( nY + 1 ) : nY; 1766 nBottom = bVMirr ? nY : ( nY + 1 ) ; 1767 1768 if( nY ==nEndY ) 1769 { 1770 nLineStart = pMapIY[ nY ]; 1771 nLineRange = 0; 1772 } 1773 else 1774 { 1775 nLineStart = pMapIY[ nTop ] ; 1776 nLineRange = ( pMapIY[ nBottom ] == pMapIY[ nTop ] ) ? 1 :( pMapIY[ nBottom ] - pMapIY[ nTop ] ); 1777 } 1778 1779 for( nX = nStartX , nXDst = 0L; nX <= nEndX; nX++ ) 1780 { 1781 nLeft = bHMirr ? ( nX + 1 ) : nX; 1782 nRight = bHMirr ? nX : ( nX + 1 ) ; 1783 1784 if( nX == nEndX ) 1785 { 1786 nRowStart = pMapIX[ nX ]; 1787 nRowRange = 0; 1788 } 1789 else 1790 { 1791 nRowStart = pMapIX[ nLeft ]; 1792 nRowRange = ( pMapIX[ nRight ] == pMapIX[ nLeft ] )? 1 : ( pMapIX[ nRight ] - pMapIX[ nLeft ] ); 1793 } 1794 1795 nSumR = nSumG = nSumB = 0; 1796 nTotalWeightY = 0; 1797 1798 for(int i = 0; i<= nLineRange; i++) 1799 { 1800 pTmpY = pAcc->GetScanline( nLineStart + i ); 1801 pTmpX = pTmpY + 3L * nRowStart; 1802 nSumRowR = nSumRowG = nSumRowB = 0; 1803 nTotalWeightX = 0; 1804 1805 for(int j = 0; j <= nRowRange; j++) 1806 { 1807 if(nX == nEndX ) 1808 { 1809 nSumRowB += ( *pTmpX ) << 7L;pTmpX++; 1810 nSumRowG += ( *pTmpX ) << 7L;pTmpX++; 1811 nSumRowR += ( *pTmpX ) << 7L;pTmpX++; 1812 nTotalWeightX += 1 << 7L; 1813 } 1814 else if( j == 0 ) 1815 { 1816 nWeightX = (nMax- pMapFX[ nLeft ]) ; 1817 nSumRowB += ( nWeightX *( *pTmpX )) ;pTmpX++; 1818 nSumRowG += ( nWeightX *( *pTmpX )) ;pTmpX++; 1819 nSumRowR += ( nWeightX *( *pTmpX )) ;pTmpX++; 1820 nTotalWeightX += nWeightX; 1821 } 1822 else if ( nRowRange == j ) 1823 { 1824 nWeightX = pMapFX[ nRight ] ; 1825 nSumRowB += ( nWeightX *( *pTmpX ) );pTmpX++; 1826 nSumRowG += ( nWeightX *( *pTmpX ) );pTmpX++; 1827 nSumRowR += ( nWeightX *( *pTmpX ) );pTmpX++; 1828 nTotalWeightX += nWeightX; 1829 } 1830 else 1831 { 1832 nSumRowB += ( *pTmpX ) << 7L;pTmpX++; 1833 nSumRowG += ( *pTmpX ) << 7L;pTmpX++; 1834 nSumRowR += ( *pTmpX ) << 7L;pTmpX++; 1835 nTotalWeightX += 1 << 7L; 1836 } 1837 } 1838 1839 if( nY == nEndY ) 1840 nWeightY = nMax; 1841 else if( i == 0 ) 1842 nWeightY = nMax - pMapFY[ nTop ]; 1843 else if( nLineRange == 1 ) 1844 nWeightY = pMapFY[ nTop ]; 1845 else if ( nLineRange == i ) 1846 nWeightY = pMapFY[ nBottom ]; 1847 else 1848 nWeightY = nMax; 1849 1850 nWeightY = nWeightY ; 1851 nSumB += nWeightY * ( nSumRowB / nTotalWeightX ); 1852 nSumG += nWeightY * ( nSumRowG / nTotalWeightX ); 1853 nSumR += nWeightY * ( nSumRowR / nTotalWeightX ); 1854 nTotalWeightY += nWeightY; 1855 } 1856 1857 aColRes.SetRed( ( sal_uInt8 ) (( nSumR / nTotalWeightY ) )); 1858 aColRes.SetGreen( ( sal_uInt8 ) (( nSumG / nTotalWeightY) )); 1859 aColRes.SetBlue( ( sal_uInt8 ) (( nSumB / nTotalWeightY ) )); 1860 pWAcc->SetPixel( nYDst, nXDst++, aColRes ); 1861 1862 } 1863 } 1864 } 1865 } 1866 else if( pAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_RGB ) 1867 { 1868 if( scaleX >= fScaleThresh && scaleY >= fScaleThresh ) 1869 { 1870 Scanline pLine0, pLine1, pTmp0, pTmp1; 1871 long nOff; 1872 1873 for( nY = nStartY, nYDst = 0L; nY <= nEndY; nY++, nYDst++ ) 1874 { 1875 nTempY = pMapIY[ nY ]; nTempFY = pMapFY[ nY ]; 1876 pLine0 = pAcc->GetScanline( nTempY ); 1877 pLine1 = pAcc->GetScanline( ++nTempY ); 1878 1879 for( nX = nStartX, nXDst = 0L; nX <= nEndX; nX++ ) 1880 { 1881 nOff = 3L * ( nTempX = pMapIX[ nX ] ); 1882 nTempFX = pMapFX[ nX ]; 1883 1884 pTmp1 = ( pTmp0 = pLine0 + nOff ) + 3L; 1885 cR0 = MAP( *pTmp0, *pTmp1, nTempFX ); pTmp0++; pTmp1++; 1886 cG0 = MAP( *pTmp0, *pTmp1, nTempFX ); pTmp0++; pTmp1++; 1887 cB0 = MAP( *pTmp0, *pTmp1, nTempFX ); 1888 1889 pTmp1 = ( pTmp0 = pLine1 + nOff ) + 3L; 1890 cR1 = MAP( *pTmp0, *pTmp1, nTempFX ); pTmp0++; pTmp1++; 1891 cG1 = MAP( *pTmp0, *pTmp1, nTempFX ); pTmp0++; pTmp1++; 1892 cB1 = MAP( *pTmp0, *pTmp1, nTempFX ); 1893 1894 aColRes.SetRed( MAP( cR0, cR1, nTempFY ) ); 1895 aColRes.SetGreen( MAP( cG0, cG1, nTempFY ) ); 1896 aColRes.SetBlue( MAP( cB0, cB1, nTempFY ) ); 1897 pWAcc->SetPixel( nYDst, nXDst++, aColRes ); 1898 } 1899 } 1900 } 1901 else 1902 { 1903 Scanline pTmpY, pTmpX; 1904 long nSumR, nSumG, nSumB,nLineStart , nLineRange, nRowStart , nRowRange ; 1905 long nLeft, nRight, nTop, nBottom, nWeightX, nWeightY ; 1906 long nSumRowR ,nSumRowG,nSumRowB, nTotalWeightX, nTotalWeightY; 1907 1908 for( nY = nStartY , nYDst = 0L; nY <= nEndY; nY++, nYDst++ ) 1909 { 1910 nTop = bVMirr ? ( nY + 1 ) : nY; 1911 nBottom = bVMirr ? nY : ( nY + 1 ) ; 1912 1913 if( nY ==nEndY ) 1914 { 1915 nLineStart = pMapIY[ nY ]; 1916 nLineRange = 0; 1917 } 1918 else 1919 { 1920 nLineStart = pMapIY[ nTop ] ; 1921 nLineRange = ( pMapIY[ nBottom ] == pMapIY[ nTop ] ) ? 1 :( pMapIY[ nBottom ] - pMapIY[ nTop ] ); 1922 } 1923 1924 for( nX = nStartX , nXDst = 0L; nX <= nEndX; nX++ ) 1925 { 1926 nLeft = bHMirr ? ( nX + 1 ) : nX; 1927 nRight = bHMirr ? nX : ( nX + 1 ) ; 1928 1929 if( nX == nEndX ) 1930 { 1931 nRowStart = pMapIX[ nX ]; 1932 nRowRange = 0; 1933 } 1934 else 1935 { 1936 nRowStart = pMapIX[ nLeft ]; 1937 nRowRange = ( pMapIX[ nRight ] == pMapIX[ nLeft ] )? 1 : ( pMapIX[ nRight ] - pMapIX[ nLeft ] ); 1938 } 1939 1940 nSumR = nSumG = nSumB = 0; 1941 nTotalWeightY = 0; 1942 1943 for(int i = 0; i<= nLineRange; i++) 1944 { 1945 pTmpY = pAcc->GetScanline( nLineStart + i ); 1946 pTmpX = pTmpY + 3L * nRowStart; 1947 nSumRowR = nSumRowG = nSumRowB = 0; 1948 nTotalWeightX = 0; 1949 1950 for(int j = 0; j <= nRowRange; j++) 1951 { 1952 if(nX == nEndX ) 1953 { 1954 nSumRowR += ( *pTmpX ) << 7L;pTmpX++; 1955 nSumRowG += ( *pTmpX ) << 7L;pTmpX++; 1956 nSumRowB += ( *pTmpX ) << 7L;pTmpX++; 1957 nTotalWeightX += 1 << 7L; 1958 } 1959 else if( j == 0 ) 1960 { 1961 nWeightX = (nMax- pMapFX[ nLeft ]) ; 1962 nSumRowR += ( nWeightX *( *pTmpX )) ;pTmpX++; 1963 nSumRowG += ( nWeightX *( *pTmpX )) ;pTmpX++; 1964 nSumRowB += ( nWeightX *( *pTmpX )) ;pTmpX++; 1965 nTotalWeightX += nWeightX; 1966 } 1967 else if ( nRowRange == j ) 1968 { 1969 nWeightX = pMapFX[ nRight ] ; 1970 nSumRowR += ( nWeightX *( *pTmpX ) );pTmpX++; 1971 nSumRowG += ( nWeightX *( *pTmpX ) );pTmpX++; 1972 nSumRowB += ( nWeightX *( *pTmpX ) );pTmpX++; 1973 nTotalWeightX += nWeightX; 1974 } 1975 else 1976 { 1977 nSumRowR += ( *pTmpX ) << 7L;pTmpX++; 1978 nSumRowG += ( *pTmpX ) << 7L;pTmpX++; 1979 nSumRowB += ( *pTmpX ) << 7L;pTmpX++; 1980 nTotalWeightX += 1 << 7L; 1981 } 1982 } 1983 1984 if( nY == nEndY ) 1985 nWeightY = nMax; 1986 else if( i == 0 ) 1987 nWeightY = nMax - pMapFY[ nTop ]; 1988 else if( nLineRange == 1 ) 1989 nWeightY = pMapFY[ nTop ]; 1990 else if ( nLineRange == i ) 1991 nWeightY = pMapFY[ nBottom ]; 1992 else 1993 nWeightY = nMax; 1994 1995 nWeightY = nWeightY ; 1996 nSumB += nWeightY * ( nSumRowB / nTotalWeightX ); 1997 nSumG += nWeightY * ( nSumRowG / nTotalWeightX ); 1998 nSumR += nWeightY * ( nSumRowR / nTotalWeightX ); 1999 nTotalWeightY += nWeightY; 2000 } 2001 2002 aColRes.SetRed( ( sal_uInt8 ) (( nSumR / nTotalWeightY ) )); 2003 aColRes.SetGreen( ( sal_uInt8 ) (( nSumG / nTotalWeightY) )); 2004 aColRes.SetBlue( ( sal_uInt8 ) (( nSumB / nTotalWeightY ) )); 2005 pWAcc->SetPixel( nYDst, nXDst++, aColRes ); 2006 2007 } 2008 } 2009 } 2010 } 2011 else 2012 { 2013 if( scaleX >= fScaleThresh && scaleY >= fScaleThresh ) 2014 { 2015 for( nY = nStartY, nYDst = 0L; nY <= nEndY; nY++, nYDst++ ) 2016 { 2017 nTempY = pMapIY[ nY ]; nTempFY = pMapFY[ nY ]; 2018 2019 for( nX = nStartX, nXDst = 0L; nX <= nEndX; nX++ ) 2020 { 2021 nTempX = pMapIX[ nX ]; nTempFX = pMapFX[ nX ]; 2022 2023 aCol0 = pAcc->GetPixel( nTempY, nTempX ); 2024 aCol1 = pAcc->GetPixel( nTempY, ++nTempX ); 2025 cR0 = MAP( aCol0.GetRed(), aCol1.GetRed(), nTempFX ); 2026 cG0 = MAP( aCol0.GetGreen(), aCol1.GetGreen(), nTempFX ); 2027 cB0 = MAP( aCol0.GetBlue(), aCol1.GetBlue(), nTempFX ); 2028 2029 aCol1 = pAcc->GetPixel( ++nTempY, nTempX ); 2030 aCol0 = pAcc->GetPixel( nTempY--, --nTempX ); 2031 cR1 = MAP( aCol0.GetRed(), aCol1.GetRed(), nTempFX ); 2032 cG1 = MAP( aCol0.GetGreen(), aCol1.GetGreen(), nTempFX ); 2033 cB1 = MAP( aCol0.GetBlue(), aCol1.GetBlue(), nTempFX ); 2034 2035 aColRes.SetRed( MAP( cR0, cR1, nTempFY ) ); 2036 aColRes.SetGreen( MAP( cG0, cG1, nTempFY ) ); 2037 aColRes.SetBlue( MAP( cB0, cB1, nTempFY ) ); 2038 pWAcc->SetPixel( nYDst, nXDst++, aColRes ); 2039 } 2040 } 2041 } 2042 else 2043 { 2044 long nSumR, nSumG, nSumB,nLineStart , nLineRange, nRowStart , nRowRange ; 2045 long nLeft, nRight, nTop, nBottom, nWeightX, nWeightY ; 2046 long nSumRowR ,nSumRowG,nSumRowB, nTotalWeightX, nTotalWeightY; 2047 2048 for( nY = nStartY , nYDst = 0L; nY <= nEndY; nY++, nYDst++ ) 2049 { 2050 nTop = bVMirr ? ( nY + 1 ) : nY; 2051 nBottom = bVMirr ? nY : ( nY + 1 ) ; 2052 2053 if( nY ==nEndY ) 2054 { 2055 nLineStart = pMapIY[ nY ]; 2056 nLineRange = 0; 2057 } 2058 else 2059 { 2060 nLineStart = pMapIY[ nTop ] ; 2061 nLineRange = ( pMapIY[ nBottom ] == pMapIY[ nTop ] ) ? 1 :( pMapIY[ nBottom ] - pMapIY[ nTop ] ); 2062 } 2063 2064 for( nX = nStartX , nXDst = 0L; nX <= nEndX; nX++ ) 2065 { 2066 nLeft = bHMirr ? ( nX + 1 ) : nX; 2067 nRight = bHMirr ? nX : ( nX + 1 ) ; 2068 2069 if( nX == nEndX ) 2070 { 2071 nRowStart = pMapIX[ nX ]; 2072 nRowRange = 0; 2073 } 2074 else 2075 { 2076 nRowStart = pMapIX[ nLeft ]; 2077 nRowRange = ( pMapIX[ nRight ] == pMapIX[ nLeft ] )? 1 : ( pMapIX[ nRight ] - pMapIX[ nLeft ] ); 2078 } 2079 2080 nSumR = nSumG = nSumB = 0; 2081 nTotalWeightY = 0; 2082 2083 for(int i = 0; i<= nLineRange; i++) 2084 { 2085 nSumRowR = nSumRowG = nSumRowB = 0; 2086 nTotalWeightX = 0; 2087 2088 for(int j = 0; j <= nRowRange; j++) 2089 { 2090 aCol0 = pAcc->GetPixel( nLineStart + i, nRowStart + j ); 2091 2092 if(nX == nEndX ) 2093 { 2094 2095 nSumRowB += aCol0.GetBlue() << 7L; 2096 nSumRowG += aCol0.GetGreen() << 7L; 2097 nSumRowR += aCol0.GetRed() << 7L; 2098 nTotalWeightX += 1 << 7L; 2099 } 2100 else if( j == 0 ) 2101 { 2102 2103 nWeightX = (nMax- pMapFX[ nLeft ]) ; 2104 nSumRowB += ( nWeightX *aCol0.GetBlue()) ; 2105 nSumRowG += ( nWeightX *aCol0.GetGreen()) ; 2106 nSumRowR += ( nWeightX *aCol0.GetRed()) ; 2107 nTotalWeightX += nWeightX; 2108 } 2109 else if ( nRowRange == j ) 2110 { 2111 2112 nWeightX = pMapFX[ nRight ] ; 2113 nSumRowB += ( nWeightX *aCol0.GetBlue() ); 2114 nSumRowG += ( nWeightX *aCol0.GetGreen() ); 2115 nSumRowR += ( nWeightX *aCol0.GetRed() ); 2116 nTotalWeightX += nWeightX; 2117 } 2118 else 2119 { 2120 nSumRowB += aCol0.GetBlue() << 7L; 2121 nSumRowG += aCol0.GetGreen() << 7L; 2122 nSumRowR += aCol0.GetRed() << 7L; 2123 nTotalWeightX += 1 << 7L; 2124 } 2125 } 2126 2127 if( nY == nEndY ) 2128 nWeightY = nMax; 2129 else if( i == 0 ) 2130 nWeightY = nMax - pMapFY[ nTop ]; 2131 else if( nLineRange == 1 ) 2132 nWeightY = pMapFY[ nTop ]; 2133 else if ( nLineRange == i ) 2134 nWeightY = pMapFY[ nBottom ]; 2135 else 2136 nWeightY = nMax; 2137 2138 nWeightY = nWeightY ; 2139 nSumB += nWeightY * ( nSumRowB / nTotalWeightX ); 2140 nSumG += nWeightY * ( nSumRowG / nTotalWeightX ); 2141 nSumR += nWeightY * ( nSumRowR / nTotalWeightX ); 2142 nTotalWeightY += nWeightY; 2143 } 2144 2145 aColRes.SetRed( ( sal_uInt8 ) (( nSumR / nTotalWeightY ) )); 2146 aColRes.SetGreen( ( sal_uInt8 ) (( nSumG / nTotalWeightY) )); 2147 aColRes.SetBlue( ( sal_uInt8 ) (( nSumB / nTotalWeightY ) )); 2148 pWAcc->SetPixel( nYDst, nXDst++, aColRes ); 2149 2150 } 2151 } 2152 } 2153 } 2154 } 2155 2156 bRet = true; 2157 } 2158 2159 delete[] pMapIX; 2160 delete[] pMapIY; 2161 delete[] pMapFX; 2162 delete[] pMapFY; 2163 2164 ReleaseAccess( pAcc ); 2165 aOutBmp.ReleaseAccess( pWAcc ); 2166 2167 if( bRet ) 2168 { 2169 ImplAdaptBitCount(aOutBmp); 2170 ImplAssignWithSize(aOutBmp); 2171 } 2172 2173 if( !bRet ) 2174 bRet = ImplScaleFast( scaleX, scaleY ); 2175 } 2176 2177 return bRet; 2178 } 2179 2180 //----------------------------------------------------------------------------------- 2181 2182 namespace 2183 { 2184 void ImplCalculateContributions( 2185 const sal_uInt32 aSourceSize, 2186 const sal_uInt32 aDestinationSize, 2187 sal_uInt32& aNumberOfContributions, 2188 double*& pWeights, 2189 sal_uInt32*& pPixels, 2190 sal_uInt32*& pCount, 2191 const Kernel& aKernel) 2192 { 2193 const double fSamplingRadius(aKernel.GetWidth()); 2194 const double fScale(aDestinationSize / static_cast< double >(aSourceSize)); 2195 const double fScaledRadius((fScale < 1.0) ? fSamplingRadius / fScale : fSamplingRadius); 2196 const double fFilterFactor((fScale < 1.0) ? fScale : 1.0); 2197 2198 aNumberOfContributions = (static_cast< sal_uInt32 >(fabs(ceil(fScaledRadius))) * 2) + 1; 2199 const sal_uInt32 nAllocSize(aDestinationSize * aNumberOfContributions); 2200 pWeights = new double[nAllocSize]; 2201 pPixels = new sal_uInt32[nAllocSize]; 2202 pCount = new sal_uInt32[aDestinationSize]; 2203 2204 for(sal_uInt32 i(0); i < aDestinationSize; i++) 2205 { 2206 const sal_uInt32 aIndex(i * aNumberOfContributions); 2207 const double aCenter(i / fScale); 2208 const sal_Int32 aLeft(static_cast< sal_Int32 >(floor(aCenter - fScaledRadius))); 2209 const sal_Int32 aRight(static_cast< sal_Int32 >(ceil(aCenter + fScaledRadius))); 2210 sal_uInt32 aCurrentCount(0); 2211 2212 for(sal_Int32 j(aLeft); j <= aRight; j++) 2213 { 2214 const double aWeight(aKernel.Calculate(fFilterFactor * (aCenter - static_cast< double>(j)))); 2215 2216 // Reduce calculations with ignoring weights of 0.0 2217 if(fabs(aWeight) < 0.0001) 2218 { 2219 continue; 2220 } 2221 2222 // Handling on edges 2223 const sal_uInt32 aPixelIndex(MinMax(j, 0, aSourceSize - 1)); 2224 const sal_uInt32 nIndex(aIndex + aCurrentCount); 2225 2226 pWeights[nIndex] = aWeight; 2227 pPixels[nIndex] = aPixelIndex; 2228 2229 aCurrentCount++; 2230 } 2231 2232 pCount[i] = aCurrentCount; 2233 } 2234 } 2235 2236 sal_Bool ImplScaleConvolutionHor( 2237 Bitmap& rSource, 2238 Bitmap& rTarget, 2239 const double& rScaleX, 2240 const Kernel& aKernel) 2241 { 2242 // Do horizontal filtering 2243 OSL_ENSURE(rScaleX > 0.0, "Error in scaling: Mirror given in non-mirror-capable method (!)"); 2244 const sal_uInt32 nWidth(rSource.GetSizePixel().Width()); 2245 const sal_uInt32 nNewWidth(FRound(nWidth * rScaleX)); 2246 2247 if(nWidth == nNewWidth) 2248 { 2249 return true; 2250 } 2251 2252 BitmapReadAccess* pReadAcc = rSource.AcquireReadAccess(); 2253 2254 if(pReadAcc) 2255 { 2256 double* pWeights = 0; 2257 sal_uInt32* pPixels = 0; 2258 sal_uInt32* pCount = 0; 2259 sal_uInt32 aNumberOfContributions(0); 2260 2261 const sal_uInt32 nHeight(rSource.GetSizePixel().Height()); 2262 ImplCalculateContributions(nWidth, nNewWidth, aNumberOfContributions, pWeights, pPixels, pCount, aKernel); 2263 rTarget = Bitmap(Size(nNewWidth, nHeight), 24); 2264 BitmapWriteAccess* pWriteAcc = rTarget.AcquireWriteAccess(); 2265 bool bResult(0 != pWriteAcc); 2266 2267 if(bResult) 2268 { 2269 for(sal_uInt32 y(0); y < nHeight; y++) 2270 { 2271 for(sal_uInt32 x(0); x < nNewWidth; x++) 2272 { 2273 const sal_uInt32 aBaseIndex(x * aNumberOfContributions); 2274 double aSum(0.0); 2275 double aValueRed(0.0); 2276 double aValueGreen(0.0); 2277 double aValueBlue(0.0); 2278 2279 for(sal_uInt32 j(0); j < pCount[x]; j++) 2280 { 2281 const sal_uInt32 aIndex(aBaseIndex + j); 2282 const double aWeight(pWeights[aIndex]); 2283 BitmapColor aColor; 2284 2285 aSum += aWeight; 2286 2287 if(pReadAcc->HasPalette()) 2288 { 2289 aColor = pReadAcc->GetPaletteColor(pReadAcc->GetPixelIndex(y, pPixels[aIndex])); 2290 } 2291 else 2292 { 2293 aColor = pReadAcc->GetPixel(y, pPixels[aIndex]); 2294 } 2295 2296 aValueRed += aWeight * aColor.GetRed(); 2297 aValueGreen += aWeight * aColor.GetGreen(); 2298 aValueBlue += aWeight * aColor.GetBlue(); 2299 } 2300 2301 const BitmapColor aResultColor( 2302 static_cast< sal_uInt8 >(MinMax(static_cast< sal_Int32 >(aValueRed / aSum), 0, 255)), 2303 static_cast< sal_uInt8 >(MinMax(static_cast< sal_Int32 >(aValueGreen / aSum), 0, 255)), 2304 static_cast< sal_uInt8 >(MinMax(static_cast< sal_Int32 >(aValueBlue / aSum), 0, 255))); 2305 2306 pWriteAcc->SetPixel(y, x, aResultColor); 2307 } 2308 } 2309 2310 rTarget.ReleaseAccess(pWriteAcc); 2311 } 2312 2313 rSource.ReleaseAccess(pReadAcc); 2314 delete[] pWeights; 2315 delete[] pCount; 2316 delete[] pPixels; 2317 2318 if(bResult) 2319 { 2320 return true; 2321 } 2322 } 2323 2324 return false; 2325 } 2326 2327 bool ImplScaleConvolutionVer( 2328 Bitmap& rSource, 2329 Bitmap& rTarget, 2330 const double& rScaleY, 2331 const Kernel& aKernel) 2332 { 2333 // Do vertical filtering 2334 OSL_ENSURE(rScaleY > 0.0, "Error in scaling: Mirror given in non-mirror-capable method (!)"); 2335 const sal_uInt32 nHeight(rSource.GetSizePixel().Height()); 2336 const sal_uInt32 nNewHeight(FRound(nHeight * rScaleY)); 2337 2338 if(nHeight == nNewHeight) 2339 { 2340 return true; 2341 } 2342 2343 BitmapReadAccess* pReadAcc = rSource.AcquireReadAccess(); 2344 2345 if(pReadAcc) 2346 { 2347 double* pWeights = 0; 2348 sal_uInt32* pPixels = 0; 2349 sal_uInt32* pCount = 0; 2350 sal_uInt32 aNumberOfContributions(0); 2351 2352 const sal_uInt32 nWidth(rSource.GetSizePixel().Width()); 2353 ImplCalculateContributions(nHeight, nNewHeight, aNumberOfContributions, pWeights, pPixels, pCount, aKernel); 2354 rTarget = Bitmap(Size(nWidth, nNewHeight), 24); 2355 BitmapWriteAccess* pWriteAcc = rTarget.AcquireWriteAccess(); 2356 bool bResult(0 != pWriteAcc); 2357 2358 if(pWriteAcc) 2359 { 2360 for(sal_uInt32 x(0); x < nWidth; x++) 2361 { 2362 for(sal_uInt32 y(0); y < nNewHeight; y++) 2363 { 2364 const sal_uInt32 aBaseIndex(y * aNumberOfContributions); 2365 double aSum(0.0); 2366 double aValueRed(0.0); 2367 double aValueGreen(0.0); 2368 double aValueBlue(0.0); 2369 2370 for(sal_uInt32 j(0); j < pCount[y]; j++) 2371 { 2372 const sal_uInt32 aIndex(aBaseIndex + j); 2373 const double aWeight(pWeights[aIndex]); 2374 BitmapColor aColor; 2375 2376 aSum += aWeight; 2377 2378 if(pReadAcc->HasPalette()) 2379 { 2380 aColor = pReadAcc->GetPaletteColor(pReadAcc->GetPixelIndex(pPixels[aIndex], x)); 2381 } 2382 else 2383 { 2384 aColor = pReadAcc->GetPixel(pPixels[aIndex], x); 2385 } 2386 2387 aValueRed += aWeight * aColor.GetRed(); 2388 aValueGreen += aWeight * aColor.GetGreen(); 2389 aValueBlue += aWeight * aColor.GetBlue(); 2390 } 2391 2392 const BitmapColor aResultColor( 2393 static_cast< sal_uInt8 >(MinMax(static_cast< sal_Int32 >(aValueRed / aSum), 0, 255)), 2394 static_cast< sal_uInt8 >(MinMax(static_cast< sal_Int32 >(aValueGreen / aSum), 0, 255)), 2395 static_cast< sal_uInt8 >(MinMax(static_cast< sal_Int32 >(aValueBlue / aSum), 0, 255))); 2396 2397 if(pWriteAcc->HasPalette()) 2398 { 2399 pWriteAcc->SetPixelIndex(y, x, static_cast< sal_uInt8 >(pWriteAcc->GetBestPaletteIndex(aResultColor))); 2400 } 2401 else 2402 { 2403 pWriteAcc->SetPixel(y, x, aResultColor); 2404 } 2405 } 2406 } 2407 } 2408 2409 rTarget.ReleaseAccess(pWriteAcc); 2410 rSource.ReleaseAccess(pReadAcc); 2411 2412 delete[] pWeights; 2413 delete[] pCount; 2414 delete[] pPixels; 2415 2416 if(bResult) 2417 { 2418 return true; 2419 } 2420 } 2421 2422 return false; 2423 } 2424 } 2425 2426 // #121233# Added BMP_SCALE_LANCZOS, BMP_SCALE_BICUBIC, BMP_SCALE_BILINEAR and 2427 // BMP_SCALE_BOX derived from the original commit from Toma� Vajngerl (see 2428 // bugzilla task for deitails) Thanks! 2429 sal_Bool Bitmap::ImplScaleConvolution( 2430 const double& rScaleX, 2431 const double& rScaleY, 2432 const Kernel& aKernel) 2433 { 2434 const bool bMirrorHor(rScaleX < 0.0); 2435 const bool bMirrorVer(rScaleY < 0.0); 2436 const double fScaleX(bMirrorHor ? -rScaleX : rScaleX); 2437 const double fScaleY(bMirrorVer ? -rScaleY : rScaleY); 2438 const sal_uInt32 nWidth(GetSizePixel().Width()); 2439 const sal_uInt32 nHeight(GetSizePixel().Height()); 2440 const sal_uInt32 nNewWidth(FRound(nWidth * fScaleX)); 2441 const sal_uInt32 nNewHeight(FRound(nHeight * fScaleY)); 2442 const bool bScaleHor(nWidth != nNewWidth); 2443 const bool bScaleVer(nHeight != nNewHeight); 2444 const bool bMirror(bMirrorHor || bMirrorVer); 2445 2446 if(!bMirror && !bScaleHor && !bScaleVer) 2447 { 2448 return true; 2449 } 2450 2451 bool bResult(true); 2452 sal_uInt32 nMirrorFlags(BMP_MIRROR_NONE); 2453 bool bMirrorAfter(false); 2454 2455 if(bMirror) 2456 { 2457 if(bMirrorHor) 2458 { 2459 nMirrorFlags |= BMP_MIRROR_HORZ; 2460 } 2461 2462 if(bMirrorVer) 2463 { 2464 nMirrorFlags |= BMP_MIRROR_VERT; 2465 } 2466 2467 const sal_uInt32 nStartSize(nWidth * nHeight); 2468 const sal_uInt32 nEndSize(nNewWidth * nNewHeight); 2469 2470 bMirrorAfter = nStartSize > nEndSize; 2471 2472 if(!bMirrorAfter) 2473 { 2474 bResult = Mirror(nMirrorFlags); 2475 } 2476 } 2477 2478 Bitmap aResult; 2479 2480 if(bResult) 2481 { 2482 const sal_uInt32 nInBetweenSizeHorFirst(nHeight * nNewWidth); 2483 const sal_uInt32 nInBetweenSizeVerFirst(nNewHeight * nWidth); 2484 2485 if(nInBetweenSizeHorFirst < nInBetweenSizeVerFirst) 2486 { 2487 if(bScaleHor) 2488 { 2489 bResult = ImplScaleConvolutionHor(*this, aResult, fScaleX, aKernel); 2490 } 2491 2492 if(bResult && bScaleVer) 2493 { 2494 bResult = ImplScaleConvolutionVer(*this, aResult, fScaleY, aKernel); 2495 } 2496 } 2497 else 2498 { 2499 if(bScaleVer) 2500 { 2501 bResult = ImplScaleConvolutionVer(*this, aResult, fScaleY, aKernel); 2502 } 2503 2504 if(bResult && bScaleHor) 2505 { 2506 bResult = ImplScaleConvolutionHor(*this, aResult, fScaleX, aKernel); 2507 } 2508 } 2509 } 2510 2511 if(bResult && bMirrorAfter) 2512 { 2513 bResult = aResult.Mirror(nMirrorFlags); 2514 } 2515 2516 if(bResult) 2517 { 2518 ImplAdaptBitCount(aResult); 2519 *this = aResult; 2520 } 2521 2522 return bResult; 2523 } 2524 2525 // ------------------------------------------------------------------------ 2526 2527 sal_Bool Bitmap::Dither( sal_uLong nDitherFlags ) 2528 { 2529 sal_Bool bRet = sal_False; 2530 2531 const Size aSizePix( GetSizePixel() ); 2532 2533 if( aSizePix.Width() == 1 || aSizePix.Height() == 1 ) 2534 bRet = sal_True; 2535 else if( nDitherFlags & BMP_DITHER_MATRIX ) 2536 bRet = ImplDitherMatrix(); 2537 else if( nDitherFlags & BMP_DITHER_FLOYD ) 2538 bRet = ImplDitherFloyd(); 2539 else if( ( nDitherFlags & BMP_DITHER_FLOYD_16 ) && ( GetBitCount() == 24 ) ) 2540 bRet = ImplDitherFloyd16(); 2541 2542 return bRet; 2543 } 2544 2545 // ------------------------------------------------------------------------ 2546 2547 sal_Bool Bitmap::ImplDitherMatrix() 2548 { 2549 BitmapReadAccess* pReadAcc = AcquireReadAccess(); 2550 Bitmap aNewBmp( GetSizePixel(), 8 ); 2551 BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess(); 2552 sal_Bool bRet = sal_False; 2553 2554 if( pReadAcc && pWriteAcc ) 2555 { 2556 const sal_uLong nWidth = pReadAcc->Width(); 2557 const sal_uLong nHeight = pReadAcc->Height(); 2558 BitmapColor aIndex( (sal_uInt8) 0 ); 2559 2560 if( pReadAcc->HasPalette() ) 2561 { 2562 for( sal_uLong nY = 0UL; nY < nHeight; nY++ ) 2563 { 2564 for( sal_uLong nX = 0UL, nModY = ( nY & 0x0FUL ) << 4UL; nX < nWidth; nX++ ) 2565 { 2566 const BitmapColor aCol( pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nY, nX ) ) ); 2567 const sal_uLong nD = nVCLDitherLut[ nModY + ( nX & 0x0FUL ) ]; 2568 const sal_uLong nR = ( nVCLLut[ aCol.GetRed() ] + nD ) >> 16UL; 2569 const sal_uLong nG = ( nVCLLut[ aCol.GetGreen() ] + nD ) >> 16UL; 2570 const sal_uLong nB = ( nVCLLut[ aCol.GetBlue() ] + nD ) >> 16UL; 2571 2572 aIndex.SetIndex( (sal_uInt8) ( nVCLRLut[ nR ] + nVCLGLut[ nG ] + nVCLBLut[ nB ] ) ); 2573 pWriteAcc->SetPixel( nY, nX, aIndex ); 2574 } 2575 } 2576 } 2577 else 2578 { 2579 for( sal_uLong nY = 0UL; nY < nHeight; nY++ ) 2580 { 2581 for( sal_uLong nX = 0UL, nModY = ( nY & 0x0FUL ) << 4UL; nX < nWidth; nX++ ) 2582 { 2583 const BitmapColor aCol( pReadAcc->GetPixel( nY, nX ) ); 2584 const sal_uLong nD = nVCLDitherLut[ nModY + ( nX & 0x0FUL ) ]; 2585 const sal_uLong nR = ( nVCLLut[ aCol.GetRed() ] + nD ) >> 16UL; 2586 const sal_uLong nG = ( nVCLLut[ aCol.GetGreen() ] + nD ) >> 16UL; 2587 const sal_uLong nB = ( nVCLLut[ aCol.GetBlue() ] + nD ) >> 16UL; 2588 2589 aIndex.SetIndex( (sal_uInt8) ( nVCLRLut[ nR ] + nVCLGLut[ nG ] + nVCLBLut[ nB ] ) ); 2590 pWriteAcc->SetPixel( nY, nX, aIndex ); 2591 } 2592 } 2593 } 2594 2595 bRet = sal_True; 2596 } 2597 2598 ReleaseAccess( pReadAcc ); 2599 aNewBmp.ReleaseAccess( pWriteAcc ); 2600 2601 if( bRet ) 2602 { 2603 const MapMode aMap( maPrefMapMode ); 2604 const Size aSize( maPrefSize ); 2605 2606 *this = aNewBmp; 2607 2608 maPrefMapMode = aMap; 2609 maPrefSize = aSize; 2610 } 2611 2612 return bRet; 2613 } 2614 2615 // ------------------------------------------------------------------------ 2616 2617 sal_Bool Bitmap::ImplDitherFloyd() 2618 { 2619 const Size aSize( GetSizePixel() ); 2620 sal_Bool bRet = sal_False; 2621 2622 if( ( aSize.Width() > 3 ) && ( aSize.Height() > 2 ) ) 2623 { 2624 BitmapReadAccess* pReadAcc = AcquireReadAccess(); 2625 Bitmap aNewBmp( GetSizePixel(), 8 ); 2626 BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess(); 2627 2628 if( pReadAcc && pWriteAcc ) 2629 { 2630 BitmapColor aColor; 2631 long nWidth = pReadAcc->Width(); 2632 long nWidth1 = nWidth - 1L; 2633 long nHeight = pReadAcc->Height(); 2634 long nX; 2635 long nW = nWidth * 3L; 2636 long nW2 = nW - 3L; 2637 long nRErr, nGErr, nBErr; 2638 long nRC, nGC, nBC; 2639 long nTemp; 2640 long nZ; 2641 long* p1 = new long[ nW ]; 2642 long* p2 = new long[ nW ]; 2643 long* p1T = p1; 2644 long* p2T = p2; 2645 long* pTmp; 2646 sal_Bool bPal = pReadAcc->HasPalette(); 2647 2648 pTmp = p2T; 2649 2650 if( bPal ) 2651 { 2652 for( nZ = 0; nZ < nWidth; nZ++ ) 2653 { 2654 aColor = pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( 0, nZ ) ); 2655 2656 *pTmp++ = (long) aColor.GetBlue() << 12; 2657 *pTmp++ = (long) aColor.GetGreen() << 12; 2658 *pTmp++ = (long) aColor.GetRed() << 12; 2659 } 2660 } 2661 else 2662 { 2663 for( nZ = 0; nZ < nWidth; nZ++ ) 2664 { 2665 aColor = pReadAcc->GetPixel( 0, nZ ); 2666 2667 *pTmp++ = (long) aColor.GetBlue() << 12; 2668 *pTmp++ = (long) aColor.GetGreen() << 12; 2669 *pTmp++ = (long) aColor.GetRed() << 12; 2670 } 2671 } 2672 2673 for( long nY = 1, nYAcc = 0L; nY <= nHeight; nY++, nYAcc++ ) 2674 { 2675 pTmp = p1T; 2676 p1T = p2T; 2677 p2T = pTmp; 2678 2679 if( nY < nHeight ) 2680 { 2681 if( bPal ) 2682 { 2683 for( nZ = 0; nZ < nWidth; nZ++ ) 2684 { 2685 aColor = pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nY, nZ ) ); 2686 2687 *pTmp++ = (long) aColor.GetBlue() << 12; 2688 *pTmp++ = (long) aColor.GetGreen() << 12; 2689 *pTmp++ = (long) aColor.GetRed() << 12; 2690 } 2691 } 2692 else 2693 { 2694 for( nZ = 0; nZ < nWidth; nZ++ ) 2695 { 2696 aColor = pReadAcc->GetPixel( nY, nZ ); 2697 2698 *pTmp++ = (long) aColor.GetBlue() << 12; 2699 *pTmp++ = (long) aColor.GetGreen() << 12; 2700 *pTmp++ = (long) aColor.GetRed() << 12; 2701 } 2702 } 2703 } 2704 2705 // erstes Pixel gesondert betrachten 2706 nX = 0; 2707 CALC_ERRORS; 2708 CALC_TABLES7; 2709 nX -= 5; 2710 CALC_TABLES5; 2711 pWriteAcc->SetPixelIndex( nYAcc, 0, static_cast<sal_uInt8>(nVCLBLut[ nBC ] + nVCLGLut[nGC ] + nVCLRLut[nRC ]) ); 2712 2713 // mittlere Pixel ueber Schleife 2714 long nXAcc; 2715 for ( nX = 3L, nXAcc = 1L; nX < nW2; nXAcc++ ) 2716 { 2717 CALC_ERRORS; 2718 CALC_TABLES7; 2719 nX -= 8; 2720 CALC_TABLES3; 2721 CALC_TABLES5; 2722 pWriteAcc->SetPixelIndex( nYAcc, nXAcc, static_cast<sal_uInt8>(nVCLBLut[ nBC ] + nVCLGLut[nGC ] + nVCLRLut[nRC ]) ); 2723 } 2724 2725 // letztes Pixel gesondert betrachten 2726 CALC_ERRORS; 2727 nX -= 5; 2728 CALC_TABLES3; 2729 CALC_TABLES5; 2730 pWriteAcc->SetPixelIndex( nYAcc, nWidth1, static_cast<sal_uInt8>(nVCLBLut[ nBC ] + nVCLGLut[nGC ] + nVCLRLut[nRC ]) ); 2731 } 2732 2733 delete[] p1; 2734 delete[] p2; 2735 bRet = sal_True; 2736 } 2737 2738 ReleaseAccess( pReadAcc ); 2739 aNewBmp.ReleaseAccess( pWriteAcc ); 2740 2741 if( bRet ) 2742 { 2743 const MapMode aMap( maPrefMapMode ); 2744 const Size aPrefSize( maPrefSize ); 2745 2746 *this = aNewBmp; 2747 2748 maPrefMapMode = aMap; 2749 maPrefSize = aPrefSize; 2750 } 2751 } 2752 2753 return bRet; 2754 } 2755 2756 // ------------------------------------------------------------------------ 2757 2758 sal_Bool Bitmap::ImplDitherFloyd16() 2759 { 2760 BitmapReadAccess* pReadAcc = AcquireReadAccess(); 2761 Bitmap aNewBmp( GetSizePixel(), 24 ); 2762 BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess(); 2763 sal_Bool bRet = sal_False; 2764 2765 if( pReadAcc && pWriteAcc ) 2766 { 2767 const long nWidth = pWriteAcc->Width(); 2768 const long nWidth1 = nWidth - 1L; 2769 const long nHeight = pWriteAcc->Height(); 2770 BitmapColor aColor; 2771 BitmapColor aBestCol; 2772 ImpErrorQuad aErrQuad; 2773 ImpErrorQuad* pErrQuad1 = new ImpErrorQuad[ nWidth ]; 2774 ImpErrorQuad* pErrQuad2 = new ImpErrorQuad[ nWidth ]; 2775 ImpErrorQuad* pQLine1 = pErrQuad1; 2776 ImpErrorQuad* pQLine2 = 0; 2777 long nX, nY; 2778 long nYTmp = 0L; 2779 sal_Bool bQ1 = sal_True; 2780 2781 for( nY = 0L; nY < Min( nHeight, 2L ); nY++, nYTmp++ ) 2782 for( nX = 0L, pQLine2 = !nY ? pErrQuad1 : pErrQuad2; nX < nWidth; nX++ ) 2783 pQLine2[ nX ] = pReadAcc->GetPixel( nYTmp, nX ); 2784 2785 for( nY = 0L; nY < nHeight; nY++, nYTmp++ ) 2786 { 2787 // erstes ZeilenPixel 2788 aBestCol = pQLine1[ 0 ].ImplGetColor(); 2789 aBestCol.SetRed( ( aBestCol.GetRed() & 248 ) | 7 ); 2790 aBestCol.SetGreen( ( aBestCol.GetGreen() & 248 ) | 7 ); 2791 aBestCol.SetBlue( ( aBestCol.GetBlue() & 248 ) | 7 ); 2792 pWriteAcc->SetPixel( nY, 0, aBestCol ); 2793 2794 for( nX = 1L; nX < nWidth1; nX++ ) 2795 { 2796 aColor = pQLine1[ nX ].ImplGetColor(); 2797 aBestCol.SetRed( ( aColor.GetRed() & 248 ) | 7 ); 2798 aBestCol.SetGreen( ( aColor.GetGreen() & 248 ) | 7 ); 2799 aBestCol.SetBlue( ( aColor.GetBlue() & 248 ) | 7 ); 2800 aErrQuad = ( ImpErrorQuad( aColor ) -= aBestCol ); 2801 pQLine1[ ++nX ].ImplAddColorError7( aErrQuad ); 2802 pQLine2[ nX-- ].ImplAddColorError1( aErrQuad ); 2803 pQLine2[ nX-- ].ImplAddColorError5( aErrQuad ); 2804 pQLine2[ nX++ ].ImplAddColorError3( aErrQuad ); 2805 pWriteAcc->SetPixel( nY, nX, aBestCol ); 2806 } 2807 2808 // letztes ZeilenPixel 2809 aBestCol = pQLine1[ nWidth1 ].ImplGetColor(); 2810 aBestCol.SetRed( ( aBestCol.GetRed() & 248 ) | 7 ); 2811 aBestCol.SetGreen( ( aBestCol.GetGreen() & 248 ) | 7 ); 2812 aBestCol.SetBlue( ( aBestCol.GetBlue() & 248 ) | 7 ); 2813 pWriteAcc->SetPixel( nY, nX, aBestCol ); 2814 2815 // Zeilenpuffer neu fuellen/kopieren 2816 pQLine1 = pQLine2; 2817 pQLine2 = ( bQ1 = !bQ1 ) != sal_False ? pErrQuad2 : pErrQuad1; 2818 2819 if( nYTmp < nHeight ) 2820 for( nX = 0L; nX < nWidth; nX++ ) 2821 pQLine2[ nX ] = pReadAcc->GetPixel( nYTmp, nX ); 2822 } 2823 2824 // Zeilenpuffer zerstoeren 2825 delete[] pErrQuad1; 2826 delete[] pErrQuad2; 2827 bRet = sal_True; 2828 } 2829 2830 ReleaseAccess( pReadAcc ); 2831 aNewBmp.ReleaseAccess( pWriteAcc ); 2832 2833 if( bRet ) 2834 { 2835 const MapMode aMap( maPrefMapMode ); 2836 const Size aSize( maPrefSize ); 2837 2838 *this = aNewBmp; 2839 2840 maPrefMapMode = aMap; 2841 maPrefSize = aSize; 2842 } 2843 2844 return bRet; 2845 } 2846 2847 // ------------------------------------------------------------------------ 2848 2849 sal_Bool Bitmap::ReduceColors( sal_uInt16 nColorCount, BmpReduce eReduce ) 2850 { 2851 sal_Bool bRet; 2852 2853 if( GetColorCount() <= (sal_uLong) nColorCount ) 2854 bRet = sal_True; 2855 else if( nColorCount ) 2856 { 2857 if( BMP_REDUCE_SIMPLE == eReduce ) 2858 bRet = ImplReduceSimple( nColorCount ); 2859 else if( BMP_REDUCE_POPULAR == eReduce ) 2860 bRet = ImplReducePopular( nColorCount ); 2861 else 2862 bRet = ImplReduceMedian( nColorCount ); 2863 } 2864 else 2865 bRet = sal_False; 2866 2867 return bRet; 2868 } 2869 2870 // ------------------------------------------------------------------------ 2871 2872 sal_Bool Bitmap::ImplReduceSimple( sal_uInt16 nColorCount ) 2873 { 2874 Bitmap aNewBmp; 2875 BitmapReadAccess* pRAcc = AcquireReadAccess(); 2876 const sal_uInt16 nColCount = Min( nColorCount, (sal_uInt16) 256 ); 2877 sal_uInt16 nBitCount; 2878 sal_Bool bRet = sal_False; 2879 2880 if( nColCount <= 2 ) 2881 nBitCount = 1; 2882 else if( nColCount <= 16 ) 2883 nBitCount = 4; 2884 else 2885 nBitCount = 8; 2886 2887 if( pRAcc ) 2888 { 2889 Octree aOct( *pRAcc, nColCount ); 2890 const BitmapPalette& rPal = aOct.GetPalette(); 2891 BitmapWriteAccess* pWAcc; 2892 2893 aNewBmp = Bitmap( GetSizePixel(), nBitCount, &rPal ); 2894 pWAcc = aNewBmp.AcquireWriteAccess(); 2895 2896 if( pWAcc ) 2897 { 2898 const long nWidth = pRAcc->Width(); 2899 const long nHeight = pRAcc->Height(); 2900 2901 if( pRAcc->HasPalette() ) 2902 { 2903 for( long nY = 0L; nY < nHeight; nY++ ) 2904 for( long nX =0L; nX < nWidth; nX++ ) 2905 pWAcc->SetPixelIndex( nY, nX, static_cast<sal_uInt8>(aOct.GetBestPaletteIndex( pRAcc->GetPaletteColor( pRAcc->GetPixelIndex( nY, nX ) ))) ); 2906 } 2907 else 2908 { 2909 for( long nY = 0L; nY < nHeight; nY++ ) 2910 for( long nX =0L; nX < nWidth; nX++ ) 2911 pWAcc->SetPixelIndex( nY, nX, static_cast<sal_uInt8>(aOct.GetBestPaletteIndex( pRAcc->GetPixel( nY, nX ) )) ); 2912 } 2913 2914 aNewBmp.ReleaseAccess( pWAcc ); 2915 bRet = sal_True; 2916 } 2917 2918 ReleaseAccess( pRAcc ); 2919 } 2920 2921 if( bRet ) 2922 { 2923 const MapMode aMap( maPrefMapMode ); 2924 const Size aSize( maPrefSize ); 2925 2926 *this = aNewBmp; 2927 maPrefMapMode = aMap; 2928 maPrefSize = aSize; 2929 } 2930 2931 return bRet; 2932 } 2933 2934 // ------------------------------------------------------------------------ 2935 2936 struct PopularColorCount 2937 { 2938 sal_uInt32 mnIndex; 2939 sal_uInt32 mnCount; 2940 }; 2941 2942 // ------------------------------------------------------------------------ 2943 2944 extern "C" int __LOADONCALLAPI ImplPopularCmpFnc( const void* p1, const void* p2 ) 2945 { 2946 int nRet; 2947 2948 if( ( (PopularColorCount*) p1 )->mnCount < ( (PopularColorCount*) p2 )->mnCount ) 2949 nRet = 1; 2950 else if( ( (PopularColorCount*) p1 )->mnCount == ( (PopularColorCount*) p2 )->mnCount ) 2951 nRet = 0; 2952 else 2953 nRet = -1; 2954 2955 return nRet; 2956 } 2957 2958 // ------------------------------------------------------------------------ 2959 2960 sal_Bool Bitmap::ImplReducePopular( sal_uInt16 nColCount ) 2961 { 2962 BitmapReadAccess* pRAcc = AcquireReadAccess(); 2963 sal_uInt16 nBitCount; 2964 sal_Bool bRet = sal_False; 2965 2966 if( nColCount > 256 ) 2967 nColCount = 256; 2968 2969 if( nColCount < 17 ) 2970 nBitCount = 4; 2971 else 2972 nBitCount = 8; 2973 2974 if( pRAcc ) 2975 { 2976 const sal_uInt32 nValidBits = 4; 2977 const sal_uInt32 nRightShiftBits = 8 - nValidBits; 2978 const sal_uInt32 nLeftShiftBits1 = nValidBits; 2979 const sal_uInt32 nLeftShiftBits2 = nValidBits << 1; 2980 const sal_uInt32 nColorsPerComponent = 1 << nValidBits; 2981 const sal_uInt32 nColorOffset = 256 / nColorsPerComponent; 2982 const sal_uInt32 nTotalColors = nColorsPerComponent * nColorsPerComponent * nColorsPerComponent; 2983 const long nWidth = pRAcc->Width(); 2984 const long nHeight = pRAcc->Height(); 2985 PopularColorCount* pCountTable = new PopularColorCount[ nTotalColors ]; 2986 long nX, nY, nR, nG, nB, nIndex; 2987 2988 rtl_zeroMemory( pCountTable, nTotalColors * sizeof( PopularColorCount ) ); 2989 2990 for( nR = 0, nIndex = 0; nR < 256; nR += nColorOffset ) 2991 { 2992 for( nG = 0; nG < 256; nG += nColorOffset ) 2993 { 2994 for( nB = 0; nB < 256; nB += nColorOffset ) 2995 { 2996 pCountTable[ nIndex ].mnIndex = nIndex; 2997 nIndex++; 2998 } 2999 } 3000 } 3001 3002 if( pRAcc->HasPalette() ) 3003 { 3004 for( nY = 0L; nY < nHeight; nY++ ) 3005 { 3006 for( nX = 0L; nX < nWidth; nX++ ) 3007 { 3008 const BitmapColor& rCol = pRAcc->GetPaletteColor( pRAcc->GetPixelIndex( nY, nX ) ); 3009 pCountTable[ ( ( ( (sal_uInt32) rCol.GetRed() ) >> nRightShiftBits ) << nLeftShiftBits2 ) | 3010 ( ( ( (sal_uInt32) rCol.GetGreen() ) >> nRightShiftBits ) << nLeftShiftBits1 ) | 3011 ( ( (sal_uInt32) rCol.GetBlue() ) >> nRightShiftBits ) ].mnCount++; 3012 } 3013 } 3014 } 3015 else 3016 { 3017 for( nY = 0L; nY < nHeight; nY++ ) 3018 { 3019 for( nX = 0L; nX < nWidth; nX++ ) 3020 { 3021 const BitmapColor aCol( pRAcc->GetPixel( nY, nX ) ); 3022 pCountTable[ ( ( ( (sal_uInt32) aCol.GetRed() ) >> nRightShiftBits ) << nLeftShiftBits2 ) | 3023 ( ( ( (sal_uInt32) aCol.GetGreen() ) >> nRightShiftBits ) << nLeftShiftBits1 ) | 3024 ( ( (sal_uInt32) aCol.GetBlue() ) >> nRightShiftBits ) ].mnCount++; 3025 } 3026 } 3027 } 3028 3029 BitmapPalette aNewPal( nColCount ); 3030 3031 qsort( pCountTable, nTotalColors, sizeof( PopularColorCount ), ImplPopularCmpFnc ); 3032 3033 for( sal_uInt16 n = 0; n < nColCount; n++ ) 3034 { 3035 const PopularColorCount& rPop = pCountTable[ n ]; 3036 aNewPal[ n ] = BitmapColor( (sal_uInt8) ( ( rPop.mnIndex >> nLeftShiftBits2 ) << nRightShiftBits ), 3037 (sal_uInt8) ( ( ( rPop.mnIndex >> nLeftShiftBits1 ) & ( nColorsPerComponent - 1 ) ) << nRightShiftBits ), 3038 (sal_uInt8) ( ( rPop.mnIndex & ( nColorsPerComponent - 1 ) ) << nRightShiftBits ) ); 3039 } 3040 3041 Bitmap aNewBmp( GetSizePixel(), nBitCount, &aNewPal ); 3042 BitmapWriteAccess* pWAcc = aNewBmp.AcquireWriteAccess(); 3043 3044 if( pWAcc ) 3045 { 3046 BitmapColor aDstCol( (sal_uInt8) 0 ); 3047 sal_uInt8* pIndexMap = new sal_uInt8[ nTotalColors ]; 3048 3049 for( nR = 0, nIndex = 0; nR < 256; nR += nColorOffset ) 3050 for( nG = 0; nG < 256; nG += nColorOffset ) 3051 for( nB = 0; nB < 256; nB += nColorOffset ) 3052 pIndexMap[ nIndex++ ] = (sal_uInt8) aNewPal.GetBestIndex( BitmapColor( (sal_uInt8) nR, (sal_uInt8) nG, (sal_uInt8) nB ) ); 3053 3054 if( pRAcc->HasPalette() ) 3055 { 3056 for( nY = 0L; nY < nHeight; nY++ ) 3057 { 3058 for( nX = 0L; nX < nWidth; nX++ ) 3059 { 3060 const BitmapColor& rCol = pRAcc->GetPaletteColor( pRAcc->GetPixelIndex( nY, nX ) ); 3061 aDstCol.SetIndex( pIndexMap[ ( ( ( (sal_uInt32) rCol.GetRed() ) >> nRightShiftBits ) << nLeftShiftBits2 ) | 3062 ( ( ( (sal_uInt32) rCol.GetGreen() ) >> nRightShiftBits ) << nLeftShiftBits1 ) | 3063 ( ( (sal_uInt32) rCol.GetBlue() ) >> nRightShiftBits ) ] ); 3064 pWAcc->SetPixel( nY, nX, aDstCol ); 3065 } 3066 } 3067 } 3068 else 3069 { 3070 for( nY = 0L; nY < nHeight; nY++ ) 3071 { 3072 for( nX = 0L; nX < nWidth; nX++ ) 3073 { 3074 const BitmapColor aCol( pRAcc->GetPixel( nY, nX ) ); 3075 aDstCol.SetIndex( pIndexMap[ ( ( ( (sal_uInt32) aCol.GetRed() ) >> nRightShiftBits ) << nLeftShiftBits2 ) | 3076 ( ( ( (sal_uInt32) aCol.GetGreen() ) >> nRightShiftBits ) << nLeftShiftBits1 ) | 3077 ( ( (sal_uInt32) aCol.GetBlue() ) >> nRightShiftBits ) ] ); 3078 pWAcc->SetPixel( nY, nX, aDstCol ); 3079 } 3080 } 3081 } 3082 3083 delete[] pIndexMap; 3084 aNewBmp.ReleaseAccess( pWAcc ); 3085 bRet = sal_True; 3086 } 3087 3088 delete[] pCountTable; 3089 ReleaseAccess( pRAcc ); 3090 3091 if( bRet ) 3092 { 3093 const MapMode aMap( maPrefMapMode ); 3094 const Size aSize( maPrefSize ); 3095 3096 *this = aNewBmp; 3097 maPrefMapMode = aMap; 3098 maPrefSize = aSize; 3099 } 3100 } 3101 3102 return bRet; 3103 } 3104 3105 // ------------------------------------------------------------------------ 3106 3107 sal_Bool Bitmap::ImplReduceMedian( sal_uInt16 nColCount ) 3108 { 3109 BitmapReadAccess* pRAcc = AcquireReadAccess(); 3110 sal_uInt16 nBitCount; 3111 sal_Bool bRet = sal_False; 3112 3113 if( nColCount < 17 ) 3114 nBitCount = 4; 3115 else if( nColCount < 257 ) 3116 nBitCount = 8; 3117 else 3118 { 3119 DBG_ERROR( "Bitmap::ImplReduceMedian(): invalid color count!" ); 3120 nBitCount = 8; 3121 nColCount = 256; 3122 } 3123 3124 if( pRAcc ) 3125 { 3126 Bitmap aNewBmp( GetSizePixel(), nBitCount ); 3127 BitmapWriteAccess* pWAcc = aNewBmp.AcquireWriteAccess(); 3128 3129 if( pWAcc ) 3130 { 3131 const sal_uLong nSize = 32768UL * sizeof( sal_uLong ); 3132 sal_uLong* pColBuf = (sal_uLong*) rtl_allocateMemory( nSize ); 3133 const long nWidth = pWAcc->Width(); 3134 const long nHeight = pWAcc->Height(); 3135 long nIndex = 0L; 3136 3137 memset( (HPBYTE) pColBuf, 0, nSize ); 3138 3139 // create Buffer 3140 if( pRAcc->HasPalette() ) 3141 { 3142 for( long nY = 0L; nY < nHeight; nY++ ) 3143 { 3144 for( long nX = 0L; nX < nWidth; nX++ ) 3145 { 3146 const BitmapColor& rCol = pRAcc->GetPaletteColor( pRAcc->GetPixelIndex( nY, nX ) ); 3147 pColBuf[ RGB15( rCol.GetRed() >> 3, rCol.GetGreen() >> 3, rCol.GetBlue() >> 3 ) ]++; 3148 } 3149 } 3150 } 3151 else 3152 { 3153 for( long nY = 0L; nY < nHeight; nY++ ) 3154 { 3155 for( long nX = 0L; nX < nWidth; nX++ ) 3156 { 3157 const BitmapColor aCol( pRAcc->GetPixel( nY, nX ) ); 3158 pColBuf[ RGB15( aCol.GetRed() >> 3, aCol.GetGreen() >> 3, aCol.GetBlue() >> 3 ) ]++; 3159 } 3160 } 3161 } 3162 3163 // create palette via median cut 3164 BitmapPalette aPal( pWAcc->GetPaletteEntryCount() ); 3165 ImplMedianCut( pColBuf, aPal, 0, 31, 0, 31, 0, 31, 3166 nColCount, nWidth * nHeight, nIndex ); 3167 3168 // do mapping of colors to palette 3169 InverseColorMap aMap( aPal ); 3170 pWAcc->SetPalette( aPal ); 3171 for( long nY = 0L; nY < nHeight; nY++ ) 3172 for( long nX = 0L; nX < nWidth; nX++ ) 3173 pWAcc->SetPixelIndex( nY, nX, static_cast<sal_uInt8>( aMap.GetBestPaletteIndex( pRAcc->GetColor( nY, nX ) )) ); 3174 3175 rtl_freeMemory( pColBuf ); 3176 aNewBmp.ReleaseAccess( pWAcc ); 3177 bRet = sal_True; 3178 } 3179 3180 ReleaseAccess( pRAcc ); 3181 3182 if( bRet ) 3183 { 3184 const MapMode aMap( maPrefMapMode ); 3185 const Size aSize( maPrefSize ); 3186 3187 *this = aNewBmp; 3188 maPrefMapMode = aMap; 3189 maPrefSize = aSize; 3190 } 3191 } 3192 3193 return bRet; 3194 } 3195 3196 // ------------------------------------------------------------------------ 3197 3198 void Bitmap::ImplMedianCut( sal_uLong* pColBuf, BitmapPalette& rPal, 3199 long nR1, long nR2, long nG1, long nG2, long nB1, long nB2, 3200 long nColors, long nPixels, long& rIndex ) 3201 { 3202 if( !nPixels ) 3203 return; 3204 3205 BitmapColor aCol; 3206 const long nRLen = nR2 - nR1; 3207 const long nGLen = nG2 - nG1; 3208 const long nBLen = nB2 - nB1; 3209 long nR, nG, nB; 3210 sal_uLong* pBuf = pColBuf; 3211 3212 if( !nRLen && !nGLen && !nBLen ) 3213 { 3214 if( pBuf[ RGB15( nR1, nG1, nB1 ) ] ) 3215 { 3216 aCol.SetRed( (sal_uInt8) ( nR1 << 3 ) ); 3217 aCol.SetGreen( (sal_uInt8) ( nG1 << 3 ) ); 3218 aCol.SetBlue( (sal_uInt8) ( nB1 << 3 ) ); 3219 rPal[ (sal_uInt16) rIndex++ ] = aCol; 3220 } 3221 } 3222 else 3223 { 3224 if( 1 == nColors || 1 == nPixels ) 3225 { 3226 long nPixSum = 0, nRSum = 0, nGSum = 0, nBSum = 0; 3227 3228 for( nR = nR1; nR <= nR2; nR++ ) 3229 { 3230 for( nG = nG1; nG <= nG2; nG++ ) 3231 { 3232 for( nB = nB1; nB <= nB2; nB++ ) 3233 { 3234 nPixSum = pBuf[ RGB15( nR, nG, nB ) ]; 3235 3236 if( nPixSum ) 3237 { 3238 nRSum += nR * nPixSum; 3239 nGSum += nG * nPixSum; 3240 nBSum += nB * nPixSum; 3241 } 3242 } 3243 } 3244 } 3245 3246 aCol.SetRed( (sal_uInt8) ( ( nRSum / nPixels ) << 3 ) ); 3247 aCol.SetGreen( (sal_uInt8) ( ( nGSum / nPixels ) << 3 ) ); 3248 aCol.SetBlue( (sal_uInt8) ( ( nBSum / nPixels ) << 3 ) ); 3249 rPal[ (sal_uInt16) rIndex++ ] = aCol; 3250 } 3251 else 3252 { 3253 const long nTest = ( nPixels >> 1 ); 3254 long nPixOld = 0; 3255 long nPixNew = 0; 3256 3257 if( nBLen > nGLen && nBLen > nRLen ) 3258 { 3259 nB = nB1 - 1; 3260 3261 while( nPixNew < nTest ) 3262 { 3263 nB++, nPixOld = nPixNew; 3264 for( nR = nR1; nR <= nR2; nR++ ) 3265 for( nG = nG1; nG <= nG2; nG++ ) 3266 nPixNew += pBuf[ RGB15( nR, nG, nB ) ]; 3267 } 3268 3269 if( nB < nB2 ) 3270 { 3271 ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG2, nB1, nB, nColors >> 1, nPixNew, rIndex ); 3272 ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG2, nB + 1, nB2, nColors >> 1, nPixels - nPixNew, rIndex ); 3273 } 3274 else 3275 { 3276 ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG2, nB1, nB - 1, nColors >> 1, nPixOld, rIndex ); 3277 ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG2, nB, nB2, nColors >> 1, nPixels - nPixOld, rIndex ); 3278 } 3279 } 3280 else if( nGLen > nRLen ) 3281 { 3282 nG = nG1 - 1; 3283 3284 while( nPixNew < nTest ) 3285 { 3286 nG++, nPixOld = nPixNew; 3287 for( nR = nR1; nR <= nR2; nR++ ) 3288 for( nB = nB1; nB <= nB2; nB++ ) 3289 nPixNew += pBuf[ RGB15( nR, nG, nB ) ]; 3290 } 3291 3292 if( nG < nG2 ) 3293 { 3294 ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG, nB1, nB2, nColors >> 1, nPixNew, rIndex ); 3295 ImplMedianCut( pBuf, rPal, nR1, nR2, nG + 1, nG2, nB1, nB2, nColors >> 1, nPixels - nPixNew, rIndex ); 3296 } 3297 else 3298 { 3299 ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG - 1, nB1, nB2, nColors >> 1, nPixOld, rIndex ); 3300 ImplMedianCut( pBuf, rPal, nR1, nR2, nG, nG2, nB1, nB2, nColors >> 1, nPixels - nPixOld, rIndex ); 3301 } 3302 } 3303 else 3304 { 3305 nR = nR1 - 1; 3306 3307 while( nPixNew < nTest ) 3308 { 3309 nR++, nPixOld = nPixNew; 3310 for( nG = nG1; nG <= nG2; nG++ ) 3311 for( nB = nB1; nB <= nB2; nB++ ) 3312 nPixNew += pBuf[ RGB15( nR, nG, nB ) ]; 3313 } 3314 3315 if( nR < nR2 ) 3316 { 3317 ImplMedianCut( pBuf, rPal, nR1, nR, nG1, nG2, nB1, nB2, nColors >> 1, nPixNew, rIndex ); 3318 ImplMedianCut( pBuf, rPal, nR1 + 1, nR2, nG1, nG2, nB1, nB2, nColors >> 1, nPixels - nPixNew, rIndex ); 3319 } 3320 else 3321 { 3322 ImplMedianCut( pBuf, rPal, nR1, nR - 1, nG1, nG2, nB1, nB2, nColors >> 1, nPixOld, rIndex ); 3323 ImplMedianCut( pBuf, rPal, nR, nR2, nG1, nG2, nB1, nB2, nColors >> 1, nPixels - nPixOld, rIndex ); 3324 } 3325 } 3326 } 3327 } 3328 } 3329 3330 // ------------------------------------------------------------------------ 3331 3332 sal_Bool Bitmap::Vectorize( PolyPolygon& rPolyPoly, sal_uLong nFlags, const Link* pProgress ) 3333 { 3334 return ImplVectorizer().ImplVectorize( *this, rPolyPoly, nFlags, pProgress ); 3335 } 3336 3337 // ------------------------------------------------------------------------ 3338 3339 sal_Bool Bitmap::Vectorize( GDIMetaFile& rMtf, sal_uInt8 cReduce, sal_uLong nFlags, const Link* pProgress ) 3340 { 3341 return ImplVectorizer().ImplVectorize( *this, rMtf, cReduce, nFlags, pProgress ); 3342 } 3343 3344 // ------------------------------------------------------------------------ 3345 3346 sal_Bool Bitmap::Adjust( short nLuminancePercent, short nContrastPercent, 3347 short nChannelRPercent, short nChannelGPercent, short nChannelBPercent, 3348 double fGamma, sal_Bool bInvert ) 3349 { 3350 sal_Bool bRet = sal_False; 3351 3352 // nothing to do => return quickly 3353 if( !nLuminancePercent && !nContrastPercent && 3354 !nChannelRPercent && !nChannelGPercent && !nChannelBPercent && 3355 ( fGamma == 1.0 ) && !bInvert ) 3356 { 3357 bRet = sal_True; 3358 } 3359 else 3360 { 3361 BitmapWriteAccess* pAcc = AcquireWriteAccess(); 3362 3363 if( pAcc ) 3364 { 3365 BitmapColor aCol; 3366 const long nW = pAcc->Width(); 3367 const long nH = pAcc->Height(); 3368 sal_uInt8* cMapR = new sal_uInt8[ 256 ]; 3369 sal_uInt8* cMapG = new sal_uInt8[ 256 ]; 3370 sal_uInt8* cMapB = new sal_uInt8[ 256 ]; 3371 long nX, nY; 3372 double fM, fROff, fGOff, fBOff, fOff; 3373 3374 // calculate slope 3375 if( nContrastPercent >= 0 ) 3376 fM = 128.0 / ( 128.0 - 1.27 * MinMax( nContrastPercent, 0L, 100L ) ); 3377 else 3378 fM = ( 128.0 + 1.27 * MinMax( nContrastPercent, -100L, 0L ) ) / 128.0; 3379 3380 // total offset = luminance offset + contrast offset 3381 fOff = MinMax( nLuminancePercent, -100L, 100L ) * 2.55 + 128.0 - fM * 128.0; 3382 3383 // channel offset = channel offset + total offset 3384 fROff = nChannelRPercent * 2.55 + fOff; 3385 fGOff = nChannelGPercent * 2.55 + fOff; 3386 fBOff = nChannelBPercent * 2.55 + fOff; 3387 3388 // calculate gamma value 3389 fGamma = ( fGamma <= 0.0 || fGamma > 10.0 ) ? 1.0 : ( 1.0 / fGamma ); 3390 const sal_Bool bGamma = ( fGamma != 1.0 ); 3391 3392 // create mapping table 3393 for( nX = 0L; nX < 256L; nX++ ) 3394 { 3395 cMapR[ nX ] = (sal_uInt8) MinMax( FRound( nX * fM + fROff ), 0L, 255L ); 3396 cMapG[ nX ] = (sal_uInt8) MinMax( FRound( nX * fM + fGOff ), 0L, 255L ); 3397 cMapB[ nX ] = (sal_uInt8) MinMax( FRound( nX * fM + fBOff ), 0L, 255L ); 3398 3399 if( bGamma ) 3400 { 3401 cMapR[ nX ] = GAMMA( cMapR[ nX ], fGamma ); 3402 cMapG[ nX ] = GAMMA( cMapG[ nX ], fGamma ); 3403 cMapB[ nX ] = GAMMA( cMapB[ nX ], fGamma ); 3404 } 3405 3406 if( bInvert ) 3407 { 3408 cMapR[ nX ] = ~cMapR[ nX ]; 3409 cMapG[ nX ] = ~cMapG[ nX ]; 3410 cMapB[ nX ] = ~cMapB[ nX ]; 3411 } 3412 } 3413 3414 // do modifying 3415 if( pAcc->HasPalette() ) 3416 { 3417 BitmapColor aNewCol; 3418 3419 for( sal_uInt16 i = 0, nCount = pAcc->GetPaletteEntryCount(); i < nCount; i++ ) 3420 { 3421 const BitmapColor& rCol = pAcc->GetPaletteColor( i ); 3422 aNewCol.SetRed( cMapR[ rCol.GetRed() ] ); 3423 aNewCol.SetGreen( cMapG[ rCol.GetGreen() ] ); 3424 aNewCol.SetBlue( cMapB[ rCol.GetBlue() ] ); 3425 pAcc->SetPaletteColor( i, aNewCol ); 3426 } 3427 } 3428 else if( pAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_BGR ) 3429 { 3430 for( nY = 0L; nY < nH; nY++ ) 3431 { 3432 Scanline pScan = pAcc->GetScanline( nY ); 3433 3434 for( nX = 0L; nX < nW; nX++ ) 3435 { 3436 *pScan = cMapB[ *pScan ]; pScan++; 3437 *pScan = cMapG[ *pScan ]; pScan++; 3438 *pScan = cMapR[ *pScan ]; pScan++; 3439 } 3440 } 3441 } 3442 else if( pAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_RGB ) 3443 { 3444 for( nY = 0L; nY < nH; nY++ ) 3445 { 3446 Scanline pScan = pAcc->GetScanline( nY ); 3447 3448 for( nX = 0L; nX < nW; nX++ ) 3449 { 3450 *pScan = cMapR[ *pScan ]; pScan++; 3451 *pScan = cMapG[ *pScan ]; pScan++; 3452 *pScan = cMapB[ *pScan ]; pScan++; 3453 } 3454 } 3455 } 3456 else 3457 { 3458 for( nY = 0L; nY < nH; nY++ ) 3459 { 3460 for( nX = 0L; nX < nW; nX++ ) 3461 { 3462 aCol = pAcc->GetPixel( nY, nX ); 3463 aCol.SetRed( cMapR[ aCol.GetRed() ] ); 3464 aCol.SetGreen( cMapG[ aCol.GetGreen() ] ); 3465 aCol.SetBlue( cMapB[ aCol.GetBlue() ] ); 3466 pAcc->SetPixel( nY, nX, aCol ); 3467 } 3468 } 3469 } 3470 3471 delete[] cMapR; 3472 delete[] cMapG; 3473 delete[] cMapB; 3474 ReleaseAccess( pAcc ); 3475 bRet = sal_True; 3476 } 3477 } 3478 3479 return bRet; 3480 } 3481