xref: /AOO41X/main/vcl/win/source/gdi/salbmp.cxx (revision ff0525f24f03981d56b7579b645949f111420994)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_vcl.hxx"
26 
27 #include <tools/svwin.h>
28 
29 #include <vcl/bitmap.hxx> // for BitmapSystemData
30 #include <vcl/salbtype.hxx>
31 
32 #include <win/wincomp.hxx>
33 #include <win/salgdi.h>
34 #include <win/saldata.hxx>
35 #include <win/salbmp.h>
36 
37 #include <string.h>
38 
39 // -----------
40 // - Inlines -
41 // -----------
42 
43 inline void ImplSetPixel4( const HPBYTE pScanline, long nX, const BYTE cIndex )
44 {
45     BYTE& rByte = pScanline[ nX >> 1 ];
46 
47     ( nX & 1 ) ? ( rByte &= 0xf0, rByte |= ( cIndex & 0x0f ) ) :
48                  ( rByte &= 0x0f, rByte |= ( cIndex << 4 ) );
49 }
50 
51 // ----------------
52 // - WinSalBitmap -
53 // ----------------
54 
55 WinSalBitmap::WinSalBitmap() :
56         mhDIB       ( 0 ),
57         mhDDB       ( 0 ),
58         mnBitCount  ( 0 )
59 {
60 }
61 
62 // ------------------------------------------------------------------
63 
64 WinSalBitmap::~WinSalBitmap()
65 {
66     Destroy();
67 }
68 
69 // ------------------------------------------------------------------
70 
71 bool WinSalBitmap::Create( HANDLE hBitmap, bool bDIB, bool bCopyHandle )
72 {
73     bool bRet = TRUE;
74 
75     if( bDIB )
76         mhDIB = (HGLOBAL) ( bCopyHandle ? ImplCopyDIBOrDDB( hBitmap, TRUE ) : hBitmap );
77     else
78         mhDDB = (HBITMAP) ( bCopyHandle ? ImplCopyDIBOrDDB( hBitmap, FALSE ) : hBitmap );
79 
80     if( mhDIB )
81     {
82         PBITMAPINFOHEADER pBIH = (PBITMAPINFOHEADER) GlobalLock( mhDIB );
83 
84         maSize = Size( pBIH->biWidth, pBIH->biHeight );
85         mnBitCount = pBIH->biBitCount;
86 
87         if( mnBitCount )
88             mnBitCount = ( mnBitCount <= 1 ) ? 1 : ( mnBitCount <= 4 ) ? 4 : ( mnBitCount <= 8 ) ? 8 : 24;
89 
90         GlobalUnlock( mhDIB );
91     }
92     else if( mhDDB )
93     {
94         BITMAP  aDDBInfo;
95 
96         if( WIN_GetObject( mhDDB, sizeof( BITMAP ), &aDDBInfo ) )
97         {
98             maSize = Size( aDDBInfo.bmWidth, aDDBInfo.bmHeight );
99             mnBitCount = aDDBInfo.bmPlanes * aDDBInfo.bmBitsPixel;
100 
101             if( mnBitCount )
102             {
103                 mnBitCount = ( mnBitCount <= 1 ) ? 1 :
104                              ( mnBitCount <= 4 ) ? 4 :
105                              ( mnBitCount <= 8 ) ? 8 : 24;
106             }
107         }
108         else
109         {
110             mhDDB = 0;
111             bRet = FALSE;
112         }
113     }
114     else
115         bRet = FALSE;
116 
117     return bRet;
118 }
119 
120 // ------------------------------------------------------------------
121 
122 bool WinSalBitmap::Create( const Size& rSize, sal_uInt16 nBitCount, const BitmapPalette& rPal )
123 {
124     bool bRet = FALSE;
125 
126     mhDIB = ImplCreateDIB( rSize, nBitCount, rPal );
127 
128     if( mhDIB )
129     {
130         maSize = rSize;
131         mnBitCount = nBitCount;
132         bRet = TRUE;
133     }
134 
135     return bRet;
136 }
137 
138 // ------------------------------------------------------------------
139 
140 bool WinSalBitmap::Create( const SalBitmap& rSSalBitmap )
141 {
142     bool bRet = FALSE;
143     const WinSalBitmap& rSalBitmap = static_cast<const WinSalBitmap&>(rSSalBitmap);
144 
145     if ( rSalBitmap.mhDIB || rSalBitmap.mhDDB )
146     {
147         HANDLE hNewHdl = ImplCopyDIBOrDDB( rSalBitmap.mhDIB ? rSalBitmap.mhDIB : rSalBitmap.mhDDB,
148                                            rSalBitmap.mhDIB != 0 );
149 
150         if ( hNewHdl )
151         {
152             if( rSalBitmap.mhDIB )
153                 mhDIB = (HGLOBAL) hNewHdl;
154             else if( rSalBitmap.mhDDB )
155                 mhDDB = (HBITMAP) hNewHdl;
156 
157             maSize = rSalBitmap.maSize;
158             mnBitCount = rSalBitmap.mnBitCount;
159 
160             bRet = TRUE;
161         }
162     }
163 
164     return bRet;
165 }
166 
167 // ------------------------------------------------------------------
168 
169 bool WinSalBitmap::Create( const SalBitmap& rSSalBmp, SalGraphics* pSGraphics )
170 {
171     bool bRet = FALSE;
172 
173     const WinSalBitmap& rSalBmp = static_cast<const WinSalBitmap&>(rSSalBmp);
174     WinSalGraphics* pGraphics = static_cast<WinSalGraphics*>(pSGraphics);
175 
176     if( rSalBmp.mhDIB )
177     {
178         PBITMAPINFO         pBI = (PBITMAPINFO) GlobalLock( rSalBmp.mhDIB );
179         PBITMAPINFOHEADER   pBIH = (PBITMAPINFOHEADER) pBI;
180         HDC                 hDC  = pGraphics->mhDC;
181         HBITMAP             hNewDDB;
182         BITMAP              aDDBInfo;
183         PBYTE               pBits = (PBYTE) pBI + *(DWORD*) pBI +
184                             ImplGetDIBColorCount( rSalBmp.mhDIB ) * sizeof( RGBQUAD );
185 
186         if( pBIH->biBitCount == 1 )
187         {
188             hNewDDB = CreateBitmap( pBIH->biWidth, pBIH->biHeight, 1, 1, NULL );
189 
190             if( hNewDDB )
191                 SetDIBits( hDC, hNewDDB, 0, pBIH->biHeight, pBits, pBI, DIB_RGB_COLORS );
192         }
193         else
194             hNewDDB = CreateDIBitmap( hDC, (PBITMAPINFOHEADER) pBI, CBM_INIT, pBits, pBI, DIB_RGB_COLORS );
195 
196         GlobalUnlock( rSalBmp.mhDIB );
197 
198         if( hNewDDB && WIN_GetObject( hNewDDB, sizeof( BITMAP ), &aDDBInfo ) )
199         {
200             mhDDB = hNewDDB;
201             maSize = Size( aDDBInfo.bmWidth, aDDBInfo.bmHeight );
202             mnBitCount = aDDBInfo.bmPlanes * aDDBInfo.bmBitsPixel;
203 
204             bRet = TRUE;
205         }
206         else if( hNewDDB )
207             DeleteObject( hNewDDB );
208     }
209 
210     return bRet;
211 }
212 
213 // ------------------------------------------------------------------
214 
215 bool WinSalBitmap::Create( const SalBitmap& rSSalBmp, sal_uInt16 nNewBitCount )
216 {
217     bool bRet = FALSE;
218 
219     const WinSalBitmap& rSalBmp = static_cast<const WinSalBitmap&>(rSSalBmp);
220 
221     if( rSalBmp.mhDDB )
222     {
223         mhDIB = ImplCreateDIB( rSalBmp.maSize, nNewBitCount, BitmapPalette() );
224 
225         if( mhDIB )
226         {
227             PBITMAPINFO pBI = (PBITMAPINFO) GlobalLock( mhDIB );
228             const int   nLines = (int) rSalBmp.maSize.Height();
229             HDC         hDC = GetDC( 0 );
230             PBYTE       pBits = (PBYTE) pBI + *(DWORD*) pBI +
231                                 ImplGetDIBColorCount( mhDIB ) * sizeof( RGBQUAD );
232             SalData*    pSalData = GetSalData();
233             HPALETTE    hOldPal = 0;
234 
235             if ( pSalData->mhDitherPal )
236             {
237                 hOldPal = SelectPalette( hDC, pSalData->mhDitherPal, TRUE );
238                 RealizePalette( hDC );
239             }
240 
241             if( GetDIBits( hDC, rSalBmp.mhDDB, 0, nLines, pBits, pBI, DIB_RGB_COLORS ) == nLines )
242             {
243                 GlobalUnlock( mhDIB );
244                 maSize = rSalBmp.maSize;
245                 mnBitCount = nNewBitCount;
246                 bRet = TRUE;
247             }
248             else
249             {
250                 GlobalUnlock( mhDIB );
251                 GlobalFree( mhDIB );
252                 mhDIB = 0;
253             }
254 
255             if( hOldPal )
256                 SelectPalette( hDC, hOldPal, TRUE );
257 
258             ReleaseDC( 0, hDC );
259         }
260     }
261 
262     return bRet;
263 }
264 
265 // ------------------------------------------------------------------
266 
267 void WinSalBitmap::Destroy()
268 {
269     if( mhDIB )
270         GlobalFree( mhDIB );
271     else if( mhDDB )
272         DeleteObject( mhDDB );
273 
274     maSize = Size();
275     mnBitCount = 0;
276 }
277 
278 // ------------------------------------------------------------------
279 
280 sal_uInt16 WinSalBitmap::ImplGetDIBColorCount( HGLOBAL hDIB )
281 {
282     sal_uInt16 nColors = 0;
283 
284     if( hDIB )
285     {
286         PBITMAPINFO         pBI = (PBITMAPINFO) GlobalLock( hDIB );
287         PBITMAPINFOHEADER   pBIH = (PBITMAPINFOHEADER) pBI;
288 
289         if ( pBIH->biSize != sizeof( BITMAPCOREHEADER ) )
290         {
291             if( pBIH->biBitCount <= 8 )
292             {
293                 if ( pBIH->biClrUsed )
294                     nColors = (sal_uInt16) pBIH->biClrUsed;
295                 else
296                     nColors = 1 << pBIH->biBitCount;
297             }
298         }
299         else if( ( (PBITMAPCOREHEADER) pBI )->bcBitCount <= 8 )
300             nColors = 1 << ( (PBITMAPCOREHEADER) pBI )->bcBitCount;
301 
302         GlobalUnlock( hDIB );
303     }
304 
305     return nColors;
306 }
307 
308 // ------------------------------------------------------------------
309 
310 HGLOBAL WinSalBitmap::ImplCreateDIB( const Size& rSize, sal_uInt16 nBits, const BitmapPalette& rPal )
311 {
312     DBG_ASSERT( nBits == 1 || nBits == 4 || nBits == 8 || nBits == 16 || nBits == 24, "Unsupported BitCount!" );
313 
314     HGLOBAL hDIB = 0;
315 
316     if( rSize.Width() <= 0 || rSize.Height() <= 0 )
317         return hDIB;
318 
319     // calculate bitmap size in Bytes
320     const sal_uLong nAlignedWidth4Bytes = AlignedWidth4Bytes( nBits * rSize.Width() );
321     const sal_uLong nImageSize = nAlignedWidth4Bytes * rSize.Height();
322     bool bOverflow = (nImageSize / nAlignedWidth4Bytes) != rSize.Height();
323     if( bOverflow )
324         return hDIB;
325 
326     // allocate bitmap memory including header and palette
327     const sal_uInt16 nColors = (nBits <= 8) ? (1 << nBits) : 0;
328     const sal_uLong nHeaderSize = sizeof( BITMAPINFOHEADER ) + nColors * sizeof( RGBQUAD );
329     bOverflow = (nHeaderSize + nImageSize) < nImageSize;
330     if( bOverflow )
331         return hDIB;
332 
333     hDIB = GlobalAlloc( GHND, nHeaderSize + nImageSize );
334     if( !hDIB )
335         return hDIB;
336 
337     PBITMAPINFO pBI = static_cast<PBITMAPINFO>( GlobalLock( hDIB ) );
338     PBITMAPINFOHEADER pBIH = reinterpret_cast<PBITMAPINFOHEADER>( pBI );
339 
340     pBIH->biSize = sizeof( BITMAPINFOHEADER );
341     pBIH->biWidth = rSize.Width();
342     pBIH->biHeight = rSize.Height();
343     pBIH->biPlanes = 1;
344     pBIH->biBitCount = nBits;
345     pBIH->biCompression = BI_RGB;
346     pBIH->biSizeImage = nImageSize;
347     pBIH->biXPelsPerMeter = 0;
348     pBIH->biYPelsPerMeter = 0;
349     pBIH->biClrUsed = 0;
350     pBIH->biClrImportant = 0;
351 
352     if( nColors )
353     {
354         // copy the palette entries if any
355         const sal_uInt16 nMinCount = Min( nColors, rPal.GetEntryCount() );
356         if( nMinCount )
357             memcpy( pBI->bmiColors, rPal.ImplGetColorBuffer(), nMinCount * sizeof(RGBQUAD) );
358     }
359 
360     GlobalUnlock( hDIB );
361 
362     return hDIB;
363 }
364 
365 // ------------------------------------------------------------------
366 
367 HANDLE WinSalBitmap::ImplCopyDIBOrDDB( HANDLE hHdl, bool bDIB )
368 {
369     HANDLE  hCopy = 0;
370 
371     if ( bDIB && hHdl )
372     {
373         const sal_uLong nSize = GlobalSize( hHdl );
374 
375         if ( (hCopy = GlobalAlloc( GHND, nSize  )) != 0 )
376         {
377             memcpy( (LPSTR) GlobalLock( hCopy ), (LPSTR) GlobalLock( hHdl ), nSize );
378 
379             GlobalUnlock( hCopy );
380             GlobalUnlock( hHdl );
381         }
382     }
383     else if ( hHdl )
384     {
385         BITMAP aBmp;
386 
387         // Source-Bitmap nach Groesse befragen
388         WIN_GetObject( hHdl, sizeof( BITMAP ), (LPSTR) &aBmp );
389 
390         // Destination-Bitmap erzeugen
391         if ( (hCopy = CreateBitmapIndirect( &aBmp )) != 0 )
392         {
393             HDC     hBmpDC = CreateCompatibleDC( 0 );
394             HBITMAP hBmpOld = (HBITMAP) SelectObject( hBmpDC, hHdl );
395             HDC     hCopyDC = CreateCompatibleDC( hBmpDC );
396             HBITMAP hCopyOld = (HBITMAP) SelectObject( hCopyDC, hCopy );
397 
398             BitBlt( hCopyDC, 0, 0, aBmp.bmWidth, aBmp.bmHeight, hBmpDC, 0, 0, SRCCOPY );
399 
400             SelectObject( hCopyDC, hCopyOld );
401             DeleteDC( hCopyDC );
402 
403             SelectObject( hBmpDC, hBmpOld );
404             DeleteDC( hBmpDC );
405         }
406     }
407 
408     return hCopy;
409 }
410 
411 // ------------------------------------------------------------------
412 
413 BitmapBuffer* WinSalBitmap::AcquireBuffer( bool /*bReadOnly*/ )
414 {
415     BitmapBuffer* pBuffer = NULL;
416 
417     if( mhDIB )
418     {
419         PBITMAPINFO         pBI = (PBITMAPINFO) GlobalLock( mhDIB );
420         PBITMAPINFOHEADER   pBIH = (PBITMAPINFOHEADER) pBI;
421 
422         if( ( pBIH->biCompression == BI_RLE4 ) || ( pBIH->biCompression == BI_RLE8 ) )
423         {
424             Size    aSizePix( pBIH->biWidth, pBIH->biHeight );
425             HGLOBAL hNewDIB = ImplCreateDIB( aSizePix, pBIH->biBitCount, BitmapPalette() );
426 
427             if( hNewDIB )
428             {
429                 PBITMAPINFO         pNewBI = (PBITMAPINFO) GlobalLock( hNewDIB );
430                 PBITMAPINFOHEADER   pNewBIH = (PBITMAPINFOHEADER) pNewBI;
431                 const sal_uInt16        nColorCount = ImplGetDIBColorCount( hNewDIB );
432                 const sal_uLong         nOffset = *(DWORD*) pBI + nColorCount * sizeof( RGBQUAD );
433                 BYTE*               pOldBits = (PBYTE) pBI + nOffset;
434                 BYTE*               pNewBits = (PBYTE) pNewBI + nOffset;
435 
436                 memcpy( pNewBI, pBI, nOffset );
437                 pNewBIH->biCompression = 0;
438                 ImplDecodeRLEBuffer( pOldBits, pNewBits, aSizePix, pBIH->biCompression == BI_RLE4 );
439 
440                 GlobalUnlock( mhDIB );
441                 GlobalFree( mhDIB );
442                 mhDIB = hNewDIB;
443                 pBI = pNewBI;
444                 pBIH = pNewBIH;
445             }
446         }
447 
448         if( pBIH->biPlanes == 1 )
449         {
450             pBuffer = new BitmapBuffer;
451 
452             pBuffer->mnFormat = BMP_FORMAT_BOTTOM_UP |
453                                 ( pBIH->biBitCount == 1 ? BMP_FORMAT_1BIT_MSB_PAL :
454                                   pBIH->biBitCount == 4 ? BMP_FORMAT_4BIT_MSN_PAL :
455                                   pBIH->biBitCount == 8 ? BMP_FORMAT_8BIT_PAL :
456                                   pBIH->biBitCount == 16 ? BMP_FORMAT_16BIT_TC_LSB_MASK :
457                                   pBIH->biBitCount == 24 ? BMP_FORMAT_24BIT_TC_BGR :
458                                   pBIH->biBitCount == 32 ? BMP_FORMAT_32BIT_TC_MASK : 0UL );
459 
460             if( BMP_SCANLINE_FORMAT( pBuffer->mnFormat ) )
461             {
462                 pBuffer->mnWidth = maSize.Width();
463                 pBuffer->mnHeight = maSize.Height();
464                 pBuffer->mnScanlineSize = AlignedWidth4Bytes( maSize.Width() * pBIH->biBitCount );
465                 pBuffer->mnBitCount = (sal_uInt16) pBIH->biBitCount;
466 
467                 if( pBuffer->mnBitCount <= 8 )
468                 {
469                     const sal_uInt16 nPalCount = ImplGetDIBColorCount( mhDIB );
470 
471                     pBuffer->maPalette.SetEntryCount( nPalCount );
472                     memcpy( pBuffer->maPalette.ImplGetColorBuffer(), pBI->bmiColors, nPalCount * sizeof( RGBQUAD ) );
473                     pBuffer->mpBits = (PBYTE) pBI + *(DWORD*) pBI + nPalCount * sizeof( RGBQUAD );
474                 }
475                 else if( ( pBIH->biBitCount == 16 ) || ( pBIH->biBitCount == 32 ) )
476                 {
477                     sal_uLong nOffset = 0UL;
478 
479                     if( pBIH->biCompression == BI_BITFIELDS )
480                     {
481                         nOffset = 3 * sizeof( RGBQUAD );
482                         pBuffer->maColorMask = ColorMask( *(UINT32*) &pBI->bmiColors[ 0 ],
483                                                           *(UINT32*) &pBI->bmiColors[ 1 ],
484                                                           *(UINT32*) &pBI->bmiColors[ 2 ] );
485                     }
486                     else if( pBIH->biBitCount == 16 )
487                         pBuffer->maColorMask = ColorMask( 0x00007c00UL, 0x000003e0UL, 0x0000001fUL );
488                     else
489                         pBuffer->maColorMask = ColorMask( 0x00ff0000UL, 0x0000ff00UL, 0x000000ffUL );
490 
491                     pBuffer->mpBits = (PBYTE) pBI + *(DWORD*) pBI + nOffset;
492                 }
493                 else
494                     pBuffer->mpBits = (PBYTE) pBI + *(DWORD*) pBI;
495             }
496             else
497             {
498                 GlobalUnlock( mhDIB );
499                 delete pBuffer;
500                 pBuffer = NULL;
501             }
502         }
503         else
504             GlobalUnlock( mhDIB );
505     }
506 
507     return pBuffer;
508 }
509 
510 // ------------------------------------------------------------------
511 
512 void WinSalBitmap::ReleaseBuffer( BitmapBuffer* pBuffer, bool bReadOnly )
513 {
514     if( pBuffer )
515     {
516         if( mhDIB )
517         {
518             if( !bReadOnly && !!pBuffer->maPalette )
519             {
520                 PBITMAPINFO     pBI = (PBITMAPINFO) GlobalLock( mhDIB );
521                 const sal_uInt16    nCount = pBuffer->maPalette.GetEntryCount();
522                 const sal_uInt16    nDIBColorCount = ImplGetDIBColorCount( mhDIB );
523                 memcpy( pBI->bmiColors, pBuffer->maPalette.ImplGetColorBuffer(), Min( nDIBColorCount, nCount ) * sizeof( RGBQUAD ) );
524                 GlobalUnlock( mhDIB );
525             }
526 
527             GlobalUnlock( mhDIB );
528         }
529 
530         delete pBuffer;
531     }
532 }
533 
534 // ------------------------------------------------------------------
535 
536 void WinSalBitmap::ImplDecodeRLEBuffer( const BYTE* pSrcBuf, BYTE* pDstBuf,
537                                      const Size& rSizePixel, bool bRLE4 )
538 {
539     HPBYTE          pRLE = (HPBYTE) pSrcBuf;
540     HPBYTE          pDIB = (HPBYTE) pDstBuf;
541     HPBYTE          pRow = (HPBYTE) pDstBuf;
542     sal_uLong           nWidthAl = AlignedWidth4Bytes( rSizePixel.Width() * ( bRLE4 ? 4UL : 8UL ) );
543     HPBYTE          pLast = pDIB + rSizePixel.Height() * nWidthAl - 1;
544     sal_uLong           nCountByte;
545     sal_uLong           nRunByte;
546     sal_uLong           nX = 0;
547     sal_uLong           i;
548     BYTE            cTmp;
549     bool            bEndDecoding = FALSE;
550 
551     if( pRLE && pDIB )
552     {
553         do
554         {
555             if( ( nCountByte = *pRLE++ ) == 0 )
556             {
557                 nRunByte = *pRLE++;
558 
559                 if( nRunByte > 2UL )
560                 {
561                     if( bRLE4 )
562                     {
563                         nCountByte = nRunByte >> 1UL;
564 
565                         for( i = 0; i < nCountByte; i++ )
566                         {
567                             cTmp = *pRLE++;
568                             ImplSetPixel4( pDIB, nX++, cTmp >> 4 );
569                             ImplSetPixel4( pDIB, nX++, cTmp & 0x0f );
570                         }
571 
572                         if( nRunByte & 1 )
573                             ImplSetPixel4( pDIB, nX++, *pRLE++ >> 4 );
574 
575                         if( ( ( nRunByte + 1 ) >> 1 ) & 1 )
576                             pRLE++;
577                     }
578                     else
579                     {
580                         memcpy( &pDIB[ nX ], pRLE, nRunByte );
581                         pRLE += nRunByte;
582                         nX += nRunByte;
583 
584                         if( nRunByte & 1 )
585                             pRLE++;
586                     }
587                 }
588                 else if( !nRunByte )
589                 {
590                     pDIB = ( pRow += nWidthAl );
591                     nX = 0UL;
592                 }
593                 else if( nRunByte == 1 )
594                     bEndDecoding = TRUE;
595                 else
596                 {
597                     nX += *pRLE++;
598                     pDIB = ( pRow += ( *pRLE++ ) * nWidthAl );
599                 }
600             }
601             else
602             {
603                 cTmp = *pRLE++;
604 
605                 if( bRLE4 )
606                 {
607                     nRunByte = nCountByte >> 1;
608 
609                     for( i = 0; i < nRunByte; i++ )
610                     {
611                         ImplSetPixel4( pDIB, nX++, cTmp >> 4 );
612                         ImplSetPixel4( pDIB, nX++, cTmp & 0x0f );
613                     }
614 
615                     if( nCountByte & 1 )
616                         ImplSetPixel4( pDIB, nX++, cTmp >> 4 );
617                 }
618                 else
619                 {
620                     for( i = 0; i < nCountByte; i++ )
621                         pDIB[ nX++ ] = cTmp;
622                 }
623             }
624         }
625         while( !bEndDecoding && ( pDIB <= pLast ) );
626     }
627 }
628 
629 bool WinSalBitmap::GetSystemData( BitmapSystemData& rData )
630 {
631     bool bRet = false;
632     if( mhDIB || mhDDB )
633     {
634         bRet = true;
635         rData.pDIB = mhDIB;
636         rData.pDDB = mhDDB;
637         const Size& rSize = GetSize ();
638         rData.mnWidth = rSize.Width();
639         rData.mnHeight = rSize.Height();
640     }
641     return bRet;
642 }
643