1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 .
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>
29 #include <vcl/timer.hxx>
30 #include <comphelper/broadcasthelper.hxx>
35 #define min(a,b) (((a) < (b)) ? (a) : (b))
38 #define max(a,b) (((a) > (b)) ? (a) : (b))
43 #pragma warning(push, 1)
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
67 bool operator()(WinSalBitmap
* pA
, WinSalBitmap
* pB
) const
73 typedef ::std::map
< WinSalBitmap
*, sal_uInt32
, Comparator
> EntryMap
;
74 static const sal_uInt32
nDefaultCycles(60);
76 class GdiPlusBuffer
: protected comphelper::OBaseMutex
, public Timer
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())
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())
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
;
139 virtual void Invoke()
141 ::osl::MutexGuard
aGuard(m_aMutex
);
142 EntryMap::iterator
aIter(maEntries
.begin());
144 while(aIter
!= maEntries
.end())
153 EntryMap::iterator
aDelete(aIter
);
154 WinSalBitmap
* pSource
= aDelete
->first
;
156 maEntries
.erase(aDelete
);
158 if(maEntries
.empty())
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())
180 // Global instance of GdiPlusBuffer which manages Gdiplus::Bitmap
183 static GdiPlusBuffer aGdiPlusBuffer
;
187 WinSalBitmap::WinSalBitmap()
192 mpAssociatedAlpha(0),
197 WinSalBitmap::~WinSalBitmap()
202 void WinSalBitmap::Destroy()
204 if(maGdiPlusBitmap
.get())
206 aGdiPlusBuffer
.remEntry(*this);
212 DeleteObject( mhDDB
);
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));
236 if(maSize
.Width() > 0 && maSize
.Height() > 0)
240 pThat
->maGdiPlusBitmap
.reset(pThat
->ImplCreateGdiPlusBitmap(*pAlphaSource
));
241 pThat
->mpAssociatedAlpha
= pAlphaSource
;
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(
283 BMP_FORMAT_24BIT_TC_BGR
,
286 pSalRGB
->ReleaseBuffer(pRGB
, BITMAP_WRITE_ACCESS
);
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
);
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
;
337 pSalRGB
->ReleaseBuffer(pRGB
, BITMAP_READ_ACCESS
);
342 delete pExtraWinSalRGB
;
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(
372 BMP_FORMAT_24BIT_TC_BGR
,
375 pSalRGB
->ReleaseBuffer(pRGB
, BITMAP_READ_ACCESS
);
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(
405 pSalA
->ReleaseBuffer(pA
, BITMAP_READ_ACCESS
);
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
;
454 pRetval
->UnlockBits(&aGdiPlusBitmapData
);
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
;
472 pSalA
->ReleaseBuffer(pA
, BITMAP_READ_ACCESS
);
477 delete pExtraWinSalA
;
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
;
489 pSalRGB
->ReleaseBuffer(pRGB
, BITMAP_READ_ACCESS
);
494 delete pExtraWinSalRGB
;
500 bool WinSalBitmap::Create( HANDLE hBitmap
, bool bDIB
, bool bCopyHandle
)
505 mhDIB
= (HGLOBAL
) ( bCopyHandle
? ImplCopyDIBOrDDB( hBitmap
, TRUE
) : hBitmap
);
507 mhDDB
= (HBITMAP
) ( bCopyHandle
? ImplCopyDIBOrDDB( hBitmap
, FALSE
) : hBitmap
);
511 PBITMAPINFOHEADER pBIH
= (PBITMAPINFOHEADER
) GlobalLock( mhDIB
);
513 maSize
= Size( pBIH
->biWidth
, pBIH
->biHeight
);
514 mnBitCount
= pBIH
->biBitCount
;
517 mnBitCount
= ( mnBitCount
<= 1 ) ? 1 : ( mnBitCount
<= 4 ) ? 4 : ( mnBitCount
<= 8 ) ? 8 : 24;
519 GlobalUnlock( mhDIB
);
525 if( GetObjectA( mhDDB
, sizeof( BITMAP
), &aDDBInfo
) )
527 maSize
= Size( aDDBInfo
.bmWidth
, aDDBInfo
.bmHeight
);
528 mnBitCount
= aDDBInfo
.bmPlanes
* aDDBInfo
.bmBitsPixel
;
532 mnBitCount
= ( mnBitCount
<= 1 ) ? 1 :
533 ( mnBitCount
<= 4 ) ? 4 :
534 ( mnBitCount
<= 8 ) ? 8 : 24;
549 bool WinSalBitmap::Create( const Size
& rSize
, sal_uInt16 nBitCount
, const BitmapPalette
& rPal
)
553 mhDIB
= ImplCreateDIB( rSize
, nBitCount
, rPal
);
558 mnBitCount
= nBitCount
;
565 bool WinSalBitmap::Create( const SalBitmap
& rSSalBitmap
)
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 );
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
;
592 bool WinSalBitmap::Create( const SalBitmap
& rSSalBmp
, SalGraphics
* pSGraphics
)
596 const WinSalBitmap
& rSalBmp
= static_cast<const WinSalBitmap
&>(rSSalBmp
);
597 WinSalGraphics
* pGraphics
= static_cast<WinSalGraphics
*>(pSGraphics
);
601 PBITMAPINFO pBI
= (PBITMAPINFO
) GlobalLock( rSalBmp
.mhDIB
);
602 PBITMAPINFOHEADER pBIH
= (PBITMAPINFOHEADER
) pBI
;
603 HDC hDC
= pGraphics
->getHDC();
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
);
614 SetDIBits( hDC
, hNewDDB
, 0, pBIH
->biHeight
, pBits
, pBI
, DIB_RGB_COLORS
);
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
) )
624 maSize
= Size( aDDBInfo
.bmWidth
, aDDBInfo
.bmHeight
);
625 mnBitCount
= aDDBInfo
.bmPlanes
* aDDBInfo
.bmBitsPixel
;
630 DeleteObject( hNewDDB
);
636 bool WinSalBitmap::Create( const SalBitmap
& rSSalBmp
, sal_uInt16 nNewBitCount
)
640 const WinSalBitmap
& rSalBmp
= static_cast<const WinSalBitmap
&>(rSSalBmp
);
644 mhDIB
= ImplCreateDIB( rSalBmp
.maSize
, nNewBitCount
, BitmapPalette() );
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
;
671 GlobalUnlock( mhDIB
);
677 SelectPalette( hDC
, hOldPal
, TRUE
);
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
) {
697 if( args
[0] >>= aHBmp64
) {
698 return Create( HBITMAP(aHBmp64
), false, false );
705 sal_uInt16
WinSalBitmap::ImplGetDIBColorCount( HGLOBAL hDIB
)
707 sal_uInt16 nColors
= 0;
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
;
721 nColors
= 1 << pBIH
->biBitCount
;
724 else if( ( (PBITMAPCOREHEADER
) pBI
)->bcBitCount
<= 8 )
725 nColors
= 1 << ( (PBITMAPCOREHEADER
) pBI
)->bcBitCount
;
727 GlobalUnlock( hDIB
);
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!" );
739 if( rSize
.Width() <= 0 || rSize
.Height() <= 0 )
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();
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
;
756 hDIB
= GlobalAlloc( GHND
, nHeaderSize
+ nImageSize
);
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();
767 pBIH
->biBitCount
= nBits
;
768 pBIH
->biCompression
= BI_RGB
;
769 pBIH
->biSizeImage
= nImageSize
;
770 pBIH
->biXPelsPerMeter
= 0;
771 pBIH
->biYPelsPerMeter
= 0;
773 pBIH
->biClrImportant
= 0;
777 // copy the palette entries if any
778 const sal_uInt16 nMinCount
= (std::min
)( nColors
, rPal
.GetEntryCount() );
780 memcpy( pBI
->bmiColors
, rPal
.ImplGetColorBuffer(), nMinCount
* sizeof(RGBQUAD
) );
783 GlobalUnlock( hDIB
);
788 HANDLE
WinSalBitmap::ImplCopyDIBOrDDB( HANDLE hHdl
, bool bDIB
)
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
);
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
);
824 SelectObject( hBmpDC
, hBmpOld
);
832 BitmapBuffer
* WinSalBitmap::AcquireBuffer( BitmapAccessMode
/*nMode*/ )
834 BitmapBuffer
* pBuffer
= NULL
;
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() );
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
);
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
);
908 pBuffer
->maColorMask
= ColorMask( 0x00ff0000UL
, 0x0000ff00UL
, 0x000000ffUL
);
910 pBuffer
->mpBits
= (PBYTE
) pBI
+ *(DWORD
*) pBI
+ nOffset
;
913 pBuffer
->mpBits
= (PBYTE
) pBI
+ *(DWORD
*) pBI
;
917 GlobalUnlock( mhDIB
);
923 GlobalUnlock( mhDIB
);
929 void WinSalBitmap::ReleaseBuffer( BitmapBuffer
* pBuffer
, BitmapAccessMode nMode
)
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
);
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
;
963 bool bEndDecoding
= FALSE
;
970 if( ( nCountByte
= *pRLE
++ ) == 0 )
978 nCountByte
= nRunByte
>> 1UL;
980 for( i
= 0; i
< nCountByte
; i
++ )
983 ImplSetPixel4( pDIB
, nX
++, cTmp
>> 4 );
984 ImplSetPixel4( pDIB
, nX
++, cTmp
& 0x0f );
988 ImplSetPixel4( pDIB
, nX
++, *pRLE
++ >> 4 );
990 if( ( ( nRunByte
+ 1 ) >> 1 ) & 1 )
995 memcpy( &pDIB
[ nX
], pRLE
, nRunByte
);
1003 else if( !nRunByte
)
1005 pDIB
= ( pRow
+= nWidthAl
);
1008 else if( nRunByte
== 1 )
1009 bEndDecoding
= TRUE
;
1013 pDIB
= ( pRow
+= ( *pRLE
++ ) * nWidthAl
);
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 );
1035 for( i
= 0; i
< nCountByte
; i
++ )
1036 pDIB
[ nX
++ ] = cTmp
;
1040 while( !bEndDecoding
&& ( pDIB
<= pLast
) );
1044 bool WinSalBitmap::GetSystemData( BitmapSystemData
& rData
)
1047 if( mhDIB
|| mhDDB
)
1052 const Size
& rSize
= GetSize ();
1053 rData
.mnWidth
= rSize
.Width();
1054 rData
.mnHeight
= rSize
.Height();
1059 bool WinSalBitmap::Crop( const Rectangle
& /*rRectPixel*/ )
1064 bool WinSalBitmap::Erase( const ::Color
& /*rFillColor*/ )
1069 bool WinSalBitmap::Scale( const double& /*rScaleX*/, const double& /*rScaleY*/, BmpScaleFlag
/*nScaleFlag*/ )
1074 bool WinSalBitmap::Replace( const Color
& /*rSearchColor*/, const Color
& /*rReplaceColor*/, sal_uLong
/*nTol*/ )
1079 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */