bump product version to 6.4.0.3
[LibreOffice.git] / vcl / win / gdi / salbmp.cxx
blob173ea361bbe8325d81bbc4b7c7872dac0eaefab1
1 /*
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 .
19 #include <svsys.h>
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>
31 #include <string.h>
32 #include <vcl/timer.hxx>
33 #include <cppuhelper/basemutex.hxx>
34 #include <sal/log.hxx>
35 #include <tools/helpers.hxx>
36 #include <map>
38 #if defined _MSC_VER
39 #ifndef min
40 #define min(a,b) (((a) < (b)) ? (a) : (b))
41 #endif
42 #ifndef max
43 #define max(a,b) (((a) > (b)) ? (a) : (b))
44 #endif
45 #endif
47 #include <prewin.h>
48 #include <gdiplus.h>
49 #include <postwin.h>
51 #if defined _MSC_VER
52 #undef min
53 #undef max
54 #endif
56 static void ImplSetPixel4( sal_uInt8* pScanline, long nX, const BYTE cIndex )
58 BYTE& rByte = pScanline[ nX >> 1 ];
60 if ( nX & 1 )
62 rByte &= 0xf0;
63 rByte |= cIndex & 0x0f;
65 else
67 rByte &= 0x0f;
68 rByte |= cIndex << 4;
72 WinSalBitmap::WinSalBitmap()
73 : SalBitmap(),
74 basegfx::SystemDependentDataHolder(),
75 maSize(),
76 mhDIB(nullptr),
77 mhDDB(nullptr),
78 mnBitCount(0)
82 WinSalBitmap::~WinSalBitmap()
84 Destroy();
87 void WinSalBitmap::Destroy()
89 if( mhDIB )
90 GlobalFree( mhDIB );
91 else if( mhDDB )
92 DeleteObject( mhDDB );
94 maSize = Size();
95 mnBitCount = 0;
98 class SystemDependentData_GdiPlusBitmap : public basegfx::SystemDependentData
100 private:
101 std::shared_ptr<Gdiplus::Bitmap> mpGdiPlusBitmap;
102 const WinSalBitmap* mpAssociatedAlpha;
104 public:
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);
130 if(mpGdiPlusBitmap)
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:
142 nRetval /= 8;
143 break;
144 case PixelFormat4bppIndexed:
145 nRetval /= 4;
146 break;
147 case PixelFormat16bppGrayScale:
148 case PixelFormat16bppRGB555:
149 case PixelFormat16bppRGB565:
150 case PixelFormat16bppARGB1555:
151 nRetval *= 2;
152 break;
153 case PixelFormat24bppRGB:
154 nRetval *= 3;
155 break;
156 case PixelFormat32bppRGB:
157 case PixelFormat32bppARGB:
158 case PixelFormat32bppPARGB:
159 case PixelFormat32bppCMYK:
160 nRetval *= 4;
161 break;
162 case PixelFormat48bppRGB:
163 nRetval *= 6;
164 break;
165 case PixelFormat64bppARGB:
166 case PixelFormat64bppPARGB:
167 nRetval *= 8;
168 break;
169 default:
170 case PixelFormat8bppIndexed:
171 break;
176 return nRetval;
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)
203 // use from buffer
204 aRetval = pSystemDependentData_GdiPlusBitmap->getGdiPlusBitmap();
206 else if(maSize.Width() > 0 && maSize.Height() > 0)
208 // create and set data
209 const WinSalBitmap* pAssociatedAlpha(nullptr);
211 if(pAlphaSource)
213 aRetval.reset(const_cast< WinSalBitmap* >(this)->ImplCreateGdiPlusBitmap(*pAlphaSource));
214 pAssociatedAlpha = pAlphaSource;
216 else
218 aRetval.reset(const_cast< WinSalBitmap* >(this)->ImplCreateGdiPlusBitmap());
219 pAssociatedAlpha = nullptr;
222 // add to buffering mechanism
223 addOrReplaceSystemDependentData<SystemDependentData_GdiPlusBitmap>(
224 ImplGetSystemDependentDataManager(),
225 aRetval,
226 pAssociatedAlpha);
229 return aRetval;
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(
254 *pRGB,
255 aSalTwoRect,
256 ScanlineFormat::N24BitTcBgr);
258 pSalRGB->ReleaseBuffer(pRGB, BitmapAccessMode::Write);
259 pRGB = pExtraRGB.get();
262 if(pRGB
263 && pRGB->mnWidth > 0
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);
293 else
295 delete pRetval;
296 pRetval = nullptr;
300 if(pExtraRGB)
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;
305 pExtraRGB.reset();
307 else
309 pSalRGB->ReleaseBuffer(pRGB, BitmapAccessMode::Read);
312 if(pExtraWinSalRGB)
314 delete pExtraWinSalRGB;
317 return pRetval;
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(
342 *pRGB,
343 aSalTwoRect,
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(
371 *pA,
372 aSalTwoRect,
373 ScanlineFormat::N8BitPal,
374 &rTargetPalette);
376 pSalA->ReleaseBuffer(pA, BitmapAccessMode::Read);
377 pA = pExtraA.get();
380 if(pRGB
381 && pA
382 && pRGB->mnWidth > 0
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;
422 pSrcA += nExtraA;
425 pRetval->UnlockBits(&aGdiPlusBitmapData);
427 else
429 delete pRetval;
430 pRetval = nullptr;
434 if(pExtraA)
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;
439 pExtraA.reset();
441 else
443 pSalA->ReleaseBuffer(pA, BitmapAccessMode::Read);
446 if(pExtraWinSalA)
448 delete pExtraWinSalA;
451 if(pExtraRGB)
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;
456 pExtraRGB.reset();
458 else
460 pSalRGB->ReleaseBuffer(pRGB, BitmapAccessMode::Read);
463 if(pExtraWinSalRGB)
465 delete pExtraWinSalRGB;
468 return pRetval;
471 bool WinSalBitmap::Create( HANDLE hBitmap, bool bDIB, bool bCopyHandle )
473 bool bRet = TRUE;
475 if( bDIB )
476 mhDIB = static_cast<HGLOBAL>( bCopyHandle ? ImplCopyDIBOrDDB( hBitmap, true ) : hBitmap );
477 else
478 mhDDB = static_cast<HBITMAP>( bCopyHandle ? ImplCopyDIBOrDDB( hBitmap, false ) : hBitmap );
480 if( mhDIB )
482 PBITMAPINFOHEADER pBIH = static_cast<PBITMAPINFOHEADER>(GlobalLock( mhDIB ));
484 maSize = Size( pBIH->biWidth, pBIH->biHeight );
485 mnBitCount = pBIH->biBitCount;
487 if( mnBitCount )
488 mnBitCount = ( mnBitCount <= 1 ) ? 1 : ( mnBitCount <= 4 ) ? 4 : ( mnBitCount <= 8 ) ? 8 : 24;
490 GlobalUnlock( mhDIB );
492 else if( mhDDB )
494 BITMAP aDDBInfo;
496 if( GetObjectW( mhDDB, sizeof( aDDBInfo ), &aDDBInfo ) )
498 maSize = Size( aDDBInfo.bmWidth, aDDBInfo.bmHeight );
499 mnBitCount = aDDBInfo.bmPlanes * aDDBInfo.bmBitsPixel;
501 if( mnBitCount )
503 mnBitCount = ( mnBitCount <= 1 ) ? 1 :
504 ( mnBitCount <= 4 ) ? 4 :
505 ( mnBitCount <= 8 ) ? 8 : 24;
508 else
510 mhDDB = nullptr;
511 bRet = FALSE;
514 else
515 bRet = FALSE;
517 return bRet;
520 bool WinSalBitmap::Create( const Size& rSize, sal_uInt16 nBitCount, const BitmapPalette& rPal )
522 bool bRet = FALSE;
524 mhDIB = ImplCreateDIB( rSize, nBitCount, rPal );
526 if( mhDIB )
528 maSize = rSize;
529 mnBitCount = nBitCount;
530 bRet = TRUE;
533 return bRet;
536 bool WinSalBitmap::Create( const SalBitmap& rSSalBitmap )
538 bool bRet = FALSE;
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 );
546 if ( hNewHdl )
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;
556 bRet = TRUE;
560 return bRet;
563 bool WinSalBitmap::Create( const SalBitmap& rSSalBmp, SalGraphics* pSGraphics )
565 bool bRet = FALSE;
567 const WinSalBitmap& rSalBmp = static_cast<const WinSalBitmap&>(rSSalBmp);
568 WinSalGraphics* pGraphics = static_cast<WinSalGraphics*>(pSGraphics);
570 if( rSalBmp.mhDIB )
572 PBITMAPINFO pBI = static_cast<PBITMAPINFO>(GlobalLock( rSalBmp.mhDIB ));
573 HDC hDC = pGraphics->getHDC();
574 HBITMAP hNewDDB;
575 BITMAP aDDBInfo;
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 );
583 if( hNewDDB )
584 SetDIBits( hDC, hNewDDB, 0, pBI->bmiHeader.biHeight, pBits, pBI, DIB_RGB_COLORS );
586 else
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 ) )
593 mhDDB = hNewDDB;
594 maSize = Size( aDDBInfo.bmWidth, aDDBInfo.bmHeight );
595 mnBitCount = aDDBInfo.bmPlanes * aDDBInfo.bmBitsPixel;
597 bRet = TRUE;
599 else if( hNewDDB )
600 DeleteObject( hNewDDB );
603 return bRet;
606 bool WinSalBitmap::Create( const SalBitmap& rSSalBmp, sal_uInt16 nNewBitCount )
608 bool bRet = FALSE;
610 const WinSalBitmap& rSalBmp = static_cast<const WinSalBitmap&>(rSSalBmp);
612 if( rSalBmp.mhDDB )
614 mhDIB = ImplCreateDIB( rSalBmp.maSize, nNewBitCount, BitmapPalette() );
616 if( mhDIB )
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;
637 bRet = TRUE;
639 else
641 GlobalUnlock( mhDIB );
642 GlobalFree( mhDIB );
643 mhDIB = nullptr;
646 if( hOldPal )
647 SelectPalette( hDC, hOldPal, TRUE );
649 ReleaseDC( nullptr, hDC );
653 return bRet;
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 ) {
665 sal_Int64 aHBmp64;
667 if( args[0] >>= aHBmp64 ) {
668 return Create( HBITMAP(aHBmp64), false, false );
672 return false;
675 sal_uInt16 WinSalBitmap::ImplGetDIBColorCount( HGLOBAL hDIB )
677 sal_uInt16 nColors = 0;
679 if( hDIB )
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);
689 else
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 );
699 return nColors;
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 )
709 return hDIB;
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());
715 if( bOverflow )
716 return hDIB;
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;
722 if( bOverflow )
723 return hDIB;
725 hDIB = GlobalAlloc( GHND, nHeaderSize + nImageSize );
726 if( !hDIB )
727 return hDIB;
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();
735 pBIH->biPlanes = 1;
736 pBIH->biBitCount = nBits;
737 pBIH->biCompression = BI_RGB;
738 pBIH->biSizeImage = nImageSize;
739 pBIH->biXPelsPerMeter = 0;
740 pBIH->biYPelsPerMeter = 0;
741 pBIH->biClrUsed = 0;
742 pBIH->biClrImportant = 0;
744 if( nColors )
746 // copy the palette entries if any
747 const sal_uInt16 nMinCount = std::min( nColors, rPal.GetEntryCount() );
748 if( nMinCount )
749 memcpy( pBI->bmiColors, rPal.ImplGetColorBuffer(), nMinCount * sizeof(RGBQUAD) );
752 GlobalUnlock( hDIB );
754 return hDIB;
757 HANDLE WinSalBitmap::ImplCopyDIBOrDDB( HANDLE hHdl, bool bDIB )
759 HANDLE hCopy = nullptr;
761 if ( bDIB && hHdl )
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 );
773 else if ( hHdl )
775 BITMAP aBmp;
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 );
791 DeleteDC( hCopyDC );
793 SelectObject( hBmpDC, hBmpOld );
794 DeleteDC( hBmpDC );
798 return hCopy;
801 BitmapBuffer* WinSalBitmap::AcquireBuffer( BitmapAccessMode /*nMode*/ )
803 BitmapBuffer* pBuffer = nullptr;
805 if( mhDIB )
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() );
815 if( hNewDIB )
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 );
829 GlobalFree( mhDIB );
830 mhDIB = hNewDIB;
831 pBI = pNewBI;
832 pBIH = pNewBIH;
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);
887 else
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;
900 else
901 pBuffer->mpBits = reinterpret_cast<PBYTE>(pBI) + pBI->bmiHeader.biSize;
903 else
905 GlobalUnlock( mhDIB );
906 delete pBuffer;
907 pBuffer = nullptr;
910 else
911 GlobalUnlock( mhDIB );
914 return pBuffer;
917 void WinSalBitmap::ReleaseBuffer( BitmapBuffer* pBuffer, BitmapAccessMode nMode )
919 if( pBuffer )
921 if( mhDIB )
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 );
935 delete pBuffer;
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;
950 sal_uLong nRunByte;
951 sal_uLong i;
952 BYTE cTmp;
953 bool bEndDecoding = FALSE;
955 if( pRLE && pDIB )
957 sal_uLong nX = 0;
960 if( ( nCountByte = *pRLE++ ) == 0 )
962 nRunByte = *pRLE++;
964 if( nRunByte > 2 )
966 if( bRLE4 )
968 nCountByte = nRunByte >> 1;
970 for( i = 0; i < nCountByte; i++ )
972 cTmp = *pRLE++;
973 ImplSetPixel4( pDIB, nX++, cTmp >> 4 );
974 ImplSetPixel4( pDIB, nX++, cTmp & 0x0f );
977 if( nRunByte & 1 )
978 ImplSetPixel4( pDIB, nX++, *pRLE++ >> 4 );
980 if( ( ( nRunByte + 1 ) >> 1 ) & 1 )
981 pRLE++;
983 else
985 memcpy( &pDIB[ nX ], pRLE, nRunByte );
986 pRLE += nRunByte;
987 nX += nRunByte;
989 if( nRunByte & 1 )
990 pRLE++;
993 else if( !nRunByte )
995 pDIB = ( pRow += nWidthAl );
996 nX = 0;
998 else if( nRunByte == 1 )
999 bEndDecoding = TRUE;
1000 else
1002 nX += *pRLE++;
1003 pDIB = ( pRow += ( *pRLE++ ) * nWidthAl );
1006 else
1008 cTmp = *pRLE++;
1010 if( bRLE4 )
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 );
1023 else
1025 for( i = 0; i < nCountByte; i++ )
1026 pDIB[ nX++ ] = cTmp;
1030 while( !bEndDecoding && ( pDIB <= pLast ) );
1034 bool WinSalBitmap::GetSystemData( BitmapSystemData& rData )
1036 bool bRet = false;
1037 if( mhDIB || mhDDB )
1039 bRet = true;
1040 rData.pDIB = mhDIB;
1041 const Size& rSize = GetSize ();
1042 rData.mnWidth = rSize.Width();
1043 rData.mnHeight = rSize.Height();
1045 return bRet;
1048 bool WinSalBitmap::ScalingSupported() const
1050 return false;
1053 bool WinSalBitmap::Scale( const double& /*rScaleX*/, const double& /*rScaleY*/, BmpScaleFlag /*nScaleFlag*/ )
1055 return false;
1058 bool WinSalBitmap::Replace( const Color& /*rSearchColor*/, const Color& /*rReplaceColor*/, sal_uInt8 /*nTol*/ )
1060 return false;
1063 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */