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 <vcl/salbtype.hxx> 28 #include <vcl/bitmap.hxx> 29 #include <vcl/bmpacc.hxx> 30 31 #include <impbmp.hxx> 32 33 #include <string.h> 34 35 // -------------------- 36 // - BitmapReadAccess - 37 // -------------------- 38 39 BitmapReadAccess::BitmapReadAccess( Bitmap& rBitmap, sal_Bool bModify ) : 40 mpBuffer ( NULL ), 41 mpScanBuf ( NULL ), 42 mFncGetPixel ( NULL ), 43 mFncSetPixel ( NULL ), 44 mbModify ( bModify ) 45 { 46 ImplCreate( rBitmap ); 47 } 48 49 // ------------------------------------------------------------------ 50 51 BitmapReadAccess::BitmapReadAccess( Bitmap& rBitmap ) : 52 mpBuffer ( NULL ), 53 mpScanBuf ( NULL ), 54 mFncGetPixel ( NULL ), 55 mFncSetPixel ( NULL ), 56 mbModify ( sal_False ) 57 { 58 ImplCreate( rBitmap ); 59 } 60 61 // ------------------------------------------------------------------ 62 63 BitmapReadAccess::~BitmapReadAccess() 64 { 65 ImplDestroy(); 66 } 67 68 // ------------------------------------------------------------------ 69 70 void BitmapReadAccess::ImplCreate( Bitmap& rBitmap ) 71 { 72 ImpBitmap* pImpBmp = rBitmap.ImplGetImpBitmap(); 73 74 DBG_ASSERT( pImpBmp, "Forbidden Access to empty bitmap!" ); 75 76 if( pImpBmp ) 77 { 78 if( mbModify && !maBitmap.ImplGetImpBitmap() ) 79 { 80 rBitmap.ImplMakeUnique(); 81 pImpBmp = rBitmap.ImplGetImpBitmap(); 82 } 83 else 84 { 85 DBG_ASSERT( !mbModify || pImpBmp->ImplGetRefCount() == 2, 86 "Unpredictable results: bitmap is referenced more than once!" ); 87 } 88 89 mpBuffer = pImpBmp->ImplAcquireBuffer( !mbModify ); 90 91 if( !mpBuffer ) 92 { 93 ImpBitmap* pNewImpBmp = new ImpBitmap; 94 95 if( pNewImpBmp->ImplCreate( *pImpBmp, rBitmap.GetBitCount() ) ) 96 { 97 pImpBmp = pNewImpBmp; 98 rBitmap.ImplSetImpBitmap( pImpBmp ); 99 mpBuffer = pImpBmp->ImplAcquireBuffer( !mbModify ); 100 } 101 else 102 delete pNewImpBmp; 103 } 104 105 if( mpBuffer ) 106 { 107 const long nHeight = mpBuffer->mnHeight; 108 Scanline pTmpLine = mpBuffer->mpBits; 109 110 mpScanBuf = new Scanline[ nHeight ]; 111 maColorMask = mpBuffer->maColorMask; 112 113 if( BMP_SCANLINE_ADJUSTMENT( mpBuffer->mnFormat ) == BMP_FORMAT_TOP_DOWN ) 114 { 115 for( long nY = 0L; nY < nHeight; nY++, pTmpLine += mpBuffer->mnScanlineSize ) 116 mpScanBuf[ nY ] = pTmpLine; 117 } 118 else 119 { 120 for( long nY = nHeight - 1; nY >= 0; nY--, pTmpLine += mpBuffer->mnScanlineSize ) 121 mpScanBuf[ nY ] = pTmpLine; 122 } 123 124 if( !ImplSetAccessPointers( BMP_SCANLINE_FORMAT( mpBuffer->mnFormat ) ) ) 125 { 126 delete[] mpScanBuf; 127 mpScanBuf = NULL; 128 129 pImpBmp->ImplReleaseBuffer( mpBuffer, !mbModify ); 130 mpBuffer = NULL; 131 } 132 else 133 maBitmap = rBitmap; 134 } 135 } 136 } 137 138 // ------------------------------------------------------------------ 139 140 void BitmapReadAccess::ImplDestroy() 141 { 142 ImpBitmap* pImpBmp = maBitmap.ImplGetImpBitmap(); 143 144 delete[] mpScanBuf; 145 mpScanBuf = NULL; 146 147 if( mpBuffer && pImpBmp ) 148 { 149 pImpBmp->ImplReleaseBuffer( mpBuffer, !mbModify ); 150 mpBuffer = NULL; 151 } 152 } 153 154 // ------------------------------------------------------------------ 155 156 sal_Bool BitmapReadAccess::ImplSetAccessPointers( sal_uLong nFormat ) 157 { 158 sal_Bool bRet = sal_True; 159 160 switch( nFormat ) 161 { 162 CASE_FORMAT( _1BIT_MSB_PAL ) 163 CASE_FORMAT( _1BIT_LSB_PAL ) 164 CASE_FORMAT( _4BIT_MSN_PAL ) 165 CASE_FORMAT( _4BIT_LSN_PAL ) 166 CASE_FORMAT( _8BIT_PAL ) 167 CASE_FORMAT( _8BIT_TC_MASK ) 168 CASE_FORMAT( _16BIT_TC_MSB_MASK ) 169 CASE_FORMAT( _16BIT_TC_LSB_MASK ) 170 CASE_FORMAT( _24BIT_TC_BGR ) 171 CASE_FORMAT( _24BIT_TC_RGB ) 172 CASE_FORMAT( _24BIT_TC_MASK ) 173 CASE_FORMAT( _32BIT_TC_ABGR ) 174 CASE_FORMAT( _32BIT_TC_ARGB ) 175 CASE_FORMAT( _32BIT_TC_BGRA ) 176 CASE_FORMAT( _32BIT_TC_RGBA ) 177 CASE_FORMAT( _32BIT_TC_MASK ) 178 179 default: 180 bRet = sal_False; 181 break; 182 } 183 184 return bRet; 185 } 186 187 // ------------------------------------------------------------------ 188 189 void BitmapReadAccess::ImplZeroInitUnusedBits() 190 { 191 const sal_uInt32 nWidth = Width(), nHeight = Height(), nScanSize = GetScanlineSize(); 192 193 if( nWidth && nHeight && nScanSize && GetBuffer() ) 194 { 195 sal_uInt32 nBits; 196 bool bMsb; 197 198 const sal_uLong nScanlineFormat = GetScanlineFormat(); 199 switch( nScanlineFormat ) 200 { 201 case( BMP_FORMAT_1BIT_MSB_PAL ): 202 nBits = 1; 203 bMsb = true; 204 break; 205 206 case( BMP_FORMAT_1BIT_LSB_PAL ): 207 nBits = 1; 208 bMsb = false; 209 break; 210 211 case( BMP_FORMAT_4BIT_MSN_PAL ): 212 nBits = 4; 213 bMsb = true; 214 break; 215 216 case( BMP_FORMAT_4BIT_LSN_PAL ): 217 nBits = 4; 218 bMsb = false; 219 break; 220 221 case( BMP_FORMAT_8BIT_PAL ): 222 case( BMP_FORMAT_8BIT_TC_MASK ): 223 bMsb = true; 224 nBits = 8; 225 break; 226 227 case( BMP_FORMAT_16BIT_TC_MSB_MASK ): 228 case( BMP_FORMAT_16BIT_TC_LSB_MASK ): 229 bMsb = true; 230 nBits = 16; 231 break; 232 233 case( BMP_FORMAT_24BIT_TC_BGR ): 234 case( BMP_FORMAT_24BIT_TC_RGB ): 235 case( BMP_FORMAT_24BIT_TC_MASK ): 236 bMsb = true; 237 nBits = 24; 238 break; 239 240 case( BMP_FORMAT_32BIT_TC_ABGR ): 241 case( BMP_FORMAT_32BIT_TC_ARGB ): 242 case( BMP_FORMAT_32BIT_TC_BGRA ): 243 case( BMP_FORMAT_32BIT_TC_RGBA ): 244 case( BMP_FORMAT_32BIT_TC_MASK ): 245 bMsb = true; 246 nBits = 32; 247 break; 248 249 default: 250 { 251 DBG_ERROR( "BitmapWriteAccess::ZeroInitUnusedBits: Unsupported pixel format"); 252 nBits = 0; 253 bMsb = true; 254 } 255 break; 256 } 257 258 nBits *= nWidth; 259 if( nScanSize % 4 || !bMsb ) 260 { 261 DBG_ASSERT( 8*nScanSize >= nBits, 262 "BitmapWriteAccess::ZeroInitUnusedBits: span size smaller than width?!"); 263 const sal_uInt32 nLeftOverBits = 8*sizeof(sal_uInt8)*nScanSize - nBits; 264 if( nLeftOverBits != 0 ) // else there is really nothing to do 265 { 266 const sal_uInt32 nBytes = (nLeftOverBits + 7U) >> 3U; 267 sal_uInt8 nMask; 268 269 if( bMsb ) 270 nMask = static_cast<sal_uInt8>(0xffU << (nLeftOverBits & 3UL)); 271 else 272 nMask = static_cast<sal_uInt8>(0xffU >> (nLeftOverBits & 3UL)); 273 274 sal_uInt8* pLastBytes = (sal_uInt8*)GetBuffer() + ( nScanSize - nBytes ); 275 for( sal_uInt32 i = 0; i < nHeight; i++, pLastBytes += nScanSize ) 276 { 277 *pLastBytes &= nMask; 278 for( sal_uInt32 j = 1; j < nBytes; j++ ) 279 pLastBytes[j] = 0; 280 } 281 } 282 } 283 else if( nBits & 0x1f ) 284 { 285 sal_uInt32 nMask = 0xffffffff << ( ( nScanSize << 3 ) - nBits ); 286 sal_uInt8* pLast4Bytes = (sal_uInt8*) GetBuffer() + ( nScanSize - 4 ); 287 288 #ifdef OSL_LITENDIAN 289 nMask = SWAPLONG( nMask ); 290 #endif 291 for( sal_uInt32 i = 0; i < nHeight; i++, pLast4Bytes += nScanSize ) 292 ( *(sal_uInt32*) pLast4Bytes ) &= nMask; 293 } 294 } 295 } 296 297 // ------------------------------------------------------------------ 298 299 void BitmapReadAccess::Flush() 300 { 301 ImplDestroy(); 302 } 303 304 // ------------------------------------------------------------------ 305 306 void BitmapReadAccess::ReAccess( sal_Bool bModify ) 307 { 308 const ImpBitmap* pImpBmp = maBitmap.ImplGetImpBitmap(); 309 310 DBG_ASSERT( !mpBuffer, "No ReAccess possible while bitmap is being accessed!" ); 311 DBG_ASSERT( pImpBmp && ( pImpBmp->ImplGetRefCount() > 1UL ), "Accessed bitmap does not exist anymore!" ); 312 313 if( !mpBuffer && pImpBmp && ( pImpBmp->ImplGetRefCount() > 1UL ) ) 314 { 315 mbModify = bModify; 316 ImplCreate( maBitmap ); 317 } 318 } 319 320 // ------------------------------------------------------------------ 321 322 sal_uInt16 BitmapReadAccess::GetBestPaletteIndex( const BitmapColor& rBitmapColor ) const 323 { 324 return( HasPalette() ? mpBuffer->maPalette.GetBestIndex( rBitmapColor ) : 0 ); 325 } 326 327 BitmapColor BitmapReadAccess::GetInterpolatedColorWithFallback( double fY, double fX, const BitmapColor& rFallback ) const 328 { 329 // ask directly doubles >= 0.0 here to avoid rounded values of 0 at small negative 330 // double values, e.g. static_cast< sal_Int32 >(-0.25) is 0, not -1, but *has* to be outside (!) 331 if(mpBuffer && fX >= 0.0 && fY >= 0.0) 332 { 333 const sal_Int32 nX(static_cast< sal_Int32 >(fX)); 334 const sal_Int32 nY(static_cast< sal_Int32 >(fY)); 335 336 if(nX < mpBuffer->mnWidth && nY < mpBuffer->mnHeight) 337 { 338 // get base-return value from inside pixel 339 BitmapColor aRetval(GetColor(nY, nX)); 340 341 // calculate deltas and indices for neighbour accesses 342 sal_Int16 nDeltaX((fX - (nX + 0.5)) * 255.0); // [-255 .. 255] 343 sal_Int16 nDeltaY((fY - (nY + 0.5)) * 255.0); // [-255 .. 255] 344 sal_Int16 nIndX(0); 345 sal_Int16 nIndY(0); 346 347 if(nDeltaX > 0) 348 { 349 nIndX = nX + 1; 350 } 351 else 352 { 353 nIndX = nX - 1; 354 nDeltaX = -nDeltaX; 355 } 356 357 if(nDeltaY > 0) 358 { 359 nIndY = nY + 1; 360 } 361 else 362 { 363 nIndY = nY - 1; 364 nDeltaY = -nDeltaY; 365 } 366 367 // get right/left neighbour 368 BitmapColor aXCol(rFallback); 369 370 if(nDeltaX && nIndX >= 0 && nIndX < mpBuffer->mnWidth) 371 { 372 aXCol = GetColor(nY, nIndX); 373 } 374 375 // get top/bottom neighbour 376 BitmapColor aYCol(rFallback); 377 378 if(nDeltaY && nIndY >= 0 && nIndY < mpBuffer->mnHeight) 379 { 380 aYCol = GetColor(nIndY, nX); 381 } 382 383 // get one of four edge neighbours 384 BitmapColor aXYCol(rFallback); 385 386 if(nDeltaX && nDeltaY && nIndX >=0 && nIndY >= 0 && nIndX < mpBuffer->mnWidth && nIndY < mpBuffer->mnHeight) 387 { 388 aXYCol = GetColor(nIndY, nIndX); 389 } 390 391 // merge return value with right/left neighbour 392 if(aXCol != aRetval) 393 { 394 aRetval.Merge(aXCol, 255 - nDeltaX); 395 } 396 397 // merge top/bottom neighbour with edge 398 if(aYCol != aXYCol) 399 { 400 aYCol.Merge(aXYCol, 255 - nDeltaX); 401 } 402 403 // merge return value with already merged top/bottom neighbour 404 if(aRetval != aYCol) 405 { 406 aRetval.Merge(aYCol, 255 - nDeltaY); 407 } 408 409 return aRetval; 410 } 411 } 412 413 return rFallback; 414 } 415 416 BitmapColor BitmapReadAccess::GetColorWithFallback( double fY, double fX, const BitmapColor& rFallback ) const 417 { 418 // ask directly doubles >= 0.0 here to avoid rounded values of 0 at small negative 419 // double values, e.g. static_cast< sal_Int32 >(-0.25) is 0, not -1, but *has* to be outside (!) 420 if(mpBuffer && fX >= 0.0 && fY >= 0.0) 421 { 422 const sal_Int32 nX(static_cast< sal_Int32 >(fX)); 423 const sal_Int32 nY(static_cast< sal_Int32 >(fY)); 424 425 if(nX < mpBuffer->mnWidth && nY < mpBuffer->mnHeight) 426 { 427 return GetColor(nY, nX); 428 } 429 } 430 431 return rFallback; 432 } 433 434 BitmapColor BitmapReadAccess::GetColorWithFallback( long nY, long nX, const BitmapColor& rFallback ) const 435 { 436 if(mpBuffer) 437 { 438 if(nX >= 0 && nY >= 0 && nX < mpBuffer->mnWidth && nY < mpBuffer->mnHeight) 439 { 440 return GetColor(nY, nX); 441 } 442 } 443 444 return rFallback; 445 } 446 447 // --------------------- 448 // - BitmapWriteAccess - 449 // --------------------- 450 451 BitmapWriteAccess::BitmapWriteAccess( Bitmap& rBitmap ) : 452 BitmapReadAccess( rBitmap, sal_True ), 453 mpLineColor ( NULL ), 454 mpFillColor ( NULL ) 455 { 456 } 457 458 // ------------------------------------------------------------------ 459 460 BitmapWriteAccess::~BitmapWriteAccess() 461 { 462 delete mpLineColor; 463 delete mpFillColor; 464 } 465 466 // ------------------------------------------------------------------ 467 468 void BitmapWriteAccess::CopyScanline( long nY, const BitmapReadAccess& rReadAcc ) 469 { 470 DBG_ASSERT( ( nY >= 0 ) && ( nY < mpBuffer->mnHeight ), "y-coordinate in destination out of range!" ); 471 DBG_ASSERT( nY < rReadAcc.Height(), "y-coordinate in source out of range!" ); 472 DBG_ASSERT( ( HasPalette() && rReadAcc.HasPalette() ) || ( !HasPalette() && !rReadAcc.HasPalette() ), "No copying possible between palette bitmap and TC bitmap!" ); 473 474 if( ( GetScanlineFormat() == rReadAcc.GetScanlineFormat() ) && 475 ( GetScanlineSize() >= rReadAcc.GetScanlineSize() ) ) 476 { 477 memcpy( mpScanBuf[ nY ], rReadAcc.GetScanline( nY ), rReadAcc.GetScanlineSize() ); 478 } 479 else 480 // TODO: use fastbmp infrastructure 481 for( long nX = 0L, nWidth = Min( mpBuffer->mnWidth, rReadAcc.Width() ); nX < nWidth; nX++ ) 482 SetPixel( nY, nX, rReadAcc.GetPixel( nY, nX ) ); 483 } 484 485 // ------------------------------------------------------------------ 486 487 void BitmapWriteAccess::CopyScanline( long nY, ConstScanline aSrcScanline, 488 sal_uLong nSrcScanlineFormat, sal_uLong nSrcScanlineSize ) 489 { 490 const sal_uLong nFormat = BMP_SCANLINE_FORMAT( nSrcScanlineFormat ); 491 492 DBG_ASSERT( ( nY >= 0 ) && ( nY < mpBuffer->mnHeight ), "y-coordinate in destination out of range!" ); 493 DBG_ASSERT( ( HasPalette() && nFormat <= BMP_FORMAT_8BIT_PAL ) || 494 ( !HasPalette() && nFormat > BMP_FORMAT_8BIT_PAL ), 495 "No copying possible between palette and non palette scanlines!" ); 496 497 const sal_uLong nCount = Min( GetScanlineSize(), nSrcScanlineSize ); 498 499 if( nCount ) 500 { 501 if( GetScanlineFormat() == BMP_SCANLINE_FORMAT( nSrcScanlineFormat ) ) 502 memcpy( mpScanBuf[ nY ], aSrcScanline, nCount ); 503 else 504 { 505 DBG_ASSERT( nFormat != BMP_FORMAT_8BIT_TC_MASK && 506 nFormat != BMP_FORMAT_16BIT_TC_MSB_MASK && nFormat != BMP_FORMAT_16BIT_TC_LSB_MASK && 507 nFormat != BMP_FORMAT_24BIT_TC_MASK && nFormat != BMP_FORMAT_32BIT_TC_MASK, 508 "No support for pixel formats with color masks yet!" ); 509 510 // TODO: use fastbmp infrastructure 511 FncGetPixel pFncGetPixel; 512 513 switch( nFormat ) 514 { 515 case( BMP_FORMAT_1BIT_MSB_PAL ): pFncGetPixel = GetPixelFor_1BIT_MSB_PAL; break; 516 case( BMP_FORMAT_1BIT_LSB_PAL ): pFncGetPixel = GetPixelFor_1BIT_LSB_PAL; break; 517 case( BMP_FORMAT_4BIT_MSN_PAL ): pFncGetPixel = GetPixelFor_4BIT_MSN_PAL; break; 518 case( BMP_FORMAT_4BIT_LSN_PAL ): pFncGetPixel = GetPixelFor_4BIT_LSN_PAL; break; 519 case( BMP_FORMAT_8BIT_PAL ): pFncGetPixel = GetPixelFor_8BIT_PAL; break; 520 case( BMP_FORMAT_8BIT_TC_MASK ): pFncGetPixel = GetPixelFor_8BIT_TC_MASK; break; 521 case( BMP_FORMAT_16BIT_TC_MSB_MASK ): pFncGetPixel = GetPixelFor_16BIT_TC_MSB_MASK; break; 522 case( BMP_FORMAT_16BIT_TC_LSB_MASK ): pFncGetPixel = GetPixelFor_16BIT_TC_LSB_MASK; break; 523 case( BMP_FORMAT_24BIT_TC_BGR ): pFncGetPixel = GetPixelFor_24BIT_TC_BGR; break; 524 case( BMP_FORMAT_24BIT_TC_RGB ): pFncGetPixel = GetPixelFor_24BIT_TC_RGB; break; 525 case( BMP_FORMAT_24BIT_TC_MASK ): pFncGetPixel = GetPixelFor_24BIT_TC_MASK; break; 526 case( BMP_FORMAT_32BIT_TC_ABGR ): pFncGetPixel = GetPixelFor_32BIT_TC_ABGR; break; 527 case( BMP_FORMAT_32BIT_TC_ARGB ): pFncGetPixel = GetPixelFor_32BIT_TC_ARGB; break; 528 case( BMP_FORMAT_32BIT_TC_BGRA ): pFncGetPixel = GetPixelFor_32BIT_TC_BGRA; break; 529 case( BMP_FORMAT_32BIT_TC_RGBA ): pFncGetPixel = GetPixelFor_32BIT_TC_RGBA; break; 530 case( BMP_FORMAT_32BIT_TC_MASK ): pFncGetPixel = GetPixelFor_32BIT_TC_MASK; break; 531 532 default: 533 pFncGetPixel = NULL; 534 break; 535 } 536 537 if( pFncGetPixel ) 538 { 539 const ColorMask aDummyMask; 540 541 for( long nX = 0L, nWidth = mpBuffer->mnWidth; nX < nWidth; nX++ ) 542 SetPixel( nY, nX, pFncGetPixel( aSrcScanline, nX, aDummyMask ) ); 543 } 544 } 545 } 546 } 547 548 549 // ------------------------------------------------------------------ 550 551 void BitmapWriteAccess::CopyBuffer( const BitmapReadAccess& rReadAcc ) 552 { 553 DBG_ASSERT( ( HasPalette() && rReadAcc.HasPalette() ) || ( !HasPalette() && !rReadAcc.HasPalette() ), "No copying possible between palette bitmap and TC bitmap!" ); 554 555 if( ( GetScanlineFormat() == rReadAcc.GetScanlineFormat() ) && 556 ( GetScanlineSize() == rReadAcc.GetScanlineSize() ) ) 557 { 558 const long nHeight = Min( mpBuffer->mnHeight, rReadAcc.Height() ); 559 const sal_uLong nCount = nHeight * mpBuffer->mnScanlineSize; 560 561 memcpy( mpBuffer->mpBits, rReadAcc.GetBuffer(), nCount ); 562 } 563 else 564 for( long nY = 0L, nHeight = Min( mpBuffer->mnHeight, rReadAcc.Height() ); nY < nHeight; nY++ ) 565 CopyScanline( nY, rReadAcc ); 566 } 567