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 .
21 #include "imgprod.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 <com/sun/star/io/XInputStream.hpp>
30 #include "svtools/imageresourceaccess.hxx"
31 #include <comphelper/processfactory.hxx>
33 // --------------------
34 // - ImgProdLockBytes -
35 // --------------------
37 class ImgProdLockBytes
: public SvLockBytes
39 ::com::sun::star::uno::Reference
< ::com::sun::star::io::XInputStream
> xStmRef
;
40 ::com::sun::star::uno::Sequence
<sal_Int8
> maSeq
;
42 ImgProdLockBytes() {};
46 ImgProdLockBytes( SvStream
* pStm
, sal_Bool bOwner
);
47 ImgProdLockBytes( ::com::sun::star::uno::Reference
< ::com::sun::star::io::XInputStream
> & rStreamRef
);
48 virtual ~ImgProdLockBytes();
50 virtual ErrCode
ReadAt( sal_Size nPos
, void* pBuffer
, sal_Size nCount
, sal_Size
* pRead
) const;
51 virtual ErrCode
WriteAt( sal_Size nPos
, const void* pBuffer
, sal_Size nCount
, sal_Size
* pWritten
);
52 virtual ErrCode
Flush() const;
53 virtual ErrCode
SetSize( sal_Size nSize
);
54 virtual ErrCode
Stat( SvLockBytesStat
*, SvLockBytesStatFlag
) const;
57 // ------------------------------------------------------------------------
59 ImgProdLockBytes::ImgProdLockBytes( SvStream
* pStm
, sal_Bool bOwner
) :
60 SvLockBytes( pStm
, bOwner
)
64 // ------------------------------------------------------------------------
66 ImgProdLockBytes::ImgProdLockBytes( ::com::sun::star::uno::Reference
< ::com::sun::star::io::XInputStream
> & rStmRef
) :
71 const sal_uInt32 nBytesToRead
= 65535;
76 ::com::sun::star::uno::Sequence
< sal_Int8
> aReadSeq
;
78 nRead
= xStmRef
->readSomeBytes( aReadSeq
, nBytesToRead
);
82 const sal_uInt32 nOldLength
= maSeq
.getLength();
83 maSeq
.realloc( nOldLength
+ nRead
);
84 memcpy( maSeq
.getArray() + nOldLength
, aReadSeq
.getConstArray(), aReadSeq
.getLength() );
87 while( nBytesToRead
== nRead
);
91 // ------------------------------------------------------------------------
93 ImgProdLockBytes::~ImgProdLockBytes()
97 // ------------------------------------------------------------------------
99 ErrCode
ImgProdLockBytes::ReadAt( sal_Size nPos
, void* pBuffer
, sal_Size nCount
, sal_Size
* pRead
) const
103 ( (SvStream
*) GetStream() )->ResetError();
104 const ErrCode nErr
= SvLockBytes::ReadAt( nPos
, pBuffer
, nCount
, pRead
);
105 ( (SvStream
*) GetStream() )->ResetError();
110 const sal_Size nSeqLen
= maSeq
.getLength();
111 ErrCode nErr
= ERRCODE_NONE
;
115 if( ( nPos
+ nCount
) > nSeqLen
)
116 nCount
= nSeqLen
- nPos
;
118 memcpy( pBuffer
, maSeq
.getConstArray() + nPos
, nCount
);
128 // ------------------------------------------------------------------------
130 ErrCode
ImgProdLockBytes::WriteAt( sal_Size nPos
, const void* pBuffer
, sal_Size nCount
, sal_Size
* pWritten
)
133 return SvLockBytes::WriteAt( nPos
, pBuffer
, nCount
, pWritten
);
136 DBG_ASSERT( xStmRef
.is(), "ImgProdLockBytes::WriteAt: xInputStream has no reference..." );
137 return ERRCODE_IO_CANTWRITE
;
141 // ------------------------------------------------------------------------
143 ErrCode
ImgProdLockBytes::Flush() const
148 // ------------------------------------------------------------------------
150 ErrCode
ImgProdLockBytes::SetSize( sal_Size nSize
)
153 return SvLockBytes::SetSize( nSize
);
156 OSL_FAIL( "ImgProdLockBytes::SetSize not supported for xInputStream..." );
157 return ERRCODE_IO_CANTWRITE
;
161 // ------------------------------------------------------------------------
163 ErrCode
ImgProdLockBytes::Stat( SvLockBytesStat
* pStat
, SvLockBytesStatFlag eFlag
) const
166 return SvLockBytes::Stat( pStat
, eFlag
);
169 DBG_ASSERT( xStmRef
.is(), "ImgProdLockBytes::Stat: xInputStream has no reference..." );
170 pStat
->nSize
= maSeq
.getLength();
179 ImageProducer::ImageProducer() :
181 mbConsInit ( sal_False
)
183 mpGraphic
= new Graphic
;
186 // ------------------------------------------------------------
188 ImageProducer::~ImageProducer()
197 // ------------------------------------------------------------
199 // ::com::sun::star::uno::XInterface
200 ::com::sun::star::uno::Any
ImageProducer::queryInterface( const ::com::sun::star::uno::Type
& rType
) throw(::com::sun::star::uno::RuntimeException
)
202 ::com::sun::star::uno::Any aRet
= ::cppu::queryInterface( rType
,
203 (static_cast< ::com::sun::star::lang::XInitialization
* >(this)),
204 (static_cast< ::com::sun::star::awt::XImageProducer
* >(this)) );
205 return (aRet
.hasValue() ? aRet
: OWeakObject::queryInterface( rType
));
208 // ------------------------------------------------------------
210 void ImageProducer::addConsumer( const ::com::sun::star::uno::Reference
< ::com::sun::star::awt::XImageConsumer
>& rxConsumer
) throw(::com::sun::star::uno::RuntimeException
)
212 DBG_ASSERT( rxConsumer
.is(), "::AddConsumer(...): No consumer referenced!" );
213 if( rxConsumer
.is() )
214 maConsList
.push_back( new ::com::sun::star::uno::Reference
< ::com::sun::star::awt::XImageConsumer
> ( rxConsumer
));
217 // ------------------------------------------------------------
219 void ImageProducer::removeConsumer( const ::com::sun::star::uno::Reference
< ::com::sun::star::awt::XImageConsumer
>& rxConsumer
) throw(::com::sun::star::uno::RuntimeException
)
221 ConsumerList_t::reverse_iterator riter
= std::find(maConsList
.rbegin(),maConsList
.rend(),rxConsumer
);
223 if (riter
!= maConsList
.rend())
224 maConsList
.erase(riter
.base()-1);
227 // ------------------------------------------------------------
229 void ImageProducer::SetImage( const OUString
& rPath
)
233 mbConsInit
= sal_False
;
236 if ( ::svt::GraphicAccess::isSupportedURL( maURL
) )
238 mpStm
= ::svt::GraphicAccess::getImageStream( ::comphelper::getProcessComponentContext(), maURL
);
240 else if( !maURL
.isEmpty() )
242 SvStream
* pIStm
= ::utl::UcbStreamHelper::CreateStream( maURL
, STREAM_STD_READ
);
243 mpStm
= pIStm
? new SvStream( new ImgProdLockBytes( pIStm
, sal_True
) ) : NULL
;
249 // ------------------------------------------------------------
251 void ImageProducer::SetImage( SvStream
& rStm
)
255 mbConsInit
= sal_False
;
258 mpStm
= new SvStream( new ImgProdLockBytes( &rStm
, sal_False
) );
261 // ------------------------------------------------------------
263 void ImageProducer::setImage( ::com::sun::star::uno::Reference
< ::com::sun::star::io::XInputStream
> & rInputStmRef
)
267 mbConsInit
= sal_False
;
270 if( rInputStmRef
.is() )
271 mpStm
= new SvStream( new ImgProdLockBytes( rInputStmRef
) );
276 // ------------------------------------------------------------
278 void ImageProducer::NewDataAvailable()
280 if( ( GRAPHIC_NONE
== mpGraphic
->GetType() ) || mpGraphic
->GetContext() )
284 // ------------------------------------------------------------
286 void ImageProducer::startProduction() throw(::com::sun::star::uno::RuntimeException
)
288 if( !maConsList
.empty() || maDoneHdl
.IsSet() )
290 bool bNotifyEmptyGraphics
= false;
292 // valid stream or filled graphic? => update consumers
293 if( mpStm
|| ( mpGraphic
->GetType() != GRAPHIC_NONE
) )
295 // if we already have a graphic, we don't have to import again;
296 // graphic is cleared if a new Stream is set
297 if( ( mpGraphic
->GetType() == GRAPHIC_NONE
) || mpGraphic
->GetContext() )
299 if ( ImplImportGraphic( *mpGraphic
) && maDoneHdl
.IsSet() )
300 maDoneHdl
.Call( mpGraphic
);
303 if( mpGraphic
->GetType() != GRAPHIC_NONE
)
304 ImplUpdateData( *mpGraphic
);
306 bNotifyEmptyGraphics
= true;
309 bNotifyEmptyGraphics
= true;
311 if ( bNotifyEmptyGraphics
)
314 // create temporary list to hold interfaces
315 ConsumerList_t aTmp
= maConsList
;
317 // iterate through interfaces
318 for( ConsumerList_t::iterator iter
= aTmp
.begin(); iter
!= aTmp
.end(); ++iter
)
320 (*iter
)->init( 0, 0 );
321 (*iter
)->complete( ::com::sun::star::awt::ImageStatus::IMAGESTATUS_STATICIMAGEDONE
, this );
324 if ( maDoneHdl
.IsSet() )
325 maDoneHdl
.Call( NULL
);
330 // ------------------------------------------------------------
332 sal_Bool
ImageProducer::ImplImportGraphic( Graphic
& rGraphic
)
334 if( ERRCODE_IO_PENDING
== mpStm
->GetError() )
339 sal_Bool bRet
= GraphicConverter::Import( *mpStm
, rGraphic
) == ERRCODE_NONE
;
341 if( ERRCODE_IO_PENDING
== mpStm
->GetError() )
347 // ------------------------------------------------------------
349 void ImageProducer::ImplUpdateData( const Graphic
& rGraphic
)
351 ImplInitConsumer( rGraphic
);
353 if( mbConsInit
&& !maConsList
.empty() )
355 // create temporary list to hold interfaces
356 ConsumerList_t aTmp
= maConsList
;
358 ImplUpdateConsumer( rGraphic
);
359 mbConsInit
= sal_False
;
361 // iterate through interfaces
362 for( ConsumerList_t::iterator iter
= aTmp
.begin(); iter
!= aTmp
.end(); ++iter
)
363 (*iter
)->complete( ::com::sun::star::awt::ImageStatus::IMAGESTATUS_STATICIMAGEDONE
, this );
367 // ------------------------------------------------------------
369 void ImageProducer::ImplInitConsumer( const Graphic
& rGraphic
)
371 Bitmap
aBmp( rGraphic
.GetBitmapEx().GetBitmap() );
372 BitmapReadAccess
* pBmpAcc
= aBmp
.AcquireReadAccess();
376 sal_uInt16 nPalCount
= 0;
377 sal_uInt32 nRMask
= 0;
378 sal_uInt32 nGMask
= 0;
379 sal_uInt32 nBMask
= 0;
380 sal_uInt32 nAMask
= 0;
381 ::com::sun::star::uno::Sequence
< sal_Int32
> aRGBPal
;
383 if( pBmpAcc
->HasPalette() )
385 nPalCount
= pBmpAcc
->GetPaletteEntryCount();
389 aRGBPal
= ::com::sun::star::uno::Sequence
< sal_Int32
>( nPalCount
+ 1 );
391 sal_Int32
* pTmp
= aRGBPal
.getArray();
393 for( sal_uInt32 i
= 0; i
< nPalCount
; i
++, pTmp
++ )
395 const BitmapColor
& rCol
= pBmpAcc
->GetPaletteColor( (sal_uInt16
) i
);
397 *pTmp
= ( (sal_Int32
) rCol
.GetRed() ) << (sal_Int32
)(24L);
398 *pTmp
|= ( (sal_Int32
) rCol
.GetGreen() ) << (sal_Int32
)(16L);
399 *pTmp
|= ( (sal_Int32
) rCol
.GetBlue() ) << (sal_Int32
)(8L);
400 *pTmp
|= (sal_Int32
)(0x000000ffL
);
403 if( rGraphic
.IsTransparent() )
405 // append transparent entry
406 *pTmp
= (sal_Int32
)(0xffffff00L
);
407 mnTransIndex
= nPalCount
;
417 nRMask
= 0xff000000UL
;
418 nGMask
= 0x00ff0000UL
;
419 nBMask
= 0x0000ff00UL
;
420 nAMask
= 0x000000ffUL
;
423 // create temporary list to hold interfaces
424 ConsumerList_t aTmp
= maConsList
;
426 // iterate through interfaces
427 for( ConsumerList_t::iterator iter
= aTmp
.begin(); iter
!= aTmp
.end(); ++iter
)
429 (*iter
)->init( pBmpAcc
->Width(), pBmpAcc
->Height() );
430 (*iter
)->setColorModel( pBmpAcc
->GetBitCount(),aRGBPal
, nRMask
, nGMask
, nBMask
, nAMask
);
433 aBmp
.ReleaseAccess( pBmpAcc
);
434 mbConsInit
= sal_True
;
438 // ------------------------------------------------------------
440 void ImageProducer::ImplUpdateConsumer( const Graphic
& rGraphic
)
442 BitmapEx
aBmpEx( rGraphic
.GetBitmapEx() );
443 Bitmap
aBmp( aBmpEx
.GetBitmap() );
444 BitmapReadAccess
* pBmpAcc
= aBmp
.AcquireReadAccess();
448 Bitmap
aMask( aBmpEx
.GetMask() );
449 BitmapReadAccess
* pMskAcc
= !!aMask
? aMask
.AcquireReadAccess() : NULL
;
450 const long nWidth
= pBmpAcc
->Width();
451 const long nHeight
= pBmpAcc
->Height();
452 const long nStartX
= 0L;
453 const long nEndX
= nWidth
- 1L;
454 const long nStartY
= 0L;
455 const long nEndY
= nHeight
- 1L;
456 const long nPartWidth
= nEndX
- nStartX
+ 1;
457 const long nPartHeight
= nEndY
- nStartY
+ 1;
461 aMask
= Bitmap( aBmp
.GetSizePixel(), 1 );
462 aMask
.Erase( COL_BLACK
);
463 pMskAcc
= aMask
.AcquireReadAccess();
466 // create temporary list to hold interfaces
467 ConsumerList_t aTmp
= maConsList
;
469 if( pBmpAcc
->HasPalette() )
471 const BitmapColor
aWhite( pMskAcc
->GetBestMatchingColor( Color( COL_WHITE
) ) );
473 if( mnTransIndex
< 256 )
475 ::com::sun::star::uno::Sequence
<sal_Int8
> aData( nPartWidth
* nPartHeight
);
476 sal_Int8
* pTmp
= aData
.getArray();
478 for( long nY
= nStartY
; nY
<= nEndY
; nY
++ )
480 for( long nX
= nStartX
; nX
<= nEndX
; nX
++ )
482 if( pMskAcc
->GetPixel( nY
, nX
) == aWhite
)
483 *pTmp
++ = sal::static_int_cast
< sal_Int8
>(
486 *pTmp
++ = pBmpAcc
->GetPixel( nY
, nX
).GetIndex();
490 // iterate through interfaces
491 for (ConsumerList_t::iterator iter
= aTmp
.begin(); iter
!= aTmp
.end(); ++iter
)
492 (*iter
)->setPixelsByBytes( nStartX
, nStartY
, nPartWidth
, nPartHeight
, aData
, 0UL, nPartWidth
);
496 ::com::sun::star::uno::Sequence
<sal_Int32
> aData( nPartWidth
* nPartHeight
);
497 sal_Int32
* pTmp
= aData
.getArray();
499 for( long nY
= nStartY
; nY
<= nEndY
; nY
++ )
501 for( long nX
= nStartX
; nX
<= nEndX
; nX
++ )
503 if( pMskAcc
->GetPixel( nY
, nX
) == aWhite
)
504 *pTmp
++ = mnTransIndex
;
506 *pTmp
++ = pBmpAcc
->GetPixel( nY
, nX
).GetIndex();
510 // iterate through interfaces
511 for (ConsumerList_t::iterator iter
= aTmp
.begin(); iter
!= aTmp
.end(); ++iter
)
512 (*iter
)->setPixelsByLongs( nStartX
, nStartY
, nPartWidth
, nPartHeight
, aData
, 0UL, nPartWidth
);
517 ::com::sun::star::uno::Sequence
<sal_Int32
> aData( nPartWidth
* nPartHeight
);
518 const BitmapColor
aWhite( pMskAcc
->GetBestMatchingColor( Color( COL_WHITE
) ) );
519 sal_Int32
* pTmp
= aData
.getArray();
521 for( long nY
= nStartY
; nY
<= nEndY
; nY
++ )
523 for( long nX
= nStartX
; nX
<= nEndX
; nX
++, pTmp
++ )
525 const BitmapColor
aCol( pBmpAcc
->GetPixel( nY
, nX
) );
527 *pTmp
= ( (sal_Int32
) aCol
.GetRed() ) << (sal_Int32
)(24L);
528 *pTmp
|= ( (sal_Int32
) aCol
.GetGreen() ) << (sal_Int32
)(16L);
529 *pTmp
|= ( (sal_Int32
) aCol
.GetBlue() ) << (sal_Int32
)(8L);
531 if( pMskAcc
->GetPixel( nY
, nX
) != aWhite
)
532 *pTmp
|= 0x000000ffUL
;
536 // iterate through interfaces
537 for (ConsumerList_t::iterator iter
= aTmp
.begin(); iter
!= aTmp
.end(); ++iter
)
538 (*iter
)->setPixelsByLongs( nStartX
, nStartY
, nPartWidth
, nPartHeight
, aData
, 0UL, nPartWidth
);
541 aBmp
.ReleaseAccess( pBmpAcc
);
542 aMask
.ReleaseAccess( pMskAcc
);
546 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
)
548 if ( aArguments
.getLength() == 1 )
550 ::com::sun::star::uno::Any aArg
= aArguments
.getConstArray()[0];
561 ::com::sun::star::uno::Reference
< ::com::sun::star::uno::XInterface
>
562 SAL_CALL
ImageProducer_CreateInstance(
563 const ::com::sun::star::uno::Reference
< ::com::sun::star::lang::XMultiServiceFactory
>& )
565 return ::com::sun::star::uno::Reference
< ::com::sun::star::uno::XInterface
>(
566 ( ::cppu::OWeakObject
* ) new ImageProducer
);
570 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */