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