1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "imgprod.hxx"
21 #include "services.hxx"
23 #include <vcl/bmpacc.hxx>
24 #include <vcl/cvtgrf.hxx>
25 #include <vcl/svapp.hxx>
26 #include <unotools/ucbstreamhelper.hxx>
27 #include <vcl/graphicfilter.hxx>
28 #include <cppuhelper/queryinterface.hxx>
29 #include <com/sun/star/io/XInputStream.hpp>
30 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
32 #include "svtools/imageresourceaccess.hxx"
33 #include <comphelper/processfactory.hxx>
35 // - ImgProdLockBytes -
38 class ImgProdLockBytes
: public SvLockBytes
40 ::com::sun::star::uno::Reference
< ::com::sun::star::io::XInputStream
> xStmRef
;
41 ::com::sun::star::uno::Sequence
<sal_Int8
> maSeq
;
45 ImgProdLockBytes( SvStream
* pStm
, bool bOwner
);
46 ImgProdLockBytes( ::com::sun::star::uno::Reference
< ::com::sun::star::io::XInputStream
> & rStreamRef
);
47 virtual ~ImgProdLockBytes();
49 virtual ErrCode
ReadAt( sal_uInt64 nPos
, void* pBuffer
, sal_Size nCount
, sal_Size
* pRead
) const SAL_OVERRIDE
;
50 virtual ErrCode
WriteAt( sal_uInt64 nPos
, const void* pBuffer
, sal_Size nCount
, sal_Size
* pWritten
) SAL_OVERRIDE
;
51 virtual ErrCode
Flush() const SAL_OVERRIDE
;
52 virtual ErrCode
SetSize( sal_uInt64 nSize
) SAL_OVERRIDE
;
53 virtual ErrCode
Stat( SvLockBytesStat
*, SvLockBytesStatFlag
) const SAL_OVERRIDE
;
58 ImgProdLockBytes::ImgProdLockBytes( SvStream
* pStm
, bool bOwner
) :
59 SvLockBytes( pStm
, bOwner
)
65 ImgProdLockBytes::ImgProdLockBytes( ::com::sun::star::uno::Reference
< ::com::sun::star::io::XInputStream
> & rStmRef
) :
70 const sal_uInt32 nBytesToRead
= 65535;
75 ::com::sun::star::uno::Sequence
< sal_Int8
> aReadSeq
;
77 nRead
= xStmRef
->readSomeBytes( aReadSeq
, nBytesToRead
);
81 const sal_uInt32 nOldLength
= maSeq
.getLength();
82 maSeq
.realloc( nOldLength
+ nRead
);
83 memcpy( maSeq
.getArray() + nOldLength
, aReadSeq
.getConstArray(), aReadSeq
.getLength() );
86 while( nBytesToRead
== nRead
);
92 ImgProdLockBytes::~ImgProdLockBytes()
96 ErrCode
ImgProdLockBytes::ReadAt(sal_uInt64
const nPos
,
97 void* pBuffer
, sal_Size nCount
, sal_Size
* pRead
) const
101 const_cast<SvStream
*>(GetStream())->ResetError();
102 const ErrCode nErr
= SvLockBytes::ReadAt( nPos
, pBuffer
, nCount
, pRead
);
103 const_cast<SvStream
*>(GetStream())->ResetError();
108 const sal_Size nSeqLen
= maSeq
.getLength();
109 ErrCode nErr
= ERRCODE_NONE
;
113 if( ( nPos
+ nCount
) > nSeqLen
)
114 nCount
= nSeqLen
- nPos
;
116 memcpy( pBuffer
, maSeq
.getConstArray() + nPos
, nCount
);
126 ErrCode
ImgProdLockBytes::WriteAt(sal_uInt64
const nPos
,
127 const void* pBuffer
, sal_Size nCount
, sal_Size
* pWritten
)
130 return SvLockBytes::WriteAt( nPos
, pBuffer
, nCount
, pWritten
);
133 DBG_ASSERT( xStmRef
.is(), "ImgProdLockBytes::WriteAt: xInputStream has no reference..." );
134 return ERRCODE_IO_CANTWRITE
;
140 ErrCode
ImgProdLockBytes::Flush() const
147 ErrCode
ImgProdLockBytes::SetSize(sal_uInt64
const nSize
)
150 return SvLockBytes::SetSize( nSize
);
153 OSL_FAIL( "ImgProdLockBytes::SetSize not supported for xInputStream..." );
154 return ERRCODE_IO_CANTWRITE
;
160 ErrCode
ImgProdLockBytes::Stat( SvLockBytesStat
* pStat
, SvLockBytesStatFlag eFlag
) const
163 return SvLockBytes::Stat( pStat
, eFlag
);
166 DBG_ASSERT( xStmRef
.is(), "ImgProdLockBytes::Stat: xInputStream has no reference..." );
167 pStat
->nSize
= maSeq
.getLength();
173 ImageProducer::ImageProducer()
178 mpGraphic
= new Graphic
;
181 ImageProducer::~ImageProducer()
190 // ::com::sun::star::uno::XInterface
191 ::com::sun::star::uno::Any
ImageProducer::queryInterface( const ::com::sun::star::uno::Type
& rType
) throw(::com::sun::star::uno::RuntimeException
, std::exception
)
193 ::com::sun::star::uno::Any aRet
= ::cppu::queryInterface( rType
,
194 (static_cast< ::com::sun::star::lang::XInitialization
* >(this)),
195 (static_cast< ::com::sun::star::awt::XImageProducer
* >(this)) );
196 return (aRet
.hasValue() ? aRet
: OWeakObject::queryInterface( rType
));
201 void ImageProducer::addConsumer( const ::com::sun::star::uno::Reference
< ::com::sun::star::awt::XImageConsumer
>& rxConsumer
)
202 throw(::com::sun::star::uno::RuntimeException
,
205 DBG_ASSERT( rxConsumer
.is(), "::AddConsumer(...): No consumer referenced!" );
206 if( rxConsumer
.is() )
207 maConsList
.push_back( new ::com::sun::star::uno::Reference
< ::com::sun::star::awt::XImageConsumer
> ( rxConsumer
));
212 void ImageProducer::removeConsumer( const ::com::sun::star::uno::Reference
< ::com::sun::star::awt::XImageConsumer
>& rxConsumer
) throw(::com::sun::star::uno::RuntimeException
, std::exception
)
214 ConsumerList_t::reverse_iterator riter
= std::find(maConsList
.rbegin(),maConsList
.rend(),rxConsumer
);
216 if (riter
!= maConsList
.rend())
217 maConsList
.erase(riter
.base()-1);
222 void ImageProducer::SetImage( const OUString
& rPath
)
229 if ( ::svt::GraphicAccess::isSupportedURL( maURL
) )
231 mpStm
= ::svt::GraphicAccess::getImageStream( ::comphelper::getProcessComponentContext(), maURL
);
233 else if( !maURL
.isEmpty() )
235 SvStream
* pIStm
= ::utl::UcbStreamHelper::CreateStream( maURL
, STREAM_STD_READ
);
236 mpStm
= pIStm
? new SvStream( new ImgProdLockBytes( pIStm
, true ) ) : NULL
;
244 void ImageProducer::SetImage( SvStream
& rStm
)
251 mpStm
= new SvStream( new ImgProdLockBytes( &rStm
, false ) );
256 void ImageProducer::setImage( ::com::sun::star::uno::Reference
< ::com::sun::star::io::XInputStream
> & rInputStmRef
)
263 if( rInputStmRef
.is() )
264 mpStm
= new SvStream( new ImgProdLockBytes( rInputStmRef
) );
271 void ImageProducer::NewDataAvailable()
273 if( ( GRAPHIC_NONE
== mpGraphic
->GetType() ) || mpGraphic
->GetContext() )
279 void ImageProducer::startProduction() throw(::com::sun::star::uno::RuntimeException
, std::exception
)
281 if( !maConsList
.empty() || maDoneHdl
.IsSet() )
283 bool bNotifyEmptyGraphics
= false;
285 // valid stream or filled graphic? => update consumers
286 if( mpStm
|| ( mpGraphic
->GetType() != GRAPHIC_NONE
) )
288 // if we already have a graphic, we don't have to import again;
289 // graphic is cleared if a new Stream is set
290 if( ( mpGraphic
->GetType() == GRAPHIC_NONE
) || mpGraphic
->GetContext() )
292 if ( ImplImportGraphic( *mpGraphic
) && maDoneHdl
.IsSet() )
293 maDoneHdl
.Call( mpGraphic
);
296 if( mpGraphic
->GetType() != GRAPHIC_NONE
)
297 ImplUpdateData( *mpGraphic
);
299 bNotifyEmptyGraphics
= true;
302 bNotifyEmptyGraphics
= true;
304 if ( bNotifyEmptyGraphics
)
307 // create temporary list to hold interfaces
308 ConsumerList_t aTmp
= maConsList
;
310 // iterate through interfaces
311 for( ConsumerList_t::iterator iter
= aTmp
.begin(); iter
!= aTmp
.end(); ++iter
)
313 (*iter
)->init( 0, 0 );
314 (*iter
)->complete( ::com::sun::star::awt::ImageStatus::IMAGESTATUS_STATICIMAGEDONE
, this );
317 if ( maDoneHdl
.IsSet() )
318 maDoneHdl
.Call( NULL
);
325 bool ImageProducer::ImplImportGraphic( Graphic
& rGraphic
)
330 if( ERRCODE_IO_PENDING
== mpStm
->GetError() )
335 bool bRet
= GraphicConverter::Import( *mpStm
, rGraphic
) == ERRCODE_NONE
;
337 if( ERRCODE_IO_PENDING
== mpStm
->GetError() )
345 void ImageProducer::ImplUpdateData( const Graphic
& rGraphic
)
347 ImplInitConsumer( rGraphic
);
349 if( mbConsInit
&& !maConsList
.empty() )
351 // create temporary list to hold interfaces
352 ConsumerList_t aTmp
= maConsList
;
354 ImplUpdateConsumer( rGraphic
);
357 // iterate through interfaces
358 for( ConsumerList_t::iterator iter
= aTmp
.begin(); iter
!= aTmp
.end(); ++iter
)
359 (*iter
)->complete( ::com::sun::star::awt::ImageStatus::IMAGESTATUS_STATICIMAGEDONE
, this );
365 void ImageProducer::ImplInitConsumer( const Graphic
& rGraphic
)
367 Bitmap
aBmp( rGraphic
.GetBitmapEx().GetBitmap() );
368 BitmapReadAccess
* pBmpAcc
= aBmp
.AcquireReadAccess();
372 sal_uInt16 nPalCount
= 0;
373 sal_uInt32 nRMask
= 0;
374 sal_uInt32 nGMask
= 0;
375 sal_uInt32 nBMask
= 0;
376 sal_uInt32 nAMask
= 0;
377 ::com::sun::star::uno::Sequence
< sal_Int32
> aRGBPal
;
379 if( pBmpAcc
->HasPalette() )
381 nPalCount
= pBmpAcc
->GetPaletteEntryCount();
385 aRGBPal
= ::com::sun::star::uno::Sequence
< sal_Int32
>( nPalCount
+ 1 );
387 sal_Int32
* pTmp
= aRGBPal
.getArray();
389 for( sal_uInt32 i
= 0; i
< nPalCount
; i
++, pTmp
++ )
391 const BitmapColor
& rCol
= pBmpAcc
->GetPaletteColor( (sal_uInt16
) i
);
393 *pTmp
= ( (sal_Int32
) rCol
.GetRed() ) << (sal_Int32
)(24L);
394 *pTmp
|= ( (sal_Int32
) rCol
.GetGreen() ) << (sal_Int32
)(16L);
395 *pTmp
|= ( (sal_Int32
) rCol
.GetBlue() ) << (sal_Int32
)(8L);
396 *pTmp
|= (sal_Int32
)(0x000000ffL
);
399 if( rGraphic
.IsTransparent() )
401 // append transparent entry
402 *pTmp
= (sal_Int32
)(0xffffff00L
);
403 mnTransIndex
= nPalCount
;
413 nRMask
= 0xff000000UL
;
414 nGMask
= 0x00ff0000UL
;
415 nBMask
= 0x0000ff00UL
;
416 nAMask
= 0x000000ffUL
;
419 // create temporary list to hold interfaces
420 ConsumerList_t aTmp
= maConsList
;
422 // iterate through interfaces
423 for( ConsumerList_t::iterator iter
= aTmp
.begin(); iter
!= aTmp
.end(); ++iter
)
425 (*iter
)->init( pBmpAcc
->Width(), pBmpAcc
->Height() );
426 (*iter
)->setColorModel( pBmpAcc
->GetBitCount(),aRGBPal
, nRMask
, nGMask
, nBMask
, nAMask
);
429 Bitmap::ReleaseAccess( pBmpAcc
);
436 void ImageProducer::ImplUpdateConsumer( const Graphic
& rGraphic
)
438 BitmapEx
aBmpEx( rGraphic
.GetBitmapEx() );
439 Bitmap
aBmp( aBmpEx
.GetBitmap() );
440 BitmapReadAccess
* pBmpAcc
= aBmp
.AcquireReadAccess();
444 Bitmap
aMask( aBmpEx
.GetMask() );
445 BitmapReadAccess
* pMskAcc
= !!aMask
? aMask
.AcquireReadAccess() : NULL
;
446 const long nWidth
= pBmpAcc
->Width();
447 const long nHeight
= pBmpAcc
->Height();
448 const long nStartX
= 0L;
449 const long nEndX
= nWidth
- 1L;
450 const long nStartY
= 0L;
451 const long nEndY
= nHeight
- 1L;
452 const long nPartWidth
= nEndX
- nStartX
+ 1;
453 const long nPartHeight
= nEndY
- nStartY
+ 1;
457 aMask
= Bitmap( aBmp
.GetSizePixel(), 1 );
458 aMask
.Erase( COL_BLACK
);
459 pMskAcc
= aMask
.AcquireReadAccess();
462 // create temporary list to hold interfaces
463 ConsumerList_t aTmp
= maConsList
;
465 if( pBmpAcc
->HasPalette() )
467 const BitmapColor
aWhite( pMskAcc
->GetBestMatchingColor( Color( COL_WHITE
) ) );
469 if( mnTransIndex
< 256 )
471 ::com::sun::star::uno::Sequence
<sal_Int8
> aData( nPartWidth
* nPartHeight
);
472 sal_Int8
* pTmp
= aData
.getArray();
474 for( long nY
= nStartY
; nY
<= nEndY
; nY
++ )
476 for( long nX
= nStartX
; nX
<= nEndX
; nX
++ )
478 if( pMskAcc
->GetPixel( nY
, nX
) == aWhite
)
479 *pTmp
++ = sal::static_int_cast
< sal_Int8
>(
482 *pTmp
++ = pBmpAcc
->GetPixel( nY
, nX
).GetIndex();
486 // iterate through interfaces
487 for (ConsumerList_t::iterator iter
= aTmp
.begin(); iter
!= aTmp
.end(); ++iter
)
488 (*iter
)->setPixelsByBytes( nStartX
, nStartY
, nPartWidth
, nPartHeight
, aData
, 0UL, nPartWidth
);
492 ::com::sun::star::uno::Sequence
<sal_Int32
> aData( nPartWidth
* nPartHeight
);
493 sal_Int32
* pTmp
= aData
.getArray();
495 for( long nY
= nStartY
; nY
<= nEndY
; nY
++ )
497 for( long nX
= nStartX
; nX
<= nEndX
; nX
++ )
499 if( pMskAcc
->GetPixel( nY
, nX
) == aWhite
)
500 *pTmp
++ = mnTransIndex
;
502 *pTmp
++ = pBmpAcc
->GetPixel( nY
, nX
).GetIndex();
506 // iterate through interfaces
507 for (ConsumerList_t::iterator iter
= aTmp
.begin(); iter
!= aTmp
.end(); ++iter
)
508 (*iter
)->setPixelsByLongs( nStartX
, nStartY
, nPartWidth
, nPartHeight
, aData
, 0UL, nPartWidth
);
513 ::com::sun::star::uno::Sequence
<sal_Int32
> aData( nPartWidth
* nPartHeight
);
514 const BitmapColor
aWhite( pMskAcc
->GetBestMatchingColor( Color( COL_WHITE
) ) );
515 sal_Int32
* pTmp
= aData
.getArray();
517 for( long nY
= nStartY
; nY
<= nEndY
; nY
++ )
519 for( long nX
= nStartX
; nX
<= nEndX
; nX
++, pTmp
++ )
521 const BitmapColor
aCol( pBmpAcc
->GetPixel( nY
, nX
) );
523 *pTmp
= ( (sal_Int32
) aCol
.GetRed() ) << (sal_Int32
)(24L);
524 *pTmp
|= ( (sal_Int32
) aCol
.GetGreen() ) << (sal_Int32
)(16L);
525 *pTmp
|= ( (sal_Int32
) aCol
.GetBlue() ) << (sal_Int32
)(8L);
527 if( pMskAcc
->GetPixel( nY
, nX
) != aWhite
)
528 *pTmp
|= 0x000000ffUL
;
532 // iterate through interfaces
533 for (ConsumerList_t::iterator iter
= aTmp
.begin(); iter
!= aTmp
.end(); ++iter
)
534 (*iter
)->setPixelsByLongs( nStartX
, nStartY
, nPartWidth
, nPartHeight
, aData
, 0UL, nPartWidth
);
537 Bitmap::ReleaseAccess( pBmpAcc
);
538 Bitmap::ReleaseAccess( pMskAcc
);
542 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
, std::exception
)
544 if ( aArguments
.getLength() == 1 )
546 ::com::sun::star::uno::Any aArg
= aArguments
.getConstArray()[0];
555 extern "C" SAL_DLLPUBLIC_EXPORT ::com::sun::star::uno::XInterface
* SAL_CALL
556 com_sun_star_form_ImageProducer_get_implementation(::com::sun::star::uno::XComponentContext
*,
557 ::com::sun::star::uno::Sequence
<css::uno::Any
> const &)
559 return cppu::acquire(new ImageProducer());
562 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */