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