1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: imgprod.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_forms.hxx"
34 #include "imgprod.hxx"
36 #include <vcl/bmpacc.hxx>
37 #include <vcl/cvtgrf.hxx>
38 #include <vcl/svapp.hxx>
39 #include <unotools/ucbstreamhelper.hxx>
40 #include <svtools/filter.hxx>
41 #include <com/sun/star/io/XInputStream.hpp>
43 #ifndef SVTOOLS_SOURCE_MISC_IMAGERESOURCEACCESS_HXX
44 #include "svtools/imageresourceaccess.hxx"
46 #include <comphelper/processfactory.hxx>
48 // --------------------
49 // - ImgProdLockBytes -
50 // --------------------
52 class ImgProdLockBytes
: public SvLockBytes
54 ::com::sun::star::uno::Reference
< ::com::sun::star::io::XInputStream
> xStmRef
;
55 ::com::sun::star::uno::Sequence
<sal_Int8
> maSeq
;
57 ImgProdLockBytes() {};
61 ImgProdLockBytes( SvStream
* pStm
, sal_Bool bOwner
);
62 ImgProdLockBytes( ::com::sun::star::uno::Reference
< ::com::sun::star::io::XInputStream
> & rStreamRef
);
63 virtual ~ImgProdLockBytes();
65 virtual ErrCode
ReadAt( sal_Size nPos
, void* pBuffer
, sal_Size nCount
, sal_Size
* pRead
) const;
66 virtual ErrCode
WriteAt( sal_Size nPos
, const void* pBuffer
, sal_Size nCount
, sal_Size
* pWritten
);
67 virtual ErrCode
Flush() const;
68 virtual ErrCode
SetSize( sal_Size nSize
);
69 virtual ErrCode
Stat( SvLockBytesStat
*, SvLockBytesStatFlag
) const;
72 // ------------------------------------------------------------------------
74 ImgProdLockBytes::ImgProdLockBytes( SvStream
* pStm
, sal_Bool bOwner
) :
75 SvLockBytes( pStm
, bOwner
)
79 // ------------------------------------------------------------------------
81 ImgProdLockBytes::ImgProdLockBytes( ::com::sun::star::uno::Reference
< ::com::sun::star::io::XInputStream
> & rStmRef
) :
86 const sal_uInt32 nBytesToRead
= 65535;
91 ::com::sun::star::uno::Sequence
< sal_Int8
> aReadSeq
;
93 nRead
= xStmRef
->readSomeBytes( aReadSeq
, nBytesToRead
);
97 const sal_uInt32 nOldLength
= maSeq
.getLength();
98 maSeq
.realloc( nOldLength
+ nRead
);
99 rtl_copyMemory( maSeq
.getArray() + nOldLength
, aReadSeq
.getConstArray(), aReadSeq
.getLength() );
102 while( nBytesToRead
== nRead
);
106 // ------------------------------------------------------------------------
108 ImgProdLockBytes::~ImgProdLockBytes()
112 // ------------------------------------------------------------------------
114 ErrCode
ImgProdLockBytes::ReadAt( sal_Size nPos
, void* pBuffer
, sal_Size nCount
, sal_Size
* pRead
) const
118 ( (SvStream
*) GetStream() )->ResetError();
119 const ErrCode nErr
= SvLockBytes::ReadAt( nPos
, pBuffer
, nCount
, pRead
);
120 ( (SvStream
*) GetStream() )->ResetError();
125 const sal_Size nSeqLen
= maSeq
.getLength();
126 ErrCode nErr
= ERRCODE_NONE
;
130 if( ( nPos
+ nCount
) > nSeqLen
)
131 nCount
= nSeqLen
- nPos
;
133 memcpy( pBuffer
, maSeq
.getConstArray() + nPos
, nCount
);
143 // ------------------------------------------------------------------------
145 ErrCode
ImgProdLockBytes::WriteAt( sal_Size nPos
, const void* pBuffer
, sal_Size nCount
, sal_Size
* pWritten
)
148 return SvLockBytes::WriteAt( nPos
, pBuffer
, nCount
, pWritten
);
151 DBG_ASSERT( xStmRef
.is(), "ImgProdLockBytes::WriteAt: xInputStream has no reference..." );
152 return ERRCODE_IO_CANTWRITE
;
156 // ------------------------------------------------------------------------
158 ErrCode
ImgProdLockBytes::Flush() const
163 // ------------------------------------------------------------------------
165 ErrCode
ImgProdLockBytes::SetSize( sal_Size nSize
)
168 return SvLockBytes::SetSize( nSize
);
171 DBG_ERROR( "ImgProdLockBytes::SetSize not supported for xInputStream..." );
172 return ERRCODE_IO_CANTWRITE
;
176 // ------------------------------------------------------------------------
178 ErrCode
ImgProdLockBytes::Stat( SvLockBytesStat
* pStat
, SvLockBytesStatFlag eFlag
) const
181 return SvLockBytes::Stat( pStat
, eFlag
);
184 DBG_ASSERT( xStmRef
.is(), "ImgProdLockBytes::Stat: xInputStream has no reference..." );
185 pStat
->nSize
= maSeq
.getLength();
194 ImageProducer::ImageProducer() :
198 mbConsInit ( sal_False
),
200 mbAsync ( sal_False
)
202 mpGraphic
= new Graphic
;
203 DBG_ASSERT( Application::GetFilterHdl().IsSet(), "ImageProducer::ImageProducer(): No filter handler set" );
206 // ------------------------------------------------------------
208 ImageProducer::~ImageProducer()
219 for( void* pCons
= maConsList
.First(); pCons
; pCons
= maConsList
.Next() )
220 delete (::com::sun::star::uno::Reference
< ::com::sun::star::awt::XImageConsumer
> *) pCons
;
223 // ------------------------------------------------------------
225 // ::com::sun::star::uno::XInterface
226 ::com::sun::star::uno::Any
ImageProducer::queryInterface( const ::com::sun::star::uno::Type
& rType
) throw(::com::sun::star::uno::RuntimeException
)
228 ::com::sun::star::uno::Any aRet
= ::cppu::queryInterface( rType
,
229 SAL_STATIC_CAST( ::com::sun::star::lang::XInitialization
*, this ),
230 SAL_STATIC_CAST( ::com::sun::star::awt::XImageProducer
*, this ) );
231 return (aRet
.hasValue() ? aRet
: OWeakObject::queryInterface( rType
));
234 // ------------------------------------------------------------
236 void ImageProducer::addConsumer( const ::com::sun::star::uno::Reference
< ::com::sun::star::awt::XImageConsumer
>& rxConsumer
) throw(::com::sun::star::uno::RuntimeException
)
238 DBG_ASSERT( rxConsumer
.is(), "::AddConsumer(...): No consumer referenced!" );
239 if( rxConsumer
.is() )
240 maConsList
.Insert( new ::com::sun::star::uno::Reference
< ::com::sun::star::awt::XImageConsumer
> ( rxConsumer
), LIST_APPEND
);
243 // ------------------------------------------------------------
245 void ImageProducer::removeConsumer( const ::com::sun::star::uno::Reference
< ::com::sun::star::awt::XImageConsumer
>& rxConsumer
) throw(::com::sun::star::uno::RuntimeException
)
247 for( sal_uInt32 n
= maConsList
.Count(); n
; )
249 ::com::sun::star::uno::Reference
< ::com::sun::star::awt::XImageConsumer
> * pRef
= (::com::sun::star::uno::Reference
< ::com::sun::star::awt::XImageConsumer
> *) maConsList
.GetObject( --n
);
251 if( *pRef
== rxConsumer
)
254 maConsList
.Remove( n
);
260 // ------------------------------------------------------------
262 void ImageProducer::SetImage( const ::rtl::OUString
& rPath
)
266 mbConsInit
= sal_False
;
270 if ( ::svt::GraphicAccess::isSupportedURL( maURL
) )
272 mpStm
= ::svt::GraphicAccess::getImageStream( ::comphelper::getProcessServiceFactory(), maURL
);
274 else if( maURL
.getLength() )
276 SvStream
* pIStm
= ::utl::UcbStreamHelper::CreateStream( maURL
, STREAM_STD_READ
);
277 mpStm
= pIStm
? new SvStream( new ImgProdLockBytes( pIStm
, sal_True
) ) : NULL
;
283 // ------------------------------------------------------------
285 void ImageProducer::SetImage( SvStream
& rStm
)
287 maURL
= ::rtl::OUString();
289 mbConsInit
= sal_False
;
293 mpStm
= new SvStream( new ImgProdLockBytes( &rStm
, sal_False
) );
296 // ------------------------------------------------------------
298 void ImageProducer::setImage( ::com::sun::star::uno::Reference
< ::com::sun::star::io::XInputStream
> & rInputStmRef
)
300 maURL
= ::rtl::OUString();
302 mbConsInit
= sal_False
;
306 if( rInputStmRef
.is() )
307 mpStm
= new SvStream( new ImgProdLockBytes( rInputStmRef
) );
312 // ------------------------------------------------------------
314 void ImageProducer::NewDataAvailable()
316 if( ( GRAPHIC_NONE
== mpGraphic
->GetType() ) || mpGraphic
->GetContext() )
320 // ------------------------------------------------------------
322 void ImageProducer::startProduction() throw(::com::sun::star::uno::RuntimeException
)
326 if( maConsList
.Count() )
328 bool bNotifyEmptyGraphics
= false;
330 // valid stream or filled graphic? => update consumers
331 if( mpStm
|| ( mpGraphic
->GetType() != GRAPHIC_NONE
) )
333 // if we already have a graphic, we don't have to import again;
334 // graphic is cleared if a new Stream is set
335 if( ( mpGraphic
->GetType() == GRAPHIC_NONE
) || mpGraphic
->GetContext() )
337 if( !ImplImportGraphic( *mpGraphic
) && maErrorHdl
.IsSet() )
338 maErrorHdl
.Call( this );
341 if( mpGraphic
->GetType() != GRAPHIC_NONE
)
342 ImplUpdateData( *mpGraphic
);
344 bNotifyEmptyGraphics
= true;
347 bNotifyEmptyGraphics
= true;
349 if ( bNotifyEmptyGraphics
)
355 // create temporary list to hold interfaces
356 for( pCons
= maConsList
.First(); pCons
; pCons
= maConsList
.Next() )
357 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
);
359 // iterate through interfaces
360 for( pCons
= aTmp
.First(); pCons
; pCons
= aTmp
.Next() )
362 ( *(::com::sun::star::uno::Reference
< ::com::sun::star::awt::XImageConsumer
> *) pCons
)->init( 0, 0 );
363 ( *(::com::sun::star::uno::Reference
< ::com::sun::star::awt::XImageConsumer
> *) pCons
)->complete( ::com::sun::star::awt::ImageStatus::IMAGESTATUS_STATICIMAGEDONE
, this );
366 // delete interfaces in temporary list
367 for( pCons
= aTmp
.First(); pCons
; pCons
= aTmp
.Next() )
368 delete (::com::sun::star::uno::Reference
< ::com::sun::star::awt::XImageConsumer
> *) pCons
;
373 // ------------------------------------------------------------
375 sal_Bool
ImageProducer::ImplImportGraphic( Graphic
& rGraphic
)
377 USHORT nFilter
= GRFILTER_FORMAT_DONTKNOW
;
379 sal_Bool bRet
= sal_False
;
381 if( ERRCODE_IO_PENDING
== mpStm
->GetError() )
387 nRet
= mpFilter
->ImportGraphic( rGraphic
, String(), *mpStm
, nFilter
);
390 if( GraphicConverter::Import( *mpStm
, rGraphic
) == ERRCODE_NONE
)
393 nRet
= GRFILTER_FILTERERROR
;
396 if( ERRCODE_IO_PENDING
== mpStm
->GetError() )
399 if( nRet
== GRFILTER_OK
)
407 // ------------------------------------------------------------
409 void ImageProducer::ImplUpdateData( const Graphic
& rGraphic
)
412 if( mpGraphic
->GetContext() )
415 ImplInitConsumer( rGraphic
);
417 if( mbConsInit
&& maConsList
.Count() )
422 ImplUpdateConsumer( rGraphic
);
423 mbConsInit
= sal_False
;
425 // create temporary list to hold interfaces
426 for( pCons
= maConsList
.First(); pCons
; pCons
= maConsList
.Next() )
427 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
);
429 // iterate through interfaces
430 for( pCons
= aTmp
.First(); pCons
; pCons
= aTmp
.Next() )
431 ( *(::com::sun::star::uno::Reference
< ::com::sun::star::awt::XImageConsumer
> *) pCons
)->complete( mnStatus
= ::com::sun::star::awt::ImageStatus::IMAGESTATUS_STATICIMAGEDONE
, this );
433 // delete interfaces in temporary list
434 for( pCons
= aTmp
.First(); pCons
; pCons
= aTmp
.Next() )
435 delete (::com::sun::star::uno::Reference
< ::com::sun::star::awt::XImageConsumer
> *) pCons
;
439 // ------------------------------------------------------------
441 void ImageProducer::ImplInitConsumer( const Graphic
& rGraphic
)
443 Bitmap
aBmp( rGraphic
.GetBitmapEx().GetBitmap() );
444 BitmapReadAccess
* pBmpAcc
= aBmp
.AcquireReadAccess();
450 sal_uInt16 nPalCount
= 0;
451 sal_uInt32 nRMask
= 0;
452 sal_uInt32 nGMask
= 0;
453 sal_uInt32 nBMask
= 0;
454 sal_uInt32 nAMask
= 0;
455 ::com::sun::star::uno::Sequence
< sal_Int32
> aRGBPal
;
457 if( pBmpAcc
->HasPalette() )
459 nPalCount
= pBmpAcc
->GetPaletteEntryCount();
463 aRGBPal
= ::com::sun::star::uno::Sequence
< sal_Int32
>( nPalCount
+ 1 );
465 sal_Int32
* pTmp
= aRGBPal
.getArray();
467 for( sal_uInt32 i
= 0; i
< nPalCount
; i
++, pTmp
++ )
469 const BitmapColor
& rCol
= pBmpAcc
->GetPaletteColor( (sal_uInt16
) i
);
471 *pTmp
= ( (sal_Int32
) rCol
.GetRed() ) << (sal_Int32
)(24L);
472 *pTmp
|= ( (sal_Int32
) rCol
.GetGreen() ) << (sal_Int32
)(16L);
473 *pTmp
|= ( (sal_Int32
) rCol
.GetBlue() ) << (sal_Int32
)(8L);
474 *pTmp
|= (sal_Int32
)(0x000000ffL
);
477 if( rGraphic
.IsTransparent() )
479 // append transparent entry
480 *pTmp
= (sal_Int32
)(0xffffff00L
);
481 mnTransIndex
= nPalCount
;
491 nRMask
= 0xff000000UL
;
492 nGMask
= 0x00ff0000UL
;
493 nBMask
= 0x0000ff00UL
;
494 nAMask
= 0x000000ffUL
;
497 // create temporary list to hold interfaces
498 for( pCons
= maConsList
.First(); pCons
; pCons
= maConsList
.Next() )
499 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
);
501 // iterate through interfaces
502 for( pCons
= aTmp
.First(); pCons
; pCons
= aTmp
.Next() )
504 ( *(::com::sun::star::uno::Reference
< ::com::sun::star::awt::XImageConsumer
> *) pCons
)->init( pBmpAcc
->Width(), pBmpAcc
->Height() );
505 ( *(::com::sun::star::uno::Reference
< ::com::sun::star::awt::XImageConsumer
> *) pCons
)->setColorModel( pBmpAcc
->GetBitCount(),
506 aRGBPal
, nRMask
, nGMask
, nBMask
, nAMask
);
509 // delete interfaces in temporary list
510 for( pCons
= aTmp
.First(); pCons
; pCons
= aTmp
.Next() )
511 delete (::com::sun::star::uno::Reference
< ::com::sun::star::awt::XImageConsumer
> *) pCons
;
513 aBmp
.ReleaseAccess( pBmpAcc
);
514 mbConsInit
= sal_True
;
518 // ------------------------------------------------------------
520 void ImageProducer::ImplUpdateConsumer( const Graphic
& rGraphic
)
522 BitmapEx
aBmpEx( rGraphic
.GetBitmapEx() );
523 Bitmap
aBmp( aBmpEx
.GetBitmap() );
524 BitmapReadAccess
* pBmpAcc
= aBmp
.AcquireReadAccess();
530 Bitmap
aMask( aBmpEx
.GetMask() );
531 BitmapReadAccess
* pMskAcc
= !!aMask
? aMask
.AcquireReadAccess() : NULL
;
532 const long nWidth
= pBmpAcc
->Width();
533 const long nHeight
= pBmpAcc
->Height();
534 const long nStartX
= 0L;
535 const long nEndX
= nWidth
- 1L;
536 const long nStartY
= 0L;
537 const long nEndY
= nHeight
- 1L;
538 const long nPartWidth
= nEndX
- nStartX
+ 1;
539 const long nPartHeight
= nEndY
- nStartY
+ 1;
543 aMask
= Bitmap( aBmp
.GetSizePixel(), 1 );
544 aMask
.Erase( COL_BLACK
);
545 pMskAcc
= aMask
.AcquireReadAccess();
548 // create temporary list to hold interfaces
549 for( pCons
= maConsList
.First(); pCons
; pCons
= maConsList
.Next() )
550 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
);
552 if( pBmpAcc
->HasPalette() )
554 const BitmapColor
aWhite( pMskAcc
->GetBestMatchingColor( Color( COL_WHITE
) ) );
556 if( mnTransIndex
< 256 )
558 ::com::sun::star::uno::Sequence
<sal_Int8
> aData( nPartWidth
* nPartHeight
);
559 sal_Int8
* pTmp
= aData
.getArray();
561 for( long nY
= nStartY
; nY
<= nEndY
; nY
++ )
563 for( long nX
= nStartX
; nX
<= nEndX
; nX
++ )
565 if( pMskAcc
->GetPixel( nY
, nX
) == aWhite
)
566 *pTmp
++ = sal::static_int_cast
< sal_Int8
>(
569 *pTmp
++ = pBmpAcc
->GetPixel( nY
, nX
).GetIndex();
573 // iterate through interfaces
574 for( pCons
= aTmp
.First(); pCons
; pCons
= aTmp
.Next() )
575 ( *(::com::sun::star::uno::Reference
< ::com::sun::star::awt::XImageConsumer
> *) pCons
)->setPixelsByBytes( nStartX
, nStartY
, nPartWidth
, nPartHeight
,
576 aData
, 0UL, nPartWidth
);
580 ::com::sun::star::uno::Sequence
<sal_Int32
> aData( nPartWidth
* nPartHeight
);
581 sal_Int32
* pTmp
= aData
.getArray();
583 for( long nY
= nStartY
; nY
<= nEndY
; nY
++ )
585 for( long nX
= nStartX
; nX
<= nEndX
; nX
++ )
587 if( pMskAcc
->GetPixel( nY
, nX
) == aWhite
)
588 *pTmp
++ = mnTransIndex
;
590 *pTmp
++ = pBmpAcc
->GetPixel( nY
, nX
).GetIndex();
594 // iterate through interfaces
595 for( pCons
= aTmp
.First(); pCons
; pCons
= aTmp
.Next() )
596 ( *(::com::sun::star::uno::Reference
< ::com::sun::star::awt::XImageConsumer
> *) pCons
)->setPixelsByLongs( nStartX
, nStartY
, nPartWidth
, nPartHeight
,
597 aData
, 0UL, nPartWidth
);
602 ::com::sun::star::uno::Sequence
<sal_Int32
> aData( nPartWidth
* nPartHeight
);
603 const BitmapColor
aWhite( pMskAcc
->GetBestMatchingColor( Color( COL_WHITE
) ) );
604 sal_Int32
* pTmp
= aData
.getArray();
606 for( long nY
= nStartY
; nY
<= nEndY
; nY
++ )
608 for( long nX
= nStartX
; nX
<= nEndX
; nX
++, pTmp
++ )
610 const BitmapColor
aCol( pBmpAcc
->GetPixel( nY
, nX
) );
612 *pTmp
= ( (sal_Int32
) aCol
.GetRed() ) << (sal_Int32
)(24L);
613 *pTmp
|= ( (sal_Int32
) aCol
.GetGreen() ) << (sal_Int32
)(16L);
614 *pTmp
|= ( (sal_Int32
) aCol
.GetBlue() ) << (sal_Int32
)(8L);
616 if( pMskAcc
->GetPixel( nY
, nX
) != aWhite
)
617 *pTmp
|= 0x000000ffUL
;
621 // iterate through interfaces
622 for( pCons
= aTmp
.First(); pCons
; pCons
= aTmp
.Next() )
623 ( *(::com::sun::star::uno::Reference
< ::com::sun::star::awt::XImageConsumer
> *) pCons
)->setPixelsByLongs( nStartX
, nStartY
, nPartWidth
, nPartHeight
,
624 aData
, 0UL, nPartWidth
);
627 // delete interfaces in temporary list
628 for( pCons
= aTmp
.First(); pCons
; pCons
= aTmp
.Next() )
629 delete (::com::sun::star::uno::Reference
< ::com::sun::star::awt::XImageConsumer
> *) pCons
;
631 aBmp
.ReleaseAccess( pBmpAcc
);
632 aMask
.ReleaseAccess( pMskAcc
);
636 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
)
638 if ( aArguments
.getLength() == 1 )
640 ::com::sun::star::uno::Any aArg
= aArguments
.getConstArray()[0];
651 ::com::sun::star::uno::Reference
< ::com::sun::star::uno::XInterface
>
652 SAL_CALL
ImageProducer_CreateInstance(
653 const ::com::sun::star::uno::Reference
< ::com::sun::star::lang::XMultiServiceFactory
>& )
655 return ::com::sun::star::uno::Reference
< ::com::sun::star::uno::XInterface
>(
656 ( ::cppu::OWeakObject
* ) new ImageProducer
);