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 #ifdef DBG_UTIL 910 // #121233# allow to test the different scalers in debug build with source 911 // level debugger (change nNumber to desired action) 912 static sal_uInt16 nNumber(0); 913 914 switch(nNumber) 915 { 916 case 0 : break; 917 case 1: nScaleFlag = BMP_SCALE_FAST; break; 918 case 2: nScaleFlag = BMP_SCALE_INTERPOLATE; break; 919 case 3: nScaleFlag = BMP_SCALE_SUPER; break; 920 case 4: nScaleFlag = BMP_SCALE_LANCZOS; break; 921 case 5: nScaleFlag = BMP_SCALE_BICUBIC; break; 922 case 6: nScaleFlag = BMP_SCALE_BILINEAR; break; 923 case 7: nScaleFlag = BMP_SCALE_BOX; break; 924 case 8: nScaleFlag = BMP_SCALE_BESTQUALITY; break; 925 case 9: nScaleFlag = BMP_SCALE_FASTESTINTERPOLATE; break; 926 } 927 #endif // DBG_UTIL 928 929 if(basegfx::fTools::equalZero(rScaleX) && basegfx::fTools::equalZero(rScaleY)) 930 { 931 // no scale 932 return true; 933 } 934 else 935 { 936 if(BMP_SCALE_BESTQUALITY == nScaleFlag) 937 { 938 // Use LANCZOS when best quality is requested 939 nScaleFlag = BMP_SCALE_LANCZOS; 940 } 941 else if(BMP_SCALE_FASTESTINTERPOLATE == nScaleFlag) 942 { 943 // Use BMP_SCALE_SUPER when speed is requested, but not worst quality 944 nScaleFlag = BMP_SCALE_SUPER; 945 } 946 947 switch(nScaleFlag) 948 { 949 default: 950 case BMP_SCALE_NONE : 951 { 952 return false; 953 break; 954 } 955 case BMP_SCALE_FAST : 956 { 957 return ImplScaleFast( rScaleX, rScaleY ); 958 break; 959 } 960 case BMP_SCALE_INTERPOLATE : 961 { 962 return ImplScaleInterpolate( rScaleX, rScaleY ); 963 break; 964 } 965 case BMP_SCALE_SUPER : 966 { 967 if(GetSizePixel().Width() < 2 || GetSizePixel().Height() < 2) 968 { 969 // fallback to ImplScaleFast 970 return ImplScaleFast( rScaleX, rScaleY ); 971 } 972 else 973 { 974 // #121233# use method from symphony 975 return ImplScaleSuper( rScaleX, rScaleY ); 976 } 977 break; 978 } 979 case BMP_SCALE_LANCZOS : 980 { 981 const Lanczos3Kernel kernel; 982 983 return ImplScaleConvolution( rScaleX, rScaleY, kernel); 984 break; 985 } 986 case BMP_SCALE_BICUBIC : 987 { 988 const BicubicKernel kernel; 989 990 return ImplScaleConvolution( rScaleX, rScaleY, kernel ); 991 break; 992 } 993 case BMP_SCALE_BILINEAR : 994 { 995 const BilinearKernel kernel; 996 997 return ImplScaleConvolution( rScaleX, rScaleY, kernel ); 998 break; 999 } 1000 case BMP_SCALE_BOX : 1001 { 1002 const BoxKernel kernel; 1003 1004 return ImplScaleConvolution( rScaleX, rScaleY, kernel ); 1005 break; 1006 } 1007 } 1008 } 1009 1010 // should not happen 1011 return false; 1012 } 1013 1014 // ------------------------------------------------------------------------ 1015 1016 sal_Bool Bitmap::Scale( const Size& rNewSize, sal_uLong nScaleFlag ) 1017 { 1018 const Size aSize( GetSizePixel() ); 1019 sal_Bool bRet; 1020 1021 if( aSize.Width() && aSize.Height() ) 1022 { 1023 bRet = Scale( (double) rNewSize.Width() / aSize.Width(), 1024 (double) rNewSize.Height() / aSize.Height(), 1025 nScaleFlag ); 1026 } 1027 else 1028 bRet = sal_True; 1029 1030 return bRet; 1031 } 1032 1033 // ------------------------------------------------------------------------ 1034 1035 void Bitmap::ImplAdaptBitCount(Bitmap& rNew) 1036 { 1037 // aNew is the result of some operation; adapt it's BitCount to the original (this) 1038 if(GetBitCount() != rNew.GetBitCount()) 1039 { 1040 switch(GetBitCount()) 1041 { 1042 case 1: 1043 { 1044 rNew.Convert(BMP_CONVERSION_1BIT_THRESHOLD); 1045 break; 1046 } 1047 case 4: 1048 { 1049 if(HasGreyPalette()) 1050 { 1051 rNew.Convert(BMP_CONVERSION_4BIT_GREYS); 1052 } 1053 else 1054 { 1055 rNew.Convert(BMP_CONVERSION_4BIT_COLORS); 1056 } 1057 break; 1058 } 1059 case 8: 1060 { 1061 if(HasGreyPalette()) 1062 { 1063 rNew.Convert(BMP_CONVERSION_8BIT_GREYS); 1064 } 1065 else 1066 { 1067 rNew.Convert(BMP_CONVERSION_8BIT_COLORS); 1068 } 1069 break; 1070 } 1071 case 24: 1072 { 1073 rNew.Convert(BMP_CONVERSION_24BIT); 1074 break; 1075 } 1076 default: 1077 { 1078 OSL_ENSURE(false, "BitDepth adaption failed (!)"); 1079 break; 1080 } 1081 } 1082 } 1083 } 1084 1085 // ------------------------------------------------------------------------ 1086 1087 sal_Bool Bitmap::ImplScaleFast( const double& rScaleX, const double& rScaleY ) 1088 { 1089 const Size aSizePix( GetSizePixel() ); 1090 const long nNewWidth = FRound( aSizePix.Width() * rScaleX ); 1091 const long nNewHeight = FRound( aSizePix.Height() * rScaleY ); 1092 sal_Bool bRet = sal_False; 1093 1094 if( nNewWidth && nNewHeight ) 1095 { 1096 BitmapReadAccess* pReadAcc = AcquireReadAccess(); 1097 if ( !pReadAcc ) 1098 return sal_False; 1099 1100 Bitmap aNewBmp( Size( nNewWidth, nNewHeight ), GetBitCount(), &pReadAcc->GetPalette() ); 1101 BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess(); 1102 1103 if( pWriteAcc ) 1104 { 1105 const long nScanlineSize = pWriteAcc->GetScanlineSize(); 1106 const long nNewWidth1 = nNewWidth - 1L; 1107 const long nNewHeight1 = nNewHeight - 1L; 1108 const long nWidth = pReadAcc->Width(); 1109 const long nHeight = pReadAcc->Height(); 1110 long* pLutX = new long[ nNewWidth ]; 1111 long* pLutY = new long[ nNewHeight ]; 1112 long nX, nY, nMapY, nActY = 0L; 1113 1114 if( nNewWidth1 && nNewHeight1 ) 1115 { 1116 for( nX = 0L; nX < nNewWidth; nX++ ) 1117 pLutX[ nX ] = nX * nWidth / nNewWidth; 1118 1119 for( nY = 0L; nY < nNewHeight; nY++ ) 1120 pLutY[ nY ] = nY * nHeight / nNewHeight; 1121 1122 while( nActY < nNewHeight ) 1123 { 1124 nMapY = pLutY[ nActY ]; 1125 1126 for( nX = 0L; nX < nNewWidth; nX++ ) 1127 pWriteAcc->SetPixel( nActY, nX, pReadAcc->GetPixel( nMapY , pLutX[ nX ] ) ); 1128 1129 while( ( nActY < nNewHeight1 ) && ( pLutY[ nActY + 1 ] == nMapY ) ) 1130 { 1131 memcpy( pWriteAcc->GetScanline( nActY + 1L ), 1132 pWriteAcc->GetScanline( nActY ), nScanlineSize ); 1133 nActY++; 1134 } 1135 1136 nActY++; 1137 } 1138 1139 bRet = sal_True; 1140 } 1141 1142 delete[] pLutX; 1143 delete[] pLutY; 1144 } 1145 1146 ReleaseAccess( pReadAcc ); 1147 aNewBmp.ReleaseAccess( pWriteAcc ); 1148 1149 if( bRet ) 1150 ImplAssignWithSize( aNewBmp ); 1151 } 1152 1153 return bRet; 1154 } 1155 1156 // ------------------------------------------------------------------------ 1157 1158 sal_Bool Bitmap::ImplScaleInterpolate( const double& rScaleX, const double& rScaleY ) 1159 { 1160 const Size aSizePix( GetSizePixel() ); 1161 const long nNewWidth = FRound( aSizePix.Width() * rScaleX ); 1162 const long nNewHeight = FRound( aSizePix.Height() * rScaleY ); 1163 sal_Bool bRet = sal_False; 1164 1165 if( ( nNewWidth > 1L ) && ( nNewHeight > 1L ) ) 1166 { 1167 BitmapColor aCol0; 1168 BitmapColor aCol1; 1169 BitmapReadAccess* pReadAcc = AcquireReadAccess(); 1170 long nWidth = pReadAcc->Width(); 1171 long nHeight = pReadAcc->Height(); 1172 Bitmap aNewBmp( Size( nNewWidth, nHeight ), 24 ); 1173 BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess(); 1174 long* pLutInt; 1175 long* pLutFrac; 1176 long nX, nY; 1177 long lXB0, lXB1, lXG0, lXG1, lXR0, lXR1; 1178 double fTemp; 1179 long nTemp; 1180 1181 if( pReadAcc && pWriteAcc ) 1182 { 1183 const long nNewWidth1 = nNewWidth - 1L; 1184 const long nWidth1 = pReadAcc->Width() - 1L; 1185 const double fRevScaleX = (double) nWidth1 / nNewWidth1; 1186 1187 pLutInt = new long[ nNewWidth ]; 1188 pLutFrac = new long[ nNewWidth ]; 1189 1190 for( nX = 0L, nTemp = nWidth - 2L; nX < nNewWidth; nX++ ) 1191 { 1192 fTemp = nX * fRevScaleX; 1193 pLutInt[ nX ] = MinMax( (long) fTemp, 0, nTemp ); 1194 fTemp -= pLutInt[ nX ]; 1195 pLutFrac[ nX ] = (long) ( fTemp * 1024. ); 1196 } 1197 1198 if( pReadAcc->HasPalette() ) 1199 { 1200 for( nY = 0L; nY < nHeight; nY++ ) 1201 { 1202 if( 1 == nWidth ) 1203 { 1204 aCol0 = pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nY, 0 ) ); 1205 1206 for( nX = 0L; nX < nNewWidth; nX++ ) 1207 pWriteAcc->SetPixel( nY, nX, aCol0 ); 1208 } 1209 else 1210 { 1211 for( nX = 0L; nX < nNewWidth; nX++ ) 1212 { 1213 nTemp = pLutInt[ nX ]; 1214 1215 aCol0 = pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nY, nTemp++ ) ); 1216 aCol1 = pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nY, nTemp ) ); 1217 1218 nTemp = pLutFrac[ nX ]; 1219 1220 lXR1 = aCol1.GetRed() - ( lXR0 = aCol0.GetRed() ); 1221 lXG1 = aCol1.GetGreen() - ( lXG0 = aCol0.GetGreen() ); 1222 lXB1 = aCol1.GetBlue() - ( lXB0 = aCol0.GetBlue() ); 1223 1224 aCol0.SetRed( (sal_uInt8) ( ( lXR1 * nTemp + ( lXR0 << 10 ) ) >> 10 ) ); 1225 aCol0.SetGreen( (sal_uInt8) ( ( lXG1 * nTemp + ( lXG0 << 10 ) ) >> 10 ) ); 1226 aCol0.SetBlue( (sal_uInt8) ( ( lXB1 * nTemp + ( lXB0 << 10 ) ) >> 10 ) ); 1227 1228 pWriteAcc->SetPixel( nY, nX, aCol0 ); 1229 } 1230 } 1231 } 1232 } 1233 else 1234 { 1235 for( nY = 0L; nY < nHeight; nY++ ) 1236 { 1237 if( 1 == nWidth ) 1238 { 1239 aCol0 = pReadAcc->GetPixel( nY, 0 ); 1240 1241 for( nX = 0L; nX < nNewWidth; nX++ ) 1242 pWriteAcc->SetPixel( nY, nX, aCol0 ); 1243 } 1244 else 1245 { 1246 for( nX = 0L; nX < nNewWidth; nX++ ) 1247 { 1248 nTemp = pLutInt[ nX ]; 1249 1250 aCol0 = pReadAcc->GetPixel( nY, nTemp++ ); 1251 aCol1 = pReadAcc->GetPixel( nY, nTemp ); 1252 1253 nTemp = pLutFrac[ nX ]; 1254 1255 lXR1 = aCol1.GetRed() - ( lXR0 = aCol0.GetRed() ); 1256 lXG1 = aCol1.GetGreen() - ( lXG0 = aCol0.GetGreen() ); 1257 lXB1 = aCol1.GetBlue() - ( lXB0 = aCol0.GetBlue() ); 1258 1259 aCol0.SetRed( (sal_uInt8) ( ( lXR1 * nTemp + ( lXR0 << 10 ) ) >> 10 ) ); 1260 aCol0.SetGreen( (sal_uInt8) ( ( lXG1 * nTemp + ( lXG0 << 10 ) ) >> 10 ) ); 1261 aCol0.SetBlue( (sal_uInt8) ( ( lXB1 * nTemp + ( lXB0 << 10 ) ) >> 10 ) ); 1262 1263 pWriteAcc->SetPixel( nY, nX, aCol0 ); 1264 } 1265 } 1266 } 1267 } 1268 1269 delete[] pLutInt; 1270 delete[] pLutFrac; 1271 bRet = sal_True; 1272 } 1273 1274 ReleaseAccess( pReadAcc ); 1275 aNewBmp.ReleaseAccess( pWriteAcc ); 1276 1277 if( bRet ) 1278 { 1279 bRet = sal_False; 1280 ImplAdaptBitCount(aNewBmp); 1281 ImplAssignWithSize( aNewBmp ); 1282 pReadAcc = AcquireReadAccess(); 1283 aNewBmp = Bitmap( Size( nNewWidth, nNewHeight ), 24 ); 1284 pWriteAcc = aNewBmp.AcquireWriteAccess(); 1285 1286 if( pReadAcc && pWriteAcc ) 1287 { 1288 const long nNewHeight1 = nNewHeight - 1L; 1289 const long nHeight1 = pReadAcc->Height() - 1L; 1290 const double fRevScaleY = (double) nHeight1 / nNewHeight1; 1291 1292 pLutInt = new long[ nNewHeight ]; 1293 pLutFrac = new long[ nNewHeight ]; 1294 1295 for( nY = 0L, nTemp = nHeight - 2L; nY < nNewHeight; nY++ ) 1296 { 1297 fTemp = nY * fRevScaleY; 1298 pLutInt[ nY ] = MinMax( (long) fTemp, 0, nTemp ); 1299 fTemp -= pLutInt[ nY ]; 1300 pLutFrac[ nY ] = (long) ( fTemp * 1024. ); 1301 } 1302 1303 if( pReadAcc->HasPalette() ) 1304 { 1305 for( nX = 0L; nX < nNewWidth; nX++ ) 1306 { 1307 if( 1 == nHeight ) 1308 { 1309 aCol0 = pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( 0, nX ) ); 1310 1311 for( nY = 0L; nY < nNewHeight; nY++ ) 1312 pWriteAcc->SetPixel( nY, nX, aCol0 ); 1313 } 1314 else 1315 { 1316 for( nY = 0L; nY < nNewHeight; nY++ ) 1317 { 1318 nTemp = pLutInt[ nY ]; 1319 1320 aCol0 = pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nTemp++, nX ) ); 1321 aCol1 = pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nTemp, nX ) ); 1322 1323 nTemp = pLutFrac[ nY ]; 1324 1325 lXR1 = aCol1.GetRed() - ( lXR0 = aCol0.GetRed() ); 1326 lXG1 = aCol1.GetGreen() - ( lXG0 = aCol0.GetGreen() ); 1327 lXB1 = aCol1.GetBlue() - ( lXB0 = aCol0.GetBlue() ); 1328 1329 aCol0.SetRed( (sal_uInt8) ( ( lXR1 * nTemp + ( lXR0 << 10 ) ) >> 10 ) ); 1330 aCol0.SetGreen( (sal_uInt8) ( ( lXG1 * nTemp + ( lXG0 << 10 ) ) >> 10 ) ); 1331 aCol0.SetBlue( (sal_uInt8) ( ( lXB1 * nTemp + ( lXB0 << 10 ) ) >> 10 ) ); 1332 1333 pWriteAcc->SetPixel( nY, nX, aCol0 ); 1334 } 1335 } 1336 } 1337 } 1338 else 1339 { 1340 for( nX = 0L; nX < nNewWidth; nX++ ) 1341 { 1342 if( 1 == nHeight ) 1343 { 1344 aCol0 = pReadAcc->GetPixel( 0, nX ); 1345 1346 for( nY = 0L; nY < nNewHeight; nY++ ) 1347 pWriteAcc->SetPixel( nY, nX, aCol0 ); 1348 } 1349 else 1350 { 1351 for( nY = 0L; nY < nNewHeight; nY++ ) 1352 { 1353 nTemp = pLutInt[ nY ]; 1354 1355 aCol0 = pReadAcc->GetPixel( nTemp++, nX ); 1356 aCol1 = pReadAcc->GetPixel( nTemp, nX ); 1357 1358 nTemp = pLutFrac[ nY ]; 1359 1360 lXR1 = aCol1.GetRed() - ( lXR0 = aCol0.GetRed() ); 1361 lXG1 = aCol1.GetGreen() - ( lXG0 = aCol0.GetGreen() ); 1362 lXB1 = aCol1.GetBlue() - ( lXB0 = aCol0.GetBlue() ); 1363 1364 aCol0.SetRed( (sal_uInt8) ( ( lXR1 * nTemp + ( lXR0 << 10 ) ) >> 10 ) ); 1365 aCol0.SetGreen( (sal_uInt8) ( ( lXG1 * nTemp + ( lXG0 << 10 ) ) >> 10 ) ); 1366 aCol0.SetBlue( (sal_uInt8) ( ( lXB1 * nTemp + ( lXB0 << 10 ) ) >> 10 ) ); 1367 1368 pWriteAcc->SetPixel( nY, nX, aCol0 ); 1369 } 1370 } 1371 } 1372 } 1373 1374 delete[] pLutInt; 1375 delete[] pLutFrac; 1376 bRet = sal_True; 1377 } 1378 1379 ReleaseAccess( pReadAcc ); 1380 aNewBmp.ReleaseAccess( pWriteAcc ); 1381 1382 if( bRet ) 1383 { 1384 ImplAdaptBitCount(aNewBmp); 1385 ImplAssignWithSize( aNewBmp ); 1386 } 1387 } 1388 } 1389 1390 if( !bRet ) 1391 bRet = ImplScaleFast( rScaleX, rScaleY ); 1392 1393 return bRet; 1394 } 1395 1396 // ------------------------------------------------------------------------ 1397 // #121233# Added BMP_SCALE_SUPER from symphony code 1398 1399 sal_Bool Bitmap::ImplScaleSuper( 1400 const double& rScaleX, 1401 const double& rScaleY ) 1402 { 1403 const Size aSizePix( GetSizePixel() ); 1404 bool bHMirr = ( rScaleX < 0 ); 1405 bool bVMirr = ( rScaleY < 0 ); 1406 double scaleX = bHMirr ? -rScaleX : rScaleX; 1407 double scaleY = bVMirr ? -rScaleY : rScaleY; 1408 const long nDstW = FRound( aSizePix.Width() * scaleX ); 1409 const long nDstH = FRound( aSizePix.Height() * scaleY ); 1410 const double fScaleThresh = 0.6; 1411 bool bRet = false; 1412 1413 if( ( nDstW > 1L ) && ( nDstH > 1L ) ) 1414 { 1415 BitmapColor aCol0, aCol1, aColRes; 1416 BitmapReadAccess* pAcc = AcquireReadAccess(); 1417 long nW = pAcc->Width() ; 1418 long nH = pAcc->Height() ; 1419 Bitmap aOutBmp( Size( nDstW, nDstH ), 24 ); 1420 BitmapWriteAccess* pWAcc = aOutBmp.AcquireWriteAccess(); 1421 long* pMapIX = new long[ nDstW ]; 1422 long* pMapIY = new long[ nDstH ]; 1423 long* pMapFX = new long[ nDstW ]; 1424 long* pMapFY = new long[ nDstH ]; 1425 long nX, nY, nXDst, nYDst;; 1426 double fTemp; 1427 long nTemp , nTempX, nTempY, nTempFX, nTempFY; 1428 sal_uInt8 cR0, cG0, cB0, cR1, cG1, cB1; 1429 long nStartX = 0 , nStartY = 0; 1430 long nEndX = nDstW - 1L; 1431 long nEndY = nDstH - 1L; 1432 long nMax = 1 << 7L; 1433 1434 if( pAcc && pWAcc ) 1435 { 1436 const double fRevScaleX = ( nDstW > 1L ) ? ( (double) ( nW - 1 ) / ( nDstW - 1 ) ) : 0.0; 1437 const double fRevScaleY = ( nDstH > 1L ) ? ( (double) ( nH - 1 ) / ( nDstH - 1 ) ) : 0.0; 1438 1439 // create horizontal mapping table 1440 for( nX = 0L, nTempX = nW - 1L, nTemp = nW - 2L; nX < nDstW; nX++ ) 1441 { 1442 fTemp = nX * fRevScaleX; 1443 1444 if( bHMirr ) 1445 fTemp = nTempX - fTemp; 1446 1447 pMapFX[ nX ] = (long) ( ( fTemp - ( pMapIX[ nX ] = MinMax( (long) fTemp, 0, nTemp ) ) ) * 128. ); 1448 } 1449 1450 // create vertical mapping table 1451 for( nY = 0L, nTempY = nH - 1L, nTemp = nH - 2L; nY < nDstH; nY++ ) 1452 { 1453 fTemp = nY * fRevScaleY; 1454 1455 if( bVMirr ) 1456 fTemp = nTempY - fTemp; 1457 1458 pMapFY[ nY ] = (long) ( ( fTemp - ( pMapIY[ nY ] = MinMax( (long) fTemp, 0, nTemp ) ) ) * 128. ); 1459 } 1460 1461 if( pAcc->HasPalette() ) 1462 { 1463 if( pAcc->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL ) 1464 { 1465 if( scaleX >= fScaleThresh && scaleY >= fScaleThresh ) 1466 { 1467 Scanline pLine0, pLine1; 1468 1469 for( nY = nStartY, nYDst = 0L; nY <= nEndY; nY++, nYDst++ ) 1470 { 1471 nTempY = pMapIY[ nY ]; nTempFY = pMapFY[ nY ]; 1472 pLine0 = pAcc->GetScanline( nTempY ); 1473 pLine1 = pAcc->GetScanline( ++nTempY ); 1474 1475 for( nX = nStartX, nXDst = 0L; nX <= nEndX; nX++ ) 1476 { 1477 nTempX = pMapIX[ nX ]; nTempFX = pMapFX[ nX ]; 1478 1479 const BitmapColor& rCol0 = pAcc->GetPaletteColor( pLine0[ nTempX ] ); 1480 const BitmapColor& rCol2 = pAcc->GetPaletteColor( pLine1[ nTempX ] ); 1481 const BitmapColor& rCol1 = pAcc->GetPaletteColor( pLine0[ ++nTempX ] ); 1482 const BitmapColor& rCol3 = pAcc->GetPaletteColor( pLine1[ nTempX ] ); 1483 1484 cR0 = MAP( rCol0.GetRed(), rCol1.GetRed(), nTempFX ); 1485 cG0 = MAP( rCol0.GetGreen(), rCol1.GetGreen(), nTempFX ); 1486 cB0 = MAP( rCol0.GetBlue(), rCol1.GetBlue(), nTempFX ); 1487 1488 cR1 = MAP( rCol2.GetRed(), rCol3.GetRed(), nTempFX ); 1489 cG1 = MAP( rCol2.GetGreen(), rCol3.GetGreen(), nTempFX ); 1490 cB1 = MAP( rCol2.GetBlue(), rCol3.GetBlue(), nTempFX ); 1491 1492 aColRes.SetRed( MAP( cR0, cR1, nTempFY ) ); 1493 aColRes.SetGreen( MAP( cG0, cG1, nTempFY ) ); 1494 aColRes.SetBlue( MAP( cB0, cB1, nTempFY ) ); 1495 pWAcc->SetPixel( nYDst, nXDst++, aColRes ); 1496 } 1497 } 1498 } 1499 else 1500 { 1501 Scanline pTmpY; 1502 long nSumR, nSumG, nSumB,nLineStart , nLineRange, nRowStart , nRowRange ; 1503 long nLeft, nRight, nTop, nBottom, nWeightX, nWeightY ; 1504 long nSumRowR ,nSumRowG,nSumRowB, nTotalWeightX, nTotalWeightY; 1505 1506 for( nY = nStartY , nYDst = 0L; nY <= nEndY; nY++, nYDst++ ) 1507 { 1508 nTop = bVMirr ? ( nY + 1 ) : nY; 1509 nBottom = bVMirr ? nY : ( nY + 1 ) ; 1510 1511 if( nY ==nEndY ) 1512 { 1513 nLineStart = pMapIY[ nY ]; 1514 nLineRange = 0; 1515 } 1516 else 1517 { 1518 nLineStart = pMapIY[ nTop ] ; 1519 nLineRange = ( pMapIY[ nBottom ] == pMapIY[ nTop ] ) ? 1 :( pMapIY[ nBottom ] - pMapIY[ nTop ] ); 1520 } 1521 1522 for( nX = nStartX , nXDst = 0L; nX <= nEndX; nX++ ) 1523 { 1524 nLeft = bHMirr ? ( nX + 1 ) : nX; 1525 nRight = bHMirr ? nX : ( nX + 1 ) ; 1526 1527 if( nX == nEndX ) 1528 { 1529 nRowStart = pMapIX[ nX ]; 1530 nRowRange = 0; 1531 } 1532 else 1533 { 1534 nRowStart = pMapIX[ nLeft ]; 1535 nRowRange = ( pMapIX[ nRight ] == pMapIX[ nLeft ] )? 1 : ( pMapIX[ nRight ] - pMapIX[ nLeft ] ); 1536 } 1537 1538 nSumR = nSumG = nSumB = 0; 1539 nTotalWeightY = 0; 1540 1541 for(int i = 0; i<= nLineRange; i++) 1542 { 1543 pTmpY = pAcc->GetScanline( nLineStart + i ); 1544 nSumRowR = nSumRowG = nSumRowB = 0; 1545 nTotalWeightX = 0; 1546 1547 for(int j = 0; j <= nRowRange; j++) 1548 { 1549 const BitmapColor& rCol = pAcc->GetPaletteColor( pTmpY[ nRowStart + j ] ); 1550 1551 if(nX == nEndX ) 1552 { 1553 nSumRowB += rCol.GetBlue() << 7L; 1554 nSumRowG += rCol.GetGreen() << 7L; 1555 nSumRowR += rCol.GetRed() << 7L; 1556 nTotalWeightX += 1 << 7L; 1557 } 1558 else if( j == 0 ) 1559 { 1560 nWeightX = (nMax- pMapFX[ nLeft ]) ; 1561 nSumRowB += ( nWeightX *rCol.GetBlue()) ; 1562 nSumRowG += ( nWeightX *rCol.GetGreen()) ; 1563 nSumRowR += ( nWeightX *rCol.GetRed()) ; 1564 nTotalWeightX += nWeightX; 1565 } 1566 else if ( nRowRange == j ) 1567 { 1568 nWeightX = pMapFX[ nRight ] ; 1569 nSumRowB += ( nWeightX *rCol.GetBlue() ); 1570 nSumRowG += ( nWeightX *rCol.GetGreen() ); 1571 nSumRowR += ( nWeightX *rCol.GetRed() ); 1572 nTotalWeightX += nWeightX; 1573 } 1574 else 1575 { 1576 nSumRowB += rCol.GetBlue() << 7L; 1577 nSumRowG += rCol.GetGreen() << 7L; 1578 nSumRowR += rCol.GetRed() << 7L; 1579 nTotalWeightX += 1 << 7L; 1580 } 1581 } 1582 1583 if( nY == nEndY ) 1584 nWeightY = nMax; 1585 else if( i == 0 ) 1586 nWeightY = nMax - pMapFY[ nTop ]; 1587 else if( nLineRange == 1 ) 1588 nWeightY = pMapFY[ nTop ]; 1589 else if ( nLineRange == i ) 1590 nWeightY = pMapFY[ nBottom ]; 1591 else 1592 nWeightY = nMax; 1593 1594 nWeightY = nWeightY ; 1595 nSumB += nWeightY * ( nSumRowB / nTotalWeightX ); 1596 nSumG += nWeightY * ( nSumRowG / nTotalWeightX ); 1597 nSumR += nWeightY * ( nSumRowR / nTotalWeightX ); 1598 nTotalWeightY += nWeightY; 1599 } 1600 1601 aColRes.SetRed( ( sal_uInt8 ) (( nSumR / nTotalWeightY ) )); 1602 aColRes.SetGreen( ( sal_uInt8 ) (( nSumG / nTotalWeightY) )); 1603 aColRes.SetBlue( ( sal_uInt8 ) (( nSumB / nTotalWeightY ) )); 1604 pWAcc->SetPixel( nYDst, nXDst++, aColRes ); 1605 1606 } 1607 } 1608 } 1609 } 1610 else 1611 { 1612 if( scaleX >= fScaleThresh && scaleY >= fScaleThresh ) 1613 { 1614 for( nY = nStartY, nYDst = 0L; nY <= nEndY; nY++, nYDst++ ) 1615 { 1616 nTempY = pMapIY[ nY ], nTempFY = pMapFY[ nY ]; 1617 1618 for( nX = nStartX, nXDst = 0L; nX <= nEndX; nX++ ) 1619 { 1620 nTempX = pMapIX[ nX ]; nTempFX = pMapFX[ nX ]; 1621 1622 aCol0 = pAcc->GetPaletteColor( pAcc->GetPixelIndex( nTempY, nTempX ) ); 1623 aCol1 = pAcc->GetPaletteColor( pAcc->GetPixelIndex( nTempY, ++nTempX ) ); 1624 cR0 = MAP( aCol0.GetRed(), aCol1.GetRed(), nTempFX ); 1625 cG0 = MAP( aCol0.GetGreen(), aCol1.GetGreen(), nTempFX ); 1626 cB0 = MAP( aCol0.GetBlue(), aCol1.GetBlue(), nTempFX ); 1627 1628 aCol1 = pAcc->GetPaletteColor( pAcc->GetPixelIndex( ++nTempY, nTempX ) ); 1629 aCol0 = pAcc->GetPaletteColor( pAcc->GetPixelIndex( nTempY--, --nTempX ) ); 1630 cR1 = MAP( aCol0.GetRed(), aCol1.GetRed(), nTempFX ); 1631 cG1 = MAP( aCol0.GetGreen(), aCol1.GetGreen(), nTempFX ); 1632 cB1 = MAP( aCol0.GetBlue(), aCol1.GetBlue(), nTempFX ); 1633 1634 aColRes.SetRed( MAP( cR0, cR1, nTempFY ) ); 1635 aColRes.SetGreen( MAP( cG0, cG1, nTempFY ) ); 1636 aColRes.SetBlue( MAP( cB0, cB1, nTempFY ) ); 1637 pWAcc->SetPixel( nYDst, nXDst++, aColRes ); 1638 } 1639 } 1640 1641 } 1642 else 1643 { 1644 long nSumR, nSumG, nSumB,nLineStart , nLineRange, nRowStart , nRowRange ; 1645 long nLeft, nRight, nTop, nBottom, nWeightX, nWeightY ; 1646 long nSumRowR ,nSumRowG,nSumRowB, nTotalWeightX, nTotalWeightY; 1647 1648 for( nY = nStartY , nYDst = 0L; nY <= nEndY; nY++, nYDst++ ) 1649 { 1650 nTop = bVMirr ? ( nY + 1 ) : nY; 1651 nBottom = bVMirr ? nY : ( nY + 1 ) ; 1652 1653 if( nY ==nEndY ) 1654 { 1655 nLineStart = pMapIY[ nY ]; 1656 nLineRange = 0; 1657 } 1658 else 1659 { 1660 nLineStart = pMapIY[ nTop ] ; 1661 nLineRange = ( pMapIY[ nBottom ] == pMapIY[ nTop ] ) ? 1 :( pMapIY[ nBottom ] - pMapIY[ nTop ] ); 1662 } 1663 1664 for( nX = nStartX , nXDst = 0L; nX <= nEndX; nX++ ) 1665 { 1666 nLeft = bHMirr ? ( nX + 1 ) : nX; 1667 nRight = bHMirr ? nX : ( nX + 1 ) ; 1668 1669 if( nX == nEndX ) 1670 { 1671 nRowStart = pMapIX[ nX ]; 1672 nRowRange = 0; 1673 } 1674 else 1675 { 1676 nRowStart = pMapIX[ nLeft ]; 1677 nRowRange = ( pMapIX[ nRight ] == pMapIX[ nLeft ] )? 1 : ( pMapIX[ nRight ] - pMapIX[ nLeft ] ); 1678 } 1679 1680 nSumR = nSumG = nSumB = 0; 1681 nTotalWeightY = 0; 1682 1683 for(int i = 0; i<= nLineRange; i++) 1684 { 1685 nSumRowR = nSumRowG = nSumRowB = 0; 1686 nTotalWeightX = 0; 1687 1688 for(int j = 0; j <= nRowRange; j++) 1689 { 1690 aCol0 = pAcc->GetPaletteColor ( pAcc->GetPixelIndex( nLineStart + i, nRowStart + j ) ); 1691 1692 if(nX == nEndX ) 1693 { 1694 1695 nSumRowB += aCol0.GetBlue() << 7L; 1696 nSumRowG += aCol0.GetGreen() << 7L; 1697 nSumRowR += aCol0.GetRed() << 7L; 1698 nTotalWeightX += 1 << 7L; 1699 } 1700 else if( j == 0 ) 1701 { 1702 1703 nWeightX = (nMax- pMapFX[ nLeft ]) ; 1704 nSumRowB += ( nWeightX *aCol0.GetBlue()) ; 1705 nSumRowG += ( nWeightX *aCol0.GetGreen()) ; 1706 nSumRowR += ( nWeightX *aCol0.GetRed()) ; 1707 nTotalWeightX += nWeightX; 1708 } 1709 else if ( nRowRange == j ) 1710 { 1711 1712 nWeightX = pMapFX[ nRight ] ; 1713 nSumRowB += ( nWeightX *aCol0.GetBlue() ); 1714 nSumRowG += ( nWeightX *aCol0.GetGreen() ); 1715 nSumRowR += ( nWeightX *aCol0.GetRed() ); 1716 nTotalWeightX += nWeightX; 1717 } 1718 else 1719 { 1720 1721 nSumRowB += aCol0.GetBlue() << 7L; 1722 nSumRowG += aCol0.GetGreen() << 7L; 1723 nSumRowR += aCol0.GetRed() << 7L; 1724 nTotalWeightX += 1 << 7L; 1725 } 1726 } 1727 1728 if( nY == nEndY ) 1729 nWeightY = nMax; 1730 else if( i == 0 ) 1731 nWeightY = nMax - pMapFY[ nTop ]; 1732 else if( nLineRange == 1 ) 1733 nWeightY = pMapFY[ nTop ]; 1734 else if ( nLineRange == i ) 1735 nWeightY = pMapFY[ nBottom ]; 1736 else 1737 nWeightY = nMax; 1738 1739 nWeightY = nWeightY ; 1740 nSumB += nWeightY * ( nSumRowB / nTotalWeightX ); 1741 nSumG += nWeightY * ( nSumRowG / nTotalWeightX ); 1742 nSumR += nWeightY * ( nSumRowR / nTotalWeightX ); 1743 nTotalWeightY += nWeightY; 1744 } 1745 1746 aColRes.SetRed( ( sal_uInt8 ) (( nSumR / nTotalWeightY ) )); 1747 aColRes.SetGreen( ( sal_uInt8 ) (( nSumG / nTotalWeightY) )); 1748 aColRes.SetBlue( ( sal_uInt8 ) (( nSumB / nTotalWeightY ) )); 1749 pWAcc->SetPixel( nYDst, nXDst++, aColRes ); 1750 } 1751 } 1752 } 1753 } 1754 } 1755 else 1756 { 1757 if( pAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_BGR ) 1758 { 1759 if( scaleX >= fScaleThresh && scaleY >= fScaleThresh ) 1760 { 1761 Scanline pLine0, pLine1, pTmp0, pTmp1; 1762 long nOff; 1763 1764 for( nY = nStartY, nYDst = 0L; nY <= nEndY; nY++, nYDst++ ) 1765 { 1766 nTempY = pMapIY[ nY ]; nTempFY = pMapFY[ nY ]; 1767 pLine0 = pAcc->GetScanline( nTempY ); 1768 pLine1 = pAcc->GetScanline( ++nTempY ); 1769 1770 for( nX = nStartX, nXDst = 0L; nX <= nEndX; nX++ ) 1771 { 1772 nOff = 3L * ( nTempX = pMapIX[ nX ] ); 1773 nTempFX = pMapFX[ nX ]; 1774 1775 pTmp1 = ( pTmp0 = pLine0 + nOff ) + 3L; 1776 cB0 = MAP( *pTmp0, *pTmp1, nTempFX ); pTmp0++; pTmp1++; 1777 cG0 = MAP( *pTmp0, *pTmp1, nTempFX ); pTmp0++; pTmp1++; 1778 cR0 = MAP( *pTmp0, *pTmp1, nTempFX ); 1779 1780 pTmp1 = ( pTmp0 = pLine1 + nOff ) + 3L; 1781 cB1 = MAP( *pTmp0, *pTmp1, nTempFX ); pTmp0++; pTmp1++; 1782 cG1 = MAP( *pTmp0, *pTmp1, nTempFX ); pTmp0++; pTmp1++; 1783 cR1 = MAP( *pTmp0, *pTmp1, nTempFX ); 1784 1785 aColRes.SetRed( MAP( cR0, cR1, nTempFY ) ); 1786 aColRes.SetGreen( MAP( cG0, cG1, nTempFY ) ); 1787 aColRes.SetBlue( MAP( cB0, cB1, nTempFY ) ); 1788 pWAcc->SetPixel( nYDst, nXDst++, aColRes ); 1789 } 1790 } 1791 } 1792 else 1793 { 1794 Scanline pTmpY, pTmpX; 1795 long nSumR, nSumG, nSumB,nLineStart , nLineRange, nRowStart , nRowRange ; 1796 long nLeft, nRight, nTop, nBottom, nWeightX, nWeightY ; 1797 long nSumRowR ,nSumRowG,nSumRowB, nTotalWeightX, nTotalWeightY; 1798 1799 for( nY = nStartY , nYDst = 0L; nY <= nEndY; nY++, nYDst++ ) 1800 { 1801 nTop = bVMirr ? ( nY + 1 ) : nY; 1802 nBottom = bVMirr ? nY : ( nY + 1 ) ; 1803 1804 if( nY ==nEndY ) 1805 { 1806 nLineStart = pMapIY[ nY ]; 1807 nLineRange = 0; 1808 } 1809 else 1810 { 1811 nLineStart = pMapIY[ nTop ] ; 1812 nLineRange = ( pMapIY[ nBottom ] == pMapIY[ nTop ] ) ? 1 :( pMapIY[ nBottom ] - pMapIY[ nTop ] ); 1813 } 1814 1815 for( nX = nStartX , nXDst = 0L; nX <= nEndX; nX++ ) 1816 { 1817 nLeft = bHMirr ? ( nX + 1 ) : nX; 1818 nRight = bHMirr ? nX : ( nX + 1 ) ; 1819 1820 if( nX == nEndX ) 1821 { 1822 nRowStart = pMapIX[ nX ]; 1823 nRowRange = 0; 1824 } 1825 else 1826 { 1827 nRowStart = pMapIX[ nLeft ]; 1828 nRowRange = ( pMapIX[ nRight ] == pMapIX[ nLeft ] )? 1 : ( pMapIX[ nRight ] - pMapIX[ nLeft ] ); 1829 } 1830 1831 nSumR = nSumG = nSumB = 0; 1832 nTotalWeightY = 0; 1833 1834 for(int i = 0; i<= nLineRange; i++) 1835 { 1836 pTmpY = pAcc->GetScanline( nLineStart + i ); 1837 pTmpX = pTmpY + 3L * nRowStart; 1838 nSumRowR = nSumRowG = nSumRowB = 0; 1839 nTotalWeightX = 0; 1840 1841 for(int j = 0; j <= nRowRange; j++) 1842 { 1843 if(nX == nEndX ) 1844 { 1845 nSumRowB += ( *pTmpX ) << 7L;pTmpX++; 1846 nSumRowG += ( *pTmpX ) << 7L;pTmpX++; 1847 nSumRowR += ( *pTmpX ) << 7L;pTmpX++; 1848 nTotalWeightX += 1 << 7L; 1849 } 1850 else if( j == 0 ) 1851 { 1852 nWeightX = (nMax- pMapFX[ nLeft ]) ; 1853 nSumRowB += ( nWeightX *( *pTmpX )) ;pTmpX++; 1854 nSumRowG += ( nWeightX *( *pTmpX )) ;pTmpX++; 1855 nSumRowR += ( nWeightX *( *pTmpX )) ;pTmpX++; 1856 nTotalWeightX += nWeightX; 1857 } 1858 else if ( nRowRange == j ) 1859 { 1860 nWeightX = pMapFX[ nRight ] ; 1861 nSumRowB += ( nWeightX *( *pTmpX ) );pTmpX++; 1862 nSumRowG += ( nWeightX *( *pTmpX ) );pTmpX++; 1863 nSumRowR += ( nWeightX *( *pTmpX ) );pTmpX++; 1864 nTotalWeightX += nWeightX; 1865 } 1866 else 1867 { 1868 nSumRowB += ( *pTmpX ) << 7L;pTmpX++; 1869 nSumRowG += ( *pTmpX ) << 7L;pTmpX++; 1870 nSumRowR += ( *pTmpX ) << 7L;pTmpX++; 1871 nTotalWeightX += 1 << 7L; 1872 } 1873 } 1874 1875 if( nY == nEndY ) 1876 nWeightY = nMax; 1877 else if( i == 0 ) 1878 nWeightY = nMax - pMapFY[ nTop ]; 1879 else if( nLineRange == 1 ) 1880 nWeightY = pMapFY[ nTop ]; 1881 else if ( nLineRange == i ) 1882 nWeightY = pMapFY[ nBottom ]; 1883 else 1884 nWeightY = nMax; 1885 1886 nWeightY = nWeightY ; 1887 nSumB += nWeightY * ( nSumRowB / nTotalWeightX ); 1888 nSumG += nWeightY * ( nSumRowG / nTotalWeightX ); 1889 nSumR += nWeightY * ( nSumRowR / nTotalWeightX ); 1890 nTotalWeightY += nWeightY; 1891 } 1892 1893 aColRes.SetRed( ( sal_uInt8 ) (( nSumR / nTotalWeightY ) )); 1894 aColRes.SetGreen( ( sal_uInt8 ) (( nSumG / nTotalWeightY) )); 1895 aColRes.SetBlue( ( sal_uInt8 ) (( nSumB / nTotalWeightY ) )); 1896 pWAcc->SetPixel( nYDst, nXDst++, aColRes ); 1897 1898 } 1899 } 1900 } 1901 } 1902 else if( pAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_RGB ) 1903 { 1904 if( scaleX >= fScaleThresh && scaleY >= fScaleThresh ) 1905 { 1906 Scanline pLine0, pLine1, pTmp0, pTmp1; 1907 long nOff; 1908 1909 for( nY = nStartY, nYDst = 0L; nY <= nEndY; nY++, nYDst++ ) 1910 { 1911 nTempY = pMapIY[ nY ]; nTempFY = pMapFY[ nY ]; 1912 pLine0 = pAcc->GetScanline( nTempY ); 1913 pLine1 = pAcc->GetScanline( ++nTempY ); 1914 1915 for( nX = nStartX, nXDst = 0L; nX <= nEndX; nX++ ) 1916 { 1917 nOff = 3L * ( nTempX = pMapIX[ nX ] ); 1918 nTempFX = pMapFX[ nX ]; 1919 1920 pTmp1 = ( pTmp0 = pLine0 + nOff ) + 3L; 1921 cR0 = MAP( *pTmp0, *pTmp1, nTempFX ); pTmp0++; pTmp1++; 1922 cG0 = MAP( *pTmp0, *pTmp1, nTempFX ); pTmp0++; pTmp1++; 1923 cB0 = MAP( *pTmp0, *pTmp1, nTempFX ); 1924 1925 pTmp1 = ( pTmp0 = pLine1 + nOff ) + 3L; 1926 cR1 = MAP( *pTmp0, *pTmp1, nTempFX ); pTmp0++; pTmp1++; 1927 cG1 = MAP( *pTmp0, *pTmp1, nTempFX ); pTmp0++; pTmp1++; 1928 cB1 = MAP( *pTmp0, *pTmp1, nTempFX ); 1929 1930 aColRes.SetRed( MAP( cR0, cR1, nTempFY ) ); 1931 aColRes.SetGreen( MAP( cG0, cG1, nTempFY ) ); 1932 aColRes.SetBlue( MAP( cB0, cB1, nTempFY ) ); 1933 pWAcc->SetPixel( nYDst, nXDst++, aColRes ); 1934 } 1935 } 1936 } 1937 else 1938 { 1939 Scanline pTmpY, pTmpX; 1940 long nSumR, nSumG, nSumB,nLineStart , nLineRange, nRowStart , nRowRange ; 1941 long nLeft, nRight, nTop, nBottom, nWeightX, nWeightY ; 1942 long nSumRowR ,nSumRowG,nSumRowB, nTotalWeightX, nTotalWeightY; 1943 1944 for( nY = nStartY , nYDst = 0L; nY <= nEndY; nY++, nYDst++ ) 1945 { 1946 nTop = bVMirr ? ( nY + 1 ) : nY; 1947 nBottom = bVMirr ? nY : ( nY + 1 ) ; 1948 1949 if( nY ==nEndY ) 1950 { 1951 nLineStart = pMapIY[ nY ]; 1952 nLineRange = 0; 1953 } 1954 else 1955 { 1956 nLineStart = pMapIY[ nTop ] ; 1957 nLineRange = ( pMapIY[ nBottom ] == pMapIY[ nTop ] ) ? 1 :( pMapIY[ nBottom ] - pMapIY[ nTop ] ); 1958 } 1959 1960 for( nX = nStartX , nXDst = 0L; nX <= nEndX; nX++ ) 1961 { 1962 nLeft = bHMirr ? ( nX + 1 ) : nX; 1963 nRight = bHMirr ? nX : ( nX + 1 ) ; 1964 1965 if( nX == nEndX ) 1966 { 1967 nRowStart = pMapIX[ nX ]; 1968 nRowRange = 0; 1969 } 1970 else 1971 { 1972 nRowStart = pMapIX[ nLeft ]; 1973 nRowRange = ( pMapIX[ nRight ] == pMapIX[ nLeft ] )? 1 : ( pMapIX[ nRight ] - pMapIX[ nLeft ] ); 1974 } 1975 1976 nSumR = nSumG = nSumB = 0; 1977 nTotalWeightY = 0; 1978 1979 for(int i = 0; i<= nLineRange; i++) 1980 { 1981 pTmpY = pAcc->GetScanline( nLineStart + i ); 1982 pTmpX = pTmpY + 3L * nRowStart; 1983 nSumRowR = nSumRowG = nSumRowB = 0; 1984 nTotalWeightX = 0; 1985 1986 for(int j = 0; j <= nRowRange; j++) 1987 { 1988 if(nX == nEndX ) 1989 { 1990 nSumRowR += ( *pTmpX ) << 7L;pTmpX++; 1991 nSumRowG += ( *pTmpX ) << 7L;pTmpX++; 1992 nSumRowB += ( *pTmpX ) << 7L;pTmpX++; 1993 nTotalWeightX += 1 << 7L; 1994 } 1995 else if( j == 0 ) 1996 { 1997 nWeightX = (nMax- pMapFX[ nLeft ]) ; 1998 nSumRowR += ( nWeightX *( *pTmpX )) ;pTmpX++; 1999 nSumRowG += ( nWeightX *( *pTmpX )) ;pTmpX++; 2000 nSumRowB += ( nWeightX *( *pTmpX )) ;pTmpX++; 2001 nTotalWeightX += nWeightX; 2002 } 2003 else if ( nRowRange == j ) 2004 { 2005 nWeightX = pMapFX[ nRight ] ; 2006 nSumRowR += ( nWeightX *( *pTmpX ) );pTmpX++; 2007 nSumRowG += ( nWeightX *( *pTmpX ) );pTmpX++; 2008 nSumRowB += ( nWeightX *( *pTmpX ) );pTmpX++; 2009 nTotalWeightX += nWeightX; 2010 } 2011 else 2012 { 2013 nSumRowR += ( *pTmpX ) << 7L;pTmpX++; 2014 nSumRowG += ( *pTmpX ) << 7L;pTmpX++; 2015 nSumRowB += ( *pTmpX ) << 7L;pTmpX++; 2016 nTotalWeightX += 1 << 7L; 2017 } 2018 } 2019 2020 if( nY == nEndY ) 2021 nWeightY = nMax; 2022 else if( i == 0 ) 2023 nWeightY = nMax - pMapFY[ nTop ]; 2024 else if( nLineRange == 1 ) 2025 nWeightY = pMapFY[ nTop ]; 2026 else if ( nLineRange == i ) 2027 nWeightY = pMapFY[ nBottom ]; 2028 else 2029 nWeightY = nMax; 2030 2031 nWeightY = nWeightY ; 2032 nSumB += nWeightY * ( nSumRowB / nTotalWeightX ); 2033 nSumG += nWeightY * ( nSumRowG / nTotalWeightX ); 2034 nSumR += nWeightY * ( nSumRowR / nTotalWeightX ); 2035 nTotalWeightY += nWeightY; 2036 } 2037 2038 aColRes.SetRed( ( sal_uInt8 ) (( nSumR / nTotalWeightY ) )); 2039 aColRes.SetGreen( ( sal_uInt8 ) (( nSumG / nTotalWeightY) )); 2040 aColRes.SetBlue( ( sal_uInt8 ) (( nSumB / nTotalWeightY ) )); 2041 pWAcc->SetPixel( nYDst, nXDst++, aColRes ); 2042 2043 } 2044 } 2045 } 2046 } 2047 else 2048 { 2049 if( scaleX >= fScaleThresh && scaleY >= fScaleThresh ) 2050 { 2051 for( nY = nStartY, nYDst = 0L; nY <= nEndY; nY++, nYDst++ ) 2052 { 2053 nTempY = pMapIY[ nY ]; nTempFY = pMapFY[ nY ]; 2054 2055 for( nX = nStartX, nXDst = 0L; nX <= nEndX; nX++ ) 2056 { 2057 nTempX = pMapIX[ nX ]; nTempFX = pMapFX[ nX ]; 2058 2059 aCol0 = pAcc->GetPixel( nTempY, nTempX ); 2060 aCol1 = pAcc->GetPixel( nTempY, ++nTempX ); 2061 cR0 = MAP( aCol0.GetRed(), aCol1.GetRed(), nTempFX ); 2062 cG0 = MAP( aCol0.GetGreen(), aCol1.GetGreen(), nTempFX ); 2063 cB0 = MAP( aCol0.GetBlue(), aCol1.GetBlue(), nTempFX ); 2064 2065 aCol1 = pAcc->GetPixel( ++nTempY, nTempX ); 2066 aCol0 = pAcc->GetPixel( nTempY--, --nTempX ); 2067 cR1 = MAP( aCol0.GetRed(), aCol1.GetRed(), nTempFX ); 2068 cG1 = MAP( aCol0.GetGreen(), aCol1.GetGreen(), nTempFX ); 2069 cB1 = MAP( aCol0.GetBlue(), aCol1.GetBlue(), nTempFX ); 2070 2071 aColRes.SetRed( MAP( cR0, cR1, nTempFY ) ); 2072 aColRes.SetGreen( MAP( cG0, cG1, nTempFY ) ); 2073 aColRes.SetBlue( MAP( cB0, cB1, nTempFY ) ); 2074 pWAcc->SetPixel( nYDst, nXDst++, aColRes ); 2075 } 2076 } 2077 } 2078 else 2079 { 2080 long nSumR, nSumG, nSumB,nLineStart , nLineRange, nRowStart , nRowRange ; 2081 long nLeft, nRight, nTop, nBottom, nWeightX, nWeightY ; 2082 long nSumRowR ,nSumRowG,nSumRowB, nTotalWeightX, nTotalWeightY; 2083 2084 for( nY = nStartY , nYDst = 0L; nY <= nEndY; nY++, nYDst++ ) 2085 { 2086 nTop = bVMirr ? ( nY + 1 ) : nY; 2087 nBottom = bVMirr ? nY : ( nY + 1 ) ; 2088 2089 if( nY ==nEndY ) 2090 { 2091 nLineStart = pMapIY[ nY ]; 2092 nLineRange = 0; 2093 } 2094 else 2095 { 2096 nLineStart = pMapIY[ nTop ] ; 2097 nLineRange = ( pMapIY[ nBottom ] == pMapIY[ nTop ] ) ? 1 :( pMapIY[ nBottom ] - pMapIY[ nTop ] ); 2098 } 2099 2100 for( nX = nStartX , nXDst = 0L; nX <= nEndX; nX++ ) 2101 { 2102 nLeft = bHMirr ? ( nX + 1 ) : nX; 2103 nRight = bHMirr ? nX : ( nX + 1 ) ; 2104 2105 if( nX == nEndX ) 2106 { 2107 nRowStart = pMapIX[ nX ]; 2108 nRowRange = 0; 2109 } 2110 else 2111 { 2112 nRowStart = pMapIX[ nLeft ]; 2113 nRowRange = ( pMapIX[ nRight ] == pMapIX[ nLeft ] )? 1 : ( pMapIX[ nRight ] - pMapIX[ nLeft ] ); 2114 } 2115 2116 nSumR = nSumG = nSumB = 0; 2117 nTotalWeightY = 0; 2118 2119 for(int i = 0; i<= nLineRange; i++) 2120 { 2121 nSumRowR = nSumRowG = nSumRowB = 0; 2122 nTotalWeightX = 0; 2123 2124 for(int j = 0; j <= nRowRange; j++) 2125 { 2126 aCol0 = pAcc->GetPixel( nLineStart + i, nRowStart + j ); 2127 2128 if(nX == nEndX ) 2129 { 2130 2131 nSumRowB += aCol0.GetBlue() << 7L; 2132 nSumRowG += aCol0.GetGreen() << 7L; 2133 nSumRowR += aCol0.GetRed() << 7L; 2134 nTotalWeightX += 1 << 7L; 2135 } 2136 else if( j == 0 ) 2137 { 2138 2139 nWeightX = (nMax- pMapFX[ nLeft ]) ; 2140 nSumRowB += ( nWeightX *aCol0.GetBlue()) ; 2141 nSumRowG += ( nWeightX *aCol0.GetGreen()) ; 2142 nSumRowR += ( nWeightX *aCol0.GetRed()) ; 2143 nTotalWeightX += nWeightX; 2144 } 2145 else if ( nRowRange == j ) 2146 { 2147 2148 nWeightX = pMapFX[ nRight ] ; 2149 nSumRowB += ( nWeightX *aCol0.GetBlue() ); 2150 nSumRowG += ( nWeightX *aCol0.GetGreen() ); 2151 nSumRowR += ( nWeightX *aCol0.GetRed() ); 2152 nTotalWeightX += nWeightX; 2153 } 2154 else 2155 { 2156 nSumRowB += aCol0.GetBlue() << 7L; 2157 nSumRowG += aCol0.GetGreen() << 7L; 2158 nSumRowR += aCol0.GetRed() << 7L; 2159 nTotalWeightX += 1 << 7L; 2160 } 2161 } 2162 2163 if( nY == nEndY ) 2164 nWeightY = nMax; 2165 else if( i == 0 ) 2166 nWeightY = nMax - pMapFY[ nTop ]; 2167 else if( nLineRange == 1 ) 2168 nWeightY = pMapFY[ nTop ]; 2169 else if ( nLineRange == i ) 2170 nWeightY = pMapFY[ nBottom ]; 2171 else 2172 nWeightY = nMax; 2173 2174 nWeightY = nWeightY ; 2175 nSumB += nWeightY * ( nSumRowB / nTotalWeightX ); 2176 nSumG += nWeightY * ( nSumRowG / nTotalWeightX ); 2177 nSumR += nWeightY * ( nSumRowR / nTotalWeightX ); 2178 nTotalWeightY += nWeightY; 2179 } 2180 2181 aColRes.SetRed( ( sal_uInt8 ) (( nSumR / nTotalWeightY ) )); 2182 aColRes.SetGreen( ( sal_uInt8 ) (( nSumG / nTotalWeightY) )); 2183 aColRes.SetBlue( ( sal_uInt8 ) (( nSumB / nTotalWeightY ) )); 2184 pWAcc->SetPixel( nYDst, nXDst++, aColRes ); 2185 2186 } 2187 } 2188 } 2189 } 2190 } 2191 2192 bRet = true; 2193 } 2194 2195 delete[] pMapIX; 2196 delete[] pMapIY; 2197 delete[] pMapFX; 2198 delete[] pMapFY; 2199 2200 ReleaseAccess( pAcc ); 2201 aOutBmp.ReleaseAccess( pWAcc ); 2202 2203 if( bRet ) 2204 { 2205 ImplAdaptBitCount(aOutBmp); 2206 ImplAssignWithSize(aOutBmp); 2207 } 2208 2209 if( !bRet ) 2210 bRet = ImplScaleFast( scaleX, scaleY ); 2211 } 2212 2213 return bRet; 2214 } 2215 2216 //----------------------------------------------------------------------------------- 2217 2218 namespace 2219 { 2220 void ImplCalculateContributions( 2221 const sal_uInt32 aSourceSize, 2222 const sal_uInt32 aDestinationSize, 2223 sal_uInt32& aNumberOfContributions, 2224 double*& pWeights, 2225 sal_uInt32*& pPixels, 2226 sal_uInt32*& pCount, 2227 const Kernel& aKernel) 2228 { 2229 const double fSamplingRadius(aKernel.GetWidth()); 2230 const double fScale(aDestinationSize / static_cast< double >(aSourceSize)); 2231 const double fScaledRadius((fScale < 1.0) ? fSamplingRadius / fScale : fSamplingRadius); 2232 const double fFilterFactor((fScale < 1.0) ? fScale : 1.0); 2233 2234 aNumberOfContributions = (static_cast< sal_uInt32 >(fabs(ceil(fScaledRadius))) * 2) + 1; 2235 const sal_uInt32 nAllocSize(aDestinationSize * aNumberOfContributions); 2236 pWeights = new double[nAllocSize]; 2237 pPixels = new sal_uInt32[nAllocSize]; 2238 pCount = new sal_uInt32[aDestinationSize]; 2239 2240 for(sal_uInt32 i(0); i < aDestinationSize; i++) 2241 { 2242 const sal_uInt32 aIndex(i * aNumberOfContributions); 2243 const double aCenter(i / fScale); 2244 const sal_Int32 aLeft(static_cast< sal_Int32 >(floor(aCenter - fScaledRadius))); 2245 const sal_Int32 aRight(static_cast< sal_Int32 >(ceil(aCenter + fScaledRadius))); 2246 sal_uInt32 aCurrentCount(0); 2247 2248 for(sal_Int32 j(aLeft); j <= aRight; j++) 2249 { 2250 const double aWeight(aKernel.Calculate(fFilterFactor * (aCenter - static_cast< double>(j)))); 2251 2252 // Reduce calculations with ignoring weights of 0.0 2253 if(fabs(aWeight) < 0.0001) 2254 { 2255 continue; 2256 } 2257 2258 // Handling on edges 2259 const sal_uInt32 aPixelIndex(MinMax(j, 0, aSourceSize - 1)); 2260 const sal_uInt32 nIndex(aIndex + aCurrentCount); 2261 2262 pWeights[nIndex] = aWeight; 2263 pPixels[nIndex] = aPixelIndex; 2264 2265 aCurrentCount++; 2266 } 2267 2268 pCount[i] = aCurrentCount; 2269 } 2270 } 2271 2272 sal_Bool ImplScaleConvolutionHor( 2273 Bitmap& rSource, 2274 Bitmap& rTarget, 2275 const double& rScaleX, 2276 const Kernel& aKernel) 2277 { 2278 // Do horizontal filtering 2279 OSL_ENSURE(rScaleX > 0.0, "Error in scaling: Mirror given in non-mirror-capable method (!)"); 2280 const sal_uInt32 nWidth(rSource.GetSizePixel().Width()); 2281 const sal_uInt32 nNewWidth(FRound(nWidth * rScaleX)); 2282 2283 if(nWidth == nNewWidth) 2284 { 2285 return true; 2286 } 2287 2288 BitmapReadAccess* pReadAcc = rSource.AcquireReadAccess(); 2289 2290 if(pReadAcc) 2291 { 2292 double* pWeights = 0; 2293 sal_uInt32* pPixels = 0; 2294 sal_uInt32* pCount = 0; 2295 sal_uInt32 aNumberOfContributions(0); 2296 2297 const sal_uInt32 nHeight(rSource.GetSizePixel().Height()); 2298 ImplCalculateContributions(nWidth, nNewWidth, aNumberOfContributions, pWeights, pPixels, pCount, aKernel); 2299 rTarget = Bitmap(Size(nNewWidth, nHeight), 24); 2300 BitmapWriteAccess* pWriteAcc = rTarget.AcquireWriteAccess(); 2301 bool bResult(0 != pWriteAcc); 2302 2303 if(bResult) 2304 { 2305 for(sal_uInt32 y(0); y < nHeight; y++) 2306 { 2307 for(sal_uInt32 x(0); x < nNewWidth; x++) 2308 { 2309 const sal_uInt32 aBaseIndex(x * aNumberOfContributions); 2310 double aSum(0.0); 2311 double aValueRed(0.0); 2312 double aValueGreen(0.0); 2313 double aValueBlue(0.0); 2314 2315 for(sal_uInt32 j(0); j < pCount[x]; j++) 2316 { 2317 const sal_uInt32 aIndex(aBaseIndex + j); 2318 const double aWeight(pWeights[aIndex]); 2319 BitmapColor aColor; 2320 2321 aSum += aWeight; 2322 2323 if(pReadAcc->HasPalette()) 2324 { 2325 aColor = pReadAcc->GetPaletteColor(pReadAcc->GetPixelIndex(y, pPixels[aIndex])); 2326 } 2327 else 2328 { 2329 aColor = pReadAcc->GetPixel(y, pPixels[aIndex]); 2330 } 2331 2332 aValueRed += aWeight * aColor.GetRed(); 2333 aValueGreen += aWeight * aColor.GetGreen(); 2334 aValueBlue += aWeight * aColor.GetBlue(); 2335 } 2336 2337 const BitmapColor aResultColor( 2338 static_cast< sal_uInt8 >(MinMax(static_cast< sal_Int32 >(aValueRed / aSum), 0, 255)), 2339 static_cast< sal_uInt8 >(MinMax(static_cast< sal_Int32 >(aValueGreen / aSum), 0, 255)), 2340 static_cast< sal_uInt8 >(MinMax(static_cast< sal_Int32 >(aValueBlue / aSum), 0, 255))); 2341 2342 pWriteAcc->SetPixel(y, x, aResultColor); 2343 } 2344 } 2345 2346 rTarget.ReleaseAccess(pWriteAcc); 2347 } 2348 2349 rSource.ReleaseAccess(pReadAcc); 2350 delete[] pWeights; 2351 delete[] pCount; 2352 delete[] pPixels; 2353 2354 if(bResult) 2355 { 2356 return true; 2357 } 2358 } 2359 2360 return false; 2361 } 2362 2363 bool ImplScaleConvolutionVer( 2364 Bitmap& rSource, 2365 Bitmap& rTarget, 2366 const double& rScaleY, 2367 const Kernel& aKernel) 2368 { 2369 // Do vertical filtering 2370 OSL_ENSURE(rScaleY > 0.0, "Error in scaling: Mirror given in non-mirror-capable method (!)"); 2371 const sal_uInt32 nHeight(rSource.GetSizePixel().Height()); 2372 const sal_uInt32 nNewHeight(FRound(nHeight * rScaleY)); 2373 2374 if(nHeight == nNewHeight) 2375 { 2376 return true; 2377 } 2378 2379 BitmapReadAccess* pReadAcc = rSource.AcquireReadAccess(); 2380 2381 if(pReadAcc) 2382 { 2383 double* pWeights = 0; 2384 sal_uInt32* pPixels = 0; 2385 sal_uInt32* pCount = 0; 2386 sal_uInt32 aNumberOfContributions(0); 2387 2388 const sal_uInt32 nWidth(rSource.GetSizePixel().Width()); 2389 ImplCalculateContributions(nHeight, nNewHeight, aNumberOfContributions, pWeights, pPixels, pCount, aKernel); 2390 rTarget = Bitmap(Size(nWidth, nNewHeight), 24); 2391 BitmapWriteAccess* pWriteAcc = rTarget.AcquireWriteAccess(); 2392 bool bResult(0 != pWriteAcc); 2393 2394 if(pWriteAcc) 2395 { 2396 for(sal_uInt32 x(0); x < nWidth; x++) 2397 { 2398 for(sal_uInt32 y(0); y < nNewHeight; y++) 2399 { 2400 const sal_uInt32 aBaseIndex(y * aNumberOfContributions); 2401 double aSum(0.0); 2402 double aValueRed(0.0); 2403 double aValueGreen(0.0); 2404 double aValueBlue(0.0); 2405 2406 for(sal_uInt32 j(0); j < pCount[y]; j++) 2407 { 2408 const sal_uInt32 aIndex(aBaseIndex + j); 2409 const double aWeight(pWeights[aIndex]); 2410 BitmapColor aColor; 2411 2412 aSum += aWeight; 2413 2414 if(pReadAcc->HasPalette()) 2415 { 2416 aColor = pReadAcc->GetPaletteColor(pReadAcc->GetPixelIndex(pPixels[aIndex], x)); 2417 } 2418 else 2419 { 2420 aColor = pReadAcc->GetPixel(pPixels[aIndex], x); 2421 } 2422 2423 aValueRed += aWeight * aColor.GetRed(); 2424 aValueGreen += aWeight * aColor.GetGreen(); 2425 aValueBlue += aWeight * aColor.GetBlue(); 2426 } 2427 2428 const BitmapColor aResultColor( 2429 static_cast< sal_uInt8 >(MinMax(static_cast< sal_Int32 >(aValueRed / aSum), 0, 255)), 2430 static_cast< sal_uInt8 >(MinMax(static_cast< sal_Int32 >(aValueGreen / aSum), 0, 255)), 2431 static_cast< sal_uInt8 >(MinMax(static_cast< sal_Int32 >(aValueBlue / aSum), 0, 255))); 2432 2433 if(pWriteAcc->HasPalette()) 2434 { 2435 pWriteAcc->SetPixelIndex(y, x, static_cast< sal_uInt8 >(pWriteAcc->GetBestPaletteIndex(aResultColor))); 2436 } 2437 else 2438 { 2439 pWriteAcc->SetPixel(y, x, aResultColor); 2440 } 2441 } 2442 } 2443 } 2444 2445 rTarget.ReleaseAccess(pWriteAcc); 2446 rSource.ReleaseAccess(pReadAcc); 2447 2448 delete[] pWeights; 2449 delete[] pCount; 2450 delete[] pPixels; 2451 2452 if(bResult) 2453 { 2454 return true; 2455 } 2456 } 2457 2458 return false; 2459 } 2460 } 2461 2462 // #121233# Added BMP_SCALE_LANCZOS, BMP_SCALE_BICUBIC, BMP_SCALE_BILINEAR and 2463 // BMP_SCALE_BOX derived from the original commit from Toma� Vajngerl (see 2464 // bugzilla task for deitails) Thanks! 2465 sal_Bool Bitmap::ImplScaleConvolution( 2466 const double& rScaleX, 2467 const double& rScaleY, 2468 const Kernel& aKernel) 2469 { 2470 const bool bMirrorHor(rScaleX < 0.0); 2471 const bool bMirrorVer(rScaleY < 0.0); 2472 const double fScaleX(bMirrorHor ? -rScaleX : rScaleX); 2473 const double fScaleY(bMirrorVer ? -rScaleY : rScaleY); 2474 const sal_uInt32 nWidth(GetSizePixel().Width()); 2475 const sal_uInt32 nHeight(GetSizePixel().Height()); 2476 const sal_uInt32 nNewWidth(FRound(nWidth * fScaleX)); 2477 const sal_uInt32 nNewHeight(FRound(nHeight * fScaleY)); 2478 const bool bScaleHor(nWidth != nNewWidth); 2479 const bool bScaleVer(nHeight != nNewHeight); 2480 const bool bMirror(bMirrorHor || bMirrorVer); 2481 2482 if(!bMirror && !bScaleHor && !bScaleVer) 2483 { 2484 return true; 2485 } 2486 2487 bool bResult(true); 2488 sal_uInt32 nMirrorFlags(BMP_MIRROR_NONE); 2489 bool bMirrorAfter(false); 2490 2491 if(bMirror) 2492 { 2493 if(bMirrorHor) 2494 { 2495 nMirrorFlags |= BMP_MIRROR_HORZ; 2496 } 2497 2498 if(bMirrorVer) 2499 { 2500 nMirrorFlags |= BMP_MIRROR_VERT; 2501 } 2502 2503 const sal_uInt32 nStartSize(nWidth * nHeight); 2504 const sal_uInt32 nEndSize(nNewWidth * nNewHeight); 2505 2506 bMirrorAfter = nStartSize > nEndSize; 2507 2508 if(!bMirrorAfter) 2509 { 2510 bResult = Mirror(nMirrorFlags); 2511 } 2512 } 2513 2514 Bitmap aResult; 2515 2516 if(bResult) 2517 { 2518 const sal_uInt32 nInBetweenSizeHorFirst(nHeight * nNewWidth); 2519 const sal_uInt32 nInBetweenSizeVerFirst(nNewHeight * nWidth); 2520 2521 if(nInBetweenSizeHorFirst < nInBetweenSizeVerFirst) 2522 { 2523 if(bScaleHor) 2524 { 2525 bResult = ImplScaleConvolutionHor(*this, aResult, fScaleX, aKernel); 2526 } 2527 2528 if(bResult && bScaleVer) 2529 { 2530 bResult = ImplScaleConvolutionVer(*this, aResult, fScaleY, aKernel); 2531 } 2532 } 2533 else 2534 { 2535 if(bScaleVer) 2536 { 2537 bResult = ImplScaleConvolutionVer(*this, aResult, fScaleY, aKernel); 2538 } 2539 2540 if(bResult && bScaleHor) 2541 { 2542 bResult = ImplScaleConvolutionHor(*this, aResult, fScaleX, aKernel); 2543 } 2544 } 2545 } 2546 2547 if(bResult && bMirrorAfter) 2548 { 2549 bResult = aResult.Mirror(nMirrorFlags); 2550 } 2551 2552 if(bResult) 2553 { 2554 ImplAdaptBitCount(aResult); 2555 *this = aResult; 2556 } 2557 2558 return bResult; 2559 } 2560 2561 // ------------------------------------------------------------------------ 2562 2563 sal_Bool Bitmap::Dither( sal_uLong nDitherFlags ) 2564 { 2565 sal_Bool bRet = sal_False; 2566 2567 const Size aSizePix( GetSizePixel() ); 2568 2569 if( aSizePix.Width() == 1 || aSizePix.Height() == 1 ) 2570 bRet = sal_True; 2571 else if( nDitherFlags & BMP_DITHER_MATRIX ) 2572 bRet = ImplDitherMatrix(); 2573 else if( nDitherFlags & BMP_DITHER_FLOYD ) 2574 bRet = ImplDitherFloyd(); 2575 else if( ( nDitherFlags & BMP_DITHER_FLOYD_16 ) && ( GetBitCount() == 24 ) ) 2576 bRet = ImplDitherFloyd16(); 2577 2578 return bRet; 2579 } 2580 2581 // ------------------------------------------------------------------------ 2582 2583 sal_Bool Bitmap::ImplDitherMatrix() 2584 { 2585 BitmapReadAccess* pReadAcc = AcquireReadAccess(); 2586 Bitmap aNewBmp( GetSizePixel(), 8 ); 2587 BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess(); 2588 sal_Bool bRet = sal_False; 2589 2590 if( pReadAcc && pWriteAcc ) 2591 { 2592 const sal_uLong nWidth = pReadAcc->Width(); 2593 const sal_uLong nHeight = pReadAcc->Height(); 2594 BitmapColor aIndex( (sal_uInt8) 0 ); 2595 2596 if( pReadAcc->HasPalette() ) 2597 { 2598 for( sal_uLong nY = 0UL; nY < nHeight; nY++ ) 2599 { 2600 for( sal_uLong nX = 0UL, nModY = ( nY & 0x0FUL ) << 4UL; nX < nWidth; nX++ ) 2601 { 2602 const BitmapColor aCol( pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nY, nX ) ) ); 2603 const sal_uLong nD = nVCLDitherLut[ nModY + ( nX & 0x0FUL ) ]; 2604 const sal_uLong nR = ( nVCLLut[ aCol.GetRed() ] + nD ) >> 16UL; 2605 const sal_uLong nG = ( nVCLLut[ aCol.GetGreen() ] + nD ) >> 16UL; 2606 const sal_uLong nB = ( nVCLLut[ aCol.GetBlue() ] + nD ) >> 16UL; 2607 2608 aIndex.SetIndex( (sal_uInt8) ( nVCLRLut[ nR ] + nVCLGLut[ nG ] + nVCLBLut[ nB ] ) ); 2609 pWriteAcc->SetPixel( nY, nX, aIndex ); 2610 } 2611 } 2612 } 2613 else 2614 { 2615 for( sal_uLong nY = 0UL; nY < nHeight; nY++ ) 2616 { 2617 for( sal_uLong nX = 0UL, nModY = ( nY & 0x0FUL ) << 4UL; nX < nWidth; nX++ ) 2618 { 2619 const BitmapColor aCol( pReadAcc->GetPixel( nY, nX ) ); 2620 const sal_uLong nD = nVCLDitherLut[ nModY + ( nX & 0x0FUL ) ]; 2621 const sal_uLong nR = ( nVCLLut[ aCol.GetRed() ] + nD ) >> 16UL; 2622 const sal_uLong nG = ( nVCLLut[ aCol.GetGreen() ] + nD ) >> 16UL; 2623 const sal_uLong nB = ( nVCLLut[ aCol.GetBlue() ] + nD ) >> 16UL; 2624 2625 aIndex.SetIndex( (sal_uInt8) ( nVCLRLut[ nR ] + nVCLGLut[ nG ] + nVCLBLut[ nB ] ) ); 2626 pWriteAcc->SetPixel( nY, nX, aIndex ); 2627 } 2628 } 2629 } 2630 2631 bRet = sal_True; 2632 } 2633 2634 ReleaseAccess( pReadAcc ); 2635 aNewBmp.ReleaseAccess( pWriteAcc ); 2636 2637 if( bRet ) 2638 { 2639 const MapMode aMap( maPrefMapMode ); 2640 const Size aSize( maPrefSize ); 2641 2642 *this = aNewBmp; 2643 2644 maPrefMapMode = aMap; 2645 maPrefSize = aSize; 2646 } 2647 2648 return bRet; 2649 } 2650 2651 // ------------------------------------------------------------------------ 2652 2653 sal_Bool Bitmap::ImplDitherFloyd() 2654 { 2655 const Size aSize( GetSizePixel() ); 2656 sal_Bool bRet = sal_False; 2657 2658 if( ( aSize.Width() > 3 ) && ( aSize.Height() > 2 ) ) 2659 { 2660 BitmapReadAccess* pReadAcc = AcquireReadAccess(); 2661 Bitmap aNewBmp( GetSizePixel(), 8 ); 2662 BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess(); 2663 2664 if( pReadAcc && pWriteAcc ) 2665 { 2666 BitmapColor aColor; 2667 long nWidth = pReadAcc->Width(); 2668 long nWidth1 = nWidth - 1L; 2669 long nHeight = pReadAcc->Height(); 2670 long nX; 2671 long nW = nWidth * 3L; 2672 long nW2 = nW - 3L; 2673 long nRErr, nGErr, nBErr; 2674 long nRC, nGC, nBC; 2675 long nTemp; 2676 long nZ; 2677 long* p1 = new long[ nW ]; 2678 long* p2 = new long[ nW ]; 2679 long* p1T = p1; 2680 long* p2T = p2; 2681 long* pTmp; 2682 sal_Bool bPal = pReadAcc->HasPalette(); 2683 2684 pTmp = p2T; 2685 2686 if( bPal ) 2687 { 2688 for( nZ = 0; nZ < nWidth; nZ++ ) 2689 { 2690 aColor = pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( 0, nZ ) ); 2691 2692 *pTmp++ = (long) aColor.GetBlue() << 12; 2693 *pTmp++ = (long) aColor.GetGreen() << 12; 2694 *pTmp++ = (long) aColor.GetRed() << 12; 2695 } 2696 } 2697 else 2698 { 2699 for( nZ = 0; nZ < nWidth; nZ++ ) 2700 { 2701 aColor = pReadAcc->GetPixel( 0, nZ ); 2702 2703 *pTmp++ = (long) aColor.GetBlue() << 12; 2704 *pTmp++ = (long) aColor.GetGreen() << 12; 2705 *pTmp++ = (long) aColor.GetRed() << 12; 2706 } 2707 } 2708 2709 for( long nY = 1, nYAcc = 0L; nY <= nHeight; nY++, nYAcc++ ) 2710 { 2711 pTmp = p1T; 2712 p1T = p2T; 2713 p2T = pTmp; 2714 2715 if( nY < nHeight ) 2716 { 2717 if( bPal ) 2718 { 2719 for( nZ = 0; nZ < nWidth; nZ++ ) 2720 { 2721 aColor = pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nY, nZ ) ); 2722 2723 *pTmp++ = (long) aColor.GetBlue() << 12; 2724 *pTmp++ = (long) aColor.GetGreen() << 12; 2725 *pTmp++ = (long) aColor.GetRed() << 12; 2726 } 2727 } 2728 else 2729 { 2730 for( nZ = 0; nZ < nWidth; nZ++ ) 2731 { 2732 aColor = pReadAcc->GetPixel( nY, nZ ); 2733 2734 *pTmp++ = (long) aColor.GetBlue() << 12; 2735 *pTmp++ = (long) aColor.GetGreen() << 12; 2736 *pTmp++ = (long) aColor.GetRed() << 12; 2737 } 2738 } 2739 } 2740 2741 // erstes Pixel gesondert betrachten 2742 nX = 0; 2743 CALC_ERRORS; 2744 CALC_TABLES7; 2745 nX -= 5; 2746 CALC_TABLES5; 2747 pWriteAcc->SetPixelIndex( nYAcc, 0, static_cast<sal_uInt8>(nVCLBLut[ nBC ] + nVCLGLut[nGC ] + nVCLRLut[nRC ]) ); 2748 2749 // mittlere Pixel ueber Schleife 2750 long nXAcc; 2751 for ( nX = 3L, nXAcc = 1L; nX < nW2; nXAcc++ ) 2752 { 2753 CALC_ERRORS; 2754 CALC_TABLES7; 2755 nX -= 8; 2756 CALC_TABLES3; 2757 CALC_TABLES5; 2758 pWriteAcc->SetPixelIndex( nYAcc, nXAcc, static_cast<sal_uInt8>(nVCLBLut[ nBC ] + nVCLGLut[nGC ] + nVCLRLut[nRC ]) ); 2759 } 2760 2761 // letztes Pixel gesondert betrachten 2762 CALC_ERRORS; 2763 nX -= 5; 2764 CALC_TABLES3; 2765 CALC_TABLES5; 2766 pWriteAcc->SetPixelIndex( nYAcc, nWidth1, static_cast<sal_uInt8>(nVCLBLut[ nBC ] + nVCLGLut[nGC ] + nVCLRLut[nRC ]) ); 2767 } 2768 2769 delete[] p1; 2770 delete[] p2; 2771 bRet = sal_True; 2772 } 2773 2774 ReleaseAccess( pReadAcc ); 2775 aNewBmp.ReleaseAccess( pWriteAcc ); 2776 2777 if( bRet ) 2778 { 2779 const MapMode aMap( maPrefMapMode ); 2780 const Size aPrefSize( maPrefSize ); 2781 2782 *this = aNewBmp; 2783 2784 maPrefMapMode = aMap; 2785 maPrefSize = aPrefSize; 2786 } 2787 } 2788 2789 return bRet; 2790 } 2791 2792 // ------------------------------------------------------------------------ 2793 2794 sal_Bool Bitmap::ImplDitherFloyd16() 2795 { 2796 BitmapReadAccess* pReadAcc = AcquireReadAccess(); 2797 Bitmap aNewBmp( GetSizePixel(), 24 ); 2798 BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess(); 2799 sal_Bool bRet = sal_False; 2800 2801 if( pReadAcc && pWriteAcc ) 2802 { 2803 const long nWidth = pWriteAcc->Width(); 2804 const long nWidth1 = nWidth - 1L; 2805 const long nHeight = pWriteAcc->Height(); 2806 BitmapColor aColor; 2807 BitmapColor aBestCol; 2808 ImpErrorQuad aErrQuad; 2809 ImpErrorQuad* pErrQuad1 = new ImpErrorQuad[ nWidth ]; 2810 ImpErrorQuad* pErrQuad2 = new ImpErrorQuad[ nWidth ]; 2811 ImpErrorQuad* pQLine1 = pErrQuad1; 2812 ImpErrorQuad* pQLine2 = 0; 2813 long nX, nY; 2814 long nYTmp = 0L; 2815 sal_Bool bQ1 = sal_True; 2816 2817 for( nY = 0L; nY < Min( nHeight, 2L ); nY++, nYTmp++ ) 2818 for( nX = 0L, pQLine2 = !nY ? pErrQuad1 : pErrQuad2; nX < nWidth; nX++ ) 2819 pQLine2[ nX ] = pReadAcc->GetPixel( nYTmp, nX ); 2820 2821 for( nY = 0L; nY < nHeight; nY++, nYTmp++ ) 2822 { 2823 // erstes ZeilenPixel 2824 aBestCol = pQLine1[ 0 ].ImplGetColor(); 2825 aBestCol.SetRed( ( aBestCol.GetRed() & 248 ) | 7 ); 2826 aBestCol.SetGreen( ( aBestCol.GetGreen() & 248 ) | 7 ); 2827 aBestCol.SetBlue( ( aBestCol.GetBlue() & 248 ) | 7 ); 2828 pWriteAcc->SetPixel( nY, 0, aBestCol ); 2829 2830 for( nX = 1L; nX < nWidth1; nX++ ) 2831 { 2832 aColor = pQLine1[ nX ].ImplGetColor(); 2833 aBestCol.SetRed( ( aColor.GetRed() & 248 ) | 7 ); 2834 aBestCol.SetGreen( ( aColor.GetGreen() & 248 ) | 7 ); 2835 aBestCol.SetBlue( ( aColor.GetBlue() & 248 ) | 7 ); 2836 aErrQuad = ( ImpErrorQuad( aColor ) -= aBestCol ); 2837 pQLine1[ ++nX ].ImplAddColorError7( aErrQuad ); 2838 pQLine2[ nX-- ].ImplAddColorError1( aErrQuad ); 2839 pQLine2[ nX-- ].ImplAddColorError5( aErrQuad ); 2840 pQLine2[ nX++ ].ImplAddColorError3( aErrQuad ); 2841 pWriteAcc->SetPixel( nY, nX, aBestCol ); 2842 } 2843 2844 // letztes ZeilenPixel 2845 aBestCol = pQLine1[ nWidth1 ].ImplGetColor(); 2846 aBestCol.SetRed( ( aBestCol.GetRed() & 248 ) | 7 ); 2847 aBestCol.SetGreen( ( aBestCol.GetGreen() & 248 ) | 7 ); 2848 aBestCol.SetBlue( ( aBestCol.GetBlue() & 248 ) | 7 ); 2849 pWriteAcc->SetPixel( nY, nX, aBestCol ); 2850 2851 // Zeilenpuffer neu fuellen/kopieren 2852 pQLine1 = pQLine2; 2853 pQLine2 = ( bQ1 = !bQ1 ) != sal_False ? pErrQuad2 : pErrQuad1; 2854 2855 if( nYTmp < nHeight ) 2856 for( nX = 0L; nX < nWidth; nX++ ) 2857 pQLine2[ nX ] = pReadAcc->GetPixel( nYTmp, nX ); 2858 } 2859 2860 // Zeilenpuffer zerstoeren 2861 delete[] pErrQuad1; 2862 delete[] pErrQuad2; 2863 bRet = sal_True; 2864 } 2865 2866 ReleaseAccess( pReadAcc ); 2867 aNewBmp.ReleaseAccess( pWriteAcc ); 2868 2869 if( bRet ) 2870 { 2871 const MapMode aMap( maPrefMapMode ); 2872 const Size aSize( maPrefSize ); 2873 2874 *this = aNewBmp; 2875 2876 maPrefMapMode = aMap; 2877 maPrefSize = aSize; 2878 } 2879 2880 return bRet; 2881 } 2882 2883 // ------------------------------------------------------------------------ 2884 2885 sal_Bool Bitmap::ReduceColors( sal_uInt16 nColorCount, BmpReduce eReduce ) 2886 { 2887 sal_Bool bRet; 2888 2889 if( GetColorCount() <= (sal_uLong) nColorCount ) 2890 bRet = sal_True; 2891 else if( nColorCount ) 2892 { 2893 if( BMP_REDUCE_SIMPLE == eReduce ) 2894 bRet = ImplReduceSimple( nColorCount ); 2895 else if( BMP_REDUCE_POPULAR == eReduce ) 2896 bRet = ImplReducePopular( nColorCount ); 2897 else 2898 bRet = ImplReduceMedian( nColorCount ); 2899 } 2900 else 2901 bRet = sal_False; 2902 2903 return bRet; 2904 } 2905 2906 // ------------------------------------------------------------------------ 2907 2908 sal_Bool Bitmap::ImplReduceSimple( sal_uInt16 nColorCount ) 2909 { 2910 Bitmap aNewBmp; 2911 BitmapReadAccess* pRAcc = AcquireReadAccess(); 2912 const sal_uInt16 nColCount = Min( nColorCount, (sal_uInt16) 256 ); 2913 sal_uInt16 nBitCount; 2914 sal_Bool bRet = sal_False; 2915 2916 if( nColCount <= 2 ) 2917 nBitCount = 1; 2918 else if( nColCount <= 16 ) 2919 nBitCount = 4; 2920 else 2921 nBitCount = 8; 2922 2923 if( pRAcc ) 2924 { 2925 Octree aOct( *pRAcc, nColCount ); 2926 const BitmapPalette& rPal = aOct.GetPalette(); 2927 BitmapWriteAccess* pWAcc; 2928 2929 aNewBmp = Bitmap( GetSizePixel(), nBitCount, &rPal ); 2930 pWAcc = aNewBmp.AcquireWriteAccess(); 2931 2932 if( pWAcc ) 2933 { 2934 const long nWidth = pRAcc->Width(); 2935 const long nHeight = pRAcc->Height(); 2936 2937 if( pRAcc->HasPalette() ) 2938 { 2939 for( long nY = 0L; nY < nHeight; nY++ ) 2940 for( long nX =0L; nX < nWidth; nX++ ) 2941 pWAcc->SetPixelIndex( nY, nX, static_cast<sal_uInt8>(aOct.GetBestPaletteIndex( pRAcc->GetPaletteColor( pRAcc->GetPixelIndex( nY, nX ) ))) ); 2942 } 2943 else 2944 { 2945 for( long nY = 0L; nY < nHeight; nY++ ) 2946 for( long nX =0L; nX < nWidth; nX++ ) 2947 pWAcc->SetPixelIndex( nY, nX, static_cast<sal_uInt8>(aOct.GetBestPaletteIndex( pRAcc->GetPixel( nY, nX ) )) ); 2948 } 2949 2950 aNewBmp.ReleaseAccess( pWAcc ); 2951 bRet = sal_True; 2952 } 2953 2954 ReleaseAccess( pRAcc ); 2955 } 2956 2957 if( bRet ) 2958 { 2959 const MapMode aMap( maPrefMapMode ); 2960 const Size aSize( maPrefSize ); 2961 2962 *this = aNewBmp; 2963 maPrefMapMode = aMap; 2964 maPrefSize = aSize; 2965 } 2966 2967 return bRet; 2968 } 2969 2970 // ------------------------------------------------------------------------ 2971 2972 struct PopularColorCount 2973 { 2974 sal_uInt32 mnIndex; 2975 sal_uInt32 mnCount; 2976 }; 2977 2978 // ------------------------------------------------------------------------ 2979 2980 extern "C" int __LOADONCALLAPI ImplPopularCmpFnc( const void* p1, const void* p2 ) 2981 { 2982 int nRet; 2983 2984 if( ( (PopularColorCount*) p1 )->mnCount < ( (PopularColorCount*) p2 )->mnCount ) 2985 nRet = 1; 2986 else if( ( (PopularColorCount*) p1 )->mnCount == ( (PopularColorCount*) p2 )->mnCount ) 2987 nRet = 0; 2988 else 2989 nRet = -1; 2990 2991 return nRet; 2992 } 2993 2994 // ------------------------------------------------------------------------ 2995 2996 sal_Bool Bitmap::ImplReducePopular( sal_uInt16 nColCount ) 2997 { 2998 BitmapReadAccess* pRAcc = AcquireReadAccess(); 2999 sal_uInt16 nBitCount; 3000 sal_Bool bRet = sal_False; 3001 3002 if( nColCount > 256 ) 3003 nColCount = 256; 3004 3005 if( nColCount < 17 ) 3006 nBitCount = 4; 3007 else 3008 nBitCount = 8; 3009 3010 if( pRAcc ) 3011 { 3012 const sal_uInt32 nValidBits = 4; 3013 const sal_uInt32 nRightShiftBits = 8 - nValidBits; 3014 const sal_uInt32 nLeftShiftBits1 = nValidBits; 3015 const sal_uInt32 nLeftShiftBits2 = nValidBits << 1; 3016 const sal_uInt32 nColorsPerComponent = 1 << nValidBits; 3017 const sal_uInt32 nColorOffset = 256 / nColorsPerComponent; 3018 const sal_uInt32 nTotalColors = nColorsPerComponent * nColorsPerComponent * nColorsPerComponent; 3019 const long nWidth = pRAcc->Width(); 3020 const long nHeight = pRAcc->Height(); 3021 PopularColorCount* pCountTable = new PopularColorCount[ nTotalColors ]; 3022 long nX, nY, nR, nG, nB, nIndex; 3023 3024 rtl_zeroMemory( pCountTable, nTotalColors * sizeof( PopularColorCount ) ); 3025 3026 for( nR = 0, nIndex = 0; nR < 256; nR += nColorOffset ) 3027 { 3028 for( nG = 0; nG < 256; nG += nColorOffset ) 3029 { 3030 for( nB = 0; nB < 256; nB += nColorOffset ) 3031 { 3032 pCountTable[ nIndex ].mnIndex = nIndex; 3033 nIndex++; 3034 } 3035 } 3036 } 3037 3038 if( pRAcc->HasPalette() ) 3039 { 3040 for( nY = 0L; nY < nHeight; nY++ ) 3041 { 3042 for( nX = 0L; nX < nWidth; nX++ ) 3043 { 3044 const BitmapColor& rCol = pRAcc->GetPaletteColor( pRAcc->GetPixelIndex( nY, nX ) ); 3045 pCountTable[ ( ( ( (sal_uInt32) rCol.GetRed() ) >> nRightShiftBits ) << nLeftShiftBits2 ) | 3046 ( ( ( (sal_uInt32) rCol.GetGreen() ) >> nRightShiftBits ) << nLeftShiftBits1 ) | 3047 ( ( (sal_uInt32) rCol.GetBlue() ) >> nRightShiftBits ) ].mnCount++; 3048 } 3049 } 3050 } 3051 else 3052 { 3053 for( nY = 0L; nY < nHeight; nY++ ) 3054 { 3055 for( nX = 0L; nX < nWidth; nX++ ) 3056 { 3057 const BitmapColor aCol( pRAcc->GetPixel( nY, nX ) ); 3058 pCountTable[ ( ( ( (sal_uInt32) aCol.GetRed() ) >> nRightShiftBits ) << nLeftShiftBits2 ) | 3059 ( ( ( (sal_uInt32) aCol.GetGreen() ) >> nRightShiftBits ) << nLeftShiftBits1 ) | 3060 ( ( (sal_uInt32) aCol.GetBlue() ) >> nRightShiftBits ) ].mnCount++; 3061 } 3062 } 3063 } 3064 3065 BitmapPalette aNewPal( nColCount ); 3066 3067 qsort( pCountTable, nTotalColors, sizeof( PopularColorCount ), ImplPopularCmpFnc ); 3068 3069 for( sal_uInt16 n = 0; n < nColCount; n++ ) 3070 { 3071 const PopularColorCount& rPop = pCountTable[ n ]; 3072 aNewPal[ n ] = BitmapColor( (sal_uInt8) ( ( rPop.mnIndex >> nLeftShiftBits2 ) << nRightShiftBits ), 3073 (sal_uInt8) ( ( ( rPop.mnIndex >> nLeftShiftBits1 ) & ( nColorsPerComponent - 1 ) ) << nRightShiftBits ), 3074 (sal_uInt8) ( ( rPop.mnIndex & ( nColorsPerComponent - 1 ) ) << nRightShiftBits ) ); 3075 } 3076 3077 Bitmap aNewBmp( GetSizePixel(), nBitCount, &aNewPal ); 3078 BitmapWriteAccess* pWAcc = aNewBmp.AcquireWriteAccess(); 3079 3080 if( pWAcc ) 3081 { 3082 BitmapColor aDstCol( (sal_uInt8) 0 ); 3083 sal_uInt8* pIndexMap = new sal_uInt8[ nTotalColors ]; 3084 3085 for( nR = 0, nIndex = 0; nR < 256; nR += nColorOffset ) 3086 for( nG = 0; nG < 256; nG += nColorOffset ) 3087 for( nB = 0; nB < 256; nB += nColorOffset ) 3088 pIndexMap[ nIndex++ ] = (sal_uInt8) aNewPal.GetBestIndex( BitmapColor( (sal_uInt8) nR, (sal_uInt8) nG, (sal_uInt8) nB ) ); 3089 3090 if( pRAcc->HasPalette() ) 3091 { 3092 for( nY = 0L; nY < nHeight; nY++ ) 3093 { 3094 for( nX = 0L; nX < nWidth; nX++ ) 3095 { 3096 const BitmapColor& rCol = pRAcc->GetPaletteColor( pRAcc->GetPixelIndex( nY, nX ) ); 3097 aDstCol.SetIndex( pIndexMap[ ( ( ( (sal_uInt32) rCol.GetRed() ) >> nRightShiftBits ) << nLeftShiftBits2 ) | 3098 ( ( ( (sal_uInt32) rCol.GetGreen() ) >> nRightShiftBits ) << nLeftShiftBits1 ) | 3099 ( ( (sal_uInt32) rCol.GetBlue() ) >> nRightShiftBits ) ] ); 3100 pWAcc->SetPixel( nY, nX, aDstCol ); 3101 } 3102 } 3103 } 3104 else 3105 { 3106 for( nY = 0L; nY < nHeight; nY++ ) 3107 { 3108 for( nX = 0L; nX < nWidth; nX++ ) 3109 { 3110 const BitmapColor aCol( pRAcc->GetPixel( nY, nX ) ); 3111 aDstCol.SetIndex( pIndexMap[ ( ( ( (sal_uInt32) aCol.GetRed() ) >> nRightShiftBits ) << nLeftShiftBits2 ) | 3112 ( ( ( (sal_uInt32) aCol.GetGreen() ) >> nRightShiftBits ) << nLeftShiftBits1 ) | 3113 ( ( (sal_uInt32) aCol.GetBlue() ) >> nRightShiftBits ) ] ); 3114 pWAcc->SetPixel( nY, nX, aDstCol ); 3115 } 3116 } 3117 } 3118 3119 delete[] pIndexMap; 3120 aNewBmp.ReleaseAccess( pWAcc ); 3121 bRet = sal_True; 3122 } 3123 3124 delete[] pCountTable; 3125 ReleaseAccess( pRAcc ); 3126 3127 if( bRet ) 3128 { 3129 const MapMode aMap( maPrefMapMode ); 3130 const Size aSize( maPrefSize ); 3131 3132 *this = aNewBmp; 3133 maPrefMapMode = aMap; 3134 maPrefSize = aSize; 3135 } 3136 } 3137 3138 return bRet; 3139 } 3140 3141 // ------------------------------------------------------------------------ 3142 3143 sal_Bool Bitmap::ImplReduceMedian( sal_uInt16 nColCount ) 3144 { 3145 BitmapReadAccess* pRAcc = AcquireReadAccess(); 3146 sal_uInt16 nBitCount; 3147 sal_Bool bRet = sal_False; 3148 3149 if( nColCount < 17 ) 3150 nBitCount = 4; 3151 else if( nColCount < 257 ) 3152 nBitCount = 8; 3153 else 3154 { 3155 DBG_ERROR( "Bitmap::ImplReduceMedian(): invalid color count!" ); 3156 nBitCount = 8; 3157 nColCount = 256; 3158 } 3159 3160 if( pRAcc ) 3161 { 3162 Bitmap aNewBmp( GetSizePixel(), nBitCount ); 3163 BitmapWriteAccess* pWAcc = aNewBmp.AcquireWriteAccess(); 3164 3165 if( pWAcc ) 3166 { 3167 const sal_uLong nSize = 32768UL * sizeof( sal_uLong ); 3168 sal_uLong* pColBuf = (sal_uLong*) rtl_allocateMemory( nSize ); 3169 const long nWidth = pWAcc->Width(); 3170 const long nHeight = pWAcc->Height(); 3171 long nIndex = 0L; 3172 3173 memset( (HPBYTE) pColBuf, 0, nSize ); 3174 3175 // create Buffer 3176 if( pRAcc->HasPalette() ) 3177 { 3178 for( long nY = 0L; nY < nHeight; nY++ ) 3179 { 3180 for( long nX = 0L; nX < nWidth; nX++ ) 3181 { 3182 const BitmapColor& rCol = pRAcc->GetPaletteColor( pRAcc->GetPixelIndex( nY, nX ) ); 3183 pColBuf[ RGB15( rCol.GetRed() >> 3, rCol.GetGreen() >> 3, rCol.GetBlue() >> 3 ) ]++; 3184 } 3185 } 3186 } 3187 else 3188 { 3189 for( long nY = 0L; nY < nHeight; nY++ ) 3190 { 3191 for( long nX = 0L; nX < nWidth; nX++ ) 3192 { 3193 const BitmapColor aCol( pRAcc->GetPixel( nY, nX ) ); 3194 pColBuf[ RGB15( aCol.GetRed() >> 3, aCol.GetGreen() >> 3, aCol.GetBlue() >> 3 ) ]++; 3195 } 3196 } 3197 } 3198 3199 // create palette via median cut 3200 BitmapPalette aPal( pWAcc->GetPaletteEntryCount() ); 3201 ImplMedianCut( pColBuf, aPal, 0, 31, 0, 31, 0, 31, 3202 nColCount, nWidth * nHeight, nIndex ); 3203 3204 // do mapping of colors to palette 3205 InverseColorMap aMap( aPal ); 3206 pWAcc->SetPalette( aPal ); 3207 for( long nY = 0L; nY < nHeight; nY++ ) 3208 for( long nX = 0L; nX < nWidth; nX++ ) 3209 pWAcc->SetPixelIndex( nY, nX, static_cast<sal_uInt8>( aMap.GetBestPaletteIndex( pRAcc->GetColor( nY, nX ) )) ); 3210 3211 rtl_freeMemory( pColBuf ); 3212 aNewBmp.ReleaseAccess( pWAcc ); 3213 bRet = sal_True; 3214 } 3215 3216 ReleaseAccess( pRAcc ); 3217 3218 if( bRet ) 3219 { 3220 const MapMode aMap( maPrefMapMode ); 3221 const Size aSize( maPrefSize ); 3222 3223 *this = aNewBmp; 3224 maPrefMapMode = aMap; 3225 maPrefSize = aSize; 3226 } 3227 } 3228 3229 return bRet; 3230 } 3231 3232 // ------------------------------------------------------------------------ 3233 3234 void Bitmap::ImplMedianCut( sal_uLong* pColBuf, BitmapPalette& rPal, 3235 long nR1, long nR2, long nG1, long nG2, long nB1, long nB2, 3236 long nColors, long nPixels, long& rIndex ) 3237 { 3238 if( !nPixels ) 3239 return; 3240 3241 BitmapColor aCol; 3242 const long nRLen = nR2 - nR1; 3243 const long nGLen = nG2 - nG1; 3244 const long nBLen = nB2 - nB1; 3245 long nR, nG, nB; 3246 sal_uLong* pBuf = pColBuf; 3247 3248 if( !nRLen && !nGLen && !nBLen ) 3249 { 3250 if( pBuf[ RGB15( nR1, nG1, nB1 ) ] ) 3251 { 3252 aCol.SetRed( (sal_uInt8) ( nR1 << 3 ) ); 3253 aCol.SetGreen( (sal_uInt8) ( nG1 << 3 ) ); 3254 aCol.SetBlue( (sal_uInt8) ( nB1 << 3 ) ); 3255 rPal[ (sal_uInt16) rIndex++ ] = aCol; 3256 } 3257 } 3258 else 3259 { 3260 if( 1 == nColors || 1 == nPixels ) 3261 { 3262 long nPixSum = 0, nRSum = 0, nGSum = 0, nBSum = 0; 3263 3264 for( nR = nR1; nR <= nR2; nR++ ) 3265 { 3266 for( nG = nG1; nG <= nG2; nG++ ) 3267 { 3268 for( nB = nB1; nB <= nB2; nB++ ) 3269 { 3270 nPixSum = pBuf[ RGB15( nR, nG, nB ) ]; 3271 3272 if( nPixSum ) 3273 { 3274 nRSum += nR * nPixSum; 3275 nGSum += nG * nPixSum; 3276 nBSum += nB * nPixSum; 3277 } 3278 } 3279 } 3280 } 3281 3282 aCol.SetRed( (sal_uInt8) ( ( nRSum / nPixels ) << 3 ) ); 3283 aCol.SetGreen( (sal_uInt8) ( ( nGSum / nPixels ) << 3 ) ); 3284 aCol.SetBlue( (sal_uInt8) ( ( nBSum / nPixels ) << 3 ) ); 3285 rPal[ (sal_uInt16) rIndex++ ] = aCol; 3286 } 3287 else 3288 { 3289 const long nTest = ( nPixels >> 1 ); 3290 long nPixOld = 0; 3291 long nPixNew = 0; 3292 3293 if( nBLen > nGLen && nBLen > nRLen ) 3294 { 3295 nB = nB1 - 1; 3296 3297 while( nPixNew < nTest ) 3298 { 3299 nB++, nPixOld = nPixNew; 3300 for( nR = nR1; nR <= nR2; nR++ ) 3301 for( nG = nG1; nG <= nG2; nG++ ) 3302 nPixNew += pBuf[ RGB15( nR, nG, nB ) ]; 3303 } 3304 3305 if( nB < nB2 ) 3306 { 3307 ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG2, nB1, nB, nColors >> 1, nPixNew, rIndex ); 3308 ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG2, nB + 1, nB2, nColors >> 1, nPixels - nPixNew, rIndex ); 3309 } 3310 else 3311 { 3312 ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG2, nB1, nB - 1, nColors >> 1, nPixOld, rIndex ); 3313 ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG2, nB, nB2, nColors >> 1, nPixels - nPixOld, rIndex ); 3314 } 3315 } 3316 else if( nGLen > nRLen ) 3317 { 3318 nG = nG1 - 1; 3319 3320 while( nPixNew < nTest ) 3321 { 3322 nG++, nPixOld = nPixNew; 3323 for( nR = nR1; nR <= nR2; nR++ ) 3324 for( nB = nB1; nB <= nB2; nB++ ) 3325 nPixNew += pBuf[ RGB15( nR, nG, nB ) ]; 3326 } 3327 3328 if( nG < nG2 ) 3329 { 3330 ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG, nB1, nB2, nColors >> 1, nPixNew, rIndex ); 3331 ImplMedianCut( pBuf, rPal, nR1, nR2, nG + 1, nG2, nB1, nB2, nColors >> 1, nPixels - nPixNew, rIndex ); 3332 } 3333 else 3334 { 3335 ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG - 1, nB1, nB2, nColors >> 1, nPixOld, rIndex ); 3336 ImplMedianCut( pBuf, rPal, nR1, nR2, nG, nG2, nB1, nB2, nColors >> 1, nPixels - nPixOld, rIndex ); 3337 } 3338 } 3339 else 3340 { 3341 nR = nR1 - 1; 3342 3343 while( nPixNew < nTest ) 3344 { 3345 nR++, nPixOld = nPixNew; 3346 for( nG = nG1; nG <= nG2; nG++ ) 3347 for( nB = nB1; nB <= nB2; nB++ ) 3348 nPixNew += pBuf[ RGB15( nR, nG, nB ) ]; 3349 } 3350 3351 if( nR < nR2 ) 3352 { 3353 ImplMedianCut( pBuf, rPal, nR1, nR, nG1, nG2, nB1, nB2, nColors >> 1, nPixNew, rIndex ); 3354 ImplMedianCut( pBuf, rPal, nR1 + 1, nR2, nG1, nG2, nB1, nB2, nColors >> 1, nPixels - nPixNew, rIndex ); 3355 } 3356 else 3357 { 3358 ImplMedianCut( pBuf, rPal, nR1, nR - 1, nG1, nG2, nB1, nB2, nColors >> 1, nPixOld, rIndex ); 3359 ImplMedianCut( pBuf, rPal, nR, nR2, nG1, nG2, nB1, nB2, nColors >> 1, nPixels - nPixOld, rIndex ); 3360 } 3361 } 3362 } 3363 } 3364 } 3365 3366 // ------------------------------------------------------------------------ 3367 3368 sal_Bool Bitmap::Vectorize( PolyPolygon& rPolyPoly, sal_uLong nFlags, const Link* pProgress ) 3369 { 3370 return ImplVectorizer().ImplVectorize( *this, rPolyPoly, nFlags, pProgress ); 3371 } 3372 3373 // ------------------------------------------------------------------------ 3374 3375 sal_Bool Bitmap::Vectorize( GDIMetaFile& rMtf, sal_uInt8 cReduce, sal_uLong nFlags, const Link* pProgress ) 3376 { 3377 return ImplVectorizer().ImplVectorize( *this, rMtf, cReduce, nFlags, pProgress ); 3378 } 3379 3380 // ------------------------------------------------------------------------ 3381 3382 sal_Bool Bitmap::Adjust( short nLuminancePercent, short nContrastPercent, 3383 short nChannelRPercent, short nChannelGPercent, short nChannelBPercent, 3384 double fGamma, sal_Bool bInvert ) 3385 { 3386 sal_Bool bRet = sal_False; 3387 3388 // nothing to do => return quickly 3389 if( !nLuminancePercent && !nContrastPercent && 3390 !nChannelRPercent && !nChannelGPercent && !nChannelBPercent && 3391 ( fGamma == 1.0 ) && !bInvert ) 3392 { 3393 bRet = sal_True; 3394 } 3395 else 3396 { 3397 BitmapWriteAccess* pAcc = AcquireWriteAccess(); 3398 3399 if( pAcc ) 3400 { 3401 BitmapColor aCol; 3402 const long nW = pAcc->Width(); 3403 const long nH = pAcc->Height(); 3404 sal_uInt8* cMapR = new sal_uInt8[ 256 ]; 3405 sal_uInt8* cMapG = new sal_uInt8[ 256 ]; 3406 sal_uInt8* cMapB = new sal_uInt8[ 256 ]; 3407 long nX, nY; 3408 double fM, fROff, fGOff, fBOff, fOff; 3409 3410 // calculate slope 3411 if( nContrastPercent >= 0 ) 3412 fM = 128.0 / ( 128.0 - 1.27 * MinMax( nContrastPercent, 0L, 100L ) ); 3413 else 3414 fM = ( 128.0 + 1.27 * MinMax( nContrastPercent, -100L, 0L ) ) / 128.0; 3415 3416 // total offset = luminance offset + contrast offset 3417 fOff = MinMax( nLuminancePercent, -100L, 100L ) * 2.55 + 128.0 - fM * 128.0; 3418 3419 // channel offset = channel offset + total offset 3420 fROff = nChannelRPercent * 2.55 + fOff; 3421 fGOff = nChannelGPercent * 2.55 + fOff; 3422 fBOff = nChannelBPercent * 2.55 + fOff; 3423 3424 // calculate gamma value 3425 fGamma = ( fGamma <= 0.0 || fGamma > 10.0 ) ? 1.0 : ( 1.0 / fGamma ); 3426 const sal_Bool bGamma = ( fGamma != 1.0 ); 3427 3428 // create mapping table 3429 for( nX = 0L; nX < 256L; nX++ ) 3430 { 3431 cMapR[ nX ] = (sal_uInt8) MinMax( FRound( nX * fM + fROff ), 0L, 255L ); 3432 cMapG[ nX ] = (sal_uInt8) MinMax( FRound( nX * fM + fGOff ), 0L, 255L ); 3433 cMapB[ nX ] = (sal_uInt8) MinMax( FRound( nX * fM + fBOff ), 0L, 255L ); 3434 3435 if( bGamma ) 3436 { 3437 cMapR[ nX ] = GAMMA( cMapR[ nX ], fGamma ); 3438 cMapG[ nX ] = GAMMA( cMapG[ nX ], fGamma ); 3439 cMapB[ nX ] = GAMMA( cMapB[ nX ], fGamma ); 3440 } 3441 3442 if( bInvert ) 3443 { 3444 cMapR[ nX ] = ~cMapR[ nX ]; 3445 cMapG[ nX ] = ~cMapG[ nX ]; 3446 cMapB[ nX ] = ~cMapB[ nX ]; 3447 } 3448 } 3449 3450 // do modifying 3451 if( pAcc->HasPalette() ) 3452 { 3453 BitmapColor aNewCol; 3454 3455 for( sal_uInt16 i = 0, nCount = pAcc->GetPaletteEntryCount(); i < nCount; i++ ) 3456 { 3457 const BitmapColor& rCol = pAcc->GetPaletteColor( i ); 3458 aNewCol.SetRed( cMapR[ rCol.GetRed() ] ); 3459 aNewCol.SetGreen( cMapG[ rCol.GetGreen() ] ); 3460 aNewCol.SetBlue( cMapB[ rCol.GetBlue() ] ); 3461 pAcc->SetPaletteColor( i, aNewCol ); 3462 } 3463 } 3464 else if( pAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_BGR ) 3465 { 3466 for( nY = 0L; nY < nH; nY++ ) 3467 { 3468 Scanline pScan = pAcc->GetScanline( nY ); 3469 3470 for( nX = 0L; nX < nW; nX++ ) 3471 { 3472 *pScan = cMapB[ *pScan ]; pScan++; 3473 *pScan = cMapG[ *pScan ]; pScan++; 3474 *pScan = cMapR[ *pScan ]; pScan++; 3475 } 3476 } 3477 } 3478 else if( pAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_RGB ) 3479 { 3480 for( nY = 0L; nY < nH; nY++ ) 3481 { 3482 Scanline pScan = pAcc->GetScanline( nY ); 3483 3484 for( nX = 0L; nX < nW; nX++ ) 3485 { 3486 *pScan = cMapR[ *pScan ]; pScan++; 3487 *pScan = cMapG[ *pScan ]; pScan++; 3488 *pScan = cMapB[ *pScan ]; pScan++; 3489 } 3490 } 3491 } 3492 else 3493 { 3494 for( nY = 0L; nY < nH; nY++ ) 3495 { 3496 for( nX = 0L; nX < nW; nX++ ) 3497 { 3498 aCol = pAcc->GetPixel( nY, nX ); 3499 aCol.SetRed( cMapR[ aCol.GetRed() ] ); 3500 aCol.SetGreen( cMapG[ aCol.GetGreen() ] ); 3501 aCol.SetBlue( cMapB[ aCol.GetBlue() ] ); 3502 pAcc->SetPixel( nY, nX, aCol ); 3503 } 3504 } 3505 } 3506 3507 delete[] cMapR; 3508 delete[] cMapG; 3509 delete[] cMapB; 3510 ReleaseAccess( pAcc ); 3511 bRet = sal_True; 3512 } 3513 } 3514 3515 return bRet; 3516 } 3517