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