/************************************************************** * * 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 // ----------- // - 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 ) ); } // ---------------- // - WinSalBitmap - // ---------------- WinSalBitmap::WinSalBitmap() : mhDIB ( 0 ), mhDDB ( 0 ), mnBitCount ( 0 ) { } // ------------------------------------------------------------------ WinSalBitmap::~WinSalBitmap() { Destroy(); } // ------------------------------------------------------------------ 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->mhDC; 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; } // ------------------------------------------------------------------ void WinSalBitmap::Destroy() { if( mhDIB ) GlobalFree( mhDIB ); else if( mhDDB ) DeleteObject( mhDDB ); maSize = Size(); mnBitCount = 0; } // ------------------------------------------------------------------ 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() && rSize.Height() ) { const sal_uLong nImageSize = AlignedWidth4Bytes( nBits * rSize.Width() ) * rSize.Height(); const sal_uInt16 nColors = ( nBits <= 8 ) ? ( 1 << nBits ) : 0; hDIB = GlobalAlloc( GHND, sizeof( BITMAPINFOHEADER ) + nColors * sizeof( RGBQUAD ) + nImageSize ); if( hDIB ) { PBITMAPINFO pBI = (PBITMAPINFO) GlobalLock( hDIB ); PBITMAPINFOHEADER pBIH = (PBITMAPINFOHEADER) 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 ) { 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; }