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 if( pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nY, nX ) ).GetLuminance() >= 387 cThreshold ) 388 { 389 pWriteAcc->SetPixel( nY, nX, aWhite ); 390 } 391 else 392 pWriteAcc->SetPixel( nY, nX, aBlack ); 393 } 394 } 395 } 396 else 397 { 398 for( long nY = 0L; nY < nHeight; nY++ ) 399 { 400 for( long nX = 0L; nX < nWidth; nX++ ) 401 { 402 if( pReadAcc->GetPixel( nY, nX ).GetLuminance() >= 403 cThreshold ) 404 { 405 pWriteAcc->SetPixel( nY, nX, aWhite ); 406 } 407 else 408 pWriteAcc->SetPixel( nY, nX, aBlack ); 409 } 410 } 411 } 412 413 aNewBmp.ReleaseAccess( pWriteAcc ); 414 bRet = sal_True; 415 } 416 417 ReleaseAccess( pReadAcc ); 418 419 if( bRet ) 420 { 421 const MapMode aMap( maPrefMapMode ); 422 const Size aSize( maPrefSize ); 423 424 *this = aNewBmp; 425 426 maPrefMapMode = aMap; 427 maPrefSize = aSize; 428 } 429 } 430 431 return bRet; 432 } 433 434 // ------------------------------------------------------------------------ 435 436 sal_Bool Bitmap::ImplMakeMonoDither() 437 { 438 BitmapReadAccess* pReadAcc = AcquireReadAccess(); 439 sal_Bool bRet = sal_False; 440 441 if( pReadAcc ) 442 { 443 Bitmap aNewBmp( GetSizePixel(), 1 ); 444 BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess(); 445 446 if( pWriteAcc ) 447 { 448 const BitmapColor aBlack( pWriteAcc->GetBestMatchingColor( Color( COL_BLACK ) ) ); 449 const BitmapColor aWhite( pWriteAcc->GetBestMatchingColor( Color( COL_WHITE ) ) ); 450 const long nWidth = pWriteAcc->Width(); 451 const long nHeight = pWriteAcc->Height(); 452 sal_uInt8 pDitherMatrix[ 16 ][ 16 ]; 453 454 ImplCreateDitherMatrix( &pDitherMatrix ); 455 456 if( pReadAcc->HasPalette() ) 457 { 458 for( long nY = 0L; nY < nHeight; nY++ ) 459 { 460 for( long nX = 0L, nModY = nY % 16; nX < nWidth; nX++ ) 461 { 462 if( pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nY, nX ) ).GetLuminance() > 463 pDitherMatrix[ nModY ][ nX % 16 ] ) 464 { 465 pWriteAcc->SetPixel( nY, nX, aWhite ); 466 } 467 else 468 pWriteAcc->SetPixel( nY, nX, aBlack ); 469 } 470 } 471 } 472 else 473 { 474 for( long nY = 0L; nY < nHeight; nY++ ) 475 { 476 for( long nX = 0L, nModY = nY % 16; nX < nWidth; nX++ ) 477 { 478 if( pReadAcc->GetPixel( nY, nX ).GetLuminance() > 479 pDitherMatrix[ nModY ][ nX % 16 ] ) 480 { 481 pWriteAcc->SetPixel( nY, nX, aWhite ); 482 } 483 else 484 pWriteAcc->SetPixel( nY, nX, aBlack ); 485 } 486 } 487 } 488 489 aNewBmp.ReleaseAccess( pWriteAcc ); 490 bRet = sal_True; 491 } 492 493 ReleaseAccess( pReadAcc ); 494 495 if( bRet ) 496 { 497 const MapMode aMap( maPrefMapMode ); 498 const Size aSize( maPrefSize ); 499 500 *this = aNewBmp; 501 502 maPrefMapMode = aMap; 503 maPrefSize = aSize; 504 } 505 } 506 507 return bRet; 508 } 509 510 // ------------------------------------------------------------------------ 511 512 sal_Bool Bitmap::ImplMakeGreyscales( sal_uInt16 nGreys ) 513 { 514 DBG_ASSERT( nGreys == 16 || nGreys == 256, "Only 16 or 256 greyscales are supported!" ); 515 516 BitmapReadAccess* pReadAcc = AcquireReadAccess(); 517 sal_Bool bRet = sal_False; 518 519 if( pReadAcc ) 520 { 521 const BitmapPalette& rPal = GetGreyPalette( nGreys ); 522 sal_uLong nShift = ( ( nGreys == 16 ) ? 4UL : 0UL ); 523 sal_Bool bPalDiffers = !pReadAcc->HasPalette() || ( rPal.GetEntryCount() != pReadAcc->GetPaletteEntryCount() ); 524 525 if( !bPalDiffers ) 526 bPalDiffers = ( (BitmapPalette&) rPal != pReadAcc->GetPalette() ); 527 528 if( bPalDiffers ) 529 { 530 Bitmap aNewBmp( GetSizePixel(), ( nGreys == 16 ) ? 4 : 8, &rPal ); 531 BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess(); 532 533 if( pWriteAcc ) 534 { 535 const long nWidth = pWriteAcc->Width(); 536 const long nHeight = pWriteAcc->Height(); 537 538 if( pReadAcc->HasPalette() ) 539 { 540 for( long nY = 0L; nY < nHeight; nY++ ) 541 { 542 for( long nX = 0L; nX < nWidth; nX++ ) 543 { 544 pWriteAcc->SetPixel( nY, nX, 545 (sal_uInt8) ( pReadAcc->GetPaletteColor( 546 pReadAcc->GetPixel( nY, nX ) ).GetLuminance() >> nShift ) ); 547 } 548 } 549 } 550 else if( pReadAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_BGR && 551 pWriteAcc->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL ) 552 { 553 nShift += 8; 554 555 for( long nY = 0L; nY < nHeight; nY++ ) 556 { 557 Scanline pReadScan = pReadAcc->GetScanline( nY ); 558 Scanline pWriteScan = pWriteAcc->GetScanline( nY ); 559 560 for( long nX = 0L; nX < nWidth; nX++ ) 561 { 562 const sal_uLong nB = *pReadScan++; 563 const sal_uLong nG = *pReadScan++; 564 const sal_uLong nR = *pReadScan++; 565 566 *pWriteScan++ = (sal_uInt8) ( ( nB * 28UL + nG * 151UL + nR * 77UL ) >> nShift ); 567 } 568 } 569 } 570 else if( pReadAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_RGB && 571 pWriteAcc->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL ) 572 { 573 nShift += 8; 574 575 for( long nY = 0L; nY < nHeight; nY++ ) 576 { 577 Scanline pReadScan = pReadAcc->GetScanline( nY ); 578 Scanline pWriteScan = pWriteAcc->GetScanline( nY ); 579 580 for( long nX = 0L; nX < nWidth; nX++ ) 581 { 582 const sal_uLong nR = *pReadScan++; 583 const sal_uLong nG = *pReadScan++; 584 const sal_uLong nB = *pReadScan++; 585 586 *pWriteScan++ = (sal_uInt8) ( ( nB * 28UL + nG * 151UL + nR * 77UL ) >> nShift ); 587 } 588 } 589 } 590 else 591 { 592 for( long nY = 0L; nY < nHeight; nY++ ) 593 for( long nX = 0L; nX < nWidth; nX++ ) 594 pWriteAcc->SetPixel( nY, nX, sal::static_int_cast<sal_uInt8>(( pReadAcc->GetPixel( nY, nX ) ).GetLuminance() >> nShift) ); 595 } 596 597 aNewBmp.ReleaseAccess( pWriteAcc ); 598 bRet = sal_True; 599 } 600 601 ReleaseAccess( pReadAcc ); 602 603 if( bRet ) 604 { 605 const MapMode aMap( maPrefMapMode ); 606 const Size aSize( maPrefSize ); 607 608 *this = aNewBmp; 609 610 maPrefMapMode = aMap; 611 maPrefSize = aSize; 612 } 613 } 614 else 615 { 616 ReleaseAccess( pReadAcc ); 617 bRet = sal_True; 618 } 619 } 620 621 return bRet; 622 } 623 624 // ------------------------------------------------------------------------ 625 626 sal_Bool Bitmap::ImplConvertUp( sal_uInt16 nBitCount, Color* pExtColor ) 627 { 628 DBG_ASSERT( nBitCount > GetBitCount(), "New BitCount must be greater!" ); 629 630 BitmapReadAccess* pReadAcc = AcquireReadAccess(); 631 sal_Bool bRet = sal_False; 632 633 if( pReadAcc ) 634 { 635 BitmapPalette aPal; 636 Bitmap aNewBmp( GetSizePixel(), nBitCount, pReadAcc->HasPalette() ? &pReadAcc->GetPalette() : &aPal ); 637 BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess(); 638 639 if( pWriteAcc ) 640 { 641 const long nWidth = pWriteAcc->Width(); 642 const long nHeight = pWriteAcc->Height(); 643 644 if( pWriteAcc->HasPalette() ) 645 { 646 const sal_uInt16 nOldCount = 1 << GetBitCount(); 647 const BitmapPalette& rOldPal = pReadAcc->GetPalette(); 648 649 aPal.SetEntryCount( 1 << nBitCount ); 650 651 for( sal_uInt16 i = 0; i < nOldCount; i++ ) 652 aPal[ i ] = rOldPal[ i ]; 653 654 if( pExtColor ) 655 aPal[ aPal.GetEntryCount() - 1 ] = *pExtColor; 656 657 pWriteAcc->SetPalette( aPal ); 658 659 for( long nY = 0L; nY < nHeight; nY++ ) 660 for( long nX = 0L; nX < nWidth; nX++ ) 661 pWriteAcc->SetPixel( nY, nX, pReadAcc->GetPixel( nY, nX ) ); 662 } 663 else 664 { 665 if( pReadAcc->HasPalette() ) 666 { 667 for( long nY = 0L; nY < nHeight; nY++ ) 668 for( long nX = 0L; nX < nWidth; nX++ ) 669 pWriteAcc->SetPixel( nY, nX, pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nY, nX ) ) ); 670 } 671 else 672 { 673 for( long nY = 0L; nY < nHeight; nY++ ) 674 for( long nX = 0L; nX < nWidth; nX++ ) 675 pWriteAcc->SetPixel( nY, nX, pReadAcc->GetPixel( nY, nX ) ); 676 } 677 } 678 679 aNewBmp.ReleaseAccess( pWriteAcc ); 680 bRet = sal_True; 681 } 682 683 ReleaseAccess( pReadAcc ); 684 685 if( bRet ) 686 { 687 const MapMode aMap( maPrefMapMode ); 688 const Size aSize( maPrefSize ); 689 690 *this = aNewBmp; 691 692 maPrefMapMode = aMap; 693 maPrefSize = aSize; 694 } 695 } 696 697 return bRet; 698 } 699 700 // ------------------------------------------------------------------------ 701 702 sal_Bool Bitmap::ImplConvertDown( sal_uInt16 nBitCount, Color* pExtColor ) 703 { 704 DBG_ASSERT( nBitCount <= GetBitCount(), "New BitCount must be lower ( or equal when pExtColor is set )!" ); 705 706 BitmapReadAccess* pReadAcc = AcquireReadAccess(); 707 sal_Bool bRet = sal_False; 708 709 if( pReadAcc ) 710 { 711 BitmapPalette aPal; 712 Bitmap aNewBmp( GetSizePixel(), nBitCount, &aPal ); 713 BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess(); 714 715 if( pWriteAcc ) 716 { 717 const sal_uInt16 nCount = 1 << nBitCount; 718 const long nWidth = pWriteAcc->Width(); 719 const long nWidth1 = nWidth - 1L; 720 const long nHeight = pWriteAcc->Height(); 721 Octree aOctree( *pReadAcc, pExtColor ? ( nCount - 1 ) : nCount ); 722 InverseColorMap aColorMap( aPal = aOctree.GetPalette() ); 723 BitmapColor aColor; 724 ImpErrorQuad aErrQuad; 725 ImpErrorQuad* pErrQuad1 = new ImpErrorQuad[ nWidth ]; 726 ImpErrorQuad* pErrQuad2 = new ImpErrorQuad[ nWidth ]; 727 ImpErrorQuad* pQLine1 = pErrQuad1; 728 ImpErrorQuad* pQLine2 = 0; 729 long nX, nY; 730 long nYTmp = 0L; 731 sal_uInt8 cIndex; 732 sal_Bool bQ1 = sal_True; 733 734 if( pExtColor ) 735 { 736 aPal.SetEntryCount( aPal.GetEntryCount() + 1 ); 737 aPal[ aPal.GetEntryCount() - 1 ] = *pExtColor; 738 } 739 740 // set Black/White always, if we have enough space 741 if( aPal.GetEntryCount() < ( nCount - 1 ) ) 742 { 743 aPal.SetEntryCount( aPal.GetEntryCount() + 2 ); 744 aPal[ aPal.GetEntryCount() - 2 ] = Color( COL_BLACK ); 745 aPal[ aPal.GetEntryCount() - 1 ] = Color( COL_WHITE ); 746 } 747 748 pWriteAcc->SetPalette( aPal ); 749 750 for( nY = 0L; nY < Min( nHeight, 2L ); nY++, nYTmp++ ) 751 { 752 for( nX = 0L, pQLine2 = !nY ? pErrQuad1 : pErrQuad2; nX < nWidth; nX++ ) 753 { 754 if( pReadAcc->HasPalette() ) 755 pQLine2[ nX ] = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nYTmp, nX ) ); 756 else 757 pQLine2[ nX ] = pReadAcc->GetPixel( nYTmp, nX ); 758 } 759 } 760 761 for( nY = 0L; nY < nHeight; nY++, nYTmp++ ) 762 { 763 // erstes ZeilenPixel 764 cIndex = (sal_uInt8) aColorMap.GetBestPaletteIndex( pQLine1[ 0 ].ImplGetColor() ); 765 pWriteAcc->SetPixel( nY, 0, cIndex ); 766 767 for( nX = 1L; nX < nWidth1; nX++ ) 768 { 769 cIndex = (sal_uInt8) aColorMap.GetBestPaletteIndex( aColor = pQLine1[ nX ].ImplGetColor() ); 770 aErrQuad = ( ImpErrorQuad( aColor ) -= pWriteAcc->GetPaletteColor( cIndex ) ); 771 pQLine1[ ++nX ].ImplAddColorError7( aErrQuad ); 772 pQLine2[ nX-- ].ImplAddColorError1( aErrQuad ); 773 pQLine2[ nX-- ].ImplAddColorError5( aErrQuad ); 774 pQLine2[ nX++ ].ImplAddColorError3( aErrQuad ); 775 pWriteAcc->SetPixel( nY, nX, cIndex ); 776 } 777 778 // letztes ZeilenPixel 779 if( nX < nWidth ) 780 { 781 cIndex = (sal_uInt8) aColorMap.GetBestPaletteIndex( pQLine1[ nWidth1 ].ImplGetColor() ); 782 pWriteAcc->SetPixel( nY, nX, cIndex ); 783 } 784 785 // Zeilenpuffer neu fuellen/kopieren 786 pQLine1 = pQLine2; 787 pQLine2 = ( bQ1 = !bQ1 ) != sal_False ? pErrQuad2 : pErrQuad1; 788 789 if( nYTmp < nHeight ) 790 { 791 for( nX = 0L; nX < nWidth; nX++ ) 792 { 793 if( pReadAcc->HasPalette() ) 794 pQLine2[ nX ] = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nYTmp, nX ) ); 795 else 796 pQLine2[ nX ] = pReadAcc->GetPixel( nYTmp, nX ); 797 } 798 } 799 } 800 801 // Zeilenpuffer zerstoeren 802 delete[] pErrQuad1; 803 delete[] pErrQuad2; 804 805 aNewBmp.ReleaseAccess( pWriteAcc ); 806 bRet = sal_True; 807 } 808 809 ReleaseAccess( pReadAcc ); 810 811 if( bRet ) 812 { 813 const MapMode aMap( maPrefMapMode ); 814 const Size aSize( maPrefSize ); 815 816 *this = aNewBmp; 817 818 maPrefMapMode = aMap; 819 maPrefSize = aSize; 820 } 821 } 822 823 return bRet; 824 } 825 826 // ------------------------------------------------------------------------ 827 828 sal_Bool Bitmap::ImplConvertGhosted() 829 { 830 Bitmap aNewBmp; 831 BitmapReadAccess* pR = AcquireReadAccess(); 832 sal_Bool bRet = sal_False; 833 834 if( pR ) 835 { 836 if( pR->HasPalette() ) 837 { 838 BitmapPalette aNewPal( pR->GetPaletteEntryCount() ); 839 840 for( long i = 0, nCount = aNewPal.GetEntryCount(); i < nCount; i++ ) 841 { 842 const BitmapColor& rOld = pR->GetPaletteColor( (sal_uInt16) i ); 843 aNewPal[ (sal_uInt16) i ] = BitmapColor( ( rOld.GetRed() >> 1 ) | 0x80, 844 ( rOld.GetGreen() >> 1 ) | 0x80, 845 ( rOld.GetBlue() >> 1 ) | 0x80 ); 846 } 847 848 aNewBmp = Bitmap( GetSizePixel(), GetBitCount(), &aNewPal ); 849 BitmapWriteAccess* pW = aNewBmp.AcquireWriteAccess(); 850 851 if( pW ) 852 { 853 pW->CopyBuffer( *pR ); 854 aNewBmp.ReleaseAccess( pW ); 855 bRet = sal_True; 856 } 857 } 858 else 859 { 860 aNewBmp = Bitmap( GetSizePixel(), 24 ); 861 862 BitmapWriteAccess* pW = aNewBmp.AcquireWriteAccess(); 863 864 if( pW ) 865 { 866 const long nWidth = pR->Width(), nHeight = pR->Height(); 867 868 for( long nY = 0; nY < nHeight; nY++ ) 869 { 870 for( long nX = 0; nX < nWidth; nX++ ) 871 { 872 const BitmapColor aOld( pR->GetPixel( nY, nX ) ); 873 pW->SetPixel( nY, nX, BitmapColor( ( aOld.GetRed() >> 1 ) | 0x80, 874 ( aOld.GetGreen() >> 1 ) | 0x80, 875 ( aOld.GetBlue() >> 1 ) | 0x80 ) ); 876 877 } 878 } 879 880 aNewBmp.ReleaseAccess( pW ); 881 bRet = sal_True; 882 } 883 } 884 885 ReleaseAccess( pR ); 886 } 887 888 if( bRet ) 889 { 890 const MapMode aMap( maPrefMapMode ); 891 const Size aSize( maPrefSize ); 892 893 *this = aNewBmp; 894 895 maPrefMapMode = aMap; 896 maPrefSize = aSize; 897 } 898 899 return bRet; 900 } 901 902 // ------------------------------------------------------------------------ 903 904 sal_Bool Bitmap::Scale( const double& rScaleX, const double& rScaleY, sal_uLong nScaleFlag ) 905 { 906 sal_Bool bRet; 907 908 if( ( rScaleX != 1.0 ) || ( rScaleY != 1.0 ) ) 909 { 910 if( BMP_SCALE_FAST == nScaleFlag ) 911 bRet = ImplScaleFast( rScaleX, rScaleY ); 912 else if( BMP_SCALE_INTERPOLATE == nScaleFlag ) 913 bRet = ImplScaleInterpolate( rScaleX, rScaleY ); 914 else 915 bRet = sal_False; 916 } 917 else 918 bRet = sal_True; 919 920 return bRet; 921 } 922 923 // ------------------------------------------------------------------------ 924 925 sal_Bool Bitmap::Scale( const Size& rNewSize, sal_uLong nScaleFlag ) 926 { 927 const Size aSize( GetSizePixel() ); 928 sal_Bool bRet; 929 930 if( aSize.Width() && aSize.Height() ) 931 { 932 bRet = Scale( (double) rNewSize.Width() / aSize.Width(), 933 (double) rNewSize.Height() / aSize.Height(), 934 nScaleFlag ); 935 } 936 else 937 bRet = sal_True; 938 939 return bRet; 940 } 941 942 // ------------------------------------------------------------------------ 943 944 sal_Bool Bitmap::ImplScaleFast( const double& rScaleX, const double& rScaleY ) 945 { 946 const Size aSizePix( GetSizePixel() ); 947 const long nNewWidth = FRound( aSizePix.Width() * rScaleX ); 948 const long nNewHeight = FRound( aSizePix.Height() * rScaleY ); 949 sal_Bool bRet = sal_False; 950 951 if( nNewWidth && nNewHeight ) 952 { 953 BitmapReadAccess* pReadAcc = AcquireReadAccess(); 954 Bitmap aNewBmp( Size( nNewWidth, nNewHeight ), GetBitCount(), &pReadAcc->GetPalette() ); 955 BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess(); 956 957 if( pReadAcc && pWriteAcc ) 958 { 959 const long nScanlineSize = pWriteAcc->GetScanlineSize(); 960 const long nNewWidth1 = nNewWidth - 1L; 961 const long nNewHeight1 = nNewHeight - 1L; 962 const long nWidth = pReadAcc->Width(); 963 const long nHeight = pReadAcc->Height(); 964 long* pLutX = new long[ nNewWidth ]; 965 long* pLutY = new long[ nNewHeight ]; 966 long nX, nY, nMapY, nActY = 0L; 967 968 if( nNewWidth1 && nNewHeight1 ) 969 { 970 for( nX = 0L; nX < nNewWidth; nX++ ) 971 pLutX[ nX ] = nX * nWidth / nNewWidth; 972 973 for( nY = 0L; nY < nNewHeight; nY++ ) 974 pLutY[ nY ] = nY * nHeight / nNewHeight; 975 976 while( nActY < nNewHeight ) 977 { 978 nMapY = pLutY[ nActY ]; 979 980 for( nX = 0L; nX < nNewWidth; nX++ ) 981 pWriteAcc->SetPixel( nActY, nX, pReadAcc->GetPixel( nMapY , pLutX[ nX ] ) ); 982 983 while( ( nActY < nNewHeight1 ) && ( pLutY[ nActY + 1 ] == nMapY ) ) 984 { 985 memcpy( pWriteAcc->GetScanline( nActY + 1L ), 986 pWriteAcc->GetScanline( nActY ), nScanlineSize ); 987 nActY++; 988 } 989 990 nActY++; 991 } 992 993 bRet = sal_True; 994 } 995 996 delete[] pLutX; 997 delete[] pLutY; 998 } 999 1000 ReleaseAccess( pReadAcc ); 1001 aNewBmp.ReleaseAccess( pWriteAcc ); 1002 1003 if( bRet ) 1004 ImplAssignWithSize( aNewBmp ); 1005 } 1006 1007 return bRet; 1008 } 1009 1010 // ------------------------------------------------------------------------ 1011 1012 sal_Bool Bitmap::ImplScaleInterpolate( const double& rScaleX, const double& rScaleY ) 1013 { 1014 const Size aSizePix( GetSizePixel() ); 1015 const long nNewWidth = FRound( aSizePix.Width() * rScaleX ); 1016 const long nNewHeight = FRound( aSizePix.Height() * rScaleY ); 1017 sal_Bool bRet = sal_False; 1018 1019 if( ( nNewWidth > 1L ) && ( nNewHeight > 1L ) ) 1020 { 1021 BitmapColor aCol0; 1022 BitmapColor aCol1; 1023 BitmapReadAccess* pReadAcc = AcquireReadAccess(); 1024 long nWidth = pReadAcc->Width(); 1025 long nHeight = pReadAcc->Height(); 1026 Bitmap aNewBmp( Size( nNewWidth, nHeight ), 24 ); 1027 BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess(); 1028 long* pLutInt; 1029 long* pLutFrac; 1030 long nX, nY; 1031 long lXB0, lXB1, lXG0, lXG1, lXR0, lXR1; 1032 double fTemp; 1033 long nTemp; 1034 1035 if( pReadAcc && pWriteAcc ) 1036 { 1037 const long nNewWidth1 = nNewWidth - 1L; 1038 const long nWidth1 = pReadAcc->Width() - 1L; 1039 const double fRevScaleX = (double) nWidth1 / nNewWidth1; 1040 1041 pLutInt = new long[ nNewWidth ]; 1042 pLutFrac = new long[ nNewWidth ]; 1043 1044 for( nX = 0L, nTemp = nWidth - 2L; nX < nNewWidth; nX++ ) 1045 { 1046 fTemp = nX * fRevScaleX; 1047 pLutInt[ nX ] = MinMax( (long) fTemp, 0, nTemp ); 1048 fTemp -= pLutInt[ nX ]; 1049 pLutFrac[ nX ] = (long) ( fTemp * 1024. ); 1050 } 1051 1052 if( pReadAcc->HasPalette() ) 1053 { 1054 for( nY = 0L; nY < nHeight; nY++ ) 1055 { 1056 if( 1 == nWidth ) 1057 { 1058 aCol0 = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nY, 0 ) ); 1059 1060 for( nX = 0L; nX < nNewWidth; nX++ ) 1061 pWriteAcc->SetPixel( nY, nX, aCol0 ); 1062 } 1063 else 1064 { 1065 for( nX = 0L; nX < nNewWidth; nX++ ) 1066 { 1067 nTemp = pLutInt[ nX ]; 1068 1069 aCol0 = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nY, nTemp++ ) ); 1070 aCol1 = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nY, nTemp ) ); 1071 1072 nTemp = pLutFrac[ nX ]; 1073 1074 lXR1 = aCol1.GetRed() - ( lXR0 = aCol0.GetRed() ); 1075 lXG1 = aCol1.GetGreen() - ( lXG0 = aCol0.GetGreen() ); 1076 lXB1 = aCol1.GetBlue() - ( lXB0 = aCol0.GetBlue() ); 1077 1078 aCol0.SetRed( (sal_uInt8) ( ( lXR1 * nTemp + ( lXR0 << 10 ) ) >> 10 ) ); 1079 aCol0.SetGreen( (sal_uInt8) ( ( lXG1 * nTemp + ( lXG0 << 10 ) ) >> 10 ) ); 1080 aCol0.SetBlue( (sal_uInt8) ( ( lXB1 * nTemp + ( lXB0 << 10 ) ) >> 10 ) ); 1081 1082 pWriteAcc->SetPixel( nY, nX, aCol0 ); 1083 } 1084 } 1085 } 1086 } 1087 else 1088 { 1089 for( nY = 0L; nY < nHeight; nY++ ) 1090 { 1091 if( 1 == nWidth ) 1092 { 1093 aCol0 = pReadAcc->GetPixel( nY, 0 ); 1094 1095 for( nX = 0L; nX < nNewWidth; nX++ ) 1096 pWriteAcc->SetPixel( nY, nX, aCol0 ); 1097 } 1098 else 1099 { 1100 for( nX = 0L; nX < nNewWidth; nX++ ) 1101 { 1102 nTemp = pLutInt[ nX ]; 1103 1104 aCol0 = pReadAcc->GetPixel( nY, nTemp++ ); 1105 aCol1 = pReadAcc->GetPixel( nY, nTemp ); 1106 1107 nTemp = pLutFrac[ nX ]; 1108 1109 lXR1 = aCol1.GetRed() - ( lXR0 = aCol0.GetRed() ); 1110 lXG1 = aCol1.GetGreen() - ( lXG0 = aCol0.GetGreen() ); 1111 lXB1 = aCol1.GetBlue() - ( lXB0 = aCol0.GetBlue() ); 1112 1113 aCol0.SetRed( (sal_uInt8) ( ( lXR1 * nTemp + ( lXR0 << 10 ) ) >> 10 ) ); 1114 aCol0.SetGreen( (sal_uInt8) ( ( lXG1 * nTemp + ( lXG0 << 10 ) ) >> 10 ) ); 1115 aCol0.SetBlue( (sal_uInt8) ( ( lXB1 * nTemp + ( lXB0 << 10 ) ) >> 10 ) ); 1116 1117 pWriteAcc->SetPixel( nY, nX, aCol0 ); 1118 } 1119 } 1120 } 1121 } 1122 1123 delete[] pLutInt; 1124 delete[] pLutFrac; 1125 bRet = sal_True; 1126 } 1127 1128 ReleaseAccess( pReadAcc ); 1129 aNewBmp.ReleaseAccess( pWriteAcc ); 1130 1131 if( bRet ) 1132 { 1133 bRet = sal_False; 1134 ImplAssignWithSize( aNewBmp ); 1135 pReadAcc = AcquireReadAccess(); 1136 aNewBmp = Bitmap( Size( nNewWidth, nNewHeight ), 24 ); 1137 pWriteAcc = aNewBmp.AcquireWriteAccess(); 1138 1139 if( pReadAcc && pWriteAcc ) 1140 { 1141 const long nNewHeight1 = nNewHeight - 1L; 1142 const long nHeight1 = pReadAcc->Height() - 1L; 1143 const double fRevScaleY = (double) nHeight1 / nNewHeight1; 1144 1145 pLutInt = new long[ nNewHeight ]; 1146 pLutFrac = new long[ nNewHeight ]; 1147 1148 for( nY = 0L, nTemp = nHeight - 2L; nY < nNewHeight; nY++ ) 1149 { 1150 fTemp = nY * fRevScaleY; 1151 pLutInt[ nY ] = MinMax( (long) fTemp, 0, nTemp ); 1152 fTemp -= pLutInt[ nY ]; 1153 pLutFrac[ nY ] = (long) ( fTemp * 1024. ); 1154 } 1155 1156 if( pReadAcc->HasPalette() ) 1157 { 1158 for( nX = 0L; nX < nNewWidth; nX++ ) 1159 { 1160 if( 1 == nHeight ) 1161 { 1162 aCol0 = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( 0, nX ) ); 1163 1164 for( nY = 0L; nY < nNewHeight; nY++ ) 1165 pWriteAcc->SetPixel( nY, nX, aCol0 ); 1166 } 1167 else 1168 { 1169 for( nY = 0L; nY < nNewHeight; nY++ ) 1170 { 1171 nTemp = pLutInt[ nY ]; 1172 1173 aCol0 = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nTemp++, nX ) ); 1174 aCol1 = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nTemp, nX ) ); 1175 1176 nTemp = pLutFrac[ nY ]; 1177 1178 lXR1 = aCol1.GetRed() - ( lXR0 = aCol0.GetRed() ); 1179 lXG1 = aCol1.GetGreen() - ( lXG0 = aCol0.GetGreen() ); 1180 lXB1 = aCol1.GetBlue() - ( lXB0 = aCol0.GetBlue() ); 1181 1182 aCol0.SetRed( (sal_uInt8) ( ( lXR1 * nTemp + ( lXR0 << 10 ) ) >> 10 ) ); 1183 aCol0.SetGreen( (sal_uInt8) ( ( lXG1 * nTemp + ( lXG0 << 10 ) ) >> 10 ) ); 1184 aCol0.SetBlue( (sal_uInt8) ( ( lXB1 * nTemp + ( lXB0 << 10 ) ) >> 10 ) ); 1185 1186 pWriteAcc->SetPixel( nY, nX, aCol0 ); 1187 } 1188 } 1189 } 1190 } 1191 else 1192 { 1193 for( nX = 0L; nX < nNewWidth; nX++ ) 1194 { 1195 if( 1 == nHeight ) 1196 { 1197 aCol0 = pReadAcc->GetPixel( 0, nX ); 1198 1199 for( nY = 0L; nY < nNewHeight; nY++ ) 1200 pWriteAcc->SetPixel( nY, nX, aCol0 ); 1201 } 1202 else 1203 { 1204 for( nY = 0L; nY < nNewHeight; nY++ ) 1205 { 1206 nTemp = pLutInt[ nY ]; 1207 1208 aCol0 = pReadAcc->GetPixel( nTemp++, nX ); 1209 aCol1 = pReadAcc->GetPixel( nTemp, nX ); 1210 1211 nTemp = pLutFrac[ nY ]; 1212 1213 lXR1 = aCol1.GetRed() - ( lXR0 = aCol0.GetRed() ); 1214 lXG1 = aCol1.GetGreen() - ( lXG0 = aCol0.GetGreen() ); 1215 lXB1 = aCol1.GetBlue() - ( lXB0 = aCol0.GetBlue() ); 1216 1217 aCol0.SetRed( (sal_uInt8) ( ( lXR1 * nTemp + ( lXR0 << 10 ) ) >> 10 ) ); 1218 aCol0.SetGreen( (sal_uInt8) ( ( lXG1 * nTemp + ( lXG0 << 10 ) ) >> 10 ) ); 1219 aCol0.SetBlue( (sal_uInt8) ( ( lXB1 * nTemp + ( lXB0 << 10 ) ) >> 10 ) ); 1220 1221 pWriteAcc->SetPixel( nY, nX, aCol0 ); 1222 } 1223 } 1224 } 1225 } 1226 1227 delete[] pLutInt; 1228 delete[] pLutFrac; 1229 bRet = sal_True; 1230 } 1231 1232 ReleaseAccess( pReadAcc ); 1233 aNewBmp.ReleaseAccess( pWriteAcc ); 1234 1235 if( bRet ) 1236 ImplAssignWithSize( aNewBmp ); 1237 } 1238 } 1239 1240 if( !bRet ) 1241 bRet = ImplScaleFast( rScaleX, rScaleY ); 1242 1243 return bRet; 1244 } 1245 1246 // ------------------------------------------------------------------------ 1247 1248 sal_Bool Bitmap::Dither( sal_uLong nDitherFlags ) 1249 { 1250 sal_Bool bRet = sal_False; 1251 1252 const Size aSizePix( GetSizePixel() ); 1253 1254 if( aSizePix.Width() == 1 || aSizePix.Height() == 1 ) 1255 bRet = sal_True; 1256 else if( nDitherFlags & BMP_DITHER_MATRIX ) 1257 bRet = ImplDitherMatrix(); 1258 else if( nDitherFlags & BMP_DITHER_FLOYD ) 1259 bRet = ImplDitherFloyd(); 1260 else if( ( nDitherFlags & BMP_DITHER_FLOYD_16 ) && ( GetBitCount() == 24 ) ) 1261 bRet = ImplDitherFloyd16(); 1262 1263 return bRet; 1264 } 1265 1266 // ------------------------------------------------------------------------ 1267 1268 sal_Bool Bitmap::ImplDitherMatrix() 1269 { 1270 BitmapReadAccess* pReadAcc = AcquireReadAccess(); 1271 Bitmap aNewBmp( GetSizePixel(), 8 ); 1272 BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess(); 1273 sal_Bool bRet = sal_False; 1274 1275 if( pReadAcc && pWriteAcc ) 1276 { 1277 const sal_uLong nWidth = pReadAcc->Width(); 1278 const sal_uLong nHeight = pReadAcc->Height(); 1279 BitmapColor aIndex( (sal_uInt8) 0 ); 1280 1281 if( pReadAcc->HasPalette() ) 1282 { 1283 for( sal_uLong nY = 0UL; nY < nHeight; nY++ ) 1284 { 1285 for( sal_uLong nX = 0UL, nModY = ( nY & 0x0FUL ) << 4UL; nX < nWidth; nX++ ) 1286 { 1287 const BitmapColor aCol( pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nY, nX ) ) ); 1288 const sal_uLong nD = nVCLDitherLut[ nModY + ( nX & 0x0FUL ) ]; 1289 const sal_uLong nR = ( nVCLLut[ aCol.GetRed() ] + nD ) >> 16UL; 1290 const sal_uLong nG = ( nVCLLut[ aCol.GetGreen() ] + nD ) >> 16UL; 1291 const sal_uLong nB = ( nVCLLut[ aCol.GetBlue() ] + nD ) >> 16UL; 1292 1293 aIndex.SetIndex( (sal_uInt8) ( nVCLRLut[ nR ] + nVCLGLut[ nG ] + nVCLBLut[ nB ] ) ); 1294 pWriteAcc->SetPixel( nY, nX, aIndex ); 1295 } 1296 } 1297 } 1298 else 1299 { 1300 for( sal_uLong nY = 0UL; nY < nHeight; nY++ ) 1301 { 1302 for( sal_uLong nX = 0UL, nModY = ( nY & 0x0FUL ) << 4UL; nX < nWidth; nX++ ) 1303 { 1304 const BitmapColor aCol( pReadAcc->GetPixel( nY, nX ) ); 1305 const sal_uLong nD = nVCLDitherLut[ nModY + ( nX & 0x0FUL ) ]; 1306 const sal_uLong nR = ( nVCLLut[ aCol.GetRed() ] + nD ) >> 16UL; 1307 const sal_uLong nG = ( nVCLLut[ aCol.GetGreen() ] + nD ) >> 16UL; 1308 const sal_uLong nB = ( nVCLLut[ aCol.GetBlue() ] + nD ) >> 16UL; 1309 1310 aIndex.SetIndex( (sal_uInt8) ( nVCLRLut[ nR ] + nVCLGLut[ nG ] + nVCLBLut[ nB ] ) ); 1311 pWriteAcc->SetPixel( nY, nX, aIndex ); 1312 } 1313 } 1314 } 1315 1316 bRet = sal_True; 1317 } 1318 1319 ReleaseAccess( pReadAcc ); 1320 aNewBmp.ReleaseAccess( pWriteAcc ); 1321 1322 if( bRet ) 1323 { 1324 const MapMode aMap( maPrefMapMode ); 1325 const Size aSize( maPrefSize ); 1326 1327 *this = aNewBmp; 1328 1329 maPrefMapMode = aMap; 1330 maPrefSize = aSize; 1331 } 1332 1333 return bRet; 1334 } 1335 1336 // ------------------------------------------------------------------------ 1337 1338 sal_Bool Bitmap::ImplDitherFloyd() 1339 { 1340 const Size aSize( GetSizePixel() ); 1341 sal_Bool bRet = sal_False; 1342 1343 if( ( aSize.Width() > 3 ) && ( aSize.Height() > 2 ) ) 1344 { 1345 BitmapReadAccess* pReadAcc = AcquireReadAccess(); 1346 Bitmap aNewBmp( GetSizePixel(), 8 ); 1347 BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess(); 1348 1349 if( pReadAcc && pWriteAcc ) 1350 { 1351 BitmapColor aColor; 1352 long nWidth = pReadAcc->Width(); 1353 long nWidth1 = nWidth - 1L; 1354 long nHeight = pReadAcc->Height(); 1355 long nX; 1356 long nW = nWidth * 3L; 1357 long nW2 = nW - 3L; 1358 long nRErr, nGErr, nBErr; 1359 long nRC, nGC, nBC; 1360 long nTemp; 1361 long nZ; 1362 long* p1 = new long[ nW ]; 1363 long* p2 = new long[ nW ]; 1364 long* p1T = p1; 1365 long* p2T = p2; 1366 long* pTmp; 1367 sal_Bool bPal = pReadAcc->HasPalette(); 1368 1369 pTmp = p2T; 1370 1371 if( bPal ) 1372 { 1373 for( nZ = 0; nZ < nWidth; nZ++ ) 1374 { 1375 aColor = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( 0, nZ ) ); 1376 1377 *pTmp++ = (long) aColor.GetBlue() << 12; 1378 *pTmp++ = (long) aColor.GetGreen() << 12; 1379 *pTmp++ = (long) aColor.GetRed() << 12; 1380 } 1381 } 1382 else 1383 { 1384 for( nZ = 0; nZ < nWidth; nZ++ ) 1385 { 1386 aColor = pReadAcc->GetPixel( 0, nZ ); 1387 1388 *pTmp++ = (long) aColor.GetBlue() << 12; 1389 *pTmp++ = (long) aColor.GetGreen() << 12; 1390 *pTmp++ = (long) aColor.GetRed() << 12; 1391 } 1392 } 1393 1394 for( long nY = 1, nYAcc = 0L; nY <= nHeight; nY++, nYAcc++ ) 1395 { 1396 pTmp = p1T; 1397 p1T = p2T; 1398 p2T = pTmp; 1399 1400 if( nY < nHeight ) 1401 { 1402 if( bPal ) 1403 { 1404 for( nZ = 0; nZ < nWidth; nZ++ ) 1405 { 1406 aColor = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nY, nZ ) ); 1407 1408 *pTmp++ = (long) aColor.GetBlue() << 12; 1409 *pTmp++ = (long) aColor.GetGreen() << 12; 1410 *pTmp++ = (long) aColor.GetRed() << 12; 1411 } 1412 } 1413 else 1414 { 1415 for( nZ = 0; nZ < nWidth; nZ++ ) 1416 { 1417 aColor = pReadAcc->GetPixel( nY, nZ ); 1418 1419 *pTmp++ = (long) aColor.GetBlue() << 12; 1420 *pTmp++ = (long) aColor.GetGreen() << 12; 1421 *pTmp++ = (long) aColor.GetRed() << 12; 1422 } 1423 } 1424 } 1425 1426 // erstes Pixel gesondert betrachten 1427 nX = 0; 1428 CALC_ERRORS; 1429 CALC_TABLES7; 1430 nX -= 5; 1431 CALC_TABLES5; 1432 pWriteAcc->SetPixel( nYAcc, 0, BitmapColor( (sal_uInt8) ( nVCLBLut[ nBC ] + nVCLGLut[nGC ] + nVCLRLut[nRC ] ) ) ); 1433 1434 // mittlere Pixel ueber Schleife 1435 long nXAcc; 1436 for ( nX = 3L, nXAcc = 1L; nX < nW2; nXAcc++ ) 1437 { 1438 CALC_ERRORS; 1439 CALC_TABLES7; 1440 nX -= 8; 1441 CALC_TABLES3; 1442 CALC_TABLES5; 1443 pWriteAcc->SetPixel( nYAcc, nXAcc, BitmapColor( (sal_uInt8) ( nVCLBLut[ nBC ] + nVCLGLut[nGC ] + nVCLRLut[nRC ] ) ) ); 1444 } 1445 1446 // letztes Pixel gesondert betrachten 1447 CALC_ERRORS; 1448 nX -= 5; 1449 CALC_TABLES3; 1450 CALC_TABLES5; 1451 pWriteAcc->SetPixel( nYAcc, nWidth1, BitmapColor( (sal_uInt8) ( nVCLBLut[ nBC ] + nVCLGLut[nGC ] + nVCLRLut[nRC ] ) ) ); 1452 } 1453 1454 delete[] p1; 1455 delete[] p2; 1456 bRet = sal_True; 1457 } 1458 1459 ReleaseAccess( pReadAcc ); 1460 aNewBmp.ReleaseAccess( pWriteAcc ); 1461 1462 if( bRet ) 1463 { 1464 const MapMode aMap( maPrefMapMode ); 1465 const Size aPrefSize( maPrefSize ); 1466 1467 *this = aNewBmp; 1468 1469 maPrefMapMode = aMap; 1470 maPrefSize = aPrefSize; 1471 } 1472 } 1473 1474 return bRet; 1475 } 1476 1477 // ------------------------------------------------------------------------ 1478 1479 sal_Bool Bitmap::ImplDitherFloyd16() 1480 { 1481 BitmapReadAccess* pReadAcc = AcquireReadAccess(); 1482 Bitmap aNewBmp( GetSizePixel(), 24 ); 1483 BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess(); 1484 sal_Bool bRet = sal_False; 1485 1486 if( pReadAcc && pWriteAcc ) 1487 { 1488 const long nWidth = pWriteAcc->Width(); 1489 const long nWidth1 = nWidth - 1L; 1490 const long nHeight = pWriteAcc->Height(); 1491 BitmapColor aColor; 1492 BitmapColor aBestCol; 1493 ImpErrorQuad aErrQuad; 1494 ImpErrorQuad* pErrQuad1 = new ImpErrorQuad[ nWidth ]; 1495 ImpErrorQuad* pErrQuad2 = new ImpErrorQuad[ nWidth ]; 1496 ImpErrorQuad* pQLine1 = pErrQuad1; 1497 ImpErrorQuad* pQLine2 = 0; 1498 long nX, nY; 1499 long nYTmp = 0L; 1500 sal_Bool bQ1 = sal_True; 1501 1502 for( nY = 0L; nY < Min( nHeight, 2L ); nY++, nYTmp++ ) 1503 for( nX = 0L, pQLine2 = !nY ? pErrQuad1 : pErrQuad2; nX < nWidth; nX++ ) 1504 pQLine2[ nX ] = pReadAcc->GetPixel( nYTmp, nX ); 1505 1506 for( nY = 0L; nY < nHeight; nY++, nYTmp++ ) 1507 { 1508 // erstes ZeilenPixel 1509 aBestCol = pQLine1[ 0 ].ImplGetColor(); 1510 aBestCol.SetRed( ( aBestCol.GetRed() & 248 ) | 7 ); 1511 aBestCol.SetGreen( ( aBestCol.GetGreen() & 248 ) | 7 ); 1512 aBestCol.SetBlue( ( aBestCol.GetBlue() & 248 ) | 7 ); 1513 pWriteAcc->SetPixel( nY, 0, aBestCol ); 1514 1515 for( nX = 1L; nX < nWidth1; nX++ ) 1516 { 1517 aColor = pQLine1[ nX ].ImplGetColor(); 1518 aBestCol.SetRed( ( aColor.GetRed() & 248 ) | 7 ); 1519 aBestCol.SetGreen( ( aColor.GetGreen() & 248 ) | 7 ); 1520 aBestCol.SetBlue( ( aColor.GetBlue() & 248 ) | 7 ); 1521 aErrQuad = ( ImpErrorQuad( aColor ) -= aBestCol ); 1522 pQLine1[ ++nX ].ImplAddColorError7( aErrQuad ); 1523 pQLine2[ nX-- ].ImplAddColorError1( aErrQuad ); 1524 pQLine2[ nX-- ].ImplAddColorError5( aErrQuad ); 1525 pQLine2[ nX++ ].ImplAddColorError3( aErrQuad ); 1526 pWriteAcc->SetPixel( nY, nX, aBestCol ); 1527 } 1528 1529 // letztes ZeilenPixel 1530 aBestCol = pQLine1[ nWidth1 ].ImplGetColor(); 1531 aBestCol.SetRed( ( aBestCol.GetRed() & 248 ) | 7 ); 1532 aBestCol.SetGreen( ( aBestCol.GetGreen() & 248 ) | 7 ); 1533 aBestCol.SetBlue( ( aBestCol.GetBlue() & 248 ) | 7 ); 1534 pWriteAcc->SetPixel( nY, nX, aBestCol ); 1535 1536 // Zeilenpuffer neu fuellen/kopieren 1537 pQLine1 = pQLine2; 1538 pQLine2 = ( bQ1 = !bQ1 ) != sal_False ? pErrQuad2 : pErrQuad1; 1539 1540 if( nYTmp < nHeight ) 1541 for( nX = 0L; nX < nWidth; nX++ ) 1542 pQLine2[ nX ] = pReadAcc->GetPixel( nYTmp, nX ); 1543 } 1544 1545 // Zeilenpuffer zerstoeren 1546 delete[] pErrQuad1; 1547 delete[] pErrQuad2; 1548 bRet = sal_True; 1549 } 1550 1551 ReleaseAccess( pReadAcc ); 1552 aNewBmp.ReleaseAccess( pWriteAcc ); 1553 1554 if( bRet ) 1555 { 1556 const MapMode aMap( maPrefMapMode ); 1557 const Size aSize( maPrefSize ); 1558 1559 *this = aNewBmp; 1560 1561 maPrefMapMode = aMap; 1562 maPrefSize = aSize; 1563 } 1564 1565 return bRet; 1566 } 1567 1568 // ------------------------------------------------------------------------ 1569 1570 sal_Bool Bitmap::ReduceColors( sal_uInt16 nColorCount, BmpReduce eReduce ) 1571 { 1572 sal_Bool bRet; 1573 1574 if( GetColorCount() <= (sal_uLong) nColorCount ) 1575 bRet = sal_True; 1576 else if( nColorCount ) 1577 { 1578 if( BMP_REDUCE_SIMPLE == eReduce ) 1579 bRet = ImplReduceSimple( nColorCount ); 1580 else if( BMP_REDUCE_POPULAR == eReduce ) 1581 bRet = ImplReducePopular( nColorCount ); 1582 else 1583 bRet = ImplReduceMedian( nColorCount ); 1584 } 1585 else 1586 bRet = sal_False; 1587 1588 return bRet; 1589 } 1590 1591 // ------------------------------------------------------------------------ 1592 1593 sal_Bool Bitmap::ImplReduceSimple( sal_uInt16 nColorCount ) 1594 { 1595 Bitmap aNewBmp; 1596 BitmapReadAccess* pRAcc = AcquireReadAccess(); 1597 const sal_uInt16 nColCount = Min( nColorCount, (sal_uInt16) 256 ); 1598 sal_uInt16 nBitCount; 1599 sal_Bool bRet = sal_False; 1600 1601 if( nColCount <= 2 ) 1602 nBitCount = 1; 1603 else if( nColCount <= 16 ) 1604 nBitCount = 4; 1605 else 1606 nBitCount = 8; 1607 1608 if( pRAcc ) 1609 { 1610 Octree aOct( *pRAcc, nColCount ); 1611 const BitmapPalette& rPal = aOct.GetPalette(); 1612 BitmapWriteAccess* pWAcc; 1613 1614 aNewBmp = Bitmap( GetSizePixel(), nBitCount, &rPal ); 1615 pWAcc = aNewBmp.AcquireWriteAccess(); 1616 1617 if( pWAcc ) 1618 { 1619 const long nWidth = pRAcc->Width(); 1620 const long nHeight = pRAcc->Height(); 1621 1622 if( pRAcc->HasPalette() ) 1623 { 1624 for( long nY = 0L; nY < nHeight; nY++ ) 1625 for( long nX =0L; nX < nWidth; nX++ ) 1626 pWAcc->SetPixel( nY, nX, (sal_uInt8) aOct.GetBestPaletteIndex( pRAcc->GetPaletteColor( pRAcc->GetPixel( nY, nX ) ) ) ); 1627 } 1628 else 1629 { 1630 for( long nY = 0L; nY < nHeight; nY++ ) 1631 for( long nX =0L; nX < nWidth; nX++ ) 1632 pWAcc->SetPixel( nY, nX, (sal_uInt8) aOct.GetBestPaletteIndex( pRAcc->GetPixel( nY, nX ) ) ); 1633 } 1634 1635 aNewBmp.ReleaseAccess( pWAcc ); 1636 bRet = sal_True; 1637 } 1638 1639 ReleaseAccess( pRAcc ); 1640 } 1641 1642 if( bRet ) 1643 { 1644 const MapMode aMap( maPrefMapMode ); 1645 const Size aSize( maPrefSize ); 1646 1647 *this = aNewBmp; 1648 maPrefMapMode = aMap; 1649 maPrefSize = aSize; 1650 } 1651 1652 return bRet; 1653 } 1654 1655 // ------------------------------------------------------------------------ 1656 1657 struct PopularColorCount 1658 { 1659 sal_uInt32 mnIndex; 1660 sal_uInt32 mnCount; 1661 }; 1662 1663 // ------------------------------------------------------------------------ 1664 1665 extern "C" int __LOADONCALLAPI ImplPopularCmpFnc( const void* p1, const void* p2 ) 1666 { 1667 int nRet; 1668 1669 if( ( (PopularColorCount*) p1 )->mnCount < ( (PopularColorCount*) p2 )->mnCount ) 1670 nRet = 1; 1671 else if( ( (PopularColorCount*) p1 )->mnCount == ( (PopularColorCount*) p2 )->mnCount ) 1672 nRet = 0; 1673 else 1674 nRet = -1; 1675 1676 return nRet; 1677 } 1678 1679 // ------------------------------------------------------------------------ 1680 1681 sal_Bool Bitmap::ImplReducePopular( sal_uInt16 nColCount ) 1682 { 1683 BitmapReadAccess* pRAcc = AcquireReadAccess(); 1684 sal_uInt16 nBitCount; 1685 sal_Bool bRet = sal_False; 1686 1687 if( nColCount > 256 ) 1688 nColCount = 256; 1689 1690 if( nColCount < 17 ) 1691 nBitCount = 4; 1692 else 1693 nBitCount = 8; 1694 1695 if( pRAcc ) 1696 { 1697 const sal_uInt32 nValidBits = 4; 1698 const sal_uInt32 nRightShiftBits = 8 - nValidBits; 1699 const sal_uInt32 nLeftShiftBits1 = nValidBits; 1700 const sal_uInt32 nLeftShiftBits2 = nValidBits << 1; 1701 const sal_uInt32 nColorsPerComponent = 1 << nValidBits; 1702 const sal_uInt32 nColorOffset = 256 / nColorsPerComponent; 1703 const sal_uInt32 nTotalColors = nColorsPerComponent * nColorsPerComponent * nColorsPerComponent; 1704 const long nWidth = pRAcc->Width(); 1705 const long nHeight = pRAcc->Height(); 1706 PopularColorCount* pCountTable = new PopularColorCount[ nTotalColors ]; 1707 long nX, nY, nR, nG, nB, nIndex; 1708 1709 rtl_zeroMemory( pCountTable, nTotalColors * sizeof( PopularColorCount ) ); 1710 1711 for( nR = 0, nIndex = 0; nR < 256; nR += nColorOffset ) 1712 { 1713 for( nG = 0; nG < 256; nG += nColorOffset ) 1714 { 1715 for( nB = 0; nB < 256; nB += nColorOffset ) 1716 { 1717 pCountTable[ nIndex ].mnIndex = nIndex; 1718 nIndex++; 1719 } 1720 } 1721 } 1722 1723 if( pRAcc->HasPalette() ) 1724 { 1725 for( nY = 0L; nY < nHeight; nY++ ) 1726 { 1727 for( nX = 0L; nX < nWidth; nX++ ) 1728 { 1729 const BitmapColor& rCol = pRAcc->GetPaletteColor( pRAcc->GetPixel( nY, nX ) ); 1730 pCountTable[ ( ( ( (sal_uInt32) rCol.GetRed() ) >> nRightShiftBits ) << nLeftShiftBits2 ) | 1731 ( ( ( (sal_uInt32) rCol.GetGreen() ) >> nRightShiftBits ) << nLeftShiftBits1 ) | 1732 ( ( (sal_uInt32) rCol.GetBlue() ) >> nRightShiftBits ) ].mnCount++; 1733 } 1734 } 1735 } 1736 else 1737 { 1738 for( nY = 0L; nY < nHeight; nY++ ) 1739 { 1740 for( nX = 0L; nX < nWidth; nX++ ) 1741 { 1742 const BitmapColor aCol( pRAcc->GetPixel( nY, nX ) ); 1743 pCountTable[ ( ( ( (sal_uInt32) aCol.GetRed() ) >> nRightShiftBits ) << nLeftShiftBits2 ) | 1744 ( ( ( (sal_uInt32) aCol.GetGreen() ) >> nRightShiftBits ) << nLeftShiftBits1 ) | 1745 ( ( (sal_uInt32) aCol.GetBlue() ) >> nRightShiftBits ) ].mnCount++; 1746 } 1747 } 1748 } 1749 1750 BitmapPalette aNewPal( nColCount ); 1751 1752 qsort( pCountTable, nTotalColors, sizeof( PopularColorCount ), ImplPopularCmpFnc ); 1753 1754 for( sal_uInt16 n = 0; n < nColCount; n++ ) 1755 { 1756 const PopularColorCount& rPop = pCountTable[ n ]; 1757 aNewPal[ n ] = BitmapColor( (sal_uInt8) ( ( rPop.mnIndex >> nLeftShiftBits2 ) << nRightShiftBits ), 1758 (sal_uInt8) ( ( ( rPop.mnIndex >> nLeftShiftBits1 ) & ( nColorsPerComponent - 1 ) ) << nRightShiftBits ), 1759 (sal_uInt8) ( ( rPop.mnIndex & ( nColorsPerComponent - 1 ) ) << nRightShiftBits ) ); 1760 } 1761 1762 Bitmap aNewBmp( GetSizePixel(), nBitCount, &aNewPal ); 1763 BitmapWriteAccess* pWAcc = aNewBmp.AcquireWriteAccess(); 1764 1765 if( pWAcc ) 1766 { 1767 BitmapColor aDstCol( (sal_uInt8) 0 ); 1768 sal_uInt8* pIndexMap = new sal_uInt8[ nTotalColors ]; 1769 1770 for( nR = 0, nIndex = 0; nR < 256; nR += nColorOffset ) 1771 for( nG = 0; nG < 256; nG += nColorOffset ) 1772 for( nB = 0; nB < 256; nB += nColorOffset ) 1773 pIndexMap[ nIndex++ ] = (sal_uInt8) aNewPal.GetBestIndex( BitmapColor( (sal_uInt8) nR, (sal_uInt8) nG, (sal_uInt8) nB ) ); 1774 1775 if( pRAcc->HasPalette() ) 1776 { 1777 for( nY = 0L; nY < nHeight; nY++ ) 1778 { 1779 for( nX = 0L; nX < nWidth; nX++ ) 1780 { 1781 const BitmapColor& rCol = pRAcc->GetPaletteColor( pRAcc->GetPixel( nY, nX ) ); 1782 aDstCol.SetIndex( pIndexMap[ ( ( ( (sal_uInt32) rCol.GetRed() ) >> nRightShiftBits ) << nLeftShiftBits2 ) | 1783 ( ( ( (sal_uInt32) rCol.GetGreen() ) >> nRightShiftBits ) << nLeftShiftBits1 ) | 1784 ( ( (sal_uInt32) rCol.GetBlue() ) >> nRightShiftBits ) ] ); 1785 pWAcc->SetPixel( nY, nX, aDstCol ); 1786 } 1787 } 1788 } 1789 else 1790 { 1791 for( nY = 0L; nY < nHeight; nY++ ) 1792 { 1793 for( nX = 0L; nX < nWidth; nX++ ) 1794 { 1795 const BitmapColor aCol( pRAcc->GetPixel( nY, nX ) ); 1796 aDstCol.SetIndex( pIndexMap[ ( ( ( (sal_uInt32) aCol.GetRed() ) >> nRightShiftBits ) << nLeftShiftBits2 ) | 1797 ( ( ( (sal_uInt32) aCol.GetGreen() ) >> nRightShiftBits ) << nLeftShiftBits1 ) | 1798 ( ( (sal_uInt32) aCol.GetBlue() ) >> nRightShiftBits ) ] ); 1799 pWAcc->SetPixel( nY, nX, aDstCol ); 1800 } 1801 } 1802 } 1803 1804 delete[] pIndexMap; 1805 aNewBmp.ReleaseAccess( pWAcc ); 1806 bRet = sal_True; 1807 } 1808 1809 delete[] pCountTable; 1810 ReleaseAccess( pRAcc ); 1811 1812 if( bRet ) 1813 { 1814 const MapMode aMap( maPrefMapMode ); 1815 const Size aSize( maPrefSize ); 1816 1817 *this = aNewBmp; 1818 maPrefMapMode = aMap; 1819 maPrefSize = aSize; 1820 } 1821 } 1822 1823 return bRet; 1824 } 1825 1826 // ------------------------------------------------------------------------ 1827 1828 sal_Bool Bitmap::ImplReduceMedian( sal_uInt16 nColCount ) 1829 { 1830 BitmapReadAccess* pRAcc = AcquireReadAccess(); 1831 sal_uInt16 nBitCount; 1832 sal_Bool bRet = sal_False; 1833 1834 if( nColCount < 17 ) 1835 nBitCount = 4; 1836 else if( nColCount < 257 ) 1837 nBitCount = 8; 1838 else 1839 { 1840 DBG_ERROR( "Bitmap::ImplReduceMedian(): invalid color count!" ); 1841 nBitCount = 8; 1842 nColCount = 256; 1843 } 1844 1845 if( pRAcc ) 1846 { 1847 Bitmap aNewBmp( GetSizePixel(), nBitCount ); 1848 BitmapWriteAccess* pWAcc = aNewBmp.AcquireWriteAccess(); 1849 1850 if( pWAcc ) 1851 { 1852 const sal_uLong nSize = 32768UL * sizeof( sal_uLong ); 1853 sal_uLong* pColBuf = (sal_uLong*) rtl_allocateMemory( nSize ); 1854 const long nWidth = pWAcc->Width(); 1855 const long nHeight = pWAcc->Height(); 1856 long nIndex = 0L; 1857 1858 memset( (HPBYTE) pColBuf, 0, nSize ); 1859 1860 // create Buffer 1861 if( pRAcc->HasPalette() ) 1862 { 1863 for( long nY = 0L; nY < nHeight; nY++ ) 1864 { 1865 for( long nX = 0L; nX < nWidth; nX++ ) 1866 { 1867 const BitmapColor& rCol = pRAcc->GetPaletteColor( pRAcc->GetPixel( nY, nX ) ); 1868 pColBuf[ RGB15( rCol.GetRed() >> 3, rCol.GetGreen() >> 3, rCol.GetBlue() >> 3 ) ]++; 1869 } 1870 } 1871 } 1872 else 1873 { 1874 for( long nY = 0L; nY < nHeight; nY++ ) 1875 { 1876 for( long nX = 0L; nX < nWidth; nX++ ) 1877 { 1878 const BitmapColor aCol( pRAcc->GetPixel( nY, nX ) ); 1879 pColBuf[ RGB15( aCol.GetRed() >> 3, aCol.GetGreen() >> 3, aCol.GetBlue() >> 3 ) ]++; 1880 } 1881 } 1882 } 1883 1884 // create palette via median cut 1885 BitmapPalette aPal( pWAcc->GetPaletteEntryCount() ); 1886 ImplMedianCut( pColBuf, aPal, 0, 31, 0, 31, 0, 31, 1887 nColCount, nWidth * nHeight, nIndex ); 1888 1889 // do mapping of colors to palette 1890 InverseColorMap aMap( aPal ); 1891 pWAcc->SetPalette( aPal ); 1892 for( long nY = 0L; nY < nHeight; nY++ ) 1893 for( long nX = 0L; nX < nWidth; nX++ ) 1894 pWAcc->SetPixel( nY, nX, (sal_uInt8) aMap.GetBestPaletteIndex( pRAcc->GetColor( nY, nX ) ) ); 1895 1896 rtl_freeMemory( pColBuf ); 1897 aNewBmp.ReleaseAccess( pWAcc ); 1898 bRet = sal_True; 1899 } 1900 1901 ReleaseAccess( pRAcc ); 1902 1903 if( bRet ) 1904 { 1905 const MapMode aMap( maPrefMapMode ); 1906 const Size aSize( maPrefSize ); 1907 1908 *this = aNewBmp; 1909 maPrefMapMode = aMap; 1910 maPrefSize = aSize; 1911 } 1912 } 1913 1914 return bRet; 1915 } 1916 1917 // ------------------------------------------------------------------------ 1918 1919 void Bitmap::ImplMedianCut( sal_uLong* pColBuf, BitmapPalette& rPal, 1920 long nR1, long nR2, long nG1, long nG2, long nB1, long nB2, 1921 long nColors, long nPixels, long& rIndex ) 1922 { 1923 if( !nPixels ) 1924 return; 1925 1926 BitmapColor aCol; 1927 const long nRLen = nR2 - nR1; 1928 const long nGLen = nG2 - nG1; 1929 const long nBLen = nB2 - nB1; 1930 long nR, nG, nB; 1931 sal_uLong* pBuf = pColBuf; 1932 1933 if( !nRLen && !nGLen && !nBLen ) 1934 { 1935 if( pBuf[ RGB15( nR1, nG1, nB1 ) ] ) 1936 { 1937 aCol.SetRed( (sal_uInt8) ( nR1 << 3 ) ); 1938 aCol.SetGreen( (sal_uInt8) ( nG1 << 3 ) ); 1939 aCol.SetBlue( (sal_uInt8) ( nB1 << 3 ) ); 1940 rPal[ (sal_uInt16) rIndex++ ] = aCol; 1941 } 1942 } 1943 else 1944 { 1945 if( 1 == nColors || 1 == nPixels ) 1946 { 1947 long nPixSum = 0, nRSum = 0, nGSum = 0, nBSum = 0; 1948 1949 for( nR = nR1; nR <= nR2; nR++ ) 1950 { 1951 for( nG = nG1; nG <= nG2; nG++ ) 1952 { 1953 for( nB = nB1; nB <= nB2; nB++ ) 1954 { 1955 nPixSum = pBuf[ RGB15( nR, nG, nB ) ]; 1956 1957 if( nPixSum ) 1958 { 1959 nRSum += nR * nPixSum; 1960 nGSum += nG * nPixSum; 1961 nBSum += nB * nPixSum; 1962 } 1963 } 1964 } 1965 } 1966 1967 aCol.SetRed( (sal_uInt8) ( ( nRSum / nPixels ) << 3 ) ); 1968 aCol.SetGreen( (sal_uInt8) ( ( nGSum / nPixels ) << 3 ) ); 1969 aCol.SetBlue( (sal_uInt8) ( ( nBSum / nPixels ) << 3 ) ); 1970 rPal[ (sal_uInt16) rIndex++ ] = aCol; 1971 } 1972 else 1973 { 1974 const long nTest = ( nPixels >> 1 ); 1975 long nPixOld = 0; 1976 long nPixNew = 0; 1977 1978 if( nBLen > nGLen && nBLen > nRLen ) 1979 { 1980 nB = nB1 - 1; 1981 1982 while( nPixNew < nTest ) 1983 { 1984 nB++, nPixOld = nPixNew; 1985 for( nR = nR1; nR <= nR2; nR++ ) 1986 for( nG = nG1; nG <= nG2; nG++ ) 1987 nPixNew += pBuf[ RGB15( nR, nG, nB ) ]; 1988 } 1989 1990 if( nB < nB2 ) 1991 { 1992 ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG2, nB1, nB, nColors >> 1, nPixNew, rIndex ); 1993 ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG2, nB + 1, nB2, nColors >> 1, nPixels - nPixNew, rIndex ); 1994 } 1995 else 1996 { 1997 ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG2, nB1, nB - 1, nColors >> 1, nPixOld, rIndex ); 1998 ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG2, nB, nB2, nColors >> 1, nPixels - nPixOld, rIndex ); 1999 } 2000 } 2001 else if( nGLen > nRLen ) 2002 { 2003 nG = nG1 - 1; 2004 2005 while( nPixNew < nTest ) 2006 { 2007 nG++, nPixOld = nPixNew; 2008 for( nR = nR1; nR <= nR2; nR++ ) 2009 for( nB = nB1; nB <= nB2; nB++ ) 2010 nPixNew += pBuf[ RGB15( nR, nG, nB ) ]; 2011 } 2012 2013 if( nG < nG2 ) 2014 { 2015 ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG, nB1, nB2, nColors >> 1, nPixNew, rIndex ); 2016 ImplMedianCut( pBuf, rPal, nR1, nR2, nG + 1, nG2, nB1, nB2, nColors >> 1, nPixels - nPixNew, rIndex ); 2017 } 2018 else 2019 { 2020 ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG - 1, nB1, nB2, nColors >> 1, nPixOld, rIndex ); 2021 ImplMedianCut( pBuf, rPal, nR1, nR2, nG, nG2, nB1, nB2, nColors >> 1, nPixels - nPixOld, rIndex ); 2022 } 2023 } 2024 else 2025 { 2026 nR = nR1 - 1; 2027 2028 while( nPixNew < nTest ) 2029 { 2030 nR++, nPixOld = nPixNew; 2031 for( nG = nG1; nG <= nG2; nG++ ) 2032 for( nB = nB1; nB <= nB2; nB++ ) 2033 nPixNew += pBuf[ RGB15( nR, nG, nB ) ]; 2034 } 2035 2036 if( nR < nR2 ) 2037 { 2038 ImplMedianCut( pBuf, rPal, nR1, nR, nG1, nG2, nB1, nB2, nColors >> 1, nPixNew, rIndex ); 2039 ImplMedianCut( pBuf, rPal, nR1 + 1, nR2, nG1, nG2, nB1, nB2, nColors >> 1, nPixels - nPixNew, rIndex ); 2040 } 2041 else 2042 { 2043 ImplMedianCut( pBuf, rPal, nR1, nR - 1, nG1, nG2, nB1, nB2, nColors >> 1, nPixOld, rIndex ); 2044 ImplMedianCut( pBuf, rPal, nR, nR2, nG1, nG2, nB1, nB2, nColors >> 1, nPixels - nPixOld, rIndex ); 2045 } 2046 } 2047 } 2048 } 2049 } 2050 2051 // ------------------------------------------------------------------------ 2052 2053 sal_Bool Bitmap::Vectorize( PolyPolygon& rPolyPoly, sal_uLong nFlags, const Link* pProgress ) 2054 { 2055 return ImplVectorizer().ImplVectorize( *this, rPolyPoly, nFlags, pProgress ); 2056 } 2057 2058 // ------------------------------------------------------------------------ 2059 2060 sal_Bool Bitmap::Vectorize( GDIMetaFile& rMtf, sal_uInt8 cReduce, sal_uLong nFlags, const Link* pProgress ) 2061 { 2062 return ImplVectorizer().ImplVectorize( *this, rMtf, cReduce, nFlags, pProgress ); 2063 } 2064 2065 // ------------------------------------------------------------------------ 2066 2067 sal_Bool Bitmap::Adjust( short nLuminancePercent, short nContrastPercent, 2068 short nChannelRPercent, short nChannelGPercent, short nChannelBPercent, 2069 double fGamma, sal_Bool bInvert ) 2070 { 2071 sal_Bool bRet = sal_False; 2072 2073 // nothing to do => return quickly 2074 if( !nLuminancePercent && !nContrastPercent && 2075 !nChannelRPercent && !nChannelGPercent && !nChannelBPercent && 2076 ( fGamma == 1.0 ) && !bInvert ) 2077 { 2078 bRet = sal_True; 2079 } 2080 else 2081 { 2082 BitmapWriteAccess* pAcc = AcquireWriteAccess(); 2083 2084 if( pAcc ) 2085 { 2086 BitmapColor aCol; 2087 const long nW = pAcc->Width(); 2088 const long nH = pAcc->Height(); 2089 sal_uInt8* cMapR = new sal_uInt8[ 256 ]; 2090 sal_uInt8* cMapG = new sal_uInt8[ 256 ]; 2091 sal_uInt8* cMapB = new sal_uInt8[ 256 ]; 2092 long nX, nY; 2093 double fM, fROff, fGOff, fBOff, fOff; 2094 2095 // calculate slope 2096 if( nContrastPercent >= 0 ) 2097 fM = 128.0 / ( 128.0 - 1.27 * MinMax( nContrastPercent, 0L, 100L ) ); 2098 else 2099 fM = ( 128.0 + 1.27 * MinMax( nContrastPercent, -100L, 0L ) ) / 128.0; 2100 2101 // total offset = luminance offset + contrast offset 2102 fOff = MinMax( nLuminancePercent, -100L, 100L ) * 2.55 + 128.0 - fM * 128.0; 2103 2104 // channel offset = channel offset + total offset 2105 fROff = nChannelRPercent * 2.55 + fOff; 2106 fGOff = nChannelGPercent * 2.55 + fOff; 2107 fBOff = nChannelBPercent * 2.55 + fOff; 2108 2109 // calculate gamma value 2110 fGamma = ( fGamma <= 0.0 || fGamma > 10.0 ) ? 1.0 : ( 1.0 / fGamma ); 2111 const sal_Bool bGamma = ( fGamma != 1.0 ); 2112 2113 // create mapping table 2114 for( nX = 0L; nX < 256L; nX++ ) 2115 { 2116 cMapR[ nX ] = (sal_uInt8) MinMax( FRound( nX * fM + fROff ), 0L, 255L ); 2117 cMapG[ nX ] = (sal_uInt8) MinMax( FRound( nX * fM + fGOff ), 0L, 255L ); 2118 cMapB[ nX ] = (sal_uInt8) MinMax( FRound( nX * fM + fBOff ), 0L, 255L ); 2119 2120 if( bGamma ) 2121 { 2122 cMapR[ nX ] = GAMMA( cMapR[ nX ], fGamma ); 2123 cMapG[ nX ] = GAMMA( cMapG[ nX ], fGamma ); 2124 cMapB[ nX ] = GAMMA( cMapB[ nX ], fGamma ); 2125 } 2126 2127 if( bInvert ) 2128 { 2129 cMapR[ nX ] = ~cMapR[ nX ]; 2130 cMapG[ nX ] = ~cMapG[ nX ]; 2131 cMapB[ nX ] = ~cMapB[ nX ]; 2132 } 2133 } 2134 2135 // do modifying 2136 if( pAcc->HasPalette() ) 2137 { 2138 BitmapColor aNewCol; 2139 2140 for( sal_uInt16 i = 0, nCount = pAcc->GetPaletteEntryCount(); i < nCount; i++ ) 2141 { 2142 const BitmapColor& rCol = pAcc->GetPaletteColor( i ); 2143 aNewCol.SetRed( cMapR[ rCol.GetRed() ] ); 2144 aNewCol.SetGreen( cMapG[ rCol.GetGreen() ] ); 2145 aNewCol.SetBlue( cMapB[ rCol.GetBlue() ] ); 2146 pAcc->SetPaletteColor( i, aNewCol ); 2147 } 2148 } 2149 else if( pAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_BGR ) 2150 { 2151 for( nY = 0L; nY < nH; nY++ ) 2152 { 2153 Scanline pScan = pAcc->GetScanline( nY ); 2154 2155 for( nX = 0L; nX < nW; nX++ ) 2156 { 2157 *pScan = cMapB[ *pScan ]; pScan++; 2158 *pScan = cMapG[ *pScan ]; pScan++; 2159 *pScan = cMapR[ *pScan ]; pScan++; 2160 } 2161 } 2162 } 2163 else if( pAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_RGB ) 2164 { 2165 for( nY = 0L; nY < nH; nY++ ) 2166 { 2167 Scanline pScan = pAcc->GetScanline( nY ); 2168 2169 for( nX = 0L; nX < nW; nX++ ) 2170 { 2171 *pScan = cMapR[ *pScan ]; pScan++; 2172 *pScan = cMapG[ *pScan ]; pScan++; 2173 *pScan = cMapB[ *pScan ]; pScan++; 2174 } 2175 } 2176 } 2177 else 2178 { 2179 for( nY = 0L; nY < nH; nY++ ) 2180 { 2181 for( nX = 0L; nX < nW; nX++ ) 2182 { 2183 aCol = pAcc->GetPixel( nY, nX ); 2184 aCol.SetRed( cMapR[ aCol.GetRed() ] ); 2185 aCol.SetGreen( cMapG[ aCol.GetGreen() ] ); 2186 aCol.SetBlue( cMapB[ aCol.GetBlue() ] ); 2187 pAcc->SetPixel( nY, nX, aCol ); 2188 } 2189 } 2190 } 2191 2192 delete[] cMapR; 2193 delete[] cMapG; 2194 delete[] cMapB; 2195 ReleaseAccess( pAcc ); 2196 bRet = sal_True; 2197 } 2198 } 2199 2200 return bRet; 2201 } 2202