2 * This file is part of the LibreOffice project.
4 * This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 * This file incorporates work covered by the following license notice:
10 * Licensed to the Apache Software Foundation (ASF) under one or more
11 * contributor license agreements. See the NOTICE file distributed
12 * with this work for additional information regarding copyright
13 * ownership. The ASF licenses this file to you under the Apache
14 * License, Version 2.0 (the "License"); you may not use this file
15 * except in compliance with the License. You may obtain a copy of
16 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <vcl/bitmap.hxx>
21 #include <vcl/salbtype.hxx>
22 #include <com/sun/star/beans/XFastPropertySet.hpp>
23 #include <win/wincomp.hxx>
24 #include <win/salgdi.h>
25 #include <win/saldata.hxx>
26 #include <win/salbmp.h>
28 #include <vcl/timer.hxx>
29 #include <cppuhelper/basemutex.hxx>
34 #define min(a,b) (((a) < (b)) ? (a) : (b))
37 #define max(a,b) (((a) > (b)) ? (a) : (b))
46 inline void ImplSetPixel4( sal_uInt8
* pScanline
, long nX
, const BYTE cIndex
)
48 BYTE
& rByte
= pScanline
[ nX
>> 1 ];
53 rByte
|= cIndex
& 0x0f;
62 // Helper class to manage Gdiplus::Bitmap instances inside of
65 typedef ::std::map
< WinSalBitmap
*, sal_uInt32
> EntryMap
;
66 static const sal_uInt32
nDefaultCycles(60);
68 class GdiPlusBuffer
: protected cppu::BaseMutex
, public Timer
82 ~GdiPlusBuffer() override
87 void addEntry(WinSalBitmap
& rEntry
)
89 ::osl::MutexGuard
aGuard(m_aMutex
);
90 EntryMap::iterator aFound
= maEntries
.find(&rEntry
);
92 if(aFound
== maEntries
.end())
99 maEntries
[&rEntry
] = nDefaultCycles
;
103 void remEntry(WinSalBitmap
& rEntry
)
105 ::osl::MutexGuard
aGuard(m_aMutex
);
106 EntryMap::iterator aFound
= maEntries
.find(&rEntry
);
108 if(aFound
!= maEntries
.end())
110 maEntries
.erase(aFound
);
112 if(maEntries
.empty())
119 void touchEntry(WinSalBitmap
& rEntry
)
121 ::osl::MutexGuard
aGuard(m_aMutex
);
122 EntryMap::iterator aFound
= maEntries
.find(&rEntry
);
124 if(aFound
!= maEntries
.end())
126 aFound
->second
= nDefaultCycles
;
131 virtual void Invoke() override
133 ::osl::MutexGuard
aGuard(m_aMutex
);
134 EntryMap::iterator
aIter(maEntries
.begin());
136 while(aIter
!= maEntries
.end())
145 EntryMap::iterator
aDelete(aIter
);
146 WinSalBitmap
* pSource
= aDelete
->first
;
148 maEntries
.erase(aDelete
);
150 if(maEntries
.empty())
155 // delete at WinSalBitmap after entry is removed; this
156 // way it would not hurt to call remEntry from there, too
157 if(pSource
->maGdiPlusBitmap
.get())
159 pSource
->maGdiPlusBitmap
.reset();
160 pSource
->mpAssociatedAlpha
= nullptr;
165 if(!maEntries
.empty())
172 // Global instance of GdiPlusBuffer which manages Gdiplus::Bitmap
175 static GdiPlusBuffer aGdiPlusBuffer
;
178 WinSalBitmap::WinSalBitmap()
183 mpAssociatedAlpha(nullptr),
188 WinSalBitmap::~WinSalBitmap()
193 void WinSalBitmap::Destroy()
195 if(maGdiPlusBitmap
.get())
197 aGdiPlusBuffer
.remEntry(*this);
203 DeleteObject( mhDDB
);
209 std::shared_ptr
< Gdiplus::Bitmap
> WinSalBitmap::ImplGetGdiPlusBitmap(const WinSalBitmap
* pAlphaSource
) const
211 WinSalBitmap
* pThat
= const_cast< WinSalBitmap
* >(this);
213 if(maGdiPlusBitmap
.get() && pAlphaSource
!= mpAssociatedAlpha
)
215 // #122350# if associated alpha with which the GDIPlus was constructed has changed
216 // it is necessary to remove it from buffer, reset reference to it and reconstruct
217 pThat
->maGdiPlusBitmap
.reset();
218 aGdiPlusBuffer
.remEntry(const_cast< WinSalBitmap
& >(*this));
221 if(maGdiPlusBitmap
.get())
223 aGdiPlusBuffer
.touchEntry(const_cast< WinSalBitmap
& >(*this));
227 if(maSize
.Width() > 0 && maSize
.Height() > 0)
231 pThat
->maGdiPlusBitmap
.reset(pThat
->ImplCreateGdiPlusBitmap(*pAlphaSource
));
232 pThat
->mpAssociatedAlpha
= pAlphaSource
;
236 pThat
->maGdiPlusBitmap
.reset(pThat
->ImplCreateGdiPlusBitmap());
237 pThat
->mpAssociatedAlpha
= nullptr;
240 if(maGdiPlusBitmap
.get())
242 aGdiPlusBuffer
.addEntry(*pThat
);
247 return maGdiPlusBitmap
;
250 Gdiplus::Bitmap
* WinSalBitmap::ImplCreateGdiPlusBitmap()
252 Gdiplus::Bitmap
* pRetval(nullptr);
253 WinSalBitmap
* pSalRGB
= this;
254 WinSalBitmap
* pExtraWinSalRGB
= nullptr;
256 if(!pSalRGB
->ImplGethDIB())
258 // we need DIB for success with AcquireBuffer, create a replacement WinSalBitmap
259 pExtraWinSalRGB
= new WinSalBitmap();
260 pExtraWinSalRGB
->Create(*pSalRGB
, pSalRGB
->GetBitCount());
261 pSalRGB
= pExtraWinSalRGB
;
264 BitmapBuffer
* pRGB
= pSalRGB
->AcquireBuffer(BitmapAccessMode::Read
);
265 BitmapBuffer
* pExtraRGB
= nullptr;
267 if(pRGB
&& ScanlineFormat::N24BitTcBgr
!= (pRGB
->mnFormat
& ~ScanlineFormat::TopDown
))
269 // convert source bitmap to BMP_FORMAT_24BIT_TC_BGR format if not yet in that format
270 SalTwoRect
aSalTwoRect(0, 0, pRGB
->mnWidth
, pRGB
->mnHeight
, 0, 0, pRGB
->mnWidth
, pRGB
->mnHeight
);
271 pExtraRGB
= StretchAndConvert(
274 ScanlineFormat::N24BitTcBgr
);
276 pSalRGB
->ReleaseBuffer(pRGB
, BitmapAccessMode::Write
);
282 && pRGB
->mnHeight
> 0
283 && ScanlineFormat::N24BitTcBgr
== (pRGB
->mnFormat
& ~ScanlineFormat::TopDown
))
285 const sal_uInt32
nW(pRGB
->mnWidth
);
286 const sal_uInt32
nH(pRGB
->mnHeight
);
288 pRetval
= new Gdiplus::Bitmap(nW
, nH
, PixelFormat24bppRGB
);
290 if ( pRetval
->GetLastStatus() == Gdiplus::Ok
)
292 sal_uInt8
* pSrcRGB(pRGB
->mpBits
);
293 const sal_uInt32
nExtraRGB(pRGB
->mnScanlineSize
- (nW
* 3));
294 const bool bTopDown(pRGB
->mnFormat
& ScanlineFormat::TopDown
);
295 const Gdiplus::Rect
aAllRect(0, 0, nW
, nH
);
296 Gdiplus::BitmapData aGdiPlusBitmapData
;
297 pRetval
->LockBits(&aAllRect
, Gdiplus::ImageLockModeWrite
, PixelFormat24bppRGB
, &aGdiPlusBitmapData
);
299 // copy data to Gdiplus::Bitmap; format is BGR here in both cases, so memcpy is possible
300 for(sal_uInt32
y(0); y
< nH
; y
++)
302 const sal_uInt32
nYInsert(bTopDown
? y
: nH
- y
- 1);
303 sal_uInt8
* targetPixels
= static_cast<sal_uInt8
*>(aGdiPlusBitmapData
.Scan0
) + (nYInsert
* aGdiPlusBitmapData
.Stride
);
305 memcpy(targetPixels
, pSrcRGB
, nW
* 3);
306 pSrcRGB
+= nW
* 3 + nExtraRGB
;
309 pRetval
->UnlockBits(&aGdiPlusBitmapData
);
320 // #i123478# shockingly, BitmapBuffer does not free the memory it is controlling
321 // in its destructor, this *has to be done handish*. Doing it here now
322 delete[] pExtraRGB
->mpBits
;
327 pSalRGB
->ReleaseBuffer(pRGB
, BitmapAccessMode::Read
);
332 delete pExtraWinSalRGB
;
338 Gdiplus::Bitmap
* WinSalBitmap::ImplCreateGdiPlusBitmap(const WinSalBitmap
& rAlphaSource
)
340 Gdiplus::Bitmap
* pRetval(nullptr);
341 WinSalBitmap
* pSalRGB
= this;
342 WinSalBitmap
* pExtraWinSalRGB
= nullptr;
344 if(!pSalRGB
->ImplGethDIB())
346 // we need DIB for success with AcquireBuffer, create a replacement WinSalBitmap
347 pExtraWinSalRGB
= new WinSalBitmap();
348 pExtraWinSalRGB
->Create(*pSalRGB
, pSalRGB
->GetBitCount());
349 pSalRGB
= pExtraWinSalRGB
;
352 BitmapBuffer
* pRGB
= pSalRGB
->AcquireBuffer(BitmapAccessMode::Read
);
353 BitmapBuffer
* pExtraRGB
= nullptr;
355 if(pRGB
&& ScanlineFormat::N24BitTcBgr
!= (pRGB
->mnFormat
& ~ScanlineFormat::TopDown
))
357 // convert source bitmap to canlineFormat::N24BitTcBgr format if not yet in that format
358 SalTwoRect
aSalTwoRect(0, 0, pRGB
->mnWidth
, pRGB
->mnHeight
, 0, 0, pRGB
->mnWidth
, pRGB
->mnHeight
);
359 pExtraRGB
= StretchAndConvert(
362 ScanlineFormat::N24BitTcBgr
);
364 pSalRGB
->ReleaseBuffer(pRGB
, BitmapAccessMode::Read
);
368 WinSalBitmap
* pSalA
= const_cast< WinSalBitmap
* >(&rAlphaSource
);
369 WinSalBitmap
* pExtraWinSalA
= nullptr;
371 if(!pSalA
->ImplGethDIB())
373 // we need DIB for success with AcquireBuffer, create a replacement WinSalBitmap
374 pExtraWinSalA
= new WinSalBitmap();
375 pExtraWinSalA
->Create(*pSalA
, pSalA
->GetBitCount());
376 pSalA
= pExtraWinSalA
;
379 BitmapBuffer
* pA
= pSalA
->AcquireBuffer(BitmapAccessMode::Read
);
380 BitmapBuffer
* pExtraA
= nullptr;
382 if(pA
&& ScanlineFormat::N8BitPal
!= (pA
->mnFormat
& ~ScanlineFormat::TopDown
))
384 // convert alpha bitmap to ScanlineFormat::N8BitPal format if not yet in that format
385 SalTwoRect
aSalTwoRect(0, 0, pA
->mnWidth
, pA
->mnHeight
, 0, 0, pA
->mnWidth
, pA
->mnHeight
);
386 const BitmapPalette
& rTargetPalette
= Bitmap::GetGreyPalette(256);
388 pExtraA
= StretchAndConvert(
391 ScanlineFormat::N8BitPal
,
394 pSalA
->ReleaseBuffer(pA
, BitmapAccessMode::Read
);
401 && pRGB
->mnHeight
> 0
402 && pRGB
->mnWidth
== pA
->mnWidth
403 && pRGB
->mnHeight
== pA
->mnHeight
404 && ScanlineFormat::N24BitTcBgr
== (pRGB
->mnFormat
& ~ScanlineFormat::TopDown
)
405 && ScanlineFormat::N8BitPal
== (pA
->mnFormat
& ~ScanlineFormat::TopDown
))
407 // we have alpha and bitmap in known formats, create GdiPlus Bitmap as 32bit ARGB
408 const sal_uInt32
nW(pRGB
->mnWidth
);
409 const sal_uInt32
nH(pRGB
->mnHeight
);
411 pRetval
= new Gdiplus::Bitmap(nW
, nH
, PixelFormat32bppARGB
);
413 if ( pRetval
->GetLastStatus() == Gdiplus::Ok
) // 2nd place to secure with new Gdiplus::Bitmap
415 sal_uInt8
* pSrcRGB(pRGB
->mpBits
);
416 sal_uInt8
* pSrcA(pA
->mpBits
);
417 const sal_uInt32
nExtraRGB(pRGB
->mnScanlineSize
- (nW
* 3));
418 const sal_uInt32
nExtraA(pA
->mnScanlineSize
- nW
);
419 const bool bTopDown(pRGB
->mnFormat
& ScanlineFormat::TopDown
);
420 const Gdiplus::Rect
aAllRect(0, 0, nW
, nH
);
421 Gdiplus::BitmapData aGdiPlusBitmapData
;
422 pRetval
->LockBits(&aAllRect
, Gdiplus::ImageLockModeWrite
, PixelFormat32bppARGB
, &aGdiPlusBitmapData
);
424 // copy data to Gdiplus::Bitmap; format is BGRA; need to mix BGR from Bitmap and
425 // A from alpha, so inner loop is needed (who invented BitmapEx..?)
426 for(sal_uInt32
y(0); y
< nH
; y
++)
428 const sal_uInt32
nYInsert(bTopDown
? y
: nH
- y
- 1);
429 sal_uInt8
* targetPixels
= static_cast<sal_uInt8
*>(aGdiPlusBitmapData
.Scan0
) + (nYInsert
* aGdiPlusBitmapData
.Stride
);
431 for(sal_uInt32
x(0); x
< nW
; x
++)
433 *targetPixels
++ = *pSrcRGB
++;
434 *targetPixels
++ = *pSrcRGB
++;
435 *targetPixels
++ = *pSrcRGB
++;
436 *targetPixels
++ = 0xff - *pSrcA
++;
439 pSrcRGB
+= nExtraRGB
;
443 pRetval
->UnlockBits(&aGdiPlusBitmapData
);
454 // #i123478# shockingly, BitmapBuffer does not free the memory it is controlling
455 // in its destructor, this *has to be done handish*. Doing it here now
456 delete[] pExtraA
->mpBits
;
461 pSalA
->ReleaseBuffer(pA
, BitmapAccessMode::Read
);
466 delete pExtraWinSalA
;
471 // #i123478# shockingly, BitmapBuffer does not free the memory it is controlling
472 // in its destructor, this *has to be done handish*. Doing it here now
473 delete[] pExtraRGB
->mpBits
;
478 pSalRGB
->ReleaseBuffer(pRGB
, BitmapAccessMode::Read
);
483 delete pExtraWinSalRGB
;
489 bool WinSalBitmap::Create( HANDLE hBitmap
, bool bDIB
, bool bCopyHandle
)
494 mhDIB
= static_cast<HGLOBAL
>( bCopyHandle
? ImplCopyDIBOrDDB( hBitmap
, true ) : hBitmap
);
496 mhDDB
= static_cast<HBITMAP
>( bCopyHandle
? ImplCopyDIBOrDDB( hBitmap
, false ) : hBitmap
);
500 PBITMAPINFOHEADER pBIH
= static_cast<PBITMAPINFOHEADER
>(GlobalLock( mhDIB
));
502 maSize
= Size( pBIH
->biWidth
, pBIH
->biHeight
);
503 mnBitCount
= pBIH
->biBitCount
;
506 mnBitCount
= ( mnBitCount
<= 1 ) ? 1 : ( mnBitCount
<= 4 ) ? 4 : ( mnBitCount
<= 8 ) ? 8 : 24;
508 GlobalUnlock( mhDIB
);
514 if( GetObjectA( mhDDB
, sizeof( BITMAP
), &aDDBInfo
) )
516 maSize
= Size( aDDBInfo
.bmWidth
, aDDBInfo
.bmHeight
);
517 mnBitCount
= aDDBInfo
.bmPlanes
* aDDBInfo
.bmBitsPixel
;
521 mnBitCount
= ( mnBitCount
<= 1 ) ? 1 :
522 ( mnBitCount
<= 4 ) ? 4 :
523 ( mnBitCount
<= 8 ) ? 8 : 24;
538 bool WinSalBitmap::Create( const Size
& rSize
, sal_uInt16 nBitCount
, const BitmapPalette
& rPal
)
542 mhDIB
= ImplCreateDIB( rSize
, nBitCount
, rPal
);
547 mnBitCount
= nBitCount
;
554 bool WinSalBitmap::Create( const SalBitmap
& rSSalBitmap
)
557 const WinSalBitmap
& rSalBitmap
= static_cast<const WinSalBitmap
&>(rSSalBitmap
);
559 if ( rSalBitmap
.mhDIB
|| rSalBitmap
.mhDDB
)
561 HANDLE hNewHdl
= ImplCopyDIBOrDDB( rSalBitmap
.mhDIB
? rSalBitmap
.mhDIB
: rSalBitmap
.mhDDB
,
562 rSalBitmap
.mhDIB
!= nullptr );
566 if( rSalBitmap
.mhDIB
)
567 mhDIB
= static_cast<HGLOBAL
>(hNewHdl
);
568 else if( rSalBitmap
.mhDDB
)
569 mhDDB
= static_cast<HBITMAP
>(hNewHdl
);
571 maSize
= rSalBitmap
.maSize
;
572 mnBitCount
= rSalBitmap
.mnBitCount
;
581 bool WinSalBitmap::Create( const SalBitmap
& rSSalBmp
, SalGraphics
* pSGraphics
)
585 const WinSalBitmap
& rSalBmp
= static_cast<const WinSalBitmap
&>(rSSalBmp
);
586 WinSalGraphics
* pGraphics
= static_cast<WinSalGraphics
*>(pSGraphics
);
590 PBITMAPINFO pBI
= static_cast<PBITMAPINFO
>(GlobalLock( rSalBmp
.mhDIB
));
591 HDC hDC
= pGraphics
->getHDC();
594 PBYTE pBits
= reinterpret_cast<PBYTE
>(pBI
) + pBI
->bmiHeader
.biSize
+
595 ImplGetDIBColorCount( rSalBmp
.mhDIB
) * sizeof( RGBQUAD
);
597 if( pBI
->bmiHeader
.biBitCount
== 1 )
599 hNewDDB
= CreateBitmap( pBI
->bmiHeader
.biWidth
, pBI
->bmiHeader
.biHeight
, 1, 1, nullptr );
602 SetDIBits( hDC
, hNewDDB
, 0, pBI
->bmiHeader
.biHeight
, pBits
, pBI
, DIB_RGB_COLORS
);
605 hNewDDB
= CreateDIBitmap( hDC
, &pBI
->bmiHeader
, CBM_INIT
, pBits
, pBI
, DIB_RGB_COLORS
);
607 GlobalUnlock( rSalBmp
.mhDIB
);
609 if( hNewDDB
&& GetObjectA( hNewDDB
, sizeof( BITMAP
), &aDDBInfo
) )
612 maSize
= Size( aDDBInfo
.bmWidth
, aDDBInfo
.bmHeight
);
613 mnBitCount
= aDDBInfo
.bmPlanes
* aDDBInfo
.bmBitsPixel
;
618 DeleteObject( hNewDDB
);
624 bool WinSalBitmap::Create( const SalBitmap
& rSSalBmp
, sal_uInt16 nNewBitCount
)
628 const WinSalBitmap
& rSalBmp
= static_cast<const WinSalBitmap
&>(rSSalBmp
);
632 mhDIB
= ImplCreateDIB( rSalBmp
.maSize
, nNewBitCount
, BitmapPalette() );
636 PBITMAPINFO pBI
= static_cast<PBITMAPINFO
>(GlobalLock( mhDIB
));
637 const int nLines
= (int) rSalBmp
.maSize
.Height();
638 HDC hDC
= GetDC( nullptr );
639 PBYTE pBits
= reinterpret_cast<PBYTE
>(pBI
) + pBI
->bmiHeader
.biSize
+
640 ImplGetDIBColorCount( mhDIB
) * sizeof( RGBQUAD
);
641 SalData
* pSalData
= GetSalData();
642 HPALETTE hOldPal
= nullptr;
644 if ( pSalData
->mhDitherPal
)
646 hOldPal
= SelectPalette( hDC
, pSalData
->mhDitherPal
, TRUE
);
647 RealizePalette( hDC
);
650 if( GetDIBits( hDC
, rSalBmp
.mhDDB
, 0, nLines
, pBits
, pBI
, DIB_RGB_COLORS
) == nLines
)
652 GlobalUnlock( mhDIB
);
653 maSize
= rSalBmp
.maSize
;
654 mnBitCount
= nNewBitCount
;
659 GlobalUnlock( mhDIB
);
665 SelectPalette( hDC
, hOldPal
, TRUE
);
667 ReleaseDC( nullptr, hDC
);
674 bool WinSalBitmap::Create( const css::uno::Reference
< css::rendering::XBitmapCanvas
>& rBitmapCanvas
, Size
& /*rSize*/, bool bMask
)
676 css::uno::Reference
< css::beans::XFastPropertySet
>
677 xFastPropertySet( rBitmapCanvas
, css::uno::UNO_QUERY
);
679 if( xFastPropertySet
.get() ) {
680 css::uno::Sequence
< css::uno::Any
> args
;
682 if( xFastPropertySet
->getFastPropertyValue(bMask
? 2 : 1) >>= args
) {
685 if( args
[0] >>= aHBmp64
) {
686 return Create( HBITMAP(aHBmp64
), false, false );
693 sal_uInt16
WinSalBitmap::ImplGetDIBColorCount( HGLOBAL hDIB
)
695 sal_uInt16 nColors
= 0;
699 PBITMAPINFO pBI
= static_cast<PBITMAPINFO
>(GlobalLock( hDIB
));
701 if ( pBI
->bmiHeader
.biSize
!= sizeof( BITMAPCOREHEADER
) )
703 if( pBI
->bmiHeader
.biBitCount
<= 8 )
705 if ( pBI
->bmiHeader
.biClrUsed
)
706 nColors
= (sal_uInt16
) pBI
->bmiHeader
.biClrUsed
;
708 nColors
= 1 << pBI
->bmiHeader
.biBitCount
;
711 else if( reinterpret_cast<PBITMAPCOREHEADER
>(pBI
)->bcBitCount
<= 8 )
712 nColors
= 1 << reinterpret_cast<PBITMAPCOREHEADER
>(pBI
)->bcBitCount
;
714 GlobalUnlock( hDIB
);
720 HGLOBAL
WinSalBitmap::ImplCreateDIB( const Size
& rSize
, sal_uInt16 nBits
, const BitmapPalette
& rPal
)
722 SAL_WARN_IF( nBits
!= 1 && nBits
!= 4 && nBits
!= 8 && nBits
!= 16 && nBits
!= 24, "vcl", "Unsupported BitCount!" );
724 HGLOBAL hDIB
= nullptr;
726 if( rSize
.Width() <= 0 || rSize
.Height() <= 0 )
729 // calculate bitmap size in Bytes
730 const sal_uLong nAlignedWidth4Bytes
= AlignedWidth4Bytes( nBits
* rSize
.Width() );
731 const sal_uLong nImageSize
= nAlignedWidth4Bytes
* rSize
.Height();
732 bool bOverflow
= (nImageSize
/ nAlignedWidth4Bytes
) != (sal_uLong
) rSize
.Height();
736 // allocate bitmap memory including header and palette
737 const sal_uInt16 nColors
= (nBits
<= 8) ? (1 << nBits
) : 0;
738 const sal_uLong nHeaderSize
= sizeof( BITMAPINFOHEADER
) + nColors
* sizeof( RGBQUAD
);
739 bOverflow
= (nHeaderSize
+ nImageSize
) < nImageSize
;
743 hDIB
= GlobalAlloc( GHND
, nHeaderSize
+ nImageSize
);
747 PBITMAPINFO pBI
= static_cast<PBITMAPINFO
>( GlobalLock( hDIB
) );
748 PBITMAPINFOHEADER pBIH
= reinterpret_cast<PBITMAPINFOHEADER
>( pBI
);
750 pBIH
->biSize
= sizeof( BITMAPINFOHEADER
);
751 pBIH
->biWidth
= rSize
.Width();
752 pBIH
->biHeight
= rSize
.Height();
754 pBIH
->biBitCount
= nBits
;
755 pBIH
->biCompression
= BI_RGB
;
756 pBIH
->biSizeImage
= nImageSize
;
757 pBIH
->biXPelsPerMeter
= 0;
758 pBIH
->biYPelsPerMeter
= 0;
760 pBIH
->biClrImportant
= 0;
764 // copy the palette entries if any
765 const sal_uInt16 nMinCount
= (std::min
)( nColors
, rPal
.GetEntryCount() );
767 memcpy( pBI
->bmiColors
, rPal
.ImplGetColorBuffer(), nMinCount
* sizeof(RGBQUAD
) );
770 GlobalUnlock( hDIB
);
775 HANDLE
WinSalBitmap::ImplCopyDIBOrDDB( HANDLE hHdl
, bool bDIB
)
777 HANDLE hCopy
= nullptr;
781 const sal_uLong nSize
= GlobalSize( hHdl
);
783 if ( (hCopy
= GlobalAlloc( GHND
, nSize
)) != nullptr )
785 memcpy( GlobalLock( hCopy
), GlobalLock( hHdl
), nSize
);
787 GlobalUnlock( hCopy
);
788 GlobalUnlock( hHdl
);
795 // find out size of source bitmap
796 GetObjectA( hHdl
, sizeof( BITMAP
), &aBmp
);
798 // create destination bitmap
799 if ( (hCopy
= CreateBitmapIndirect( &aBmp
)) != nullptr )
801 HDC hBmpDC
= CreateCompatibleDC( nullptr );
802 HBITMAP hBmpOld
= static_cast<HBITMAP
>(SelectObject( hBmpDC
, hHdl
));
803 HDC hCopyDC
= CreateCompatibleDC( hBmpDC
);
804 HBITMAP hCopyOld
= static_cast<HBITMAP
>(SelectObject( hCopyDC
, hCopy
));
806 BitBlt( hCopyDC
, 0, 0, aBmp
.bmWidth
, aBmp
.bmHeight
, hBmpDC
, 0, 0, SRCCOPY
);
808 SelectObject( hCopyDC
, hCopyOld
);
811 SelectObject( hBmpDC
, hBmpOld
);
819 BitmapBuffer
* WinSalBitmap::AcquireBuffer( BitmapAccessMode
/*nMode*/ )
821 BitmapBuffer
* pBuffer
= nullptr;
825 PBITMAPINFO pBI
= static_cast<PBITMAPINFO
>(GlobalLock( mhDIB
));
826 PBITMAPINFOHEADER pBIH
= &pBI
->bmiHeader
;
828 if( ( pBIH
->biCompression
== BI_RLE4
) || ( pBIH
->biCompression
== BI_RLE8
) )
830 Size
aSizePix( pBIH
->biWidth
, pBIH
->biHeight
);
831 HGLOBAL hNewDIB
= ImplCreateDIB( aSizePix
, pBIH
->biBitCount
, BitmapPalette() );
835 PBITMAPINFO pNewBI
= static_cast<PBITMAPINFO
>(GlobalLock( hNewDIB
));
836 PBITMAPINFOHEADER pNewBIH
= &pNewBI
->bmiHeader
;
837 const sal_uInt16 nColorCount
= ImplGetDIBColorCount( hNewDIB
);
838 const sal_uLong nOffset
= pBI
->bmiHeader
.biSize
+ nColorCount
* sizeof( RGBQUAD
);
839 BYTE
* pOldBits
= reinterpret_cast<PBYTE
>(pBI
) + nOffset
;
840 BYTE
* pNewBits
= reinterpret_cast<PBYTE
>(pNewBI
) + nOffset
;
842 memcpy( pNewBI
, pBI
, nOffset
);
843 pNewBIH
->biCompression
= 0;
844 ImplDecodeRLEBuffer( pOldBits
, pNewBits
, aSizePix
, pBIH
->biCompression
== BI_RLE4
);
846 GlobalUnlock( mhDIB
);
854 if( pBIH
->biPlanes
== 1 )
856 pBuffer
= new BitmapBuffer
;
858 pBuffer
->mnFormat
= pBIH
->biBitCount
== 1 ? ScanlineFormat::N1BitMsbPal
:
859 pBIH
->biBitCount
== 4 ? ScanlineFormat::N4BitMsnPal
:
860 pBIH
->biBitCount
== 8 ? ScanlineFormat::N8BitPal
:
861 pBIH
->biBitCount
== 16 ? ScanlineFormat::N16BitTcLsbMask
:
862 pBIH
->biBitCount
== 24 ? ScanlineFormat::N24BitTcBgr
:
863 pBIH
->biBitCount
== 32 ? ScanlineFormat::N32BitTcMask
:
864 ScanlineFormat::NONE
;
866 if( RemoveScanline( pBuffer
->mnFormat
) != ScanlineFormat::NONE
)
868 pBuffer
->mnWidth
= maSize
.Width();
869 pBuffer
->mnHeight
= maSize
.Height();
870 pBuffer
->mnScanlineSize
= AlignedWidth4Bytes( maSize
.Width() * pBIH
->biBitCount
);
871 pBuffer
->mnBitCount
= (sal_uInt16
) pBIH
->biBitCount
;
873 if( pBuffer
->mnBitCount
<= 8 )
875 const sal_uInt16 nPalCount
= ImplGetDIBColorCount( mhDIB
);
877 pBuffer
->maPalette
.SetEntryCount( nPalCount
);
878 memcpy( pBuffer
->maPalette
.ImplGetColorBuffer(), pBI
->bmiColors
, nPalCount
* sizeof( RGBQUAD
) );
879 pBuffer
->mpBits
= reinterpret_cast<PBYTE
>(pBI
) + pBI
->bmiHeader
.biSize
+ nPalCount
* sizeof( RGBQUAD
);
881 else if( ( pBIH
->biBitCount
== 16 ) || ( pBIH
->biBitCount
== 32 ) )
883 sal_uLong nOffset
= 0;
885 if( pBIH
->biCompression
== BI_BITFIELDS
)
887 nOffset
= 3 * sizeof( RGBQUAD
);
888 ColorMaskElement
aRedMask(*reinterpret_cast<UINT32
*>(&pBI
->bmiColors
[ 0 ]));
889 aRedMask
.CalcMaskShift();
890 ColorMaskElement
aGreenMask(*reinterpret_cast<UINT32
*>(&pBI
->bmiColors
[ 1 ]));
891 aGreenMask
.CalcMaskShift();
892 ColorMaskElement
aBlueMask(*reinterpret_cast<UINT32
*>(&pBI
->bmiColors
[ 2 ]));
893 aBlueMask
.CalcMaskShift();
894 pBuffer
->maColorMask
= ColorMask(aRedMask
, aGreenMask
, aBlueMask
);
896 else if( pBIH
->biBitCount
== 16 )
898 ColorMaskElement
aRedMask(0x00007c00UL
);
899 aRedMask
.CalcMaskShift();
900 ColorMaskElement
aGreenMask(0x000003e0UL
);
901 aGreenMask
.CalcMaskShift();
902 ColorMaskElement
aBlueMask(0x0000001fUL
);
903 aBlueMask
.CalcMaskShift();
904 pBuffer
->maColorMask
= ColorMask(aRedMask
, aGreenMask
, aBlueMask
);
908 ColorMaskElement
aRedMask(0x00ff0000UL
);
909 aRedMask
.CalcMaskShift();
910 ColorMaskElement
aGreenMask(0x0000ff00UL
);
911 aGreenMask
.CalcMaskShift();
912 ColorMaskElement
aBlueMask(0x000000ffUL
);
913 aBlueMask
.CalcMaskShift();
914 pBuffer
->maColorMask
= ColorMask(aRedMask
, aGreenMask
, aBlueMask
);
917 pBuffer
->mpBits
= reinterpret_cast<PBYTE
>(pBI
) + pBI
->bmiHeader
.biSize
+ nOffset
;
920 pBuffer
->mpBits
= reinterpret_cast<PBYTE
>(pBI
) + pBI
->bmiHeader
.biSize
;
924 GlobalUnlock( mhDIB
);
930 GlobalUnlock( mhDIB
);
936 void WinSalBitmap::ReleaseBuffer( BitmapBuffer
* pBuffer
, BitmapAccessMode nMode
)
942 if( nMode
== BitmapAccessMode::Write
&& !!pBuffer
->maPalette
)
944 PBITMAPINFO pBI
= static_cast<PBITMAPINFO
>(GlobalLock( mhDIB
));
945 const sal_uInt16 nCount
= pBuffer
->maPalette
.GetEntryCount();
946 const sal_uInt16 nDIBColorCount
= ImplGetDIBColorCount( mhDIB
);
947 memcpy( pBI
->bmiColors
, pBuffer
->maPalette
.ImplGetColorBuffer(), (std::min
)( nDIBColorCount
, nCount
) * sizeof( RGBQUAD
) );
948 GlobalUnlock( mhDIB
);
951 GlobalUnlock( mhDIB
);
958 void WinSalBitmap::ImplDecodeRLEBuffer( const BYTE
* pSrcBuf
, BYTE
* pDstBuf
,
959 const Size
& rSizePixel
, bool bRLE4
)
961 sal_uInt8
const * pRLE
= pSrcBuf
;
962 sal_uInt8
* pDIB
= pDstBuf
;
963 sal_uInt8
* pRow
= pDstBuf
;
964 sal_uLong nWidthAl
= AlignedWidth4Bytes( rSizePixel
.Width() * ( bRLE4
? 4UL : 8UL ) );
965 sal_uInt8
* pLast
= pDIB
+ rSizePixel
.Height() * nWidthAl
- 1;
966 sal_uLong nCountByte
;
970 bool bEndDecoding
= FALSE
;
977 if( ( nCountByte
= *pRLE
++ ) == 0 )
985 nCountByte
= nRunByte
>> 1;
987 for( i
= 0; i
< nCountByte
; i
++ )
990 ImplSetPixel4( pDIB
, nX
++, cTmp
>> 4 );
991 ImplSetPixel4( pDIB
, nX
++, cTmp
& 0x0f );
995 ImplSetPixel4( pDIB
, nX
++, *pRLE
++ >> 4 );
997 if( ( ( nRunByte
+ 1 ) >> 1 ) & 1 )
1002 memcpy( &pDIB
[ nX
], pRLE
, nRunByte
);
1010 else if( !nRunByte
)
1012 pDIB
= ( pRow
+= nWidthAl
);
1015 else if( nRunByte
== 1 )
1016 bEndDecoding
= TRUE
;
1020 pDIB
= ( pRow
+= ( *pRLE
++ ) * nWidthAl
);
1029 nRunByte
= nCountByte
>> 1;
1031 for( i
= 0; i
< nRunByte
; i
++ )
1033 ImplSetPixel4( pDIB
, nX
++, cTmp
>> 4 );
1034 ImplSetPixel4( pDIB
, nX
++, cTmp
& 0x0f );
1037 if( nCountByte
& 1 )
1038 ImplSetPixel4( pDIB
, nX
++, cTmp
>> 4 );
1042 for( i
= 0; i
< nCountByte
; i
++ )
1043 pDIB
[ nX
++ ] = cTmp
;
1047 while( !bEndDecoding
&& ( pDIB
<= pLast
) );
1051 bool WinSalBitmap::GetSystemData( BitmapSystemData
& rData
)
1054 if( mhDIB
|| mhDDB
)
1059 const Size
& rSize
= GetSize ();
1060 rData
.mnWidth
= rSize
.Width();
1061 rData
.mnHeight
= rSize
.Height();
1066 bool WinSalBitmap::ScalingSupported() const
1071 bool WinSalBitmap::Scale( const double& /*rScaleX*/, const double& /*rScaleY*/, BmpScaleFlag
/*nScaleFlag*/ )
1076 bool WinSalBitmap::Replace( const Color
& /*rSearchColor*/, const Color
& /*rReplaceColor*/, sal_uLong
/*nTol*/ )
1081 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */