bump product version to 7.6.3.2-android
[LibreOffice.git] / forms / source / component / imgprod.cxx
blobfaa8663a2461ef8c06d5a62d57aa1c5a809c8f3e
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
24 #include <utility>
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>
37 namespace {
39 class ImgProdLockBytes : public SvLockBytes
41 css::uno::Reference< css::io::XInputStream > xStmRef;
42 css::uno::Sequence<sal_Int8> maSeq;
44 public:
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 ))
67 if( !xStmRef.is() )
68 return;
70 const sal_uInt32 nBytesToRead = 65535;
71 sal_uInt32 nRead;
75 css::uno::Sequence< sal_Int8 > aReadSeq;
77 nRead = xStmRef->readSomeBytes( aReadSeq, nBytesToRead );
79 if( nRead )
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
92 if( GetStream() )
94 const_cast<SvStream*>(GetStream())->ResetError();
95 const ErrCode nErr = SvLockBytes::ReadAt( nPos, pBuffer, nCount, pRead );
96 const_cast<SvStream*>(GetStream())->ResetError();
97 return nErr;
99 else
101 const std::size_t nSeqLen = maSeq.getLength();
103 if( nPos < nSeqLen )
105 if( ( nPos + nCount ) > nSeqLen )
106 nCount = nSeqLen - nPos;
108 memcpy( pBuffer, maSeq.getConstArray() + nPos, nCount );
109 *pRead = nCount;
111 else
112 *pRead = 0;
114 return ERRCODE_NONE;
119 ErrCode ImgProdLockBytes::WriteAt(sal_uInt64 const nPos,
120 const void* pBuffer, std::size_t nCount, std::size_t * pWritten)
122 if( GetStream() )
123 return SvLockBytes::WriteAt( nPos, pBuffer, nCount, pWritten );
124 else
126 DBG_ASSERT( xStmRef.is(), "ImgProdLockBytes::WriteAt: xInputStream has no reference..." );
127 return ERRCODE_IO_CANTWRITE;
132 ErrCode ImgProdLockBytes::Flush() const
134 return ERRCODE_NONE;
138 ErrCode ImgProdLockBytes::SetSize(sal_uInt64 const nSize)
140 if( GetStream() )
141 return SvLockBytes::SetSize( nSize );
142 else
144 OSL_FAIL( "ImgProdLockBytes::SetSize not supported for xInputStream..." );
145 return ERRCODE_IO_CANTWRITE;
150 ErrCode ImgProdLockBytes::Stat( SvLockBytesStat* pStat ) const
152 if( GetStream() )
153 return SvLockBytes::Stat( pStat );
154 else
156 DBG_ASSERT( xStmRef.is(), "ImgProdLockBytes::Stat: xInputStream has no reference..." );
157 pStat->nSize = maSeq.getLength();
158 return ERRCODE_NONE;
163 ImageProducer::ImageProducer()
164 : mnTransIndex(0)
165 , mbConsInit(false)
167 moGraphic.emplace();
170 ImageProducer::~ImageProducer()
175 // XInterface
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 )
205 maURL = rPath;
206 moGraphic->Clear();
207 mbConsInit = false;
208 mpStm.reset();
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 );
217 if (pIStm)
218 mpStm.reset( new SvStream( new ImgProdLockBytes( pIStm.release(), true ) ) );
223 void ImageProducer::SetImage( SvStream& rStm )
225 maURL.clear();
226 moGraphic->Clear();
227 mbConsInit = false;
229 mpStm.reset( new SvStream( new ImgProdLockBytes( &rStm, false ) ) );
233 void ImageProducer::setImage( css::uno::Reference< css::io::XInputStream > const & rInputStmRef )
235 maURL.clear();
236 moGraphic->Clear();
237 mbConsInit = false;
238 mpStm.reset();
240 if( rInputStmRef.is() )
241 mpStm.reset( new SvStream( new ImgProdLockBytes( rInputStmRef ) ) );
245 void ImageProducer::NewDataAvailable()
247 if( ( GraphicType::NONE == moGraphic->GetType() ) || moGraphic->GetReaderContext() )
248 startProduction();
252 void ImageProducer::startProduction()
254 if( maConsList.empty() && !maDoneHdl.IsSet() )
255 return;
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 );
272 else
273 bNotifyEmptyGraphics = true;
275 else
276 bNotifyEmptyGraphics = true;
278 if ( !bNotifyEmptyGraphics )
279 return;
281 // reset image
282 // create temporary list to hold interfaces
283 ConsumerList_t aTmp = maConsList;
285 // iterate through interfaces
286 for (auto const& elem : aTmp)
288 elem->init( 0, 0 );
289 elem->complete( css::awt::ImageStatus::IMAGESTATUS_STATICIMAGEDONE, this );
292 maDoneHdl.Call( nullptr );
296 bool ImageProducer::ImplImportGraphic( Graphic& rGraphic )
298 if (!mpStm)
299 return false;
301 if( ERRCODE_IO_PENDING == mpStm->GetError() )
302 mpStm->ResetError();
304 mpStm->Seek( 0 );
306 bool bRet = GraphicConverter::Import( *mpStm, rGraphic ) == ERRCODE_NONE;
308 if( ERRCODE_IO_PENDING == mpStm->GetError() )
309 mpStm->ResetError();
311 return bRet;
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 );
325 mbConsInit = false;
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 );
356 mbConsInit = true;
360 void ImageProducer::ImplUpdateConsumer( const Graphic& rGraphic )
362 BitmapEx aBmpEx( rGraphic.GetBitmapEx() );
363 Bitmap aBmp( aBmpEx.GetBitmap() );
364 BitmapReadAccess* pBmpAcc = aBmp.AcquireReadAccess();
366 if( !pBmpAcc )
367 return;
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;
380 if( !pMskAcc )
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 >(
407 mnTransIndex );
408 else
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 );
417 else
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;
430 else
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 );
440 else
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];
478 OUString aURL;
479 if ( aArg >>= aURL )
481 SetImage( aURL );
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: */