xref: /aoo41x/main/vcl/unx/generic/dtrans/bmp.cxx (revision cdf0e10c)
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