Version 7.1.7.1, tag libreoffice-7.1.7.1
[LibreOffice.git] / vcl / win / gdi / salbmp.cxx
blob2418c10a17705c656eae7165efac02aa2eb81f10
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, tools::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 namespace {
100 class SystemDependentData_GdiPlusBitmap : public basegfx::SystemDependentData
102 private:
103 std::shared_ptr<Gdiplus::Bitmap> mpGdiPlusBitmap;
104 const WinSalBitmap* mpAssociatedAlpha;
106 public:
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);
134 if(mpGdiPlusBitmap)
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:
146 nRetval /= 8;
147 break;
148 case PixelFormat4bppIndexed:
149 nRetval /= 4;
150 break;
151 case PixelFormat16bppGrayScale:
152 case PixelFormat16bppRGB555:
153 case PixelFormat16bppRGB565:
154 case PixelFormat16bppARGB1555:
155 nRetval *= 2;
156 break;
157 case PixelFormat24bppRGB:
158 nRetval *= 3;
159 break;
160 case PixelFormat32bppRGB:
161 case PixelFormat32bppARGB:
162 case PixelFormat32bppPARGB:
163 case PixelFormat32bppCMYK:
164 nRetval *= 4;
165 break;
166 case PixelFormat48bppRGB:
167 nRetval *= 6;
168 break;
169 case PixelFormat64bppARGB:
170 case PixelFormat64bppPARGB:
171 nRetval *= 8;
172 break;
173 default:
174 case PixelFormat8bppIndexed:
175 break;
180 return nRetval;
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)
207 // use from buffer
208 aRetval = pSystemDependentData_GdiPlusBitmap->getGdiPlusBitmap();
210 else if(!maSize.IsEmpty())
212 // create and set data
213 const WinSalBitmap* pAssociatedAlpha(nullptr);
215 if(pAlphaSource)
217 aRetval.reset(const_cast< WinSalBitmap* >(this)->ImplCreateGdiPlusBitmap(*pAlphaSource));
218 pAssociatedAlpha = pAlphaSource;
220 else
222 aRetval.reset(const_cast< WinSalBitmap* >(this)->ImplCreateGdiPlusBitmap());
223 pAssociatedAlpha = nullptr;
226 // add to buffering mechanism
227 addOrReplaceSystemDependentData<SystemDependentData_GdiPlusBitmap>(
228 ImplGetSystemDependentDataManager(),
229 aRetval,
230 pAssociatedAlpha);
233 return aRetval;
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(
258 *pRGB,
259 aSalTwoRect,
260 ScanlineFormat::N24BitTcBgr);
262 pSalRGB->ReleaseBuffer(pRGB, BitmapAccessMode::Write);
263 pRGB = pExtraRGB.get();
266 if(pRGB
267 && pRGB->mnWidth > 0
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);
297 else
299 delete pRetval;
300 pRetval = nullptr;
304 if(pExtraRGB)
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;
309 pExtraRGB.reset();
311 else
313 pSalRGB->ReleaseBuffer(pRGB, BitmapAccessMode::Read);
316 if(pExtraWinSalRGB)
318 delete pExtraWinSalRGB;
321 return pRetval;
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(
346 *pRGB,
347 aSalTwoRect,
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(
375 *pA,
376 aSalTwoRect,
377 ScanlineFormat::N8BitPal,
378 &rTargetPalette);
380 pSalA->ReleaseBuffer(pA, BitmapAccessMode::Read);
381 pA = pExtraA.get();
384 if(pRGB
385 && pA
386 && pRGB->mnWidth > 0
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;
426 pSrcA += nExtraA;
429 pRetval->UnlockBits(&aGdiPlusBitmapData);
431 else
433 delete pRetval;
434 pRetval = nullptr;
438 if(pExtraA)
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;
443 pExtraA.reset();
445 else
447 pSalA->ReleaseBuffer(pA, BitmapAccessMode::Read);
450 if(pExtraWinSalA)
452 delete pExtraWinSalA;
455 if(pExtraRGB)
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;
460 pExtraRGB.reset();
462 else
464 pSalRGB->ReleaseBuffer(pRGB, BitmapAccessMode::Read);
467 if(pExtraWinSalRGB)
469 delete pExtraWinSalRGB;
472 return pRetval;
475 bool WinSalBitmap::Create( HANDLE hBitmap, bool bDIB, bool bCopyHandle )
477 bool bRet = true;
479 if( bDIB )
480 mhDIB = static_cast<HGLOBAL>( bCopyHandle ? ImplCopyDIBOrDDB( hBitmap, true ) : hBitmap );
481 else
482 mhDDB = static_cast<HBITMAP>( bCopyHandle ? ImplCopyDIBOrDDB( hBitmap, false ) : hBitmap );
484 if( mhDIB )
486 PBITMAPINFOHEADER pBIH = static_cast<PBITMAPINFOHEADER>(GlobalLock( mhDIB ));
488 maSize = Size( pBIH->biWidth, pBIH->biHeight );
489 mnBitCount = pBIH->biBitCount;
491 if( mnBitCount )
492 mnBitCount = ( mnBitCount <= 1 ) ? 1 : ( mnBitCount <= 4 ) ? 4 : ( mnBitCount <= 8 ) ? 8 : 24;
494 GlobalUnlock( mhDIB );
496 else if( mhDDB )
498 BITMAP aDDBInfo;
500 if( GetObjectW( mhDDB, sizeof( aDDBInfo ), &aDDBInfo ) )
502 maSize = Size( aDDBInfo.bmWidth, aDDBInfo.bmHeight );
503 mnBitCount = aDDBInfo.bmPlanes * aDDBInfo.bmBitsPixel;
505 if( mnBitCount )
507 mnBitCount = ( mnBitCount <= 1 ) ? 1 :
508 ( mnBitCount <= 4 ) ? 4 :
509 ( mnBitCount <= 8 ) ? 8 : 24;
512 else
514 mhDDB = nullptr;
515 bRet = false;
518 else
519 bRet = false;
521 return bRet;
524 bool WinSalBitmap::Create( const Size& rSize, sal_uInt16 nBitCount, const BitmapPalette& rPal )
526 bool bRet = false;
528 mhDIB = ImplCreateDIB( rSize, nBitCount, rPal );
530 if( mhDIB )
532 maSize = rSize;
533 mnBitCount = nBitCount;
534 bRet = true;
537 return bRet;
540 bool WinSalBitmap::Create( const SalBitmap& rSSalBitmap )
542 bool bRet = false;
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 );
550 if ( hNewHdl )
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;
560 bRet = true;
564 return bRet;
567 bool WinSalBitmap::Create( const SalBitmap& rSSalBmp, SalGraphics* pSGraphics )
569 bool bRet = false;
571 const WinSalBitmap& rSalBmp = static_cast<const WinSalBitmap&>(rSSalBmp);
572 WinSalGraphics* pGraphics = static_cast<WinSalGraphics*>(pSGraphics);
574 if( rSalBmp.mhDIB )
576 PBITMAPINFO pBI = static_cast<PBITMAPINFO>(GlobalLock( rSalBmp.mhDIB ));
577 HDC hDC = pGraphics->getHDC();
578 HBITMAP hNewDDB;
579 BITMAP aDDBInfo;
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 );
587 if( hNewDDB )
588 SetDIBits( hDC, hNewDDB, 0, pBI->bmiHeader.biHeight, pBits, pBI, DIB_RGB_COLORS );
590 else
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 ) )
597 mhDDB = hNewDDB;
598 maSize = Size( aDDBInfo.bmWidth, aDDBInfo.bmHeight );
599 mnBitCount = aDDBInfo.bmPlanes * aDDBInfo.bmBitsPixel;
601 bRet = true;
603 else if( hNewDDB )
604 DeleteObject( hNewDDB );
607 return bRet;
610 bool WinSalBitmap::Create( const SalBitmap& rSSalBmp, sal_uInt16 nNewBitCount )
612 bool bRet = false;
614 const WinSalBitmap& rSalBmp = static_cast<const WinSalBitmap&>(rSSalBmp);
616 if( rSalBmp.mhDDB )
618 mhDIB = ImplCreateDIB( rSalBmp.maSize, nNewBitCount, BitmapPalette() );
620 if( mhDIB )
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;
641 bRet = true;
643 else
645 GlobalUnlock( mhDIB );
646 GlobalFree( mhDIB );
647 mhDIB = nullptr;
650 if( hOldPal )
651 SelectPalette( hDC, hOldPal, TRUE );
653 ReleaseDC( nullptr, hDC );
657 return bRet;
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 ) {
669 sal_Int64 aHBmp64;
671 if( args[0] >>= aHBmp64 ) {
672 return Create( reinterpret_cast<HANDLE>(aHBmp64), false, false );
676 return false;
679 sal_uInt16 WinSalBitmap::ImplGetDIBColorCount( HGLOBAL hDIB )
681 sal_uInt16 nColors = 0;
683 if( hDIB )
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);
693 else
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 );
703 return nColors;
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() )
713 return hDIB;
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());
719 if( bOverflow )
720 return hDIB;
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;
726 if( bOverflow )
727 return hDIB;
729 hDIB = GlobalAlloc( GHND, nHeaderSize + nImageSize );
730 if( !hDIB )
731 return hDIB;
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();
739 pBIH->biPlanes = 1;
740 pBIH->biBitCount = nBits;
741 pBIH->biCompression = BI_RGB;
742 pBIH->biSizeImage = nImageSize;
743 pBIH->biXPelsPerMeter = 0;
744 pBIH->biYPelsPerMeter = 0;
745 pBIH->biClrUsed = 0;
746 pBIH->biClrImportant = 0;
748 if( nColors )
750 // copy the palette entries if any
751 const sal_uInt16 nMinCount = std::min( nColors, rPal.GetEntryCount() );
752 if( nMinCount )
753 memcpy( pBI->bmiColors, rPal.ImplGetColorBuffer(), nMinCount * sizeof(RGBQUAD) );
756 GlobalUnlock( hDIB );
758 return hDIB;
761 HANDLE WinSalBitmap::ImplCopyDIBOrDDB( HANDLE hHdl, bool bDIB )
763 HANDLE hCopy = nullptr;
765 if ( bDIB && hHdl )
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 );
777 else if ( hHdl )
779 BITMAP aBmp;
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 );
795 DeleteDC( hCopyDC );
797 SelectObject( hBmpDC, hBmpOld );
798 DeleteDC( hBmpDC );
802 return hCopy;
805 BitmapBuffer* WinSalBitmap::AcquireBuffer( BitmapAccessMode /*nMode*/ )
807 BitmapBuffer* pBuffer = nullptr;
809 if( mhDIB )
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() );
819 if( hNewDIB )
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 );
833 GlobalFree( mhDIB );
834 mhDIB = hNewDIB;
835 pBI = pNewBI;
836 pBIH = pNewBIH;
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);
891 else
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;
904 else
905 pBuffer->mpBits = reinterpret_cast<PBYTE>(pBI) + pBI->bmiHeader.biSize;
907 else
909 GlobalUnlock( mhDIB );
910 delete pBuffer;
911 pBuffer = nullptr;
914 else
915 GlobalUnlock( mhDIB );
918 return pBuffer;
921 void WinSalBitmap::ReleaseBuffer( BitmapBuffer* pBuffer, BitmapAccessMode nMode )
923 if( pBuffer )
925 if( mhDIB )
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 );
939 delete pBuffer;
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;
954 sal_uLong nRunByte;
955 sal_uLong i;
956 BYTE cTmp;
957 bool bEndDecoding = false;
959 if( pRLE && pDIB )
961 sal_uLong nX = 0;
964 if( ( nCountByte = *pRLE++ ) == 0 )
966 nRunByte = *pRLE++;
968 if( nRunByte > 2 )
970 if( bRLE4 )
972 nCountByte = nRunByte >> 1;
974 for( i = 0; i < nCountByte; i++ )
976 cTmp = *pRLE++;
977 ImplSetPixel4( pDIB, nX++, cTmp >> 4 );
978 ImplSetPixel4( pDIB, nX++, cTmp & 0x0f );
981 if( nRunByte & 1 )
982 ImplSetPixel4( pDIB, nX++, *pRLE++ >> 4 );
984 if( ( ( nRunByte + 1 ) >> 1 ) & 1 )
985 pRLE++;
987 else
989 memcpy( &pDIB[ nX ], pRLE, nRunByte );
990 pRLE += nRunByte;
991 nX += nRunByte;
993 if( nRunByte & 1 )
994 pRLE++;
997 else if( !nRunByte )
999 pDIB = ( pRow += nWidthAl );
1000 nX = 0;
1002 else if( nRunByte == 1 )
1003 bEndDecoding = true;
1004 else
1006 nX += *pRLE++;
1007 pDIB = ( pRow += ( *pRLE++ ) * nWidthAl );
1010 else
1012 cTmp = *pRLE++;
1014 if( bRLE4 )
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 );
1027 else
1029 for( i = 0; i < nCountByte; i++ )
1030 pDIB[ nX++ ] = cTmp;
1034 while( !bEndDecoding && ( pDIB <= pLast ) );
1038 bool WinSalBitmap::GetSystemData( BitmapSystemData& rData )
1040 bool bRet = false;
1041 if( mhDIB || mhDDB )
1043 bRet = true;
1044 rData.pDIB = mhDIB;
1045 const Size& rSize = GetSize ();
1046 rData.mnWidth = rSize.Width();
1047 rData.mnHeight = rSize.Height();
1049 return bRet;
1052 bool WinSalBitmap::ScalingSupported() const
1054 return false;
1057 bool WinSalBitmap::Scale( const double& /*rScaleX*/, const double& /*rScaleY*/, BmpScaleFlag /*nScaleFlag*/ )
1059 return false;
1062 bool WinSalBitmap::Replace( const Color& /*rSearchColor*/, const Color& /*rReplaceColor*/, sal_uInt8 /*nTol*/ )
1064 return false;
1067 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */