/************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * *************************************************************/ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_vcl.hxx" #include #include // for BitmapSystemData #include #include #include #include #include #include #include #include #include #ifndef min #define min(a,b) (((a) < (b)) ? (a) : (b)) #endif #ifndef max #define max(a,b) (((a) > (b)) ? (a) : (b)) #endif #include // ------------------------------------------------------------------ // - Inlines - inline void ImplSetPixel4( const HPBYTE pScanline, long nX, const BYTE cIndex ) { BYTE& rByte = pScanline[ nX >> 1 ]; ( nX & 1 ) ? ( rByte &= 0xf0, rByte |= ( cIndex & 0x0f ) ) : ( rByte &= 0x0f, rByte |= ( cIndex << 4 ) ); } // ------------------------------------------------------------------ // Helper class to manage Gdiplus::Bitmap instances inside of // WinSalBitmap struct Comparator { bool operator()(WinSalBitmap* pA, WinSalBitmap* pB) const { return pA < pB; } }; typedef ::std::map< WinSalBitmap*, sal_uInt32, Comparator > EntryMap; static const sal_uInt32 nDefaultCycles(60); class GdiPlusBuffer : protected comphelper::OBaseMutex, public Timer { private: EntryMap maEntries; public: GdiPlusBuffer() : Timer(), maEntries() { SetTimeout(1000); Stop(); } ~GdiPlusBuffer() { Stop(); } void addEntry(WinSalBitmap& rEntry) { ::osl::MutexGuard aGuard(m_aMutex); EntryMap::iterator aFound = maEntries.find(&rEntry); if(aFound == maEntries.end()) { if(maEntries.empty()) { Start(); } maEntries[&rEntry] = nDefaultCycles; } } void remEntry(WinSalBitmap& rEntry) { ::osl::MutexGuard aGuard(m_aMutex); EntryMap::iterator aFound = maEntries.find(&rEntry); if(aFound != maEntries.end()) { maEntries.erase(aFound); if(maEntries.empty()) { Stop(); } } } void touchEntry(WinSalBitmap& rEntry) { ::osl::MutexGuard aGuard(m_aMutex); EntryMap::iterator aFound = maEntries.find(&rEntry); if(aFound != maEntries.end()) { aFound->second = nDefaultCycles; } } // from parent Timer virtual void Timeout() { ::osl::MutexGuard aGuard(m_aMutex); EntryMap::iterator aIter(maEntries.begin()); while(aIter != maEntries.end()) { if(aIter->second) { aIter->second--; aIter++; } else { EntryMap::iterator aDelete(aIter); WinSalBitmap* pSource = aDelete->first; aIter++; maEntries.erase(aDelete); if(maEntries.empty()) { Stop(); } // delete at WinSalBitmap after entry is removed; this // way it would not hurt to call remEntry from there, too if(pSource->maGdiPlusBitmap.get()) { pSource->maGdiPlusBitmap.reset(); pSource->mpAssociatedAlpha = 0; } } } if(!maEntries.empty()) { Start(); } } }; // ------------------------------------------------------------------ // Global instance of GdiPlusBuffer which manages Gdiplus::Bitmap // instances static GdiPlusBuffer aGdiPlusBuffer; // ------------------------------------------------------------------ // - WinSalBitmap - WinSalBitmap::WinSalBitmap() : maSize(), mhDIB(0), mhDDB(0), maGdiPlusBitmap(), mpAssociatedAlpha(0), mnBitCount(0) { } // ------------------------------------------------------------------ WinSalBitmap::~WinSalBitmap() { Destroy(); } // ------------------------------------------------------------------ void WinSalBitmap::Destroy() { if(maGdiPlusBitmap.get()) { aGdiPlusBuffer.remEntry(*this); } if( mhDIB ) GlobalFree( mhDIB ); else if( mhDDB ) DeleteObject( mhDDB ); maSize = Size(); mnBitCount = 0; } // ------------------------------------------------------------------ GdiPlusBmpPtr WinSalBitmap::ImplGetGdiPlusBitmap(const WinSalBitmap* pAlphaSource) const { WinSalBitmap* pThat = const_cast< WinSalBitmap* >(this); if(maGdiPlusBitmap.get() && pAlphaSource != mpAssociatedAlpha) { // #122350# if associated alpha with which the GDIPlus was constructed has changed // it is necessary to remove it from buffer, reset reference to it and reconstruct pThat->maGdiPlusBitmap.reset(); aGdiPlusBuffer.remEntry(const_cast< WinSalBitmap& >(*this)); } if(maGdiPlusBitmap.get()) { aGdiPlusBuffer.touchEntry(const_cast< WinSalBitmap& >(*this)); } else { if(maSize.Width() > 0 && maSize.Height() > 0) { if(pAlphaSource) { pThat->maGdiPlusBitmap.reset(pThat->ImplCreateGdiPlusBitmap(*pAlphaSource)); pThat->mpAssociatedAlpha = pAlphaSource; } else { pThat->maGdiPlusBitmap.reset(pThat->ImplCreateGdiPlusBitmap()); pThat->mpAssociatedAlpha = 0; } if(maGdiPlusBitmap.get()) { aGdiPlusBuffer.addEntry(*pThat); } } } return maGdiPlusBitmap; } // ------------------------------------------------------------------ Gdiplus::Bitmap* WinSalBitmap::ImplCreateGdiPlusBitmap() { Gdiplus::Bitmap* pRetval(0); WinSalBitmap* pSalRGB = const_cast< WinSalBitmap* >(this); WinSalBitmap* pExtraWinSalRGB = 0; if(!pSalRGB->ImplGethDIB()) { // we need DIB for success with AcquireBuffer, create a replacement WinSalBitmap pExtraWinSalRGB = new WinSalBitmap(); pExtraWinSalRGB->Create(*pSalRGB, pSalRGB->GetBitCount()); pSalRGB = pExtraWinSalRGB; } BitmapBuffer* pRGB = pSalRGB->AcquireBuffer(true); BitmapBuffer* pExtraRGB = 0; if(pRGB && BMP_FORMAT_24BIT_TC_BGR != (pRGB->mnFormat & ~BMP_FORMAT_TOP_DOWN)) { // convert source bitmap to BMP_FORMAT_24BIT_TC_BGR format if not yet in that format SalTwoRect aSalTwoRect; aSalTwoRect.mnSrcX = aSalTwoRect.mnSrcY = aSalTwoRect.mnDestX = aSalTwoRect.mnDestY = 0; aSalTwoRect.mnSrcWidth = aSalTwoRect.mnDestWidth = pRGB->mnWidth; aSalTwoRect.mnSrcHeight = aSalTwoRect.mnDestHeight = pRGB->mnHeight; pExtraRGB = StretchAndConvert( *pRGB, aSalTwoRect, BMP_FORMAT_24BIT_TC_BGR, 0); pSalRGB->ReleaseBuffer(pRGB, true); pRGB = pExtraRGB; } if(pRGB && pRGB->mnWidth > 0 && pRGB->mnHeight > 0 && BMP_FORMAT_24BIT_TC_BGR == (pRGB->mnFormat & ~BMP_FORMAT_TOP_DOWN)) { const sal_uInt32 nW(pRGB->mnWidth); const sal_uInt32 nH(pRGB->mnHeight); pRetval = new Gdiplus::Bitmap(nW, nH, PixelFormat24bppRGB); if(pRetval) { if ( pRetval->GetLastStatus() == Gdiplus::Ok ) { sal_uInt8* pSrcRGB(pRGB->mpBits); const sal_uInt32 nExtraRGB(pRGB->mnScanlineSize - (nW * 3)); const bool bTopDown(pRGB->mnFormat & BMP_FORMAT_TOP_DOWN); const Gdiplus::Rect aAllRect(0, 0, nW, nH); Gdiplus::BitmapData aGdiPlusBitmapData; pRetval->LockBits(&aAllRect, Gdiplus::ImageLockModeWrite, PixelFormat24bppRGB, &aGdiPlusBitmapData); // copy data to Gdiplus::Bitmap; format is BGR here in both cases, so memcpy is possible for(sal_uInt32 y(0); y < nH; y++) { const sal_uInt32 nYInsert(bTopDown ? y : nH - y - 1); sal_uInt8* targetPixels = (sal_uInt8*)aGdiPlusBitmapData.Scan0 + (nYInsert * aGdiPlusBitmapData.Stride); memcpy(targetPixels, pSrcRGB, nW * 3); pSrcRGB += nW * 3 + nExtraRGB; } pRetval->UnlockBits(&aGdiPlusBitmapData); } else { delete pRetval; pRetval = NULL; } } } if(pExtraRGB) { // #123478# shockingly, BitmapBuffer does not free the memory it is controlling // in it's destructor, this *has to be done handish*. Doing it here now delete[] pExtraRGB->mpBits; delete pExtraRGB; } else { pSalRGB->ReleaseBuffer(pRGB, true); } if(pExtraWinSalRGB) { delete pExtraWinSalRGB; } return pRetval; } // ------------------------------------------------------------------ Gdiplus::Bitmap* WinSalBitmap::ImplCreateGdiPlusBitmap(const WinSalBitmap& rAlphaSource) { Gdiplus::Bitmap* pRetval(0); WinSalBitmap* pSalRGB = const_cast< WinSalBitmap* >(this); WinSalBitmap* pExtraWinSalRGB = 0; if(!pSalRGB->ImplGethDIB()) { // we need DIB for success with AcquireBuffer, create a replacement WinSalBitmap pExtraWinSalRGB = new WinSalBitmap(); pExtraWinSalRGB->Create(*pSalRGB, pSalRGB->GetBitCount()); pSalRGB = pExtraWinSalRGB; } BitmapBuffer* pRGB = pSalRGB->AcquireBuffer(true); BitmapBuffer* pExtraRGB = 0; if(pRGB && BMP_FORMAT_24BIT_TC_BGR != (pRGB->mnFormat & ~BMP_FORMAT_TOP_DOWN)) { // convert source bitmap to BMP_FORMAT_24BIT_TC_BGR format if not yet in that format SalTwoRect aSalTwoRect; aSalTwoRect.mnSrcX = aSalTwoRect.mnSrcY = aSalTwoRect.mnDestX = aSalTwoRect.mnDestY = 0; aSalTwoRect.mnSrcWidth = aSalTwoRect.mnDestWidth = pRGB->mnWidth; aSalTwoRect.mnSrcHeight = aSalTwoRect.mnDestHeight = pRGB->mnHeight; pExtraRGB = StretchAndConvert( *pRGB, aSalTwoRect, BMP_FORMAT_24BIT_TC_BGR, 0); pSalRGB->ReleaseBuffer(pRGB, true); pRGB = pExtraRGB; } WinSalBitmap* pSalA = const_cast< WinSalBitmap* >(&rAlphaSource); WinSalBitmap* pExtraWinSalA = 0; if(!pSalA->ImplGethDIB()) { // we need DIB for success with AcquireBuffer, create a replacement WinSalBitmap pExtraWinSalA = new WinSalBitmap(); pExtraWinSalA->Create(*pSalA, pSalA->GetBitCount()); pSalA = pExtraWinSalA; } BitmapBuffer* pA = pSalA->AcquireBuffer(true); BitmapBuffer* pExtraA = 0; if(pA && BMP_FORMAT_8BIT_PAL != (pA->mnFormat & ~BMP_FORMAT_TOP_DOWN)) { // convert alpha bitmap to BMP_FORMAT_8BIT_PAL format if not yet in that format SalTwoRect aSalTwoRect; aSalTwoRect.mnSrcX = aSalTwoRect.mnSrcY = aSalTwoRect.mnDestX = aSalTwoRect.mnDestY = 0; aSalTwoRect.mnSrcWidth = aSalTwoRect.mnDestWidth = pA->mnWidth; aSalTwoRect.mnSrcHeight = aSalTwoRect.mnDestHeight = pA->mnHeight; const BitmapPalette& rTargetPalette = Bitmap::GetGreyPalette(256); pExtraA = StretchAndConvert( *pA, aSalTwoRect, BMP_FORMAT_8BIT_PAL, &rTargetPalette); pSalA->ReleaseBuffer(pA, true); pA = pExtraA; } if(pRGB && pA && pRGB->mnWidth > 0 && pRGB->mnHeight > 0 && pRGB->mnWidth == pA->mnWidth && pRGB->mnHeight == pA->mnHeight && BMP_FORMAT_24BIT_TC_BGR == (pRGB->mnFormat & ~BMP_FORMAT_TOP_DOWN) && BMP_FORMAT_8BIT_PAL == (pA->mnFormat & ~BMP_FORMAT_TOP_DOWN)) { // we have alpha and bitmap in known formats, create GdiPlus Bitmap as 32bit ARGB const sal_uInt32 nW(pRGB->mnWidth); const sal_uInt32 nH(pRGB->mnHeight); pRetval = new Gdiplus::Bitmap(nW, nH, PixelFormat32bppARGB); if(pRetval) { if ( pRetval->GetLastStatus() == Gdiplus::Ok ) // 2nd place to secure with new Gdiplus::Bitmap { sal_uInt8* pSrcRGB(pRGB->mpBits); sal_uInt8* pSrcA(pA->mpBits); const sal_uInt32 nExtraRGB(pRGB->mnScanlineSize - (nW * 3)); const sal_uInt32 nExtraA(pA->mnScanlineSize - nW); const bool bTopDown(pRGB->mnFormat & BMP_FORMAT_TOP_DOWN); const Gdiplus::Rect aAllRect(0, 0, nW, nH); Gdiplus::BitmapData aGdiPlusBitmapData; pRetval->LockBits(&aAllRect, Gdiplus::ImageLockModeWrite, PixelFormat32bppARGB, &aGdiPlusBitmapData); // copy data to Gdiplus::Bitmap; format is BGRA; need to mix BGR from Bitmap and // A from alpha, so inner loop is needed (who invented BitmapEx..?) for(sal_uInt32 y(0); y < nH; y++) { const sal_uInt32 nYInsert(bTopDown ? y : nH - y - 1); sal_uInt8* targetPixels = (sal_uInt8*)aGdiPlusBitmapData.Scan0 + (nYInsert * aGdiPlusBitmapData.Stride); for(sal_uInt32 x(0); x < nW; x++) { *targetPixels++ = *pSrcRGB++; *targetPixels++ = *pSrcRGB++; *targetPixels++ = *pSrcRGB++; *targetPixels++ = 0xff - *pSrcA++; } pSrcRGB += nExtraRGB; pSrcA += nExtraA; } pRetval->UnlockBits(&aGdiPlusBitmapData); } else { delete pRetval; pRetval = NULL; } } } if(pExtraA) { // #123478# shockingly, BitmapBuffer does not free the memory it is controlling // in it's destructor, this *has to be done handish*. Doing it here now delete[] pExtraA->mpBits; delete pExtraA; } else { pSalA->ReleaseBuffer(pA, true); } if(pExtraWinSalA) { delete pExtraWinSalA; } if(pExtraRGB) { // #123478# shockingly, BitmapBuffer does not free the memory it is controlling // in it's destructor, this *has to be done handish*. Doing it here now delete[] pExtraRGB->mpBits; delete pExtraRGB; } else { pSalRGB->ReleaseBuffer(pRGB, true); } if(pExtraWinSalRGB) { delete pExtraWinSalRGB; } return pRetval; } // ------------------------------------------------------------------ bool WinSalBitmap::Create( HANDLE hBitmap, bool bDIB, bool bCopyHandle ) { bool bRet = TRUE; if( bDIB ) mhDIB = (HGLOBAL) ( bCopyHandle ? ImplCopyDIBOrDDB( hBitmap, TRUE ) : hBitmap ); else mhDDB = (HBITMAP) ( bCopyHandle ? ImplCopyDIBOrDDB( hBitmap, FALSE ) : hBitmap ); if( mhDIB ) { PBITMAPINFOHEADER pBIH = (PBITMAPINFOHEADER) GlobalLock( mhDIB ); maSize = Size( pBIH->biWidth, pBIH->biHeight ); mnBitCount = pBIH->biBitCount; if( mnBitCount ) mnBitCount = ( mnBitCount <= 1 ) ? 1 : ( mnBitCount <= 4 ) ? 4 : ( mnBitCount <= 8 ) ? 8 : 24; GlobalUnlock( mhDIB ); } else if( mhDDB ) { BITMAP aDDBInfo; if( WIN_GetObject( mhDDB, sizeof( BITMAP ), &aDDBInfo ) ) { maSize = Size( aDDBInfo.bmWidth, aDDBInfo.bmHeight ); mnBitCount = aDDBInfo.bmPlanes * aDDBInfo.bmBitsPixel; if( mnBitCount ) { mnBitCount = ( mnBitCount <= 1 ) ? 1 : ( mnBitCount <= 4 ) ? 4 : ( mnBitCount <= 8 ) ? 8 : 24; } } else { mhDDB = 0; bRet = FALSE; } } else bRet = FALSE; return bRet; } // ------------------------------------------------------------------ bool WinSalBitmap::Create( const Size& rSize, sal_uInt16 nBitCount, const BitmapPalette& rPal ) { bool bRet = FALSE; mhDIB = ImplCreateDIB( rSize, nBitCount, rPal ); if( mhDIB ) { maSize = rSize; mnBitCount = nBitCount; bRet = TRUE; } return bRet; } // ------------------------------------------------------------------ bool WinSalBitmap::Create( const SalBitmap& rSSalBitmap ) { bool bRet = FALSE; const WinSalBitmap& rSalBitmap = static_cast(rSSalBitmap); if ( rSalBitmap.mhDIB || rSalBitmap.mhDDB ) { HANDLE hNewHdl = ImplCopyDIBOrDDB( rSalBitmap.mhDIB ? rSalBitmap.mhDIB : rSalBitmap.mhDDB, rSalBitmap.mhDIB != 0 ); if ( hNewHdl ) { if( rSalBitmap.mhDIB ) mhDIB = (HGLOBAL) hNewHdl; else if( rSalBitmap.mhDDB ) mhDDB = (HBITMAP) hNewHdl; maSize = rSalBitmap.maSize; mnBitCount = rSalBitmap.mnBitCount; bRet = TRUE; } } return bRet; } // ------------------------------------------------------------------ bool WinSalBitmap::Create( const SalBitmap& rSSalBmp, SalGraphics* pSGraphics ) { bool bRet = FALSE; const WinSalBitmap& rSalBmp = static_cast(rSSalBmp); WinSalGraphics* pGraphics = static_cast(pSGraphics); if( rSalBmp.mhDIB ) { PBITMAPINFO pBI = (PBITMAPINFO) GlobalLock( rSalBmp.mhDIB ); PBITMAPINFOHEADER pBIH = (PBITMAPINFOHEADER) pBI; HDC hDC = pGraphics->getHDC(); HBITMAP hNewDDB; BITMAP aDDBInfo; PBYTE pBits = (PBYTE) pBI + *(DWORD*) pBI + ImplGetDIBColorCount( rSalBmp.mhDIB ) * sizeof( RGBQUAD ); if( pBIH->biBitCount == 1 ) { hNewDDB = CreateBitmap( pBIH->biWidth, pBIH->biHeight, 1, 1, NULL ); if( hNewDDB ) SetDIBits( hDC, hNewDDB, 0, pBIH->biHeight, pBits, pBI, DIB_RGB_COLORS ); } else hNewDDB = CreateDIBitmap( hDC, (PBITMAPINFOHEADER) pBI, CBM_INIT, pBits, pBI, DIB_RGB_COLORS ); GlobalUnlock( rSalBmp.mhDIB ); if( hNewDDB && WIN_GetObject( hNewDDB, sizeof( BITMAP ), &aDDBInfo ) ) { mhDDB = hNewDDB; maSize = Size( aDDBInfo.bmWidth, aDDBInfo.bmHeight ); mnBitCount = aDDBInfo.bmPlanes * aDDBInfo.bmBitsPixel; bRet = TRUE; } else if( hNewDDB ) DeleteObject( hNewDDB ); } return bRet; } // ------------------------------------------------------------------ bool WinSalBitmap::Create( const SalBitmap& rSSalBmp, sal_uInt16 nNewBitCount ) { bool bRet = FALSE; const WinSalBitmap& rSalBmp = static_cast(rSSalBmp); if( rSalBmp.mhDDB ) { mhDIB = ImplCreateDIB( rSalBmp.maSize, nNewBitCount, BitmapPalette() ); if( mhDIB ) { PBITMAPINFO pBI = (PBITMAPINFO) GlobalLock( mhDIB ); const int nLines = (int) rSalBmp.maSize.Height(); HDC hDC = GetDC( 0 ); PBYTE pBits = (PBYTE) pBI + *(DWORD*) pBI + ImplGetDIBColorCount( mhDIB ) * sizeof( RGBQUAD ); SalData* pSalData = GetSalData(); HPALETTE hOldPal = 0; if ( pSalData->mhDitherPal ) { hOldPal = SelectPalette( hDC, pSalData->mhDitherPal, TRUE ); RealizePalette( hDC ); } if( GetDIBits( hDC, rSalBmp.mhDDB, 0, nLines, pBits, pBI, DIB_RGB_COLORS ) == nLines ) { GlobalUnlock( mhDIB ); maSize = rSalBmp.maSize; mnBitCount = nNewBitCount; bRet = TRUE; } else { GlobalUnlock( mhDIB ); GlobalFree( mhDIB ); mhDIB = 0; } if( hOldPal ) SelectPalette( hDC, hOldPal, TRUE ); ReleaseDC( 0, hDC ); } } return bRet; } // ------------------------------------------------------------------ sal_uInt16 WinSalBitmap::ImplGetDIBColorCount( HGLOBAL hDIB ) { sal_uInt16 nColors = 0; if( hDIB ) { PBITMAPINFO pBI = (PBITMAPINFO) GlobalLock( hDIB ); PBITMAPINFOHEADER pBIH = (PBITMAPINFOHEADER) pBI; if ( pBIH->biSize != sizeof( BITMAPCOREHEADER ) ) { if( pBIH->biBitCount <= 8 ) { if ( pBIH->biClrUsed ) nColors = (sal_uInt16) pBIH->biClrUsed; else nColors = 1 << pBIH->biBitCount; } } else if( ( (PBITMAPCOREHEADER) pBI )->bcBitCount <= 8 ) nColors = 1 << ( (PBITMAPCOREHEADER) pBI )->bcBitCount; GlobalUnlock( hDIB ); } return nColors; } // ------------------------------------------------------------------ HGLOBAL WinSalBitmap::ImplCreateDIB( const Size& rSize, sal_uInt16 nBits, const BitmapPalette& rPal ) { DBG_ASSERT( nBits == 1 || nBits == 4 || nBits == 8 || nBits == 16 || nBits == 24, "Unsupported BitCount!" ); HGLOBAL hDIB = 0; if( rSize.Width() <= 0 || rSize.Height() <= 0 ) return hDIB; // calculate bitmap size in Bytes const sal_uLong nAlignedWidth4Bytes = AlignedWidth4Bytes( nBits * rSize.Width() ); const sal_uLong nImageSize = nAlignedWidth4Bytes * rSize.Height(); bool bOverflow = (nImageSize / nAlignedWidth4Bytes) != rSize.Height(); if( bOverflow ) return hDIB; // allocate bitmap memory including header and palette const sal_uInt16 nColors = (nBits <= 8) ? (1 << nBits) : 0; const sal_uLong nHeaderSize = sizeof( BITMAPINFOHEADER ) + nColors * sizeof( RGBQUAD ); bOverflow = (nHeaderSize + nImageSize) < nImageSize; if( bOverflow ) return hDIB; hDIB = GlobalAlloc( GHND, nHeaderSize + nImageSize ); if( !hDIB ) return hDIB; PBITMAPINFO pBI = static_cast( GlobalLock( hDIB ) ); PBITMAPINFOHEADER pBIH = reinterpret_cast( pBI ); pBIH->biSize = sizeof( BITMAPINFOHEADER ); pBIH->biWidth = rSize.Width(); pBIH->biHeight = rSize.Height(); pBIH->biPlanes = 1; pBIH->biBitCount = nBits; pBIH->biCompression = BI_RGB; pBIH->biSizeImage = nImageSize; pBIH->biXPelsPerMeter = 0; pBIH->biYPelsPerMeter = 0; pBIH->biClrUsed = 0; pBIH->biClrImportant = 0; if( nColors ) { // copy the palette entries if any const sal_uInt16 nMinCount = Min( nColors, rPal.GetEntryCount() ); if( nMinCount ) memcpy( pBI->bmiColors, rPal.ImplGetColorBuffer(), nMinCount * sizeof(RGBQUAD) ); } GlobalUnlock( hDIB ); return hDIB; } // ------------------------------------------------------------------ HANDLE WinSalBitmap::ImplCopyDIBOrDDB( HANDLE hHdl, bool bDIB ) { HANDLE hCopy = 0; if ( bDIB && hHdl ) { const sal_uLong nSize = GlobalSize( hHdl ); if ( (hCopy = GlobalAlloc( GHND, nSize )) != 0 ) { memcpy( (LPSTR) GlobalLock( hCopy ), (LPSTR) GlobalLock( hHdl ), nSize ); GlobalUnlock( hCopy ); GlobalUnlock( hHdl ); } } else if ( hHdl ) { BITMAP aBmp; // Source-Bitmap nach Groesse befragen WIN_GetObject( hHdl, sizeof( BITMAP ), (LPSTR) &aBmp ); // Destination-Bitmap erzeugen if ( (hCopy = CreateBitmapIndirect( &aBmp )) != 0 ) { HDC hBmpDC = CreateCompatibleDC( 0 ); HBITMAP hBmpOld = (HBITMAP) SelectObject( hBmpDC, hHdl ); HDC hCopyDC = CreateCompatibleDC( hBmpDC ); HBITMAP hCopyOld = (HBITMAP) SelectObject( hCopyDC, hCopy ); BitBlt( hCopyDC, 0, 0, aBmp.bmWidth, aBmp.bmHeight, hBmpDC, 0, 0, SRCCOPY ); SelectObject( hCopyDC, hCopyOld ); DeleteDC( hCopyDC ); SelectObject( hBmpDC, hBmpOld ); DeleteDC( hBmpDC ); } } return hCopy; } // ------------------------------------------------------------------ BitmapBuffer* WinSalBitmap::AcquireBuffer( bool /*bReadOnly*/ ) { BitmapBuffer* pBuffer = NULL; if( mhDIB ) { PBITMAPINFO pBI = (PBITMAPINFO) GlobalLock( mhDIB ); PBITMAPINFOHEADER pBIH = (PBITMAPINFOHEADER) pBI; if( ( pBIH->biCompression == BI_RLE4 ) || ( pBIH->biCompression == BI_RLE8 ) ) { Size aSizePix( pBIH->biWidth, pBIH->biHeight ); HGLOBAL hNewDIB = ImplCreateDIB( aSizePix, pBIH->biBitCount, BitmapPalette() ); if( hNewDIB ) { PBITMAPINFO pNewBI = (PBITMAPINFO) GlobalLock( hNewDIB ); PBITMAPINFOHEADER pNewBIH = (PBITMAPINFOHEADER) pNewBI; const sal_uInt16 nColorCount = ImplGetDIBColorCount( hNewDIB ); const sal_uLong nOffset = *(DWORD*) pBI + nColorCount * sizeof( RGBQUAD ); BYTE* pOldBits = (PBYTE) pBI + nOffset; BYTE* pNewBits = (PBYTE) pNewBI + nOffset; memcpy( pNewBI, pBI, nOffset ); pNewBIH->biCompression = 0; ImplDecodeRLEBuffer( pOldBits, pNewBits, aSizePix, pBIH->biCompression == BI_RLE4 ); GlobalUnlock( mhDIB ); GlobalFree( mhDIB ); mhDIB = hNewDIB; pBI = pNewBI; pBIH = pNewBIH; } } if( pBIH->biPlanes == 1 ) { pBuffer = new BitmapBuffer; pBuffer->mnFormat = BMP_FORMAT_BOTTOM_UP | ( pBIH->biBitCount == 1 ? BMP_FORMAT_1BIT_MSB_PAL : pBIH->biBitCount == 4 ? BMP_FORMAT_4BIT_MSN_PAL : pBIH->biBitCount == 8 ? BMP_FORMAT_8BIT_PAL : pBIH->biBitCount == 16 ? BMP_FORMAT_16BIT_TC_LSB_MASK : pBIH->biBitCount == 24 ? BMP_FORMAT_24BIT_TC_BGR : pBIH->biBitCount == 32 ? BMP_FORMAT_32BIT_TC_MASK : 0UL ); if( BMP_SCANLINE_FORMAT( pBuffer->mnFormat ) ) { pBuffer->mnWidth = maSize.Width(); pBuffer->mnHeight = maSize.Height(); pBuffer->mnScanlineSize = AlignedWidth4Bytes( maSize.Width() * pBIH->biBitCount ); pBuffer->mnBitCount = (sal_uInt16) pBIH->biBitCount; if( pBuffer->mnBitCount <= 8 ) { const sal_uInt16 nPalCount = ImplGetDIBColorCount( mhDIB ); pBuffer->maPalette.SetEntryCount( nPalCount ); memcpy( pBuffer->maPalette.ImplGetColorBuffer(), pBI->bmiColors, nPalCount * sizeof( RGBQUAD ) ); pBuffer->mpBits = (PBYTE) pBI + *(DWORD*) pBI + nPalCount * sizeof( RGBQUAD ); } else if( ( pBIH->biBitCount == 16 ) || ( pBIH->biBitCount == 32 ) ) { sal_uLong nOffset = 0UL; if( pBIH->biCompression == BI_BITFIELDS ) { nOffset = 3 * sizeof( RGBQUAD ); pBuffer->maColorMask = ColorMask( *(UINT32*) &pBI->bmiColors[ 0 ], *(UINT32*) &pBI->bmiColors[ 1 ], *(UINT32*) &pBI->bmiColors[ 2 ] ); } else if( pBIH->biBitCount == 16 ) pBuffer->maColorMask = ColorMask( 0x00007c00UL, 0x000003e0UL, 0x0000001fUL ); else pBuffer->maColorMask = ColorMask( 0x00ff0000UL, 0x0000ff00UL, 0x000000ffUL ); pBuffer->mpBits = (PBYTE) pBI + *(DWORD*) pBI + nOffset; } else pBuffer->mpBits = (PBYTE) pBI + *(DWORD*) pBI; } else { GlobalUnlock( mhDIB ); delete pBuffer; pBuffer = NULL; } } else GlobalUnlock( mhDIB ); } return pBuffer; } // ------------------------------------------------------------------ void WinSalBitmap::ReleaseBuffer( BitmapBuffer* pBuffer, bool bReadOnly ) { if( pBuffer ) { if( mhDIB ) { if( !bReadOnly && !!pBuffer->maPalette ) { PBITMAPINFO pBI = (PBITMAPINFO) GlobalLock( mhDIB ); const sal_uInt16 nCount = pBuffer->maPalette.GetEntryCount(); const sal_uInt16 nDIBColorCount = ImplGetDIBColorCount( mhDIB ); memcpy( pBI->bmiColors, pBuffer->maPalette.ImplGetColorBuffer(), Min( nDIBColorCount, nCount ) * sizeof( RGBQUAD ) ); GlobalUnlock( mhDIB ); } GlobalUnlock( mhDIB ); } delete pBuffer; } } // ------------------------------------------------------------------ void WinSalBitmap::ImplDecodeRLEBuffer( const BYTE* pSrcBuf, BYTE* pDstBuf, const Size& rSizePixel, bool bRLE4 ) { HPBYTE pRLE = (HPBYTE) pSrcBuf; HPBYTE pDIB = (HPBYTE) pDstBuf; HPBYTE pRow = (HPBYTE) pDstBuf; sal_uLong nWidthAl = AlignedWidth4Bytes( rSizePixel.Width() * ( bRLE4 ? 4UL : 8UL ) ); HPBYTE pLast = pDIB + rSizePixel.Height() * nWidthAl - 1; sal_uLong nCountByte; sal_uLong nRunByte; sal_uLong nX = 0; sal_uLong i; BYTE cTmp; bool bEndDecoding = FALSE; if( pRLE && pDIB ) { do { if( ( nCountByte = *pRLE++ ) == 0 ) { nRunByte = *pRLE++; if( nRunByte > 2UL ) { if( bRLE4 ) { nCountByte = nRunByte >> 1UL; for( i = 0; i < nCountByte; i++ ) { cTmp = *pRLE++; ImplSetPixel4( pDIB, nX++, cTmp >> 4 ); ImplSetPixel4( pDIB, nX++, cTmp & 0x0f ); } if( nRunByte & 1 ) ImplSetPixel4( pDIB, nX++, *pRLE++ >> 4 ); if( ( ( nRunByte + 1 ) >> 1 ) & 1 ) pRLE++; } else { memcpy( &pDIB[ nX ], pRLE, nRunByte ); pRLE += nRunByte; nX += nRunByte; if( nRunByte & 1 ) pRLE++; } } else if( !nRunByte ) { pDIB = ( pRow += nWidthAl ); nX = 0UL; } else if( nRunByte == 1 ) bEndDecoding = TRUE; else { nX += *pRLE++; pDIB = ( pRow += ( *pRLE++ ) * nWidthAl ); } } else { cTmp = *pRLE++; if( bRLE4 ) { nRunByte = nCountByte >> 1; for( i = 0; i < nRunByte; i++ ) { ImplSetPixel4( pDIB, nX++, cTmp >> 4 ); ImplSetPixel4( pDIB, nX++, cTmp & 0x0f ); } if( nCountByte & 1 ) ImplSetPixel4( pDIB, nX++, cTmp >> 4 ); } else { for( i = 0; i < nCountByte; i++ ) pDIB[ nX++ ] = cTmp; } } } while( !bEndDecoding && ( pDIB <= pLast ) ); } } bool WinSalBitmap::GetSystemData( BitmapSystemData& rData ) { bool bRet = false; if( mhDIB || mhDDB ) { bRet = true; rData.pDIB = mhDIB; rData.pDDB = mhDDB; const Size& rSize = GetSize (); rData.mnWidth = rSize.Width(); rData.mnHeight = rSize.Height(); } return bRet; }