430 lines
15 KiB
C++
430 lines
15 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/*************************************************************************
|
|
*
|
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
*
|
|
* Copyright 2000, 2010 Oracle and/or its affiliates.
|
|
*
|
|
* OpenOffice.org - a multi-platform office productivity suite
|
|
*
|
|
* This file is part of OpenOffice.org.
|
|
*
|
|
* OpenOffice.org is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Lesser General Public License version 3
|
|
* only, as published by the Free Software Foundation.
|
|
*
|
|
* OpenOffice.org is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU Lesser General Public License version 3 for more details
|
|
* (a copy is included in the LICENSE file that accompanied this code).
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public License
|
|
* version 3 along with OpenOffice.org. If not, see
|
|
* <http://www.openoffice.org/license.html>
|
|
* for a copy of the LGPLv3 License.
|
|
*
|
|
************************************************************************/
|
|
|
|
// MARKER(update_precomp.py): autogen include statement, do not remove
|
|
#include "precompiled_vcl.hxx"
|
|
|
|
#include <vcl/salbtype.hxx>
|
|
#include <vcl/bitmap.hxx>
|
|
#include <vcl/bmpacc.hxx>
|
|
|
|
#include <impbmp.hxx>
|
|
|
|
#include <string.h>
|
|
|
|
// --------------------
|
|
// - BitmapReadAccess -
|
|
// --------------------
|
|
|
|
BitmapReadAccess::BitmapReadAccess( Bitmap& rBitmap, sal_Bool bModify ) :
|
|
mpBuffer ( NULL ),
|
|
mpScanBuf ( NULL ),
|
|
mFncGetPixel ( NULL ),
|
|
mFncSetPixel ( NULL ),
|
|
mbModify ( bModify )
|
|
{
|
|
ImplCreate( rBitmap );
|
|
}
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
BitmapReadAccess::BitmapReadAccess( Bitmap& rBitmap ) :
|
|
mpBuffer ( NULL ),
|
|
mpScanBuf ( NULL ),
|
|
mFncGetPixel ( NULL ),
|
|
mFncSetPixel ( NULL ),
|
|
mbModify ( sal_False )
|
|
{
|
|
ImplCreate( rBitmap );
|
|
}
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
BitmapReadAccess::~BitmapReadAccess()
|
|
{
|
|
ImplDestroy();
|
|
}
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
void BitmapReadAccess::ImplCreate( Bitmap& rBitmap )
|
|
{
|
|
ImpBitmap* pImpBmp = rBitmap.ImplGetImpBitmap();
|
|
|
|
DBG_ASSERT( pImpBmp, "Forbidden Access to empty bitmap!" );
|
|
|
|
if( pImpBmp )
|
|
{
|
|
if( mbModify && !maBitmap.ImplGetImpBitmap() )
|
|
{
|
|
rBitmap.ImplMakeUnique();
|
|
pImpBmp = rBitmap.ImplGetImpBitmap();
|
|
}
|
|
else
|
|
{
|
|
DBG_ASSERT( !mbModify || pImpBmp->ImplGetRefCount() == 2,
|
|
"Unpredictable results: bitmap is referenced more than once!" );
|
|
}
|
|
|
|
mpBuffer = pImpBmp->ImplAcquireBuffer( !mbModify );
|
|
|
|
if( !mpBuffer )
|
|
{
|
|
ImpBitmap* pNewImpBmp = new ImpBitmap;
|
|
|
|
if( pNewImpBmp->ImplCreate( *pImpBmp, rBitmap.GetBitCount() ) )
|
|
{
|
|
pImpBmp = pNewImpBmp;
|
|
rBitmap.ImplSetImpBitmap( pImpBmp );
|
|
mpBuffer = pImpBmp->ImplAcquireBuffer( !mbModify );
|
|
}
|
|
else
|
|
delete pNewImpBmp;
|
|
}
|
|
|
|
if( mpBuffer )
|
|
{
|
|
const long nHeight = mpBuffer->mnHeight;
|
|
Scanline pTmpLine = mpBuffer->mpBits;
|
|
|
|
mpScanBuf = new Scanline[ nHeight ];
|
|
maColorMask = mpBuffer->maColorMask;
|
|
|
|
if( BMP_SCANLINE_ADJUSTMENT( mpBuffer->mnFormat ) == BMP_FORMAT_TOP_DOWN )
|
|
{
|
|
for( long nY = 0L; nY < nHeight; nY++, pTmpLine += mpBuffer->mnScanlineSize )
|
|
mpScanBuf[ nY ] = pTmpLine;
|
|
}
|
|
else
|
|
{
|
|
for( long nY = nHeight - 1; nY >= 0; nY--, pTmpLine += mpBuffer->mnScanlineSize )
|
|
mpScanBuf[ nY ] = pTmpLine;
|
|
}
|
|
|
|
if( !ImplSetAccessPointers( BMP_SCANLINE_FORMAT( mpBuffer->mnFormat ) ) )
|
|
{
|
|
delete[] mpScanBuf;
|
|
mpScanBuf = NULL;
|
|
|
|
pImpBmp->ImplReleaseBuffer( mpBuffer, !mbModify );
|
|
mpBuffer = NULL;
|
|
}
|
|
else
|
|
maBitmap = rBitmap;
|
|
}
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
void BitmapReadAccess::ImplDestroy()
|
|
{
|
|
ImpBitmap* pImpBmp = maBitmap.ImplGetImpBitmap();
|
|
|
|
delete[] mpScanBuf;
|
|
mpScanBuf = NULL;
|
|
|
|
if( mpBuffer && pImpBmp )
|
|
{
|
|
pImpBmp->ImplReleaseBuffer( mpBuffer, !mbModify );
|
|
mpBuffer = NULL;
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
sal_Bool BitmapReadAccess::ImplSetAccessPointers( sal_uLong nFormat )
|
|
{
|
|
sal_Bool bRet = sal_True;
|
|
|
|
switch( nFormat )
|
|
{
|
|
CASE_FORMAT( _1BIT_MSB_PAL )
|
|
CASE_FORMAT( _1BIT_LSB_PAL )
|
|
CASE_FORMAT( _4BIT_MSN_PAL )
|
|
CASE_FORMAT( _4BIT_LSN_PAL )
|
|
CASE_FORMAT( _8BIT_PAL )
|
|
CASE_FORMAT( _8BIT_TC_MASK )
|
|
CASE_FORMAT( _16BIT_TC_MSB_MASK )
|
|
CASE_FORMAT( _16BIT_TC_LSB_MASK )
|
|
CASE_FORMAT( _24BIT_TC_BGR )
|
|
CASE_FORMAT( _24BIT_TC_RGB )
|
|
CASE_FORMAT( _24BIT_TC_MASK )
|
|
CASE_FORMAT( _32BIT_TC_ABGR )
|
|
CASE_FORMAT( _32BIT_TC_ARGB )
|
|
CASE_FORMAT( _32BIT_TC_BGRA )
|
|
CASE_FORMAT( _32BIT_TC_RGBA )
|
|
CASE_FORMAT( _32BIT_TC_MASK )
|
|
|
|
default:
|
|
bRet = sal_False;
|
|
break;
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
void BitmapReadAccess::ImplZeroInitUnusedBits()
|
|
{
|
|
const sal_uInt32 nWidth = Width(), nHeight = Height(), nScanSize = GetScanlineSize();
|
|
|
|
if( nWidth && nHeight && nScanSize && GetBuffer() )
|
|
{
|
|
sal_uInt32 nBits;
|
|
bool bMsb;
|
|
|
|
const sal_uLong nScanlineFormat = GetScanlineFormat();
|
|
switch( nScanlineFormat )
|
|
{
|
|
case( BMP_FORMAT_1BIT_MSB_PAL ):
|
|
nBits = 1;
|
|
bMsb = true;
|
|
break;
|
|
|
|
case( BMP_FORMAT_1BIT_LSB_PAL ):
|
|
nBits = 1;
|
|
bMsb = false;
|
|
break;
|
|
|
|
case( BMP_FORMAT_4BIT_MSN_PAL ):
|
|
nBits = 4;
|
|
bMsb = true;
|
|
break;
|
|
|
|
case( BMP_FORMAT_4BIT_LSN_PAL ):
|
|
nBits = 4;
|
|
bMsb = false;
|
|
break;
|
|
|
|
case( BMP_FORMAT_8BIT_PAL ):
|
|
case( BMP_FORMAT_8BIT_TC_MASK ):
|
|
bMsb = true;
|
|
nBits = 8;
|
|
break;
|
|
|
|
case( BMP_FORMAT_16BIT_TC_MSB_MASK ):
|
|
case( BMP_FORMAT_16BIT_TC_LSB_MASK ):
|
|
bMsb = true;
|
|
nBits = 16;
|
|
break;
|
|
|
|
case( BMP_FORMAT_24BIT_TC_BGR ):
|
|
case( BMP_FORMAT_24BIT_TC_RGB ):
|
|
case( BMP_FORMAT_24BIT_TC_MASK ):
|
|
bMsb = true;
|
|
nBits = 24;
|
|
break;
|
|
|
|
case( BMP_FORMAT_32BIT_TC_ABGR ):
|
|
case( BMP_FORMAT_32BIT_TC_ARGB ):
|
|
case( BMP_FORMAT_32BIT_TC_BGRA ):
|
|
case( BMP_FORMAT_32BIT_TC_RGBA ):
|
|
case( BMP_FORMAT_32BIT_TC_MASK ):
|
|
bMsb = true;
|
|
nBits = 32;
|
|
break;
|
|
|
|
default:
|
|
{
|
|
OSL_FAIL( "BitmapWriteAccess::ZeroInitUnusedBits: Unsupported pixel format");
|
|
nBits = 0;
|
|
bMsb = true;
|
|
}
|
|
break;
|
|
}
|
|
|
|
nBits *= nWidth;
|
|
if( nScanSize % 4 || !bMsb )
|
|
{
|
|
DBG_ASSERT( 8*nScanSize >= nBits,
|
|
"BitmapWriteAccess::ZeroInitUnusedBits: span size smaller than width?!");
|
|
const sal_uInt32 nLeftOverBits = 8*sizeof(sal_uInt8)*nScanSize - nBits;
|
|
if( nLeftOverBits != 0 ) // else there is really nothing to do
|
|
{
|
|
const sal_uInt32 nBytes = (nLeftOverBits + 7U) >> 3U;
|
|
sal_uInt8 nMask;
|
|
|
|
if( bMsb )
|
|
nMask = static_cast<sal_uInt8>(0xffU << (nLeftOverBits & 3UL));
|
|
else
|
|
nMask = static_cast<sal_uInt8>(0xffU >> (nLeftOverBits & 3UL));
|
|
|
|
sal_uInt8* pLastBytes = (sal_uInt8*)GetBuffer() + ( nScanSize - nBytes );
|
|
for( sal_uInt32 i = 0; i < nHeight; i++, pLastBytes += nScanSize )
|
|
{
|
|
*pLastBytes &= nMask;
|
|
for( sal_uInt32 j = 1; j < nBytes; j++ )
|
|
pLastBytes[j] = 0;
|
|
}
|
|
}
|
|
}
|
|
else if( nBits & 0x1f )
|
|
{
|
|
sal_uInt32 nMask = 0xffffffff << ( ( nScanSize << 3 ) - nBits );
|
|
sal_uInt8* pLast4Bytes = (sal_uInt8*) GetBuffer() + ( nScanSize - 4 );
|
|
|
|
#ifdef OSL_LITENDIAN
|
|
nMask = SWAPLONG( nMask );
|
|
#endif
|
|
for( sal_uInt32 i = 0; i < nHeight; i++, pLast4Bytes += nScanSize )
|
|
( *(sal_uInt32*) pLast4Bytes ) &= nMask;
|
|
}
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
sal_uInt16 BitmapReadAccess::GetBestPaletteIndex( const BitmapColor& rBitmapColor ) const
|
|
{
|
|
return( HasPalette() ? mpBuffer->maPalette.GetBestIndex( rBitmapColor ) : 0 );
|
|
}
|
|
|
|
// ---------------------
|
|
// - BitmapWriteAccess -
|
|
// ---------------------
|
|
|
|
BitmapWriteAccess::BitmapWriteAccess( Bitmap& rBitmap ) :
|
|
BitmapReadAccess( rBitmap, sal_True ),
|
|
mpLineColor ( NULL ),
|
|
mpFillColor ( NULL )
|
|
{
|
|
}
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
BitmapWriteAccess::~BitmapWriteAccess()
|
|
{
|
|
delete mpLineColor;
|
|
delete mpFillColor;
|
|
}
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
void BitmapWriteAccess::CopyScanline( long nY, const BitmapReadAccess& rReadAcc )
|
|
{
|
|
DBG_ASSERT( ( nY >= 0 ) && ( nY < mpBuffer->mnHeight ), "y-coordinate in destination out of range!" );
|
|
DBG_ASSERT( nY < rReadAcc.Height(), "y-coordinate in source out of range!" );
|
|
DBG_ASSERT( ( HasPalette() && rReadAcc.HasPalette() ) || ( !HasPalette() && !rReadAcc.HasPalette() ), "No copying possible between palette bitmap and TC bitmap!" );
|
|
|
|
if( ( GetScanlineFormat() == rReadAcc.GetScanlineFormat() ) &&
|
|
( GetScanlineSize() >= rReadAcc.GetScanlineSize() ) )
|
|
{
|
|
memcpy( mpScanBuf[ nY ], rReadAcc.GetScanline( nY ), rReadAcc.GetScanlineSize() );
|
|
}
|
|
else
|
|
// TODO: use fastbmp infrastructure
|
|
for( long nX = 0L, nWidth = Min( mpBuffer->mnWidth, rReadAcc.Width() ); nX < nWidth; nX++ )
|
|
SetPixel( nY, nX, rReadAcc.GetPixel( nY, nX ) );
|
|
}
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
void BitmapWriteAccess::CopyScanline( long nY, ConstScanline aSrcScanline,
|
|
sal_uLong nSrcScanlineFormat, sal_uLong nSrcScanlineSize )
|
|
{
|
|
const sal_uLong nFormat = BMP_SCANLINE_FORMAT( nSrcScanlineFormat );
|
|
|
|
DBG_ASSERT( ( nY >= 0 ) && ( nY < mpBuffer->mnHeight ), "y-coordinate in destination out of range!" );
|
|
DBG_ASSERT( ( HasPalette() && nFormat <= BMP_FORMAT_8BIT_PAL ) ||
|
|
( !HasPalette() && nFormat > BMP_FORMAT_8BIT_PAL ),
|
|
"No copying possible between palette and non palette scanlines!" );
|
|
|
|
const sal_uLong nCount = Min( GetScanlineSize(), nSrcScanlineSize );
|
|
|
|
if( nCount )
|
|
{
|
|
if( GetScanlineFormat() == BMP_SCANLINE_FORMAT( nSrcScanlineFormat ) )
|
|
memcpy( mpScanBuf[ nY ], aSrcScanline, nCount );
|
|
else
|
|
{
|
|
DBG_ASSERT( nFormat != BMP_FORMAT_8BIT_TC_MASK &&
|
|
nFormat != BMP_FORMAT_16BIT_TC_MSB_MASK && nFormat != BMP_FORMAT_16BIT_TC_LSB_MASK &&
|
|
nFormat != BMP_FORMAT_24BIT_TC_MASK && nFormat != BMP_FORMAT_32BIT_TC_MASK,
|
|
"No support for pixel formats with color masks yet!" );
|
|
|
|
// TODO: use fastbmp infrastructure
|
|
FncGetPixel pFncGetPixel;
|
|
|
|
switch( nFormat )
|
|
{
|
|
case( BMP_FORMAT_1BIT_MSB_PAL ): pFncGetPixel = GetPixelFor_1BIT_MSB_PAL; break;
|
|
case( BMP_FORMAT_1BIT_LSB_PAL ): pFncGetPixel = GetPixelFor_1BIT_LSB_PAL; break;
|
|
case( BMP_FORMAT_4BIT_MSN_PAL ): pFncGetPixel = GetPixelFor_4BIT_MSN_PAL; break;
|
|
case( BMP_FORMAT_4BIT_LSN_PAL ): pFncGetPixel = GetPixelFor_4BIT_LSN_PAL; break;
|
|
case( BMP_FORMAT_8BIT_PAL ): pFncGetPixel = GetPixelFor_8BIT_PAL; break;
|
|
case( BMP_FORMAT_8BIT_TC_MASK ): pFncGetPixel = GetPixelFor_8BIT_TC_MASK; break;
|
|
case( BMP_FORMAT_16BIT_TC_MSB_MASK ): pFncGetPixel = GetPixelFor_16BIT_TC_MSB_MASK; break;
|
|
case( BMP_FORMAT_16BIT_TC_LSB_MASK ): pFncGetPixel = GetPixelFor_16BIT_TC_LSB_MASK; break;
|
|
case( BMP_FORMAT_24BIT_TC_BGR ): pFncGetPixel = GetPixelFor_24BIT_TC_BGR; break;
|
|
case( BMP_FORMAT_24BIT_TC_RGB ): pFncGetPixel = GetPixelFor_24BIT_TC_RGB; break;
|
|
case( BMP_FORMAT_24BIT_TC_MASK ): pFncGetPixel = GetPixelFor_24BIT_TC_MASK; break;
|
|
case( BMP_FORMAT_32BIT_TC_ABGR ): pFncGetPixel = GetPixelFor_32BIT_TC_ABGR; break;
|
|
case( BMP_FORMAT_32BIT_TC_ARGB ): pFncGetPixel = GetPixelFor_32BIT_TC_ARGB; break;
|
|
case( BMP_FORMAT_32BIT_TC_BGRA ): pFncGetPixel = GetPixelFor_32BIT_TC_BGRA; break;
|
|
case( BMP_FORMAT_32BIT_TC_RGBA ): pFncGetPixel = GetPixelFor_32BIT_TC_RGBA; break;
|
|
case( BMP_FORMAT_32BIT_TC_MASK ): pFncGetPixel = GetPixelFor_32BIT_TC_MASK; break;
|
|
|
|
default:
|
|
pFncGetPixel = NULL;
|
|
break;
|
|
}
|
|
|
|
if( pFncGetPixel )
|
|
{
|
|
const ColorMask aDummyMask;
|
|
|
|
for( long nX = 0L, nWidth = mpBuffer->mnWidth; nX < nWidth; nX++ )
|
|
SetPixel( nY, nX, pFncGetPixel( aSrcScanline, nX, aDummyMask ) );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
void BitmapWriteAccess::CopyBuffer( const BitmapReadAccess& rReadAcc )
|
|
{
|
|
DBG_ASSERT( ( HasPalette() && rReadAcc.HasPalette() ) || ( !HasPalette() && !rReadAcc.HasPalette() ), "No copying possible between palette bitmap and TC bitmap!" );
|
|
|
|
if( ( GetScanlineFormat() == rReadAcc.GetScanlineFormat() ) &&
|
|
( GetScanlineSize() == rReadAcc.GetScanlineSize() ) )
|
|
{
|
|
const long nHeight = Min( mpBuffer->mnHeight, rReadAcc.Height() );
|
|
const sal_uLong nCount = nHeight * mpBuffer->mnScanlineSize;
|
|
|
|
memcpy( mpBuffer->mpBits, rReadAcc.GetBuffer(), nCount );
|
|
}
|
|
else
|
|
for( long nY = 0L, nHeight = Min( mpBuffer->mnHeight, rReadAcc.Height() ); nY < nHeight; nY++ )
|
|
CopyScanline( nY, rReadAcc );
|
|
}
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|