Branch libreoffice-5-0-4
[LibreOffice.git] / vcl / win / source / gdi / salbmp.cxx
blob86656dd1d86a6fc06f36dd80eb0dc7bdf8d60ede
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <svsys.h>
21 #include <vcl/bitmap.hxx>
22 #include <vcl/salbtype.hxx>
23 #include <com/sun/star/beans/XFastPropertySet.hpp>
24 #include <win/wincomp.hxx>
25 #include <win/salgdi.h>
26 #include <win/saldata.hxx>
27 #include <win/salbmp.h>
28 #include <string.h>
29 #include <vcl/timer.hxx>
30 #include <comphelper/broadcasthelper.hxx>
31 #include <map>
33 #if defined _MSC_VER
34 #ifndef min
35 #define min(a,b) (((a) < (b)) ? (a) : (b))
36 #endif
37 #ifndef max
38 #define max(a,b) (((a) > (b)) ? (a) : (b))
39 #endif
40 #endif
42 #if defined _MSC_VER
43 #pragma warning(push, 1)
44 #endif
46 #include <gdiplus.h>
48 #if defined _MSC_VER
49 #pragma warning(pop)
50 #endif
52 // - Inlines -
54 inline void ImplSetPixel4( const HPBYTE pScanline, long nX, const BYTE cIndex )
56 BYTE& rByte = pScanline[ nX >> 1 ];
58 ( nX & 1 ) ? ( rByte &= 0xf0, rByte |= ( cIndex & 0x0f ) ) :
59 ( rByte &= 0x0f, rByte |= ( cIndex << 4 ) );
62 // Helper class to manage Gdiplus::Bitmap instances inside of
63 // WinSalBitmap
65 struct Comparator
67 bool operator()(WinSalBitmap* pA, WinSalBitmap* pB) const
69 return pA < pB;
73 typedef ::std::map< WinSalBitmap*, sal_uInt32, Comparator > EntryMap;
74 static const sal_uInt32 nDefaultCycles(60);
76 class GdiPlusBuffer : protected comphelper::OBaseMutex, public Timer
78 private:
79 EntryMap maEntries;
81 public:
82 GdiPlusBuffer()
83 : Timer(),
84 maEntries()
86 SetTimeout(1000);
87 Stop();
90 ~GdiPlusBuffer()
92 Stop();
95 void addEntry(WinSalBitmap& rEntry)
97 ::osl::MutexGuard aGuard(m_aMutex);
98 EntryMap::iterator aFound = maEntries.find(&rEntry);
100 if(aFound == maEntries.end())
102 if(maEntries.empty())
104 Start();
107 maEntries[&rEntry] = nDefaultCycles;
111 void remEntry(WinSalBitmap& rEntry)
113 ::osl::MutexGuard aGuard(m_aMutex);
114 EntryMap::iterator aFound = maEntries.find(&rEntry);
116 if(aFound != maEntries.end())
118 maEntries.erase(aFound);
120 if(maEntries.empty())
122 Stop();
127 void touchEntry(WinSalBitmap& rEntry)
129 ::osl::MutexGuard aGuard(m_aMutex);
130 EntryMap::iterator aFound = maEntries.find(&rEntry);
132 if(aFound != maEntries.end())
134 aFound->second = nDefaultCycles;
138 // from parent Timer
139 virtual void Invoke()
141 ::osl::MutexGuard aGuard(m_aMutex);
142 EntryMap::iterator aIter(maEntries.begin());
144 while(aIter != maEntries.end())
146 if(aIter->second)
148 aIter->second--;
149 ++aIter;
151 else
153 EntryMap::iterator aDelete(aIter);
154 WinSalBitmap* pSource = aDelete->first;
155 ++aIter;
156 maEntries.erase(aDelete);
158 if(maEntries.empty())
160 Stop();
163 // delete at WinSalBitmap after entry is removed; this
164 // way it would not hurt to call remEntry from there, too
165 if(pSource->maGdiPlusBitmap.get())
167 pSource->maGdiPlusBitmap.reset();
168 pSource->mpAssociatedAlpha = 0;
173 if(!maEntries.empty())
175 Start();
180 // Global instance of GdiPlusBuffer which manages Gdiplus::Bitmap
181 // instances
183 static GdiPlusBuffer aGdiPlusBuffer;
185 // - WinSalBitmap -
187 WinSalBitmap::WinSalBitmap()
188 : maSize(),
189 mhDIB(0),
190 mhDDB(0),
191 maGdiPlusBitmap(),
192 mpAssociatedAlpha(0),
193 mnBitCount(0)
197 WinSalBitmap::~WinSalBitmap()
199 Destroy();
202 void WinSalBitmap::Destroy()
204 if(maGdiPlusBitmap.get())
206 aGdiPlusBuffer.remEntry(*this);
209 if( mhDIB )
210 GlobalFree( mhDIB );
211 else if( mhDDB )
212 DeleteObject( mhDDB );
214 maSize = Size();
215 mnBitCount = 0;
218 GdiPlusBmpPtr WinSalBitmap::ImplGetGdiPlusBitmap(const WinSalBitmap* pAlphaSource) const
220 WinSalBitmap* pThat = const_cast< WinSalBitmap* >(this);
222 if(maGdiPlusBitmap.get() && pAlphaSource != mpAssociatedAlpha)
224 // #122350# if associated alpha with which the GDIPlus was constructed has changed
225 // it is necessary to remove it from buffer, reset reference to it and reconstruct
226 pThat->maGdiPlusBitmap.reset();
227 aGdiPlusBuffer.remEntry(const_cast< WinSalBitmap& >(*this));
230 if(maGdiPlusBitmap.get())
232 aGdiPlusBuffer.touchEntry(const_cast< WinSalBitmap& >(*this));
234 else
236 if(maSize.Width() > 0 && maSize.Height() > 0)
238 if(pAlphaSource)
240 pThat->maGdiPlusBitmap.reset(pThat->ImplCreateGdiPlusBitmap(*pAlphaSource));
241 pThat->mpAssociatedAlpha = pAlphaSource;
243 else
245 pThat->maGdiPlusBitmap.reset(pThat->ImplCreateGdiPlusBitmap());
246 pThat->mpAssociatedAlpha = 0;
249 if(maGdiPlusBitmap.get())
251 aGdiPlusBuffer.addEntry(*pThat);
256 return maGdiPlusBitmap;
259 Gdiplus::Bitmap* WinSalBitmap::ImplCreateGdiPlusBitmap()
261 Gdiplus::Bitmap* pRetval(0);
262 WinSalBitmap* pSalRGB = const_cast< WinSalBitmap* >(this);
263 WinSalBitmap* pExtraWinSalRGB = 0;
265 if(!pSalRGB->ImplGethDIB())
267 // we need DIB for success with AcquireBuffer, create a replacement WinSalBitmap
268 pExtraWinSalRGB = new WinSalBitmap();
269 pExtraWinSalRGB->Create(*pSalRGB, pSalRGB->GetBitCount());
270 pSalRGB = pExtraWinSalRGB;
273 BitmapBuffer* pRGB = pSalRGB->AcquireBuffer(BITMAP_READ_ACCESS);
274 BitmapBuffer* pExtraRGB = 0;
276 if(pRGB && BMP_FORMAT_24BIT_TC_BGR != (pRGB->mnFormat & ~BMP_FORMAT_TOP_DOWN))
278 // convert source bitmap to BMP_FORMAT_24BIT_TC_BGR format if not yet in that format
279 SalTwoRect aSalTwoRect(0, 0, pRGB->mnWidth, pRGB->mnHeight, 0, 0, pRGB->mnWidth, pRGB->mnHeight);
280 pExtraRGB = StretchAndConvert(
281 *pRGB,
282 aSalTwoRect,
283 BMP_FORMAT_24BIT_TC_BGR,
286 pSalRGB->ReleaseBuffer(pRGB, BITMAP_WRITE_ACCESS);
287 pRGB = pExtraRGB;
290 if(pRGB
291 && pRGB->mnWidth > 0
292 && pRGB->mnHeight > 0
293 && BMP_FORMAT_24BIT_TC_BGR == (pRGB->mnFormat & ~BMP_FORMAT_TOP_DOWN))
295 const sal_uInt32 nW(pRGB->mnWidth);
296 const sal_uInt32 nH(pRGB->mnHeight);
298 pRetval = new Gdiplus::Bitmap(nW, nH, PixelFormat24bppRGB);
300 if ( pRetval->GetLastStatus() == Gdiplus::Ok )
302 sal_uInt8* pSrcRGB(pRGB->mpBits);
303 const sal_uInt32 nExtraRGB(pRGB->mnScanlineSize - (nW * 3));
304 const bool bTopDown(pRGB->mnFormat & BMP_FORMAT_TOP_DOWN);
305 const Gdiplus::Rect aAllRect(0, 0, nW, nH);
306 Gdiplus::BitmapData aGdiPlusBitmapData;
307 pRetval->LockBits(&aAllRect, Gdiplus::ImageLockModeWrite, PixelFormat24bppRGB, &aGdiPlusBitmapData);
309 // copy data to Gdiplus::Bitmap; format is BGR here in both cases, so memcpy is possible
310 for(sal_uInt32 y(0); y < nH; y++)
312 const sal_uInt32 nYInsert(bTopDown ? y : nH - y - 1);
313 sal_uInt8* targetPixels = (sal_uInt8*)aGdiPlusBitmapData.Scan0 + (nYInsert * aGdiPlusBitmapData.Stride);
315 memcpy(targetPixels, pSrcRGB, nW * 3);
316 pSrcRGB += nW * 3 + nExtraRGB;
319 pRetval->UnlockBits(&aGdiPlusBitmapData);
321 else
323 delete pRetval;
324 pRetval = NULL;
328 if(pExtraRGB)
330 // #i123478# shockingly, BitmapBuffer does not free the memory it is controlling
331 // in its destructor, this *has to be done handish*. Doing it here now
332 delete[] pExtraRGB->mpBits;
333 delete pExtraRGB;
335 else
337 pSalRGB->ReleaseBuffer(pRGB, BITMAP_READ_ACCESS);
340 if(pExtraWinSalRGB)
342 delete pExtraWinSalRGB;
345 return pRetval;
348 Gdiplus::Bitmap* WinSalBitmap::ImplCreateGdiPlusBitmap(const WinSalBitmap& rAlphaSource)
350 Gdiplus::Bitmap* pRetval(0);
351 WinSalBitmap* pSalRGB = const_cast< WinSalBitmap* >(this);
352 WinSalBitmap* pExtraWinSalRGB = 0;
354 if(!pSalRGB->ImplGethDIB())
356 // we need DIB for success with AcquireBuffer, create a replacement WinSalBitmap
357 pExtraWinSalRGB = new WinSalBitmap();
358 pExtraWinSalRGB->Create(*pSalRGB, pSalRGB->GetBitCount());
359 pSalRGB = pExtraWinSalRGB;
362 BitmapBuffer* pRGB = pSalRGB->AcquireBuffer(BITMAP_READ_ACCESS);
363 BitmapBuffer* pExtraRGB = 0;
365 if(pRGB && BMP_FORMAT_24BIT_TC_BGR != (pRGB->mnFormat & ~BMP_FORMAT_TOP_DOWN))
367 // convert source bitmap to BMP_FORMAT_24BIT_TC_BGR format if not yet in that format
368 SalTwoRect aSalTwoRect(0, 0, pRGB->mnWidth, pRGB->mnHeight, 0, 0, pRGB->mnWidth, pRGB->mnHeight);
369 pExtraRGB = StretchAndConvert(
370 *pRGB,
371 aSalTwoRect,
372 BMP_FORMAT_24BIT_TC_BGR,
375 pSalRGB->ReleaseBuffer(pRGB, BITMAP_READ_ACCESS);
376 pRGB = pExtraRGB;
379 WinSalBitmap* pSalA = const_cast< WinSalBitmap* >(&rAlphaSource);
380 WinSalBitmap* pExtraWinSalA = 0;
382 if(!pSalA->ImplGethDIB())
384 // we need DIB for success with AcquireBuffer, create a replacement WinSalBitmap
385 pExtraWinSalA = new WinSalBitmap();
386 pExtraWinSalA->Create(*pSalA, pSalA->GetBitCount());
387 pSalA = pExtraWinSalA;
390 BitmapBuffer* pA = pSalA->AcquireBuffer(BITMAP_READ_ACCESS);
391 BitmapBuffer* pExtraA = 0;
393 if(pA && BMP_FORMAT_8BIT_PAL != (pA->mnFormat & ~BMP_FORMAT_TOP_DOWN))
395 // convert alpha bitmap to BMP_FORMAT_8BIT_PAL format if not yet in that format
396 SalTwoRect aSalTwoRect(0, 0, pA->mnWidth, pA->mnHeight, 0, 0, pA->mnWidth, pA->mnHeight);
397 const BitmapPalette& rTargetPalette = Bitmap::GetGreyPalette(256);
399 pExtraA = StretchAndConvert(
400 *pA,
401 aSalTwoRect,
402 BMP_FORMAT_8BIT_PAL,
403 &rTargetPalette);
405 pSalA->ReleaseBuffer(pA, BITMAP_READ_ACCESS);
406 pA = pExtraA;
409 if(pRGB
410 && pA
411 && pRGB->mnWidth > 0
412 && pRGB->mnHeight > 0
413 && pRGB->mnWidth == pA->mnWidth
414 && pRGB->mnHeight == pA->mnHeight
415 && BMP_FORMAT_24BIT_TC_BGR == (pRGB->mnFormat & ~BMP_FORMAT_TOP_DOWN)
416 && BMP_FORMAT_8BIT_PAL == (pA->mnFormat & ~BMP_FORMAT_TOP_DOWN))
418 // we have alpha and bitmap in known formats, create GdiPlus Bitmap as 32bit ARGB
419 const sal_uInt32 nW(pRGB->mnWidth);
420 const sal_uInt32 nH(pRGB->mnHeight);
422 pRetval = new Gdiplus::Bitmap(nW, nH, PixelFormat32bppARGB);
424 if ( pRetval->GetLastStatus() == Gdiplus::Ok ) // 2nd place to secure with new Gdiplus::Bitmap
426 sal_uInt8* pSrcRGB(pRGB->mpBits);
427 sal_uInt8* pSrcA(pA->mpBits);
428 const sal_uInt32 nExtraRGB(pRGB->mnScanlineSize - (nW * 3));
429 const sal_uInt32 nExtraA(pA->mnScanlineSize - nW);
430 const bool bTopDown(pRGB->mnFormat & BMP_FORMAT_TOP_DOWN);
431 const Gdiplus::Rect aAllRect(0, 0, nW, nH);
432 Gdiplus::BitmapData aGdiPlusBitmapData;
433 pRetval->LockBits(&aAllRect, Gdiplus::ImageLockModeWrite, PixelFormat32bppARGB, &aGdiPlusBitmapData);
435 // copy data to Gdiplus::Bitmap; format is BGRA; need to mix BGR from Bitmap and
436 // A from alpha, so inner loop is needed (who invented BitmapEx..?)
437 for(sal_uInt32 y(0); y < nH; y++)
439 const sal_uInt32 nYInsert(bTopDown ? y : nH - y - 1);
440 sal_uInt8* targetPixels = (sal_uInt8*)aGdiPlusBitmapData.Scan0 + (nYInsert * aGdiPlusBitmapData.Stride);
442 for(sal_uInt32 x(0); x < nW; x++)
444 *targetPixels++ = *pSrcRGB++;
445 *targetPixels++ = *pSrcRGB++;
446 *targetPixels++ = *pSrcRGB++;
447 *targetPixels++ = 0xff - *pSrcA++;
450 pSrcRGB += nExtraRGB;
451 pSrcA += nExtraA;
454 pRetval->UnlockBits(&aGdiPlusBitmapData);
456 else
458 delete pRetval;
459 pRetval = NULL;
463 if(pExtraA)
465 // #i123478# shockingly, BitmapBuffer does not free the memory it is controlling
466 // in its destructor, this *has to be done handish*. Doing it here now
467 delete[] pExtraA->mpBits;
468 delete pExtraA;
470 else
472 pSalA->ReleaseBuffer(pA, BITMAP_READ_ACCESS);
475 if(pExtraWinSalA)
477 delete pExtraWinSalA;
480 if(pExtraRGB)
482 // #i123478# shockingly, BitmapBuffer does not free the memory it is controlling
483 // in its destructor, this *has to be done handish*. Doing it here now
484 delete[] pExtraRGB->mpBits;
485 delete pExtraRGB;
487 else
489 pSalRGB->ReleaseBuffer(pRGB, BITMAP_READ_ACCESS);
492 if(pExtraWinSalRGB)
494 delete pExtraWinSalRGB;
497 return pRetval;
500 bool WinSalBitmap::Create( HANDLE hBitmap, bool bDIB, bool bCopyHandle )
502 bool bRet = TRUE;
504 if( bDIB )
505 mhDIB = (HGLOBAL) ( bCopyHandle ? ImplCopyDIBOrDDB( hBitmap, TRUE ) : hBitmap );
506 else
507 mhDDB = (HBITMAP) ( bCopyHandle ? ImplCopyDIBOrDDB( hBitmap, FALSE ) : hBitmap );
509 if( mhDIB )
511 PBITMAPINFOHEADER pBIH = (PBITMAPINFOHEADER) GlobalLock( mhDIB );
513 maSize = Size( pBIH->biWidth, pBIH->biHeight );
514 mnBitCount = pBIH->biBitCount;
516 if( mnBitCount )
517 mnBitCount = ( mnBitCount <= 1 ) ? 1 : ( mnBitCount <= 4 ) ? 4 : ( mnBitCount <= 8 ) ? 8 : 24;
519 GlobalUnlock( mhDIB );
521 else if( mhDDB )
523 BITMAP aDDBInfo;
525 if( GetObjectA( mhDDB, sizeof( BITMAP ), &aDDBInfo ) )
527 maSize = Size( aDDBInfo.bmWidth, aDDBInfo.bmHeight );
528 mnBitCount = aDDBInfo.bmPlanes * aDDBInfo.bmBitsPixel;
530 if( mnBitCount )
532 mnBitCount = ( mnBitCount <= 1 ) ? 1 :
533 ( mnBitCount <= 4 ) ? 4 :
534 ( mnBitCount <= 8 ) ? 8 : 24;
537 else
539 mhDDB = 0;
540 bRet = FALSE;
543 else
544 bRet = FALSE;
546 return bRet;
549 bool WinSalBitmap::Create( const Size& rSize, sal_uInt16 nBitCount, const BitmapPalette& rPal )
551 bool bRet = FALSE;
553 mhDIB = ImplCreateDIB( rSize, nBitCount, rPal );
555 if( mhDIB )
557 maSize = rSize;
558 mnBitCount = nBitCount;
559 bRet = TRUE;
562 return bRet;
565 bool WinSalBitmap::Create( const SalBitmap& rSSalBitmap )
567 bool bRet = FALSE;
568 const WinSalBitmap& rSalBitmap = static_cast<const WinSalBitmap&>(rSSalBitmap);
570 if ( rSalBitmap.mhDIB || rSalBitmap.mhDDB )
572 HANDLE hNewHdl = ImplCopyDIBOrDDB( rSalBitmap.mhDIB ? rSalBitmap.mhDIB : rSalBitmap.mhDDB,
573 rSalBitmap.mhDIB != 0 );
575 if ( hNewHdl )
577 if( rSalBitmap.mhDIB )
578 mhDIB = (HGLOBAL) hNewHdl;
579 else if( rSalBitmap.mhDDB )
580 mhDDB = (HBITMAP) hNewHdl;
582 maSize = rSalBitmap.maSize;
583 mnBitCount = rSalBitmap.mnBitCount;
585 bRet = TRUE;
589 return bRet;
592 bool WinSalBitmap::Create( const SalBitmap& rSSalBmp, SalGraphics* pSGraphics )
594 bool bRet = FALSE;
596 const WinSalBitmap& rSalBmp = static_cast<const WinSalBitmap&>(rSSalBmp);
597 WinSalGraphics* pGraphics = static_cast<WinSalGraphics*>(pSGraphics);
599 if( rSalBmp.mhDIB )
601 PBITMAPINFO pBI = (PBITMAPINFO) GlobalLock( rSalBmp.mhDIB );
602 PBITMAPINFOHEADER pBIH = (PBITMAPINFOHEADER) pBI;
603 HDC hDC = pGraphics->getHDC();
604 HBITMAP hNewDDB;
605 BITMAP aDDBInfo;
606 PBYTE pBits = (PBYTE) pBI + *(DWORD*) pBI +
607 ImplGetDIBColorCount( rSalBmp.mhDIB ) * sizeof( RGBQUAD );
609 if( pBIH->biBitCount == 1 )
611 hNewDDB = CreateBitmap( pBIH->biWidth, pBIH->biHeight, 1, 1, NULL );
613 if( hNewDDB )
614 SetDIBits( hDC, hNewDDB, 0, pBIH->biHeight, pBits, pBI, DIB_RGB_COLORS );
616 else
617 hNewDDB = CreateDIBitmap( hDC, (PBITMAPINFOHEADER) pBI, CBM_INIT, pBits, pBI, DIB_RGB_COLORS );
619 GlobalUnlock( rSalBmp.mhDIB );
621 if( hNewDDB && GetObjectA( hNewDDB, sizeof( BITMAP ), &aDDBInfo ) )
623 mhDDB = hNewDDB;
624 maSize = Size( aDDBInfo.bmWidth, aDDBInfo.bmHeight );
625 mnBitCount = aDDBInfo.bmPlanes * aDDBInfo.bmBitsPixel;
627 bRet = TRUE;
629 else if( hNewDDB )
630 DeleteObject( hNewDDB );
633 return bRet;
636 bool WinSalBitmap::Create( const SalBitmap& rSSalBmp, sal_uInt16 nNewBitCount )
638 bool bRet = FALSE;
640 const WinSalBitmap& rSalBmp = static_cast<const WinSalBitmap&>(rSSalBmp);
642 if( rSalBmp.mhDDB )
644 mhDIB = ImplCreateDIB( rSalBmp.maSize, nNewBitCount, BitmapPalette() );
646 if( mhDIB )
648 PBITMAPINFO pBI = (PBITMAPINFO) GlobalLock( mhDIB );
649 const int nLines = (int) rSalBmp.maSize.Height();
650 HDC hDC = GetDC( 0 );
651 PBYTE pBits = (PBYTE) pBI + *(DWORD*) pBI +
652 ImplGetDIBColorCount( mhDIB ) * sizeof( RGBQUAD );
653 SalData* pSalData = GetSalData();
654 HPALETTE hOldPal = 0;
656 if ( pSalData->mhDitherPal )
658 hOldPal = SelectPalette( hDC, pSalData->mhDitherPal, TRUE );
659 RealizePalette( hDC );
662 if( GetDIBits( hDC, rSalBmp.mhDDB, 0, nLines, pBits, pBI, DIB_RGB_COLORS ) == nLines )
664 GlobalUnlock( mhDIB );
665 maSize = rSalBmp.maSize;
666 mnBitCount = nNewBitCount;
667 bRet = TRUE;
669 else
671 GlobalUnlock( mhDIB );
672 GlobalFree( mhDIB );
673 mhDIB = 0;
676 if( hOldPal )
677 SelectPalette( hDC, hOldPal, TRUE );
679 ReleaseDC( 0, hDC );
683 return bRet;
686 bool WinSalBitmap::Create( const ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XBitmapCanvas >& rBitmapCanvas, Size& /*rSize*/, bool bMask )
688 ::com::sun::star::uno::Reference< ::com::sun::star::beans::XFastPropertySet >
689 xFastPropertySet( rBitmapCanvas, ::com::sun::star::uno::UNO_QUERY );
691 if( xFastPropertySet.get() ) {
692 ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any > args;
694 if( xFastPropertySet->getFastPropertyValue(bMask ? 2 : 1) >>= args ) {
695 sal_Int64 aHBmp64;
697 if( args[0] >>= aHBmp64 ) {
698 return Create( HBITMAP(aHBmp64), false, false );
702 return false;
705 sal_uInt16 WinSalBitmap::ImplGetDIBColorCount( HGLOBAL hDIB )
707 sal_uInt16 nColors = 0;
709 if( hDIB )
711 PBITMAPINFO pBI = (PBITMAPINFO) GlobalLock( hDIB );
712 PBITMAPINFOHEADER pBIH = (PBITMAPINFOHEADER) pBI;
714 if ( pBIH->biSize != sizeof( BITMAPCOREHEADER ) )
716 if( pBIH->biBitCount <= 8 )
718 if ( pBIH->biClrUsed )
719 nColors = (sal_uInt16) pBIH->biClrUsed;
720 else
721 nColors = 1 << pBIH->biBitCount;
724 else if( ( (PBITMAPCOREHEADER) pBI )->bcBitCount <= 8 )
725 nColors = 1 << ( (PBITMAPCOREHEADER) pBI )->bcBitCount;
727 GlobalUnlock( hDIB );
730 return nColors;
733 HGLOBAL WinSalBitmap::ImplCreateDIB( const Size& rSize, sal_uInt16 nBits, const BitmapPalette& rPal )
735 DBG_ASSERT( nBits == 1 || nBits == 4 || nBits == 8 || nBits == 16 || nBits == 24, "Unsupported BitCount!" );
737 HGLOBAL hDIB = 0;
739 if( rSize.Width() <= 0 || rSize.Height() <= 0 )
740 return hDIB;
742 // calculate bitmap size in Bytes
743 const sal_uLong nAlignedWidth4Bytes = AlignedWidth4Bytes( nBits * rSize.Width() );
744 const sal_uLong nImageSize = nAlignedWidth4Bytes * rSize.Height();
745 bool bOverflow = (nImageSize / nAlignedWidth4Bytes) != (sal_uLong) rSize.Height();
746 if( bOverflow )
747 return hDIB;
749 // allocate bitmap memory including header and palette
750 const sal_uInt16 nColors = (nBits <= 8) ? (1 << nBits) : 0;
751 const sal_uLong nHeaderSize = sizeof( BITMAPINFOHEADER ) + nColors * sizeof( RGBQUAD );
752 bOverflow = (nHeaderSize + nImageSize) < nImageSize;
753 if( bOverflow )
754 return hDIB;
756 hDIB = GlobalAlloc( GHND, nHeaderSize + nImageSize );
757 if( !hDIB )
758 return hDIB;
760 PBITMAPINFO pBI = static_cast<PBITMAPINFO>( GlobalLock( hDIB ) );
761 PBITMAPINFOHEADER pBIH = reinterpret_cast<PBITMAPINFOHEADER>( pBI );
763 pBIH->biSize = sizeof( BITMAPINFOHEADER );
764 pBIH->biWidth = rSize.Width();
765 pBIH->biHeight = rSize.Height();
766 pBIH->biPlanes = 1;
767 pBIH->biBitCount = nBits;
768 pBIH->biCompression = BI_RGB;
769 pBIH->biSizeImage = nImageSize;
770 pBIH->biXPelsPerMeter = 0;
771 pBIH->biYPelsPerMeter = 0;
772 pBIH->biClrUsed = 0;
773 pBIH->biClrImportant = 0;
775 if( nColors )
777 // copy the palette entries if any
778 const sal_uInt16 nMinCount = (std::min)( nColors, rPal.GetEntryCount() );
779 if( nMinCount )
780 memcpy( pBI->bmiColors, rPal.ImplGetColorBuffer(), nMinCount * sizeof(RGBQUAD) );
783 GlobalUnlock( hDIB );
785 return hDIB;
788 HANDLE WinSalBitmap::ImplCopyDIBOrDDB( HANDLE hHdl, bool bDIB )
790 HANDLE hCopy = 0;
792 if ( bDIB && hHdl )
794 const sal_uLong nSize = GlobalSize( hHdl );
796 if ( (hCopy = GlobalAlloc( GHND, nSize )) != 0 )
798 memcpy( (LPSTR) GlobalLock( hCopy ), (LPSTR) GlobalLock( hHdl ), nSize );
800 GlobalUnlock( hCopy );
801 GlobalUnlock( hHdl );
804 else if ( hHdl )
806 BITMAP aBmp;
808 // find out size of source bitmap
809 GetObjectA( hHdl, sizeof( BITMAP ), (LPSTR) &aBmp );
811 // create destination bitmap
812 if ( (hCopy = CreateBitmapIndirect( &aBmp )) != 0 )
814 HDC hBmpDC = CreateCompatibleDC( 0 );
815 HBITMAP hBmpOld = (HBITMAP) SelectObject( hBmpDC, hHdl );
816 HDC hCopyDC = CreateCompatibleDC( hBmpDC );
817 HBITMAP hCopyOld = (HBITMAP) SelectObject( hCopyDC, hCopy );
819 BitBlt( hCopyDC, 0, 0, aBmp.bmWidth, aBmp.bmHeight, hBmpDC, 0, 0, SRCCOPY );
821 SelectObject( hCopyDC, hCopyOld );
822 DeleteDC( hCopyDC );
824 SelectObject( hBmpDC, hBmpOld );
825 DeleteDC( hBmpDC );
829 return hCopy;
832 BitmapBuffer* WinSalBitmap::AcquireBuffer( BitmapAccessMode /*nMode*/ )
834 BitmapBuffer* pBuffer = NULL;
836 if( mhDIB )
838 PBITMAPINFO pBI = (PBITMAPINFO) GlobalLock( mhDIB );
839 PBITMAPINFOHEADER pBIH = (PBITMAPINFOHEADER) pBI;
841 if( ( pBIH->biCompression == BI_RLE4 ) || ( pBIH->biCompression == BI_RLE8 ) )
843 Size aSizePix( pBIH->biWidth, pBIH->biHeight );
844 HGLOBAL hNewDIB = ImplCreateDIB( aSizePix, pBIH->biBitCount, BitmapPalette() );
846 if( hNewDIB )
848 PBITMAPINFO pNewBI = (PBITMAPINFO) GlobalLock( hNewDIB );
849 PBITMAPINFOHEADER pNewBIH = (PBITMAPINFOHEADER) pNewBI;
850 const sal_uInt16 nColorCount = ImplGetDIBColorCount( hNewDIB );
851 const sal_uLong nOffset = *(DWORD*) pBI + nColorCount * sizeof( RGBQUAD );
852 BYTE* pOldBits = (PBYTE) pBI + nOffset;
853 BYTE* pNewBits = (PBYTE) pNewBI + nOffset;
855 memcpy( pNewBI, pBI, nOffset );
856 pNewBIH->biCompression = 0;
857 ImplDecodeRLEBuffer( pOldBits, pNewBits, aSizePix, pBIH->biCompression == BI_RLE4 );
859 GlobalUnlock( mhDIB );
860 GlobalFree( mhDIB );
861 mhDIB = hNewDIB;
862 pBI = pNewBI;
863 pBIH = pNewBIH;
867 if( pBIH->biPlanes == 1 )
869 pBuffer = new BitmapBuffer;
871 pBuffer->mnFormat = BMP_FORMAT_BOTTOM_UP |
872 ( pBIH->biBitCount == 1 ? BMP_FORMAT_1BIT_MSB_PAL :
873 pBIH->biBitCount == 4 ? BMP_FORMAT_4BIT_MSN_PAL :
874 pBIH->biBitCount == 8 ? BMP_FORMAT_8BIT_PAL :
875 pBIH->biBitCount == 16 ? BMP_FORMAT_16BIT_TC_LSB_MASK :
876 pBIH->biBitCount == 24 ? BMP_FORMAT_24BIT_TC_BGR :
877 pBIH->biBitCount == 32 ? BMP_FORMAT_32BIT_TC_MASK : 0UL );
879 if( BMP_SCANLINE_FORMAT( pBuffer->mnFormat ) )
881 pBuffer->mnWidth = maSize.Width();
882 pBuffer->mnHeight = maSize.Height();
883 pBuffer->mnScanlineSize = AlignedWidth4Bytes( maSize.Width() * pBIH->biBitCount );
884 pBuffer->mnBitCount = (sal_uInt16) pBIH->biBitCount;
886 if( pBuffer->mnBitCount <= 8 )
888 const sal_uInt16 nPalCount = ImplGetDIBColorCount( mhDIB );
890 pBuffer->maPalette.SetEntryCount( nPalCount );
891 memcpy( pBuffer->maPalette.ImplGetColorBuffer(), pBI->bmiColors, nPalCount * sizeof( RGBQUAD ) );
892 pBuffer->mpBits = (PBYTE) pBI + *(DWORD*) pBI + nPalCount * sizeof( RGBQUAD );
894 else if( ( pBIH->biBitCount == 16 ) || ( pBIH->biBitCount == 32 ) )
896 sal_uLong nOffset = 0UL;
898 if( pBIH->biCompression == BI_BITFIELDS )
900 nOffset = 3 * sizeof( RGBQUAD );
901 pBuffer->maColorMask = ColorMask( *(UINT32*) &pBI->bmiColors[ 0 ],
902 *(UINT32*) &pBI->bmiColors[ 1 ],
903 *(UINT32*) &pBI->bmiColors[ 2 ] );
905 else if( pBIH->biBitCount == 16 )
906 pBuffer->maColorMask = ColorMask( 0x00007c00UL, 0x000003e0UL, 0x0000001fUL );
907 else
908 pBuffer->maColorMask = ColorMask( 0x00ff0000UL, 0x0000ff00UL, 0x000000ffUL );
910 pBuffer->mpBits = (PBYTE) pBI + *(DWORD*) pBI + nOffset;
912 else
913 pBuffer->mpBits = (PBYTE) pBI + *(DWORD*) pBI;
915 else
917 GlobalUnlock( mhDIB );
918 delete pBuffer;
919 pBuffer = NULL;
922 else
923 GlobalUnlock( mhDIB );
926 return pBuffer;
929 void WinSalBitmap::ReleaseBuffer( BitmapBuffer* pBuffer, BitmapAccessMode nMode )
931 if( pBuffer )
933 if( mhDIB )
935 if( nMode == BITMAP_WRITE_ACCESS && !!pBuffer->maPalette )
937 PBITMAPINFO pBI = (PBITMAPINFO) GlobalLock( mhDIB );
938 const sal_uInt16 nCount = pBuffer->maPalette.GetEntryCount();
939 const sal_uInt16 nDIBColorCount = ImplGetDIBColorCount( mhDIB );
940 memcpy( pBI->bmiColors, pBuffer->maPalette.ImplGetColorBuffer(), (std::min)( nDIBColorCount, nCount ) * sizeof( RGBQUAD ) );
941 GlobalUnlock( mhDIB );
944 GlobalUnlock( mhDIB );
947 delete pBuffer;
951 void WinSalBitmap::ImplDecodeRLEBuffer( const BYTE* pSrcBuf, BYTE* pDstBuf,
952 const Size& rSizePixel, bool bRLE4 )
954 HPBYTE pRLE = (HPBYTE) pSrcBuf;
955 HPBYTE pDIB = (HPBYTE) pDstBuf;
956 HPBYTE pRow = (HPBYTE) pDstBuf;
957 sal_uLong nWidthAl = AlignedWidth4Bytes( rSizePixel.Width() * ( bRLE4 ? 4UL : 8UL ) );
958 HPBYTE pLast = pDIB + rSizePixel.Height() * nWidthAl - 1;
959 sal_uLong nCountByte;
960 sal_uLong nRunByte;
961 sal_uLong i;
962 BYTE cTmp;
963 bool bEndDecoding = FALSE;
965 if( pRLE && pDIB )
967 sal_uLong nX = 0;
970 if( ( nCountByte = *pRLE++ ) == 0 )
972 nRunByte = *pRLE++;
974 if( nRunByte > 2UL )
976 if( bRLE4 )
978 nCountByte = nRunByte >> 1UL;
980 for( i = 0; i < nCountByte; i++ )
982 cTmp = *pRLE++;
983 ImplSetPixel4( pDIB, nX++, cTmp >> 4 );
984 ImplSetPixel4( pDIB, nX++, cTmp & 0x0f );
987 if( nRunByte & 1 )
988 ImplSetPixel4( pDIB, nX++, *pRLE++ >> 4 );
990 if( ( ( nRunByte + 1 ) >> 1 ) & 1 )
991 pRLE++;
993 else
995 memcpy( &pDIB[ nX ], pRLE, nRunByte );
996 pRLE += nRunByte;
997 nX += nRunByte;
999 if( nRunByte & 1 )
1000 pRLE++;
1003 else if( !nRunByte )
1005 pDIB = ( pRow += nWidthAl );
1006 nX = 0UL;
1008 else if( nRunByte == 1 )
1009 bEndDecoding = TRUE;
1010 else
1012 nX += *pRLE++;
1013 pDIB = ( pRow += ( *pRLE++ ) * nWidthAl );
1016 else
1018 cTmp = *pRLE++;
1020 if( bRLE4 )
1022 nRunByte = nCountByte >> 1;
1024 for( i = 0; i < nRunByte; i++ )
1026 ImplSetPixel4( pDIB, nX++, cTmp >> 4 );
1027 ImplSetPixel4( pDIB, nX++, cTmp & 0x0f );
1030 if( nCountByte & 1 )
1031 ImplSetPixel4( pDIB, nX++, cTmp >> 4 );
1033 else
1035 for( i = 0; i < nCountByte; i++ )
1036 pDIB[ nX++ ] = cTmp;
1040 while( !bEndDecoding && ( pDIB <= pLast ) );
1044 bool WinSalBitmap::GetSystemData( BitmapSystemData& rData )
1046 bool bRet = false;
1047 if( mhDIB || mhDDB )
1049 bRet = true;
1050 rData.pDIB = mhDIB;
1051 rData.pDDB = mhDDB;
1052 const Size& rSize = GetSize ();
1053 rData.mnWidth = rSize.Width();
1054 rData.mnHeight = rSize.Height();
1056 return bRet;
1059 bool WinSalBitmap::Crop( const Rectangle& /*rRectPixel*/ )
1061 return false;
1064 bool WinSalBitmap::Erase( const ::Color& /*rFillColor*/ )
1066 return false;
1069 bool WinSalBitmap::Scale( const double& /*rScaleX*/, const double& /*rScaleY*/, BmpScaleFlag /*nScaleFlag*/ )
1071 return false;
1074 bool WinSalBitmap::Replace( const Color& /*rSearchColor*/, const Color& /*rReplaceColor*/, sal_uLong /*nTol*/ )
1076 return false;
1079 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */