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"
22 #include <osl/diagnose.h>
23 #include <tools/debug.hxx>
25 #include <vcl/BitmapReadAccess.hxx>
26 #include <vcl/cvtgrf.hxx>
27 #include <vcl/svapp.hxx>
28 #include <unotools/ucbstreamhelper.hxx>
29 #include <cppuhelper/queryinterface.hxx>
30 #include <cppuhelper/supportsservice.hxx>
31 #include <com/sun/star/awt/ImageStatus.hpp>
32 #include <com/sun/star/io/XInputStream.hpp>
34 #include <svtools/imageresourceaccess.hxx>
35 #include <comphelper/processfactory.hxx>
39 class ImgProdLockBytes
: public SvLockBytes
41 css::uno::Reference
< css::io::XInputStream
> xStmRef
;
42 css::uno::Sequence
<sal_Int8
> maSeq
;
46 ImgProdLockBytes( SvStream
* pStm
, bool bOwner
);
47 explicit ImgProdLockBytes( css::uno::Reference
< css::io::XInputStream
> xStreamRef
);
49 virtual ErrCode
ReadAt( sal_uInt64 nPos
, void* pBuffer
, std::size_t nCount
, std::size_t * pRead
) const override
;
50 virtual ErrCode
WriteAt( sal_uInt64 nPos
, const void* pBuffer
, std::size_t nCount
, std::size_t * pWritten
) override
;
51 virtual ErrCode
Flush() const override
;
52 virtual ErrCode
SetSize( sal_uInt64 nSize
) override
;
53 virtual ErrCode
Stat( SvLockBytesStat
* ) const override
;
58 ImgProdLockBytes::ImgProdLockBytes( SvStream
* pStm
, bool bOwner
) :
59 SvLockBytes( pStm
, bOwner
)
64 ImgProdLockBytes::ImgProdLockBytes( css::uno::Reference
< css::io::XInputStream
> _xStmRef
) :
65 xStmRef(std::move( _xStmRef
))
70 const sal_uInt32 nBytesToRead
= 65535;
75 css::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
);
89 ErrCode
ImgProdLockBytes::ReadAt(sal_uInt64
const nPos
,
90 void* pBuffer
, std::size_t nCount
, std::size_t * pRead
) const
94 const_cast<SvStream
*>(GetStream())->ResetError();
95 const ErrCode nErr
= SvLockBytes::ReadAt( nPos
, pBuffer
, nCount
, pRead
);
96 const_cast<SvStream
*>(GetStream())->ResetError();
101 const std::size_t nSeqLen
= maSeq
.getLength();
105 if( ( nPos
+ nCount
) > nSeqLen
)
106 nCount
= nSeqLen
- nPos
;
108 memcpy( pBuffer
, maSeq
.getConstArray() + nPos
, nCount
);
119 ErrCode
ImgProdLockBytes::WriteAt(sal_uInt64
const nPos
,
120 const void* pBuffer
, std::size_t nCount
, std::size_t * pWritten
)
123 return SvLockBytes::WriteAt( nPos
, pBuffer
, nCount
, pWritten
);
126 DBG_ASSERT( xStmRef
.is(), "ImgProdLockBytes::WriteAt: xInputStream has no reference..." );
127 return ERRCODE_IO_CANTWRITE
;
132 ErrCode
ImgProdLockBytes::Flush() const
138 ErrCode
ImgProdLockBytes::SetSize(sal_uInt64
const nSize
)
141 return SvLockBytes::SetSize( nSize
);
144 OSL_FAIL( "ImgProdLockBytes::SetSize not supported for xInputStream..." );
145 return ERRCODE_IO_CANTWRITE
;
150 ErrCode
ImgProdLockBytes::Stat( SvLockBytesStat
* pStat
) const
153 return SvLockBytes::Stat( pStat
);
156 DBG_ASSERT( xStmRef
.is(), "ImgProdLockBytes::Stat: xInputStream has no reference..." );
157 pStat
->nSize
= maSeq
.getLength();
163 ImageProducer::ImageProducer()
170 ImageProducer::~ImageProducer()
176 css::uno::Any
ImageProducer::queryInterface( const css::uno::Type
& rType
)
178 css::uno::Any aRet
= ::cppu::queryInterface( rType
,
179 static_cast< css::lang::XInitialization
* >(this),
180 static_cast< css::lang::XServiceInfo
* >(this),
181 static_cast< css::awt::XImageProducer
* >(this) );
182 return (aRet
.hasValue() ? aRet
: OWeakObject::queryInterface( rType
));
186 void ImageProducer::addConsumer( const css::uno::Reference
< css::awt::XImageConsumer
>& rxConsumer
)
188 DBG_ASSERT( rxConsumer
.is(), "::AddConsumer(...): No consumer referenced!" );
189 if( rxConsumer
.is() )
190 maConsList
.push_back( rxConsumer
);
194 void ImageProducer::removeConsumer( const css::uno::Reference
< css::awt::XImageConsumer
>& rxConsumer
)
196 ConsumerList_t::reverse_iterator riter
= std::find(maConsList
.rbegin(),maConsList
.rend(),rxConsumer
);
198 if (riter
!= maConsList
.rend())
199 maConsList
.erase(riter
.base()-1);
203 void ImageProducer::SetImage( const OUString
& rPath
)
210 if ( ::svt::GraphicAccess::isSupportedURL( maURL
) )
212 mpStm
= ::svt::GraphicAccess::getImageStream( ::comphelper::getProcessComponentContext(), maURL
);
214 else if( !maURL
.isEmpty() )
216 std::unique_ptr
<SvStream
> pIStm
= ::utl::UcbStreamHelper::CreateStream( maURL
, StreamMode::STD_READ
);
218 mpStm
.reset( new SvStream( new ImgProdLockBytes( pIStm
.release(), true ) ) );
223 void ImageProducer::SetImage( SvStream
& rStm
)
229 mpStm
.reset( new SvStream( new ImgProdLockBytes( &rStm
, false ) ) );
233 void ImageProducer::setImage( css::uno::Reference
< css::io::XInputStream
> const & rInputStmRef
)
240 if( rInputStmRef
.is() )
241 mpStm
.reset( new SvStream( new ImgProdLockBytes( rInputStmRef
) ) );
245 void ImageProducer::NewDataAvailable()
247 if( ( GraphicType::NONE
== moGraphic
->GetType() ) || moGraphic
->GetReaderContext() )
252 void ImageProducer::startProduction()
254 if( maConsList
.empty() && !maDoneHdl
.IsSet() )
257 bool bNotifyEmptyGraphics
= false;
259 // valid stream or filled graphic? => update consumers
260 if( mpStm
|| ( moGraphic
->GetType() != GraphicType::NONE
) )
262 // if we already have a graphic, we don't have to import again;
263 // graphic is cleared if a new Stream is set
264 if( ( moGraphic
->GetType() == GraphicType::NONE
) || moGraphic
->GetReaderContext() )
266 if ( ImplImportGraphic( *moGraphic
) )
267 maDoneHdl
.Call( &*moGraphic
);
270 if( moGraphic
->GetType() != GraphicType::NONE
)
271 ImplUpdateData( *moGraphic
);
273 bNotifyEmptyGraphics
= true;
276 bNotifyEmptyGraphics
= true;
278 if ( !bNotifyEmptyGraphics
)
282 // create temporary list to hold interfaces
283 ConsumerList_t aTmp
= maConsList
;
285 // iterate through interfaces
286 for (auto const& elem
: aTmp
)
289 elem
->complete( css::awt::ImageStatus::IMAGESTATUS_STATICIMAGEDONE
, this );
292 maDoneHdl
.Call( nullptr );
296 bool ImageProducer::ImplImportGraphic( Graphic
& rGraphic
)
301 if( ERRCODE_IO_PENDING
== mpStm
->GetError() )
306 bool bRet
= GraphicConverter::Import( *mpStm
, rGraphic
) == ERRCODE_NONE
;
308 if( ERRCODE_IO_PENDING
== mpStm
->GetError() )
315 void ImageProducer::ImplUpdateData( const Graphic
& rGraphic
)
317 ImplInitConsumer( rGraphic
);
319 if( mbConsInit
&& !maConsList
.empty() )
321 // create temporary list to hold interfaces
322 ConsumerList_t aTmp
= maConsList
;
324 ImplUpdateConsumer( rGraphic
);
327 // iterate through interfaces
328 for (auto const& elem
: aTmp
)
329 elem
->complete( css::awt::ImageStatus::IMAGESTATUS_STATICIMAGEDONE
, this );
334 void ImageProducer::ImplInitConsumer( const Graphic
& rGraphic
)
336 sal_uInt32 nRMask
= 0;
337 sal_uInt32 nGMask
= 0;
338 sal_uInt32 nBMask
= 0;
339 sal_uInt32 nAMask
= 0;
340 sal_uInt32 nWidth
= 0;
341 sal_uInt32 nHeight
= 0;
342 sal_uInt8 nBitCount
= 0;
343 css::uno::Sequence
< sal_Int32
> aRGBPal
;
344 rGraphic
.GetBitmapEx().GetColorModel(aRGBPal
, nRMask
, nGMask
, nBMask
, nAMask
, mnTransIndex
, nWidth
, nHeight
, nBitCount
);
346 // create temporary list to hold interfaces
347 ConsumerList_t aTmp
= maConsList
;
349 // iterate through interfaces
350 for (auto const& elem
: aTmp
)
352 elem
->init( nWidth
, nHeight
);
353 elem
->setColorModel( nBitCount
,aRGBPal
, nRMask
, nGMask
, nBMask
, nAMask
);
360 void ImageProducer::ImplUpdateConsumer( const Graphic
& rGraphic
)
362 BitmapEx
aBmpEx( rGraphic
.GetBitmapEx() );
363 Bitmap
aBmp( aBmpEx
.GetBitmap() );
364 BitmapReadAccess
* pBmpAcc
= aBmp
.AcquireReadAccess();
369 Bitmap
aMask( aBmpEx
.GetAlphaMask() );
370 BitmapReadAccess
* pMskAcc
= !aMask
.IsEmpty() ? aMask
.AcquireReadAccess() : nullptr;
371 const tools::Long nWidth
= pBmpAcc
->Width();
372 const tools::Long nHeight
= pBmpAcc
->Height();
373 const tools::Long nStartX
= 0;
374 const tools::Long nEndX
= nWidth
- 1;
375 const tools::Long nStartY
= 0;
376 const tools::Long nEndY
= nHeight
- 1;
377 const tools::Long nPartWidth
= nEndX
- nStartX
+ 1;
378 const tools::Long nPartHeight
= nEndY
- nStartY
+ 1;
382 aMask
= Bitmap(aBmp
.GetSizePixel(), vcl::PixelFormat::N8_BPP
, &Bitmap::GetGreyPalette(256));
383 aMask
.Erase( COL_BLACK
);
384 pMskAcc
= aMask
.AcquireReadAccess();
387 // create temporary list to hold interfaces
388 ConsumerList_t aTmp
= maConsList
;
390 if( pBmpAcc
->HasPalette() )
392 const BitmapColor
aWhite( pMskAcc
->GetBestMatchingColor( COL_WHITE
) );
394 if( mnTransIndex
< 256 )
396 css::uno::Sequence
<sal_Int8
> aData( nPartWidth
* nPartHeight
);
397 sal_Int8
* pTmp
= aData
.getArray();
399 for( tools::Long nY
= nStartY
; nY
<= nEndY
; nY
++ )
401 Scanline pScanlineMask
= pMskAcc
->GetScanline( nY
);
402 Scanline pScanline
= pBmpAcc
->GetScanline( nY
);
403 for( tools::Long nX
= nStartX
; nX
<= nEndX
; nX
++ )
405 if( pMskAcc
->GetPixelFromData( pScanlineMask
, nX
) == aWhite
)
406 *pTmp
++ = sal::static_int_cast
< sal_Int8
>(
409 *pTmp
++ = pBmpAcc
->GetPixelFromData( pScanline
, nX
).GetIndex();
413 // iterate through interfaces
414 for (auto const& elem
: aTmp
)
415 elem
->setPixelsByBytes( nStartX
, nStartY
, nPartWidth
, nPartHeight
, aData
, 0UL, nPartWidth
);
419 css::uno::Sequence
<sal_Int32
> aData( nPartWidth
* nPartHeight
);
420 sal_Int32
* pTmp
= aData
.getArray();
422 for( tools::Long nY
= nStartY
; nY
<= nEndY
; nY
++ )
424 Scanline pScanlineMask
= pMskAcc
->GetScanline( nY
);
425 Scanline pScanline
= pBmpAcc
->GetScanline( nY
);
426 for( tools::Long nX
= nStartX
; nX
<= nEndX
; nX
++ )
428 if( pMskAcc
->GetPixelFromData( pScanlineMask
, nX
) == aWhite
)
429 *pTmp
++ = mnTransIndex
;
431 *pTmp
++ = pBmpAcc
->GetPixelFromData( pScanline
, nX
).GetIndex();
435 // iterate through interfaces
436 for (auto const& elem
: aTmp
)
437 elem
->setPixelsByLongs( nStartX
, nStartY
, nPartWidth
, nPartHeight
, aData
, 0UL, nPartWidth
);
442 css::uno::Sequence
<sal_Int32
> aData( nPartWidth
* nPartHeight
);
443 const BitmapColor
aWhite( pMskAcc
->GetBestMatchingColor( COL_WHITE
) );
444 sal_Int32
* pTmp
= aData
.getArray();
446 for( tools::Long nY
= nStartY
; nY
<= nEndY
; nY
++ )
448 Scanline pScanlineMask
= pMskAcc
->GetScanline( nY
);
449 Scanline pScanline
= pBmpAcc
->GetScanline( nY
);
450 for( tools::Long nX
= nStartX
; nX
<= nEndX
; nX
++, pTmp
++ )
452 const BitmapColor
aCol( pBmpAcc
->GetPixelFromData( pScanline
, nX
) );
454 *pTmp
= static_cast<sal_Int32
>(aCol
.GetRed()) << 24;
455 *pTmp
|= static_cast<sal_Int32
>(aCol
.GetGreen()) << 16;
456 *pTmp
|= static_cast<sal_Int32
>(aCol
.GetBlue()) << 8;
458 if( pMskAcc
->GetPixelFromData( pScanlineMask
, nX
) != aWhite
)
459 *pTmp
|= 0x000000ffUL
;
463 // iterate through interfaces
464 for (auto const& elem
: aTmp
)
465 elem
->setPixelsByLongs( nStartX
, nStartY
, nPartWidth
, nPartHeight
, aData
, 0UL, nPartWidth
);
468 Bitmap::ReleaseAccess( pBmpAcc
);
469 Bitmap::ReleaseAccess( pMskAcc
);
473 void ImageProducer::initialize( const css::uno::Sequence
< css::uno::Any
>& aArguments
)
475 if ( aArguments
.getLength() == 1 )
477 css::uno::Any aArg
= aArguments
.getConstArray()[0];
486 OUString
ImageProducer::getImplementationName() {
487 return "com.sun.star.form.ImageProducer";
490 sal_Bool
ImageProducer::supportsService(OUString
const & ServiceName
) {
491 return cppu::supportsService(this, ServiceName
);
494 css::uno::Sequence
<OUString
> ImageProducer::getSupportedServiceNames() {
495 return {"com.sun.star.awt.ImageProducer"};
499 extern "C" SAL_DLLPUBLIC_EXPORT
css::uno::XInterface
*
500 com_sun_star_form_ImageProducer_get_implementation(css::uno::XComponentContext
*,
501 css::uno::Sequence
<css::uno::Any
> const &)
503 return cppu::acquire(new ImageProducer());
506 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */