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 <unistd.h> 32 #include <cstdio> 33 #include <cstring> 34 35 #include <bmp.hxx> 36 37 #include <X11_selection.hxx> 38 39 using namespace x11; 40 using namespace com::sun::star::uno; 41 using namespace com::sun::star::script; 42 using namespace com::sun::star::awt; 43 using namespace rtl; 44 45 /* 46 * helper functions 47 */ 48 49 inline void writeLE( sal_uInt16 nNumber, sal_uInt8* pBuffer ) 50 { 51 pBuffer[ 0 ] = (nNumber & 0xff); 52 pBuffer[ 1 ] = ((nNumber>>8)&0xff); 53 } 54 55 inline void writeLE( sal_uInt32 nNumber, sal_uInt8* pBuffer ) 56 { 57 pBuffer[ 0 ] = (nNumber & 0xff); 58 pBuffer[ 1 ] = ((nNumber>>8)&0xff); 59 pBuffer[ 2 ] = ((nNumber>>16)&0xff); 60 pBuffer[ 3 ] = ((nNumber>>24)&0xff); 61 } 62 63 inline sal_uInt16 readLE16( const sal_uInt8* pBuffer ) 64 { 65 return (((sal_uInt16)pBuffer[1]) << 8 ) | pBuffer[0]; 66 } 67 68 inline sal_uInt16 readLE32( const sal_uInt8* pBuffer ) 69 { 70 return 71 (((sal_uInt32)pBuffer[3]) << 24 ) | 72 (((sal_uInt32)pBuffer[2]) << 16 ) | 73 (((sal_uInt32)pBuffer[1]) << 8 ) | 74 pBuffer[0]; 75 } 76 77 78 /* 79 * BmpTransporter 80 */ 81 82 BmpTransporter::BmpTransporter( const Sequence<sal_Int8>& rBmp ) : 83 m_aBM( rBmp ) 84 { 85 const sal_uInt8* pData = (const sal_uInt8*)rBmp.getConstArray(); 86 87 if( pData[0] == 'B' || pData[1] == 'M' ) 88 { 89 pData = pData+14; 90 m_aSize.Width = readLE32( pData+4 ); 91 m_aSize.Height = readLE32( pData+8 ); 92 } 93 else 94 m_aSize.Width = m_aSize.Height = 0; 95 } 96 97 BmpTransporter::~BmpTransporter() 98 { 99 } 100 101 com::sun::star::awt::Size SAL_CALL BmpTransporter::getSize() throw() 102 { 103 return m_aSize; 104 } 105 106 Sequence< sal_Int8 > SAL_CALL BmpTransporter::getDIB() throw() 107 { 108 return m_aBM; 109 } 110 111 Sequence< sal_Int8 > SAL_CALL BmpTransporter::getMaskDIB() throw() 112 { 113 return Sequence< sal_Int8 >(); 114 } 115 116 /* 117 * scanline helpers 118 */ 119 120 inline void X11_writeScanlinePixel( unsigned long nColor, sal_uInt8* pScanline, int depth, int x ) 121 { 122 switch( depth ) 123 { 124 case 1: 125 pScanline[ x/8 ] &= ~(1 << (x&7)); 126 pScanline[ x/8 ] |= ((nColor & 1) << (x&7)); 127 break; 128 case 4: 129 pScanline[ x/2 ] &= ((x&1) ? 0x0f : 0xf0); 130 pScanline[ x/2 ] |= ((x&1) ? (nColor & 0x0f) : ((nColor & 0x0f) << 4)); 131 break; 132 default: 133 case 8: 134 pScanline[ x ] = (nColor & 0xff); 135 break; 136 } 137 } 138 139 static sal_uInt8* X11_getPaletteBmpFromImage( 140 Display* pDisplay, 141 XImage* pImage, 142 Colormap aColormap, 143 sal_Int32& rOutSize 144 ) 145 { 146 sal_uInt32 nColors = 0; 147 148 rOutSize = 0; 149 150 sal_uInt8* pBuffer = 0; 151 sal_uInt32 nHeaderSize, nScanlineSize; 152 sal_uInt16 nBitCount; 153 // determine header and scanline size 154 switch( pImage->depth ) 155 { 156 case 1: 157 nHeaderSize = 64; 158 nScanlineSize = (pImage->width+31)/32; 159 nBitCount = 1; 160 break; 161 case 4: 162 nHeaderSize = 72; 163 nScanlineSize = (pImage->width+1)/2; 164 nBitCount = 4; 165 break; 166 default: 167 case 8: 168 nHeaderSize = 1084; 169 nScanlineSize = pImage->width; 170 nBitCount = 8; 171 break; 172 } 173 // adjust scan lines to begin on %4 boundaries 174 if( nScanlineSize & 3 ) 175 { 176 nScanlineSize &= 0xfffffffc; 177 nScanlineSize += 4; 178 } 179 180 // allocate buffer to hold header and scanlines, initialize to zero 181 rOutSize = nHeaderSize + nScanlineSize*pImage->height; 182 pBuffer = (sal_uInt8*)rtl_allocateZeroMemory( rOutSize ); 183 for( int y = 0; y < pImage->height; y++ ) 184 { 185 sal_uInt8* pScanline = pBuffer + nHeaderSize + (pImage->height-1-y)*nScanlineSize; 186 for( int x = 0; x < pImage->width; x++ ) 187 { 188 unsigned long nPixel = XGetPixel( pImage, x, y ); 189 if( nPixel >= nColors ) 190 nColors = nPixel+1; 191 X11_writeScanlinePixel( nPixel, pScanline, pImage->depth, x ); 192 } 193 } 194 195 // fill in header fields 196 pBuffer[ 0 ] = 'B'; 197 pBuffer[ 1 ] = 'M'; 198 199 writeLE( nHeaderSize, pBuffer+10 ); 200 writeLE( (sal_uInt32)40, pBuffer+14 ); 201 writeLE( (sal_uInt32)pImage->width, pBuffer+18 ); 202 writeLE( (sal_uInt32)pImage->height, pBuffer+22 ); 203 writeLE( (sal_uInt16)1, pBuffer+26 ); 204 writeLE( nBitCount, pBuffer+28 ); 205 writeLE( (sal_uInt32)(DisplayWidth(pDisplay,DefaultScreen(pDisplay))*1000/DisplayWidthMM(pDisplay,DefaultScreen(pDisplay))), pBuffer+38); 206 writeLE( (sal_uInt32)(DisplayHeight(pDisplay,DefaultScreen(pDisplay))*1000/DisplayHeightMM(pDisplay,DefaultScreen(pDisplay))), pBuffer+42); 207 writeLE( nColors, pBuffer+46 ); 208 writeLE( nColors, pBuffer+50 ); 209 210 XColor aColors[256]; 211 if( nColors > (1U << nBitCount) ) // paranoia 212 nColors = (1U << nBitCount); 213 for( unsigned long nPixel = 0; nPixel < nColors; nPixel++ ) 214 { 215 aColors[nPixel].flags = DoRed | DoGreen | DoBlue; 216 aColors[nPixel].pixel = nPixel; 217 } 218 XQueryColors( pDisplay, aColormap, aColors, nColors ); 219 for( sal_uInt32 i = 0; i < nColors; i++ ) 220 { 221 pBuffer[ 54 + i*4 ] = (sal_uInt8)(aColors[i].blue >> 8); 222 pBuffer[ 55 + i*4 ] = (sal_uInt8)(aColors[i].green >> 8); 223 pBuffer[ 56 + i*4 ] = (sal_uInt8)(aColors[i].red >> 8); 224 } 225 226 // done 227 228 return pBuffer; 229 } 230 231 inline unsigned long doRightShift( unsigned long nValue, int nShift ) 232 { 233 return (nShift > 0) ? (nValue >> nShift) : (nValue << (-nShift)); 234 } 235 236 inline unsigned long doLeftShift( unsigned long nValue, int nShift ) 237 { 238 return (nShift > 0) ? (nValue << nShift) : (nValue >> (-nShift)); 239 } 240 241 static void getShift( unsigned long nMask, int& rShift, int& rSigBits, int& rShift2 ) 242 { 243 unsigned long nUseMask = nMask; 244 rShift = 0; 245 while( nMask & 0xffffff00 ) 246 { 247 rShift++; 248 nMask >>= 1; 249 } 250 if( rShift == 0 ) 251 while( ! (nMask & 0x00000080) ) 252 { 253 rShift--; 254 nMask <<= 1; 255 } 256 257 int nRotate = sizeof(unsigned long)*8 - rShift; 258 rSigBits = 0; 259 nMask = doRightShift( nUseMask, rShift) ; 260 while( nRotate-- ) 261 { 262 if( nMask & 1 ) 263 rSigBits++; 264 nMask >>= 1; 265 } 266 267 rShift2 = 0; 268 if( rSigBits < 8 ) 269 rShift2 = 8-rSigBits; 270 } 271 272 static sal_uInt8* X11_getTCBmpFromImage( 273 Display* pDisplay, 274 XImage* pImage, 275 sal_Int32& rOutSize, 276 int nScreenNo 277 ) 278 { 279 // get masks from visual info (guesswork) 280 XVisualInfo aVInfo; 281 if( ! XMatchVisualInfo( pDisplay, nScreenNo, pImage->depth, TrueColor, &aVInfo ) ) 282 return NULL; 283 284 rOutSize = 0; 285 286 sal_uInt8* pBuffer = 0; 287 sal_uInt32 nHeaderSize = 60; 288 sal_uInt32 nScanlineSize = pImage->width*3; 289 290 // adjust scan lines to begin on %4 boundaries 291 if( nScanlineSize & 3 ) 292 { 293 nScanlineSize &= 0xfffffffc; 294 nScanlineSize += 4; 295 } 296 int nRedShift, nRedSig, nRedShift2 = 0; 297 getShift( aVInfo.red_mask, nRedShift, nRedSig, nRedShift2 ); 298 int nGreenShift, nGreenSig, nGreenShift2 = 0; 299 getShift( aVInfo.green_mask, nGreenShift, nGreenSig, nGreenShift2 ); 300 int nBlueShift, nBlueSig, nBlueShift2 = 0; 301 getShift( aVInfo.blue_mask, nBlueShift, nBlueSig, nBlueShift2 ); 302 303 // allocate buffer to hold header and scanlines, initialize to zero 304 rOutSize = nHeaderSize + nScanlineSize*pImage->height; 305 pBuffer = (sal_uInt8*)rtl_allocateZeroMemory( rOutSize ); 306 for( int y = 0; y < pImage->height; y++ ) 307 { 308 sal_uInt8* pScanline = pBuffer + nHeaderSize + (pImage->height-1-y)*nScanlineSize; 309 for( int x = 0; x < pImage->width; x++ ) 310 { 311 unsigned long nPixel = XGetPixel( pImage, x, y ); 312 313 sal_uInt8 nValue = (sal_uInt8)doRightShift( nPixel&aVInfo.blue_mask, nBlueShift); 314 if( nBlueShift2 ) 315 nValue |= (nValue >> nBlueShift2 ); 316 *pScanline++ = nValue; 317 318 nValue = (sal_uInt8)doRightShift( nPixel&aVInfo.green_mask, nGreenShift); 319 if( nGreenShift2 ) 320 nValue |= (nValue >> nGreenShift2 ); 321 *pScanline++ = nValue; 322 323 nValue = (sal_uInt8)doRightShift( nPixel&aVInfo.red_mask, nRedShift); 324 if( nRedShift2 ) 325 nValue |= (nValue >> nRedShift2 ); 326 *pScanline++ = nValue; 327 } 328 } 329 330 // fill in header fields 331 pBuffer[ 0 ] = 'B'; 332 pBuffer[ 1 ] = 'M'; 333 334 writeLE( nHeaderSize, pBuffer+10 ); 335 writeLE( (sal_uInt32)40, pBuffer+14 ); 336 writeLE( (sal_uInt32)pImage->width, pBuffer+18 ); 337 writeLE( (sal_uInt32)pImage->height, pBuffer+22 ); 338 writeLE( (sal_uInt16)1, pBuffer+26 ); 339 writeLE( (sal_uInt16)24, pBuffer+28 ); 340 writeLE( (sal_uInt32)(DisplayWidth(pDisplay,DefaultScreen(pDisplay))*1000/DisplayWidthMM(pDisplay,DefaultScreen(pDisplay))), pBuffer+38); 341 writeLE( (sal_uInt32)(DisplayHeight(pDisplay,DefaultScreen(pDisplay))*1000/DisplayHeightMM(pDisplay,DefaultScreen(pDisplay))), pBuffer+42); 342 343 // done 344 345 return pBuffer; 346 } 347 348 sal_uInt8* x11::X11_getBmpFromPixmap( 349 Display* pDisplay, 350 Drawable aDrawable, 351 Colormap aColormap, 352 sal_Int32& rOutSize 353 ) 354 { 355 // get geometry of drawable 356 XLIB_Window aRoot; 357 int x,y; 358 unsigned int w, h, bw, d; 359 XGetGeometry( pDisplay, aDrawable, &aRoot, &x, &y, &w, &h, &bw, &d ); 360 361 // find which screen we are on 362 int nScreenNo = ScreenCount( pDisplay ); 363 while( nScreenNo-- ) 364 { 365 if( RootWindow( pDisplay, nScreenNo ) == aRoot ) 366 break; 367 } 368 if( nScreenNo < 0 ) 369 return NULL; 370 371 if( aColormap == None ) 372 aColormap = DefaultColormap( pDisplay, nScreenNo ); 373 374 // get the image 375 XImage* pImage = XGetImage( pDisplay, aDrawable, 0, 0, w, h, AllPlanes, ZPixmap ); 376 if( ! pImage ) 377 return NULL; 378 379 sal_uInt8* pBmp = d <= 8 ? 380 X11_getPaletteBmpFromImage( pDisplay, pImage, aColormap, rOutSize ) : 381 X11_getTCBmpFromImage( pDisplay, pImage, rOutSize, nScreenNo ); 382 XDestroyImage( pImage ); 383 384 return pBmp; 385 } 386 387 void x11::X11_freeBmp( sal_uInt8* pBmp ) 388 { 389 rtl_freeMemory( pBmp ); 390 } 391 392 /* 393 * PixmapHolder 394 */ 395 396 PixmapHolder::PixmapHolder( Display* pDisplay ) : 397 m_pDisplay( pDisplay ), 398 m_aColormap( None ), 399 m_aPixmap( None ), 400 m_aBitmap( None ) 401 { 402 /* try to get a 24 bit true color visual, if that fails, 403 * revert to default visual 404 */ 405 if( ! XMatchVisualInfo( m_pDisplay, DefaultScreen( m_pDisplay ), 24, TrueColor, &m_aInfo ) ) 406 { 407 #if OSL_DEBUG_LEVEL > 1 408 fprintf( stderr, "PixmapHolder reverting to default visual\n" ); 409 #endif 410 Visual* pVisual = DefaultVisual( m_pDisplay, DefaultScreen( m_pDisplay ) ); 411 m_aInfo.screen = DefaultScreen( m_pDisplay ); 412 m_aInfo.visual = pVisual; 413 m_aInfo.visualid = pVisual->visualid; 414 m_aInfo.c_class = pVisual->c_class; 415 m_aInfo.red_mask = pVisual->red_mask; 416 m_aInfo.green_mask = pVisual->green_mask; 417 m_aInfo.blue_mask = pVisual->blue_mask; 418 m_aInfo.depth = DefaultDepth( m_pDisplay, m_aInfo.screen ); 419 } 420 m_aColormap = DefaultColormap( m_pDisplay, m_aInfo.screen ); 421 #if OSL_DEBUG_LEVEL > 1 422 static const char* pClasses[] = 423 { "StaticGray", "GrayScale", "StaticColor", "PseudoColor", "TrueColor", "DirectColor" }; 424 fprintf( stderr, "PixmapHolder visual: id = 0x%lx, class = %s (%d), depth=%d; color map = 0x%lx\n", 425 m_aInfo.visualid, 426 (m_aInfo.c_class >= 0 && unsigned(m_aInfo.c_class) < sizeof(pClasses)/sizeof(pClasses[0])) ? pClasses[m_aInfo.c_class] : "<unknown>", 427 m_aInfo.c_class, 428 m_aInfo.depth, 429 m_aColormap ); 430 #endif 431 if( m_aInfo.c_class == TrueColor ) 432 { 433 int nRedSig, nGreenSig, nBlueSig; 434 m_nRedShift = m_nRedShift2 = 0; 435 getShift( m_aInfo.red_mask, m_nRedShift, nRedSig, m_nRedShift2 ); 436 m_nGreenShift = m_nGreenShift2 = 0; 437 getShift( m_aInfo.green_mask, m_nGreenShift, nGreenSig, m_nGreenShift2 ); 438 m_nBlueShift = m_nBlueShift2 = 0; 439 getShift( m_aInfo.blue_mask, m_nBlueShift, nBlueSig, m_nBlueShift2 ); 440 441 m_nBlueShift2Mask = m_nBlueShift2 ? ~((unsigned long)((1<<m_nBlueShift2)-1)) : ~0L; 442 m_nGreenShift2Mask = m_nGreenShift2 ? ~((unsigned long)((1<<m_nGreenShift2)-1)) : ~0L; 443 m_nRedShift2Mask = m_nRedShift2 ? ~((unsigned long)((1<<m_nRedShift2)-1)) : ~0L; 444 } 445 } 446 447 PixmapHolder::~PixmapHolder() 448 { 449 if( m_aPixmap != None ) 450 XFreePixmap( m_pDisplay, m_aPixmap ); 451 if( m_aBitmap != None ) 452 XFreePixmap( m_pDisplay, m_aBitmap ); 453 } 454 455 unsigned long PixmapHolder::getTCPixel( sal_uInt8 r, sal_uInt8 g, sal_uInt8 b ) const 456 { 457 unsigned long nPixel = 0; 458 unsigned long nValue = (unsigned long)b; 459 nValue &= m_nBlueShift2Mask; 460 nPixel |= doLeftShift( nValue, m_nBlueShift ); 461 462 nValue = (unsigned long)g; 463 nValue &= m_nGreenShift2Mask; 464 nPixel |= doLeftShift( nValue, m_nGreenShift ); 465 466 nValue = (unsigned long)r; 467 nValue &= m_nRedShift2Mask; 468 nPixel |= doLeftShift( nValue, m_nRedShift ); 469 470 return nPixel; 471 } 472 473 void PixmapHolder::setBitmapDataPalette( const sal_uInt8* pData, XImage* pImage ) 474 { 475 // setup palette 476 XColor aPalette[256]; 477 478 sal_uInt32 nColors = readLE32( pData+32 ); 479 sal_uInt32 nWidth = readLE32( pData+4 ); 480 sal_uInt32 nHeight = readLE32( pData+8 ); 481 sal_uInt16 nDepth = readLE16( pData+14 ); 482 483 for( sal_uInt16 i = 0 ; i < nColors; i++ ) 484 { 485 if( m_aInfo.c_class != TrueColor ) 486 { 487 aPalette[i].red = ((unsigned short)pData[42 + i*4]) << 8 | ((unsigned short)pData[42 + i*4]); 488 aPalette[i].green = ((unsigned short)pData[41 + i*4]) << 8 | ((unsigned short)pData[41 + i*4]); 489 aPalette[i].blue = ((unsigned short)pData[40 + i*4]) << 8 | ((unsigned short)pData[40 + i*4]); 490 XAllocColor( m_pDisplay, m_aColormap, aPalette+i ); 491 } 492 else 493 aPalette[i].pixel = getTCPixel( pData[42+i*4], pData[41+i*4], pData[40+i*4] ); 494 } 495 const sal_uInt8* pBMData = pData + readLE32( pData ) + 4*nColors; 496 497 sal_uInt32 nScanlineSize = 0; 498 switch( nDepth ) 499 { 500 case 1: 501 nScanlineSize = (nWidth+31)/32; 502 break; 503 case 4: 504 nScanlineSize = (nWidth+1)/2; 505 break; 506 case 8: 507 nScanlineSize = nWidth; 508 break; 509 } 510 // adjust scan lines to begin on %4 boundaries 511 if( nScanlineSize & 3 ) 512 { 513 nScanlineSize &= 0xfffffffc; 514 nScanlineSize += 4; 515 } 516 517 // allocate buffer to hold header and scanlines, initialize to zero 518 for( unsigned int y = 0; y < nHeight; y++ ) 519 { 520 const sal_uInt8* pScanline = pBMData + (nHeight-1-y)*nScanlineSize; 521 for( unsigned int x = 0; x < nWidth; x++ ) 522 { 523 int nCol = 0; 524 switch( nDepth ) 525 { 526 case 1: nCol = (pScanline[ x/8 ] & (0x80 >> (x&7))) != 0 ? 0 : 1; break; 527 case 4: 528 if( x & 1 ) 529 nCol = (int)(pScanline[ x/2 ] >> 4); 530 else 531 nCol = (int)(pScanline[ x/2 ] & 0x0f); 532 break; 533 case 8: nCol = (int)pScanline[x]; 534 } 535 XPutPixel( pImage, x, y, aPalette[nCol].pixel ); 536 } 537 } 538 } 539 540 void PixmapHolder::setBitmapDataTCDither( const sal_uInt8* pData, XImage* pImage ) 541 { 542 XColor aPalette[216]; 543 544 int nNonAllocs = 0; 545 546 for( int r = 0; r < 6; r++ ) 547 { 548 for( int g = 0; g < 6; g++ ) 549 { 550 for( int b = 0; b < 6; b++ ) 551 { 552 int i = r*36+g*6+b; 553 aPalette[i].red = r == 5 ? 0xffff : r*10922; 554 aPalette[i].green = g == 5 ? 0xffff : g*10922; 555 aPalette[i].blue = b == 5 ? 0xffff : b*10922; 556 aPalette[i].pixel = 0; 557 if( ! XAllocColor( m_pDisplay, m_aColormap, aPalette+i ) ) 558 nNonAllocs++; 559 } 560 } 561 } 562 563 if( nNonAllocs ) 564 { 565 XColor aRealPalette[256]; 566 int nColors = 1 << m_aInfo.depth; 567 int i; 568 for( i = 0; i < nColors; i++ ) 569 aRealPalette[i].pixel = (unsigned long)i; 570 XQueryColors( m_pDisplay, m_aColormap, aRealPalette, nColors ); 571 for( i = 0; i < nColors; i++ ) 572 { 573 sal_uInt8 nIndex = 574 36*(sal_uInt8)(aRealPalette[i].red/10923) + 575 6*(sal_uInt8)(aRealPalette[i].green/10923) + 576 (sal_uInt8)(aRealPalette[i].blue/10923); 577 if( aPalette[nIndex].pixel == 0 ) 578 aPalette[nIndex] = aRealPalette[i]; 579 } 580 } 581 582 sal_uInt32 nWidth = readLE32( pData+4 ); 583 sal_uInt32 nHeight = readLE32( pData+8 ); 584 585 const sal_uInt8* pBMData = pData + readLE32( pData ); 586 sal_uInt32 nScanlineSize = nWidth*3; 587 // adjust scan lines to begin on %4 boundaries 588 if( nScanlineSize & 3 ) 589 { 590 nScanlineSize &= 0xfffffffc; 591 nScanlineSize += 4; 592 } 593 594 for( int y = 0; y < (int)nHeight; y++ ) 595 { 596 const sal_uInt8* pScanline = pBMData + (nHeight-1-(sal_uInt32)y)*nScanlineSize; 597 for( int x = 0; x < (int)nWidth; x++ ) 598 { 599 sal_uInt8 b = pScanline[3*x]; 600 sal_uInt8 g = pScanline[3*x+1]; 601 sal_uInt8 r = pScanline[3*x+2]; 602 sal_uInt8 i = 36*(r/43) + 6*(g/43) + (b/43); 603 604 XPutPixel( pImage, x, y, aPalette[ i ].pixel ); 605 } 606 } 607 } 608 609 void PixmapHolder::setBitmapDataTC( const sal_uInt8* pData, XImage* pImage ) 610 { 611 sal_uInt32 nWidth = readLE32( pData+4 ); 612 sal_uInt32 nHeight = readLE32( pData+8 ); 613 614 const sal_uInt8* pBMData = pData + readLE32( pData ); 615 sal_uInt32 nScanlineSize = nWidth*3; 616 // adjust scan lines to begin on %4 boundaries 617 if( nScanlineSize & 3 ) 618 { 619 nScanlineSize &= 0xfffffffc; 620 nScanlineSize += 4; 621 } 622 623 for( int y = 0; y < (int)nHeight; y++ ) 624 { 625 const sal_uInt8* pScanline = pBMData + (nHeight-1-(sal_uInt32)y)*nScanlineSize; 626 for( int x = 0; x < (int)nWidth; x++ ) 627 { 628 unsigned long nPixel = getTCPixel( pScanline[3*x+2], pScanline[3*x+1], pScanline[3*x] ); 629 XPutPixel( pImage, x, y, nPixel ); 630 } 631 } 632 } 633 634 bool PixmapHolder::needsConversion( const sal_uInt8* pData ) 635 { 636 if( pData[0] != 'B' || pData[1] != 'M' ) 637 return true; 638 639 pData = pData+14; 640 sal_uInt32 nDepth = readLE32( pData+14 ); 641 if( nDepth == 24 ) 642 { 643 if( m_aInfo.c_class != TrueColor ) 644 return true; 645 } 646 else if( nDepth != (sal_uInt32)m_aInfo.depth ) 647 { 648 if( m_aInfo.c_class != TrueColor ) 649 return true; 650 } 651 652 return false; 653 } 654 655 Pixmap PixmapHolder::setBitmapData( const sal_uInt8* pData ) 656 { 657 if( pData[0] != 'B' || pData[1] != 'M' ) 658 return None; 659 660 pData = pData+14; 661 662 // reject compressed data 663 if( readLE32( pData + 16 ) != 0 ) 664 return None; 665 666 sal_uInt32 nWidth = readLE32( pData+4 ); 667 sal_uInt32 nHeight = readLE32( pData+8 ); 668 669 if( m_aPixmap != None ) 670 XFreePixmap( m_pDisplay, m_aPixmap ), m_aPixmap = None; 671 if( m_aBitmap != None ) 672 XFreePixmap( m_pDisplay, m_aBitmap ), m_aBitmap = None; 673 674 m_aPixmap = XCreatePixmap( m_pDisplay, 675 RootWindow( m_pDisplay, m_aInfo.screen ), 676 nWidth, nHeight, m_aInfo.depth ); 677 678 if( m_aPixmap != None ) 679 { 680 XImage aImage; 681 aImage.width = (int)nWidth; 682 aImage.height = (int)nHeight; 683 aImage.xoffset = 0; 684 aImage.format = ZPixmap; 685 aImage.data = NULL; 686 aImage.byte_order = ImageByteOrder( m_pDisplay ); 687 aImage.bitmap_unit = BitmapUnit( m_pDisplay ); 688 aImage.bitmap_bit_order = BitmapBitOrder( m_pDisplay ); 689 aImage.bitmap_pad = BitmapPad( m_pDisplay ); 690 aImage.depth = m_aInfo.depth; 691 aImage.red_mask = m_aInfo.red_mask; 692 aImage.green_mask = m_aInfo.green_mask; 693 aImage.blue_mask = m_aInfo.blue_mask; 694 aImage.bytes_per_line = 0; // filled in by XInitImage 695 if( m_aInfo.depth <= 8 ) 696 aImage.bits_per_pixel = m_aInfo.depth; 697 else 698 aImage.bits_per_pixel = 8*((m_aInfo.depth+7)/8); 699 aImage.obdata = NULL; 700 701 XInitImage( &aImage ); 702 aImage.data = (char*)rtl_allocateMemory( nHeight*aImage.bytes_per_line ); 703 704 if( readLE32( pData+14 ) == 24 ) 705 { 706 if( m_aInfo.c_class == TrueColor ) 707 setBitmapDataTC( pData, &aImage ); 708 else 709 setBitmapDataTCDither( pData, &aImage ); 710 } 711 else 712 setBitmapDataPalette( pData, &aImage ); 713 714 // put the image 715 XPutImage( m_pDisplay, 716 m_aPixmap, 717 DefaultGC( m_pDisplay, m_aInfo.screen ), 718 &aImage, 719 0, 0, 720 0, 0, 721 nWidth, nHeight ); 722 723 // clean up 724 rtl_freeMemory( aImage.data ); 725 726 // prepare bitmap (mask) 727 m_aBitmap = XCreatePixmap( m_pDisplay, 728 RootWindow( m_pDisplay, m_aInfo.screen ), 729 nWidth, nHeight, 1 ); 730 XGCValues aVal; 731 aVal.function = GXcopy; 732 aVal.foreground = 0xffffffff; 733 GC aGC = XCreateGC( m_pDisplay, m_aBitmap, GCFunction | GCForeground, &aVal ); 734 XFillRectangle( m_pDisplay, m_aBitmap, aGC, 0, 0, nWidth, nHeight ); 735 XFreeGC( m_pDisplay, aGC ); 736 } 737 738 return m_aPixmap; 739 } 740