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 if ( !pReadAcc ) 955 return sal_False; 956 957 Bitmap aNewBmp( Size( nNewWidth, nNewHeight ), GetBitCount(), &pReadAcc->GetPalette() ); 958 BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess(); 959 960 if( pWriteAcc ) 961 { 962 const long nScanlineSize = pWriteAcc->GetScanlineSize(); 963 const long nNewWidth1 = nNewWidth - 1L; 964 const long nNewHeight1 = nNewHeight - 1L; 965 const long nWidth = pReadAcc->Width(); 966 const long nHeight = pReadAcc->Height(); 967 long* pLutX = new long[ nNewWidth ]; 968 long* pLutY = new long[ nNewHeight ]; 969 long nX, nY, nMapY, nActY = 0L; 970 971 if( nNewWidth1 && nNewHeight1 ) 972 { 973 for( nX = 0L; nX < nNewWidth; nX++ ) 974 pLutX[ nX ] = nX * nWidth / nNewWidth; 975 976 for( nY = 0L; nY < nNewHeight; nY++ ) 977 pLutY[ nY ] = nY * nHeight / nNewHeight; 978 979 while( nActY < nNewHeight ) 980 { 981 nMapY = pLutY[ nActY ]; 982 983 for( nX = 0L; nX < nNewWidth; nX++ ) 984 pWriteAcc->SetPixel( nActY, nX, pReadAcc->GetPixel( nMapY , pLutX[ nX ] ) ); 985 986 while( ( nActY < nNewHeight1 ) && ( pLutY[ nActY + 1 ] == nMapY ) ) 987 { 988 memcpy( pWriteAcc->GetScanline( nActY + 1L ), 989 pWriteAcc->GetScanline( nActY ), nScanlineSize ); 990 nActY++; 991 } 992 993 nActY++; 994 } 995 996 bRet = sal_True; 997 } 998 999 delete[] pLutX; 1000 delete[] pLutY; 1001 } 1002 1003 ReleaseAccess( pReadAcc ); 1004 aNewBmp.ReleaseAccess( pWriteAcc ); 1005 1006 if( bRet ) 1007 ImplAssignWithSize( aNewBmp ); 1008 } 1009 1010 return bRet; 1011 } 1012 1013 // ------------------------------------------------------------------------ 1014 1015 sal_Bool Bitmap::ImplScaleInterpolate( const double& rScaleX, const double& rScaleY ) 1016 { 1017 const Size aSizePix( GetSizePixel() ); 1018 const long nNewWidth = FRound( aSizePix.Width() * rScaleX ); 1019 const long nNewHeight = FRound( aSizePix.Height() * rScaleY ); 1020 sal_Bool bRet = sal_False; 1021 1022 if( ( nNewWidth > 1L ) && ( nNewHeight > 1L ) ) 1023 { 1024 BitmapColor aCol0; 1025 BitmapColor aCol1; 1026 BitmapReadAccess* pReadAcc = AcquireReadAccess(); 1027 long nWidth = pReadAcc->Width(); 1028 long nHeight = pReadAcc->Height(); 1029 Bitmap aNewBmp( Size( nNewWidth, nHeight ), 24 ); 1030 BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess(); 1031 long* pLutInt; 1032 long* pLutFrac; 1033 long nX, nY; 1034 long lXB0, lXB1, lXG0, lXG1, lXR0, lXR1; 1035 double fTemp; 1036 long nTemp; 1037 1038 if( pReadAcc && pWriteAcc ) 1039 { 1040 const long nNewWidth1 = nNewWidth - 1L; 1041 const long nWidth1 = pReadAcc->Width() - 1L; 1042 const double fRevScaleX = (double) nWidth1 / nNewWidth1; 1043 1044 pLutInt = new long[ nNewWidth ]; 1045 pLutFrac = new long[ nNewWidth ]; 1046 1047 for( nX = 0L, nTemp = nWidth - 2L; nX < nNewWidth; nX++ ) 1048 { 1049 fTemp = nX * fRevScaleX; 1050 pLutInt[ nX ] = MinMax( (long) fTemp, 0, nTemp ); 1051 fTemp -= pLutInt[ nX ]; 1052 pLutFrac[ nX ] = (long) ( fTemp * 1024. ); 1053 } 1054 1055 if( pReadAcc->HasPalette() ) 1056 { 1057 for( nY = 0L; nY < nHeight; nY++ ) 1058 { 1059 if( 1 == nWidth ) 1060 { 1061 aCol0 = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nY, 0 ) ); 1062 1063 for( nX = 0L; nX < nNewWidth; nX++ ) 1064 pWriteAcc->SetPixel( nY, nX, aCol0 ); 1065 } 1066 else 1067 { 1068 for( nX = 0L; nX < nNewWidth; nX++ ) 1069 { 1070 nTemp = pLutInt[ nX ]; 1071 1072 aCol0 = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nY, nTemp++ ) ); 1073 aCol1 = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nY, nTemp ) ); 1074 1075 nTemp = pLutFrac[ nX ]; 1076 1077 lXR1 = aCol1.GetRed() - ( lXR0 = aCol0.GetRed() ); 1078 lXG1 = aCol1.GetGreen() - ( lXG0 = aCol0.GetGreen() ); 1079 lXB1 = aCol1.GetBlue() - ( lXB0 = aCol0.GetBlue() ); 1080 1081 aCol0.SetRed( (sal_uInt8) ( ( lXR1 * nTemp + ( lXR0 << 10 ) ) >> 10 ) ); 1082 aCol0.SetGreen( (sal_uInt8) ( ( lXG1 * nTemp + ( lXG0 << 10 ) ) >> 10 ) ); 1083 aCol0.SetBlue( (sal_uInt8) ( ( lXB1 * nTemp + ( lXB0 << 10 ) ) >> 10 ) ); 1084 1085 pWriteAcc->SetPixel( nY, nX, aCol0 ); 1086 } 1087 } 1088 } 1089 } 1090 else 1091 { 1092 for( nY = 0L; nY < nHeight; nY++ ) 1093 { 1094 if( 1 == nWidth ) 1095 { 1096 aCol0 = pReadAcc->GetPixel( nY, 0 ); 1097 1098 for( nX = 0L; nX < nNewWidth; nX++ ) 1099 pWriteAcc->SetPixel( nY, nX, aCol0 ); 1100 } 1101 else 1102 { 1103 for( nX = 0L; nX < nNewWidth; nX++ ) 1104 { 1105 nTemp = pLutInt[ nX ]; 1106 1107 aCol0 = pReadAcc->GetPixel( nY, nTemp++ ); 1108 aCol1 = pReadAcc->GetPixel( nY, nTemp ); 1109 1110 nTemp = pLutFrac[ nX ]; 1111 1112 lXR1 = aCol1.GetRed() - ( lXR0 = aCol0.GetRed() ); 1113 lXG1 = aCol1.GetGreen() - ( lXG0 = aCol0.GetGreen() ); 1114 lXB1 = aCol1.GetBlue() - ( lXB0 = aCol0.GetBlue() ); 1115 1116 aCol0.SetRed( (sal_uInt8) ( ( lXR1 * nTemp + ( lXR0 << 10 ) ) >> 10 ) ); 1117 aCol0.SetGreen( (sal_uInt8) ( ( lXG1 * nTemp + ( lXG0 << 10 ) ) >> 10 ) ); 1118 aCol0.SetBlue( (sal_uInt8) ( ( lXB1 * nTemp + ( lXB0 << 10 ) ) >> 10 ) ); 1119 1120 pWriteAcc->SetPixel( nY, nX, aCol0 ); 1121 } 1122 } 1123 } 1124 } 1125 1126 delete[] pLutInt; 1127 delete[] pLutFrac; 1128 bRet = sal_True; 1129 } 1130 1131 ReleaseAccess( pReadAcc ); 1132 aNewBmp.ReleaseAccess( pWriteAcc ); 1133 1134 if( bRet ) 1135 { 1136 bRet = sal_False; 1137 ImplAssignWithSize( aNewBmp ); 1138 pReadAcc = AcquireReadAccess(); 1139 aNewBmp = Bitmap( Size( nNewWidth, nNewHeight ), 24 ); 1140 pWriteAcc = aNewBmp.AcquireWriteAccess(); 1141 1142 if( pReadAcc && pWriteAcc ) 1143 { 1144 const long nNewHeight1 = nNewHeight - 1L; 1145 const long nHeight1 = pReadAcc->Height() - 1L; 1146 const double fRevScaleY = (double) nHeight1 / nNewHeight1; 1147 1148 pLutInt = new long[ nNewHeight ]; 1149 pLutFrac = new long[ nNewHeight ]; 1150 1151 for( nY = 0L, nTemp = nHeight - 2L; nY < nNewHeight; nY++ ) 1152 { 1153 fTemp = nY * fRevScaleY; 1154 pLutInt[ nY ] = MinMax( (long) fTemp, 0, nTemp ); 1155 fTemp -= pLutInt[ nY ]; 1156 pLutFrac[ nY ] = (long) ( fTemp * 1024. ); 1157 } 1158 1159 if( pReadAcc->HasPalette() ) 1160 { 1161 for( nX = 0L; nX < nNewWidth; nX++ ) 1162 { 1163 if( 1 == nHeight ) 1164 { 1165 aCol0 = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( 0, nX ) ); 1166 1167 for( nY = 0L; nY < nNewHeight; nY++ ) 1168 pWriteAcc->SetPixel( nY, nX, aCol0 ); 1169 } 1170 else 1171 { 1172 for( nY = 0L; nY < nNewHeight; nY++ ) 1173 { 1174 nTemp = pLutInt[ nY ]; 1175 1176 aCol0 = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nTemp++, nX ) ); 1177 aCol1 = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nTemp, nX ) ); 1178 1179 nTemp = pLutFrac[ nY ]; 1180 1181 lXR1 = aCol1.GetRed() - ( lXR0 = aCol0.GetRed() ); 1182 lXG1 = aCol1.GetGreen() - ( lXG0 = aCol0.GetGreen() ); 1183 lXB1 = aCol1.GetBlue() - ( lXB0 = aCol0.GetBlue() ); 1184 1185 aCol0.SetRed( (sal_uInt8) ( ( lXR1 * nTemp + ( lXR0 << 10 ) ) >> 10 ) ); 1186 aCol0.SetGreen( (sal_uInt8) ( ( lXG1 * nTemp + ( lXG0 << 10 ) ) >> 10 ) ); 1187 aCol0.SetBlue( (sal_uInt8) ( ( lXB1 * nTemp + ( lXB0 << 10 ) ) >> 10 ) ); 1188 1189 pWriteAcc->SetPixel( nY, nX, aCol0 ); 1190 } 1191 } 1192 } 1193 } 1194 else 1195 { 1196 for( nX = 0L; nX < nNewWidth; nX++ ) 1197 { 1198 if( 1 == nHeight ) 1199 { 1200 aCol0 = pReadAcc->GetPixel( 0, nX ); 1201 1202 for( nY = 0L; nY < nNewHeight; nY++ ) 1203 pWriteAcc->SetPixel( nY, nX, aCol0 ); 1204 } 1205 else 1206 { 1207 for( nY = 0L; nY < nNewHeight; nY++ ) 1208 { 1209 nTemp = pLutInt[ nY ]; 1210 1211 aCol0 = pReadAcc->GetPixel( nTemp++, nX ); 1212 aCol1 = pReadAcc->GetPixel( nTemp, nX ); 1213 1214 nTemp = pLutFrac[ nY ]; 1215 1216 lXR1 = aCol1.GetRed() - ( lXR0 = aCol0.GetRed() ); 1217 lXG1 = aCol1.GetGreen() - ( lXG0 = aCol0.GetGreen() ); 1218 lXB1 = aCol1.GetBlue() - ( lXB0 = aCol0.GetBlue() ); 1219 1220 aCol0.SetRed( (sal_uInt8) ( ( lXR1 * nTemp + ( lXR0 << 10 ) ) >> 10 ) ); 1221 aCol0.SetGreen( (sal_uInt8) ( ( lXG1 * nTemp + ( lXG0 << 10 ) ) >> 10 ) ); 1222 aCol0.SetBlue( (sal_uInt8) ( ( lXB1 * nTemp + ( lXB0 << 10 ) ) >> 10 ) ); 1223 1224 pWriteAcc->SetPixel( nY, nX, aCol0 ); 1225 } 1226 } 1227 } 1228 } 1229 1230 delete[] pLutInt; 1231 delete[] pLutFrac; 1232 bRet = sal_True; 1233 } 1234 1235 ReleaseAccess( pReadAcc ); 1236 aNewBmp.ReleaseAccess( pWriteAcc ); 1237 1238 if( bRet ) 1239 ImplAssignWithSize( aNewBmp ); 1240 } 1241 } 1242 1243 if( !bRet ) 1244 bRet = ImplScaleFast( rScaleX, rScaleY ); 1245 1246 return bRet; 1247 } 1248 1249 // ------------------------------------------------------------------------ 1250 1251 sal_Bool Bitmap::Dither( sal_uLong nDitherFlags ) 1252 { 1253 sal_Bool bRet = sal_False; 1254 1255 const Size aSizePix( GetSizePixel() ); 1256 1257 if( aSizePix.Width() == 1 || aSizePix.Height() == 1 ) 1258 bRet = sal_True; 1259 else if( nDitherFlags & BMP_DITHER_MATRIX ) 1260 bRet = ImplDitherMatrix(); 1261 else if( nDitherFlags & BMP_DITHER_FLOYD ) 1262 bRet = ImplDitherFloyd(); 1263 else if( ( nDitherFlags & BMP_DITHER_FLOYD_16 ) && ( GetBitCount() == 24 ) ) 1264 bRet = ImplDitherFloyd16(); 1265 1266 return bRet; 1267 } 1268 1269 // ------------------------------------------------------------------------ 1270 1271 sal_Bool Bitmap::ImplDitherMatrix() 1272 { 1273 BitmapReadAccess* pReadAcc = AcquireReadAccess(); 1274 Bitmap aNewBmp( GetSizePixel(), 8 ); 1275 BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess(); 1276 sal_Bool bRet = sal_False; 1277 1278 if( pReadAcc && pWriteAcc ) 1279 { 1280 const sal_uLong nWidth = pReadAcc->Width(); 1281 const sal_uLong nHeight = pReadAcc->Height(); 1282 BitmapColor aIndex( (sal_uInt8) 0 ); 1283 1284 if( pReadAcc->HasPalette() ) 1285 { 1286 for( sal_uLong nY = 0UL; nY < nHeight; nY++ ) 1287 { 1288 for( sal_uLong nX = 0UL, nModY = ( nY & 0x0FUL ) << 4UL; nX < nWidth; nX++ ) 1289 { 1290 const BitmapColor aCol( pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nY, nX ) ) ); 1291 const sal_uLong nD = nVCLDitherLut[ nModY + ( nX & 0x0FUL ) ]; 1292 const sal_uLong nR = ( nVCLLut[ aCol.GetRed() ] + nD ) >> 16UL; 1293 const sal_uLong nG = ( nVCLLut[ aCol.GetGreen() ] + nD ) >> 16UL; 1294 const sal_uLong nB = ( nVCLLut[ aCol.GetBlue() ] + nD ) >> 16UL; 1295 1296 aIndex.SetIndex( (sal_uInt8) ( nVCLRLut[ nR ] + nVCLGLut[ nG ] + nVCLBLut[ nB ] ) ); 1297 pWriteAcc->SetPixel( nY, nX, aIndex ); 1298 } 1299 } 1300 } 1301 else 1302 { 1303 for( sal_uLong nY = 0UL; nY < nHeight; nY++ ) 1304 { 1305 for( sal_uLong nX = 0UL, nModY = ( nY & 0x0FUL ) << 4UL; nX < nWidth; nX++ ) 1306 { 1307 const BitmapColor aCol( pReadAcc->GetPixel( nY, nX ) ); 1308 const sal_uLong nD = nVCLDitherLut[ nModY + ( nX & 0x0FUL ) ]; 1309 const sal_uLong nR = ( nVCLLut[ aCol.GetRed() ] + nD ) >> 16UL; 1310 const sal_uLong nG = ( nVCLLut[ aCol.GetGreen() ] + nD ) >> 16UL; 1311 const sal_uLong nB = ( nVCLLut[ aCol.GetBlue() ] + nD ) >> 16UL; 1312 1313 aIndex.SetIndex( (sal_uInt8) ( nVCLRLut[ nR ] + nVCLGLut[ nG ] + nVCLBLut[ nB ] ) ); 1314 pWriteAcc->SetPixel( nY, nX, aIndex ); 1315 } 1316 } 1317 } 1318 1319 bRet = sal_True; 1320 } 1321 1322 ReleaseAccess( pReadAcc ); 1323 aNewBmp.ReleaseAccess( pWriteAcc ); 1324 1325 if( bRet ) 1326 { 1327 const MapMode aMap( maPrefMapMode ); 1328 const Size aSize( maPrefSize ); 1329 1330 *this = aNewBmp; 1331 1332 maPrefMapMode = aMap; 1333 maPrefSize = aSize; 1334 } 1335 1336 return bRet; 1337 } 1338 1339 // ------------------------------------------------------------------------ 1340 1341 sal_Bool Bitmap::ImplDitherFloyd() 1342 { 1343 const Size aSize( GetSizePixel() ); 1344 sal_Bool bRet = sal_False; 1345 1346 if( ( aSize.Width() > 3 ) && ( aSize.Height() > 2 ) ) 1347 { 1348 BitmapReadAccess* pReadAcc = AcquireReadAccess(); 1349 Bitmap aNewBmp( GetSizePixel(), 8 ); 1350 BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess(); 1351 1352 if( pReadAcc && pWriteAcc ) 1353 { 1354 BitmapColor aColor; 1355 long nWidth = pReadAcc->Width(); 1356 long nWidth1 = nWidth - 1L; 1357 long nHeight = pReadAcc->Height(); 1358 long nX; 1359 long nW = nWidth * 3L; 1360 long nW2 = nW - 3L; 1361 long nRErr, nGErr, nBErr; 1362 long nRC, nGC, nBC; 1363 long nTemp; 1364 long nZ; 1365 long* p1 = new long[ nW ]; 1366 long* p2 = new long[ nW ]; 1367 long* p1T = p1; 1368 long* p2T = p2; 1369 long* pTmp; 1370 sal_Bool bPal = pReadAcc->HasPalette(); 1371 1372 pTmp = p2T; 1373 1374 if( bPal ) 1375 { 1376 for( nZ = 0; nZ < nWidth; nZ++ ) 1377 { 1378 aColor = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( 0, nZ ) ); 1379 1380 *pTmp++ = (long) aColor.GetBlue() << 12; 1381 *pTmp++ = (long) aColor.GetGreen() << 12; 1382 *pTmp++ = (long) aColor.GetRed() << 12; 1383 } 1384 } 1385 else 1386 { 1387 for( nZ = 0; nZ < nWidth; nZ++ ) 1388 { 1389 aColor = pReadAcc->GetPixel( 0, nZ ); 1390 1391 *pTmp++ = (long) aColor.GetBlue() << 12; 1392 *pTmp++ = (long) aColor.GetGreen() << 12; 1393 *pTmp++ = (long) aColor.GetRed() << 12; 1394 } 1395 } 1396 1397 for( long nY = 1, nYAcc = 0L; nY <= nHeight; nY++, nYAcc++ ) 1398 { 1399 pTmp = p1T; 1400 p1T = p2T; 1401 p2T = pTmp; 1402 1403 if( nY < nHeight ) 1404 { 1405 if( bPal ) 1406 { 1407 for( nZ = 0; nZ < nWidth; nZ++ ) 1408 { 1409 aColor = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( nY, nZ ) ); 1410 1411 *pTmp++ = (long) aColor.GetBlue() << 12; 1412 *pTmp++ = (long) aColor.GetGreen() << 12; 1413 *pTmp++ = (long) aColor.GetRed() << 12; 1414 } 1415 } 1416 else 1417 { 1418 for( nZ = 0; nZ < nWidth; nZ++ ) 1419 { 1420 aColor = pReadAcc->GetPixel( nY, nZ ); 1421 1422 *pTmp++ = (long) aColor.GetBlue() << 12; 1423 *pTmp++ = (long) aColor.GetGreen() << 12; 1424 *pTmp++ = (long) aColor.GetRed() << 12; 1425 } 1426 } 1427 } 1428 1429 // erstes Pixel gesondert betrachten 1430 nX = 0; 1431 CALC_ERRORS; 1432 CALC_TABLES7; 1433 nX -= 5; 1434 CALC_TABLES5; 1435 pWriteAcc->SetPixel( nYAcc, 0, BitmapColor( (sal_uInt8) ( nVCLBLut[ nBC ] + nVCLGLut[nGC ] + nVCLRLut[nRC ] ) ) ); 1436 1437 // mittlere Pixel ueber Schleife 1438 long nXAcc; 1439 for ( nX = 3L, nXAcc = 1L; nX < nW2; nXAcc++ ) 1440 { 1441 CALC_ERRORS; 1442 CALC_TABLES7; 1443 nX -= 8; 1444 CALC_TABLES3; 1445 CALC_TABLES5; 1446 pWriteAcc->SetPixel( nYAcc, nXAcc, BitmapColor( (sal_uInt8) ( nVCLBLut[ nBC ] + nVCLGLut[nGC ] + nVCLRLut[nRC ] ) ) ); 1447 } 1448 1449 // letztes Pixel gesondert betrachten 1450 CALC_ERRORS; 1451 nX -= 5; 1452 CALC_TABLES3; 1453 CALC_TABLES5; 1454 pWriteAcc->SetPixel( nYAcc, nWidth1, BitmapColor( (sal_uInt8) ( nVCLBLut[ nBC ] + nVCLGLut[nGC ] + nVCLRLut[nRC ] ) ) ); 1455 } 1456 1457 delete[] p1; 1458 delete[] p2; 1459 bRet = sal_True; 1460 } 1461 1462 ReleaseAccess( pReadAcc ); 1463 aNewBmp.ReleaseAccess( pWriteAcc ); 1464 1465 if( bRet ) 1466 { 1467 const MapMode aMap( maPrefMapMode ); 1468 const Size aPrefSize( maPrefSize ); 1469 1470 *this = aNewBmp; 1471 1472 maPrefMapMode = aMap; 1473 maPrefSize = aPrefSize; 1474 } 1475 } 1476 1477 return bRet; 1478 } 1479 1480 // ------------------------------------------------------------------------ 1481 1482 sal_Bool Bitmap::ImplDitherFloyd16() 1483 { 1484 BitmapReadAccess* pReadAcc = AcquireReadAccess(); 1485 Bitmap aNewBmp( GetSizePixel(), 24 ); 1486 BitmapWriteAccess* pWriteAcc = aNewBmp.AcquireWriteAccess(); 1487 sal_Bool bRet = sal_False; 1488 1489 if( pReadAcc && pWriteAcc ) 1490 { 1491 const long nWidth = pWriteAcc->Width(); 1492 const long nWidth1 = nWidth - 1L; 1493 const long nHeight = pWriteAcc->Height(); 1494 BitmapColor aColor; 1495 BitmapColor aBestCol; 1496 ImpErrorQuad aErrQuad; 1497 ImpErrorQuad* pErrQuad1 = new ImpErrorQuad[ nWidth ]; 1498 ImpErrorQuad* pErrQuad2 = new ImpErrorQuad[ nWidth ]; 1499 ImpErrorQuad* pQLine1 = pErrQuad1; 1500 ImpErrorQuad* pQLine2 = 0; 1501 long nX, nY; 1502 long nYTmp = 0L; 1503 sal_Bool bQ1 = sal_True; 1504 1505 for( nY = 0L; nY < Min( nHeight, 2L ); nY++, nYTmp++ ) 1506 for( nX = 0L, pQLine2 = !nY ? pErrQuad1 : pErrQuad2; nX < nWidth; nX++ ) 1507 pQLine2[ nX ] = pReadAcc->GetPixel( nYTmp, nX ); 1508 1509 for( nY = 0L; nY < nHeight; nY++, nYTmp++ ) 1510 { 1511 // erstes ZeilenPixel 1512 aBestCol = pQLine1[ 0 ].ImplGetColor(); 1513 aBestCol.SetRed( ( aBestCol.GetRed() & 248 ) | 7 ); 1514 aBestCol.SetGreen( ( aBestCol.GetGreen() & 248 ) | 7 ); 1515 aBestCol.SetBlue( ( aBestCol.GetBlue() & 248 ) | 7 ); 1516 pWriteAcc->SetPixel( nY, 0, aBestCol ); 1517 1518 for( nX = 1L; nX < nWidth1; nX++ ) 1519 { 1520 aColor = pQLine1[ nX ].ImplGetColor(); 1521 aBestCol.SetRed( ( aColor.GetRed() & 248 ) | 7 ); 1522 aBestCol.SetGreen( ( aColor.GetGreen() & 248 ) | 7 ); 1523 aBestCol.SetBlue( ( aColor.GetBlue() & 248 ) | 7 ); 1524 aErrQuad = ( ImpErrorQuad( aColor ) -= aBestCol ); 1525 pQLine1[ ++nX ].ImplAddColorError7( aErrQuad ); 1526 pQLine2[ nX-- ].ImplAddColorError1( aErrQuad ); 1527 pQLine2[ nX-- ].ImplAddColorError5( aErrQuad ); 1528 pQLine2[ nX++ ].ImplAddColorError3( aErrQuad ); 1529 pWriteAcc->SetPixel( nY, nX, aBestCol ); 1530 } 1531 1532 // letztes ZeilenPixel 1533 aBestCol = pQLine1[ nWidth1 ].ImplGetColor(); 1534 aBestCol.SetRed( ( aBestCol.GetRed() & 248 ) | 7 ); 1535 aBestCol.SetGreen( ( aBestCol.GetGreen() & 248 ) | 7 ); 1536 aBestCol.SetBlue( ( aBestCol.GetBlue() & 248 ) | 7 ); 1537 pWriteAcc->SetPixel( nY, nX, aBestCol ); 1538 1539 // Zeilenpuffer neu fuellen/kopieren 1540 pQLine1 = pQLine2; 1541 pQLine2 = ( bQ1 = !bQ1 ) != sal_False ? pErrQuad2 : pErrQuad1; 1542 1543 if( nYTmp < nHeight ) 1544 for( nX = 0L; nX < nWidth; nX++ ) 1545 pQLine2[ nX ] = pReadAcc->GetPixel( nYTmp, nX ); 1546 } 1547 1548 // Zeilenpuffer zerstoeren 1549 delete[] pErrQuad1; 1550 delete[] pErrQuad2; 1551 bRet = sal_True; 1552 } 1553 1554 ReleaseAccess( pReadAcc ); 1555 aNewBmp.ReleaseAccess( pWriteAcc ); 1556 1557 if( bRet ) 1558 { 1559 const MapMode aMap( maPrefMapMode ); 1560 const Size aSize( maPrefSize ); 1561 1562 *this = aNewBmp; 1563 1564 maPrefMapMode = aMap; 1565 maPrefSize = aSize; 1566 } 1567 1568 return bRet; 1569 } 1570 1571 // ------------------------------------------------------------------------ 1572 1573 sal_Bool Bitmap::ReduceColors( sal_uInt16 nColorCount, BmpReduce eReduce ) 1574 { 1575 sal_Bool bRet; 1576 1577 if( GetColorCount() <= (sal_uLong) nColorCount ) 1578 bRet = sal_True; 1579 else if( nColorCount ) 1580 { 1581 if( BMP_REDUCE_SIMPLE == eReduce ) 1582 bRet = ImplReduceSimple( nColorCount ); 1583 else if( BMP_REDUCE_POPULAR == eReduce ) 1584 bRet = ImplReducePopular( nColorCount ); 1585 else 1586 bRet = ImplReduceMedian( nColorCount ); 1587 } 1588 else 1589 bRet = sal_False; 1590 1591 return bRet; 1592 } 1593 1594 // ------------------------------------------------------------------------ 1595 1596 sal_Bool Bitmap::ImplReduceSimple( sal_uInt16 nColorCount ) 1597 { 1598 Bitmap aNewBmp; 1599 BitmapReadAccess* pRAcc = AcquireReadAccess(); 1600 const sal_uInt16 nColCount = Min( nColorCount, (sal_uInt16) 256 ); 1601 sal_uInt16 nBitCount; 1602 sal_Bool bRet = sal_False; 1603 1604 if( nColCount <= 2 ) 1605 nBitCount = 1; 1606 else if( nColCount <= 16 ) 1607 nBitCount = 4; 1608 else 1609 nBitCount = 8; 1610 1611 if( pRAcc ) 1612 { 1613 Octree aOct( *pRAcc, nColCount ); 1614 const BitmapPalette& rPal = aOct.GetPalette(); 1615 BitmapWriteAccess* pWAcc; 1616 1617 aNewBmp = Bitmap( GetSizePixel(), nBitCount, &rPal ); 1618 pWAcc = aNewBmp.AcquireWriteAccess(); 1619 1620 if( pWAcc ) 1621 { 1622 const long nWidth = pRAcc->Width(); 1623 const long nHeight = pRAcc->Height(); 1624 1625 if( pRAcc->HasPalette() ) 1626 { 1627 for( long nY = 0L; nY < nHeight; nY++ ) 1628 for( long nX =0L; nX < nWidth; nX++ ) 1629 pWAcc->SetPixel( nY, nX, (sal_uInt8) aOct.GetBestPaletteIndex( pRAcc->GetPaletteColor( pRAcc->GetPixel( nY, nX ) ) ) ); 1630 } 1631 else 1632 { 1633 for( long nY = 0L; nY < nHeight; nY++ ) 1634 for( long nX =0L; nX < nWidth; nX++ ) 1635 pWAcc->SetPixel( nY, nX, (sal_uInt8) aOct.GetBestPaletteIndex( pRAcc->GetPixel( nY, nX ) ) ); 1636 } 1637 1638 aNewBmp.ReleaseAccess( pWAcc ); 1639 bRet = sal_True; 1640 } 1641 1642 ReleaseAccess( pRAcc ); 1643 } 1644 1645 if( bRet ) 1646 { 1647 const MapMode aMap( maPrefMapMode ); 1648 const Size aSize( maPrefSize ); 1649 1650 *this = aNewBmp; 1651 maPrefMapMode = aMap; 1652 maPrefSize = aSize; 1653 } 1654 1655 return bRet; 1656 } 1657 1658 // ------------------------------------------------------------------------ 1659 1660 struct PopularColorCount 1661 { 1662 sal_uInt32 mnIndex; 1663 sal_uInt32 mnCount; 1664 }; 1665 1666 // ------------------------------------------------------------------------ 1667 1668 extern "C" int __LOADONCALLAPI ImplPopularCmpFnc( const void* p1, const void* p2 ) 1669 { 1670 int nRet; 1671 1672 if( ( (PopularColorCount*) p1 )->mnCount < ( (PopularColorCount*) p2 )->mnCount ) 1673 nRet = 1; 1674 else if( ( (PopularColorCount*) p1 )->mnCount == ( (PopularColorCount*) p2 )->mnCount ) 1675 nRet = 0; 1676 else 1677 nRet = -1; 1678 1679 return nRet; 1680 } 1681 1682 // ------------------------------------------------------------------------ 1683 1684 sal_Bool Bitmap::ImplReducePopular( sal_uInt16 nColCount ) 1685 { 1686 BitmapReadAccess* pRAcc = AcquireReadAccess(); 1687 sal_uInt16 nBitCount; 1688 sal_Bool bRet = sal_False; 1689 1690 if( nColCount > 256 ) 1691 nColCount = 256; 1692 1693 if( nColCount < 17 ) 1694 nBitCount = 4; 1695 else 1696 nBitCount = 8; 1697 1698 if( pRAcc ) 1699 { 1700 const sal_uInt32 nValidBits = 4; 1701 const sal_uInt32 nRightShiftBits = 8 - nValidBits; 1702 const sal_uInt32 nLeftShiftBits1 = nValidBits; 1703 const sal_uInt32 nLeftShiftBits2 = nValidBits << 1; 1704 const sal_uInt32 nColorsPerComponent = 1 << nValidBits; 1705 const sal_uInt32 nColorOffset = 256 / nColorsPerComponent; 1706 const sal_uInt32 nTotalColors = nColorsPerComponent * nColorsPerComponent * nColorsPerComponent; 1707 const long nWidth = pRAcc->Width(); 1708 const long nHeight = pRAcc->Height(); 1709 PopularColorCount* pCountTable = new PopularColorCount[ nTotalColors ]; 1710 long nX, nY, nR, nG, nB, nIndex; 1711 1712 rtl_zeroMemory( pCountTable, nTotalColors * sizeof( PopularColorCount ) ); 1713 1714 for( nR = 0, nIndex = 0; nR < 256; nR += nColorOffset ) 1715 { 1716 for( nG = 0; nG < 256; nG += nColorOffset ) 1717 { 1718 for( nB = 0; nB < 256; nB += nColorOffset ) 1719 { 1720 pCountTable[ nIndex ].mnIndex = nIndex; 1721 nIndex++; 1722 } 1723 } 1724 } 1725 1726 if( pRAcc->HasPalette() ) 1727 { 1728 for( nY = 0L; nY < nHeight; nY++ ) 1729 { 1730 for( nX = 0L; nX < nWidth; nX++ ) 1731 { 1732 const BitmapColor& rCol = pRAcc->GetPaletteColor( pRAcc->GetPixel( nY, nX ) ); 1733 pCountTable[ ( ( ( (sal_uInt32) rCol.GetRed() ) >> nRightShiftBits ) << nLeftShiftBits2 ) | 1734 ( ( ( (sal_uInt32) rCol.GetGreen() ) >> nRightShiftBits ) << nLeftShiftBits1 ) | 1735 ( ( (sal_uInt32) rCol.GetBlue() ) >> nRightShiftBits ) ].mnCount++; 1736 } 1737 } 1738 } 1739 else 1740 { 1741 for( nY = 0L; nY < nHeight; nY++ ) 1742 { 1743 for( nX = 0L; nX < nWidth; nX++ ) 1744 { 1745 const BitmapColor aCol( pRAcc->GetPixel( nY, nX ) ); 1746 pCountTable[ ( ( ( (sal_uInt32) aCol.GetRed() ) >> nRightShiftBits ) << nLeftShiftBits2 ) | 1747 ( ( ( (sal_uInt32) aCol.GetGreen() ) >> nRightShiftBits ) << nLeftShiftBits1 ) | 1748 ( ( (sal_uInt32) aCol.GetBlue() ) >> nRightShiftBits ) ].mnCount++; 1749 } 1750 } 1751 } 1752 1753 BitmapPalette aNewPal( nColCount ); 1754 1755 qsort( pCountTable, nTotalColors, sizeof( PopularColorCount ), ImplPopularCmpFnc ); 1756 1757 for( sal_uInt16 n = 0; n < nColCount; n++ ) 1758 { 1759 const PopularColorCount& rPop = pCountTable[ n ]; 1760 aNewPal[ n ] = BitmapColor( (sal_uInt8) ( ( rPop.mnIndex >> nLeftShiftBits2 ) << nRightShiftBits ), 1761 (sal_uInt8) ( ( ( rPop.mnIndex >> nLeftShiftBits1 ) & ( nColorsPerComponent - 1 ) ) << nRightShiftBits ), 1762 (sal_uInt8) ( ( rPop.mnIndex & ( nColorsPerComponent - 1 ) ) << nRightShiftBits ) ); 1763 } 1764 1765 Bitmap aNewBmp( GetSizePixel(), nBitCount, &aNewPal ); 1766 BitmapWriteAccess* pWAcc = aNewBmp.AcquireWriteAccess(); 1767 1768 if( pWAcc ) 1769 { 1770 BitmapColor aDstCol( (sal_uInt8) 0 ); 1771 sal_uInt8* pIndexMap = new sal_uInt8[ nTotalColors ]; 1772 1773 for( nR = 0, nIndex = 0; nR < 256; nR += nColorOffset ) 1774 for( nG = 0; nG < 256; nG += nColorOffset ) 1775 for( nB = 0; nB < 256; nB += nColorOffset ) 1776 pIndexMap[ nIndex++ ] = (sal_uInt8) aNewPal.GetBestIndex( BitmapColor( (sal_uInt8) nR, (sal_uInt8) nG, (sal_uInt8) nB ) ); 1777 1778 if( pRAcc->HasPalette() ) 1779 { 1780 for( nY = 0L; nY < nHeight; nY++ ) 1781 { 1782 for( nX = 0L; nX < nWidth; nX++ ) 1783 { 1784 const BitmapColor& rCol = pRAcc->GetPaletteColor( pRAcc->GetPixel( nY, nX ) ); 1785 aDstCol.SetIndex( pIndexMap[ ( ( ( (sal_uInt32) rCol.GetRed() ) >> nRightShiftBits ) << nLeftShiftBits2 ) | 1786 ( ( ( (sal_uInt32) rCol.GetGreen() ) >> nRightShiftBits ) << nLeftShiftBits1 ) | 1787 ( ( (sal_uInt32) rCol.GetBlue() ) >> nRightShiftBits ) ] ); 1788 pWAcc->SetPixel( nY, nX, aDstCol ); 1789 } 1790 } 1791 } 1792 else 1793 { 1794 for( nY = 0L; nY < nHeight; nY++ ) 1795 { 1796 for( nX = 0L; nX < nWidth; nX++ ) 1797 { 1798 const BitmapColor aCol( pRAcc->GetPixel( nY, nX ) ); 1799 aDstCol.SetIndex( pIndexMap[ ( ( ( (sal_uInt32) aCol.GetRed() ) >> nRightShiftBits ) << nLeftShiftBits2 ) | 1800 ( ( ( (sal_uInt32) aCol.GetGreen() ) >> nRightShiftBits ) << nLeftShiftBits1 ) | 1801 ( ( (sal_uInt32) aCol.GetBlue() ) >> nRightShiftBits ) ] ); 1802 pWAcc->SetPixel( nY, nX, aDstCol ); 1803 } 1804 } 1805 } 1806 1807 delete[] pIndexMap; 1808 aNewBmp.ReleaseAccess( pWAcc ); 1809 bRet = sal_True; 1810 } 1811 1812 delete[] pCountTable; 1813 ReleaseAccess( pRAcc ); 1814 1815 if( bRet ) 1816 { 1817 const MapMode aMap( maPrefMapMode ); 1818 const Size aSize( maPrefSize ); 1819 1820 *this = aNewBmp; 1821 maPrefMapMode = aMap; 1822 maPrefSize = aSize; 1823 } 1824 } 1825 1826 return bRet; 1827 } 1828 1829 // ------------------------------------------------------------------------ 1830 1831 sal_Bool Bitmap::ImplReduceMedian( sal_uInt16 nColCount ) 1832 { 1833 BitmapReadAccess* pRAcc = AcquireReadAccess(); 1834 sal_uInt16 nBitCount; 1835 sal_Bool bRet = sal_False; 1836 1837 if( nColCount < 17 ) 1838 nBitCount = 4; 1839 else if( nColCount < 257 ) 1840 nBitCount = 8; 1841 else 1842 { 1843 DBG_ERROR( "Bitmap::ImplReduceMedian(): invalid color count!" ); 1844 nBitCount = 8; 1845 nColCount = 256; 1846 } 1847 1848 if( pRAcc ) 1849 { 1850 Bitmap aNewBmp( GetSizePixel(), nBitCount ); 1851 BitmapWriteAccess* pWAcc = aNewBmp.AcquireWriteAccess(); 1852 1853 if( pWAcc ) 1854 { 1855 const sal_uLong nSize = 32768UL * sizeof( sal_uLong ); 1856 sal_uLong* pColBuf = (sal_uLong*) rtl_allocateMemory( nSize ); 1857 const long nWidth = pWAcc->Width(); 1858 const long nHeight = pWAcc->Height(); 1859 long nIndex = 0L; 1860 1861 memset( (HPBYTE) pColBuf, 0, nSize ); 1862 1863 // create Buffer 1864 if( pRAcc->HasPalette() ) 1865 { 1866 for( long nY = 0L; nY < nHeight; nY++ ) 1867 { 1868 for( long nX = 0L; nX < nWidth; nX++ ) 1869 { 1870 const BitmapColor& rCol = pRAcc->GetPaletteColor( pRAcc->GetPixel( nY, nX ) ); 1871 pColBuf[ RGB15( rCol.GetRed() >> 3, rCol.GetGreen() >> 3, rCol.GetBlue() >> 3 ) ]++; 1872 } 1873 } 1874 } 1875 else 1876 { 1877 for( long nY = 0L; nY < nHeight; nY++ ) 1878 { 1879 for( long nX = 0L; nX < nWidth; nX++ ) 1880 { 1881 const BitmapColor aCol( pRAcc->GetPixel( nY, nX ) ); 1882 pColBuf[ RGB15( aCol.GetRed() >> 3, aCol.GetGreen() >> 3, aCol.GetBlue() >> 3 ) ]++; 1883 } 1884 } 1885 } 1886 1887 // create palette via median cut 1888 BitmapPalette aPal( pWAcc->GetPaletteEntryCount() ); 1889 ImplMedianCut( pColBuf, aPal, 0, 31, 0, 31, 0, 31, 1890 nColCount, nWidth * nHeight, nIndex ); 1891 1892 // do mapping of colors to palette 1893 InverseColorMap aMap( aPal ); 1894 pWAcc->SetPalette( aPal ); 1895 for( long nY = 0L; nY < nHeight; nY++ ) 1896 for( long nX = 0L; nX < nWidth; nX++ ) 1897 pWAcc->SetPixel( nY, nX, (sal_uInt8) aMap.GetBestPaletteIndex( pRAcc->GetColor( nY, nX ) ) ); 1898 1899 rtl_freeMemory( pColBuf ); 1900 aNewBmp.ReleaseAccess( pWAcc ); 1901 bRet = sal_True; 1902 } 1903 1904 ReleaseAccess( pRAcc ); 1905 1906 if( bRet ) 1907 { 1908 const MapMode aMap( maPrefMapMode ); 1909 const Size aSize( maPrefSize ); 1910 1911 *this = aNewBmp; 1912 maPrefMapMode = aMap; 1913 maPrefSize = aSize; 1914 } 1915 } 1916 1917 return bRet; 1918 } 1919 1920 // ------------------------------------------------------------------------ 1921 1922 void Bitmap::ImplMedianCut( sal_uLong* pColBuf, BitmapPalette& rPal, 1923 long nR1, long nR2, long nG1, long nG2, long nB1, long nB2, 1924 long nColors, long nPixels, long& rIndex ) 1925 { 1926 if( !nPixels ) 1927 return; 1928 1929 BitmapColor aCol; 1930 const long nRLen = nR2 - nR1; 1931 const long nGLen = nG2 - nG1; 1932 const long nBLen = nB2 - nB1; 1933 long nR, nG, nB; 1934 sal_uLong* pBuf = pColBuf; 1935 1936 if( !nRLen && !nGLen && !nBLen ) 1937 { 1938 if( pBuf[ RGB15( nR1, nG1, nB1 ) ] ) 1939 { 1940 aCol.SetRed( (sal_uInt8) ( nR1 << 3 ) ); 1941 aCol.SetGreen( (sal_uInt8) ( nG1 << 3 ) ); 1942 aCol.SetBlue( (sal_uInt8) ( nB1 << 3 ) ); 1943 rPal[ (sal_uInt16) rIndex++ ] = aCol; 1944 } 1945 } 1946 else 1947 { 1948 if( 1 == nColors || 1 == nPixels ) 1949 { 1950 long nPixSum = 0, nRSum = 0, nGSum = 0, nBSum = 0; 1951 1952 for( nR = nR1; nR <= nR2; nR++ ) 1953 { 1954 for( nG = nG1; nG <= nG2; nG++ ) 1955 { 1956 for( nB = nB1; nB <= nB2; nB++ ) 1957 { 1958 nPixSum = pBuf[ RGB15( nR, nG, nB ) ]; 1959 1960 if( nPixSum ) 1961 { 1962 nRSum += nR * nPixSum; 1963 nGSum += nG * nPixSum; 1964 nBSum += nB * nPixSum; 1965 } 1966 } 1967 } 1968 } 1969 1970 aCol.SetRed( (sal_uInt8) ( ( nRSum / nPixels ) << 3 ) ); 1971 aCol.SetGreen( (sal_uInt8) ( ( nGSum / nPixels ) << 3 ) ); 1972 aCol.SetBlue( (sal_uInt8) ( ( nBSum / nPixels ) << 3 ) ); 1973 rPal[ (sal_uInt16) rIndex++ ] = aCol; 1974 } 1975 else 1976 { 1977 const long nTest = ( nPixels >> 1 ); 1978 long nPixOld = 0; 1979 long nPixNew = 0; 1980 1981 if( nBLen > nGLen && nBLen > nRLen ) 1982 { 1983 nB = nB1 - 1; 1984 1985 while( nPixNew < nTest ) 1986 { 1987 nB++, nPixOld = nPixNew; 1988 for( nR = nR1; nR <= nR2; nR++ ) 1989 for( nG = nG1; nG <= nG2; nG++ ) 1990 nPixNew += pBuf[ RGB15( nR, nG, nB ) ]; 1991 } 1992 1993 if( nB < nB2 ) 1994 { 1995 ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG2, nB1, nB, nColors >> 1, nPixNew, rIndex ); 1996 ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG2, nB + 1, nB2, nColors >> 1, nPixels - nPixNew, rIndex ); 1997 } 1998 else 1999 { 2000 ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG2, nB1, nB - 1, nColors >> 1, nPixOld, rIndex ); 2001 ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG2, nB, nB2, nColors >> 1, nPixels - nPixOld, rIndex ); 2002 } 2003 } 2004 else if( nGLen > nRLen ) 2005 { 2006 nG = nG1 - 1; 2007 2008 while( nPixNew < nTest ) 2009 { 2010 nG++, nPixOld = nPixNew; 2011 for( nR = nR1; nR <= nR2; nR++ ) 2012 for( nB = nB1; nB <= nB2; nB++ ) 2013 nPixNew += pBuf[ RGB15( nR, nG, nB ) ]; 2014 } 2015 2016 if( nG < nG2 ) 2017 { 2018 ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG, nB1, nB2, nColors >> 1, nPixNew, rIndex ); 2019 ImplMedianCut( pBuf, rPal, nR1, nR2, nG + 1, nG2, nB1, nB2, nColors >> 1, nPixels - nPixNew, rIndex ); 2020 } 2021 else 2022 { 2023 ImplMedianCut( pBuf, rPal, nR1, nR2, nG1, nG - 1, nB1, nB2, nColors >> 1, nPixOld, rIndex ); 2024 ImplMedianCut( pBuf, rPal, nR1, nR2, nG, nG2, nB1, nB2, nColors >> 1, nPixels - nPixOld, rIndex ); 2025 } 2026 } 2027 else 2028 { 2029 nR = nR1 - 1; 2030 2031 while( nPixNew < nTest ) 2032 { 2033 nR++, nPixOld = nPixNew; 2034 for( nG = nG1; nG <= nG2; nG++ ) 2035 for( nB = nB1; nB <= nB2; nB++ ) 2036 nPixNew += pBuf[ RGB15( nR, nG, nB ) ]; 2037 } 2038 2039 if( nR < nR2 ) 2040 { 2041 ImplMedianCut( pBuf, rPal, nR1, nR, nG1, nG2, nB1, nB2, nColors >> 1, nPixNew, rIndex ); 2042 ImplMedianCut( pBuf, rPal, nR1 + 1, nR2, nG1, nG2, nB1, nB2, nColors >> 1, nPixels - nPixNew, rIndex ); 2043 } 2044 else 2045 { 2046 ImplMedianCut( pBuf, rPal, nR1, nR - 1, nG1, nG2, nB1, nB2, nColors >> 1, nPixOld, rIndex ); 2047 ImplMedianCut( pBuf, rPal, nR, nR2, nG1, nG2, nB1, nB2, nColors >> 1, nPixels - nPixOld, rIndex ); 2048 } 2049 } 2050 } 2051 } 2052 } 2053 2054 // ------------------------------------------------------------------------ 2055 2056 sal_Bool Bitmap::Vectorize( PolyPolygon& rPolyPoly, sal_uLong nFlags, const Link* pProgress ) 2057 { 2058 return ImplVectorizer().ImplVectorize( *this, rPolyPoly, nFlags, pProgress ); 2059 } 2060 2061 // ------------------------------------------------------------------------ 2062 2063 sal_Bool Bitmap::Vectorize( GDIMetaFile& rMtf, sal_uInt8 cReduce, sal_uLong nFlags, const Link* pProgress ) 2064 { 2065 return ImplVectorizer().ImplVectorize( *this, rMtf, cReduce, nFlags, pProgress ); 2066 } 2067 2068 // ------------------------------------------------------------------------ 2069 2070 sal_Bool Bitmap::Adjust( short nLuminancePercent, short nContrastPercent, 2071 short nChannelRPercent, short nChannelGPercent, short nChannelBPercent, 2072 double fGamma, sal_Bool bInvert ) 2073 { 2074 sal_Bool bRet = sal_False; 2075 2076 // nothing to do => return quickly 2077 if( !nLuminancePercent && !nContrastPercent && 2078 !nChannelRPercent && !nChannelGPercent && !nChannelBPercent && 2079 ( fGamma == 1.0 ) && !bInvert ) 2080 { 2081 bRet = sal_True; 2082 } 2083 else 2084 { 2085 BitmapWriteAccess* pAcc = AcquireWriteAccess(); 2086 2087 if( pAcc ) 2088 { 2089 BitmapColor aCol; 2090 const long nW = pAcc->Width(); 2091 const long nH = pAcc->Height(); 2092 sal_uInt8* cMapR = new sal_uInt8[ 256 ]; 2093 sal_uInt8* cMapG = new sal_uInt8[ 256 ]; 2094 sal_uInt8* cMapB = new sal_uInt8[ 256 ]; 2095 long nX, nY; 2096 double fM, fROff, fGOff, fBOff, fOff; 2097 2098 // calculate slope 2099 if( nContrastPercent >= 0 ) 2100 fM = 128.0 / ( 128.0 - 1.27 * MinMax( nContrastPercent, 0L, 100L ) ); 2101 else 2102 fM = ( 128.0 + 1.27 * MinMax( nContrastPercent, -100L, 0L ) ) / 128.0; 2103 2104 // total offset = luminance offset + contrast offset 2105 fOff = MinMax( nLuminancePercent, -100L, 100L ) * 2.55 + 128.0 - fM * 128.0; 2106 2107 // channel offset = channel offset + total offset 2108 fROff = nChannelRPercent * 2.55 + fOff; 2109 fGOff = nChannelGPercent * 2.55 + fOff; 2110 fBOff = nChannelBPercent * 2.55 + fOff; 2111 2112 // calculate gamma value 2113 fGamma = ( fGamma <= 0.0 || fGamma > 10.0 ) ? 1.0 : ( 1.0 / fGamma ); 2114 const sal_Bool bGamma = ( fGamma != 1.0 ); 2115 2116 // create mapping table 2117 for( nX = 0L; nX < 256L; nX++ ) 2118 { 2119 cMapR[ nX ] = (sal_uInt8) MinMax( FRound( nX * fM + fROff ), 0L, 255L ); 2120 cMapG[ nX ] = (sal_uInt8) MinMax( FRound( nX * fM + fGOff ), 0L, 255L ); 2121 cMapB[ nX ] = (sal_uInt8) MinMax( FRound( nX * fM + fBOff ), 0L, 255L ); 2122 2123 if( bGamma ) 2124 { 2125 cMapR[ nX ] = GAMMA( cMapR[ nX ], fGamma ); 2126 cMapG[ nX ] = GAMMA( cMapG[ nX ], fGamma ); 2127 cMapB[ nX ] = GAMMA( cMapB[ nX ], fGamma ); 2128 } 2129 2130 if( bInvert ) 2131 { 2132 cMapR[ nX ] = ~cMapR[ nX ]; 2133 cMapG[ nX ] = ~cMapG[ nX ]; 2134 cMapB[ nX ] = ~cMapB[ nX ]; 2135 } 2136 } 2137 2138 // do modifying 2139 if( pAcc->HasPalette() ) 2140 { 2141 BitmapColor aNewCol; 2142 2143 for( sal_uInt16 i = 0, nCount = pAcc->GetPaletteEntryCount(); i < nCount; i++ ) 2144 { 2145 const BitmapColor& rCol = pAcc->GetPaletteColor( i ); 2146 aNewCol.SetRed( cMapR[ rCol.GetRed() ] ); 2147 aNewCol.SetGreen( cMapG[ rCol.GetGreen() ] ); 2148 aNewCol.SetBlue( cMapB[ rCol.GetBlue() ] ); 2149 pAcc->SetPaletteColor( i, aNewCol ); 2150 } 2151 } 2152 else if( pAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_BGR ) 2153 { 2154 for( nY = 0L; nY < nH; nY++ ) 2155 { 2156 Scanline pScan = pAcc->GetScanline( nY ); 2157 2158 for( nX = 0L; nX < nW; nX++ ) 2159 { 2160 *pScan = cMapB[ *pScan ]; pScan++; 2161 *pScan = cMapG[ *pScan ]; pScan++; 2162 *pScan = cMapR[ *pScan ]; pScan++; 2163 } 2164 } 2165 } 2166 else if( pAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_RGB ) 2167 { 2168 for( nY = 0L; nY < nH; nY++ ) 2169 { 2170 Scanline pScan = pAcc->GetScanline( nY ); 2171 2172 for( nX = 0L; nX < nW; nX++ ) 2173 { 2174 *pScan = cMapR[ *pScan ]; pScan++; 2175 *pScan = cMapG[ *pScan ]; pScan++; 2176 *pScan = cMapB[ *pScan ]; pScan++; 2177 } 2178 } 2179 } 2180 else 2181 { 2182 for( nY = 0L; nY < nH; nY++ ) 2183 { 2184 for( nX = 0L; nX < nW; nX++ ) 2185 { 2186 aCol = pAcc->GetPixel( nY, nX ); 2187 aCol.SetRed( cMapR[ aCol.GetRed() ] ); 2188 aCol.SetGreen( cMapG[ aCol.GetGreen() ] ); 2189 aCol.SetBlue( cMapB[ aCol.GetBlue() ] ); 2190 pAcc->SetPixel( nY, nX, aCol ); 2191 } 2192 } 2193 } 2194 2195 delete[] cMapR; 2196 delete[] cMapG; 2197 delete[] cMapB; 2198 ReleaseAccess( pAcc ); 2199 bRet = sal_True; 2200 } 2201 } 2202 2203 return bRet; 2204 } 2205