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 // MARKER(update_precomp.py): autogen include statement, do not remove 23 #include "precompiled_vcl.hxx" 24 25 #include <vcl/salbtype.hxx> 26 #include <vcl/dibtools.hxx> 27 #include <tools/zcodec.hxx> 28 #include <tools/stream.hxx> 29 #include <vcl/bitmapex.hxx> 30 #include <vcl/bmpacc.hxx> 31 #include <vcl/outdev.hxx> 32 33 ////////////////////////////////////////////////////////////////////////////// 34 // - Defines - 35 36 #define DIBCOREHEADERSIZE ( 12UL ) 37 #define DIBINFOHEADERSIZE ( sizeof(DIBInfoHeader) ) 38 #define DIBV5HEADERSIZE ( sizeof(DIBV5Header) ) 39 40 ////////////////////////////////////////////////////////////////////////////// 41 // - Compression defines 42 43 #define COMPRESS_OWN ('S'|('D'<<8UL)) 44 #define COMPRESS_NONE ( 0UL ) 45 #define RLE_8 ( 1UL ) 46 #define RLE_4 ( 2UL ) 47 #define BITFIELDS ( 3UL ) 48 #define ZCOMPRESS ( COMPRESS_OWN | 0x01000000UL ) /* == 'SD01' (binary) */ 49 50 ////////////////////////////////////////////////////////////////////////////// 51 // - DIBInfoHeader and DIBV5Header 52 53 typedef sal_Int32 FXPT2DOT30; 54 55 struct CIEXYZ 56 { 57 FXPT2DOT30 aXyzX; 58 FXPT2DOT30 aXyzY; 59 FXPT2DOT30 aXyzZ; 60 61 CIEXYZ() 62 : aXyzX(0L), 63 aXyzY(0L), 64 aXyzZ(0L) 65 {} 66 67 ~CIEXYZ() 68 {} 69 }; 70 71 struct CIEXYZTriple 72 { 73 CIEXYZ aXyzRed; 74 CIEXYZ aXyzGreen; 75 CIEXYZ aXyzBlue; 76 77 CIEXYZTriple() 78 : aXyzRed(), 79 aXyzGreen(), 80 aXyzBlue() 81 {} 82 83 ~CIEXYZTriple() 84 {} 85 }; 86 87 struct DIBInfoHeader 88 { 89 sal_uInt32 nSize; 90 sal_Int32 nWidth; 91 sal_Int32 nHeight; 92 sal_uInt16 nPlanes; 93 sal_uInt16 nBitCount; 94 sal_uInt32 nCompression; 95 sal_uInt32 nSizeImage; 96 sal_Int32 nXPelsPerMeter; 97 sal_Int32 nYPelsPerMeter; 98 sal_uInt32 nColsUsed; 99 sal_uInt32 nColsImportant; 100 101 DIBInfoHeader() 102 : nSize(0UL), 103 nWidth(0UL), 104 nHeight(0UL), 105 nPlanes(0), 106 nBitCount(0), 107 nCompression(0), 108 nSizeImage(0), 109 nXPelsPerMeter(0UL), 110 nYPelsPerMeter(0UL), 111 nColsUsed(0UL), 112 nColsImportant(0UL) 113 {} 114 115 ~DIBInfoHeader() 116 {} 117 }; 118 119 struct DIBV5Header : public DIBInfoHeader 120 { 121 sal_uInt32 nV5RedMask; 122 sal_uInt32 nV5GreenMask; 123 sal_uInt32 nV5BlueMask; 124 sal_uInt32 nV5AlphaMask; 125 sal_uInt32 nV5CSType; 126 CIEXYZTriple aV5Endpoints; 127 sal_uInt32 nV5GammaRed; 128 sal_uInt32 nV5GammaGreen; 129 sal_uInt32 nV5GammaBlue; 130 sal_uInt32 nV5Intent; 131 sal_uInt32 nV5ProfileData; 132 sal_uInt32 nV5ProfileSize; 133 sal_uInt32 nV5Reserved; 134 135 DIBV5Header() 136 : DIBInfoHeader(), 137 nV5RedMask(0UL), 138 nV5GreenMask(0UL), 139 nV5BlueMask(0UL), 140 nV5AlphaMask(0UL), 141 nV5CSType(0UL), 142 aV5Endpoints(), 143 nV5GammaRed(0UL), 144 nV5GammaGreen(0UL), 145 nV5GammaBlue(0UL), 146 nV5Intent(0UL), 147 nV5ProfileData(0UL), 148 nV5ProfileSize(0UL), 149 nV5Reserved(0UL) 150 {} 151 152 ~DIBV5Header() 153 {} 154 }; 155 156 ////////////////////////////////////////////////////////////////////////////// 157 158 namespace 159 { 160 inline sal_uInt16 discretizeBitcount( sal_uInt16 nInputCount ) 161 { 162 return ( nInputCount <= 1 ) ? 1 : 163 ( nInputCount <= 4 ) ? 4 : 164 ( nInputCount <= 8 ) ? 8 : 24; 165 } 166 167 inline bool isBitfieldCompression( sal_uLong nScanlineFormat ) 168 { 169 return (BMP_FORMAT_16BIT_TC_LSB_MASK == nScanlineFormat) || (BMP_FORMAT_32BIT_TC_MASK == nScanlineFormat); 170 } 171 } 172 173 ////////////////////////////////////////////////////////////////////////////// 174 175 bool ImplReadDIBInfoHeader(SvStream& rIStm, DIBV5Header& rHeader, bool& bTopDown) 176 { 177 // BITMAPINFOHEADER or BITMAPCOREHEADER or BITMAPV5HEADER 178 const sal_Size aStartPos(rIStm.Tell()); 179 rIStm >> rHeader.nSize; 180 181 // BITMAPCOREHEADER 182 if ( rHeader.nSize == DIBCOREHEADERSIZE ) 183 { 184 sal_Int16 nTmp16; 185 186 rIStm >> nTmp16; rHeader.nWidth = nTmp16; 187 rIStm >> nTmp16; rHeader.nHeight = nTmp16; 188 rIStm >> rHeader.nPlanes; 189 rIStm >> rHeader.nBitCount; 190 } 191 else 192 { 193 // BITMAPCOREHEADER, BITMAPV5HEADER or unknown. Read as far as possible 194 sal_Size nUsed(sizeof(rHeader.nSize)); 195 196 // read DIBInfoHeader entries 197 if(nUsed < rHeader.nSize) { rIStm >> rHeader.nWidth; nUsed += sizeof(rHeader.nWidth); } 198 if(nUsed < rHeader.nSize) { rIStm >> rHeader.nHeight; nUsed += sizeof(rHeader.nHeight); } 199 if(nUsed < rHeader.nSize) { rIStm >> rHeader.nPlanes; nUsed += sizeof(rHeader.nPlanes); } 200 if(nUsed < rHeader.nSize) { rIStm >> rHeader.nBitCount; nUsed += sizeof(rHeader.nBitCount); } 201 if(nUsed < rHeader.nSize) { rIStm >> rHeader.nCompression; nUsed += sizeof(rHeader.nCompression); } 202 if(nUsed < rHeader.nSize) { rIStm >> rHeader.nSizeImage; nUsed += sizeof(rHeader.nSizeImage); } 203 if(nUsed < rHeader.nSize) { rIStm >> rHeader.nXPelsPerMeter; nUsed += sizeof(rHeader.nXPelsPerMeter); } 204 if(nUsed < rHeader.nSize) { rIStm >> rHeader.nYPelsPerMeter; nUsed += sizeof(rHeader.nYPelsPerMeter); } 205 if(nUsed < rHeader.nSize) { rIStm >> rHeader.nColsUsed; nUsed += sizeof(rHeader.nColsUsed); } 206 if(nUsed < rHeader.nSize) { rIStm >> rHeader.nColsImportant; nUsed += sizeof(rHeader.nColsImportant); } 207 208 // read DIBV5HEADER members 209 if(nUsed < rHeader.nSize) { rIStm >> rHeader.nV5RedMask; nUsed += sizeof(rHeader.nV5RedMask); } 210 if(nUsed < rHeader.nSize) { rIStm >> rHeader.nV5GreenMask; nUsed += sizeof(rHeader.nV5GreenMask); } 211 if(nUsed < rHeader.nSize) { rIStm >> rHeader.nV5BlueMask; nUsed += sizeof(rHeader.nV5BlueMask); } 212 if(nUsed < rHeader.nSize) { rIStm >> rHeader.nV5AlphaMask; nUsed += sizeof(rHeader.nV5AlphaMask); } 213 if(nUsed < rHeader.nSize) { rIStm >> rHeader.nV5CSType; nUsed += sizeof(rHeader.nV5CSType); } 214 215 // read contained CIEXYZTriple's 216 if(nUsed < rHeader.nSize) { rIStm >> rHeader.aV5Endpoints.aXyzRed.aXyzX; nUsed += sizeof(rHeader.aV5Endpoints.aXyzRed.aXyzX); } 217 if(nUsed < rHeader.nSize) { rIStm >> rHeader.aV5Endpoints.aXyzRed.aXyzY; nUsed += sizeof(rHeader.aV5Endpoints.aXyzRed.aXyzY); } 218 if(nUsed < rHeader.nSize) { rIStm >> rHeader.aV5Endpoints.aXyzRed.aXyzZ; nUsed += sizeof(rHeader.aV5Endpoints.aXyzRed.aXyzZ); } 219 if(nUsed < rHeader.nSize) { rIStm >> rHeader.aV5Endpoints.aXyzGreen.aXyzX; nUsed += sizeof(rHeader.aV5Endpoints.aXyzGreen.aXyzX); } 220 if(nUsed < rHeader.nSize) { rIStm >> rHeader.aV5Endpoints.aXyzGreen.aXyzY; nUsed += sizeof(rHeader.aV5Endpoints.aXyzGreen.aXyzY); } 221 if(nUsed < rHeader.nSize) { rIStm >> rHeader.aV5Endpoints.aXyzGreen.aXyzZ; nUsed += sizeof(rHeader.aV5Endpoints.aXyzGreen.aXyzZ); } 222 if(nUsed < rHeader.nSize) { rIStm >> rHeader.aV5Endpoints.aXyzBlue.aXyzX; nUsed += sizeof(rHeader.aV5Endpoints.aXyzBlue.aXyzX); } 223 if(nUsed < rHeader.nSize) { rIStm >> rHeader.aV5Endpoints.aXyzBlue.aXyzY; nUsed += sizeof(rHeader.aV5Endpoints.aXyzBlue.aXyzY); } 224 if(nUsed < rHeader.nSize) { rIStm >> rHeader.aV5Endpoints.aXyzBlue.aXyzZ; nUsed += sizeof(rHeader.aV5Endpoints.aXyzBlue.aXyzZ); } 225 226 if(nUsed < rHeader.nSize) { rIStm >> rHeader.nV5GammaRed; nUsed += sizeof(rHeader.nV5GammaRed); } 227 if(nUsed < rHeader.nSize) { rIStm >> rHeader.nV5GammaGreen; nUsed += sizeof(rHeader.nV5GammaGreen); } 228 if(nUsed < rHeader.nSize) { rIStm >> rHeader.nV5GammaBlue; nUsed += sizeof(rHeader.nV5GammaBlue); } 229 if(nUsed < rHeader.nSize) { rIStm >> rHeader.nV5Intent; nUsed += sizeof(rHeader.nV5Intent); } 230 if(nUsed < rHeader.nSize) { rIStm >> rHeader.nV5ProfileData; nUsed += sizeof(rHeader.nV5ProfileData); } 231 if(nUsed < rHeader.nSize) { rIStm >> rHeader.nV5ProfileSize; nUsed += sizeof(rHeader.nV5ProfileSize); } 232 if(nUsed < rHeader.nSize) { rIStm >> rHeader.nV5Reserved; nUsed += sizeof(rHeader.nV5Reserved); } 233 234 // seek to EndPos 235 rIStm.Seek(aStartPos + rHeader.nSize); 236 } 237 238 if ( rHeader.nHeight < 0 ) 239 { 240 bTopDown = true; 241 rHeader.nHeight *= -1; 242 } 243 else 244 { 245 bTopDown = false; 246 } 247 248 if ( rHeader.nWidth < 0 ) 249 { 250 rIStm.SetError( SVSTREAM_FILEFORMAT_ERROR ); 251 } 252 253 // #144105# protect a little against damaged files 254 if( rHeader.nSizeImage > ( 16 * static_cast< sal_uInt32 >( rHeader.nWidth * rHeader.nHeight ) ) ) 255 { 256 rHeader.nSizeImage = 0; 257 } 258 259 return( ( rHeader.nPlanes == 1 ) && ( rIStm.GetError() == 0UL ) ); 260 } 261 262 bool ImplReadDIBPalette( SvStream& rIStm, BitmapWriteAccess& rAcc, bool bQuad ) 263 { 264 const sal_uInt16 nColors = rAcc.GetPaletteEntryCount(); 265 const sal_uLong nPalSize = nColors * ( bQuad ? 4UL : 3UL ); 266 BitmapColor aPalColor; 267 268 sal_uInt8* pEntries = new sal_uInt8[ nPalSize ]; 269 rIStm.Read( pEntries, nPalSize ); 270 271 sal_uInt8* pTmpEntry = pEntries; 272 for( sal_uInt16 i = 0; i < nColors; i++ ) 273 { 274 aPalColor.SetBlue( *pTmpEntry++ ); 275 aPalColor.SetGreen( *pTmpEntry++ ); 276 aPalColor.SetRed( *pTmpEntry++ ); 277 278 if( bQuad ) 279 pTmpEntry++; 280 281 rAcc.SetPaletteColor( i, aPalColor ); 282 } 283 284 delete[] pEntries; 285 286 return( rIStm.GetError() == 0UL ); 287 } 288 289 void ImplDecodeRLE( sal_uInt8* pBuffer, DIBV5Header& rHeader, BitmapWriteAccess& rAcc, bool bRLE4 ) 290 { 291 Scanline pRLE = pBuffer; 292 long nY = rHeader.nHeight - 1L; 293 const sal_uLong nWidth = rAcc.Width(); 294 sal_uLong nCountByte; 295 sal_uLong nRunByte; 296 sal_uLong nX = 0UL; 297 sal_uInt8 cTmp; 298 bool bEndDecoding = false; 299 300 do 301 { 302 if( ( nCountByte = *pRLE++ ) == 0 ) 303 { 304 nRunByte = *pRLE++; 305 306 if( nRunByte > 2 ) 307 { 308 if( bRLE4 ) 309 { 310 nCountByte = nRunByte >> 1; 311 312 for( sal_uLong i = 0UL; i < nCountByte; i++ ) 313 { 314 cTmp = *pRLE++; 315 316 if( nX < nWidth ) 317 rAcc.SetPixelIndex( nY, nX++, cTmp >> 4 ); 318 319 if( nX < nWidth ) 320 rAcc.SetPixelIndex( nY, nX++, cTmp & 0x0f ); 321 } 322 323 if( nRunByte & 1 ) 324 { 325 if( nX < nWidth ) 326 rAcc.SetPixelIndex( nY, nX++, *pRLE >> 4 ); 327 328 pRLE++; 329 } 330 331 if( ( ( nRunByte + 1 ) >> 1 ) & 1 ) 332 pRLE++; 333 } 334 else 335 { 336 for( sal_uLong i = 0UL; i < nRunByte; i++ ) 337 { 338 if( nX < nWidth ) 339 rAcc.SetPixelIndex( nY, nX++, *pRLE ); 340 341 pRLE++; 342 } 343 344 if( nRunByte & 1 ) 345 pRLE++; 346 } 347 } 348 else if( !nRunByte ) 349 { 350 nY--; 351 nX = 0UL; 352 } 353 else if( nRunByte == 1 ) 354 bEndDecoding = true; 355 else 356 { 357 nX += *pRLE++; 358 nY -= *pRLE++; 359 } 360 } 361 else 362 { 363 cTmp = *pRLE++; 364 365 if( bRLE4 ) 366 { 367 nRunByte = nCountByte >> 1; 368 369 for( sal_uLong i = 0UL; i < nRunByte; i++ ) 370 { 371 if( nX < nWidth ) 372 rAcc.SetPixelIndex( nY, nX++, cTmp >> 4 ); 373 374 if( nX < nWidth ) 375 rAcc.SetPixelIndex( nY, nX++, cTmp & 0x0f ); 376 } 377 378 if( ( nCountByte & 1 ) && ( nX < nWidth ) ) 379 rAcc.SetPixelIndex( nY, nX++, cTmp >> 4 ); 380 } 381 else 382 { 383 for( sal_uLong i = 0UL; ( i < nCountByte ) && ( nX < nWidth ); i++ ) 384 rAcc.SetPixelIndex( nY, nX++, cTmp ); 385 } 386 } 387 } 388 while ( !bEndDecoding && ( nY >= 0L ) ); 389 } 390 391 bool ImplReadDIBBits(SvStream& rIStm, DIBV5Header& rHeader, BitmapWriteAccess& rAcc, BitmapWriteAccess* pAccAlpha, bool bTopDown) 392 { 393 const sal_uLong nAlignedWidth = AlignedWidth4Bytes(rHeader.nWidth * rHeader.nBitCount); 394 sal_uInt32 nRMask(0); 395 sal_uInt32 nGMask(0); 396 sal_uInt32 nBMask(0); 397 bool bNative(false); 398 bool bTCMask(!pAccAlpha && ((16 == rHeader.nBitCount) || (32 == rHeader.nBitCount))); 399 bool bRLE((RLE_8 == rHeader.nCompression && 8 == rHeader.nBitCount) || (RLE_4 == rHeader.nCompression && 4 == rHeader.nBitCount)); 400 401 // Is native format? 402 switch(rAcc.GetScanlineFormat()) 403 { 404 case( BMP_FORMAT_1BIT_MSB_PAL ): 405 case( BMP_FORMAT_4BIT_MSN_PAL ): 406 case( BMP_FORMAT_8BIT_PAL ): 407 case( BMP_FORMAT_24BIT_TC_BGR ): 408 { 409 bNative = ( ( static_cast< bool >(rAcc.IsBottomUp()) != bTopDown ) && !bRLE && !bTCMask && ( rAcc.GetScanlineSize() == nAlignedWidth ) ); 410 break; 411 } 412 413 default: 414 { 415 break; 416 } 417 } 418 419 // Read data 420 if(bNative) 421 { 422 // true color DIB's can have a (optimization) palette 423 if(rHeader.nColsUsed && 8 < rHeader.nBitCount) 424 { 425 rIStm.SeekRel(rHeader.nColsUsed * ((rHeader.nSize != DIBCOREHEADERSIZE ) ? 4 : 3)); 426 } 427 428 rIStm.Read(rAcc.GetBuffer(), rHeader.nHeight * nAlignedWidth); 429 } 430 else 431 { 432 // Read color mask 433 if(bTCMask) 434 { 435 if(BITFIELDS == rHeader.nCompression) 436 { 437 rIStm.SeekRel( -12L ); 438 rIStm >> nRMask; 439 rIStm >> nGMask; 440 rIStm >> nBMask; 441 } 442 else 443 { 444 nRMask = ( rHeader.nBitCount == 16 ) ? 0x00007c00UL : 0x00ff0000UL; 445 nGMask = ( rHeader.nBitCount == 16 ) ? 0x000003e0UL : 0x0000ff00UL; 446 nBMask = ( rHeader.nBitCount == 16 ) ? 0x0000001fUL : 0x000000ffUL; 447 } 448 } 449 450 if(bRLE) 451 { 452 if(!rHeader.nSizeImage) 453 { 454 const sal_uLong nOldPos(rIStm.Tell()); 455 456 rIStm.Seek(STREAM_SEEK_TO_END); 457 rHeader.nSizeImage = rIStm.Tell() - nOldPos; 458 rIStm.Seek(nOldPos); 459 } 460 461 sal_uInt8* pBuffer = (sal_uInt8*)rtl_allocateMemory(rHeader.nSizeImage); 462 rIStm.Read((char*)pBuffer, rHeader.nSizeImage); 463 ImplDecodeRLE(pBuffer, rHeader, rAcc, RLE_4 == rHeader.nCompression); 464 rtl_freeMemory(pBuffer); 465 } 466 else 467 { 468 const long nWidth(rHeader.nWidth); 469 const long nHeight(rHeader.nHeight); 470 sal_uInt8* pBuf = new sal_uInt8[nAlignedWidth]; 471 472 // true color DIB's can have a (optimization) palette 473 if(rHeader.nColsUsed && 8 < rHeader.nBitCount) 474 { 475 rIStm.SeekRel(rHeader.nColsUsed * ((rHeader.nSize != DIBCOREHEADERSIZE ) ? 4 : 3)); 476 } 477 478 const long nI(bTopDown ? 1 : -1); 479 long nY(bTopDown ? 0 : nHeight - 1); 480 long nCount(nHeight); 481 482 switch(rHeader.nBitCount) 483 { 484 case( 1 ): 485 { 486 sal_uInt8* pTmp; 487 sal_uInt8 cTmp; 488 489 for( ; nCount--; nY += nI ) 490 { 491 rIStm.Read( pTmp = pBuf, nAlignedWidth ); 492 cTmp = *pTmp++; 493 494 for( long nX = 0L, nShift = 8L; nX < nWidth; nX++ ) 495 { 496 if( !nShift ) 497 { 498 nShift = 8L, 499 cTmp = *pTmp++; 500 } 501 502 rAcc.SetPixelIndex( nY, nX, (cTmp >> --nShift) & 1); 503 } 504 } 505 } 506 break; 507 508 case( 4 ): 509 { 510 sal_uInt8* pTmp; 511 sal_uInt8 cTmp; 512 513 for( ; nCount--; nY += nI ) 514 { 515 rIStm.Read( pTmp = pBuf, nAlignedWidth ); 516 cTmp = *pTmp++; 517 518 for( long nX = 0L, nShift = 2L; nX < nWidth; nX++ ) 519 { 520 if( !nShift ) 521 { 522 nShift = 2UL, 523 cTmp = *pTmp++; 524 } 525 526 rAcc.SetPixelIndex( nY, nX, (cTmp >> ( --nShift << 2UL ) ) & 0x0f); 527 } 528 } 529 } 530 break; 531 532 case( 8 ): 533 { 534 sal_uInt8* pTmp; 535 536 for( ; nCount--; nY += nI ) 537 { 538 rIStm.Read( pTmp = pBuf, nAlignedWidth ); 539 540 for( long nX = 0L; nX < nWidth; nX++ ) 541 rAcc.SetPixelIndex( nY, nX, *pTmp++ ); 542 } 543 } 544 break; 545 546 case( 16 ): 547 { 548 ColorMask aMask( nRMask, nGMask, nBMask ); 549 BitmapColor aColor; 550 sal_uInt16* pTmp16; 551 552 for( ; nCount--; nY += nI ) 553 { 554 rIStm.Read( (char*)( pTmp16 = (sal_uInt16*) pBuf ), nAlignedWidth ); 555 556 for( long nX = 0L; nX < nWidth; nX++ ) 557 { 558 aMask.GetColorFor16BitLSB( aColor, (sal_uInt8*) pTmp16++ ); 559 rAcc.SetPixel( nY, nX, aColor ); 560 } 561 } 562 } 563 break; 564 565 case( 24 ): 566 { 567 BitmapColor aPixelColor; 568 sal_uInt8* pTmp; 569 570 for( ; nCount--; nY += nI ) 571 { 572 rIStm.Read( pTmp = pBuf, nAlignedWidth ); 573 574 for( long nX = 0L; nX < nWidth; nX++ ) 575 { 576 aPixelColor.SetBlue( *pTmp++ ); 577 aPixelColor.SetGreen( *pTmp++ ); 578 aPixelColor.SetRed( *pTmp++ ); 579 rAcc.SetPixel( nY, nX, aPixelColor ); 580 } 581 } 582 } 583 break; 584 585 case( 32 ): 586 { 587 ColorMask aMask(nRMask, nGMask, nBMask); 588 BitmapColor aColor; 589 sal_uInt32* pTmp32; 590 591 if(pAccAlpha) 592 { 593 sal_uInt8 aAlpha; 594 595 for( ; nCount--; nY += nI ) 596 { 597 rIStm.Read( (char*)( pTmp32 = (sal_uInt32*) pBuf ), nAlignedWidth ); 598 599 for( long nX = 0L; nX < nWidth; nX++ ) 600 { 601 aMask.GetColorAndAlphaFor32Bit( aColor, aAlpha, (sal_uInt8*) pTmp32++ ); 602 rAcc.SetPixel( nY, nX, aColor ); 603 pAccAlpha->SetPixelIndex(nY, nX, sal_uInt8(0xff) - aAlpha); 604 } 605 } 606 } 607 else 608 { 609 for( ; nCount--; nY += nI ) 610 { 611 rIStm.Read( (char*)( pTmp32 = (sal_uInt32*) pBuf ), nAlignedWidth ); 612 613 for( long nX = 0L; nX < nWidth; nX++ ) 614 { 615 aMask.GetColorFor32Bit( aColor, (sal_uInt8*) pTmp32++ ); 616 rAcc.SetPixel( nY, nX, aColor ); 617 } 618 } 619 } 620 } 621 } 622 623 delete[] pBuf; 624 } 625 } 626 627 return( rIStm.GetError() == 0UL ); 628 } 629 630 bool ImplReadDIBBody( SvStream& rIStm, Bitmap& rBmp, Bitmap* pBmpAlpha, sal_uLong nOffset ) 631 { 632 DIBV5Header aHeader; 633 const sal_uLong nStmPos = rIStm.Tell(); 634 bool bRet(false); 635 bool bTopDown(false); 636 637 if(ImplReadDIBInfoHeader(rIStm, aHeader, bTopDown) && aHeader.nWidth && aHeader.nHeight && aHeader.nBitCount) 638 { 639 const sal_uInt16 nBitCount(discretizeBitcount(aHeader.nBitCount)); 640 const Size aSizePixel(aHeader.nWidth, aHeader.nHeight); 641 BitmapPalette aDummyPal; 642 Bitmap aNewBmp(aSizePixel, nBitCount, &aDummyPal); 643 Bitmap aNewBmpAlpha; 644 BitmapWriteAccess* pAcc = aNewBmp.AcquireWriteAccess(); 645 BitmapWriteAccess* pAccAlpha = 0; 646 bool bAlphaPossible(pBmpAlpha && aHeader.nBitCount == 32); 647 648 if(bAlphaPossible) 649 { 650 const bool bRedSet(0 != aHeader.nV5RedMask); 651 const bool bGreenSet(0 != aHeader.nV5GreenMask); 652 const bool bBlueSet(0 != aHeader.nV5BlueMask); 653 654 // some clipboard entries have alpha mask on zero to say that there is 655 // no alpha; do only use this when the other masks are set. The MS docu 656 // says that that masks are only to be set when bV5Compression is set to 657 // BI_BITFIELDS, but there seem to exist a wild variety of usages... 658 if((bRedSet || bGreenSet || bBlueSet) && (0 == aHeader.nV5AlphaMask)) 659 { 660 bAlphaPossible = false; 661 } 662 } 663 664 if(bAlphaPossible) 665 { 666 aNewBmpAlpha = Bitmap(aSizePixel, 8); 667 pAccAlpha = aNewBmpAlpha.AcquireWriteAccess(); 668 } 669 670 if(pAcc) 671 { 672 sal_uInt16 nColors(0); 673 SvStream* pIStm; 674 SvMemoryStream* pMemStm = NULL; 675 sal_uInt8* pData = NULL; 676 677 if(nBitCount <= 8) 678 { 679 if(aHeader.nColsUsed) 680 { 681 nColors = (sal_uInt16)aHeader.nColsUsed; 682 } 683 else 684 { 685 nColors = ( 1 << aHeader.nBitCount ); 686 } 687 } 688 689 if(ZCOMPRESS == aHeader.nCompression) 690 { 691 ZCodec aCodec; 692 sal_uInt32 nCodedSize(0); 693 sal_uInt32 nUncodedSize(0); 694 sal_uLong nCodedPos(0); 695 696 // read coding information 697 rIStm >> nCodedSize >> nUncodedSize >> aHeader.nCompression; 698 pData = (sal_uInt8*) rtl_allocateMemory( nUncodedSize ); 699 700 // decode buffer 701 nCodedPos = rIStm.Tell(); 702 aCodec.BeginCompression(); 703 aCodec.Read( rIStm, pData, nUncodedSize ); 704 aCodec.EndCompression(); 705 706 // skip unread bytes from coded buffer 707 rIStm.SeekRel( nCodedSize - ( rIStm.Tell() - nCodedPos ) ); 708 709 // set decoded bytes to memory stream, 710 // from which we will read the bitmap data 711 pIStm = pMemStm = new SvMemoryStream; 712 pMemStm->SetBuffer( (char*) pData, nUncodedSize, false, nUncodedSize ); 713 nOffset = 0; 714 } 715 else 716 { 717 pIStm = &rIStm; 718 } 719 720 // read palette 721 if(nColors) 722 { 723 pAcc->SetPaletteEntryCount(nColors); 724 ImplReadDIBPalette(*pIStm, *pAcc, aHeader.nSize != DIBCOREHEADERSIZE); 725 } 726 727 // read bits 728 if(!pIStm->GetError()) 729 { 730 if(nOffset) 731 { 732 pIStm->SeekRel(nOffset - (pIStm->Tell() - nStmPos)); 733 } 734 735 bRet = ImplReadDIBBits(*pIStm, aHeader, *pAcc, pAccAlpha, bTopDown); 736 737 if(bRet && aHeader.nXPelsPerMeter && aHeader.nYPelsPerMeter) 738 { 739 MapMode aMapMode( 740 MAP_MM, 741 Point(), 742 Fraction(1000, aHeader.nXPelsPerMeter), 743 Fraction(1000, aHeader.nYPelsPerMeter)); 744 745 aNewBmp.SetPrefMapMode(aMapMode); 746 aNewBmp.SetPrefSize(Size(aHeader.nWidth, aHeader.nHeight)); 747 } 748 } 749 750 if( pData ) 751 { 752 rtl_freeMemory(pData); 753 } 754 755 delete pMemStm; 756 aNewBmp.ReleaseAccess(pAcc); 757 758 if(bAlphaPossible) 759 { 760 aNewBmpAlpha.ReleaseAccess(pAccAlpha); 761 } 762 763 if(bRet) 764 { 765 rBmp = aNewBmp; 766 767 if(bAlphaPossible) 768 { 769 *pBmpAlpha = aNewBmpAlpha; 770 } 771 } 772 } 773 } 774 775 return bRet; 776 } 777 778 bool ImplReadDIBFileHeader( SvStream& rIStm, sal_uLong& rOffset ) 779 { 780 sal_uInt32 nTmp32; 781 sal_uInt16 nTmp16 = 0; 782 bool bRet = false; 783 784 rIStm >> nTmp16; 785 786 if ( ( 0x4D42 == nTmp16 ) || ( 0x4142 == nTmp16 ) ) 787 { 788 if ( 0x4142 == nTmp16 ) 789 { 790 rIStm.SeekRel( 12L ); 791 rIStm >> nTmp16; 792 rIStm.SeekRel( 8L ); 793 rIStm >> nTmp32; 794 rOffset = nTmp32 - 28UL; 795 bRet = ( 0x4D42 == nTmp16 ); 796 } 797 else // 0x4D42 == nTmp16, 'MB' from BITMAPFILEHEADER 798 { 799 rIStm.SeekRel( 8L ); // we are on bfSize member of BITMAPFILEHEADER, forward to bfOffBits 800 rIStm >> nTmp32; // read bfOffBits 801 rOffset = nTmp32 - 14UL; // adapt offset by sizeof(BITMAPFILEHEADER) 802 bRet = ( rIStm.GetError() == 0UL ); 803 } 804 } 805 else 806 rIStm.SetError( SVSTREAM_FILEFORMAT_ERROR ); 807 808 return bRet; 809 } 810 811 bool ImplWriteDIBPalette( SvStream& rOStm, BitmapReadAccess& rAcc ) 812 { 813 const sal_uInt16 nColors = rAcc.GetPaletteEntryCount(); 814 const sal_uLong nPalSize = nColors * 4UL; 815 sal_uInt8* pEntries = new sal_uInt8[ nPalSize ]; 816 sal_uInt8* pTmpEntry = pEntries; 817 BitmapColor aPalColor; 818 819 for( sal_uInt16 i = 0; i < nColors; i++ ) 820 { 821 const BitmapColor& rPalColor = rAcc.GetPaletteColor( i ); 822 823 *pTmpEntry++ = rPalColor.GetBlue(); 824 *pTmpEntry++ = rPalColor.GetGreen(); 825 *pTmpEntry++ = rPalColor.GetRed(); 826 *pTmpEntry++ = 0; 827 } 828 829 rOStm.Write( pEntries, nPalSize ); 830 delete[] pEntries; 831 832 return( rOStm.GetError() == 0UL ); 833 } 834 835 bool ImplWriteRLE( SvStream& rOStm, BitmapReadAccess& rAcc, bool bRLE4 ) 836 { 837 const sal_uLong nWidth = rAcc.Width(); 838 const sal_uLong nHeight = rAcc.Height(); 839 sal_uLong nX; 840 sal_uLong nSaveIndex; 841 sal_uLong nCount; 842 sal_uLong nBufCount; 843 sal_uInt8* pBuf = new sal_uInt8[ ( nWidth << 1 ) + 2 ]; 844 sal_uInt8* pTmp; 845 sal_uInt8 cPix; 846 sal_uInt8 cLast; 847 bool bFound; 848 849 for ( long nY = nHeight - 1L; nY >= 0L; nY-- ) 850 { 851 pTmp = pBuf; 852 nX = nBufCount = 0UL; 853 854 while( nX < nWidth ) 855 { 856 nCount = 1L; 857 cPix = rAcc.GetPixelIndex( nY, nX++ ); 858 859 while( ( nX < nWidth ) && ( nCount < 255L ) 860 && ( cPix == rAcc.GetPixelIndex( nY, nX ) ) ) 861 { 862 nX++; 863 nCount++; 864 } 865 866 if ( nCount > 1 ) 867 { 868 *pTmp++ = (sal_uInt8) nCount; 869 *pTmp++ = ( bRLE4 ? ( ( cPix << 4 ) | cPix ) : cPix ); 870 nBufCount += 2; 871 } 872 else 873 { 874 cLast = cPix; 875 nSaveIndex = nX - 1UL; 876 bFound = false; 877 878 while( ( nX < nWidth ) && ( nCount < 256L ) 879 && ( cPix = rAcc.GetPixelIndex( nY, nX ) ) != cLast ) 880 { 881 nX++; nCount++; 882 cLast = cPix; 883 bFound = true; 884 } 885 886 if ( bFound ) 887 nX--; 888 889 if ( nCount > 3 ) 890 { 891 *pTmp++ = 0; 892 *pTmp++ = (sal_uInt8) --nCount; 893 894 if( bRLE4 ) 895 { 896 for ( sal_uLong i = 0; i < nCount; i++, pTmp++ ) 897 { 898 *pTmp = rAcc.GetPixelIndex( nY, nSaveIndex++ ) << 4; 899 900 if ( ++i < nCount ) 901 *pTmp |= rAcc.GetPixelIndex( nY, nSaveIndex++ ); 902 } 903 904 nCount = ( nCount + 1 ) >> 1; 905 } 906 else 907 { 908 for( sal_uLong i = 0UL; i < nCount; i++ ) 909 *pTmp++ = rAcc.GetPixelIndex( nY, nSaveIndex++ ); 910 } 911 912 if ( nCount & 1 ) 913 { 914 *pTmp++ = 0; 915 nBufCount += ( nCount + 3 ); 916 } 917 else 918 nBufCount += ( nCount + 2 ); 919 } 920 else 921 { 922 *pTmp++ = 1; 923 *pTmp++ = rAcc.GetPixelIndex( nY, nSaveIndex ) << (bRLE4 ? 4 : 0); 924 925 if ( nCount == 3 ) 926 { 927 *pTmp++ = 1; 928 *pTmp++ = rAcc.GetPixelIndex( nY, ++nSaveIndex ) << ( bRLE4 ? 4 : 0 ); 929 nBufCount += 4; 930 } 931 else 932 nBufCount += 2; 933 } 934 } 935 } 936 937 pBuf[ nBufCount++ ] = 0; 938 pBuf[ nBufCount++ ] = 0; 939 940 rOStm.Write( pBuf, nBufCount ); 941 } 942 943 rOStm << (sal_uInt8) 0; 944 rOStm << (sal_uInt8) 1; 945 946 delete[] pBuf; 947 948 return( rOStm.GetError() == 0UL ); 949 } 950 951 bool ImplWriteDIBBits(SvStream& rOStm, BitmapReadAccess& rAcc, BitmapReadAccess* pAccAlpha, sal_uLong nCompression, sal_uInt32& rImageSize) 952 { 953 if(!pAccAlpha && BITFIELDS == nCompression) 954 { 955 const ColorMask& rMask = rAcc.GetColorMask(); 956 SVBT32 aVal32; 957 958 UInt32ToSVBT32( rMask.GetRedMask(), aVal32 ); 959 rOStm.Write( (sal_uInt8*) aVal32, 4UL ); 960 961 UInt32ToSVBT32( rMask.GetGreenMask(), aVal32 ); 962 rOStm.Write( (sal_uInt8*) aVal32, 4UL ); 963 964 UInt32ToSVBT32( rMask.GetBlueMask(), aVal32 ); 965 rOStm.Write( (sal_uInt8*) aVal32, 4UL ); 966 967 rImageSize = rOStm.Tell(); 968 969 if( rAcc.IsBottomUp() ) 970 rOStm.Write( rAcc.GetBuffer(), rAcc.Height() * rAcc.GetScanlineSize() ); 971 else 972 { 973 for( long nY = rAcc.Height() - 1, nScanlineSize = rAcc.GetScanlineSize(); nY >= 0L; nY-- ) 974 rOStm.Write( rAcc.GetScanline( nY ), nScanlineSize ); 975 } 976 } 977 else if(!pAccAlpha && ((RLE_4 == nCompression) || (RLE_8 == nCompression))) 978 { 979 rImageSize = rOStm.Tell(); 980 ImplWriteRLE( rOStm, rAcc, RLE_4 == nCompression ); 981 } 982 else if(!nCompression) 983 { 984 // #i5xxx# Limit bitcount to 24bit, the 32 bit cases are not 985 // handled properly below (would have to set color masks, and 986 // nCompression=BITFIELDS - but color mask is not set for 987 // formats != *_TC_*). Note that this very problem might cause 988 // trouble at other places - the introduction of 32 bit RGBA 989 // bitmaps is relatively recent. 990 // #i59239# discretize bitcount for aligned width to 1,4,8,24 991 // (other cases are not written below) 992 const sal_uInt16 nBitCount(pAccAlpha ? 32 : discretizeBitcount(static_cast< sal_uInt16 >(rAcc.GetBitCount()))); 993 const sal_uLong nAlignedWidth(AlignedWidth4Bytes(rAcc.Width() * nBitCount)); 994 bool bNative(false); 995 996 switch(rAcc.GetScanlineFormat()) 997 { 998 case( BMP_FORMAT_1BIT_MSB_PAL ): 999 case( BMP_FORMAT_4BIT_MSN_PAL ): 1000 case( BMP_FORMAT_8BIT_PAL ): 1001 case( BMP_FORMAT_24BIT_TC_BGR ): 1002 { 1003 if(!pAccAlpha && rAcc.IsBottomUp() && (rAcc.GetScanlineSize() == nAlignedWidth)) 1004 { 1005 bNative = true; 1006 } 1007 1008 break; 1009 } 1010 1011 default: 1012 { 1013 break; 1014 } 1015 } 1016 1017 rImageSize = rOStm.Tell(); 1018 1019 if(bNative) 1020 { 1021 rOStm.Write(rAcc.GetBuffer(), nAlignedWidth * rAcc.Height()); 1022 } 1023 else 1024 { 1025 const long nWidth(rAcc.Width()); 1026 const long nHeight(rAcc.Height()); 1027 sal_uInt8* pBuf = new sal_uInt8[ nAlignedWidth ]; 1028 sal_uInt8* pTmp(0); 1029 sal_uInt8 cTmp(0); 1030 1031 switch( nBitCount ) 1032 { 1033 case( 1 ): 1034 { 1035 for( long nY = nHeight - 1; nY >= 0L; nY-- ) 1036 { 1037 pTmp = pBuf; 1038 cTmp = 0; 1039 1040 for( long nX = 0L, nShift = 8L; nX < nWidth; nX++ ) 1041 { 1042 if( !nShift ) 1043 { 1044 nShift = 8L; 1045 *pTmp++ = cTmp; 1046 cTmp = 0; 1047 } 1048 1049 cTmp |= rAcc.GetPixelIndex( nY, nX ) << --nShift; 1050 } 1051 1052 *pTmp = cTmp; 1053 rOStm.Write( pBuf, nAlignedWidth ); 1054 } 1055 } 1056 break; 1057 1058 case( 4 ): 1059 { 1060 for( long nY = nHeight - 1; nY >= 0L; nY-- ) 1061 { 1062 pTmp = pBuf; 1063 cTmp = 0; 1064 1065 for( long nX = 0L, nShift = 2L; nX < nWidth; nX++ ) 1066 { 1067 if( !nShift ) 1068 { 1069 nShift = 2L; 1070 *pTmp++ = cTmp; 1071 cTmp = 0; 1072 } 1073 1074 cTmp |= rAcc.GetPixelIndex( nY, nX ) << ( --nShift << 2L ); 1075 } 1076 *pTmp = cTmp; 1077 rOStm.Write( pBuf, nAlignedWidth ); 1078 } 1079 } 1080 break; 1081 1082 case( 8 ): 1083 { 1084 for( long nY = nHeight - 1; nY >= 0L; nY-- ) 1085 { 1086 pTmp = pBuf; 1087 1088 for( long nX = 0L; nX < nWidth; nX++ ) 1089 *pTmp++ = rAcc.GetPixelIndex( nY, nX ); 1090 1091 rOStm.Write( pBuf, nAlignedWidth ); 1092 } 1093 } 1094 break; 1095 1096 // #i59239# fallback to 24 bit format, if bitcount is non-default 1097 default: 1098 // FALLTHROUGH intended 1099 case( 24 ): 1100 { 1101 BitmapColor aPixelColor; 1102 const bool bWriteAlpha(32 == nBitCount && pAccAlpha); 1103 1104 for( long nY = nHeight - 1; nY >= 0L; nY-- ) 1105 { 1106 pTmp = pBuf; 1107 1108 for( long nX = 0L; nX < nWidth; nX++ ) 1109 { 1110 // when alpha is used, this may be non-24bit main bitmap, so use GetColor 1111 // instead of GetPixel to ensure RGB value 1112 aPixelColor = rAcc.GetColor( nY, nX ); 1113 1114 *pTmp++ = aPixelColor.GetBlue(); 1115 *pTmp++ = aPixelColor.GetGreen(); 1116 *pTmp++ = aPixelColor.GetRed(); 1117 1118 if(bWriteAlpha) 1119 { 1120 if(pAccAlpha) 1121 { 1122 *pTmp++ = (sal_uInt8)0xff - (sal_uInt8)pAccAlpha->GetPixelIndex( nY, nX ); 1123 } 1124 else 1125 { 1126 *pTmp++ = (sal_uInt8)0xff; 1127 } 1128 } 1129 } 1130 1131 rOStm.Write( pBuf, nAlignedWidth ); 1132 } 1133 } 1134 break; 1135 } 1136 1137 delete[] pBuf; 1138 } 1139 } 1140 1141 rImageSize = rOStm.Tell() - rImageSize; 1142 1143 return (!rOStm.GetError()); 1144 } 1145 1146 bool ImplWriteDIBBody(const Bitmap& rBitmap, SvStream& rOStm, BitmapReadAccess& rAcc, BitmapReadAccess* pAccAlpha, bool bCompressed) 1147 { 1148 const MapMode aMapPixel(MAP_PIXEL); 1149 DIBV5Header aHeader; 1150 sal_uLong nImageSizePos(0); 1151 sal_uLong nEndPos(0); 1152 sal_uInt32 nCompression(COMPRESS_NONE); 1153 bool bRet(false); 1154 1155 aHeader.nSize = pAccAlpha ? DIBV5HEADERSIZE : DIBINFOHEADERSIZE; // size dependent on CF_DIB type to use 1156 aHeader.nWidth = rAcc.Width(); 1157 aHeader.nHeight = rAcc.Height(); 1158 aHeader.nPlanes = 1; 1159 1160 if(!pAccAlpha && isBitfieldCompression(rAcc.GetScanlineFormat())) 1161 { 1162 aHeader.nBitCount = (BMP_FORMAT_16BIT_TC_LSB_MASK == rAcc.GetScanlineFormat()) ? 16 : 32; 1163 aHeader.nSizeImage = rAcc.Height() * rAcc.GetScanlineSize(); 1164 nCompression = BITFIELDS; 1165 } 1166 else 1167 { 1168 // #i5xxx# Limit bitcount to 24bit, the 32 bit cases are 1169 // not handled properly below (would have to set color 1170 // masks, and nCompression=BITFIELDS - but color mask is 1171 // not set for formats != *_TC_*). Note that this very 1172 // problem might cause trouble at other places - the 1173 // introduction of 32 bit RGBA bitmaps is relatively 1174 // recent. 1175 // #i59239# discretize bitcount to 1,4,8,24 (other cases 1176 // are not written below) 1177 const sal_uInt16 nBitCount(pAccAlpha ? 32 : discretizeBitcount(static_cast< sal_uInt16 >(rAcc.GetBitCount()))); 1178 aHeader.nBitCount = nBitCount; 1179 aHeader.nSizeImage = rAcc.Height() * AlignedWidth4Bytes(rAcc.Width() * aHeader.nBitCount); 1180 1181 if(bCompressed) 1182 { 1183 if(4 == nBitCount) 1184 { 1185 nCompression = RLE_4; 1186 } 1187 else if(8 == nBitCount) 1188 { 1189 nCompression = RLE_8; 1190 } 1191 } 1192 } 1193 1194 if((rOStm.GetCompressMode() & COMPRESSMODE_ZBITMAP) && (rOStm.GetVersion() >= SOFFICE_FILEFORMAT_40)) 1195 { 1196 aHeader.nCompression = ZCOMPRESS; 1197 } 1198 else 1199 { 1200 aHeader.nCompression = nCompression; 1201 } 1202 1203 if(rBitmap.GetPrefSize().Width() && rBitmap.GetPrefSize().Height() && (rBitmap.GetPrefMapMode() != aMapPixel)) 1204 { 1205 // #i48108# Try to recover xpels/ypels as previously stored on 1206 // disk. The problem with just converting maPrefSize to 100th 1207 // mm and then relating that to the bitmap pixel size is that 1208 // MapMode is integer-based, and suffers from roundoffs, 1209 // especially if maPrefSize is small. Trying to circumvent 1210 // that by performing part of the math in floating point. 1211 const Size aScale100000(OutputDevice::LogicToLogic(Size(100000L, 100000L), MAP_100TH_MM, rBitmap.GetPrefMapMode())); 1212 const double fBmpWidthM((double)rBitmap.GetPrefSize().Width() / aScale100000.Width()); 1213 const double fBmpHeightM((double)rBitmap.GetPrefSize().Height() / aScale100000.Height()); 1214 1215 if(!basegfx::fTools::equalZero(fBmpWidthM) && !basegfx::fTools::equalZero(fBmpHeightM)) 1216 { 1217 aHeader.nXPelsPerMeter = basegfx::fround(rAcc.Width() / fabs(fBmpWidthM)); 1218 aHeader.nYPelsPerMeter = basegfx::fround(rAcc.Height() / fabs(fBmpHeightM)); 1219 } 1220 } 1221 1222 aHeader.nColsUsed = ((!pAccAlpha && aHeader.nBitCount <= 8) ? rAcc.GetPaletteEntryCount() : 0); 1223 aHeader.nColsImportant = 0; 1224 1225 rOStm << aHeader.nSize; 1226 rOStm << aHeader.nWidth; 1227 rOStm << aHeader.nHeight; 1228 rOStm << aHeader.nPlanes; 1229 rOStm << aHeader.nBitCount; 1230 rOStm << aHeader.nCompression; 1231 1232 nImageSizePos = rOStm.Tell(); 1233 rOStm.SeekRel( sizeof( aHeader.nSizeImage ) ); 1234 1235 rOStm << aHeader.nXPelsPerMeter; 1236 rOStm << aHeader.nYPelsPerMeter; 1237 rOStm << aHeader.nColsUsed; 1238 rOStm << aHeader.nColsImportant; 1239 1240 if(pAccAlpha) // only write DIBV5 when asked to do so 1241 { 1242 aHeader.nV5CSType = 0x57696E20; // LCS_WINDOWS_COLOR_SPACE 1243 aHeader.nV5Intent = 0x00000008; // LCS_GM_ABS_COLORIMETRIC 1244 1245 rOStm << aHeader.nV5RedMask; 1246 rOStm << aHeader.nV5GreenMask; 1247 rOStm << aHeader.nV5BlueMask; 1248 rOStm << aHeader.nV5AlphaMask; 1249 rOStm << aHeader.nV5CSType; 1250 1251 rOStm << aHeader.aV5Endpoints.aXyzRed.aXyzX; 1252 rOStm << aHeader.aV5Endpoints.aXyzRed.aXyzY; 1253 rOStm << aHeader.aV5Endpoints.aXyzRed.aXyzZ; 1254 rOStm << aHeader.aV5Endpoints.aXyzGreen.aXyzX; 1255 rOStm << aHeader.aV5Endpoints.aXyzGreen.aXyzY; 1256 rOStm << aHeader.aV5Endpoints.aXyzGreen.aXyzZ; 1257 rOStm << aHeader.aV5Endpoints.aXyzBlue.aXyzX; 1258 rOStm << aHeader.aV5Endpoints.aXyzBlue.aXyzY; 1259 rOStm << aHeader.aV5Endpoints.aXyzBlue.aXyzZ; 1260 1261 rOStm << aHeader.nV5GammaRed; 1262 rOStm << aHeader.nV5GammaGreen; 1263 rOStm << aHeader.nV5GammaBlue; 1264 rOStm << aHeader.nV5Intent; 1265 rOStm << aHeader.nV5ProfileData; 1266 rOStm << aHeader.nV5ProfileSize; 1267 rOStm << aHeader.nV5Reserved; 1268 } 1269 1270 if(ZCOMPRESS == aHeader.nCompression) 1271 { 1272 ZCodec aCodec; 1273 SvMemoryStream aMemStm(aHeader.nSizeImage + 4096, 65535); 1274 sal_uLong nCodedPos(rOStm.Tell()); 1275 sal_uLong nLastPos(0); 1276 sal_uInt32 nCodedSize(0); 1277 sal_uInt32 nUncodedSize(0); 1278 1279 // write uncoded data palette 1280 if(aHeader.nColsUsed) 1281 { 1282 ImplWriteDIBPalette(aMemStm, rAcc); 1283 } 1284 1285 // write uncoded bits 1286 bRet = ImplWriteDIBBits(aMemStm, rAcc, pAccAlpha, nCompression, aHeader.nSizeImage); 1287 1288 // get uncoded size 1289 nUncodedSize = aMemStm.Tell(); 1290 1291 // seek over compress info 1292 rOStm.SeekRel(12); 1293 1294 // write compressed data 1295 aCodec.BeginCompression(3); 1296 aCodec.Write(rOStm, (sal_uInt8*)aMemStm.GetData(), nUncodedSize); 1297 aCodec.EndCompression(); 1298 1299 // update compress info ( coded size, uncoded size, uncoded compression ) 1300 nLastPos = rOStm.Tell(); 1301 nCodedSize = nLastPos - nCodedPos - 12; 1302 rOStm.Seek(nCodedPos); 1303 rOStm << nCodedSize << nUncodedSize << nCompression; 1304 rOStm.Seek(nLastPos); 1305 1306 if(bRet) 1307 { 1308 bRet = (ERRCODE_NONE == rOStm.GetError()); 1309 } 1310 } 1311 else 1312 { 1313 if(aHeader.nColsUsed) 1314 { 1315 ImplWriteDIBPalette(rOStm, rAcc); 1316 } 1317 1318 bRet = ImplWriteDIBBits(rOStm, rAcc, pAccAlpha, aHeader.nCompression, aHeader.nSizeImage); 1319 } 1320 1321 nEndPos = rOStm.Tell(); 1322 rOStm.Seek(nImageSizePos); 1323 rOStm << aHeader.nSizeImage; 1324 rOStm.Seek(nEndPos); 1325 1326 return bRet; 1327 } 1328 1329 bool ImplWriteDIBFileHeader(SvStream& rOStm, BitmapReadAccess& rAcc, bool bUseDIBV5) 1330 { 1331 const sal_uInt32 nPalCount((rAcc.HasPalette() ? rAcc.GetPaletteEntryCount() : isBitfieldCompression(rAcc.GetScanlineFormat()) ? 3UL : 0UL)); 1332 const sal_uInt32 nOffset(14 + (bUseDIBV5 ? DIBV5HEADERSIZE : DIBINFOHEADERSIZE) + nPalCount * 4UL); 1333 1334 rOStm << (sal_uInt16)0x4D42; // 'MB' from BITMAPFILEHEADER 1335 rOStm << (sal_uInt32)(nOffset + (rAcc.Height() * rAcc.GetScanlineSize())); 1336 rOStm << (sal_uInt16)0; 1337 rOStm << (sal_uInt16)0; 1338 rOStm << nOffset; 1339 1340 return( rOStm.GetError() == 0UL ); 1341 } 1342 1343 ////////////////////////////////////////////////////////////////////////////// 1344 1345 bool ImplReadDIB( 1346 Bitmap& rTarget, Bitmap* 1347 pTargetAlpha, 1348 SvStream& rIStm, 1349 bool bFileHeader) 1350 { 1351 const sal_uInt16 nOldFormat(rIStm.GetNumberFormatInt()); 1352 const sal_uLong nOldPos(rIStm.Tell()); 1353 sal_uLong nOffset(0UL); 1354 bool bRet(false); 1355 1356 rIStm.SetNumberFormatInt(NUMBERFORMAT_INT_LITTLEENDIAN); 1357 1358 if(bFileHeader) 1359 { 1360 if(ImplReadDIBFileHeader(rIStm, nOffset)) 1361 { 1362 bRet = ImplReadDIBBody(rIStm, rTarget, nOffset >= DIBV5HEADERSIZE ? pTargetAlpha : 0, nOffset); 1363 } 1364 } 1365 else 1366 { 1367 bRet = ImplReadDIBBody(rIStm, rTarget, 0, nOffset); 1368 } 1369 1370 if(!bRet) 1371 { 1372 if(!rIStm.GetError()) 1373 { 1374 rIStm.SetError(SVSTREAM_GENERALERROR); 1375 } 1376 1377 rIStm.Seek(nOldPos); 1378 } 1379 1380 rIStm.SetNumberFormatInt(nOldFormat); 1381 1382 return bRet; 1383 } 1384 1385 bool ImplWriteDIB( 1386 const Bitmap& rSource, 1387 const Bitmap* pSourceAlpha, 1388 SvStream& rOStm, 1389 bool bCompressed, 1390 bool bFileHeader) 1391 { 1392 const Size aSizePix(rSource.GetSizePixel()); 1393 bool bRet(false); 1394 1395 if(aSizePix.Width() && aSizePix.Height()) 1396 { 1397 BitmapReadAccess* pAcc = const_cast< Bitmap& >(rSource).AcquireReadAccess(); 1398 BitmapReadAccess* pAccAlpha = 0; 1399 const sal_uInt16 nOldFormat(rOStm.GetNumberFormatInt()); 1400 const sal_uLong nOldPos(rOStm.Tell()); 1401 1402 if(pSourceAlpha) 1403 { 1404 const Size aSizePixAlpha(pSourceAlpha->GetSizePixel()); 1405 1406 if(aSizePixAlpha == aSizePix) 1407 { 1408 pAccAlpha = const_cast< Bitmap* >(pSourceAlpha)->AcquireReadAccess(); 1409 } 1410 else 1411 { 1412 OSL_ENSURE(false, "WriteDIB got an alpha channel, but it's pixel size differs from the base bitmap (!)"); 1413 } 1414 } 1415 1416 rOStm.SetNumberFormatInt(NUMBERFORMAT_INT_LITTLEENDIAN); 1417 1418 if(pAcc) 1419 { 1420 if(bFileHeader) 1421 { 1422 if(ImplWriteDIBFileHeader(rOStm, *pAcc, 0 != pSourceAlpha)) 1423 { 1424 bRet = ImplWriteDIBBody(rSource, rOStm, *pAcc, pAccAlpha, bCompressed); 1425 } 1426 } 1427 else 1428 { 1429 bRet = ImplWriteDIBBody(rSource, rOStm, *pAcc, pAccAlpha, bCompressed); 1430 } 1431 1432 const_cast< Bitmap& >(rSource).ReleaseAccess(pAcc); 1433 1434 if(pAccAlpha) 1435 { 1436 const_cast< Bitmap* >(pSourceAlpha)->ReleaseAccess(pAccAlpha); 1437 } 1438 } 1439 1440 if(!bRet) 1441 { 1442 rOStm.SetError(SVSTREAM_GENERALERROR); 1443 rOStm.Seek(nOldPos); 1444 } 1445 1446 rOStm.SetNumberFormatInt(nOldFormat); 1447 } 1448 1449 return bRet; 1450 } 1451 1452 ////////////////////////////////////////////////////////////////////////////// 1453 1454 bool ReadDIB( 1455 Bitmap& rTarget, 1456 SvStream& rIStm, 1457 bool bFileHeader) 1458 { 1459 return ImplReadDIB(rTarget, 0, rIStm, bFileHeader); 1460 } 1461 1462 bool ReadDIBBitmapEx( 1463 BitmapEx& rTarget, 1464 SvStream& rIStm) 1465 { 1466 Bitmap aBmp; 1467 bool bRetval(ImplReadDIB(aBmp, 0, rIStm, true) && !rIStm.GetError()); 1468 1469 if(bRetval) 1470 { 1471 // base bitmap was read, set as return value and try to read alpha extra-data 1472 const sal_uLong nStmPos(rIStm.Tell()); 1473 sal_uInt32 nMagic1(0); 1474 sal_uInt32 nMagic2(0); 1475 1476 rTarget = BitmapEx(aBmp); 1477 rIStm >> nMagic1 >> nMagic2; 1478 bRetval = (0x25091962 == nMagic1) && (0xACB20201 == nMagic2) && !rIStm.GetError(); 1479 1480 if(bRetval) 1481 { 1482 sal_uInt8 bTransparent(false); 1483 1484 rIStm >> bTransparent; 1485 bRetval = !rIStm.GetError(); 1486 1487 if(bRetval) 1488 { 1489 if((sal_uInt8)TRANSPARENT_BITMAP == bTransparent) 1490 { 1491 Bitmap aMask; 1492 1493 bRetval = ImplReadDIB(aMask, 0, rIStm, true); 1494 1495 if(bRetval) 1496 { 1497 if(!!aMask) 1498 { 1499 // do we have an alpha mask? 1500 if((8 == aMask.GetBitCount()) && aMask.HasGreyPalette()) 1501 { 1502 AlphaMask aAlpha; 1503 1504 // create alpha mask quickly (without greyscale conversion) 1505 aAlpha.ImplSetBitmap(aMask); 1506 rTarget = BitmapEx(aBmp, aAlpha); 1507 } 1508 else 1509 { 1510 rTarget = BitmapEx(aBmp, aMask); 1511 } 1512 } 1513 } 1514 } 1515 else if((sal_uInt8)TRANSPARENT_COLOR == bTransparent) 1516 { 1517 Color aTransparentColor; 1518 1519 rIStm >> aTransparentColor; 1520 bRetval = !rIStm.GetError(); 1521 1522 if(bRetval) 1523 { 1524 rTarget = BitmapEx(aBmp, aTransparentColor); 1525 } 1526 } 1527 } 1528 } 1529 1530 if(!bRetval) 1531 { 1532 // alpha extra data could not be read; reset, but use base bitmap as result 1533 rIStm.ResetError(); 1534 rIStm.Seek(nStmPos); 1535 bRetval = true; 1536 } 1537 } 1538 1539 return bRetval; 1540 } 1541 1542 bool ReadDIBV5( 1543 Bitmap& rTarget, 1544 Bitmap& rTargetAlpha, 1545 SvStream& rIStm) 1546 { 1547 return ImplReadDIB(rTarget, &rTargetAlpha, rIStm, true); 1548 } 1549 1550 ////////////////////////////////////////////////////////////////////////////// 1551 1552 bool WriteDIB( 1553 const Bitmap& rSource, 1554 SvStream& rOStm, 1555 bool bCompressed, 1556 bool bFileHeader) 1557 { 1558 return ImplWriteDIB(rSource, 0, rOStm, bCompressed, bFileHeader); 1559 } 1560 1561 bool WriteDIBBitmapEx( 1562 const BitmapEx& rSource, 1563 SvStream& rOStm) 1564 { 1565 if(ImplWriteDIB(rSource.GetBitmap(), 0, rOStm, true, true)) 1566 { 1567 rOStm << (sal_uInt32)0x25091962; 1568 rOStm << (sal_uInt32)0xACB20201; 1569 rOStm << (sal_uInt8)rSource.eTransparent; 1570 1571 if(TRANSPARENT_BITMAP == rSource.eTransparent) 1572 { 1573 return ImplWriteDIB(rSource.aMask, 0, rOStm, true, true); 1574 } 1575 else if(TRANSPARENT_COLOR == rSource.eTransparent) 1576 { 1577 rOStm << rSource.aTransparentColor; 1578 return true; 1579 } 1580 } 1581 1582 return false; 1583 } 1584 1585 bool WriteDIBV5( 1586 const Bitmap& rSource, 1587 const Bitmap& rSourceAlpha, 1588 SvStream& rOStm) 1589 { 1590 return ImplWriteDIB(rSource, &rSourceAlpha, rOStm, false, true); 1591 } 1592 1593 ////////////////////////////////////////////////////////////////////////////// 1594 // eof 1595