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 44 #define CALC_ERRORS \ 45 nTemp = p1T[nX++] >> 12; \ 46 nBErr = MinMax( nTemp, 0, 255 ); \ 47 nBErr = nBErr - FloydIndexMap[ nBC = FloydMap[nBErr] ]; \ 48 nTemp = p1T[nX++] >> 12; \ 49 nGErr = MinMax( nTemp, 0, 255 ); \ 50 nGErr = nGErr - FloydIndexMap[ nGC = FloydMap[nGErr] ]; \ 51 nTemp = p1T[nX] >> 12; \ 52 nRErr = MinMax( nTemp, 0, 255 ); \ 53 nRErr = nRErr - FloydIndexMap[ nRC = FloydMap[nRErr] ]; 54 55 #define CALC_TABLES3 \ 56 p2T[nX++] += FloydError3[nBErr]; \ 57 p2T[nX++] += FloydError3[nGErr]; \ 58 p2T[nX++] += FloydError3[nRErr]; 59 60 #define CALC_TABLES5 \ 61 p2T[nX++] += FloydError5[nBErr]; \ 62 p2T[nX++] += FloydError5[nGErr]; \ 63 p2T[nX++] += FloydError5[nRErr]; 64 65 #define CALC_TABLES7 \ 66 p1T[++nX] += FloydError7[nBErr]; \ 67 p2T[nX++] += FloydError1[nBErr]; \ 68 p1T[nX] += FloydError7[nGErr]; \ 69 p2T[nX++] += FloydError1[nGErr]; \ 70 p1T[nX] += FloydError7[nRErr]; \ 71 p2T[nX] += FloydError1[nRErr]; 72 73 // ----------- 74 // - Statics - 75 // ----------- 76 77 sal_uLong nVCLRLut[ 6 ] = { 16, 17, 18, 19, 20, 21 }; 78 sal_uLong nVCLGLut[ 6 ] = { 0, 6, 12, 18, 24, 30 }; 79 sal_uLong nVCLBLut[ 6 ] = { 0, 36, 72, 108, 144, 180 }; 80 81 // ------------------------------------------------------------------------ 82 83 sal_uLong nVCLDitherLut[ 256 ] = 84 { 85 0, 49152, 12288, 61440, 3072, 52224, 15360, 64512, 768, 49920, 13056, 86 62208, 3840, 52992, 16128, 65280, 32768, 16384, 45056, 28672, 35840, 19456, 87 48128, 31744, 33536, 17152, 45824, 29440, 36608, 20224, 48896, 32512, 8192, 88 57344, 4096, 53248, 11264, 60416, 7168, 56320, 8960, 58112, 4864, 54016, 89 12032, 61184, 7936, 57088, 40960, 24576, 36864, 20480, 44032, 27648, 39936, 90 23552, 41728, 25344, 37632, 21248, 44800, 28416, 40704, 24320, 2048, 51200, 91 14336, 63488, 1024, 50176, 13312, 62464, 2816, 51968, 15104, 64256, 1792, 92 50944, 14080, 63232, 34816, 18432, 47104, 30720, 33792, 17408, 46080, 29696, 93 35584, 19200, 47872, 31488, 34560, 18176, 46848, 30464, 10240, 59392, 6144, 94 55296, 9216, 58368, 5120, 54272, 11008, 60160, 6912, 56064, 9984, 59136, 95 5888, 55040, 43008, 26624, 38912, 22528, 41984, 25600, 37888, 21504, 43776, 96 27392, 39680, 23296, 42752, 26368, 38656, 22272, 512, 49664, 12800, 61952, 97 3584, 52736, 15872, 65024, 256, 49408, 12544, 61696, 3328, 52480, 15616, 98 64768, 33280, 16896, 45568, 29184, 36352, 19968, 48640, 32256, 33024, 16640, 99 45312, 28928, 36096, 19712, 48384, 32000, 8704, 57856, 4608, 53760, 11776, 100 60928, 7680, 56832, 8448, 57600, 4352, 53504, 11520, 60672, 7424, 56576, 101 41472, 25088, 37376, 20992, 44544, 28160, 40448, 24064, 41216, 24832, 37120, 102 20736, 44288, 27904, 40192, 23808, 2560, 51712, 14848, 64000, 1536, 50688, 103 13824, 62976, 2304, 51456, 14592, 63744, 1280, 50432, 13568, 62720, 35328, 104 18944, 47616, 31232, 34304, 17920, 46592, 30208, 35072, 18688, 47360, 30976, 105 34048, 17664, 46336, 29952, 10752, 59904, 6656, 55808, 9728, 58880, 5632, 106 54784, 10496, 59648, 6400, 55552, 9472, 58624, 5376, 54528, 43520, 27136, 107 39424, 23040, 42496, 26112, 38400, 22016, 43264, 26880, 39168, 22784, 42240, 108 25856, 38144, 21760 109 }; 110 111 // ------------------------------------------------------------------------ 112 113 sal_uLong nVCLLut[ 256 ] = 114 { 115 0, 1286, 2572, 3858, 5144, 6430, 7716, 9002, 116 10288, 11574, 12860, 14146, 15432, 16718, 18004, 19290, 117 20576, 21862, 23148, 24434, 25720, 27006, 28292, 29578, 118 30864, 32150, 33436, 34722, 36008, 37294, 38580, 39866, 119 41152, 42438, 43724, 45010, 46296, 47582, 48868, 50154, 120 51440, 52726, 54012, 55298, 56584, 57870, 59156, 60442, 121 61728, 63014, 64300, 65586, 66872, 68158, 69444, 70730, 122 72016, 73302, 74588, 75874, 77160, 78446, 79732, 81018, 123 82304, 83590, 84876, 86162, 87448, 88734, 90020, 91306, 124 92592, 93878, 95164, 96450, 97736, 99022,100308,101594, 125 102880,104166,105452,106738,108024,109310,110596,111882, 126 113168,114454,115740,117026,118312,119598,120884,122170, 127 123456,124742,126028,127314,128600,129886,131172,132458, 128 133744,135030,136316,137602,138888,140174,141460,142746, 129 144032,145318,146604,147890,149176,150462,151748,153034, 130 154320,155606,156892,158178,159464,160750,162036,163322, 131 164608,165894,167180,168466,169752,171038,172324,173610, 132 174896,176182,177468,178754,180040,181326,182612,183898, 133 185184,186470,187756,189042,190328,191614,192900,194186, 134 195472,196758,198044,199330,200616,201902,203188,204474, 135 205760,207046,208332,209618,210904,212190,213476,214762, 136 216048,217334,218620,219906,221192,222478,223764,225050, 137 226336,227622,228908,230194,231480,232766,234052,235338, 138 236624,237910,239196,240482,241768,243054,244340,245626, 139 246912,248198,249484,250770,252056,253342,254628,255914, 140 257200,258486,259772,261058,262344,263630,264916,266202, 141 267488,268774,270060,271346,272632,273918,275204,276490, 142 277776,279062,280348,281634,282920,284206,285492,286778, 143 288064,289350,290636,291922,293208,294494,295780,297066, 144 298352,299638,300924,302210,303496,304782,306068,307354, 145 308640,309926,311212,312498,313784,315070,316356,317642, 146 318928,320214,321500,322786,324072,325358,326644,327930 147 }; 148 149 // ------------------------------------------------------------------------ 150 151 long FloydMap[256] = 152 { 153 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 154 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 155 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 2, 2, 2, 158 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 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 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 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, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 165 4, 4, 4, 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, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 168 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 169 }; 170 171 // ------------------------------------------------------------------------ 172 173 long FloydError1[61] = 174 { 175 -7680, -7424, -7168, -6912, -6656, -6400, -6144, 176 -5888, -5632, -5376, -5120, -4864, -4608, -4352, 177 -4096, -3840, -3584, -3328, -3072, -2816, -2560, 178 -2304, -2048, -1792, -1536, -1280, -1024, -768, 179 -512, -256, 0, 256, 512, 768, 1024, 1280, 1536, 180 1792, 2048, 2304, 2560, 2816, 3072, 3328, 3584, 181 3840, 4096, 4352, 4608, 4864, 5120, 5376, 5632, 182 5888, 6144, 6400, 6656, 6912, 7168, 7424, 7680 183 }; 184 185 // ------------------------------------------------------------------------ 186 187 long FloydError3[61] = 188 { 189 -23040, -22272, -21504, -20736, -19968, -19200, 190 -18432, -17664, -16896, -16128, -15360, -14592, 191 -13824, -13056, -12288, -11520, -10752, -9984, 192 -9216, -8448, -7680, -6912, -6144, -5376, -4608, 193 -3840, -3072, -2304, -1536, -768, 0, 768, 1536, 194 2304, 3072, 3840, 4608, 5376, 6144, 6912, 7680, 195 8448, 9216, 9984, 10752, 11520, 12288, 13056, 196 13824, 14592, 15360, 16128, 16896, 17664, 18432, 197 19200, 19968, 20736, 21504, 22272, 23040 198 }; 199 200 // ------------------------------------------------------------------------ 201 202 long FloydError5[61] = 203 { 204 -38400, -37120, -35840, -34560, -33280, -32000, 205 -30720, -29440, -28160, -26880, -25600, -24320, 206 -23040, -21760, -20480, -19200, -17920, -16640, 207 -15360, -14080, -12800, -11520, -10240, -8960, 208 -7680, -6400, -5120, -3840, -2560, -1280, 0, 209 1280, 2560, 3840, 5120, 6400, 7680, 8960, 10240, 210 11520, 12800, 14080, 15360, 16640, 17920, 19200, 211 20480, 21760, 23040, 24320, 25600, 26880, 28160, 212 29440, 30720, 32000, 33280, 34560, 35840, 37120, 213 38400 214 }; 215 216 // ------------------------------------------------------------------------ 217 218 long FloydError7[61] = 219 { 220 -53760, -51968, -50176, -48384, -46592, -44800, 221 -43008, -41216, -39424, -37632, -35840, -34048, 222 -32256, -30464, -28672, -26880, -25088, -23296, 223 -21504, -19712, -17920, -16128, -14336, -12544, 224 -10752, -8960, -7168, -5376, -3584, -1792, 0, 225 1792, 3584, 5376, 7168, 8960, 10752, 12544, 14336, 226 16128, 17920, 19712, 21504, 23296, 25088, 26880, 227 28672, 30464, 32256, 34048, 35840, 37632, 39424, 228 41216, 43008, 44800, 46592, 48384, 50176, 51968, 229 53760 230 }; 231 232 // ------------------------------------------------------------------------ 233 234 long FloydIndexMap[6] = 235 { 236 -30, 21, 72, 123, 174, 225 237 }; 238 239 // -------------------------- 240 // - ImplCreateDitherMatrix - 241 // -------------------------- 242 243 void ImplCreateDitherMatrix( sal_uInt8 (*pDitherMatrix)[16][16] ) 244 { 245 double fVal = 3.125; 246 const double fVal16 = fVal / 16.; 247 long i, j, k, l; 248 sal_uInt16 pMtx[ 16 ][ 16 ]; 249 sal_uInt16 nMax = 0; 250 static sal_uInt8 pMagic[4][4] = { { 0, 14, 3, 13, }, 251 {11, 5, 8, 6, }, 252 {12, 2, 15, 1, }, 253 {7, 9, 4, 10 } }; 254 255 // MagicSquare aufbauen 256 for ( i = 0; i < 4; i++ ) 257 for ( j = 0; j < 4; j++ ) 258 for ( k = 0; k < 4; k++ ) 259 for ( l = 0; l < 4; l++ ) 260 nMax = Max ( pMtx[ (k<<2) + i][(l<<2 ) + j] = 261 (sal_uInt16) ( 0.5 + pMagic[i][j]*fVal + pMagic[k][l]*fVal16 ), nMax ); 262 263 // auf Intervall [0;254] skalieren 264 for ( i = 0, fVal = 254. / nMax; i < 16; i++ ) 265 for( j = 0; j < 16; j++ ) 266 (*pDitherMatrix)[i][j] = (sal_uInt8) ( fVal * pMtx[i][j] ); 267 } 268 269 // ---------- 270 // - Bitmap - 271 // ---------- 272 273 sal_Bool Bitmap::Convert( BmpConversion eConversion ) 274 { 275 const sal_uInt16 nBitCount = GetBitCount(); 276 sal_Bool bRet = sal_False; 277 278 switch( eConversion ) 279 { 280 case( BMP_CONVERSION_1BIT_THRESHOLD ): 281 bRet = ImplMakeMono( 128 ); 282 break; 283 284 case( BMP_CONVERSION_1BIT_MATRIX ): 285 bRet = ImplMakeMonoDither(); 286 break; 287 288 case( BMP_CONVERSION_4BIT_GREYS ): 289 bRet = ImplMakeGreyscales( 16 ); 290 break; 291 292 case( BMP_CONVERSION_4BIT_COLORS ): 293 { 294 if( nBitCount < 4 ) 295 bRet = ImplConvertUp( 4, NULL ); 296 else if( nBitCount > 4 ) 297 bRet = ImplConvertDown( 4, NULL ); 298 else 299 bRet = sal_True; 300 } 301 break; 302 303 case( BMP_CONVERSION_4BIT_TRANS ): 304 { 305 Color aTrans( BMP_COL_TRANS ); 306 307 if( nBitCount < 4 ) 308 bRet = ImplConvertUp( 4, &aTrans ); 309 else 310 bRet = ImplConvertDown( 4, &aTrans ); 311 } 312 break; 313 314 case( BMP_CONVERSION_8BIT_GREYS ): 315 bRet = ImplMakeGreyscales( 256 ); 316 break; 317 318 case( BMP_CONVERSION_8BIT_COLORS ): 319 { 320 if( nBitCount < 8 ) 321 bRet = ImplConvertUp( 8 ); 322 else if( nBitCount > 8 ) 323 bRet = ImplConvertDown( 8 ); 324 else 325 bRet = sal_True; 326 } 327 break; 328 329 case( BMP_CONVERSION_8BIT_TRANS ): 330 { 331 Color aTrans( BMP_COL_TRANS ); 332 333 if( nBitCount < 8 ) 334 bRet = ImplConvertUp( 8, &aTrans ); 335 else 336 bRet = ImplConvertDown( 8, &aTrans ); 337 } 338 break; 339 340 case( BMP_CONVERSION_24BIT ): 341 { 342 if( nBitCount < 24 ) 343 bRet = ImplConvertUp( 24, sal_False ); 344 else 345 bRet = sal_True; 346 } 347 break; 348 349 case( BMP_CONVERSION_GHOSTED ): 350 bRet = ImplConvertGhosted(); 351 break; 352 353 default: 354 DBG_ERROR( "Bitmap::Convert(): Unsupported conversion" ); 355 break; 356 } 357 358 return bRet; 359 } 360 361 // ------------------------------------------------------------------------ 362 363 sal_Bool Bitmap::ImplMakeMono( sal_uInt8 cThreshold ) 364 { 365 BitmapReadAccess* pReadAcc = AcquireReadAccess(); 366 sal_Bool bRet = sal_False; 367 368 if( pReadAcc ) 369 { 370 Bitmap aNewBmp( GetSizePixel(), 1 ); 371 BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess(); 372 373 if( pWriteAcc ) 374 { 375 const BitmapColor aBlack( pWriteAcc->GetBestMatchingColor( Color( COL_BLACK ) ) ); 376 const BitmapColor aWhite( pWriteAcc->GetBestMatchingColor( Color( COL_WHITE ) ) ); 377 const long nWidth = pWriteAcc->Width(); 378 const long nHeight = pWriteAcc->Height(); 379 380 if( pReadAcc->HasPalette() ) 381 { 382 for( long nY = 0L; nY < nHeight; nY++ ) 383 { 384 for( long nX = 0L; nX < nWidth; nX++ ) 385 { 386 const sal_uInt8 cIndex = pReadAcc->GetPixelIndex( nY, nX ); 387 if( pReadAcc->GetPaletteColor( cIndex ).GetLuminance() >= 388 cThreshold ) 389 { 390 pWriteAcc->SetPixel( nY, nX, aWhite ); 391 } 392 else 393 pWriteAcc->SetPixel( nY, nX, aBlack ); 394 } 395 } 396 } 397 else 398 { 399 for( long nY = 0L; nY < nHeight; nY++ ) 400 { 401 for( long nX = 0L; nX < nWidth; nX++ ) 402 { 403 if( pReadAcc->GetPixel( nY, nX ).GetLuminance() >= 404 cThreshold ) 405 { 406 pWriteAcc->SetPixel( nY, nX, aWhite ); 407 } 408 else 409 pWriteAcc->SetPixel( nY, nX, aBlack ); 410 } 411 } 412 } 413 414 aNewBmp.ReleaseAccess( pWriteAcc ); 415 bRet = sal_True; 416 } 417 418 ReleaseAccess( pReadAcc ); 419 420 if( bRet ) 421 { 422 const MapMode aMap( maPrefMapMode ); 423 const Size aSize( maPrefSize ); 424 425 *this = aNewBmp; 426 427 maPrefMapMode = aMap; 428 maPrefSize = aSize; 429 } 430 } 431 432 return bRet; 433 } 434 435 // ------------------------------------------------------------------------ 436 437 sal_Bool Bitmap::ImplMakeMonoDither() 438 { 439 BitmapReadAccess* pReadAcc = AcquireReadAccess(); 440 sal_Bool bRet = sal_False; 441 442 if( pReadAcc ) 443 { 444 Bitmap aNewBmp( GetSizePixel(), 1 ); 445 BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess(); 446 447 if( pWriteAcc ) 448 { 449 const BitmapColor aBlack( pWriteAcc->GetBestMatchingColor( Color( COL_BLACK ) ) ); 450 const BitmapColor aWhite( pWriteAcc->GetBestMatchingColor( Color( COL_WHITE ) ) ); 451 const long nWidth = pWriteAcc->Width(); 452 const long nHeight = pWriteAcc->Height(); 453 sal_uInt8 pDitherMatrix[ 16 ][ 16 ]; 454 455 ImplCreateDitherMatrix( &pDitherMatrix ); 456 457 if( pReadAcc->HasPalette() ) 458 { 459 for( long nY = 0L; nY < nHeight; nY++ ) 460 { 461 for( long nX = 0L, nModY = nY % 16; nX < nWidth; nX++ ) 462 { 463 const sal_uInt8 cIndex = pReadAcc->GetPixelIndex( nY, nX ); 464 if( pReadAcc->GetPaletteColor( cIndex ).GetLuminance() > 465 pDitherMatrix[ nModY ][ nX % 16 ] ) 466 { 467 pWriteAcc->SetPixel( nY, nX, aWhite ); 468 } 469 else 470 pWriteAcc->SetPixel( nY, nX, aBlack ); 471 } 472 } 473 } 474 else 475 { 476 for( long nY = 0L; nY < nHeight; nY++ ) 477 { 478 for( long nX = 0L, nModY = nY % 16; nX < nWidth; nX++ ) 479 { 480 if( pReadAcc->GetPixel( nY, nX ).GetLuminance() > 481 pDitherMatrix[ nModY ][ nX % 16 ] ) 482 { 483 pWriteAcc->SetPixel( nY, nX, aWhite ); 484 } 485 else 486 pWriteAcc->SetPixel( nY, nX, aBlack ); 487 } 488 } 489 } 490 491 aNewBmp.ReleaseAccess( pWriteAcc ); 492 bRet = sal_True; 493 } 494 495 ReleaseAccess( pReadAcc ); 496 497 if( bRet ) 498 { 499 const MapMode aMap( maPrefMapMode ); 500 const Size aSize( maPrefSize ); 501 502 *this = aNewBmp; 503 504 maPrefMapMode = aMap; 505 maPrefSize = aSize; 506 } 507 } 508 509 return bRet; 510 } 511 512 // ------------------------------------------------------------------------ 513 514 sal_Bool Bitmap::ImplMakeGreyscales( sal_uInt16 nGreys ) 515 { 516 DBG_ASSERT( nGreys == 16 || nGreys == 256, "Only 16 or 256 greyscales are supported!" ); 517 518 BitmapReadAccess* pReadAcc = AcquireReadAccess(); 519 sal_Bool bRet = sal_False; 520 521 if( pReadAcc ) 522 { 523 const BitmapPalette& rPal = GetGreyPalette( nGreys ); 524 sal_uLong nShift = ( ( nGreys == 16 ) ? 4UL : 0UL ); 525 sal_Bool bPalDiffers = !pReadAcc->HasPalette() || ( rPal.GetEntryCount() != pReadAcc->GetPaletteEntryCount() ); 526 527 if( !bPalDiffers ) 528 bPalDiffers = ( (BitmapPalette&) rPal != pReadAcc->GetPalette() ); 529 530 if( bPalDiffers ) 531 { 532 Bitmap aNewBmp( GetSizePixel(), ( nGreys == 16 ) ? 4 : 8, &rPal ); 533 BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess(); 534 535 if( pWriteAcc ) 536 { 537 const long nWidth = pWriteAcc->Width(); 538 const long nHeight = pWriteAcc->Height(); 539 540 if( pReadAcc->HasPalette() ) 541 { 542 for( long nY = 0L; nY < nHeight; nY++ ) 543 { 544 for( long nX = 0L; nX < nWidth; nX++ ) 545 { 546 const sal_uInt8 cIndex = pReadAcc->GetPixelIndex( nY, nX ); 547 pWriteAcc->SetPixelIndex( nY, nX, 548 (pReadAcc->GetPaletteColor( cIndex ).GetLuminance() >> nShift) ); 549 } 550 } 551 } 552 else if( pReadAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_BGR && 553 pWriteAcc->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL ) 554 { 555 nShift += 8; 556 557 for( long nY = 0L; nY < nHeight; nY++ ) 558 { 559 Scanline pReadScan = pReadAcc->GetScanline( nY ); 560 Scanline pWriteScan = pWriteAcc->GetScanline( nY ); 561 562 for( long nX = 0L; nX < nWidth; nX++ ) 563 { 564 const sal_uLong nB = *pReadScan++; 565 const sal_uLong nG = *pReadScan++; 566 const sal_uLong nR = *pReadScan++; 567 568 *pWriteScan++ = (sal_uInt8) ( ( nB * 28UL + nG * 151UL + nR * 77UL ) >> nShift ); 569 } 570 } 571 } 572 else if( pReadAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_RGB && 573 pWriteAcc->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL ) 574 { 575 nShift += 8; 576 577 for( long nY = 0L; nY < nHeight; nY++ ) 578 { 579 Scanline pReadScan = pReadAcc->GetScanline( nY ); 580 Scanline pWriteScan = pWriteAcc->GetScanline( nY ); 581 582 for( long nX = 0L; nX < nWidth; nX++ ) 583 { 584 const sal_uLong nR = *pReadScan++; 585 const sal_uLong nG = *pReadScan++; 586 const sal_uLong nB = *pReadScan++; 587 588 *pWriteScan++ = (sal_uInt8) ( ( nB * 28UL + nG * 151UL + nR * 77UL ) >> nShift ); 589 } 590 } 591 } 592 else 593 { 594 for( long nY = 0L; nY < nHeight; nY++ ) 595 for( long nX = 0L; nX < nWidth; nX++ ) 596 pWriteAcc->SetPixelIndex( nY, nX, (pReadAcc->GetPixel( nY, nX ) ).GetLuminance() >> nShift ); 597 } 598 599 aNewBmp.ReleaseAccess( pWriteAcc ); 600 bRet = sal_True; 601 } 602 603 ReleaseAccess( pReadAcc ); 604 605 if( bRet ) 606 { 607 const MapMode aMap( maPrefMapMode ); 608 const Size aSize( maPrefSize ); 609 610 *this = aNewBmp; 611 612 maPrefMapMode = aMap; 613 maPrefSize = aSize; 614 } 615 } 616 else 617 { 618 ReleaseAccess( pReadAcc ); 619 bRet = sal_True; 620 } 621 } 622 623 return bRet; 624 } 625 626 // ------------------------------------------------------------------------ 627 628 sal_Bool Bitmap::ImplConvertUp( sal_uInt16 nBitCount, Color* pExtColor ) 629 { 630 DBG_ASSERT( nBitCount > GetBitCount(), "New BitCount must be greater!" ); 631 632 BitmapReadAccess* pReadAcc = AcquireReadAccess(); 633 sal_Bool bRet = sal_False; 634 635 if( pReadAcc ) 636 { 637 BitmapPalette aPal; 638 Bitmap aNewBmp( GetSizePixel(), nBitCount, pReadAcc->HasPalette() ? &pReadAcc->GetPalette() : &aPal ); 639 BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess(); 640 641 if( pWriteAcc ) 642 { 643 const long nWidth = pWriteAcc->Width(); 644 const long nHeight = pWriteAcc->Height(); 645 646 if( pWriteAcc->HasPalette() ) 647 { 648 const sal_uInt16 nOldCount = 1 << GetBitCount(); 649 const BitmapPalette& rOldPal = pReadAcc->GetPalette(); 650 651 aPal.SetEntryCount( 1 << nBitCount ); 652 653 for( sal_uInt16 i = 0; i < nOldCount; i++ ) 654 aPal[ i ] = rOldPal[ i ]; 655 656 if( pExtColor ) 657 aPal[ aPal.GetEntryCount() - 1 ] = *pExtColor; 658 659 pWriteAcc->SetPalette( aPal ); 660 661 for( long nY = 0L; nY < nHeight; nY++ ) 662 for( long nX = 0L; nX < nWidth; nX++ ) 663 pWriteAcc->SetPixel( nY, nX, pReadAcc->GetPixel( nY, nX ) ); 664 } 665 else 666 { 667 if( pReadAcc->HasPalette() ) 668 { 669 for( long nY = 0L; nY < nHeight; nY++ ) 670 for( long nX = 0L; nX < nWidth; nX++ ) 671 pWriteAcc->SetPixel( nY, nX, pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nY, nX ) ) ); 672 } 673 else 674 { 675 for( long nY = 0L; nY < nHeight; nY++ ) 676 for( long nX = 0L; nX < nWidth; nX++ ) 677 pWriteAcc->SetPixel( nY, nX, pReadAcc->GetPixel( nY, nX ) ); 678 } 679 } 680 681 aNewBmp.ReleaseAccess( pWriteAcc ); 682 bRet = sal_True; 683 } 684 685 ReleaseAccess( pReadAcc ); 686 687 if( bRet ) 688 { 689 const MapMode aMap( maPrefMapMode ); 690 const Size aSize( maPrefSize ); 691 692 *this = aNewBmp; 693 694 maPrefMapMode = aMap; 695 maPrefSize = aSize; 696 } 697 } 698 699 return bRet; 700 } 701 702 // ------------------------------------------------------------------------ 703 704 sal_Bool Bitmap::ImplConvertDown( sal_uInt16 nBitCount, Color* pExtColor ) 705 { 706 DBG_ASSERT( nBitCount <= GetBitCount(), "New BitCount must be lower ( or equal when pExtColor is set )!" ); 707 708 BitmapReadAccess* pReadAcc = AcquireReadAccess(); 709 sal_Bool bRet = sal_False; 710 711 if( pReadAcc ) 712 { 713 BitmapPalette aPal; 714 Bitmap aNewBmp( GetSizePixel(), nBitCount, &aPal ); 715 BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess(); 716 717 if( pWriteAcc ) 718 { 719 const sal_uInt16 nCount = 1 << nBitCount; 720 const long nWidth = pWriteAcc->Width(); 721 const long nWidth1 = nWidth - 1L; 722 const long nHeight = pWriteAcc->Height(); 723 Octree aOctree( *pReadAcc, pExtColor ? ( nCount - 1 ) : nCount ); 724 InverseColorMap aColorMap( aPal = aOctree.GetPalette() ); 725 BitmapColor aColor; 726 ImpErrorQuad aErrQuad; 727 ImpErrorQuad* pErrQuad1 = new ImpErrorQuad[ nWidth ]; 728 ImpErrorQuad* pErrQuad2 = new ImpErrorQuad[ nWidth ]; 729 ImpErrorQuad* pQLine1 = pErrQuad1; 730 ImpErrorQuad* pQLine2 = 0; 731 long nX, nY; 732 long nYTmp = 0L; 733 sal_uInt8 cIndex; 734 sal_Bool bQ1 = sal_True; 735 736 if( pExtColor ) 737 { 738 aPal.SetEntryCount( aPal.GetEntryCount() + 1 ); 739 aPal[ aPal.GetEntryCount() - 1 ] = *pExtColor; 740 } 741 742 // set Black/White always, if we have enough space 743 if( aPal.GetEntryCount() < ( nCount - 1 ) ) 744 { 745 aPal.SetEntryCount( aPal.GetEntryCount() + 2 ); 746 aPal[ aPal.GetEntryCount() - 2 ] = Color( COL_BLACK ); 747 aPal[ aPal.GetEntryCount() - 1 ] = Color( COL_WHITE ); 748 } 749 750 pWriteAcc->SetPalette( aPal ); 751 752 for( nY = 0L; nY < Min( nHeight, 2L ); nY++, nYTmp++ ) 753 { 754 for( nX = 0L, pQLine2 = !nY ? pErrQuad1 : pErrQuad2; nX < nWidth; nX++ ) 755 { 756 if( pReadAcc->HasPalette() ) 757 pQLine2[ nX ] = pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nYTmp, nX ) ); 758 else 759 pQLine2[ nX ] = pReadAcc->GetPixel( nYTmp, nX ); 760 } 761 } 762 763 for( nY = 0L; nY < nHeight; nY++, nYTmp++ ) 764 { 765 // first pixel in the line 766 cIndex = (sal_uInt8) aColorMap.GetBestPaletteIndex( pQLine1[ 0 ].ImplGetColor() ); 767 pWriteAcc->SetPixelIndex( nY, 0, cIndex ); 768 769 for( nX = 1L; nX < nWidth1; nX++ ) 770 { 771 cIndex = (sal_uInt8) aColorMap.GetBestPaletteIndex( aColor = pQLine1[ nX ].ImplGetColor() ); 772 aErrQuad = ( ImpErrorQuad( aColor ) -= pWriteAcc->GetPaletteColor( cIndex ) ); 773 pQLine1[ ++nX ].ImplAddColorError7( aErrQuad ); 774 pQLine2[ nX-- ].ImplAddColorError1( aErrQuad ); 775 pQLine2[ nX-- ].ImplAddColorError5( aErrQuad ); 776 pQLine2[ nX++ ].ImplAddColorError3( aErrQuad ); 777 pWriteAcc->SetPixelIndex( nY, nX, cIndex ); 778 } 779 780 // letztes ZeilenPixel 781 if( nX < nWidth ) 782 { 783 cIndex = (sal_uInt8) aColorMap.GetBestPaletteIndex( pQLine1[ nWidth1 ].ImplGetColor() ); 784 pWriteAcc->SetPixelIndex( nY, nX, cIndex ); 785 } 786 787 // Zeilenpuffer neu fuellen/kopieren 788 pQLine1 = pQLine2; 789 pQLine2 = ( bQ1 = !bQ1 ) != sal_False ? pErrQuad2 : pErrQuad1; 790 791 if( nYTmp < nHeight ) 792 { 793 for( nX = 0L; nX < nWidth; nX++ ) 794 { 795 if( pReadAcc->HasPalette() ) 796 pQLine2[ nX ] = pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nYTmp, nX ) ); 797 else 798 pQLine2[ nX ] = pReadAcc->GetPixel( nYTmp, nX ); 799 } 800 } 801 } 802 803 // Zeilenpuffer zerstoeren 804 delete[] pErrQuad1; 805 delete[] pErrQuad2; 806 807 aNewBmp.ReleaseAccess( pWriteAcc ); 808 bRet = sal_True; 809 } 810 811 ReleaseAccess( pReadAcc ); 812 813 if( bRet ) 814 { 815 const MapMode aMap( maPrefMapMode ); 816 const Size aSize( maPrefSize ); 817 818 *this = aNewBmp; 819 820 maPrefMapMode = aMap; 821 maPrefSize = aSize; 822 } 823 } 824 825 return bRet; 826 } 827 828 // ------------------------------------------------------------------------ 829 830 sal_Bool Bitmap::ImplConvertGhosted() 831 { 832 Bitmap aNewBmp; 833 BitmapReadAccess* pR = AcquireReadAccess(); 834 sal_Bool bRet = sal_False; 835 836 if( pR ) 837 { 838 if( pR->HasPalette() ) 839 { 840 BitmapPalette aNewPal( pR->GetPaletteEntryCount() ); 841 842 for( long i = 0, nCount = aNewPal.GetEntryCount(); i < nCount; i++ ) 843 { 844 const BitmapColor& rOld = pR->GetPaletteColor( (sal_uInt16) i ); 845 aNewPal[ (sal_uInt16) i ] = BitmapColor( ( rOld.GetRed() >> 1 ) | 0x80, 846 ( rOld.GetGreen() >> 1 ) | 0x80, 847 ( rOld.GetBlue() >> 1 ) | 0x80 ); 848 } 849 850 aNewBmp = Bitmap( GetSizePixel(), GetBitCount(), &aNewPal ); 851 BitmapWriteAccess* pW = aNewBmp.AcquireWriteAccess(); 852 853 if( pW ) 854 { 855 pW->CopyBuffer( *pR ); 856 aNewBmp.ReleaseAccess( pW ); 857 bRet = sal_True; 858 } 859 } 860 else 861 { 862 aNewBmp = Bitmap( GetSizePixel(), 24 ); 863 864 BitmapWriteAccess* pW = aNewBmp.AcquireWriteAccess(); 865 866 if( pW ) 867 { 868 const long nWidth = pR->Width(), nHeight = pR->Height(); 869 870 for( long nY = 0; nY < nHeight; nY++ ) 871 { 872 for( long nX = 0; nX < nWidth; nX++ ) 873 { 874 const BitmapColor aOld( pR->GetPixel( nY, nX ) ); 875 pW->SetPixel( nY, nX, BitmapColor( ( aOld.GetRed() >> 1 ) | 0x80, 876 ( aOld.GetGreen() >> 1 ) | 0x80, 877 ( aOld.GetBlue() >> 1 ) | 0x80 ) ); 878 879 } 880 } 881 882 aNewBmp.ReleaseAccess( pW ); 883 bRet = sal_True; 884 } 885 } 886 887 ReleaseAccess( pR ); 888 } 889 890 if( bRet ) 891 { 892 const MapMode aMap( maPrefMapMode ); 893 const Size aSize( maPrefSize ); 894 895 *this = aNewBmp; 896 897 maPrefMapMode = aMap; 898 maPrefSize = aSize; 899 } 900 901 return bRet; 902 } 903 904 // ------------------------------------------------------------------------ 905 906 sal_Bool Bitmap::Scale( const double& rScaleX, const double& rScaleY, sal_uLong nScaleFlag ) 907 { 908 sal_Bool bRet; 909 910 if( ( rScaleX != 1.0 ) || ( rScaleY != 1.0 ) ) 911 { 912 if( BMP_SCALE_FAST == nScaleFlag ) 913 bRet = ImplScaleFast( rScaleX, rScaleY ); 914 else if( BMP_SCALE_INTERPOLATE == nScaleFlag ) 915 bRet = ImplScaleInterpolate( rScaleX, rScaleY ); 916 else 917 bRet = sal_False; 918 } 919 else 920 bRet = sal_True; 921 922 return bRet; 923 } 924 925 // ------------------------------------------------------------------------ 926 927 sal_Bool Bitmap::Scale( const Size& rNewSize, sal_uLong nScaleFlag ) 928 { 929 const Size aSize( GetSizePixel() ); 930 sal_Bool bRet; 931 932 if( aSize.Width() && aSize.Height() ) 933 { 934 bRet = Scale( (double) rNewSize.Width() / aSize.Width(), 935 (double) rNewSize.Height() / aSize.Height(), 936 nScaleFlag ); 937 } 938 else 939 bRet = sal_True; 940 941 return bRet; 942 } 943 944 // ------------------------------------------------------------------------ 945 946 sal_Bool Bitmap::ImplScaleFast( const double& rScaleX, const double& rScaleY ) 947 { 948 const Size aSizePix( GetSizePixel() ); 949 const long nNewWidth = FRound( aSizePix.Width() * rScaleX ); 950 const long nNewHeight = FRound( aSizePix.Height() * rScaleY ); 951 sal_Bool bRet = sal_False; 952 953 if( nNewWidth && nNewHeight ) 954 { 955 BitmapReadAccess* pReadAcc = AcquireReadAccess(); 956 if ( !pReadAcc ) 957 return sal_False; 958 959 Bitmap aNewBmp( Size( nNewWidth, nNewHeight ), GetBitCount(), &pReadAcc->GetPalette() ); 960 BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess(); 961 962 if( pWriteAcc ) 963 { 964 const long nScanlineSize = pWriteAcc->GetScanlineSize(); 965 const long nNewWidth1 = nNewWidth - 1L; 966 const long nNewHeight1 = nNewHeight - 1L; 967 const long nWidth = pReadAcc->Width(); 968 const long nHeight = pReadAcc->Height(); 969 long* pLutX = new long[ nNewWidth ]; 970 long* pLutY = new long[ nNewHeight ]; 971 long nX, nY, nMapY, nActY = 0L; 972 973 if( nNewWidth1 && nNewHeight1 ) 974 { 975 for( nX = 0L; nX < nNewWidth; nX++ ) 976 pLutX[ nX ] = nX * nWidth / nNewWidth; 977 978 for( nY = 0L; nY < nNewHeight; nY++ ) 979 pLutY[ nY ] = nY * nHeight / nNewHeight; 980 981 while( nActY < nNewHeight ) 982 { 983 nMapY = pLutY[ nActY ]; 984 985 for( nX = 0L; nX < nNewWidth; nX++ ) 986 pWriteAcc->SetPixel( nActY, nX, pReadAcc->GetPixel( nMapY , pLutX[ nX ] ) ); 987 988 while( ( nActY < nNewHeight1 ) && ( pLutY[ nActY + 1 ] == nMapY ) ) 989 { 990 memcpy( pWriteAcc->GetScanline( nActY + 1L ), 991 pWriteAcc->GetScanline( nActY ), nScanlineSize ); 992 nActY++; 993 } 994 995 nActY++; 996 } 997 998 bRet = sal_True; 999 } 1000 1001 delete[] pLutX; 1002 delete[] pLutY; 1003 } 1004 1005 ReleaseAccess( pReadAcc ); 1006 aNewBmp.ReleaseAccess( pWriteAcc ); 1007 1008 if( bRet ) 1009 ImplAssignWithSize( aNewBmp ); 1010 } 1011 1012 return bRet; 1013 } 1014 1015 // ------------------------------------------------------------------------ 1016 1017 sal_Bool Bitmap::ImplScaleInterpolate( const double& rScaleX, const double& rScaleY ) 1018 { 1019 const Size aSizePix( GetSizePixel() ); 1020 const long nNewWidth = FRound( aSizePix.Width() * rScaleX ); 1021 const long nNewHeight = FRound( aSizePix.Height() * rScaleY ); 1022 sal_Bool bRet = sal_False; 1023 1024 if( ( nNewWidth > 1L ) && ( nNewHeight > 1L ) ) 1025 { 1026 BitmapColor aCol0; 1027 BitmapColor aCol1; 1028 BitmapReadAccess* pReadAcc = AcquireReadAccess(); 1029 long nWidth = pReadAcc->Width(); 1030 long nHeight = pReadAcc->Height(); 1031 Bitmap aNewBmp( Size( nNewWidth, nHeight ), 24 ); 1032 BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess(); 1033 long* pLutInt; 1034 long* pLutFrac; 1035 long nX, nY; 1036 long lXB0, lXB1, lXG0, lXG1, lXR0, lXR1; 1037 double fTemp; 1038 long nTemp; 1039 1040 if( pReadAcc && pWriteAcc ) 1041 { 1042 const long nNewWidth1 = nNewWidth - 1L; 1043 const long nWidth1 = pReadAcc->Width() - 1L; 1044 const double fRevScaleX = (double) nWidth1 / nNewWidth1; 1045 1046 pLutInt = new long[ nNewWidth ]; 1047 pLutFrac = new long[ nNewWidth ]; 1048 1049 for( nX = 0L, nTemp = nWidth - 2L; nX < nNewWidth; nX++ ) 1050 { 1051 fTemp = nX * fRevScaleX; 1052 pLutInt[ nX ] = MinMax( (long) fTemp, 0, nTemp ); 1053 fTemp -= pLutInt[ nX ]; 1054 pLutFrac[ nX ] = (long) ( fTemp * 1024. ); 1055 } 1056 1057 if( pReadAcc->HasPalette() ) 1058 { 1059 for( nY = 0L; nY < nHeight; nY++ ) 1060 { 1061 if( 1 == nWidth ) 1062 { 1063 aCol0 = pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nY, 0 ) ); 1064 1065 for( nX = 0L; nX < nNewWidth; nX++ ) 1066 pWriteAcc->SetPixel( nY, nX, aCol0 ); 1067 } 1068 else 1069 { 1070 for( nX = 0L; nX < nNewWidth; nX++ ) 1071 { 1072 nTemp = pLutInt[ nX ]; 1073 1074 aCol0 = pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nY, nTemp++ ) ); 1075 aCol1 = pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nY, nTemp ) ); 1076 1077 nTemp = pLutFrac[ nX ]; 1078 1079 lXR1 = aCol1.GetRed() - ( lXR0 = aCol0.GetRed() ); 1080 lXG1 = aCol1.GetGreen() - ( lXG0 = aCol0.GetGreen() ); 1081 lXB1 = aCol1.GetBlue() - ( lXB0 = aCol0.GetBlue() ); 1082 1083 aCol0.SetRed( (sal_uInt8) ( ( lXR1 * nTemp + ( lXR0 << 10 ) ) >> 10 ) ); 1084 aCol0.SetGreen( (sal_uInt8) ( ( lXG1 * nTemp + ( lXG0 << 10 ) ) >> 10 ) ); 1085 aCol0.SetBlue( (sal_uInt8) ( ( lXB1 * nTemp + ( lXB0 << 10 ) ) >> 10 ) ); 1086 1087 pWriteAcc->SetPixel( nY, nX, aCol0 ); 1088 } 1089 } 1090 } 1091 } 1092 else 1093 { 1094 for( nY = 0L; nY < nHeight; nY++ ) 1095 { 1096 if( 1 == nWidth ) 1097 { 1098 aCol0 = pReadAcc->GetPixel( nY, 0 ); 1099 1100 for( nX = 0L; nX < nNewWidth; nX++ ) 1101 pWriteAcc->SetPixel( nY, nX, aCol0 ); 1102 } 1103 else 1104 { 1105 for( nX = 0L; nX < nNewWidth; nX++ ) 1106 { 1107 nTemp = pLutInt[ nX ]; 1108 1109 aCol0 = pReadAcc->GetPixel( nY, nTemp++ ); 1110 aCol1 = pReadAcc->GetPixel( nY, nTemp ); 1111 1112 nTemp = pLutFrac[ nX ]; 1113 1114 lXR1 = aCol1.GetRed() - ( lXR0 = aCol0.GetRed() ); 1115 lXG1 = aCol1.GetGreen() - ( lXG0 = aCol0.GetGreen() ); 1116 lXB1 = aCol1.GetBlue() - ( lXB0 = aCol0.GetBlue() ); 1117 1118 aCol0.SetRed( (sal_uInt8) ( ( lXR1 * nTemp + ( lXR0 << 10 ) ) >> 10 ) ); 1119 aCol0.SetGreen( (sal_uInt8) ( ( lXG1 * nTemp + ( lXG0 << 10 ) ) >> 10 ) ); 1120 aCol0.SetBlue( (sal_uInt8) ( ( lXB1 * nTemp + ( lXB0 << 10 ) ) >> 10 ) ); 1121 1122 pWriteAcc->SetPixel( nY, nX, aCol0 ); 1123 } 1124 } 1125 } 1126 } 1127 1128 delete[] pLutInt; 1129 delete[] pLutFrac; 1130 bRet = sal_True; 1131 } 1132 1133 ReleaseAccess( pReadAcc ); 1134 aNewBmp.ReleaseAccess( pWriteAcc ); 1135 1136 if( bRet ) 1137 { 1138 bRet = sal_False; 1139 ImplAssignWithSize( aNewBmp ); 1140 pReadAcc = AcquireReadAccess(); 1141 aNewBmp = Bitmap( Size( nNewWidth, nNewHeight ), 24 ); 1142 pWriteAcc = aNewBmp.AcquireWriteAccess(); 1143 1144 if( pReadAcc && pWriteAcc ) 1145 { 1146 const long nNewHeight1 = nNewHeight - 1L; 1147 const long nHeight1 = pReadAcc->Height() - 1L; 1148 const double fRevScaleY = (double) nHeight1 / nNewHeight1; 1149 1150 pLutInt = new long[ nNewHeight ]; 1151 pLutFrac = new long[ nNewHeight ]; 1152 1153 for( nY = 0L, nTemp = nHeight - 2L; nY < nNewHeight; nY++ ) 1154 { 1155 fTemp = nY * fRevScaleY; 1156 pLutInt[ nY ] = MinMax( (long) fTemp, 0, nTemp ); 1157 fTemp -= pLutInt[ nY ]; 1158 pLutFrac[ nY ] = (long) ( fTemp * 1024. ); 1159 } 1160 1161 if( pReadAcc->HasPalette() ) 1162 { 1163 for( nX = 0L; nX < nNewWidth; nX++ ) 1164 { 1165 if( 1 == nHeight ) 1166 { 1167 aCol0 = pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( 0, nX ) ); 1168 1169 for( nY = 0L; nY < nNewHeight; nY++ ) 1170 pWriteAcc->SetPixel( nY, nX, aCol0 ); 1171 } 1172 else 1173 { 1174 for( nY = 0L; nY < nNewHeight; nY++ ) 1175 { 1176 nTemp = pLutInt[ nY ]; 1177 1178 aCol0 = pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nTemp++, nX ) ); 1179 aCol1 = pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nTemp, nX ) ); 1180 1181 nTemp = pLutFrac[ nY ]; 1182 1183 lXR1 = aCol1.GetRed() - ( lXR0 = aCol0.GetRed() ); 1184 lXG1 = aCol1.GetGreen() - ( lXG0 = aCol0.GetGreen() ); 1185 lXB1 = aCol1.GetBlue() - ( lXB0 = aCol0.GetBlue() ); 1186 1187 aCol0.SetRed( (sal_uInt8) ( ( lXR1 * nTemp + ( lXR0 << 10 ) ) >> 10 ) ); 1188 aCol0.SetGreen( (sal_uInt8) ( ( lXG1 * nTemp + ( lXG0 << 10 ) ) >> 10 ) ); 1189 aCol0.SetBlue( (sal_uInt8) ( ( lXB1 * nTemp + ( lXB0 << 10 ) ) >> 10 ) ); 1190 1191 pWriteAcc->SetPixel( nY, nX, aCol0 ); 1192 } 1193 } 1194 } 1195 } 1196 else 1197 { 1198 for( nX = 0L; nX < nNewWidth; nX++ ) 1199 { 1200 if( 1 == nHeight ) 1201 { 1202 aCol0 = pReadAcc->GetPixel( 0, nX ); 1203 1204 for( nY = 0L; nY < nNewHeight; nY++ ) 1205 pWriteAcc->SetPixel( nY, nX, aCol0 ); 1206 } 1207 else 1208 { 1209 for( nY = 0L; nY < nNewHeight; nY++ ) 1210 { 1211 nTemp = pLutInt[ nY ]; 1212 1213 aCol0 = pReadAcc->GetPixel( nTemp++, nX ); 1214 aCol1 = pReadAcc->GetPixel( nTemp, nX ); 1215 1216 nTemp = pLutFrac[ nY ]; 1217 1218 lXR1 = aCol1.GetRed() - ( lXR0 = aCol0.GetRed() ); 1219 lXG1 = aCol1.GetGreen() - ( lXG0 = aCol0.GetGreen() ); 1220 lXB1 = aCol1.GetBlue() - ( lXB0 = aCol0.GetBlue() ); 1221 1222 aCol0.SetRed( (sal_uInt8) ( ( lXR1 * nTemp + ( lXR0 << 10 ) ) >> 10 ) ); 1223 aCol0.SetGreen( (sal_uInt8) ( ( lXG1 * nTemp + ( lXG0 << 10 ) ) >> 10 ) ); 1224 aCol0.SetBlue( (sal_uInt8) ( ( lXB1 * nTemp + ( lXB0 << 10 ) ) >> 10 ) ); 1225 1226 pWriteAcc->SetPixel( nY, nX, aCol0 ); 1227 } 1228 } 1229 } 1230 } 1231 1232 delete[] pLutInt; 1233 delete[] pLutFrac; 1234 bRet = sal_True; 1235 } 1236 1237 ReleaseAccess( pReadAcc ); 1238 aNewBmp.ReleaseAccess( pWriteAcc ); 1239 1240 if( bRet ) 1241 ImplAssignWithSize( aNewBmp ); 1242 } 1243 } 1244 1245 if( !bRet ) 1246 bRet = ImplScaleFast( rScaleX, rScaleY ); 1247 1248 return bRet; 1249 } 1250 1251 // ------------------------------------------------------------------------ 1252 1253 sal_Bool Bitmap::Dither( sal_uLong nDitherFlags ) 1254 { 1255 sal_Bool bRet = sal_False; 1256 1257 const Size aSizePix( GetSizePixel() ); 1258 1259 if( aSizePix.Width() == 1 || aSizePix.Height() == 1 ) 1260 bRet = sal_True; 1261 else if( nDitherFlags & BMP_DITHER_MATRIX ) 1262 bRet = ImplDitherMatrix(); 1263 else if( nDitherFlags & BMP_DITHER_FLOYD ) 1264 bRet = ImplDitherFloyd(); 1265 else if( ( nDitherFlags & BMP_DITHER_FLOYD_16 ) && ( GetBitCount() == 24 ) ) 1266 bRet = ImplDitherFloyd16(); 1267 1268 return bRet; 1269 } 1270 1271 // ------------------------------------------------------------------------ 1272 1273 sal_Bool Bitmap::ImplDitherMatrix() 1274 { 1275 BitmapReadAccess* pReadAcc = AcquireReadAccess(); 1276 Bitmap aNewBmp( GetSizePixel(), 8 ); 1277 BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess(); 1278 sal_Bool bRet = sal_False; 1279 1280 if( pReadAcc && pWriteAcc ) 1281 { 1282 const sal_uLong nWidth = pReadAcc->Width(); 1283 const sal_uLong nHeight = pReadAcc->Height(); 1284 BitmapColor aIndex( (sal_uInt8) 0 ); 1285 1286 if( pReadAcc->HasPalette() ) 1287 { 1288 for( sal_uLong nY = 0UL; nY < nHeight; nY++ ) 1289 { 1290 for( sal_uLong nX = 0UL, nModY = ( nY & 0x0FUL ) << 4UL; nX < nWidth; nX++ ) 1291 { 1292 const BitmapColor aCol( pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nY, nX ) ) ); 1293 const sal_uLong nD = nVCLDitherLut[ nModY + ( nX & 0x0FUL ) ]; 1294 const sal_uLong nR = ( nVCLLut[ aCol.GetRed() ] + nD ) >> 16UL; 1295 const sal_uLong nG = ( nVCLLut[ aCol.GetGreen() ] + nD ) >> 16UL; 1296 const sal_uLong nB = ( nVCLLut[ aCol.GetBlue() ] + nD ) >> 16UL; 1297 1298 aIndex.SetIndex( (sal_uInt8) ( nVCLRLut[ nR ] + nVCLGLut[ nG ] + nVCLBLut[ nB ] ) ); 1299 pWriteAcc->SetPixel( nY, nX, aIndex ); 1300 } 1301 } 1302 } 1303 else 1304 { 1305 for( sal_uLong nY = 0UL; nY < nHeight; nY++ ) 1306 { 1307 for( sal_uLong nX = 0UL, nModY = ( nY & 0x0FUL ) << 4UL; nX < nWidth; nX++ ) 1308 { 1309 const BitmapColor aCol( pReadAcc->GetPixel( nY, nX ) ); 1310 const sal_uLong nD = nVCLDitherLut[ nModY + ( nX & 0x0FUL ) ]; 1311 const sal_uLong nR = ( nVCLLut[ aCol.GetRed() ] + nD ) >> 16UL; 1312 const sal_uLong nG = ( nVCLLut[ aCol.GetGreen() ] + nD ) >> 16UL; 1313 const sal_uLong nB = ( nVCLLut[ aCol.GetBlue() ] + nD ) >> 16UL; 1314 1315 aIndex.SetIndex( (sal_uInt8) ( nVCLRLut[ nR ] + nVCLGLut[ nG ] + nVCLBLut[ nB ] ) ); 1316 pWriteAcc->SetPixel( nY, nX, aIndex ); 1317 } 1318 } 1319 } 1320 1321 bRet = sal_True; 1322 } 1323 1324 ReleaseAccess( pReadAcc ); 1325 aNewBmp.ReleaseAccess( pWriteAcc ); 1326 1327 if( bRet ) 1328 { 1329 const MapMode aMap( maPrefMapMode ); 1330 const Size aSize( maPrefSize ); 1331 1332 *this = aNewBmp; 1333 1334 maPrefMapMode = aMap; 1335 maPrefSize = aSize; 1336 } 1337 1338 return bRet; 1339 } 1340 1341 // ------------------------------------------------------------------------ 1342 1343 sal_Bool Bitmap::ImplDitherFloyd() 1344 { 1345 const Size aSize( GetSizePixel() ); 1346 sal_Bool bRet = sal_False; 1347 1348 if( ( aSize.Width() > 3 ) && ( aSize.Height() > 2 ) ) 1349 { 1350 BitmapReadAccess* pReadAcc = AcquireReadAccess(); 1351 Bitmap aNewBmp( GetSizePixel(), 8 ); 1352 BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess(); 1353 1354 if( pReadAcc && pWriteAcc ) 1355 { 1356 BitmapColor aColor; 1357 long nWidth = pReadAcc->Width(); 1358 long nWidth1 = nWidth - 1L; 1359 long nHeight = pReadAcc->Height(); 1360 long nX; 1361 long nW = nWidth * 3L; 1362 long nW2 = nW - 3L; 1363 long nRErr, nGErr, nBErr; 1364 long nRC, nGC, nBC; 1365 long nTemp; 1366 long nZ; 1367 long* p1 = new long[ nW ]; 1368 long* p2 = new long[ nW ]; 1369 long* p1T = p1; 1370 long* p2T = p2; 1371 long* pTmp; 1372 sal_Bool bPal = pReadAcc->HasPalette(); 1373 1374 pTmp = p2T; 1375 1376 if( bPal ) 1377 { 1378 for( nZ = 0; nZ < nWidth; nZ++ ) 1379 { 1380 aColor = pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( 0, nZ ) ); 1381 1382 *pTmp++ = (long) aColor.GetBlue() << 12; 1383 *pTmp++ = (long) aColor.GetGreen() << 12; 1384 *pTmp++ = (long) aColor.GetRed() << 12; 1385 } 1386 } 1387 else 1388 { 1389 for( nZ = 0; nZ < nWidth; nZ++ ) 1390 { 1391 aColor = pReadAcc->GetPixel( 0, nZ ); 1392 1393 *pTmp++ = (long) aColor.GetBlue() << 12; 1394 *pTmp++ = (long) aColor.GetGreen() << 12; 1395 *pTmp++ = (long) aColor.GetRed() << 12; 1396 } 1397 } 1398 1399 for( long nY = 1, nYAcc = 0L; nY <= nHeight; nY++, nYAcc++ ) 1400 { 1401 pTmp = p1T; 1402 p1T = p2T; 1403 p2T = pTmp; 1404 1405 if( nY < nHeight ) 1406 { 1407 if( bPal ) 1408 { 1409 for( nZ = 0; nZ < nWidth; nZ++ ) 1410 { 1411 aColor = pReadAcc->GetPaletteColor( pReadAcc->GetPixelIndex( nY, nZ ) ); 1412 1413 *pTmp++ = (long) aColor.GetBlue() << 12; 1414 *pTmp++ = (long) aColor.GetGreen() << 12; 1415 *pTmp++ = (long) aColor.GetRed() << 12; 1416 } 1417 } 1418 else 1419 { 1420 for( nZ = 0; nZ < nWidth; nZ++ ) 1421 { 1422 aColor = pReadAcc->GetPixel( nY, nZ ); 1423 1424 *pTmp++ = (long) aColor.GetBlue() << 12; 1425 *pTmp++ = (long) aColor.GetGreen() << 12; 1426 *pTmp++ = (long) aColor.GetRed() << 12; 1427 } 1428 } 1429 } 1430 1431 // erstes Pixel gesondert betrachten 1432 nX = 0; 1433 CALC_ERRORS; 1434 CALC_TABLES7; 1435 nX -= 5; 1436 CALC_TABLES5; 1437 pWriteAcc->SetPixelIndex( nYAcc, 0, static_cast<sal_uInt8>(nVCLBLut[ nBC ] + nVCLGLut[nGC ] + nVCLRLut[nRC ]) ); 1438 1439 // mittlere Pixel ueber Schleife 1440 long nXAcc; 1441 for ( nX = 3L, nXAcc = 1L; nX < nW2; nXAcc++ ) 1442 { 1443 CALC_ERRORS; 1444 CALC_TABLES7; 1445 nX -= 8; 1446 CALC_TABLES3; 1447 CALC_TABLES5; 1448 pWriteAcc->SetPixelIndex( nYAcc, nXAcc, static_cast<sal_uInt8>(nVCLBLut[ nBC ] + nVCLGLut[nGC ] + nVCLRLut[nRC ]) ); 1449 } 1450 1451 // letztes Pixel gesondert betrachten 1452 CALC_ERRORS; 1453 nX -= 5; 1454 CALC_TABLES3; 1455 CALC_TABLES5; 1456 pWriteAcc->SetPixelIndex( nYAcc, nWidth1, static_cast<sal_uInt8>(nVCLBLut[ nBC ] + nVCLGLut[nGC ] + nVCLRLut[nRC ]) ); 1457 } 1458 1459 delete[] p1; 1460 delete[] p2; 1461 bRet = sal_True; 1462 } 1463 1464 ReleaseAccess( pReadAcc ); 1465 aNewBmp.ReleaseAccess( pWriteAcc ); 1466 1467 if( bRet ) 1468 { 1469 const MapMode aMap( maPrefMapMode ); 1470 const Size aPrefSize( maPrefSize ); 1471 1472 *this = aNewBmp; 1473 1474 maPrefMapMode = aMap; 1475 maPrefSize = aPrefSize; 1476 } 1477 } 1478 1479 return bRet; 1480 } 1481 1482 // ------------------------------------------------------------------------ 1483 1484 sal_Bool Bitmap::ImplDitherFloyd16() 1485 { 1486 BitmapReadAccess* pReadAcc = AcquireReadAccess(); 1487 Bitmap aNewBmp( GetSizePixel(), 24 ); 1488 BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess(); 1489 sal_Bool bRet = sal_False; 1490 1491 if( pReadAcc && pWriteAcc ) 1492 { 1493 const long nWidth = pWriteAcc->Width(); 1494 const long nWidth1 = nWidth - 1L; 1495 const long nHeight = pWriteAcc->Height(); 1496 BitmapColor aColor; 1497 BitmapColor aBestCol; 1498 ImpErrorQuad aErrQuad; 1499 ImpErrorQuad* pErrQuad1 = new ImpErrorQuad[ nWidth ]; 1500 ImpErrorQuad* pErrQuad2 = new ImpErrorQuad[ nWidth ]; 1501 ImpErrorQuad* pQLine1 = pErrQuad1; 1502 ImpErrorQuad* pQLine2 = 0; 1503 long nX, nY; 1504 long nYTmp = 0L; 1505 sal_Bool bQ1 = sal_True; 1506 1507 for( nY = 0L; nY < Min( nHeight, 2L ); nY++, nYTmp++ ) 1508 for( nX = 0L, pQLine2 = !nY ? pErrQuad1 : pErrQuad2; nX < nWidth; nX++ ) 1509 pQLine2[ nX ] = pReadAcc->GetPixel( nYTmp, nX ); 1510 1511 for( nY = 0L; nY < nHeight; nY++, nYTmp++ ) 1512 { 1513 // erstes ZeilenPixel 1514 aBestCol = pQLine1[ 0 ].ImplGetColor(); 1515 aBestCol.SetRed( ( aBestCol.GetRed() & 248 ) | 7 ); 1516 aBestCol.SetGreen( ( aBestCol.GetGreen() & 248 ) | 7 ); 1517 aBestCol.SetBlue( ( aBestCol.GetBlue() & 248 ) | 7 ); 1518 pWriteAcc->SetPixel( nY, 0, aBestCol ); 1519 1520 for( nX = 1L; nX < nWidth1; nX++ ) 1521 { 1522 aColor = pQLine1[ nX ].ImplGetColor(); 1523 aBestCol.SetRed( ( aColor.GetRed() & 248 ) | 7 ); 1524 aBestCol.SetGreen( ( aColor.GetGreen() & 248 ) | 7 ); 1525 aBestCol.SetBlue( ( aColor.GetBlue() & 248 ) | 7 ); 1526 aErrQuad = ( ImpErrorQuad( aColor ) -= aBestCol ); 1527 pQLine1[ ++nX ].ImplAddColorError7( aErrQuad ); 1528 pQLine2[ nX-- ].ImplAddColorError1( aErrQuad ); 1529 pQLine2[ nX-- ].ImplAddColorError5( aErrQuad ); 1530 pQLine2[ nX++ ].ImplAddColorError3( aErrQuad ); 1531 pWriteAcc->SetPixel( nY, nX, aBestCol ); 1532 } 1533 1534 // letztes ZeilenPixel 1535 aBestCol = pQLine1[ nWidth1 ].ImplGetColor(); 1536 aBestCol.SetRed( ( aBestCol.GetRed() & 248 ) | 7 ); 1537 aBestCol.SetGreen( ( aBestCol.GetGreen() & 248 ) | 7 ); 1538 aBestCol.SetBlue( ( aBestCol.GetBlue() & 248 ) | 7 ); 1539 pWriteAcc->SetPixel( nY, nX, aBestCol ); 1540 1541 // Zeilenpuffer neu fuellen/kopieren 1542 pQLine1 = pQLine2; 1543 pQLine2 = ( bQ1 = !bQ1 ) != sal_False ? pErrQuad2 : pErrQuad1; 1544 1545 if( nYTmp < nHeight ) 1546 for( nX = 0L; nX < nWidth; nX++ ) 1547 pQLine2[ nX ] = pReadAcc->GetPixel( nYTmp, nX ); 1548 } 1549 1550 // Zeilenpuffer zerstoeren 1551 delete[] pErrQuad1; 1552 delete[] pErrQuad2; 1553 bRet = sal_True; 1554 } 1555 1556 ReleaseAccess( pReadAcc ); 1557 aNewBmp.ReleaseAccess( pWriteAcc ); 1558 1559 if( bRet ) 1560 { 1561 const MapMode aMap( maPrefMapMode ); 1562 const Size aSize( maPrefSize ); 1563 1564 *this = aNewBmp; 1565 1566 maPrefMapMode = aMap; 1567 maPrefSize = aSize; 1568 } 1569 1570 return bRet; 1571 } 1572 1573 // ------------------------------------------------------------------------ 1574 1575 sal_Bool Bitmap::ReduceColors( sal_uInt16 nColorCount, BmpReduce eReduce ) 1576 { 1577 sal_Bool bRet; 1578 1579 if( GetColorCount() <= (sal_uLong) nColorCount ) 1580 bRet = sal_True; 1581 else if( nColorCount ) 1582 { 1583 if( BMP_REDUCE_SIMPLE == eReduce ) 1584 bRet = ImplReduceSimple( nColorCount ); 1585 else if( BMP_REDUCE_POPULAR == eReduce ) 1586 bRet = ImplReducePopular( nColorCount ); 1587 else 1588 bRet = ImplReduceMedian( nColorCount ); 1589 } 1590 else 1591 bRet = sal_False; 1592 1593 return bRet; 1594 } 1595 1596 // ------------------------------------------------------------------------ 1597 1598 sal_Bool Bitmap::ImplReduceSimple( sal_uInt16 nColorCount ) 1599 { 1600 Bitmap aNewBmp; 1601 BitmapReadAccess* pRAcc = AcquireReadAccess(); 1602 const sal_uInt16 nColCount = Min( nColorCount, (sal_uInt16) 256 ); 1603 sal_uInt16 nBitCount; 1604 sal_Bool bRet = sal_False; 1605 1606 if( nColCount <= 2 ) 1607 nBitCount = 1; 1608 else if( nColCount <= 16 ) 1609 nBitCount = 4; 1610 else 1611 nBitCount = 8; 1612 1613 if( pRAcc ) 1614 { 1615 Octree aOct( *pRAcc, nColCount ); 1616 const BitmapPalette& rPal = aOct.GetPalette(); 1617 BitmapWriteAccess* pWAcc; 1618 1619 aNewBmp = Bitmap( GetSizePixel(), nBitCount, &rPal ); 1620 pWAcc = aNewBmp.AcquireWriteAccess(); 1621 1622 if( pWAcc ) 1623 { 1624 const long nWidth = pRAcc->Width(); 1625 const long nHeight = pRAcc->Height(); 1626 1627 if( pRAcc->HasPalette() ) 1628 { 1629 for( long nY = 0L; nY < nHeight; nY++ ) 1630 for( long nX =0L; nX < nWidth; nX++ ) 1631 pWAcc->SetPixelIndex( nY, nX, static_cast<sal_uInt8>(aOct.GetBestPaletteIndex( pRAcc->GetPaletteColor( pRAcc->GetPixelIndex( nY, nX ) ))) ); 1632 } 1633 else 1634 { 1635 for( long nY = 0L; nY < nHeight; nY++ ) 1636 for( long nX =0L; nX < nWidth; nX++ ) 1637 pWAcc->SetPixelIndex( nY, nX, static_cast<sal_uInt8>(aOct.GetBestPaletteIndex( pRAcc->GetPixel( nY, nX ) )) ); 1638 } 1639 1640 aNewBmp.ReleaseAccess( pWAcc ); 1641 bRet = sal_True; 1642 } 1643 1644 ReleaseAccess( pRAcc ); 1645 } 1646 1647 if( bRet ) 1648 { 1649 const MapMode aMap( maPrefMapMode ); 1650 const Size aSize( maPrefSize ); 1651 1652 *this = aNewBmp; 1653 maPrefMapMode = aMap; 1654 maPrefSize = aSize; 1655 } 1656 1657 return bRet; 1658 } 1659 1660 // ------------------------------------------------------------------------ 1661 1662 struct PopularColorCount 1663 { 1664 sal_uInt32 mnIndex; 1665 sal_uInt32 mnCount; 1666 }; 1667 1668 // ------------------------------------------------------------------------ 1669 1670 extern "C" int __LOADONCALLAPI ImplPopularCmpFnc( const void* p1, const void* p2 ) 1671 { 1672 int nRet; 1673 1674 if( ( (PopularColorCount*) p1 )->mnCount < ( (PopularColorCount*) p2 )->mnCount ) 1675 nRet = 1; 1676 else if( ( (PopularColorCount*) p1 )->mnCount == ( (PopularColorCount*) p2 )->mnCount ) 1677 nRet = 0; 1678 else 1679 nRet = -1; 1680 1681 return nRet; 1682 } 1683 1684 // ------------------------------------------------------------------------ 1685 1686 sal_Bool Bitmap::ImplReducePopular( sal_uInt16 nColCount ) 1687 { 1688 BitmapReadAccess* pRAcc = AcquireReadAccess(); 1689 sal_uInt16 nBitCount; 1690 sal_Bool bRet = sal_False; 1691 1692 if( nColCount > 256 ) 1693 nColCount = 256; 1694 1695 if( nColCount < 17 ) 1696 nBitCount = 4; 1697 else 1698 nBitCount = 8; 1699 1700 if( pRAcc ) 1701 { 1702 const sal_uInt32 nValidBits = 4; 1703 const sal_uInt32 nRightShiftBits = 8 - nValidBits; 1704 const sal_uInt32 nLeftShiftBits1 = nValidBits; 1705 const sal_uInt32 nLeftShiftBits2 = nValidBits << 1; 1706 const sal_uInt32 nColorsPerComponent = 1 << nValidBits; 1707 const sal_uInt32 nColorOffset = 256 / nColorsPerComponent; 1708 const sal_uInt32 nTotalColors = nColorsPerComponent * nColorsPerComponent * nColorsPerComponent; 1709 const long nWidth = pRAcc->Width(); 1710 const long nHeight = pRAcc->Height(); 1711 PopularColorCount* pCountTable = new PopularColorCount[ nTotalColors ]; 1712 long nX, nY, nR, nG, nB, nIndex; 1713 1714 rtl_zeroMemory( pCountTable, nTotalColors * sizeof( PopularColorCount ) ); 1715 1716 for( nR = 0, nIndex = 0; nR < 256; nR += nColorOffset ) 1717 { 1718 for( nG = 0; nG < 256; nG += nColorOffset ) 1719 { 1720 for( nB = 0; nB < 256; nB += nColorOffset ) 1721 { 1722 pCountTable[ nIndex ].mnIndex = nIndex; 1723 nIndex++; 1724 } 1725 } 1726 } 1727 1728 if( pRAcc->HasPalette() ) 1729 { 1730 for( nY = 0L; nY < nHeight; nY++ ) 1731 { 1732 for( nX = 0L; nX < nWidth; nX++ ) 1733 { 1734 const BitmapColor& rCol = pRAcc->GetPaletteColor( pRAcc->GetPixelIndex( nY, nX ) ); 1735 pCountTable[ ( ( ( (sal_uInt32) rCol.GetRed() ) >> nRightShiftBits ) << nLeftShiftBits2 ) | 1736 ( ( ( (sal_uInt32) rCol.GetGreen() ) >> nRightShiftBits ) << nLeftShiftBits1 ) | 1737 ( ( (sal_uInt32) rCol.GetBlue() ) >> nRightShiftBits ) ].mnCount++; 1738 } 1739 } 1740 } 1741 else 1742 { 1743 for( nY = 0L; nY < nHeight; nY++ ) 1744 { 1745 for( nX = 0L; nX < nWidth; nX++ ) 1746 { 1747 const BitmapColor aCol( pRAcc->GetPixel( nY, nX ) ); 1748 pCountTable[ ( ( ( (sal_uInt32) aCol.GetRed() ) >> nRightShiftBits ) << nLeftShiftBits2 ) | 1749 ( ( ( (sal_uInt32) aCol.GetGreen() ) >> nRightShiftBits ) << nLeftShiftBits1 ) | 1750 ( ( (sal_uInt32) aCol.GetBlue() ) >> nRightShiftBits ) ].mnCount++; 1751 } 1752 } 1753 } 1754 1755 BitmapPalette aNewPal( nColCount ); 1756 1757 qsort( pCountTable, nTotalColors, sizeof( PopularColorCount ), ImplPopularCmpFnc ); 1758 1759 for( sal_uInt16 n = 0; n < nColCount; n++ ) 1760 { 1761 const PopularColorCount& rPop = pCountTable[ n ]; 1762 aNewPal[ n ] = BitmapColor( (sal_uInt8) ( ( rPop.mnIndex >> nLeftShiftBits2 ) << nRightShiftBits ), 1763 (sal_uInt8) ( ( ( rPop.mnIndex >> nLeftShiftBits1 ) & ( nColorsPerComponent - 1 ) ) << nRightShiftBits ), 1764 (sal_uInt8) ( ( rPop.mnIndex & ( nColorsPerComponent - 1 ) ) << nRightShiftBits ) ); 1765 } 1766 1767 Bitmap aNewBmp( GetSizePixel(), nBitCount, &aNewPal ); 1768 BitmapWriteAccess* pWAcc = aNewBmp.AcquireWriteAccess(); 1769 1770 if( pWAcc ) 1771 { 1772 BitmapColor aDstCol( (sal_uInt8) 0 ); 1773 sal_uInt8* pIndexMap = new sal_uInt8[ nTotalColors ]; 1774 1775 for( nR = 0, nIndex = 0; nR < 256; nR += nColorOffset ) 1776 for( nG = 0; nG < 256; nG += nColorOffset ) 1777 for( nB = 0; nB < 256; nB += nColorOffset ) 1778 pIndexMap[ nIndex++ ] = (sal_uInt8) aNewPal.GetBestIndex( BitmapColor( (sal_uInt8) nR, (sal_uInt8) nG, (sal_uInt8) nB ) ); 1779 1780 if( pRAcc->HasPalette() ) 1781 { 1782 for( nY = 0L; nY < nHeight; nY++ ) 1783 { 1784 for( nX = 0L; nX < nWidth; nX++ ) 1785 { 1786 const BitmapColor& rCol = pRAcc->GetPaletteColor( pRAcc->GetPixelIndex( nY, nX ) ); 1787 aDstCol.SetIndex( pIndexMap[ ( ( ( (sal_uInt32) rCol.GetRed() ) >> nRightShiftBits ) << nLeftShiftBits2 ) | 1788 ( ( ( (sal_uInt32) rCol.GetGreen() ) >> nRightShiftBits ) << nLeftShiftBits1 ) | 1789 ( ( (sal_uInt32) rCol.GetBlue() ) >> nRightShiftBits ) ] ); 1790 pWAcc->SetPixel( nY, nX, aDstCol ); 1791 } 1792 } 1793 } 1794 else 1795 { 1796 for( nY = 0L; nY < nHeight; nY++ ) 1797 { 1798 for( nX = 0L; nX < nWidth; nX++ ) 1799 { 1800 const BitmapColor aCol( pRAcc->GetPixel( nY, nX ) ); 1801 aDstCol.SetIndex( pIndexMap[ ( ( ( (sal_uInt32) aCol.GetRed() ) >> nRightShiftBits ) << nLeftShiftBits2 ) | 1802 ( ( ( (sal_uInt32) aCol.GetGreen() ) >> nRightShiftBits ) << nLeftShiftBits1 ) | 1803 ( ( (sal_uInt32) aCol.GetBlue() ) >> nRightShiftBits ) ] ); 1804 pWAcc->SetPixel( nY, nX, aDstCol ); 1805 } 1806 } 1807 } 1808 1809 delete[] pIndexMap; 1810 aNewBmp.ReleaseAccess( pWAcc ); 1811 bRet = sal_True; 1812 } 1813 1814 delete[] pCountTable; 1815 ReleaseAccess( pRAcc ); 1816 1817 if( bRet ) 1818 { 1819 const MapMode aMap( maPrefMapMode ); 1820 const Size aSize( maPrefSize ); 1821 1822 *this = aNewBmp; 1823 maPrefMapMode = aMap; 1824 maPrefSize = aSize; 1825 } 1826 } 1827 1828 return bRet; 1829 } 1830 1831 // ------------------------------------------------------------------------ 1832 1833 sal_Bool Bitmap::ImplReduceMedian( sal_uInt16 nColCount ) 1834 { 1835 BitmapReadAccess* pRAcc = AcquireReadAccess(); 1836 sal_uInt16 nBitCount; 1837 sal_Bool bRet = sal_False; 1838 1839 if( nColCount < 17 ) 1840 nBitCount = 4; 1841 else if( nColCount < 257 ) 1842 nBitCount = 8; 1843 else 1844 { 1845 DBG_ERROR( "Bitmap::ImplReduceMedian(): invalid color count!" ); 1846 nBitCount = 8; 1847 nColCount = 256; 1848 } 1849 1850 if( pRAcc ) 1851 { 1852 Bitmap aNewBmp( GetSizePixel(), nBitCount ); 1853 BitmapWriteAccess* pWAcc = aNewBmp.AcquireWriteAccess(); 1854 1855 if( pWAcc ) 1856 { 1857 const sal_uLong nSize = 32768UL * sizeof( sal_uLong ); 1858 sal_uLong* pColBuf = (sal_uLong*) rtl_allocateMemory( nSize ); 1859 const long nWidth = pWAcc->Width(); 1860 const long nHeight = pWAcc->Height(); 1861 long nIndex = 0L; 1862 1863 memset( (HPBYTE) pColBuf, 0, nSize ); 1864 1865 // create Buffer 1866 if( pRAcc->HasPalette() ) 1867 { 1868 for( long nY = 0L; nY < nHeight; nY++ ) 1869 { 1870 for( long nX = 0L; nX < nWidth; nX++ ) 1871 { 1872 const BitmapColor& rCol = pRAcc->GetPaletteColor( pRAcc->GetPixelIndex( nY, nX ) ); 1873 pColBuf[ RGB15( rCol.GetRed() >> 3, rCol.GetGreen() >> 3, rCol.GetBlue() >> 3 ) ]++; 1874 } 1875 } 1876 } 1877 else 1878 { 1879 for( long nY = 0L; nY < nHeight; nY++ ) 1880 { 1881 for( long nX = 0L; nX < nWidth; nX++ ) 1882 { 1883 const BitmapColor aCol( pRAcc->GetPixel( nY, nX ) ); 1884 pColBuf[ RGB15( aCol.GetRed() >> 3, aCol.GetGreen() >> 3, aCol.GetBlue() >> 3 ) ]++; 1885 } 1886 } 1887 } 1888 1889 // create palette via median cut 1890 BitmapPalette aPal( pWAcc->GetPaletteEntryCount() ); 1891 ImplMedianCut( pColBuf, aPal, 0, 31, 0, 31, 0, 31, 1892 nColCount, nWidth * nHeight, nIndex ); 1893 1894 // do mapping of colors to palette 1895 InverseColorMap aMap( aPal ); 1896 pWAcc->SetPalette( aPal ); 1897 for( long nY = 0L; nY < nHeight; nY++ ) 1898 for( long nX = 0L; nX < nWidth; nX++ ) 1899 pWAcc->SetPixelIndex( nY, nX, static_cast<sal_uInt8>( aMap.GetBestPaletteIndex( pRAcc->GetColor( nY, nX ) )) ); 1900 1901 rtl_freeMemory( pColBuf ); 1902 aNewBmp.ReleaseAccess( pWAcc ); 1903 bRet = sal_True; 1904 } 1905 1906 ReleaseAccess( pRAcc ); 1907 1908 if( bRet ) 1909 { 1910 const MapMode aMap( maPrefMapMode ); 1911 const Size aSize( maPrefSize ); 1912 1913 *this = aNewBmp; 1914 maPrefMapMode = aMap; 1915 maPrefSize = aSize; 1916 } 1917 } 1918 1919 return bRet; 1920 } 1921 1922 // ------------------------------------------------------------------------ 1923 1924 void Bitmap::ImplMedianCut( sal_uLong* pColBuf, BitmapPalette& rPal, 1925 long nR1, long nR2, long nG1, long nG2, long nB1, long nB2, 1926 long nColors, long nPixels, long& rIndex ) 1927 { 1928 if( !nPixels ) 1929 return; 1930 1931 BitmapColor aCol; 1932 const long nRLen = nR2 - nR1; 1933 const long nGLen = nG2 - nG1; 1934 const long nBLen = nB2 - nB1; 1935 long nR, nG, nB; 1936 sal_uLong* pBuf = pColBuf; 1937 1938 if( !nRLen && !nGLen && !nBLen ) 1939 { 1940 if( pBuf[ RGB15( nR1, nG1, nB1 ) ] ) 1941 { 1942 aCol.SetRed( (sal_uInt8) ( nR1 << 3 ) ); 1943 aCol.SetGreen( (sal_uInt8) ( nG1 << 3 ) ); 1944 aCol.SetBlue( (sal_uInt8) ( nB1 << 3 ) ); 1945 rPal[ (sal_uInt16) rIndex++ ] = aCol; 1946 } 1947 } 1948 else 1949 { 1950 if( 1 == nColors || 1 == nPixels ) 1951 { 1952 long nPixSum = 0, nRSum = 0, nGSum = 0, nBSum = 0; 1953 1954 for( nR = nR1; nR <= nR2; nR++ ) 1955 { 1956 for( nG = nG1; nG <= nG2; nG++ ) 1957 { 1958 for( nB = nB1; nB <= nB2; nB++ ) 1959 { 1960 nPixSum = pBuf[ RGB15( nR, nG, nB ) ]; 1961 1962 if( nPixSum ) 1963 { 1964 nRSum += nR * nPixSum; 1965 nGSum += nG * nPixSum; 1966 nBSum += nB * nPixSum; 1967 } 1968 } 1969 } 1970 } 1971 1972 aCol.SetRed( (sal_uInt8) ( ( nRSum / nPixels ) << 3 ) ); 1973 aCol.SetGreen( (sal_uInt8) ( ( nGSum / nPixels ) << 3 ) ); 1974 aCol.SetBlue( (sal_uInt8) ( ( nBSum / nPixels ) << 3 ) ); 1975 rPal[ (sal_uInt16) rIndex++ ] = aCol; 1976 } 1977 else 1978 { 1979 const long nTest = ( nPixels >> 1 ); 1980 long nPixOld = 0; 1981 long nPixNew = 0; 1982 1983 if( nBLen > nGLen && nBLen > nRLen ) 1984 { 1985 nB = nB1 - 1; 1986 1987 while( nPixNew < nTest ) 1988 { 1989 nB++, nPixOld = nPixNew; 1990 for( nR = nR1; nR <= nR2; nR++ ) 1991 for( nG = nG1; nG <= nG2; nG++ ) 1992 nPixNew += pBuf[ RGB15( nR, nG, nB ) ]; 1993 } 1994 1995 if( nB < nB2 ) 1996 { 1997 ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG2, nB1, nB, nColors >> 1, nPixNew, rIndex ); 1998 ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG2, nB + 1, nB2, nColors >> 1, nPixels - nPixNew, rIndex ); 1999 } 2000 else 2001 { 2002 ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG2, nB1, nB - 1, nColors >> 1, nPixOld, rIndex ); 2003 ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG2, nB, nB2, nColors >> 1, nPixels - nPixOld, rIndex ); 2004 } 2005 } 2006 else if( nGLen > nRLen ) 2007 { 2008 nG = nG1 - 1; 2009 2010 while( nPixNew < nTest ) 2011 { 2012 nG++, nPixOld = nPixNew; 2013 for( nR = nR1; nR <= nR2; nR++ ) 2014 for( nB = nB1; nB <= nB2; nB++ ) 2015 nPixNew += pBuf[ RGB15( nR, nG, nB ) ]; 2016 } 2017 2018 if( nG < nG2 ) 2019 { 2020 ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG, nB1, nB2, nColors >> 1, nPixNew, rIndex ); 2021 ImplMedianCut( pBuf, rPal, nR1, nR2, nG + 1, nG2, nB1, nB2, nColors >> 1, nPixels - nPixNew, rIndex ); 2022 } 2023 else 2024 { 2025 ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG - 1, nB1, nB2, nColors >> 1, nPixOld, rIndex ); 2026 ImplMedianCut( pBuf, rPal, nR1, nR2, nG, nG2, nB1, nB2, nColors >> 1, nPixels - nPixOld, rIndex ); 2027 } 2028 } 2029 else 2030 { 2031 nR = nR1 - 1; 2032 2033 while( nPixNew < nTest ) 2034 { 2035 nR++, nPixOld = nPixNew; 2036 for( nG = nG1; nG <= nG2; nG++ ) 2037 for( nB = nB1; nB <= nB2; nB++ ) 2038 nPixNew += pBuf[ RGB15( nR, nG, nB ) ]; 2039 } 2040 2041 if( nR < nR2 ) 2042 { 2043 ImplMedianCut( pBuf, rPal, nR1, nR, nG1, nG2, nB1, nB2, nColors >> 1, nPixNew, rIndex ); 2044 ImplMedianCut( pBuf, rPal, nR1 + 1, nR2, nG1, nG2, nB1, nB2, nColors >> 1, nPixels - nPixNew, rIndex ); 2045 } 2046 else 2047 { 2048 ImplMedianCut( pBuf, rPal, nR1, nR - 1, nG1, nG2, nB1, nB2, nColors >> 1, nPixOld, rIndex ); 2049 ImplMedianCut( pBuf, rPal, nR, nR2, nG1, nG2, nB1, nB2, nColors >> 1, nPixels - nPixOld, rIndex ); 2050 } 2051 } 2052 } 2053 } 2054 } 2055 2056 // ------------------------------------------------------------------------ 2057 2058 sal_Bool Bitmap::Vectorize( PolyPolygon& rPolyPoly, sal_uLong nFlags, const Link* pProgress ) 2059 { 2060 return ImplVectorizer().ImplVectorize( *this, rPolyPoly, nFlags, pProgress ); 2061 } 2062 2063 // ------------------------------------------------------------------------ 2064 2065 sal_Bool Bitmap::Vectorize( GDIMetaFile& rMtf, sal_uInt8 cReduce, sal_uLong nFlags, const Link* pProgress ) 2066 { 2067 return ImplVectorizer().ImplVectorize( *this, rMtf, cReduce, nFlags, pProgress ); 2068 } 2069 2070 // ------------------------------------------------------------------------ 2071 2072 sal_Bool Bitmap::Adjust( short nLuminancePercent, short nContrastPercent, 2073 short nChannelRPercent, short nChannelGPercent, short nChannelBPercent, 2074 double fGamma, sal_Bool bInvert ) 2075 { 2076 sal_Bool bRet = sal_False; 2077 2078 // nothing to do => return quickly 2079 if( !nLuminancePercent && !nContrastPercent && 2080 !nChannelRPercent && !nChannelGPercent && !nChannelBPercent && 2081 ( fGamma == 1.0 ) && !bInvert ) 2082 { 2083 bRet = sal_True; 2084 } 2085 else 2086 { 2087 BitmapWriteAccess* pAcc = AcquireWriteAccess(); 2088 2089 if( pAcc ) 2090 { 2091 BitmapColor aCol; 2092 const long nW = pAcc->Width(); 2093 const long nH = pAcc->Height(); 2094 sal_uInt8* cMapR = new sal_uInt8[ 256 ]; 2095 sal_uInt8* cMapG = new sal_uInt8[ 256 ]; 2096 sal_uInt8* cMapB = new sal_uInt8[ 256 ]; 2097 long nX, nY; 2098 double fM, fROff, fGOff, fBOff, fOff; 2099 2100 // calculate slope 2101 if( nContrastPercent >= 0 ) 2102 fM = 128.0 / ( 128.0 - 1.27 * MinMax( nContrastPercent, 0L, 100L ) ); 2103 else 2104 fM = ( 128.0 + 1.27 * MinMax( nContrastPercent, -100L, 0L ) ) / 128.0; 2105 2106 // total offset = luminance offset + contrast offset 2107 fOff = MinMax( nLuminancePercent, -100L, 100L ) * 2.55 + 128.0 - fM * 128.0; 2108 2109 // channel offset = channel offset + total offset 2110 fROff = nChannelRPercent * 2.55 + fOff; 2111 fGOff = nChannelGPercent * 2.55 + fOff; 2112 fBOff = nChannelBPercent * 2.55 + fOff; 2113 2114 // calculate gamma value 2115 fGamma = ( fGamma <= 0.0 || fGamma > 10.0 ) ? 1.0 : ( 1.0 / fGamma ); 2116 const sal_Bool bGamma = ( fGamma != 1.0 ); 2117 2118 // create mapping table 2119 for( nX = 0L; nX < 256L; nX++ ) 2120 { 2121 cMapR[ nX ] = (sal_uInt8) MinMax( FRound( nX * fM + fROff ), 0L, 255L ); 2122 cMapG[ nX ] = (sal_uInt8) MinMax( FRound( nX * fM + fGOff ), 0L, 255L ); 2123 cMapB[ nX ] = (sal_uInt8) MinMax( FRound( nX * fM + fBOff ), 0L, 255L ); 2124 2125 if( bGamma ) 2126 { 2127 cMapR[ nX ] = GAMMA( cMapR[ nX ], fGamma ); 2128 cMapG[ nX ] = GAMMA( cMapG[ nX ], fGamma ); 2129 cMapB[ nX ] = GAMMA( cMapB[ nX ], fGamma ); 2130 } 2131 2132 if( bInvert ) 2133 { 2134 cMapR[ nX ] = ~cMapR[ nX ]; 2135 cMapG[ nX ] = ~cMapG[ nX ]; 2136 cMapB[ nX ] = ~cMapB[ nX ]; 2137 } 2138 } 2139 2140 // do modifying 2141 if( pAcc->HasPalette() ) 2142 { 2143 BitmapColor aNewCol; 2144 2145 for( sal_uInt16 i = 0, nCount = pAcc->GetPaletteEntryCount(); i < nCount; i++ ) 2146 { 2147 const BitmapColor& rCol = pAcc->GetPaletteColor( i ); 2148 aNewCol.SetRed( cMapR[ rCol.GetRed() ] ); 2149 aNewCol.SetGreen( cMapG[ rCol.GetGreen() ] ); 2150 aNewCol.SetBlue( cMapB[ rCol.GetBlue() ] ); 2151 pAcc->SetPaletteColor( i, aNewCol ); 2152 } 2153 } 2154 else if( pAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_BGR ) 2155 { 2156 for( nY = 0L; nY < nH; nY++ ) 2157 { 2158 Scanline pScan = pAcc->GetScanline( nY ); 2159 2160 for( nX = 0L; nX < nW; nX++ ) 2161 { 2162 *pScan = cMapB[ *pScan ]; pScan++; 2163 *pScan = cMapG[ *pScan ]; pScan++; 2164 *pScan = cMapR[ *pScan ]; pScan++; 2165 } 2166 } 2167 } 2168 else if( pAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_RGB ) 2169 { 2170 for( nY = 0L; nY < nH; nY++ ) 2171 { 2172 Scanline pScan = pAcc->GetScanline( nY ); 2173 2174 for( nX = 0L; nX < nW; nX++ ) 2175 { 2176 *pScan = cMapR[ *pScan ]; pScan++; 2177 *pScan = cMapG[ *pScan ]; pScan++; 2178 *pScan = cMapB[ *pScan ]; pScan++; 2179 } 2180 } 2181 } 2182 else 2183 { 2184 for( nY = 0L; nY < nH; nY++ ) 2185 { 2186 for( nX = 0L; nX < nW; nX++ ) 2187 { 2188 aCol = pAcc->GetPixel( nY, nX ); 2189 aCol.SetRed( cMapR[ aCol.GetRed() ] ); 2190 aCol.SetGreen( cMapG[ aCol.GetGreen() ] ); 2191 aCol.SetBlue( cMapB[ aCol.GetBlue() ] ); 2192 pAcc->SetPixel( nY, nX, aCol ); 2193 } 2194 } 2195 } 2196 2197 delete[] cMapR; 2198 delete[] cMapG; 2199 delete[] cMapB; 2200 ReleaseAccess( pAcc ); 2201 bRet = sal_True; 2202 } 2203 } 2204 2205 return bRet; 2206 } 2207