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/BitmapAccessMode.hxx>
22 #include <vcl/BitmapBuffer.hxx>
23 #include <vcl/BitmapPalette.hxx>
24 #include <vcl/ColorMask.hxx>
25 #include <vcl/Scanline.hxx>
26 #include <com/sun/star/beans/XFastPropertySet.hpp>
27 #include <win/wincomp.hxx>
28 #include <win/salgdi.h>
29 #include <win/saldata.hxx>
30 #include <win/salbmp.h>
32 #include <vcl/timer.hxx>
33 #include <cppuhelper/basemutex.hxx>
34 #include <sal/log.hxx>
35 #include <tools/helpers.hxx>
40 #define min(a,b) (((a) < (b)) ? (a) : (b))
43 #define max(a,b) (((a) > (b)) ? (a) : (b))
56 static void ImplSetPixel4( sal_uInt8
* pScanline
, long nX
, const BYTE cIndex
)
58 BYTE
& rByte
= pScanline
[ nX
>> 1 ];
63 rByte
|= cIndex
& 0x0f;
72 WinSalBitmap::WinSalBitmap()
74 basegfx::SystemDependentDataHolder(),
82 WinSalBitmap::~WinSalBitmap()
87 void WinSalBitmap::Destroy()
92 DeleteObject( mhDDB
);
98 class SystemDependentData_GdiPlusBitmap
: public basegfx::SystemDependentData
101 std::shared_ptr
<Gdiplus::Bitmap
> mpGdiPlusBitmap
;
102 const WinSalBitmap
* mpAssociatedAlpha
;
105 SystemDependentData_GdiPlusBitmap(
106 basegfx::SystemDependentDataManager
& rSystemDependentDataManager
,
107 const std::shared_ptr
<Gdiplus::Bitmap
>& rGdiPlusBitmap
,
108 const WinSalBitmap
* pAssociatedAlpha
);
110 const WinSalBitmap
* getAssociatedAlpha() const { return mpAssociatedAlpha
; }
111 const std::shared_ptr
<Gdiplus::Bitmap
>& getGdiPlusBitmap() const { return mpGdiPlusBitmap
; }
113 virtual sal_Int64
estimateUsageInBytes() const override
;
116 SystemDependentData_GdiPlusBitmap::SystemDependentData_GdiPlusBitmap(
117 basegfx::SystemDependentDataManager
& rSystemDependentDataManager
,
118 const std::shared_ptr
<Gdiplus::Bitmap
>& rGdiPlusBitmap
,
119 const WinSalBitmap
* pAssociatedAlpha
)
120 : basegfx::SystemDependentData(rSystemDependentDataManager
),
121 mpGdiPlusBitmap(rGdiPlusBitmap
),
122 mpAssociatedAlpha(pAssociatedAlpha
)
126 sal_Int64
SystemDependentData_GdiPlusBitmap::estimateUsageInBytes() const
128 sal_Int64
nRetval(0);
132 const UINT
nWidth(mpGdiPlusBitmap
->GetWidth());
133 const UINT
nHeight(mpGdiPlusBitmap
->GetHeight());
135 if(0 != nWidth
&& 0 != nHeight
)
137 nRetval
= nWidth
* nHeight
;
139 switch(mpGdiPlusBitmap
->GetPixelFormat())
141 case PixelFormat1bppIndexed
:
144 case PixelFormat4bppIndexed
:
147 case PixelFormat16bppGrayScale
:
148 case PixelFormat16bppRGB555
:
149 case PixelFormat16bppRGB565
:
150 case PixelFormat16bppARGB1555
:
153 case PixelFormat24bppRGB
:
156 case PixelFormat32bppRGB
:
157 case PixelFormat32bppARGB
:
158 case PixelFormat32bppPARGB
:
159 case PixelFormat32bppCMYK
:
162 case PixelFormat48bppRGB
:
165 case PixelFormat64bppARGB
:
166 case PixelFormat64bppPARGB
:
170 case PixelFormat8bppIndexed
:
179 std::shared_ptr
< Gdiplus::Bitmap
> WinSalBitmap::ImplGetGdiPlusBitmap(const WinSalBitmap
* pAlphaSource
) const
181 std::shared_ptr
< Gdiplus::Bitmap
> aRetval
;
183 // try to access buffered data
184 std::shared_ptr
<SystemDependentData_GdiPlusBitmap
> pSystemDependentData_GdiPlusBitmap(
185 getSystemDependentData
<SystemDependentData_GdiPlusBitmap
>());
187 if(pSystemDependentData_GdiPlusBitmap
)
189 // check data validity
190 if(pSystemDependentData_GdiPlusBitmap
->getAssociatedAlpha() != pAlphaSource
191 || 0 == maSize
.Width()
192 || 0 == maSize
.Height())
194 // #122350# if associated alpha with which the GDIPlus was constructed has changed
195 // it is necessary to remove it from buffer, reset reference to it and reconstruct
196 // data invalid, forget
197 pSystemDependentData_GdiPlusBitmap
.reset();
201 if(pSystemDependentData_GdiPlusBitmap
)
204 aRetval
= pSystemDependentData_GdiPlusBitmap
->getGdiPlusBitmap();
206 else if(maSize
.Width() > 0 && maSize
.Height() > 0)
208 // create and set data
209 const WinSalBitmap
* pAssociatedAlpha(nullptr);
213 aRetval
.reset(const_cast< WinSalBitmap
* >(this)->ImplCreateGdiPlusBitmap(*pAlphaSource
));
214 pAssociatedAlpha
= pAlphaSource
;
218 aRetval
.reset(const_cast< WinSalBitmap
* >(this)->ImplCreateGdiPlusBitmap());
219 pAssociatedAlpha
= nullptr;
222 // add to buffering mechanism
223 addOrReplaceSystemDependentData
<SystemDependentData_GdiPlusBitmap
>(
224 ImplGetSystemDependentDataManager(),
232 Gdiplus::Bitmap
* WinSalBitmap::ImplCreateGdiPlusBitmap()
234 Gdiplus::Bitmap
* pRetval(nullptr);
235 WinSalBitmap
* pSalRGB
= this;
236 WinSalBitmap
* pExtraWinSalRGB
= nullptr;
238 if(!pSalRGB
->ImplGethDIB())
240 // we need DIB for success with AcquireBuffer, create a replacement WinSalBitmap
241 pExtraWinSalRGB
= new WinSalBitmap();
242 pExtraWinSalRGB
->Create(*pSalRGB
, pSalRGB
->GetBitCount());
243 pSalRGB
= pExtraWinSalRGB
;
246 BitmapBuffer
* pRGB
= pSalRGB
->AcquireBuffer(BitmapAccessMode::Read
);
247 std::unique_ptr
<BitmapBuffer
> pExtraRGB
;
249 if(pRGB
&& ScanlineFormat::N24BitTcBgr
!= RemoveScanline(pRGB
->mnFormat
))
251 // convert source bitmap to BMP_FORMAT_24BIT_TC_BGR format if not yet in that format
252 SalTwoRect
aSalTwoRect(0, 0, pRGB
->mnWidth
, pRGB
->mnHeight
, 0, 0, pRGB
->mnWidth
, pRGB
->mnHeight
);
253 pExtraRGB
= StretchAndConvert(
256 ScanlineFormat::N24BitTcBgr
);
258 pSalRGB
->ReleaseBuffer(pRGB
, BitmapAccessMode::Write
);
259 pRGB
= pExtraRGB
.get();
264 && pRGB
->mnHeight
> 0
265 && ScanlineFormat::N24BitTcBgr
== RemoveScanline(pRGB
->mnFormat
))
267 const sal_uInt32
nW(pRGB
->mnWidth
);
268 const sal_uInt32
nH(pRGB
->mnHeight
);
270 pRetval
= new Gdiplus::Bitmap(nW
, nH
, PixelFormat24bppRGB
);
272 if ( pRetval
->GetLastStatus() == Gdiplus::Ok
)
274 sal_uInt8
* pSrcRGB(pRGB
->mpBits
);
275 const sal_uInt32
nExtraRGB(pRGB
->mnScanlineSize
- (nW
* 3));
276 const bool bTopDown(pRGB
->mnFormat
& ScanlineFormat::TopDown
);
277 const Gdiplus::Rect
aAllRect(0, 0, nW
, nH
);
278 Gdiplus::BitmapData aGdiPlusBitmapData
;
279 pRetval
->LockBits(&aAllRect
, Gdiplus::ImageLockModeWrite
, PixelFormat24bppRGB
, &aGdiPlusBitmapData
);
281 // copy data to Gdiplus::Bitmap; format is BGR here in both cases, so memcpy is possible
282 for(sal_uInt32
y(0); y
< nH
; y
++)
284 const sal_uInt32
nYInsert(bTopDown
? y
: nH
- y
- 1);
285 sal_uInt8
* targetPixels
= static_cast<sal_uInt8
*>(aGdiPlusBitmapData
.Scan0
) + (nYInsert
* aGdiPlusBitmapData
.Stride
);
287 memcpy(targetPixels
, pSrcRGB
, nW
* 3);
288 pSrcRGB
+= nW
* 3 + nExtraRGB
;
291 pRetval
->UnlockBits(&aGdiPlusBitmapData
);
302 // #i123478# shockingly, BitmapBuffer does not free the memory it is controlling
303 // in its destructor, this *has to be done by hand*. Doing it here now
304 delete[] pExtraRGB
->mpBits
;
309 pSalRGB
->ReleaseBuffer(pRGB
, BitmapAccessMode::Read
);
314 delete pExtraWinSalRGB
;
320 Gdiplus::Bitmap
* WinSalBitmap::ImplCreateGdiPlusBitmap(const WinSalBitmap
& rAlphaSource
)
322 Gdiplus::Bitmap
* pRetval(nullptr);
323 WinSalBitmap
* pSalRGB
= this;
324 WinSalBitmap
* pExtraWinSalRGB
= nullptr;
326 if(!pSalRGB
->ImplGethDIB())
328 // we need DIB for success with AcquireBuffer, create a replacement WinSalBitmap
329 pExtraWinSalRGB
= new WinSalBitmap();
330 pExtraWinSalRGB
->Create(*pSalRGB
, pSalRGB
->GetBitCount());
331 pSalRGB
= pExtraWinSalRGB
;
334 BitmapBuffer
* pRGB
= pSalRGB
->AcquireBuffer(BitmapAccessMode::Read
);
335 std::unique_ptr
<BitmapBuffer
> pExtraRGB
;
337 if(pRGB
&& ScanlineFormat::N24BitTcBgr
!= RemoveScanline(pRGB
->mnFormat
))
339 // convert source bitmap to canlineFormat::N24BitTcBgr format if not yet in that format
340 SalTwoRect
aSalTwoRect(0, 0, pRGB
->mnWidth
, pRGB
->mnHeight
, 0, 0, pRGB
->mnWidth
, pRGB
->mnHeight
);
341 pExtraRGB
= StretchAndConvert(
344 ScanlineFormat::N24BitTcBgr
);
346 pSalRGB
->ReleaseBuffer(pRGB
, BitmapAccessMode::Read
);
347 pRGB
= pExtraRGB
.get();
350 WinSalBitmap
* pSalA
= const_cast< WinSalBitmap
* >(&rAlphaSource
);
351 WinSalBitmap
* pExtraWinSalA
= nullptr;
353 if(!pSalA
->ImplGethDIB())
355 // we need DIB for success with AcquireBuffer, create a replacement WinSalBitmap
356 pExtraWinSalA
= new WinSalBitmap();
357 pExtraWinSalA
->Create(*pSalA
, pSalA
->GetBitCount());
358 pSalA
= pExtraWinSalA
;
361 BitmapBuffer
* pA
= pSalA
->AcquireBuffer(BitmapAccessMode::Read
);
362 std::unique_ptr
<BitmapBuffer
> pExtraA
;
364 if(pA
&& ScanlineFormat::N8BitPal
!= RemoveScanline(pA
->mnFormat
))
366 // convert alpha bitmap to ScanlineFormat::N8BitPal format if not yet in that format
367 SalTwoRect
aSalTwoRect(0, 0, pA
->mnWidth
, pA
->mnHeight
, 0, 0, pA
->mnWidth
, pA
->mnHeight
);
368 const BitmapPalette
& rTargetPalette
= Bitmap::GetGreyPalette(256);
370 pExtraA
= StretchAndConvert(
373 ScanlineFormat::N8BitPal
,
376 pSalA
->ReleaseBuffer(pA
, BitmapAccessMode::Read
);
383 && pRGB
->mnHeight
> 0
384 && pRGB
->mnWidth
== pA
->mnWidth
385 && pRGB
->mnHeight
== pA
->mnHeight
386 && ScanlineFormat::N24BitTcBgr
== RemoveScanline(pRGB
->mnFormat
)
387 && ScanlineFormat::N8BitPal
== RemoveScanline(pA
->mnFormat
))
389 // we have alpha and bitmap in known formats, create GdiPlus Bitmap as 32bit ARGB
390 const sal_uInt32
nW(pRGB
->mnWidth
);
391 const sal_uInt32
nH(pRGB
->mnHeight
);
393 pRetval
= new Gdiplus::Bitmap(nW
, nH
, PixelFormat32bppARGB
);
395 if ( pRetval
->GetLastStatus() == Gdiplus::Ok
) // 2nd place to secure with new Gdiplus::Bitmap
397 sal_uInt8
* pSrcRGB(pRGB
->mpBits
);
398 sal_uInt8
* pSrcA(pA
->mpBits
);
399 const sal_uInt32
nExtraRGB(pRGB
->mnScanlineSize
- (nW
* 3));
400 const sal_uInt32
nExtraA(pA
->mnScanlineSize
- nW
);
401 const bool bTopDown(pRGB
->mnFormat
& ScanlineFormat::TopDown
);
402 const Gdiplus::Rect
aAllRect(0, 0, nW
, nH
);
403 Gdiplus::BitmapData aGdiPlusBitmapData
;
404 pRetval
->LockBits(&aAllRect
, Gdiplus::ImageLockModeWrite
, PixelFormat32bppARGB
, &aGdiPlusBitmapData
);
406 // copy data to Gdiplus::Bitmap; format is BGRA; need to mix BGR from Bitmap and
407 // A from alpha, so inner loop is needed (who invented BitmapEx..?)
408 for(sal_uInt32
y(0); y
< nH
; y
++)
410 const sal_uInt32
nYInsert(bTopDown
? y
: nH
- y
- 1);
411 sal_uInt8
* targetPixels
= static_cast<sal_uInt8
*>(aGdiPlusBitmapData
.Scan0
) + (nYInsert
* aGdiPlusBitmapData
.Stride
);
413 for(sal_uInt32
x(0); x
< nW
; x
++)
415 *targetPixels
++ = *pSrcRGB
++;
416 *targetPixels
++ = *pSrcRGB
++;
417 *targetPixels
++ = *pSrcRGB
++;
418 *targetPixels
++ = 0xff - *pSrcA
++;
421 pSrcRGB
+= nExtraRGB
;
425 pRetval
->UnlockBits(&aGdiPlusBitmapData
);
436 // #i123478# shockingly, BitmapBuffer does not free the memory it is controlling
437 // in its destructor, this *has to be done handish*. Doing it here now
438 delete[] pExtraA
->mpBits
;
443 pSalA
->ReleaseBuffer(pA
, BitmapAccessMode::Read
);
448 delete pExtraWinSalA
;
453 // #i123478# shockingly, BitmapBuffer does not free the memory it is controlling
454 // in its destructor, this *has to be done by hand*. Doing it here now
455 delete[] pExtraRGB
->mpBits
;
460 pSalRGB
->ReleaseBuffer(pRGB
, BitmapAccessMode::Read
);
465 delete pExtraWinSalRGB
;
471 bool WinSalBitmap::Create( HANDLE hBitmap
, bool bDIB
, bool bCopyHandle
)
476 mhDIB
= static_cast<HGLOBAL
>( bCopyHandle
? ImplCopyDIBOrDDB( hBitmap
, true ) : hBitmap
);
478 mhDDB
= static_cast<HBITMAP
>( bCopyHandle
? ImplCopyDIBOrDDB( hBitmap
, false ) : hBitmap
);
482 PBITMAPINFOHEADER pBIH
= static_cast<PBITMAPINFOHEADER
>(GlobalLock( mhDIB
));
484 maSize
= Size( pBIH
->biWidth
, pBIH
->biHeight
);
485 mnBitCount
= pBIH
->biBitCount
;
488 mnBitCount
= ( mnBitCount
<= 1 ) ? 1 : ( mnBitCount
<= 4 ) ? 4 : ( mnBitCount
<= 8 ) ? 8 : 24;
490 GlobalUnlock( mhDIB
);
496 if( GetObjectW( mhDDB
, sizeof( aDDBInfo
), &aDDBInfo
) )
498 maSize
= Size( aDDBInfo
.bmWidth
, aDDBInfo
.bmHeight
);
499 mnBitCount
= aDDBInfo
.bmPlanes
* aDDBInfo
.bmBitsPixel
;
503 mnBitCount
= ( mnBitCount
<= 1 ) ? 1 :
504 ( mnBitCount
<= 4 ) ? 4 :
505 ( mnBitCount
<= 8 ) ? 8 : 24;
520 bool WinSalBitmap::Create( const Size
& rSize
, sal_uInt16 nBitCount
, const BitmapPalette
& rPal
)
524 mhDIB
= ImplCreateDIB( rSize
, nBitCount
, rPal
);
529 mnBitCount
= nBitCount
;
536 bool WinSalBitmap::Create( const SalBitmap
& rSSalBitmap
)
539 const WinSalBitmap
& rSalBitmap
= static_cast<const WinSalBitmap
&>(rSSalBitmap
);
541 if ( rSalBitmap
.mhDIB
|| rSalBitmap
.mhDDB
)
543 HANDLE hNewHdl
= ImplCopyDIBOrDDB( rSalBitmap
.mhDIB
? rSalBitmap
.mhDIB
: rSalBitmap
.mhDDB
,
544 rSalBitmap
.mhDIB
!= nullptr );
548 if( rSalBitmap
.mhDIB
)
549 mhDIB
= static_cast<HGLOBAL
>(hNewHdl
);
550 else if( rSalBitmap
.mhDDB
)
551 mhDDB
= static_cast<HBITMAP
>(hNewHdl
);
553 maSize
= rSalBitmap
.maSize
;
554 mnBitCount
= rSalBitmap
.mnBitCount
;
563 bool WinSalBitmap::Create( const SalBitmap
& rSSalBmp
, SalGraphics
* pSGraphics
)
567 const WinSalBitmap
& rSalBmp
= static_cast<const WinSalBitmap
&>(rSSalBmp
);
568 WinSalGraphics
* pGraphics
= static_cast<WinSalGraphics
*>(pSGraphics
);
572 PBITMAPINFO pBI
= static_cast<PBITMAPINFO
>(GlobalLock( rSalBmp
.mhDIB
));
573 HDC hDC
= pGraphics
->getHDC();
576 PBYTE pBits
= reinterpret_cast<PBYTE
>(pBI
) + pBI
->bmiHeader
.biSize
+
577 ImplGetDIBColorCount( rSalBmp
.mhDIB
) * sizeof( RGBQUAD
);
579 if( pBI
->bmiHeader
.biBitCount
== 1 )
581 hNewDDB
= CreateBitmap( pBI
->bmiHeader
.biWidth
, pBI
->bmiHeader
.biHeight
, 1, 1, nullptr );
584 SetDIBits( hDC
, hNewDDB
, 0, pBI
->bmiHeader
.biHeight
, pBits
, pBI
, DIB_RGB_COLORS
);
587 hNewDDB
= CreateDIBitmap( hDC
, &pBI
->bmiHeader
, CBM_INIT
, pBits
, pBI
, DIB_RGB_COLORS
);
589 GlobalUnlock( rSalBmp
.mhDIB
);
591 if( hNewDDB
&& GetObjectW( hNewDDB
, sizeof( aDDBInfo
), &aDDBInfo
) )
594 maSize
= Size( aDDBInfo
.bmWidth
, aDDBInfo
.bmHeight
);
595 mnBitCount
= aDDBInfo
.bmPlanes
* aDDBInfo
.bmBitsPixel
;
600 DeleteObject( hNewDDB
);
606 bool WinSalBitmap::Create( const SalBitmap
& rSSalBmp
, sal_uInt16 nNewBitCount
)
610 const WinSalBitmap
& rSalBmp
= static_cast<const WinSalBitmap
&>(rSSalBmp
);
614 mhDIB
= ImplCreateDIB( rSalBmp
.maSize
, nNewBitCount
, BitmapPalette() );
618 PBITMAPINFO pBI
= static_cast<PBITMAPINFO
>(GlobalLock( mhDIB
));
619 const int nLines
= static_cast<int>(rSalBmp
.maSize
.Height());
620 HDC hDC
= GetDC( nullptr );
621 PBYTE pBits
= reinterpret_cast<PBYTE
>(pBI
) + pBI
->bmiHeader
.biSize
+
622 ImplGetDIBColorCount( mhDIB
) * sizeof( RGBQUAD
);
623 SalData
* pSalData
= GetSalData();
624 HPALETTE hOldPal
= nullptr;
626 if ( pSalData
->mhDitherPal
)
628 hOldPal
= SelectPalette( hDC
, pSalData
->mhDitherPal
, TRUE
);
629 RealizePalette( hDC
);
632 if( GetDIBits( hDC
, rSalBmp
.mhDDB
, 0, nLines
, pBits
, pBI
, DIB_RGB_COLORS
) == nLines
)
634 GlobalUnlock( mhDIB
);
635 maSize
= rSalBmp
.maSize
;
636 mnBitCount
= nNewBitCount
;
641 GlobalUnlock( mhDIB
);
647 SelectPalette( hDC
, hOldPal
, TRUE
);
649 ReleaseDC( nullptr, hDC
);
656 bool WinSalBitmap::Create( const css::uno::Reference
< css::rendering::XBitmapCanvas
>& rBitmapCanvas
, Size
& /*rSize*/, bool bMask
)
658 css::uno::Reference
< css::beans::XFastPropertySet
>
659 xFastPropertySet( rBitmapCanvas
, css::uno::UNO_QUERY
);
661 if( xFastPropertySet
.get() ) {
662 css::uno::Sequence
< css::uno::Any
> args
;
664 if( xFastPropertySet
->getFastPropertyValue(bMask
? 2 : 1) >>= args
) {
667 if( args
[0] >>= aHBmp64
) {
668 return Create( HBITMAP(aHBmp64
), false, false );
675 sal_uInt16
WinSalBitmap::ImplGetDIBColorCount( HGLOBAL hDIB
)
677 sal_uInt16 nColors
= 0;
681 PBITMAPINFO pBI
= static_cast<PBITMAPINFO
>(GlobalLock( hDIB
));
683 if ( pBI
->bmiHeader
.biSize
!= sizeof( BITMAPCOREHEADER
) )
685 if( pBI
->bmiHeader
.biBitCount
<= 8 )
687 if ( pBI
->bmiHeader
.biClrUsed
)
688 nColors
= static_cast<sal_uInt16
>(pBI
->bmiHeader
.biClrUsed
);
690 nColors
= 1 << pBI
->bmiHeader
.biBitCount
;
693 else if( reinterpret_cast<PBITMAPCOREHEADER
>(pBI
)->bcBitCount
<= 8 )
694 nColors
= 1 << reinterpret_cast<PBITMAPCOREHEADER
>(pBI
)->bcBitCount
;
696 GlobalUnlock( hDIB
);
702 HGLOBAL
WinSalBitmap::ImplCreateDIB( const Size
& rSize
, sal_uInt16 nBits
, const BitmapPalette
& rPal
)
704 SAL_WARN_IF( nBits
!= 1 && nBits
!= 4 && nBits
!= 8 && nBits
!= 24, "vcl", "Unsupported BitCount!" );
706 HGLOBAL hDIB
= nullptr;
708 if( rSize
.Width() <= 0 || rSize
.Height() <= 0 )
711 // calculate bitmap size in Bytes
712 const sal_uLong nAlignedWidth4Bytes
= AlignedWidth4Bytes( nBits
* rSize
.Width() );
713 const sal_uLong nImageSize
= nAlignedWidth4Bytes
* rSize
.Height();
714 bool bOverflow
= (nImageSize
/ nAlignedWidth4Bytes
) != static_cast<sal_uLong
>(rSize
.Height());
718 // allocate bitmap memory including header and palette
719 const sal_uInt16 nColors
= (nBits
<= 8) ? (1 << nBits
) : 0;
720 const sal_uLong nHeaderSize
= sizeof( BITMAPINFOHEADER
) + nColors
* sizeof( RGBQUAD
);
721 bOverflow
= (nHeaderSize
+ nImageSize
) < nImageSize
;
725 hDIB
= GlobalAlloc( GHND
, nHeaderSize
+ nImageSize
);
729 PBITMAPINFO pBI
= static_cast<PBITMAPINFO
>( GlobalLock( hDIB
) );
730 PBITMAPINFOHEADER pBIH
= reinterpret_cast<PBITMAPINFOHEADER
>( pBI
);
732 pBIH
->biSize
= sizeof( BITMAPINFOHEADER
);
733 pBIH
->biWidth
= rSize
.Width();
734 pBIH
->biHeight
= rSize
.Height();
736 pBIH
->biBitCount
= nBits
;
737 pBIH
->biCompression
= BI_RGB
;
738 pBIH
->biSizeImage
= nImageSize
;
739 pBIH
->biXPelsPerMeter
= 0;
740 pBIH
->biYPelsPerMeter
= 0;
742 pBIH
->biClrImportant
= 0;
746 // copy the palette entries if any
747 const sal_uInt16 nMinCount
= std::min( nColors
, rPal
.GetEntryCount() );
749 memcpy( pBI
->bmiColors
, rPal
.ImplGetColorBuffer(), nMinCount
* sizeof(RGBQUAD
) );
752 GlobalUnlock( hDIB
);
757 HANDLE
WinSalBitmap::ImplCopyDIBOrDDB( HANDLE hHdl
, bool bDIB
)
759 HANDLE hCopy
= nullptr;
763 const sal_uLong nSize
= GlobalSize( hHdl
);
765 if ( (hCopy
= GlobalAlloc( GHND
, nSize
)) != nullptr )
767 memcpy( GlobalLock( hCopy
), GlobalLock( hHdl
), nSize
);
769 GlobalUnlock( hCopy
);
770 GlobalUnlock( hHdl
);
777 // find out size of source bitmap
778 GetObjectW( hHdl
, sizeof( aBmp
), &aBmp
);
780 // create destination bitmap
781 if ( (hCopy
= CreateBitmapIndirect( &aBmp
)) != nullptr )
783 HDC hBmpDC
= CreateCompatibleDC( nullptr );
784 HBITMAP hBmpOld
= static_cast<HBITMAP
>(SelectObject( hBmpDC
, hHdl
));
785 HDC hCopyDC
= CreateCompatibleDC( hBmpDC
);
786 HBITMAP hCopyOld
= static_cast<HBITMAP
>(SelectObject( hCopyDC
, hCopy
));
788 BitBlt( hCopyDC
, 0, 0, aBmp
.bmWidth
, aBmp
.bmHeight
, hBmpDC
, 0, 0, SRCCOPY
);
790 SelectObject( hCopyDC
, hCopyOld
);
793 SelectObject( hBmpDC
, hBmpOld
);
801 BitmapBuffer
* WinSalBitmap::AcquireBuffer( BitmapAccessMode
/*nMode*/ )
803 BitmapBuffer
* pBuffer
= nullptr;
807 PBITMAPINFO pBI
= static_cast<PBITMAPINFO
>(GlobalLock( mhDIB
));
808 PBITMAPINFOHEADER pBIH
= &pBI
->bmiHeader
;
810 if( ( pBIH
->biCompression
== BI_RLE4
) || ( pBIH
->biCompression
== BI_RLE8
) )
812 Size
aSizePix( pBIH
->biWidth
, pBIH
->biHeight
);
813 HGLOBAL hNewDIB
= ImplCreateDIB( aSizePix
, pBIH
->biBitCount
, BitmapPalette() );
817 PBITMAPINFO pNewBI
= static_cast<PBITMAPINFO
>(GlobalLock( hNewDIB
));
818 PBITMAPINFOHEADER pNewBIH
= &pNewBI
->bmiHeader
;
819 const sal_uInt16 nColorCount
= ImplGetDIBColorCount( hNewDIB
);
820 const sal_uLong nOffset
= pBI
->bmiHeader
.biSize
+ nColorCount
* sizeof( RGBQUAD
);
821 BYTE
* pOldBits
= reinterpret_cast<PBYTE
>(pBI
) + nOffset
;
822 BYTE
* pNewBits
= reinterpret_cast<PBYTE
>(pNewBI
) + nOffset
;
824 memcpy( pNewBI
, pBI
, nOffset
);
825 pNewBIH
->biCompression
= 0;
826 ImplDecodeRLEBuffer( pOldBits
, pNewBits
, aSizePix
, pBIH
->biCompression
== BI_RLE4
);
828 GlobalUnlock( mhDIB
);
836 if( pBIH
->biPlanes
== 1 )
838 pBuffer
= new BitmapBuffer
;
840 pBuffer
->mnFormat
= pBIH
->biBitCount
== 1 ? ScanlineFormat::N1BitMsbPal
:
841 pBIH
->biBitCount
== 4 ? ScanlineFormat::N4BitMsnPal
:
842 pBIH
->biBitCount
== 8 ? ScanlineFormat::N8BitPal
:
843 pBIH
->biBitCount
== 24 ? ScanlineFormat::N24BitTcBgr
:
844 pBIH
->biBitCount
== 32 ? ScanlineFormat::N32BitTcMask
:
845 ScanlineFormat::NONE
;
847 if( RemoveScanline( pBuffer
->mnFormat
) != ScanlineFormat::NONE
)
849 pBuffer
->mnWidth
= maSize
.Width();
850 pBuffer
->mnHeight
= maSize
.Height();
851 pBuffer
->mnScanlineSize
= AlignedWidth4Bytes( maSize
.Width() * pBIH
->biBitCount
);
852 pBuffer
->mnBitCount
= static_cast<sal_uInt16
>(pBIH
->biBitCount
);
854 if( pBuffer
->mnBitCount
<= 8 )
856 const sal_uInt16 nPalCount
= ImplGetDIBColorCount( mhDIB
);
858 pBuffer
->maPalette
.SetEntryCount( nPalCount
);
859 memcpy( pBuffer
->maPalette
.ImplGetColorBuffer(), pBI
->bmiColors
, nPalCount
* sizeof( RGBQUAD
) );
860 pBuffer
->mpBits
= reinterpret_cast<PBYTE
>(pBI
) + pBI
->bmiHeader
.biSize
+ nPalCount
* sizeof( RGBQUAD
);
862 else if( ( pBIH
->biBitCount
== 16 ) || ( pBIH
->biBitCount
== 32 ) )
864 sal_uLong nOffset
= 0;
866 if( pBIH
->biCompression
== BI_BITFIELDS
)
868 nOffset
= 3 * sizeof( RGBQUAD
);
869 ColorMaskElement
aRedMask(*reinterpret_cast<UINT32
*>(&pBI
->bmiColors
[ 0 ]));
870 aRedMask
.CalcMaskShift();
871 ColorMaskElement
aGreenMask(*reinterpret_cast<UINT32
*>(&pBI
->bmiColors
[ 1 ]));
872 aGreenMask
.CalcMaskShift();
873 ColorMaskElement
aBlueMask(*reinterpret_cast<UINT32
*>(&pBI
->bmiColors
[ 2 ]));
874 aBlueMask
.CalcMaskShift();
875 pBuffer
->maColorMask
= ColorMask(aRedMask
, aGreenMask
, aBlueMask
);
877 else if( pBIH
->biBitCount
== 16 )
879 ColorMaskElement
aRedMask(0x00007c00UL
);
880 aRedMask
.CalcMaskShift();
881 ColorMaskElement
aGreenMask(0x000003e0UL
);
882 aGreenMask
.CalcMaskShift();
883 ColorMaskElement
aBlueMask(0x0000001fUL
);
884 aBlueMask
.CalcMaskShift();
885 pBuffer
->maColorMask
= ColorMask(aRedMask
, aGreenMask
, aBlueMask
);
889 ColorMaskElement
aRedMask(0x00ff0000UL
);
890 aRedMask
.CalcMaskShift();
891 ColorMaskElement
aGreenMask(0x0000ff00UL
);
892 aGreenMask
.CalcMaskShift();
893 ColorMaskElement
aBlueMask(0x000000ffUL
);
894 aBlueMask
.CalcMaskShift();
895 pBuffer
->maColorMask
= ColorMask(aRedMask
, aGreenMask
, aBlueMask
);
898 pBuffer
->mpBits
= reinterpret_cast<PBYTE
>(pBI
) + pBI
->bmiHeader
.biSize
+ nOffset
;
901 pBuffer
->mpBits
= reinterpret_cast<PBYTE
>(pBI
) + pBI
->bmiHeader
.biSize
;
905 GlobalUnlock( mhDIB
);
911 GlobalUnlock( mhDIB
);
917 void WinSalBitmap::ReleaseBuffer( BitmapBuffer
* pBuffer
, BitmapAccessMode nMode
)
923 if( nMode
== BitmapAccessMode::Write
&& !!pBuffer
->maPalette
)
925 PBITMAPINFO pBI
= static_cast<PBITMAPINFO
>(GlobalLock( mhDIB
));
926 const sal_uInt16 nCount
= pBuffer
->maPalette
.GetEntryCount();
927 const sal_uInt16 nDIBColorCount
= ImplGetDIBColorCount( mhDIB
);
928 memcpy( pBI
->bmiColors
, pBuffer
->maPalette
.ImplGetColorBuffer(), std::min( nDIBColorCount
, nCount
) * sizeof( RGBQUAD
) );
929 GlobalUnlock( mhDIB
);
932 GlobalUnlock( mhDIB
);
937 if( nMode
== BitmapAccessMode::Write
)
938 InvalidateChecksum();
941 void WinSalBitmap::ImplDecodeRLEBuffer( const BYTE
* pSrcBuf
, BYTE
* pDstBuf
,
942 const Size
& rSizePixel
, bool bRLE4
)
944 sal_uInt8
const * pRLE
= pSrcBuf
;
945 sal_uInt8
* pDIB
= pDstBuf
;
946 sal_uInt8
* pRow
= pDstBuf
;
947 sal_uLong nWidthAl
= AlignedWidth4Bytes( rSizePixel
.Width() * ( bRLE4
? 4UL : 8UL ) );
948 sal_uInt8
* pLast
= pDIB
+ rSizePixel
.Height() * nWidthAl
- 1;
949 sal_uLong nCountByte
;
953 bool bEndDecoding
= FALSE
;
960 if( ( nCountByte
= *pRLE
++ ) == 0 )
968 nCountByte
= nRunByte
>> 1;
970 for( i
= 0; i
< nCountByte
; i
++ )
973 ImplSetPixel4( pDIB
, nX
++, cTmp
>> 4 );
974 ImplSetPixel4( pDIB
, nX
++, cTmp
& 0x0f );
978 ImplSetPixel4( pDIB
, nX
++, *pRLE
++ >> 4 );
980 if( ( ( nRunByte
+ 1 ) >> 1 ) & 1 )
985 memcpy( &pDIB
[ nX
], pRLE
, nRunByte
);
995 pDIB
= ( pRow
+= nWidthAl
);
998 else if( nRunByte
== 1 )
1003 pDIB
= ( pRow
+= ( *pRLE
++ ) * nWidthAl
);
1012 nRunByte
= nCountByte
>> 1;
1014 for( i
= 0; i
< nRunByte
; i
++ )
1016 ImplSetPixel4( pDIB
, nX
++, cTmp
>> 4 );
1017 ImplSetPixel4( pDIB
, nX
++, cTmp
& 0x0f );
1020 if( nCountByte
& 1 )
1021 ImplSetPixel4( pDIB
, nX
++, cTmp
>> 4 );
1025 for( i
= 0; i
< nCountByte
; i
++ )
1026 pDIB
[ nX
++ ] = cTmp
;
1030 while( !bEndDecoding
&& ( pDIB
<= pLast
) );
1034 bool WinSalBitmap::GetSystemData( BitmapSystemData
& rData
)
1037 if( mhDIB
|| mhDDB
)
1041 const Size
& rSize
= GetSize ();
1042 rData
.mnWidth
= rSize
.Width();
1043 rData
.mnHeight
= rSize
.Height();
1048 bool WinSalBitmap::ScalingSupported() const
1053 bool WinSalBitmap::Scale( const double& /*rScaleX*/, const double& /*rScaleY*/, BmpScaleFlag
/*nScaleFlag*/ )
1058 bool WinSalBitmap::Replace( const Color
& /*rSearchColor*/, const Color
& /*rReplaceColor*/, sal_uInt8
/*nTol*/ )
1063 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */