blob: 82d157893691d3f49f7a0879c4c97cdc9c5d041c [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_forms.hxx"
#include "imgprod.hxx"
#include <vcl/bmpacc.hxx>
#include <vcl/cvtgrf.hxx>
#include <vcl/svapp.hxx>
#include <unotools/ucbstreamhelper.hxx>
#include <svtools/filter.hxx>
#include <com/sun/star/io/XInputStream.hpp>
#ifndef SVTOOLS_SOURCE_MISC_IMAGERESOURCEACCESS_HXX
#include "svtools/imageresourceaccess.hxx"
#endif
#include <comphelper/processfactory.hxx>
// --------------------
// - ImgProdLockBytes -
// --------------------
class ImgProdLockBytes : public SvLockBytes
{
::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream > xStmRef;
::com::sun::star::uno::Sequence<sal_Int8> maSeq;
ImgProdLockBytes() {};
public:
ImgProdLockBytes( SvStream* pStm, sal_Bool bOwner );
ImgProdLockBytes( ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream > & rStreamRef );
virtual ~ImgProdLockBytes();
virtual ErrCode ReadAt( sal_Size nPos, void* pBuffer, sal_Size nCount, sal_Size* pRead ) const;
virtual ErrCode WriteAt( sal_Size nPos, const void* pBuffer, sal_Size nCount, sal_Size* pWritten );
virtual ErrCode Flush() const;
virtual ErrCode SetSize( sal_Size nSize );
virtual ErrCode Stat( SvLockBytesStat*, SvLockBytesStatFlag ) const;
};
// ------------------------------------------------------------------------
ImgProdLockBytes::ImgProdLockBytes( SvStream* pStm, sal_Bool bOwner ) :
SvLockBytes( pStm, bOwner )
{
}
// ------------------------------------------------------------------------
ImgProdLockBytes::ImgProdLockBytes( ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream > & rStmRef ) :
xStmRef( rStmRef )
{
if( xStmRef.is() )
{
const sal_uInt32 nBytesToRead = 65535;
sal_uInt32 nRead;
do
{
::com::sun::star::uno::Sequence< sal_Int8 > aReadSeq;
nRead = xStmRef->readSomeBytes( aReadSeq, nBytesToRead );
if( nRead )
{
const sal_uInt32 nOldLength = maSeq.getLength();
maSeq.realloc( nOldLength + nRead );
rtl_copyMemory( maSeq.getArray() + nOldLength, aReadSeq.getConstArray(), aReadSeq.getLength() );
}
}
while( nBytesToRead == nRead );
}
}
// ------------------------------------------------------------------------
ImgProdLockBytes::~ImgProdLockBytes()
{
}
// ------------------------------------------------------------------------
ErrCode ImgProdLockBytes::ReadAt( sal_Size nPos, void* pBuffer, sal_Size nCount, sal_Size* pRead ) const
{
if( GetStream() )
{
( (SvStream*) GetStream() )->ResetError();
const ErrCode nErr = SvLockBytes::ReadAt( nPos, pBuffer, nCount, pRead );
( (SvStream*) GetStream() )->ResetError();
return nErr;
}
else
{
const sal_Size nSeqLen = maSeq.getLength();
ErrCode nErr = ERRCODE_NONE;
if( nPos < nSeqLen )
{
if( ( nPos + nCount ) > nSeqLen )
nCount = nSeqLen - nPos;
memcpy( pBuffer, maSeq.getConstArray() + nPos, nCount );
*pRead = nCount;
}
else
*pRead = 0UL;
return nErr;
}
}
// ------------------------------------------------------------------------
ErrCode ImgProdLockBytes::WriteAt( sal_Size nPos, const void* pBuffer, sal_Size nCount, sal_Size* pWritten )
{
if( GetStream() )
return SvLockBytes::WriteAt( nPos, pBuffer, nCount, pWritten );
else
{
DBG_ASSERT( xStmRef.is(), "ImgProdLockBytes::WriteAt: xInputStream has no reference..." );
return ERRCODE_IO_CANTWRITE;
}
}
// ------------------------------------------------------------------------
ErrCode ImgProdLockBytes::Flush() const
{
return ERRCODE_NONE;
}
// ------------------------------------------------------------------------
ErrCode ImgProdLockBytes::SetSize( sal_Size nSize )
{
if( GetStream() )
return SvLockBytes::SetSize( nSize );
else
{
DBG_ERROR( "ImgProdLockBytes::SetSize not supported for xInputStream..." );
return ERRCODE_IO_CANTWRITE;
}
}
// ------------------------------------------------------------------------
ErrCode ImgProdLockBytes::Stat( SvLockBytesStat* pStat, SvLockBytesStatFlag eFlag ) const
{
if( GetStream() )
return SvLockBytes::Stat( pStat, eFlag );
else
{
DBG_ASSERT( xStmRef.is(), "ImgProdLockBytes::Stat: xInputStream has no reference..." );
pStat->nSize = maSeq.getLength();
return ERRCODE_NONE;
}
}
// -----------------
// - ImageProducer -
// -----------------
ImageProducer::ImageProducer() :
mpStm ( NULL ),
mbConsInit ( sal_False )
{
mpGraphic = new Graphic;
DBG_ASSERT( Application::GetFilterHdl().IsSet(), "ImageProducer::ImageProducer(): No filter handler set" );
}
// ------------------------------------------------------------
ImageProducer::~ImageProducer()
{
delete mpGraphic;
mpGraphic = NULL;
delete mpStm;
mpStm = NULL;
for( void* pCons = maConsList.First(); pCons; pCons = maConsList.Next() )
delete (::com::sun::star::uno::Reference< ::com::sun::star::awt::XImageConsumer > *) pCons;
}
// ------------------------------------------------------------
// ::com::sun::star::uno::XInterface
::com::sun::star::uno::Any ImageProducer::queryInterface( const ::com::sun::star::uno::Type & rType ) throw(::com::sun::star::uno::RuntimeException)
{
::com::sun::star::uno::Any aRet = ::cppu::queryInterface( rType,
SAL_STATIC_CAST( ::com::sun::star::lang::XInitialization*, this ),
SAL_STATIC_CAST( ::com::sun::star::awt::XImageProducer*, this ) );
return (aRet.hasValue() ? aRet : OWeakObject::queryInterface( rType ));
}
// ------------------------------------------------------------
void ImageProducer::addConsumer( const ::com::sun::star::uno::Reference< ::com::sun::star::awt::XImageConsumer >& rxConsumer ) throw(::com::sun::star::uno::RuntimeException)
{
DBG_ASSERT( rxConsumer.is(), "::AddConsumer(...): No consumer referenced!" );
if( rxConsumer.is() )
maConsList.Insert( new ::com::sun::star::uno::Reference< ::com::sun::star::awt::XImageConsumer > ( rxConsumer ), LIST_APPEND );
}
// ------------------------------------------------------------
void ImageProducer::removeConsumer( const ::com::sun::star::uno::Reference< ::com::sun::star::awt::XImageConsumer >& rxConsumer ) throw(::com::sun::star::uno::RuntimeException)
{
for( sal_uInt32 n = maConsList.Count(); n; )
{
::com::sun::star::uno::Reference< ::com::sun::star::awt::XImageConsumer > * pRef = (::com::sun::star::uno::Reference< ::com::sun::star::awt::XImageConsumer > *) maConsList.GetObject( --n );
if( *pRef == rxConsumer )
{
delete pRef;
maConsList.Remove( n );
break;
}
}
}
// ------------------------------------------------------------
void ImageProducer::SetImage( const ::rtl::OUString& rPath )
{
maURL = rPath;
mpGraphic->Clear();
mbConsInit = sal_False;
delete mpStm;
if ( ::svt::GraphicAccess::isSupportedURL( maURL ) )
{
mpStm = ::svt::GraphicAccess::getImageStream( ::comphelper::getProcessServiceFactory(), maURL );
}
else if( maURL.getLength() )
{
SvStream* pIStm = ::utl::UcbStreamHelper::CreateStream( maURL, STREAM_STD_READ );
mpStm = pIStm ? new SvStream( new ImgProdLockBytes( pIStm, sal_True ) ) : NULL;
}
else
mpStm = NULL;
}
// ------------------------------------------------------------
void ImageProducer::SetImage( SvStream& rStm )
{
maURL = ::rtl::OUString();
mpGraphic->Clear();
mbConsInit = sal_False;
delete mpStm;
mpStm = new SvStream( new ImgProdLockBytes( &rStm, sal_False ) );
}
// ------------------------------------------------------------
void ImageProducer::setImage( ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream > & rInputStmRef )
{
maURL = ::rtl::OUString();
mpGraphic->Clear();
mbConsInit = sal_False;
delete mpStm;
if( rInputStmRef.is() )
mpStm = new SvStream( new ImgProdLockBytes( rInputStmRef ) );
else
mpStm = NULL;
}
// ------------------------------------------------------------
void ImageProducer::NewDataAvailable()
{
if( ( GRAPHIC_NONE == mpGraphic->GetType() ) || mpGraphic->GetContext() )
startProduction();
}
// ------------------------------------------------------------
void ImageProducer::startProduction() throw(::com::sun::star::uno::RuntimeException)
{
if( maConsList.Count() || maDoneHdl.IsSet() )
{
bool bNotifyEmptyGraphics = false;
// valid stream or filled graphic? => update consumers
if( mpStm || ( mpGraphic->GetType() != GRAPHIC_NONE ) )
{
// if we already have a graphic, we don't have to import again;
// graphic is cleared if a new Stream is set
if( ( mpGraphic->GetType() == GRAPHIC_NONE ) || mpGraphic->GetContext() )
{
if ( ImplImportGraphic( *mpGraphic ) && maDoneHdl.IsSet() )
maDoneHdl.Call( mpGraphic );
}
if( mpGraphic->GetType() != GRAPHIC_NONE )
ImplUpdateData( *mpGraphic );
else
bNotifyEmptyGraphics = true;
}
else
bNotifyEmptyGraphics = true;
if ( bNotifyEmptyGraphics )
{
// reset image
List aTmp;
void* pCons;
// create temporary list to hold interfaces
for( pCons = maConsList.First(); pCons; pCons = maConsList.Next() )
aTmp.Insert( new ::com::sun::star::uno::Reference< ::com::sun::star::awt::XImageConsumer > ( *(::com::sun::star::uno::Reference< ::com::sun::star::awt::XImageConsumer > *) pCons ), LIST_APPEND );
// iterate through interfaces
for( pCons = aTmp.First(); pCons; pCons = aTmp.Next() )
{
( *(::com::sun::star::uno::Reference< ::com::sun::star::awt::XImageConsumer > *) pCons )->init( 0, 0 );
( *(::com::sun::star::uno::Reference< ::com::sun::star::awt::XImageConsumer > *) pCons )->complete( ::com::sun::star::awt::ImageStatus::IMAGESTATUS_STATICIMAGEDONE, this );
}
// delete interfaces in temporary list
for( pCons = aTmp.First(); pCons; pCons = aTmp.Next() )
delete (::com::sun::star::uno::Reference< ::com::sun::star::awt::XImageConsumer > *) pCons;
if ( maDoneHdl.IsSet() )
maDoneHdl.Call( NULL );
}
}
}
// ------------------------------------------------------------
sal_Bool ImageProducer::ImplImportGraphic( Graphic& rGraphic )
{
if( ERRCODE_IO_PENDING == mpStm->GetError() )
mpStm->ResetError();
mpStm->Seek( 0UL );
sal_Bool bRet = GraphicConverter::Import( *mpStm, rGraphic ) == ERRCODE_NONE;
if( ERRCODE_IO_PENDING == mpStm->GetError() )
mpStm->ResetError();
return bRet;
}
// ------------------------------------------------------------
void ImageProducer::ImplUpdateData( const Graphic& rGraphic )
{
ImplInitConsumer( rGraphic );
if( mbConsInit && maConsList.Count() )
{
List aTmp;
void* pCons;
ImplUpdateConsumer( rGraphic );
mbConsInit = sal_False;
// create temporary list to hold interfaces
for( pCons = maConsList.First(); pCons; pCons = maConsList.Next() )
aTmp.Insert( new ::com::sun::star::uno::Reference< ::com::sun::star::awt::XImageConsumer > ( *(::com::sun::star::uno::Reference< ::com::sun::star::awt::XImageConsumer > *) pCons ), LIST_APPEND );
// iterate through interfaces
for( pCons = aTmp.First(); pCons; pCons = aTmp.Next() )
( *(::com::sun::star::uno::Reference< ::com::sun::star::awt::XImageConsumer > *) pCons )->complete( ::com::sun::star::awt::ImageStatus::IMAGESTATUS_STATICIMAGEDONE, this );
// delete interfaces in temporary list
for( pCons = aTmp.First(); pCons; pCons = aTmp.Next() )
delete (::com::sun::star::uno::Reference< ::com::sun::star::awt::XImageConsumer > *) pCons;
}
}
// ------------------------------------------------------------
void ImageProducer::ImplInitConsumer( const Graphic& rGraphic )
{
Bitmap aBmp( rGraphic.GetBitmapEx().GetBitmap() );
BitmapReadAccess* pBmpAcc = aBmp.AcquireReadAccess();
if( pBmpAcc )
{
List aTmp;
void * pCons;
sal_uInt16 nPalCount = 0;
sal_uInt32 nRMask = 0;
sal_uInt32 nGMask = 0;
sal_uInt32 nBMask = 0;
sal_uInt32 nAMask = 0;
::com::sun::star::uno::Sequence< sal_Int32 > aRGBPal;
if( pBmpAcc->HasPalette() )
{
nPalCount = pBmpAcc->GetPaletteEntryCount();
if( nPalCount )
{
aRGBPal = ::com::sun::star::uno::Sequence< sal_Int32 >( nPalCount + 1 );
sal_Int32* pTmp = aRGBPal.getArray();
for( sal_uInt32 i = 0; i < nPalCount; i++, pTmp++ )
{
const BitmapColor& rCol = pBmpAcc->GetPaletteColor( (sal_uInt16) i );
*pTmp = ( (sal_Int32) rCol.GetRed() ) << (sal_Int32)(24L);
*pTmp |= ( (sal_Int32) rCol.GetGreen() ) << (sal_Int32)(16L);
*pTmp |= ( (sal_Int32) rCol.GetBlue() ) << (sal_Int32)(8L);
*pTmp |= (sal_Int32)(0x000000ffL);
}
if( rGraphic.IsTransparent() )
{
// append transparent entry
*pTmp = (sal_Int32)(0xffffff00L);
mnTransIndex = nPalCount;
nPalCount++;
}
else
mnTransIndex = 0;
}
}
else
{
nRMask = 0xff000000UL;
nGMask = 0x00ff0000UL;
nBMask = 0x0000ff00UL;
nAMask = 0x000000ffUL;
}
// create temporary list to hold interfaces
for( pCons = maConsList.First(); pCons; pCons = maConsList.Next() )
aTmp.Insert( new ::com::sun::star::uno::Reference< ::com::sun::star::awt::XImageConsumer > ( *(::com::sun::star::uno::Reference< ::com::sun::star::awt::XImageConsumer > *) pCons ), LIST_APPEND );
// iterate through interfaces
for( pCons = aTmp.First(); pCons; pCons = aTmp.Next() )
{
( *(::com::sun::star::uno::Reference< ::com::sun::star::awt::XImageConsumer > *) pCons )->init( pBmpAcc->Width(), pBmpAcc->Height() );
( *(::com::sun::star::uno::Reference< ::com::sun::star::awt::XImageConsumer > *) pCons )->setColorModel( pBmpAcc->GetBitCount(),
aRGBPal, nRMask, nGMask, nBMask, nAMask );
}
// delete interfaces in temporary list
for( pCons = aTmp.First(); pCons; pCons = aTmp.Next() )
delete (::com::sun::star::uno::Reference< ::com::sun::star::awt::XImageConsumer > *) pCons;
aBmp.ReleaseAccess( pBmpAcc );
mbConsInit = sal_True;
}
}
// ------------------------------------------------------------
void ImageProducer::ImplUpdateConsumer( const Graphic& rGraphic )
{
BitmapEx aBmpEx( rGraphic.GetBitmapEx() );
Bitmap aBmp( aBmpEx.GetBitmap() );
BitmapReadAccess* pBmpAcc = aBmp.AcquireReadAccess();
if( pBmpAcc )
{
List aTmp;
void* pCons;
Bitmap aMask( aBmpEx.GetMask() );
BitmapReadAccess* pMskAcc = !!aMask ? aMask.AcquireReadAccess() : NULL;
const long nWidth = pBmpAcc->Width();
const long nHeight = pBmpAcc->Height();
const long nStartX = 0L;
const long nEndX = nWidth - 1L;
const long nStartY = 0L;
const long nEndY = nHeight - 1L;
const long nPartWidth = nEndX - nStartX + 1;
const long nPartHeight = nEndY - nStartY + 1;
if( !pMskAcc )
{
aMask = Bitmap( aBmp.GetSizePixel(), 1 );
aMask.Erase( COL_BLACK );
pMskAcc = aMask.AcquireReadAccess();
}
// create temporary list to hold interfaces
for( pCons = maConsList.First(); pCons; pCons = maConsList.Next() )
aTmp.Insert( new ::com::sun::star::uno::Reference< ::com::sun::star::awt::XImageConsumer > ( *(::com::sun::star::uno::Reference< ::com::sun::star::awt::XImageConsumer > *) pCons ), LIST_APPEND );
if( pBmpAcc->HasPalette() )
{
const BitmapColor aWhite( pMskAcc->GetBestMatchingColor( Color( COL_WHITE ) ) );
if( mnTransIndex < 256 )
{
::com::sun::star::uno::Sequence<sal_Int8> aData( nPartWidth * nPartHeight );
sal_Int8* pTmp = aData.getArray();
for( long nY = nStartY; nY <= nEndY; nY++ )
{
for( long nX = nStartX; nX <= nEndX; nX++ )
{
if( pMskAcc->GetPixel( nY, nX ) == aWhite )
*pTmp++ = sal::static_int_cast< sal_Int8 >(
mnTransIndex );
else
*pTmp++ = pBmpAcc->GetPixel( nY, nX ).GetIndex();
}
}
// iterate through interfaces
for( pCons = aTmp.First(); pCons; pCons = aTmp.Next() )
( *(::com::sun::star::uno::Reference< ::com::sun::star::awt::XImageConsumer > *) pCons )->setPixelsByBytes( nStartX, nStartY, nPartWidth, nPartHeight,
aData, 0UL, nPartWidth );
}
else
{
::com::sun::star::uno::Sequence<sal_Int32> aData( nPartWidth * nPartHeight );
sal_Int32* pTmp = aData.getArray();
for( long nY = nStartY; nY <= nEndY; nY++ )
{
for( long nX = nStartX; nX <= nEndX; nX++ )
{
if( pMskAcc->GetPixel( nY, nX ) == aWhite )
*pTmp++ = mnTransIndex;
else
*pTmp++ = pBmpAcc->GetPixel( nY, nX ).GetIndex();
}
}
// iterate through interfaces
for( pCons = aTmp.First(); pCons; pCons = aTmp.Next() )
( *(::com::sun::star::uno::Reference< ::com::sun::star::awt::XImageConsumer > *) pCons )->setPixelsByLongs( nStartX, nStartY, nPartWidth, nPartHeight,
aData, 0UL, nPartWidth );
}
}
else
{
::com::sun::star::uno::Sequence<sal_Int32> aData( nPartWidth * nPartHeight );
const BitmapColor aWhite( pMskAcc->GetBestMatchingColor( Color( COL_WHITE ) ) );
sal_Int32* pTmp = aData.getArray();
for( long nY = nStartY; nY <= nEndY; nY++ )
{
for( long nX = nStartX; nX <= nEndX; nX++, pTmp++ )
{
const BitmapColor aCol( pBmpAcc->GetPixel( nY, nX ) );
*pTmp = ( (sal_Int32) aCol.GetRed() ) << (sal_Int32)(24L);
*pTmp |= ( (sal_Int32) aCol.GetGreen() ) << (sal_Int32)(16L);
*pTmp |= ( (sal_Int32) aCol.GetBlue() ) << (sal_Int32)(8L);
if( pMskAcc->GetPixel( nY, nX ) != aWhite )
*pTmp |= 0x000000ffUL;
}
}
// iterate through interfaces
for( pCons = aTmp.First(); pCons; pCons = aTmp.Next() )
( *(::com::sun::star::uno::Reference< ::com::sun::star::awt::XImageConsumer > *) pCons )->setPixelsByLongs( nStartX, nStartY, nPartWidth, nPartHeight,
aData, 0UL, nPartWidth );
}
// delete interfaces in temporary list
for( pCons = aTmp.First(); pCons; pCons = aTmp.Next() )
delete (::com::sun::star::uno::Reference< ::com::sun::star::awt::XImageConsumer > *) pCons;
aBmp.ReleaseAccess( pBmpAcc );
aMask.ReleaseAccess( pMskAcc );
}
}
void ImageProducer::initialize( const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any >& aArguments ) throw (::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException)
{
if ( aArguments.getLength() == 1 )
{
::com::sun::star::uno::Any aArg = aArguments.getConstArray()[0];
rtl::OUString aURL;
if ( aArg >>= aURL )
{
SetImage( aURL );
}
}
}
namespace frm
{
::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >
SAL_CALL ImageProducer_CreateInstance(
const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& )
{
return ::com::sun::star::uno::Reference < ::com::sun::star::uno::XInterface >(
( ::cppu::OWeakObject* ) new ImageProducer );
}
} // namespace frm