diff options
Diffstat (limited to 'vcl/unx/source/dtrans/bmp.cxx')
-rw-r--r-- | vcl/unx/source/dtrans/bmp.cxx | 742 |
1 files changed, 742 insertions, 0 deletions
diff --git a/vcl/unx/source/dtrans/bmp.cxx b/vcl/unx/source/dtrans/bmp.cxx new file mode 100644 index 000000000000..49219bfb0e2a --- /dev/null +++ b/vcl/unx/source/dtrans/bmp.cxx @@ -0,0 +1,742 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: bmp.cxx,v $ + * $Revision: 1.8 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_vcl.hxx" + +#include <unistd.h> +#include <cstdio> +#include <cstring> + +#include <bmp.hxx> + +#include <X11_selection.hxx> + +using namespace x11; +using namespace com::sun::star::uno; +using namespace com::sun::star::script; +using namespace com::sun::star::awt; +using namespace rtl; + +/* + * helper functions + */ + +inline void writeLE( sal_uInt16 nNumber, sal_uInt8* pBuffer ) +{ + pBuffer[ 0 ] = (nNumber & 0xff); + pBuffer[ 1 ] = ((nNumber>>8)&0xff); +} + +inline void writeLE( sal_uInt32 nNumber, sal_uInt8* pBuffer ) +{ + pBuffer[ 0 ] = (nNumber & 0xff); + pBuffer[ 1 ] = ((nNumber>>8)&0xff); + pBuffer[ 2 ] = ((nNumber>>16)&0xff); + pBuffer[ 3 ] = ((nNumber>>24)&0xff); +} + +inline sal_uInt16 readLE16( const sal_uInt8* pBuffer ) +{ + return (((sal_uInt16)pBuffer[1]) << 8 ) | pBuffer[0]; +} + +inline sal_uInt16 readLE32( const sal_uInt8* pBuffer ) +{ + return + (((sal_uInt32)pBuffer[3]) << 24 ) | + (((sal_uInt32)pBuffer[2]) << 16 ) | + (((sal_uInt32)pBuffer[1]) << 8 ) | + pBuffer[0]; +} + + +/* + * BmpTransporter + */ + +BmpTransporter::BmpTransporter( const Sequence<sal_Int8>& rBmp ) : + m_aBM( rBmp ) +{ + const sal_uInt8* pData = (const sal_uInt8*)rBmp.getConstArray(); + + if( pData[0] == 'B' || pData[1] == 'M' ) + { + pData = pData+14; + m_aSize.Width = readLE32( pData+4 ); + m_aSize.Height = readLE32( pData+8 ); + } + else + m_aSize.Width = m_aSize.Height = 0; +} + +BmpTransporter::~BmpTransporter() +{ +} + +com::sun::star::awt::Size SAL_CALL BmpTransporter::getSize() throw() +{ + return m_aSize; +} + +Sequence< sal_Int8 > SAL_CALL BmpTransporter::getDIB() throw() +{ + return m_aBM; +} + +Sequence< sal_Int8 > SAL_CALL BmpTransporter::getMaskDIB() throw() +{ + return Sequence< sal_Int8 >(); +} + +/* + * scanline helpers + */ + +inline void X11_writeScanlinePixel( unsigned long nColor, sal_uInt8* pScanline, int depth, int x ) +{ + switch( depth ) + { + case 1: + pScanline[ x/8 ] &= ~(1 << (x&7)); + pScanline[ x/8 ] |= ((nColor & 1) << (x&7)); + break; + case 4: + pScanline[ x/2 ] &= ((x&1) ? 0x0f : 0xf0); + pScanline[ x/2 ] |= ((x&1) ? (nColor & 0x0f) : ((nColor & 0x0f) << 4)); + break; + default: + case 8: + pScanline[ x ] = (nColor & 0xff); + break; + } +} + +static sal_uInt8* X11_getPaletteBmpFromImage( + Display* pDisplay, + XImage* pImage, + Colormap aColormap, + sal_Int32& rOutSize + ) +{ + sal_uInt32 nColors = 0; + + rOutSize = 0; + + sal_uInt8* pBuffer = 0; + sal_uInt32 nHeaderSize, nScanlineSize; + sal_uInt16 nBitCount; + // determine header and scanline size + switch( pImage->depth ) + { + case 1: + nHeaderSize = 64; + nScanlineSize = (pImage->width+31)/32; + nBitCount = 1; + break; + case 4: + nHeaderSize = 72; + nScanlineSize = (pImage->width+1)/2; + nBitCount = 4; + break; + default: + case 8: + nHeaderSize = 1084; + nScanlineSize = pImage->width; + nBitCount = 8; + break; + } + // adjust scan lines to begin on %4 boundaries + if( nScanlineSize & 3 ) + { + nScanlineSize &= 0xfffffffc; + nScanlineSize += 4; + } + + // allocate buffer to hold header and scanlines, initialize to zero + rOutSize = nHeaderSize + nScanlineSize*pImage->height; + pBuffer = (sal_uInt8*)rtl_allocateZeroMemory( rOutSize ); + for( int y = 0; y < pImage->height; y++ ) + { + sal_uInt8* pScanline = pBuffer + nHeaderSize + (pImage->height-1-y)*nScanlineSize; + for( int x = 0; x < pImage->width; x++ ) + { + unsigned long nPixel = XGetPixel( pImage, x, y ); + if( nPixel >= nColors ) + nColors = nPixel+1; + X11_writeScanlinePixel( nPixel, pScanline, pImage->depth, x ); + } + } + + // fill in header fields + pBuffer[ 0 ] = 'B'; + pBuffer[ 1 ] = 'M'; + + writeLE( nHeaderSize, pBuffer+10 ); + writeLE( (sal_uInt32)40, pBuffer+14 ); + writeLE( (sal_uInt32)pImage->width, pBuffer+18 ); + writeLE( (sal_uInt32)pImage->height, pBuffer+22 ); + writeLE( (sal_uInt16)1, pBuffer+26 ); + writeLE( nBitCount, pBuffer+28 ); + writeLE( (sal_uInt32)(DisplayWidth(pDisplay,DefaultScreen(pDisplay))*1000/DisplayWidthMM(pDisplay,DefaultScreen(pDisplay))), pBuffer+38); + writeLE( (sal_uInt32)(DisplayHeight(pDisplay,DefaultScreen(pDisplay))*1000/DisplayHeightMM(pDisplay,DefaultScreen(pDisplay))), pBuffer+42); + writeLE( nColors, pBuffer+46 ); + writeLE( nColors, pBuffer+50 ); + + XColor aColors[256]; + if( nColors > (1U << nBitCount) ) // paranoia + nColors = (1U << nBitCount); + for( unsigned long nPixel = 0; nPixel < nColors; nPixel++ ) + { + aColors[nPixel].flags = DoRed | DoGreen | DoBlue; + aColors[nPixel].pixel = nPixel; + } + XQueryColors( pDisplay, aColormap, aColors, nColors ); + for( sal_uInt32 i = 0; i < nColors; i++ ) + { + pBuffer[ 54 + i*4 ] = (sal_uInt8)(aColors[i].blue >> 8); + pBuffer[ 55 + i*4 ] = (sal_uInt8)(aColors[i].green >> 8); + pBuffer[ 56 + i*4 ] = (sal_uInt8)(aColors[i].red >> 8); + } + + // done + + return pBuffer; +} + +inline unsigned long doRightShift( unsigned long nValue, int nShift ) +{ + return (nShift > 0) ? (nValue >> nShift) : (nValue << (-nShift)); +} + +inline unsigned long doLeftShift( unsigned long nValue, int nShift ) +{ + return (nShift > 0) ? (nValue << nShift) : (nValue >> (-nShift)); +} + +static void getShift( unsigned long nMask, int& rShift, int& rSigBits, int& rShift2 ) +{ + unsigned long nUseMask = nMask; + rShift = 0; + while( nMask & 0xffffff00 ) + { + rShift++; + nMask >>= 1; + } + if( rShift == 0 ) + while( ! (nMask & 0x00000080) ) + { + rShift--; + nMask <<= 1; + } + + int nRotate = sizeof(unsigned long)*8 - rShift; + rSigBits = 0; + nMask = doRightShift( nUseMask, rShift) ; + while( nRotate-- ) + { + if( nMask & 1 ) + rSigBits++; + nMask >>= 1; + } + + rShift2 = 0; + if( rSigBits < 8 ) + rShift2 = 8-rSigBits; +} + +static sal_uInt8* X11_getTCBmpFromImage( + Display* pDisplay, + XImage* pImage, + sal_Int32& rOutSize, + int nScreenNo + ) +{ + // get masks from visual info (guesswork) + XVisualInfo aVInfo; + if( ! XMatchVisualInfo( pDisplay, nScreenNo, pImage->depth, TrueColor, &aVInfo ) ) + return NULL; + + rOutSize = 0; + + sal_uInt8* pBuffer = 0; + sal_uInt32 nHeaderSize = 60; + sal_uInt32 nScanlineSize = pImage->width*3; + + // adjust scan lines to begin on %4 boundaries + if( nScanlineSize & 3 ) + { + nScanlineSize &= 0xfffffffc; + nScanlineSize += 4; + } + int nRedShift, nRedSig, nRedShift2 = 0; + getShift( aVInfo.red_mask, nRedShift, nRedSig, nRedShift2 ); + int nGreenShift, nGreenSig, nGreenShift2 = 0; + getShift( aVInfo.green_mask, nGreenShift, nGreenSig, nGreenShift2 ); + int nBlueShift, nBlueSig, nBlueShift2 = 0; + getShift( aVInfo.blue_mask, nBlueShift, nBlueSig, nBlueShift2 ); + + // allocate buffer to hold header and scanlines, initialize to zero + rOutSize = nHeaderSize + nScanlineSize*pImage->height; + pBuffer = (sal_uInt8*)rtl_allocateZeroMemory( rOutSize ); + for( int y = 0; y < pImage->height; y++ ) + { + sal_uInt8* pScanline = pBuffer + nHeaderSize + (pImage->height-1-y)*nScanlineSize; + for( int x = 0; x < pImage->width; x++ ) + { + unsigned long nPixel = XGetPixel( pImage, x, y ); + + sal_uInt8 nValue = (sal_uInt8)doRightShift( nPixel&aVInfo.blue_mask, nBlueShift); + if( nBlueShift2 ) + nValue |= (nValue >> nBlueShift2 ); + *pScanline++ = nValue; + + nValue = (sal_uInt8)doRightShift( nPixel&aVInfo.green_mask, nGreenShift); + if( nGreenShift2 ) + nValue |= (nValue >> nGreenShift2 ); + *pScanline++ = nValue; + + nValue = (sal_uInt8)doRightShift( nPixel&aVInfo.red_mask, nRedShift); + if( nRedShift2 ) + nValue |= (nValue >> nRedShift2 ); + *pScanline++ = nValue; + } + } + + // fill in header fields + pBuffer[ 0 ] = 'B'; + pBuffer[ 1 ] = 'M'; + + writeLE( nHeaderSize, pBuffer+10 ); + writeLE( (sal_uInt32)40, pBuffer+14 ); + writeLE( (sal_uInt32)pImage->width, pBuffer+18 ); + writeLE( (sal_uInt32)pImage->height, pBuffer+22 ); + writeLE( (sal_uInt16)1, pBuffer+26 ); + writeLE( (sal_uInt16)24, pBuffer+28 ); + writeLE( (sal_uInt32)(DisplayWidth(pDisplay,DefaultScreen(pDisplay))*1000/DisplayWidthMM(pDisplay,DefaultScreen(pDisplay))), pBuffer+38); + writeLE( (sal_uInt32)(DisplayHeight(pDisplay,DefaultScreen(pDisplay))*1000/DisplayHeightMM(pDisplay,DefaultScreen(pDisplay))), pBuffer+42); + + // done + + return pBuffer; +} + +sal_uInt8* x11::X11_getBmpFromPixmap( + Display* pDisplay, + Drawable aDrawable, + Colormap aColormap, + sal_Int32& rOutSize + ) +{ + // get geometry of drawable + Window aRoot; + int x,y; + unsigned int w, h, bw, d; + XGetGeometry( pDisplay, aDrawable, &aRoot, &x, &y, &w, &h, &bw, &d ); + + // find which screen we are on + int nScreenNo = ScreenCount( pDisplay ); + while( nScreenNo-- ) + { + if( RootWindow( pDisplay, nScreenNo ) == aRoot ) + break; + } + if( nScreenNo < 0 ) + return NULL; + + if( aColormap == None ) + aColormap = DefaultColormap( pDisplay, nScreenNo ); + + // get the image + XImage* pImage = XGetImage( pDisplay, aDrawable, 0, 0, w, h, AllPlanes, ZPixmap ); + if( ! pImage ) + return NULL; + + sal_uInt8* pBmp = d <= 8 ? + X11_getPaletteBmpFromImage( pDisplay, pImage, aColormap, rOutSize ) : + X11_getTCBmpFromImage( pDisplay, pImage, rOutSize, nScreenNo ); + XDestroyImage( pImage ); + + return pBmp; +} + +void x11::X11_freeBmp( sal_uInt8* pBmp ) +{ + rtl_freeMemory( pBmp ); +} + +/* + * PixmapHolder + */ + +PixmapHolder::PixmapHolder( Display* pDisplay ) : + m_pDisplay( pDisplay ), + m_aColormap( None ), + m_aPixmap( None ), + m_aBitmap( None ) +{ + /* try to get a 24 bit true color visual, if that fails, + * revert to default visual + */ + if( ! XMatchVisualInfo( m_pDisplay, DefaultScreen( m_pDisplay ), 24, TrueColor, &m_aInfo ) ) + { +#if OSL_DEBUG_LEVEL > 1 + fprintf( stderr, "PixmapHolder reverting to default visual\n" ); +#endif + Visual* pVisual = DefaultVisual( m_pDisplay, DefaultScreen( m_pDisplay ) ); + m_aInfo.screen = DefaultScreen( m_pDisplay ); + m_aInfo.visual = pVisual; + m_aInfo.visualid = pVisual->visualid; + m_aInfo.c_class = pVisual->c_class; + m_aInfo.red_mask = pVisual->red_mask; + m_aInfo.green_mask = pVisual->green_mask; + m_aInfo.blue_mask = pVisual->blue_mask; + m_aInfo.depth = DefaultDepth( m_pDisplay, m_aInfo.screen ); + } + m_aColormap = DefaultColormap( m_pDisplay, m_aInfo.screen ); +#if OSL_DEBUG_LEVEL > 1 + static const char* pClasses[] = + { "StaticGray", "GrayScale", "StaticColor", "PseudoColor", "TrueColor", "DirectColor" }; + fprintf( stderr, "PixmapHolder visual: id = 0x%lx, class = %s (%d), depth=%d; color map = 0x%lx\n", + m_aInfo.visualid, + (m_aInfo.c_class >= 0 && unsigned(m_aInfo.c_class) < sizeof(pClasses)/sizeof(pClasses[0])) ? pClasses[m_aInfo.c_class] : "<unknown>", + m_aInfo.c_class, + m_aInfo.depth, + m_aColormap ); +#endif + if( m_aInfo.c_class == TrueColor ) + { + int nRedSig, nGreenSig, nBlueSig; + m_nRedShift = m_nRedShift2 = 0; + getShift( m_aInfo.red_mask, m_nRedShift, nRedSig, m_nRedShift2 ); + m_nGreenShift = m_nGreenShift2 = 0; + getShift( m_aInfo.green_mask, m_nGreenShift, nGreenSig, m_nGreenShift2 ); + m_nBlueShift = m_nBlueShift2 = 0; + getShift( m_aInfo.blue_mask, m_nBlueShift, nBlueSig, m_nBlueShift2 ); + + m_nBlueShift2Mask = m_nBlueShift2 ? ~((unsigned long)((1<<m_nBlueShift2)-1)) : ~0L; + m_nGreenShift2Mask = m_nGreenShift2 ? ~((unsigned long)((1<<m_nGreenShift2)-1)) : ~0L; + m_nRedShift2Mask = m_nRedShift2 ? ~((unsigned long)((1<<m_nRedShift2)-1)) : ~0L; + } +} + +PixmapHolder::~PixmapHolder() +{ + if( m_aPixmap != None ) + XFreePixmap( m_pDisplay, m_aPixmap ); + if( m_aBitmap != None ) + XFreePixmap( m_pDisplay, m_aBitmap ); +} + +unsigned long PixmapHolder::getTCPixel( sal_uInt8 r, sal_uInt8 g, sal_uInt8 b ) const +{ + unsigned long nPixel = 0; + unsigned long nValue = (unsigned long)b; + nValue &= m_nBlueShift2Mask; + nPixel |= doLeftShift( nValue, m_nBlueShift ); + + nValue = (unsigned long)g; + nValue &= m_nGreenShift2Mask; + nPixel |= doLeftShift( nValue, m_nGreenShift ); + + nValue = (unsigned long)r; + nValue &= m_nRedShift2Mask; + nPixel |= doLeftShift( nValue, m_nRedShift ); + + return nPixel; +} + +void PixmapHolder::setBitmapDataPalette( const sal_uInt8* pData, XImage* pImage ) +{ + // setup palette + XColor aPalette[256]; + + sal_uInt32 nColors = readLE32( pData+32 ); + sal_uInt32 nWidth = readLE32( pData+4 ); + sal_uInt32 nHeight = readLE32( pData+8 ); + sal_uInt16 nDepth = readLE16( pData+14 ); + + for( sal_uInt16 i = 0 ; i < nColors; i++ ) + { + if( m_aInfo.c_class != TrueColor ) + { + aPalette[i].red = ((unsigned short)pData[42 + i*4]) << 8 | ((unsigned short)pData[42 + i*4]); + aPalette[i].green = ((unsigned short)pData[41 + i*4]) << 8 | ((unsigned short)pData[41 + i*4]); + aPalette[i].blue = ((unsigned short)pData[40 + i*4]) << 8 | ((unsigned short)pData[40 + i*4]); + XAllocColor( m_pDisplay, m_aColormap, aPalette+i ); + } + else + aPalette[i].pixel = getTCPixel( pData[42+i*4], pData[41+i*4], pData[40+i*4] ); + } + const sal_uInt8* pBMData = pData + readLE32( pData ) + 4*nColors; + + sal_uInt32 nScanlineSize = 0; + switch( nDepth ) + { + case 1: + nScanlineSize = (nWidth+31)/32; + break; + case 4: + nScanlineSize = (nWidth+1)/2; + break; + case 8: + nScanlineSize = nWidth; + break; + } + // adjust scan lines to begin on %4 boundaries + if( nScanlineSize & 3 ) + { + nScanlineSize &= 0xfffffffc; + nScanlineSize += 4; + } + + // allocate buffer to hold header and scanlines, initialize to zero + for( unsigned int y = 0; y < nHeight; y++ ) + { + const sal_uInt8* pScanline = pBMData + (nHeight-1-y)*nScanlineSize; + for( unsigned int x = 0; x < nWidth; x++ ) + { + int nCol = 0; + switch( nDepth ) + { + case 1: nCol = (pScanline[ x/8 ] & (0x80 >> (x&7))) != 0 ? 0 : 1; break; + case 4: + if( x & 1 ) + nCol = (int)(pScanline[ x/2 ] >> 4); + else + nCol = (int)(pScanline[ x/2 ] & 0x0f); + break; + case 8: nCol = (int)pScanline[x]; + } + XPutPixel( pImage, x, y, aPalette[nCol].pixel ); + } + } +} + +void PixmapHolder::setBitmapDataTCDither( const sal_uInt8* pData, XImage* pImage ) +{ + XColor aPalette[216]; + + int nNonAllocs = 0; + + for( int r = 0; r < 6; r++ ) + { + for( int g = 0; g < 6; g++ ) + { + for( int b = 0; b < 6; b++ ) + { + int i = r*36+g*6+b; + aPalette[i].red = r == 5 ? 0xffff : r*10922; + aPalette[i].green = g == 5 ? 0xffff : g*10922; + aPalette[i].blue = b == 5 ? 0xffff : b*10922; + aPalette[i].pixel = 0; + if( ! XAllocColor( m_pDisplay, m_aColormap, aPalette+i ) ) + nNonAllocs++; + } + } + } + + if( nNonAllocs ) + { + XColor aRealPalette[256]; + int nColors = 1 << m_aInfo.depth; + int i; + for( i = 0; i < nColors; i++ ) + aRealPalette[i].pixel = (unsigned long)i; + XQueryColors( m_pDisplay, m_aColormap, aRealPalette, nColors ); + for( i = 0; i < nColors; i++ ) + { + sal_uInt8 nIndex = + 36*(sal_uInt8)(aRealPalette[i].red/10923) + + 6*(sal_uInt8)(aRealPalette[i].green/10923) + + (sal_uInt8)(aRealPalette[i].blue/10923); + if( aPalette[nIndex].pixel == 0 ) + aPalette[nIndex] = aRealPalette[i]; + } + } + + sal_uInt32 nWidth = readLE32( pData+4 ); + sal_uInt32 nHeight = readLE32( pData+8 ); + + const sal_uInt8* pBMData = pData + readLE32( pData ); + sal_uInt32 nScanlineSize = nWidth*3; + // adjust scan lines to begin on %4 boundaries + if( nScanlineSize & 3 ) + { + nScanlineSize &= 0xfffffffc; + nScanlineSize += 4; + } + + for( int y = 0; y < (int)nHeight; y++ ) + { + const sal_uInt8* pScanline = pBMData + (nHeight-1-(sal_uInt32)y)*nScanlineSize; + for( int x = 0; x < (int)nWidth; x++ ) + { + sal_uInt8 b = pScanline[3*x]; + sal_uInt8 g = pScanline[3*x+1]; + sal_uInt8 r = pScanline[3*x+2]; + sal_uInt8 i = 36*(r/43) + 6*(g/43) + (b/43); + + XPutPixel( pImage, x, y, aPalette[ i ].pixel ); + } + } +} + +void PixmapHolder::setBitmapDataTC( const sal_uInt8* pData, XImage* pImage ) +{ + sal_uInt32 nWidth = readLE32( pData+4 ); + sal_uInt32 nHeight = readLE32( pData+8 ); + + const sal_uInt8* pBMData = pData + readLE32( pData ); + sal_uInt32 nScanlineSize = nWidth*3; + // adjust scan lines to begin on %4 boundaries + if( nScanlineSize & 3 ) + { + nScanlineSize &= 0xfffffffc; + nScanlineSize += 4; + } + + for( int y = 0; y < (int)nHeight; y++ ) + { + const sal_uInt8* pScanline = pBMData + (nHeight-1-(sal_uInt32)y)*nScanlineSize; + for( int x = 0; x < (int)nWidth; x++ ) + { + unsigned long nPixel = getTCPixel( pScanline[3*x+2], pScanline[3*x+1], pScanline[3*x] ); + XPutPixel( pImage, x, y, nPixel ); + } + } +} + +bool PixmapHolder::needsConversion( const sal_uInt8* pData ) +{ + if( pData[0] != 'B' || pData[1] != 'M' ) + return true; + + pData = pData+14; + sal_uInt32 nDepth = readLE32( pData+14 ); + if( nDepth == 24 ) + { + if( m_aInfo.c_class != TrueColor ) + return true; + } + else if( nDepth != (sal_uInt32)m_aInfo.depth ) + { + if( m_aInfo.c_class != TrueColor ) + return true; + } + + return false; +} + +Pixmap PixmapHolder::setBitmapData( const sal_uInt8* pData ) +{ + if( pData[0] != 'B' || pData[1] != 'M' ) + return None; + + pData = pData+14; + + // reject compressed data + if( readLE32( pData + 16 ) != 0 ) + return None; + + sal_uInt32 nWidth = readLE32( pData+4 ); + sal_uInt32 nHeight = readLE32( pData+8 ); + + if( m_aPixmap != None ) + XFreePixmap( m_pDisplay, m_aPixmap ), m_aPixmap = None; + if( m_aBitmap != None ) + XFreePixmap( m_pDisplay, m_aBitmap ), m_aBitmap = None; + + m_aPixmap = XCreatePixmap( m_pDisplay, + RootWindow( m_pDisplay, m_aInfo.screen ), + nWidth, nHeight, m_aInfo.depth ); + + if( m_aPixmap != None ) + { + XImage aImage; + aImage.width = (int)nWidth; + aImage.height = (int)nHeight; + aImage.xoffset = 0; + aImage.format = ZPixmap; + aImage.data = NULL; + aImage.byte_order = ImageByteOrder( m_pDisplay ); + aImage.bitmap_unit = BitmapUnit( m_pDisplay ); + aImage.bitmap_bit_order = BitmapBitOrder( m_pDisplay ); + aImage.bitmap_pad = BitmapPad( m_pDisplay ); + aImage.depth = m_aInfo.depth; + aImage.red_mask = m_aInfo.red_mask; + aImage.green_mask = m_aInfo.green_mask; + aImage.blue_mask = m_aInfo.blue_mask; + aImage.bytes_per_line = 0; // filled in by XInitImage + if( m_aInfo.depth <= 8 ) + aImage.bits_per_pixel = m_aInfo.depth; + else + aImage.bits_per_pixel = 8*((m_aInfo.depth+7)/8); + aImage.obdata = NULL; + + XInitImage( &aImage ); + aImage.data = (char*)rtl_allocateMemory( nHeight*aImage.bytes_per_line ); + + if( readLE32( pData+14 ) == 24 ) + { + if( m_aInfo.c_class == TrueColor ) + setBitmapDataTC( pData, &aImage ); + else + setBitmapDataTCDither( pData, &aImage ); + } + else + setBitmapDataPalette( pData, &aImage ); + + // put the image + XPutImage( m_pDisplay, + m_aPixmap, + DefaultGC( m_pDisplay, m_aInfo.screen ), + &aImage, + 0, 0, + 0, 0, + nWidth, nHeight ); + + // clean up + rtl_freeMemory( aImage.data ); + + // prepare bitmap (mask) + m_aBitmap = XCreatePixmap( m_pDisplay, + RootWindow( m_pDisplay, m_aInfo.screen ), + nWidth, nHeight, 1 ); + XGCValues aVal; + aVal.function = GXcopy; + aVal.foreground = 0xffffffff; + GC aGC = XCreateGC( m_pDisplay, m_aBitmap, GCFunction | GCForeground, &aVal ); + XFillRectangle( m_pDisplay, m_aBitmap, aGC, 0, 0, nWidth, nHeight ); + XFreeGC( m_pDisplay, aGC ); + } + + return m_aPixmap; +} |