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
, tools::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
);
100 class SystemDependentData_GdiPlusBitmap
: public basegfx::SystemDependentData
103 std::shared_ptr
<Gdiplus::Bitmap
> mpGdiPlusBitmap
;
104 const WinSalBitmap
* mpAssociatedAlpha
;
107 SystemDependentData_GdiPlusBitmap(
108 basegfx::SystemDependentDataManager
& rSystemDependentDataManager
,
109 const std::shared_ptr
<Gdiplus::Bitmap
>& rGdiPlusBitmap
,
110 const WinSalBitmap
* pAssociatedAlpha
);
112 const WinSalBitmap
* getAssociatedAlpha() const { return mpAssociatedAlpha
; }
113 const std::shared_ptr
<Gdiplus::Bitmap
>& getGdiPlusBitmap() const { return mpGdiPlusBitmap
; }
115 virtual sal_Int64
estimateUsageInBytes() const override
;
120 SystemDependentData_GdiPlusBitmap::SystemDependentData_GdiPlusBitmap(
121 basegfx::SystemDependentDataManager
& rSystemDependentDataManager
,
122 const std::shared_ptr
<Gdiplus::Bitmap
>& rGdiPlusBitmap
,
123 const WinSalBitmap
* pAssociatedAlpha
)
124 : basegfx::SystemDependentData(rSystemDependentDataManager
),
125 mpGdiPlusBitmap(rGdiPlusBitmap
),
126 mpAssociatedAlpha(pAssociatedAlpha
)
130 sal_Int64
SystemDependentData_GdiPlusBitmap::estimateUsageInBytes() const
132 sal_Int64
nRetval(0);
136 const UINT
nWidth(mpGdiPlusBitmap
->GetWidth());
137 const UINT
nHeight(mpGdiPlusBitmap
->GetHeight());
139 if(0 != nWidth
&& 0 != nHeight
)
141 nRetval
= nWidth
* nHeight
;
143 switch(mpGdiPlusBitmap
->GetPixelFormat())
145 case PixelFormat1bppIndexed
:
148 case PixelFormat4bppIndexed
:
151 case PixelFormat16bppGrayScale
:
152 case PixelFormat16bppRGB555
:
153 case PixelFormat16bppRGB565
:
154 case PixelFormat16bppARGB1555
:
157 case PixelFormat24bppRGB
:
160 case PixelFormat32bppRGB
:
161 case PixelFormat32bppARGB
:
162 case PixelFormat32bppPARGB
:
163 case PixelFormat32bppCMYK
:
166 case PixelFormat48bppRGB
:
169 case PixelFormat64bppARGB
:
170 case PixelFormat64bppPARGB
:
174 case PixelFormat8bppIndexed
:
183 std::shared_ptr
< Gdiplus::Bitmap
> WinSalBitmap::ImplGetGdiPlusBitmap(const WinSalBitmap
* pAlphaSource
) const
185 std::shared_ptr
< Gdiplus::Bitmap
> aRetval
;
187 // try to access buffered data
188 std::shared_ptr
<SystemDependentData_GdiPlusBitmap
> pSystemDependentData_GdiPlusBitmap(
189 getSystemDependentData
<SystemDependentData_GdiPlusBitmap
>());
191 if(pSystemDependentData_GdiPlusBitmap
)
193 // check data validity
194 if(pSystemDependentData_GdiPlusBitmap
->getAssociatedAlpha() != pAlphaSource
195 || 0 == maSize
.Width()
196 || 0 == maSize
.Height())
198 // #122350# if associated alpha with which the GDIPlus was constructed has changed
199 // it is necessary to remove it from buffer, reset reference to it and reconstruct
200 // data invalid, forget
201 pSystemDependentData_GdiPlusBitmap
.reset();
205 if(pSystemDependentData_GdiPlusBitmap
)
208 aRetval
= pSystemDependentData_GdiPlusBitmap
->getGdiPlusBitmap();
210 else if(!maSize
.IsEmpty())
212 // create and set data
213 const WinSalBitmap
* pAssociatedAlpha(nullptr);
217 aRetval
.reset(const_cast< WinSalBitmap
* >(this)->ImplCreateGdiPlusBitmap(*pAlphaSource
));
218 pAssociatedAlpha
= pAlphaSource
;
222 aRetval
.reset(const_cast< WinSalBitmap
* >(this)->ImplCreateGdiPlusBitmap());
223 pAssociatedAlpha
= nullptr;
226 // add to buffering mechanism
227 addOrReplaceSystemDependentData
<SystemDependentData_GdiPlusBitmap
>(
228 ImplGetSystemDependentDataManager(),
236 Gdiplus::Bitmap
* WinSalBitmap::ImplCreateGdiPlusBitmap()
238 Gdiplus::Bitmap
* pRetval(nullptr);
239 WinSalBitmap
* pSalRGB
= this;
240 WinSalBitmap
* pExtraWinSalRGB
= nullptr;
242 if(!pSalRGB
->ImplGethDIB())
244 // we need DIB for success with AcquireBuffer, create a replacement WinSalBitmap
245 pExtraWinSalRGB
= new WinSalBitmap();
246 pExtraWinSalRGB
->Create(*pSalRGB
, pSalRGB
->GetBitCount());
247 pSalRGB
= pExtraWinSalRGB
;
250 BitmapBuffer
* pRGB
= pSalRGB
->AcquireBuffer(BitmapAccessMode::Read
);
251 std::unique_ptr
<BitmapBuffer
> pExtraRGB
;
253 if(pRGB
&& ScanlineFormat::N24BitTcBgr
!= RemoveScanline(pRGB
->mnFormat
))
255 // convert source bitmap to BMP_FORMAT_24BIT_TC_BGR format if not yet in that format
256 SalTwoRect
aSalTwoRect(0, 0, pRGB
->mnWidth
, pRGB
->mnHeight
, 0, 0, pRGB
->mnWidth
, pRGB
->mnHeight
);
257 pExtraRGB
= StretchAndConvert(
260 ScanlineFormat::N24BitTcBgr
);
262 pSalRGB
->ReleaseBuffer(pRGB
, BitmapAccessMode::Write
);
263 pRGB
= pExtraRGB
.get();
268 && pRGB
->mnHeight
> 0
269 && ScanlineFormat::N24BitTcBgr
== RemoveScanline(pRGB
->mnFormat
))
271 const sal_uInt32
nW(pRGB
->mnWidth
);
272 const sal_uInt32
nH(pRGB
->mnHeight
);
274 pRetval
= new Gdiplus::Bitmap(nW
, nH
, PixelFormat24bppRGB
);
276 if ( pRetval
->GetLastStatus() == Gdiplus::Ok
)
278 sal_uInt8
* pSrcRGB(pRGB
->mpBits
);
279 const sal_uInt32
nExtraRGB(pRGB
->mnScanlineSize
- (nW
* 3));
280 const bool bTopDown(pRGB
->mnFormat
& ScanlineFormat::TopDown
);
281 const Gdiplus::Rect
aAllRect(0, 0, nW
, nH
);
282 Gdiplus::BitmapData aGdiPlusBitmapData
;
283 pRetval
->LockBits(&aAllRect
, Gdiplus::ImageLockModeWrite
, PixelFormat24bppRGB
, &aGdiPlusBitmapData
);
285 // copy data to Gdiplus::Bitmap; format is BGR here in both cases, so memcpy is possible
286 for(sal_uInt32
y(0); y
< nH
; y
++)
288 const sal_uInt32
nYInsert(bTopDown
? y
: nH
- y
- 1);
289 sal_uInt8
* targetPixels
= static_cast<sal_uInt8
*>(aGdiPlusBitmapData
.Scan0
) + (nYInsert
* aGdiPlusBitmapData
.Stride
);
291 memcpy(targetPixels
, pSrcRGB
, nW
* 3);
292 pSrcRGB
+= nW
* 3 + nExtraRGB
;
295 pRetval
->UnlockBits(&aGdiPlusBitmapData
);
306 // #i123478# shockingly, BitmapBuffer does not free the memory it is controlling
307 // in its destructor, this *has to be done by hand*. Doing it here now
308 delete[] pExtraRGB
->mpBits
;
313 pSalRGB
->ReleaseBuffer(pRGB
, BitmapAccessMode::Read
);
318 delete pExtraWinSalRGB
;
324 Gdiplus::Bitmap
* WinSalBitmap::ImplCreateGdiPlusBitmap(const WinSalBitmap
& rAlphaSource
)
326 Gdiplus::Bitmap
* pRetval(nullptr);
327 WinSalBitmap
* pSalRGB
= this;
328 WinSalBitmap
* pExtraWinSalRGB
= nullptr;
330 if(!pSalRGB
->ImplGethDIB())
332 // we need DIB for success with AcquireBuffer, create a replacement WinSalBitmap
333 pExtraWinSalRGB
= new WinSalBitmap();
334 pExtraWinSalRGB
->Create(*pSalRGB
, pSalRGB
->GetBitCount());
335 pSalRGB
= pExtraWinSalRGB
;
338 BitmapBuffer
* pRGB
= pSalRGB
->AcquireBuffer(BitmapAccessMode::Read
);
339 std::unique_ptr
<BitmapBuffer
> pExtraRGB
;
341 if(pRGB
&& ScanlineFormat::N24BitTcBgr
!= RemoveScanline(pRGB
->mnFormat
))
343 // convert source bitmap to canlineFormat::N24BitTcBgr format if not yet in that format
344 SalTwoRect
aSalTwoRect(0, 0, pRGB
->mnWidth
, pRGB
->mnHeight
, 0, 0, pRGB
->mnWidth
, pRGB
->mnHeight
);
345 pExtraRGB
= StretchAndConvert(
348 ScanlineFormat::N24BitTcBgr
);
350 pSalRGB
->ReleaseBuffer(pRGB
, BitmapAccessMode::Read
);
351 pRGB
= pExtraRGB
.get();
354 WinSalBitmap
* pSalA
= const_cast< WinSalBitmap
* >(&rAlphaSource
);
355 WinSalBitmap
* pExtraWinSalA
= nullptr;
357 if(!pSalA
->ImplGethDIB())
359 // we need DIB for success with AcquireBuffer, create a replacement WinSalBitmap
360 pExtraWinSalA
= new WinSalBitmap();
361 pExtraWinSalA
->Create(*pSalA
, pSalA
->GetBitCount());
362 pSalA
= pExtraWinSalA
;
365 BitmapBuffer
* pA
= pSalA
->AcquireBuffer(BitmapAccessMode::Read
);
366 std::unique_ptr
<BitmapBuffer
> pExtraA
;
368 if(pA
&& ScanlineFormat::N8BitPal
!= RemoveScanline(pA
->mnFormat
))
370 // convert alpha bitmap to ScanlineFormat::N8BitPal format if not yet in that format
371 SalTwoRect
aSalTwoRect(0, 0, pA
->mnWidth
, pA
->mnHeight
, 0, 0, pA
->mnWidth
, pA
->mnHeight
);
372 const BitmapPalette
& rTargetPalette
= Bitmap::GetGreyPalette(256);
374 pExtraA
= StretchAndConvert(
377 ScanlineFormat::N8BitPal
,
380 pSalA
->ReleaseBuffer(pA
, BitmapAccessMode::Read
);
387 && pRGB
->mnHeight
> 0
388 && pRGB
->mnWidth
== pA
->mnWidth
389 && pRGB
->mnHeight
== pA
->mnHeight
390 && ScanlineFormat::N24BitTcBgr
== RemoveScanline(pRGB
->mnFormat
)
391 && ScanlineFormat::N8BitPal
== RemoveScanline(pA
->mnFormat
))
393 // we have alpha and bitmap in known formats, create GdiPlus Bitmap as 32bit ARGB
394 const sal_uInt32
nW(pRGB
->mnWidth
);
395 const sal_uInt32
nH(pRGB
->mnHeight
);
397 pRetval
= new Gdiplus::Bitmap(nW
, nH
, PixelFormat32bppARGB
);
399 if ( pRetval
->GetLastStatus() == Gdiplus::Ok
) // 2nd place to secure with new Gdiplus::Bitmap
401 sal_uInt8
* pSrcRGB(pRGB
->mpBits
);
402 sal_uInt8
* pSrcA(pA
->mpBits
);
403 const sal_uInt32
nExtraRGB(pRGB
->mnScanlineSize
- (nW
* 3));
404 const sal_uInt32
nExtraA(pA
->mnScanlineSize
- nW
);
405 const bool bTopDown(pRGB
->mnFormat
& ScanlineFormat::TopDown
);
406 const Gdiplus::Rect
aAllRect(0, 0, nW
, nH
);
407 Gdiplus::BitmapData aGdiPlusBitmapData
;
408 pRetval
->LockBits(&aAllRect
, Gdiplus::ImageLockModeWrite
, PixelFormat32bppARGB
, &aGdiPlusBitmapData
);
410 // copy data to Gdiplus::Bitmap; format is BGRA; need to mix BGR from Bitmap and
411 // A from alpha, so inner loop is needed (who invented BitmapEx..?)
412 for(sal_uInt32
y(0); y
< nH
; y
++)
414 const sal_uInt32
nYInsert(bTopDown
? y
: nH
- y
- 1);
415 sal_uInt8
* targetPixels
= static_cast<sal_uInt8
*>(aGdiPlusBitmapData
.Scan0
) + (nYInsert
* aGdiPlusBitmapData
.Stride
);
417 for(sal_uInt32
x(0); x
< nW
; x
++)
419 *targetPixels
++ = *pSrcRGB
++;
420 *targetPixels
++ = *pSrcRGB
++;
421 *targetPixels
++ = *pSrcRGB
++;
422 *targetPixels
++ = 0xff - *pSrcA
++;
425 pSrcRGB
+= nExtraRGB
;
429 pRetval
->UnlockBits(&aGdiPlusBitmapData
);
440 // #i123478# shockingly, BitmapBuffer does not free the memory it is controlling
441 // in its destructor, this *has to be done handish*. Doing it here now
442 delete[] pExtraA
->mpBits
;
447 pSalA
->ReleaseBuffer(pA
, BitmapAccessMode::Read
);
452 delete pExtraWinSalA
;
457 // #i123478# shockingly, BitmapBuffer does not free the memory it is controlling
458 // in its destructor, this *has to be done by hand*. Doing it here now
459 delete[] pExtraRGB
->mpBits
;
464 pSalRGB
->ReleaseBuffer(pRGB
, BitmapAccessMode::Read
);
469 delete pExtraWinSalRGB
;
475 bool WinSalBitmap::Create( HANDLE hBitmap
, bool bDIB
, bool bCopyHandle
)
480 mhDIB
= static_cast<HGLOBAL
>( bCopyHandle
? ImplCopyDIBOrDDB( hBitmap
, true ) : hBitmap
);
482 mhDDB
= static_cast<HBITMAP
>( bCopyHandle
? ImplCopyDIBOrDDB( hBitmap
, false ) : hBitmap
);
486 PBITMAPINFOHEADER pBIH
= static_cast<PBITMAPINFOHEADER
>(GlobalLock( mhDIB
));
488 maSize
= Size( pBIH
->biWidth
, pBIH
->biHeight
);
489 mnBitCount
= pBIH
->biBitCount
;
492 mnBitCount
= ( mnBitCount
<= 1 ) ? 1 : ( mnBitCount
<= 4 ) ? 4 : ( mnBitCount
<= 8 ) ? 8 : 24;
494 GlobalUnlock( mhDIB
);
500 if( GetObjectW( mhDDB
, sizeof( aDDBInfo
), &aDDBInfo
) )
502 maSize
= Size( aDDBInfo
.bmWidth
, aDDBInfo
.bmHeight
);
503 mnBitCount
= aDDBInfo
.bmPlanes
* aDDBInfo
.bmBitsPixel
;
507 mnBitCount
= ( mnBitCount
<= 1 ) ? 1 :
508 ( mnBitCount
<= 4 ) ? 4 :
509 ( mnBitCount
<= 8 ) ? 8 : 24;
524 bool WinSalBitmap::Create( const Size
& rSize
, sal_uInt16 nBitCount
, const BitmapPalette
& rPal
)
528 mhDIB
= ImplCreateDIB( rSize
, nBitCount
, rPal
);
533 mnBitCount
= nBitCount
;
540 bool WinSalBitmap::Create( const SalBitmap
& rSSalBitmap
)
543 const WinSalBitmap
& rSalBitmap
= static_cast<const WinSalBitmap
&>(rSSalBitmap
);
545 if ( rSalBitmap
.mhDIB
|| rSalBitmap
.mhDDB
)
547 HANDLE hNewHdl
= ImplCopyDIBOrDDB( rSalBitmap
.mhDIB
? rSalBitmap
.mhDIB
: rSalBitmap
.mhDDB
,
548 rSalBitmap
.mhDIB
!= nullptr );
552 if( rSalBitmap
.mhDIB
)
553 mhDIB
= static_cast<HGLOBAL
>(hNewHdl
);
554 else if( rSalBitmap
.mhDDB
)
555 mhDDB
= static_cast<HBITMAP
>(hNewHdl
);
557 maSize
= rSalBitmap
.maSize
;
558 mnBitCount
= rSalBitmap
.mnBitCount
;
567 bool WinSalBitmap::Create( const SalBitmap
& rSSalBmp
, SalGraphics
* pSGraphics
)
571 const WinSalBitmap
& rSalBmp
= static_cast<const WinSalBitmap
&>(rSSalBmp
);
572 WinSalGraphics
* pGraphics
= static_cast<WinSalGraphics
*>(pSGraphics
);
576 PBITMAPINFO pBI
= static_cast<PBITMAPINFO
>(GlobalLock( rSalBmp
.mhDIB
));
577 HDC hDC
= pGraphics
->getHDC();
580 PBYTE pBits
= reinterpret_cast<PBYTE
>(pBI
) + pBI
->bmiHeader
.biSize
+
581 ImplGetDIBColorCount( rSalBmp
.mhDIB
) * sizeof( RGBQUAD
);
583 if( pBI
->bmiHeader
.biBitCount
== 1 )
585 hNewDDB
= CreateBitmap( pBI
->bmiHeader
.biWidth
, pBI
->bmiHeader
.biHeight
, 1, 1, nullptr );
588 SetDIBits( hDC
, hNewDDB
, 0, pBI
->bmiHeader
.biHeight
, pBits
, pBI
, DIB_RGB_COLORS
);
591 hNewDDB
= CreateDIBitmap( hDC
, &pBI
->bmiHeader
, CBM_INIT
, pBits
, pBI
, DIB_RGB_COLORS
);
593 GlobalUnlock( rSalBmp
.mhDIB
);
595 if( hNewDDB
&& GetObjectW( hNewDDB
, sizeof( aDDBInfo
), &aDDBInfo
) )
598 maSize
= Size( aDDBInfo
.bmWidth
, aDDBInfo
.bmHeight
);
599 mnBitCount
= aDDBInfo
.bmPlanes
* aDDBInfo
.bmBitsPixel
;
604 DeleteObject( hNewDDB
);
610 bool WinSalBitmap::Create( const SalBitmap
& rSSalBmp
, sal_uInt16 nNewBitCount
)
614 const WinSalBitmap
& rSalBmp
= static_cast<const WinSalBitmap
&>(rSSalBmp
);
618 mhDIB
= ImplCreateDIB( rSalBmp
.maSize
, nNewBitCount
, BitmapPalette() );
622 PBITMAPINFO pBI
= static_cast<PBITMAPINFO
>(GlobalLock( mhDIB
));
623 const int nLines
= static_cast<int>(rSalBmp
.maSize
.Height());
624 HDC hDC
= GetDC( nullptr );
625 PBYTE pBits
= reinterpret_cast<PBYTE
>(pBI
) + pBI
->bmiHeader
.biSize
+
626 ImplGetDIBColorCount( mhDIB
) * sizeof( RGBQUAD
);
627 SalData
* pSalData
= GetSalData();
628 HPALETTE hOldPal
= nullptr;
630 if ( pSalData
->mhDitherPal
)
632 hOldPal
= SelectPalette( hDC
, pSalData
->mhDitherPal
, TRUE
);
633 RealizePalette( hDC
);
636 if( GetDIBits( hDC
, rSalBmp
.mhDDB
, 0, nLines
, pBits
, pBI
, DIB_RGB_COLORS
) == nLines
)
638 GlobalUnlock( mhDIB
);
639 maSize
= rSalBmp
.maSize
;
640 mnBitCount
= nNewBitCount
;
645 GlobalUnlock( mhDIB
);
651 SelectPalette( hDC
, hOldPal
, TRUE
);
653 ReleaseDC( nullptr, hDC
);
660 bool WinSalBitmap::Create( const css::uno::Reference
< css::rendering::XBitmapCanvas
>& rBitmapCanvas
, Size
& /*rSize*/, bool bMask
)
662 css::uno::Reference
< css::beans::XFastPropertySet
>
663 xFastPropertySet( rBitmapCanvas
, css::uno::UNO_QUERY
);
665 if( xFastPropertySet
) {
666 css::uno::Sequence
< css::uno::Any
> args
;
668 if( xFastPropertySet
->getFastPropertyValue(bMask
? 2 : 1) >>= args
) {
671 if( args
[0] >>= aHBmp64
) {
672 return Create( reinterpret_cast<HANDLE
>(aHBmp64
), false, false );
679 sal_uInt16
WinSalBitmap::ImplGetDIBColorCount( HGLOBAL hDIB
)
681 sal_uInt16 nColors
= 0;
685 PBITMAPINFO pBI
= static_cast<PBITMAPINFO
>(GlobalLock( hDIB
));
687 if ( pBI
->bmiHeader
.biSize
!= sizeof( BITMAPCOREHEADER
) )
689 if( pBI
->bmiHeader
.biBitCount
<= 8 )
691 if ( pBI
->bmiHeader
.biClrUsed
)
692 nColors
= static_cast<sal_uInt16
>(pBI
->bmiHeader
.biClrUsed
);
694 nColors
= 1 << pBI
->bmiHeader
.biBitCount
;
697 else if( reinterpret_cast<PBITMAPCOREHEADER
>(pBI
)->bcBitCount
<= 8 )
698 nColors
= 1 << reinterpret_cast<PBITMAPCOREHEADER
>(pBI
)->bcBitCount
;
700 GlobalUnlock( hDIB
);
706 HGLOBAL
WinSalBitmap::ImplCreateDIB( const Size
& rSize
, sal_uInt16 nBits
, const BitmapPalette
& rPal
)
708 SAL_WARN_IF( nBits
!= 1 && nBits
!= 4 && nBits
!= 8 && nBits
!= 24, "vcl", "Unsupported BitCount!" );
710 HGLOBAL hDIB
= nullptr;
712 if( rSize
.IsEmpty() )
715 // calculate bitmap size in Bytes
716 const sal_uLong nAlignedWidth4Bytes
= AlignedWidth4Bytes( nBits
* rSize
.Width() );
717 const sal_uLong nImageSize
= nAlignedWidth4Bytes
* rSize
.Height();
718 bool bOverflow
= (nImageSize
/ nAlignedWidth4Bytes
) != static_cast<sal_uLong
>(rSize
.Height());
722 // allocate bitmap memory including header and palette
723 const sal_uInt16 nColors
= (nBits
<= 8) ? (1 << nBits
) : 0;
724 const sal_uLong nHeaderSize
= sizeof( BITMAPINFOHEADER
) + nColors
* sizeof( RGBQUAD
);
725 bOverflow
= (nHeaderSize
+ nImageSize
) < nImageSize
;
729 hDIB
= GlobalAlloc( GHND
, nHeaderSize
+ nImageSize
);
733 PBITMAPINFO pBI
= static_cast<PBITMAPINFO
>( GlobalLock( hDIB
) );
734 PBITMAPINFOHEADER pBIH
= reinterpret_cast<PBITMAPINFOHEADER
>( pBI
);
736 pBIH
->biSize
= sizeof( BITMAPINFOHEADER
);
737 pBIH
->biWidth
= rSize
.Width();
738 pBIH
->biHeight
= rSize
.Height();
740 pBIH
->biBitCount
= nBits
;
741 pBIH
->biCompression
= BI_RGB
;
742 pBIH
->biSizeImage
= nImageSize
;
743 pBIH
->biXPelsPerMeter
= 0;
744 pBIH
->biYPelsPerMeter
= 0;
746 pBIH
->biClrImportant
= 0;
750 // copy the palette entries if any
751 const sal_uInt16 nMinCount
= std::min( nColors
, rPal
.GetEntryCount() );
753 memcpy( pBI
->bmiColors
, rPal
.ImplGetColorBuffer(), nMinCount
* sizeof(RGBQUAD
) );
756 GlobalUnlock( hDIB
);
761 HANDLE
WinSalBitmap::ImplCopyDIBOrDDB( HANDLE hHdl
, bool bDIB
)
763 HANDLE hCopy
= nullptr;
767 const sal_uLong nSize
= GlobalSize( hHdl
);
769 if ( (hCopy
= GlobalAlloc( GHND
, nSize
)) != nullptr )
771 memcpy( GlobalLock( hCopy
), GlobalLock( hHdl
), nSize
);
773 GlobalUnlock( hCopy
);
774 GlobalUnlock( hHdl
);
781 // find out size of source bitmap
782 GetObjectW( hHdl
, sizeof( aBmp
), &aBmp
);
784 // create destination bitmap
785 if ( (hCopy
= CreateBitmapIndirect( &aBmp
)) != nullptr )
787 HDC hBmpDC
= CreateCompatibleDC( nullptr );
788 HBITMAP hBmpOld
= static_cast<HBITMAP
>(SelectObject( hBmpDC
, hHdl
));
789 HDC hCopyDC
= CreateCompatibleDC( hBmpDC
);
790 HBITMAP hCopyOld
= static_cast<HBITMAP
>(SelectObject( hCopyDC
, hCopy
));
792 BitBlt( hCopyDC
, 0, 0, aBmp
.bmWidth
, aBmp
.bmHeight
, hBmpDC
, 0, 0, SRCCOPY
);
794 SelectObject( hCopyDC
, hCopyOld
);
797 SelectObject( hBmpDC
, hBmpOld
);
805 BitmapBuffer
* WinSalBitmap::AcquireBuffer( BitmapAccessMode
/*nMode*/ )
807 BitmapBuffer
* pBuffer
= nullptr;
811 PBITMAPINFO pBI
= static_cast<PBITMAPINFO
>(GlobalLock( mhDIB
));
812 PBITMAPINFOHEADER pBIH
= &pBI
->bmiHeader
;
814 if( ( pBIH
->biCompression
== BI_RLE4
) || ( pBIH
->biCompression
== BI_RLE8
) )
816 Size
aSizePix( pBIH
->biWidth
, pBIH
->biHeight
);
817 HGLOBAL hNewDIB
= ImplCreateDIB( aSizePix
, pBIH
->biBitCount
, BitmapPalette() );
821 PBITMAPINFO pNewBI
= static_cast<PBITMAPINFO
>(GlobalLock( hNewDIB
));
822 PBITMAPINFOHEADER pNewBIH
= &pNewBI
->bmiHeader
;
823 const sal_uInt16 nColorCount
= ImplGetDIBColorCount( hNewDIB
);
824 const sal_uLong nOffset
= pBI
->bmiHeader
.biSize
+ nColorCount
* sizeof( RGBQUAD
);
825 BYTE
* pOldBits
= reinterpret_cast<PBYTE
>(pBI
) + nOffset
;
826 BYTE
* pNewBits
= reinterpret_cast<PBYTE
>(pNewBI
) + nOffset
;
828 memcpy( pNewBI
, pBI
, nOffset
);
829 pNewBIH
->biCompression
= 0;
830 ImplDecodeRLEBuffer( pOldBits
, pNewBits
, aSizePix
, pBIH
->biCompression
== BI_RLE4
);
832 GlobalUnlock( mhDIB
);
840 if( pBIH
->biPlanes
== 1 )
842 pBuffer
= new BitmapBuffer
;
844 pBuffer
->mnFormat
= pBIH
->biBitCount
== 1 ? ScanlineFormat::N1BitMsbPal
:
845 pBIH
->biBitCount
== 4 ? ScanlineFormat::N4BitMsnPal
:
846 pBIH
->biBitCount
== 8 ? ScanlineFormat::N8BitPal
:
847 pBIH
->biBitCount
== 24 ? ScanlineFormat::N24BitTcBgr
:
848 pBIH
->biBitCount
== 32 ? ScanlineFormat::N32BitTcMask
:
849 ScanlineFormat::NONE
;
851 if( RemoveScanline( pBuffer
->mnFormat
) != ScanlineFormat::NONE
)
853 pBuffer
->mnWidth
= maSize
.Width();
854 pBuffer
->mnHeight
= maSize
.Height();
855 pBuffer
->mnScanlineSize
= AlignedWidth4Bytes( maSize
.Width() * pBIH
->biBitCount
);
856 pBuffer
->mnBitCount
= static_cast<sal_uInt16
>(pBIH
->biBitCount
);
858 if( pBuffer
->mnBitCount
<= 8 )
860 const sal_uInt16 nPalCount
= ImplGetDIBColorCount( mhDIB
);
862 pBuffer
->maPalette
.SetEntryCount( nPalCount
);
863 memcpy( pBuffer
->maPalette
.ImplGetColorBuffer(), pBI
->bmiColors
, nPalCount
* sizeof( RGBQUAD
) );
864 pBuffer
->mpBits
= reinterpret_cast<PBYTE
>(pBI
) + pBI
->bmiHeader
.biSize
+ nPalCount
* sizeof( RGBQUAD
);
866 else if( ( pBIH
->biBitCount
== 16 ) || ( pBIH
->biBitCount
== 32 ) )
868 sal_uLong nOffset
= 0;
870 if( pBIH
->biCompression
== BI_BITFIELDS
)
872 nOffset
= 3 * sizeof( RGBQUAD
);
873 ColorMaskElement
aRedMask(*reinterpret_cast<UINT32
*>(&pBI
->bmiColors
[ 0 ]));
874 aRedMask
.CalcMaskShift();
875 ColorMaskElement
aGreenMask(*reinterpret_cast<UINT32
*>(&pBI
->bmiColors
[ 1 ]));
876 aGreenMask
.CalcMaskShift();
877 ColorMaskElement
aBlueMask(*reinterpret_cast<UINT32
*>(&pBI
->bmiColors
[ 2 ]));
878 aBlueMask
.CalcMaskShift();
879 pBuffer
->maColorMask
= ColorMask(aRedMask
, aGreenMask
, aBlueMask
);
881 else if( pBIH
->biBitCount
== 16 )
883 ColorMaskElement
aRedMask(0x00007c00UL
);
884 aRedMask
.CalcMaskShift();
885 ColorMaskElement
aGreenMask(0x000003e0UL
);
886 aGreenMask
.CalcMaskShift();
887 ColorMaskElement
aBlueMask(0x0000001fUL
);
888 aBlueMask
.CalcMaskShift();
889 pBuffer
->maColorMask
= ColorMask(aRedMask
, aGreenMask
, aBlueMask
);
893 ColorMaskElement
aRedMask(0x00ff0000UL
);
894 aRedMask
.CalcMaskShift();
895 ColorMaskElement
aGreenMask(0x0000ff00UL
);
896 aGreenMask
.CalcMaskShift();
897 ColorMaskElement
aBlueMask(0x000000ffUL
);
898 aBlueMask
.CalcMaskShift();
899 pBuffer
->maColorMask
= ColorMask(aRedMask
, aGreenMask
, aBlueMask
);
902 pBuffer
->mpBits
= reinterpret_cast<PBYTE
>(pBI
) + pBI
->bmiHeader
.biSize
+ nOffset
;
905 pBuffer
->mpBits
= reinterpret_cast<PBYTE
>(pBI
) + pBI
->bmiHeader
.biSize
;
909 GlobalUnlock( mhDIB
);
915 GlobalUnlock( mhDIB
);
921 void WinSalBitmap::ReleaseBuffer( BitmapBuffer
* pBuffer
, BitmapAccessMode nMode
)
927 if( nMode
== BitmapAccessMode::Write
&& !!pBuffer
->maPalette
)
929 PBITMAPINFO pBI
= static_cast<PBITMAPINFO
>(GlobalLock( mhDIB
));
930 const sal_uInt16 nCount
= pBuffer
->maPalette
.GetEntryCount();
931 const sal_uInt16 nDIBColorCount
= ImplGetDIBColorCount( mhDIB
);
932 memcpy( pBI
->bmiColors
, pBuffer
->maPalette
.ImplGetColorBuffer(), std::min( nDIBColorCount
, nCount
) * sizeof( RGBQUAD
) );
933 GlobalUnlock( mhDIB
);
936 GlobalUnlock( mhDIB
);
941 if( nMode
== BitmapAccessMode::Write
)
942 InvalidateChecksum();
945 void WinSalBitmap::ImplDecodeRLEBuffer( const BYTE
* pSrcBuf
, BYTE
* pDstBuf
,
946 const Size
& rSizePixel
, bool bRLE4
)
948 sal_uInt8
const * pRLE
= pSrcBuf
;
949 sal_uInt8
* pDIB
= pDstBuf
;
950 sal_uInt8
* pRow
= pDstBuf
;
951 sal_uLong nWidthAl
= AlignedWidth4Bytes( rSizePixel
.Width() * ( bRLE4
? 4UL : 8UL ) );
952 sal_uInt8
* pLast
= pDIB
+ rSizePixel
.Height() * nWidthAl
- 1;
953 sal_uLong nCountByte
;
957 bool bEndDecoding
= false;
964 if( ( nCountByte
= *pRLE
++ ) == 0 )
972 nCountByte
= nRunByte
>> 1;
974 for( i
= 0; i
< nCountByte
; i
++ )
977 ImplSetPixel4( pDIB
, nX
++, cTmp
>> 4 );
978 ImplSetPixel4( pDIB
, nX
++, cTmp
& 0x0f );
982 ImplSetPixel4( pDIB
, nX
++, *pRLE
++ >> 4 );
984 if( ( ( nRunByte
+ 1 ) >> 1 ) & 1 )
989 memcpy( &pDIB
[ nX
], pRLE
, nRunByte
);
999 pDIB
= ( pRow
+= nWidthAl
);
1002 else if( nRunByte
== 1 )
1003 bEndDecoding
= true;
1007 pDIB
= ( pRow
+= ( *pRLE
++ ) * nWidthAl
);
1016 nRunByte
= nCountByte
>> 1;
1018 for( i
= 0; i
< nRunByte
; i
++ )
1020 ImplSetPixel4( pDIB
, nX
++, cTmp
>> 4 );
1021 ImplSetPixel4( pDIB
, nX
++, cTmp
& 0x0f );
1024 if( nCountByte
& 1 )
1025 ImplSetPixel4( pDIB
, nX
++, cTmp
>> 4 );
1029 for( i
= 0; i
< nCountByte
; i
++ )
1030 pDIB
[ nX
++ ] = cTmp
;
1034 while( !bEndDecoding
&& ( pDIB
<= pLast
) );
1038 bool WinSalBitmap::GetSystemData( BitmapSystemData
& rData
)
1041 if( mhDIB
|| mhDDB
)
1045 const Size
& rSize
= GetSize ();
1046 rData
.mnWidth
= rSize
.Width();
1047 rData
.mnHeight
= rSize
.Height();
1052 bool WinSalBitmap::ScalingSupported() const
1057 bool WinSalBitmap::Scale( const double& /*rScaleX*/, const double& /*rScaleY*/, BmpScaleFlag
/*nScaleFlag*/ )
1062 bool WinSalBitmap::Replace( const Color
& /*rSearchColor*/, const Color
& /*rReplaceColor*/, sal_uInt8
/*nTol*/ )
1067 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */