blob: be559ee00a89008adaa6dcc0c58cac4d2aa383a4 [file] [log] [blame]
/**************************************************************
*
* 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 <vcl/outdev.hxx>
#include <vcl/bitmapex.hxx>
#include <vcl/alpha.hxx>
#include <vcl/window.hxx>
#include <vcl/bmpacc.hxx>
#include <vcl/virdev.hxx>
#include <vcl/image.hxx>
#include <image.h>
// -----------
// - Defines -
// -----------
#define IMPSYSIMAGEITEM_MASK ( 0x01 )
#define IMPSYSIMAGEITEM_ALPHA ( 0x02 )
#define DISA_ALL ( 0xffff )
// ----------------
// - ImageAryData -
// ----------------
ImageAryData::ImageAryData() :
maName(),
mnId( 0 ),
maBitmapEx()
{
}
// -----------------------------------------------------------------------
ImageAryData::ImageAryData( const ImageAryData& rData ) :
maName( rData.maName ),
mnId( rData.mnId ),
maBitmapEx( rData.maBitmapEx )
{
}
ImageAryData::ImageAryData( const rtl::OUString &aName,
sal_uInt16 nId, const BitmapEx &aBitmap )
: maName( aName ), mnId( nId ), maBitmapEx( aBitmap )
{
}
// -----------------------------------------------------------------------
ImageAryData::~ImageAryData()
{
}
// -----------------------------------------------------------------------
ImageAryData& ImageAryData::operator=( const ImageAryData& rData )
{
maName = rData.maName;
mnId = rData.mnId;
maBitmapEx = rData.maBitmapEx;
return *this;
}
// -----------------
// - ImplImageList -
// -----------------
ImplImageList::ImplImageList()
{
}
ImplImageList::ImplImageList( const ImplImageList &aSrc ) :
maPrefix( aSrc.maPrefix ),
maImageSize( aSrc.maImageSize ),
mnRefCount( 1 )
{
maImages.reserve( aSrc.maImages.size() );
for ( ImageAryDataVec::const_iterator aIt = aSrc.maImages.begin(), aEnd = aSrc.maImages.end(); aIt != aEnd; ++aIt )
{
ImageAryData* pAryData = new ImageAryData( **aIt );
maImages.push_back( pAryData );
if( pAryData->maName.getLength() )
maNameHash [ pAryData->maName ] = pAryData;
}
}
ImplImageList::~ImplImageList()
{
for ( ImageAryDataVec::iterator aIt = maImages.begin(), aEnd = maImages.end(); aIt != aEnd; ++aIt )
delete *aIt;
}
void ImplImageList::AddImage( const ::rtl::OUString &aName,
sal_uInt16 nId, const BitmapEx &aBitmapEx )
{
ImageAryData *pImg = new ImageAryData( aName, nId, aBitmapEx );
maImages.push_back( pImg );
if( aName.getLength() )
maNameHash [ aName ] = pImg;
}
void ImplImageList::RemoveImage( sal_uInt16 nPos )
{
ImageAryData *pImg = maImages[ nPos ];
if( pImg->maName.getLength() )
maNameHash.erase( pImg->maName );
maImages.erase( maImages.begin() + nPos );
}
sal_uInt16 ImplImageList::GetImageCount() const
{
return sal::static_int_cast< sal_uInt16 >( maImages.size() );
}
// -----------------
// - ImplImageData -
// -----------------
ImplImageData::ImplImageData( const BitmapEx& rBmpEx ) :
mpImageBitmap( NULL ),
maBmpEx( rBmpEx )
{
}
// -----------------------------------------------------------------------
ImplImageData::~ImplImageData()
{
delete mpImageBitmap;
}
// -----------------
// - ImplImageData -
// -----------------
sal_Bool ImplImageData::IsEqual( const ImplImageData& rData )
{
return( maBmpEx == rData.maBmpEx );
}
// -------------
// - ImplImage -
// -------------
ImplImage::ImplImage()
{
}
// ------------------------------------------------------------------------------
ImplImage::~ImplImage()
{
switch( meType )
{
case IMAGETYPE_BITMAP:
delete static_cast< Bitmap* >( mpData );
break;
case IMAGETYPE_IMAGE:
delete static_cast< ImplImageData* >( mpData );
break;
}
}
// ----------------
// - ImplImageBmp -
// ----------------
ImplImageBmp::ImplImageBmp() :
mpDisplayBmp( NULL ),
mpInfoAry( NULL ),
mnSize( 0 )
{
}
// -------------
// - ImplImage -
// -------------
ImplImageBmp::~ImplImageBmp()
{
delete[] mpInfoAry;
delete mpDisplayBmp;
}
// -----------------------------------------------------------------------
void ImplImageBmp::Create( long nItemWidth, long nItemHeight, sal_uInt16 nInitSize )
{
const Size aTotalSize( nInitSize * nItemWidth, nItemHeight );
maBmpEx = Bitmap( aTotalSize, 24 );
maDisabledBmpEx.SetEmpty();
delete mpDisplayBmp;
mpDisplayBmp = NULL;
maSize = Size( nItemWidth, nItemHeight );
mnSize = nInitSize;
delete[] mpInfoAry;
mpInfoAry = new sal_uInt8[ mnSize ];
memset( mpInfoAry, 0, mnSize );
}
// -----------------------------------------------------------------------
void ImplImageBmp::Create( const BitmapEx& rBmpEx, long nItemWidth, long nItemHeight, sal_uInt16 nInitSize )
{
maBmpEx = rBmpEx;
maDisabledBmpEx.SetEmpty();
delete mpDisplayBmp;
mpDisplayBmp = NULL;
maSize = Size( nItemWidth, nItemHeight );
mnSize = nInitSize;
delete[] mpInfoAry;
mpInfoAry = new sal_uInt8[ mnSize ];
memset( mpInfoAry,
rBmpEx.IsAlpha() ? IMPSYSIMAGEITEM_ALPHA : ( rBmpEx.IsTransparent() ? IMPSYSIMAGEITEM_MASK : 0 ),
mnSize );
}
// -----------------------------------------------------------------------
void ImplImageBmp::Expand( sal_uInt16 nGrowSize )
{
const sal_uLong nDX = nGrowSize * maSize.Width();
const sal_uInt16 nOldSize = mnSize;
sal_uInt8* pNewAry = new sal_uInt8[ mnSize = sal::static_int_cast<sal_uInt16>(mnSize+nGrowSize) ];
maBmpEx.Expand( nDX, 0UL );
if( !maDisabledBmpEx.IsEmpty() )
maDisabledBmpEx.Expand( nDX, 0UL );
delete mpDisplayBmp;
mpDisplayBmp = NULL;
memset( pNewAry, 0, mnSize );
memcpy( pNewAry, mpInfoAry, nOldSize );
delete[] mpInfoAry;
mpInfoAry = pNewAry;
}
// -----------------------------------------------------------------------
void ImplImageBmp::Invert()
{
delete mpDisplayBmp;
mpDisplayBmp = NULL;
maBmpEx.Invert();
}
// -----------------------------------------------------------------------
void ImplImageBmp::Replace( sal_uInt16 nPos, sal_uInt16 nSrcPos )
{
const Point aSrcPos( nSrcPos * maSize.Width(), 0L ), aPos( nPos * maSize.Width(), 0L );
const Rectangle aSrcRect( aSrcPos, maSize );
const Rectangle aDstRect( aPos, maSize );
maBmpEx.CopyPixel( aDstRect, aSrcRect );
if( !maDisabledBmpEx.IsEmpty() )
maDisabledBmpEx.CopyPixel( aDstRect, aSrcRect );
delete mpDisplayBmp;
mpDisplayBmp = NULL;
mpInfoAry[ nPos ] = mpInfoAry[ nSrcPos ];
}
// -----------------------------------------------------------------------
void ImplImageBmp::Replace( sal_uInt16 nPos, const ImplImageBmp& rImageBmp, sal_uInt16 nSrcPos )
{
const Point aSrcPos( nSrcPos * maSize.Width(), 0L ), aPos( nPos * maSize.Width(), 0L );
const Rectangle aSrcRect( aSrcPos, maSize );
const Rectangle aDstRect( aPos, maSize );
maBmpEx.CopyPixel( aDstRect, aSrcRect, &rImageBmp.maBmpEx );
ImplUpdateDisabledBmpEx( nPos );
delete mpDisplayBmp;
mpDisplayBmp = NULL;
mpInfoAry[ nPos ] = rImageBmp.mpInfoAry[ nSrcPos ];
}
// -----------------------------------------------------------------------
void ImplImageBmp::Replace( sal_uInt16 nPos, const BitmapEx& rBmpEx )
{
const Point aNullPos, aPos( nPos * maSize.Width(), 0L );
const Rectangle aSrcRect( aNullPos, maSize );
const Rectangle aDstRect( aPos, maSize );
maBmpEx.CopyPixel( aDstRect, aSrcRect, &rBmpEx );
ImplUpdateDisabledBmpEx( nPos );
delete mpDisplayBmp;
mpDisplayBmp = NULL;
mpInfoAry[ nPos ] &= ~( IMPSYSIMAGEITEM_MASK | IMPSYSIMAGEITEM_ALPHA );
mpInfoAry[ nPos ] |= ( rBmpEx.IsAlpha() ? IMPSYSIMAGEITEM_ALPHA : ( rBmpEx.IsTransparent() ? IMPSYSIMAGEITEM_MASK : 0 ) );
}
// -----------------------------------------------------------------------
void ImplImageBmp::ReplaceColors( const Color* pSrcColors, const Color* pDstColors, sal_uLong nColorCount )
{
maBmpEx.Replace( pSrcColors, pDstColors, nColorCount );
delete mpDisplayBmp;
mpDisplayBmp = NULL;
}
// -----------------------------------------------------------------------
void ImplImageBmp::ColorTransform( BmpColorMode eColorMode )
{
maBmpEx = maBmpEx.GetColorTransformedBitmapEx( eColorMode );
delete mpDisplayBmp;
mpDisplayBmp = NULL;
}
// -----------------------------------------------------------------------
BitmapEx ImplImageBmp::GetBitmapEx( sal_uInt16 nPosCount, sal_uInt16* pPosAry ) const
{
const Bitmap aNewBmp( Size( nPosCount * maSize.Width(), maSize.Height() ), maBmpEx.GetBitmap().GetBitCount() );
BitmapEx aRet;
if( maBmpEx.IsAlpha() )
{
// initialize target bitmap with an empty alpha mask
// which allows for using an optimized copypixel later on (see AlphaMask::CopyPixel)
// that avoids palette lookups
AlphaMask aAlpha( Size( nPosCount * maSize.Width(), maSize.Height() ) );
aRet = BitmapEx( aNewBmp, aAlpha );
}
else
aRet = BitmapEx( aNewBmp );
for( sal_uInt16 i = 0; i < nPosCount; i++ )
{
const Point aSrcPos( pPosAry[ i ] * maSize.Width(), 0L );
const Point aPos( i * maSize.Width(), 0L );
const Rectangle aSrcRect( aSrcPos, maSize );
const Rectangle aDstRect( aPos, maSize );
aRet.CopyPixel( aDstRect, aSrcRect, &maBmpEx );
}
return aRet;
}
// -----------------------------------------------------------------------
void ImplImageBmp::Draw( sal_uInt16 nPos, OutputDevice* pOutDev,
const Point& rPos, sal_uInt16 nStyle,
const Size* pSize )
{
if( pOutDev->IsDeviceOutputNecessary() )
{
const Point aSrcPos( nPos * maSize.Width(), 0 );
Size aOutSize;
aOutSize = ( pSize ? *pSize : pOutDev->PixelToLogic( maSize ) );
if( nStyle & IMAGE_DRAW_DISABLE )
{
ImplUpdateDisabledBmpEx( nPos);
pOutDev->DrawBitmapEx( rPos, aOutSize, aSrcPos, maSize, maDisabledBmpEx );
}
else
{
if( nStyle & ( IMAGE_DRAW_COLORTRANSFORM |
IMAGE_DRAW_MONOCHROME_BLACK | IMAGE_DRAW_MONOCHROME_WHITE |
IMAGE_DRAW_HIGHLIGHT | IMAGE_DRAW_DEACTIVE | IMAGE_DRAW_SEMITRANSPARENT ) )
{
BitmapEx aTmpBmpEx;
const Rectangle aCropRect( aSrcPos, maSize );
if( mpInfoAry[ nPos ] & ( IMPSYSIMAGEITEM_MASK | IMPSYSIMAGEITEM_ALPHA ) )
aTmpBmpEx = maBmpEx;
else
aTmpBmpEx = maBmpEx.GetBitmap();
aTmpBmpEx.Crop( aCropRect );
if( nStyle & ( IMAGE_DRAW_COLORTRANSFORM | IMAGE_DRAW_MONOCHROME_BLACK | IMAGE_DRAW_MONOCHROME_WHITE ) )
{
const BmpColorMode eMode = ( nStyle & IMAGE_DRAW_COLORTRANSFORM ) ? BMP_COLOR_HIGHCONTRAST :
( ( nStyle & IMAGE_DRAW_MONOCHROME_BLACK ) ? BMP_COLOR_MONOCHROME_BLACK : BMP_COLOR_MONOCHROME_WHITE );
aTmpBmpEx = aTmpBmpEx.GetColorTransformedBitmapEx( eMode );
}
Bitmap aTmpBmp( aTmpBmpEx.GetBitmap() );
if( nStyle & ( IMAGE_DRAW_HIGHLIGHT | IMAGE_DRAW_DEACTIVE ) )
{
BitmapWriteAccess* pAcc = aTmpBmp.AcquireWriteAccess();
if( pAcc )
{
const StyleSettings& rSettings = pOutDev->GetSettings().GetStyleSettings();
Color aColor;
BitmapColor aCol;
const long nW = pAcc->Width();
const long nH = pAcc->Height();
sal_uInt8* pMapR = new sal_uInt8[ 256 ];
sal_uInt8* pMapG = new sal_uInt8[ 256 ];
sal_uInt8* pMapB = new sal_uInt8[ 256 ];
long nX, nY;
if( nStyle & IMAGE_DRAW_HIGHLIGHT )
aColor = rSettings.GetHighlightColor();
else
aColor = rSettings.GetDeactiveColor();
const sal_uInt8 cR = aColor.GetRed();
const sal_uInt8 cG = aColor.GetGreen();
const sal_uInt8 cB = aColor.GetBlue();
for( nX = 0L; nX < 256L; nX++ )
{
pMapR[ nX ] = (sal_uInt8) ( ( ( nY = ( nX + cR ) >> 1 ) > 255 ) ? 255 : nY );
pMapG[ nX ] = (sal_uInt8) ( ( ( nY = ( nX + cG ) >> 1 ) > 255 ) ? 255 : nY );
pMapB[ nX ] = (sal_uInt8) ( ( ( nY = ( nX + cB ) >> 1 ) > 255 ) ? 255 : nY );
}
if( pAcc->HasPalette() )
{
for( sal_uInt16 i = 0, nCount = pAcc->GetPaletteEntryCount(); i < nCount; i++ )
{
const BitmapColor& rCol = pAcc->GetPaletteColor( i );
aCol.SetRed( pMapR[ rCol.GetRed() ] );
aCol.SetGreen( pMapG[ rCol.GetGreen() ] );
aCol.SetBlue( pMapB[ rCol.GetBlue() ] );
pAcc->SetPaletteColor( i, aCol );
}
}
else if( pAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_BGR )
{
for( nY = 0L; nY < nH; nY++ )
{
Scanline pScan = pAcc->GetScanline( nY );
for( nX = 0L; nX < nW; nX++ )
{
*pScan = pMapB[ *pScan ]; pScan++;
*pScan = pMapG[ *pScan ]; pScan++;
*pScan = pMapR[ *pScan ]; pScan++;
}
}
}
else
{
for( nY = 0L; nY < nH; nY++ )
{
for( nX = 0L; nX < nW; nX++ )
{
aCol = pAcc->GetPixel( nY, nX );
aCol.SetRed( pMapR[ aCol.GetRed() ] );
aCol.SetGreen( pMapG[ aCol.GetGreen() ] );
aCol.SetBlue( pMapB[ aCol.GetBlue() ] );
pAcc->SetPixel( nY, nX, aCol );
}
}
}
delete[] pMapR;
delete[] pMapG;
delete[] pMapB;
aTmpBmp.ReleaseAccess( pAcc );
}
}
if( nStyle & IMAGE_DRAW_SEMITRANSPARENT )
{
if( aTmpBmpEx.IsTransparent() )
{
Bitmap aAlphaBmp( aTmpBmpEx.GetAlpha().GetBitmap() );
aAlphaBmp.Adjust( 50 );
aTmpBmpEx = BitmapEx( aTmpBmp, AlphaMask( aAlphaBmp ) );
}
else
{
sal_uInt8 cErase = 128;
aTmpBmpEx = BitmapEx( aTmpBmp, AlphaMask( aTmpBmp.GetSizePixel(), &cErase ) );
}
}
else
{
if( aTmpBmpEx.IsAlpha() )
aTmpBmpEx = BitmapEx( aTmpBmp, aTmpBmpEx.GetAlpha() );
else if( aTmpBmpEx.IsAlpha() )
aTmpBmpEx = BitmapEx( aTmpBmp, aTmpBmpEx.GetMask() );
}
pOutDev->DrawBitmapEx( rPos, aOutSize, aTmpBmpEx );
}
else
{
const BitmapEx* pOutputBmp;
if( pOutDev->GetOutDevType() == OUTDEV_WINDOW )
{
ImplUpdateDisplayBmp( pOutDev );
pOutputBmp = mpDisplayBmp;
}
else
pOutputBmp = &maBmpEx;
if( pOutputBmp )
pOutDev->DrawBitmapEx( rPos, aOutSize, aSrcPos, maSize, *pOutputBmp );
}
}
}
}
// -----------------------------------------------------------------------
void ImplImageBmp::ImplUpdateDisplayBmp( OutputDevice*
#if defined WNT
pOutDev
#endif
)
{
if( !mpDisplayBmp && !maBmpEx.IsEmpty() )
{
#if defined WNT
if( maBmpEx.IsAlpha() )
mpDisplayBmp = new BitmapEx( maBmpEx );
else
{
const Bitmap aBmp( maBmpEx.GetBitmap().CreateDisplayBitmap( pOutDev ) );
if( maBmpEx.IsTransparent() )
mpDisplayBmp = new BitmapEx( aBmp, maBmpEx.GetMask().CreateDisplayBitmap( pOutDev ) );
else
mpDisplayBmp = new BitmapEx( aBmp );
}
#else
mpDisplayBmp = new BitmapEx( maBmpEx );
#endif
}
}
// -----------------------------------------------------------------------
void ImplImageBmp::ImplUpdateDisabledBmpEx( int nPos )
{
const Size aTotalSize( maBmpEx.GetSizePixel() );
if( maDisabledBmpEx.IsEmpty() )
{
Bitmap aGrey( aTotalSize, 8, &Bitmap::GetGreyPalette( 256 ) );
AlphaMask aGreyAlphaMask( aTotalSize );
maDisabledBmpEx = BitmapEx( aGrey, aGreyAlphaMask );
nPos = -1;
}
Bitmap aBmp( maBmpEx.GetBitmap() );
BitmapReadAccess* pBmp( aBmp.AcquireReadAccess() );
AlphaMask aBmpAlphaMask( maBmpEx.GetAlpha() );
BitmapReadAccess* pBmpAlphaMask( aBmpAlphaMask.AcquireReadAccess() );
Bitmap aGrey( maDisabledBmpEx.GetBitmap() );
BitmapWriteAccess* pGrey( aGrey.AcquireWriteAccess() );
AlphaMask aGreyAlphaMask( maDisabledBmpEx.GetAlpha() );
BitmapWriteAccess* pGreyAlphaMask( aGreyAlphaMask.AcquireWriteAccess() );
if( pBmp && pBmpAlphaMask && pGrey && pGreyAlphaMask )
{
BitmapColor aGreyVal( 0 );
BitmapColor aGreyAlphaMaskVal( 0 );
const Point aPos( ( nPos < 0 ) ? 0 : ( nPos * maSize.Width() ), 0 );
const int nLeft = aPos.X(), nRight = nLeft + ( ( nPos < 0 ) ? aTotalSize.Width() : maSize.Width() );
const int nTop = aPos.Y(), nBottom = nTop + maSize.Height();
for( int nY = nTop; nY < nBottom; ++nY )
{
for( int nX = nLeft; nX < nRight; ++nX )
{
aGreyVal.SetIndex( pBmp->GetLuminance( nY, nX ) );
pGrey->SetPixel( nY, nX, aGreyVal );
const BitmapColor aBmpAlphaMaskVal( pBmpAlphaMask->GetPixel( nY, nX ) );
aGreyAlphaMaskVal.SetIndex( static_cast< sal_uInt8 >( ::std::min( aBmpAlphaMaskVal.GetIndex() + 178ul, 255ul ) ) );
pGreyAlphaMask->SetPixel( nY, nX, aGreyAlphaMaskVal );
}
}
}
aBmp.ReleaseAccess( pBmp );
aBmpAlphaMask.ReleaseAccess( pBmpAlphaMask );
aGrey.ReleaseAccess( pGrey );
aGreyAlphaMask.ReleaseAccess( pGreyAlphaMask );
maDisabledBmpEx = BitmapEx( aGrey, aGreyAlphaMask );
}