LibreOffice Module forms (master) 1
imgprod.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20#include "imgprod.hxx"
21
22#include <osl/diagnose.h>
23#include <tools/debug.hxx>
24#include <utility>
26#include <vcl/cvtgrf.hxx>
27#include <vcl/svapp.hxx>
31#include <com/sun/star/awt/ImageStatus.hpp>
32#include <com/sun/star/io/XInputStream.hpp>
33
36
37namespace {
38
39class ImgProdLockBytes : public SvLockBytes
40{
41 css::uno::Reference< css::io::XInputStream > xStmRef;
42 css::uno::Sequence<sal_Int8> maSeq;
43
44public:
45
46 ImgProdLockBytes( SvStream* pStm, bool bOwner );
47 explicit ImgProdLockBytes( css::uno::Reference< css::io::XInputStream > xStreamRef );
48
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;
54};
55
56}
57
58ImgProdLockBytes::ImgProdLockBytes( SvStream* pStm, bool bOwner ) :
59 SvLockBytes( pStm, bOwner )
60{
61}
62
63
64ImgProdLockBytes::ImgProdLockBytes( css::uno::Reference< css::io::XInputStream > _xStmRef ) :
65 xStmRef(std::move( _xStmRef ))
66{
67 if( !xStmRef.is() )
68 return;
69
70 const sal_uInt32 nBytesToRead = 65535;
71 sal_uInt32 nRead;
72
73 do
74 {
75 css::uno::Sequence< sal_Int8 > aReadSeq;
76
77 nRead = xStmRef->readSomeBytes( aReadSeq, nBytesToRead );
78
79 if( nRead )
80 {
81 const sal_uInt32 nOldLength = maSeq.getLength();
82 maSeq.realloc( nOldLength + nRead );
83 memcpy( maSeq.getArray() + nOldLength, aReadSeq.getConstArray(), aReadSeq.getLength() );
84 }
85 }
86 while( nBytesToRead == nRead );
87}
88
89ErrCode ImgProdLockBytes::ReadAt(sal_uInt64 const nPos,
90 void* pBuffer, std::size_t nCount, std::size_t * pRead) const
91{
92 if( GetStream() )
93 {
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;
98 }
99 else
100 {
101 const std::size_t nSeqLen = maSeq.getLength();
102
103 if( nPos < nSeqLen )
104 {
105 if( ( nPos + nCount ) > nSeqLen )
106 nCount = nSeqLen - nPos;
107
108 memcpy( pBuffer, maSeq.getConstArray() + nPos, nCount );
109 *pRead = nCount;
110 }
111 else
112 *pRead = 0;
113
114 return ERRCODE_NONE;
115 }
116}
117
118
119ErrCode ImgProdLockBytes::WriteAt(sal_uInt64 const nPos,
120 const void* pBuffer, std::size_t nCount, std::size_t * pWritten)
121{
122 if( GetStream() )
123 return SvLockBytes::WriteAt( nPos, pBuffer, nCount, pWritten );
124 else
125 {
126 DBG_ASSERT( xStmRef.is(), "ImgProdLockBytes::WriteAt: xInputStream has no reference..." );
128 }
129}
130
131
132ErrCode ImgProdLockBytes::Flush() const
133{
134 return ERRCODE_NONE;
135}
136
137
138ErrCode ImgProdLockBytes::SetSize(sal_uInt64 const nSize)
139{
140 if( GetStream() )
141 return SvLockBytes::SetSize( nSize );
142 else
143 {
144 OSL_FAIL( "ImgProdLockBytes::SetSize not supported for xInputStream..." );
146 }
147}
148
149
150ErrCode ImgProdLockBytes::Stat( SvLockBytesStat* pStat ) const
151{
152 if( GetStream() )
153 return SvLockBytes::Stat( pStat );
154 else
155 {
156 DBG_ASSERT( xStmRef.is(), "ImgProdLockBytes::Stat: xInputStream has no reference..." );
157 pStat->nSize = maSeq.getLength();
158 return ERRCODE_NONE;
159 }
160}
161
162
164 : mnTransIndex(0)
165 , mbConsInit(false)
166{
167 moGraphic.emplace();
168}
169
171{
172}
173
174
175// XInterface
176css::uno::Any ImageProducer::queryInterface( const css::uno::Type & rType )
177{
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 ));
183}
184
185
186void ImageProducer::addConsumer( const css::uno::Reference< css::awt::XImageConsumer >& rxConsumer )
187{
188 DBG_ASSERT( rxConsumer.is(), "::AddConsumer(...): No consumer referenced!" );
189 if( rxConsumer.is() )
190 maConsList.push_back( rxConsumer );
191}
192
193
194void ImageProducer::removeConsumer( const css::uno::Reference< css::awt::XImageConsumer >& rxConsumer )
195{
196 ConsumerList_t::reverse_iterator riter = std::find(maConsList.rbegin(),maConsList.rend(),rxConsumer);
197
198 if (riter != maConsList.rend())
199 maConsList.erase(riter.base()-1);
200}
201
202
203void ImageProducer::SetImage( const OUString& rPath )
204{
205 maURL = rPath;
206 moGraphic->Clear();
207 mbConsInit = false;
208 mpStm.reset();
209
210 if ( ::svt::GraphicAccess::isSupportedURL( maURL ) )
211 {
212 mpStm = ::svt::GraphicAccess::getImageStream( ::comphelper::getProcessComponentContext(), maURL );
213 }
214 else if( !maURL.isEmpty() )
215 {
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 ) ) );
219 }
220}
221
222
224{
225 maURL.clear();
226 moGraphic->Clear();
227 mbConsInit = false;
228
229 mpStm.reset( new SvStream( new ImgProdLockBytes( &rStm, false ) ) );
230}
231
232
233void ImageProducer::setImage( css::uno::Reference< css::io::XInputStream > const & rInputStmRef )
234{
235 maURL.clear();
236 moGraphic->Clear();
237 mbConsInit = false;
238 mpStm.reset();
239
240 if( rInputStmRef.is() )
241 mpStm.reset( new SvStream( new ImgProdLockBytes( rInputStmRef ) ) );
242}
243
244
246{
247 if( ( GraphicType::NONE == moGraphic->GetType() ) || moGraphic->GetReaderContext() )
249}
250
251
253{
254 if( maConsList.empty() && !maDoneHdl.IsSet() )
255 return;
256
257 bool bNotifyEmptyGraphics = false;
258
259 // valid stream or filled graphic? => update consumers
260 if( mpStm || ( moGraphic->GetType() != GraphicType::NONE ) )
261 {
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() )
265 {
268 }
269
270 if( moGraphic->GetType() != GraphicType::NONE )
272 else
273 bNotifyEmptyGraphics = true;
274 }
275 else
276 bNotifyEmptyGraphics = true;
277
278 if ( !bNotifyEmptyGraphics )
279 return;
280
281 // reset image
282 // create temporary list to hold interfaces
284
285 // iterate through interfaces
286 for (auto const& elem : aTmp)
287 {
288 elem->init( 0, 0 );
289 elem->complete( css::awt::ImageStatus::IMAGESTATUS_STATICIMAGEDONE, this );
290 }
291
292 maDoneHdl.Call( nullptr );
293}
294
295
297{
298 if (!mpStm)
299 return false;
300
301 if( ERRCODE_IO_PENDING == mpStm->GetError() )
302 mpStm->ResetError();
303
304 mpStm->Seek( 0 );
305
306 bool bRet = GraphicConverter::Import( *mpStm, rGraphic ) == ERRCODE_NONE;
307
308 if( ERRCODE_IO_PENDING == mpStm->GetError() )
309 mpStm->ResetError();
310
311 return bRet;
312}
313
314
316{
317 ImplInitConsumer( rGraphic );
318
319 if( mbConsInit && !maConsList.empty() )
320 {
321 // create temporary list to hold interfaces
323
324 ImplUpdateConsumer( rGraphic );
325 mbConsInit = false;
326
327 // iterate through interfaces
328 for (auto const& elem : aTmp)
329 elem->complete( css::awt::ImageStatus::IMAGESTATUS_STATICIMAGEDONE, this );
330 }
331}
332
333
335{
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;
343 css::uno::Sequence< sal_Int32 > aRGBPal;
344 rGraphic.GetBitmapEx().GetColorModel(aRGBPal, nRMask, nGMask, nBMask, nAMask, mnTransIndex, nWidth, nHeight, nBitCount);
345
346 // create temporary list to hold interfaces
348
349 // iterate through interfaces
350 for (auto const& elem : aTmp)
351 {
352 elem->init( nWidth, nHeight );
353 elem->setColorModel( nBitCount,aRGBPal, nRMask, nGMask, nBMask, nAMask );
354 }
355
356 mbConsInit = true;
357}
358
359
361{
362 BitmapEx aBmpEx( rGraphic.GetBitmapEx() );
363 Bitmap aBmp( aBmpEx.GetBitmap() );
364 BitmapReadAccess* pBmpAcc = aBmp.AcquireReadAccess();
365
366 if( !pBmpAcc )
367 return;
368
369 AlphaMask 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;
379
380 if( !pMskAcc )
381 {
382 aMask = AlphaMask(aBmp.GetSizePixel());
383 aMask.Erase( 0 );
384 pMskAcc = aMask.AcquireReadAccess();
385 }
386
387 // create temporary list to hold interfaces
389
390 if( pBmpAcc->HasPalette() )
391 {
392 const BitmapColor aWhite( pMskAcc->GetBestMatchingColor( COL_ALPHA_TRANSPARENT ) );
393
394 if( mnTransIndex < 256 )
395 {
396 css::uno::Sequence<sal_Int8> aData( nPartWidth * nPartHeight );
397 sal_Int8* pTmp = aData.getArray();
398
399 for( tools::Long nY = nStartY; nY <= nEndY; nY++ )
400 {
401 Scanline pScanlineMask = pMskAcc->GetScanline( nY );
402 Scanline pScanline = pBmpAcc->GetScanline( nY );
403 for( tools::Long nX = nStartX; nX <= nEndX; nX++ )
404 {
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();
410 }
411 }
412
413 // iterate through interfaces
414 for (auto const& elem : aTmp)
415 elem->setPixelsByBytes( nStartX, nStartY, nPartWidth, nPartHeight, aData, 0UL, nPartWidth );
416 }
417 else
418 {
419 css::uno::Sequence<sal_Int32> aData( nPartWidth * nPartHeight );
420 sal_Int32* pTmp = aData.getArray();
421
422 for( tools::Long nY = nStartY; nY <= nEndY; nY++ )
423 {
424 Scanline pScanlineMask = pMskAcc->GetScanline( nY );
425 Scanline pScanline = pBmpAcc->GetScanline( nY );
426 for( tools::Long nX = nStartX; nX <= nEndX; nX++ )
427 {
428 if( pMskAcc->GetPixelFromData( pScanlineMask, nX ) == aWhite )
429 *pTmp++ = mnTransIndex;
430 else
431 *pTmp++ = pBmpAcc->GetPixelFromData( pScanline, nX ).GetIndex();
432 }
433 }
434
435 // iterate through interfaces
436 for (auto const& elem : aTmp)
437 elem->setPixelsByLongs( nStartX, nStartY, nPartWidth, nPartHeight, aData, 0UL, nPartWidth );
438 }
439 }
440 else
441 {
442 css::uno::Sequence<sal_Int32> aData( nPartWidth * nPartHeight );
443 const BitmapColor aWhite( pMskAcc->GetBestMatchingColor( COL_WHITE ) );
444 sal_Int32* pTmp = aData.getArray();
445
446 for( tools::Long nY = nStartY; nY <= nEndY; nY++ )
447 {
448 Scanline pScanlineMask = pMskAcc->GetScanline( nY );
449 Scanline pScanline = pBmpAcc->GetScanline( nY );
450 for( tools::Long nX = nStartX; nX <= nEndX; nX++, pTmp++ )
451 {
452 const BitmapColor aCol( pBmpAcc->GetPixelFromData( pScanline, nX ) );
453
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;
457
458 if( pMskAcc->GetPixelFromData( pScanlineMask, nX ) != aWhite )
459 *pTmp |= 0x000000ffUL;
460 }
461 }
462
463 // iterate through interfaces
464 for (auto const& elem : aTmp)
465 elem->setPixelsByLongs( nStartX, nStartY, nPartWidth, nPartHeight, aData, 0UL, nPartWidth );
466 }
467
468 Bitmap::ReleaseAccess( pBmpAcc );
469 Bitmap::ReleaseAccess( pMskAcc );
470}
471
472
473void ImageProducer::initialize( const css::uno::Sequence< css::uno::Any >& aArguments )
474{
475 if ( aArguments.getLength() == 1 )
476 {
477 css::uno::Any aArg = aArguments.getConstArray()[0];
478 OUString aURL;
479 if ( aArg >>= aURL )
480 {
481 SetImage( aURL );
482 }
483 }
484}
485
487 return "com.sun.star.form.ImageProducer";
488}
489
490sal_Bool ImageProducer::supportsService(OUString const & ServiceName) {
492}
493
494css::uno::Sequence<OUString> ImageProducer::getSupportedServiceNames() {
495 return {"com.sun.star.awt.ImageProducer"};
496}
497
498
499extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
501 css::uno::Sequence<css::uno::Any> const &)
502{
503 return cppu::acquire(new ImageProducer());
504}
505
506/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
sal_uInt8 * Scanline
bool IsEmpty() const
void Erase(sal_uInt8 cTransparency)
sal_uInt8 GetIndex() const
const AlphaMask & GetAlphaMask() const
Bitmap GetBitmap(Color aTransparentReplaceColor) const
void GetColorModel(css::uno::Sequence< sal_Int32 > &rRGBPalette, sal_uInt32 &rnRedMask, sal_uInt32 &rnGreenMask, sal_uInt32 &rnBlueMask, sal_uInt32 &rnAlphaMask, sal_uInt32 &rnTransparencyIndex, sal_uInt32 &rnWidth, sal_uInt32 &rnHeight, sal_uInt8 &rnBitCount)
tools::Long Height() const
tools::Long Width() const
BitmapColor GetBestMatchingColor(const BitmapColor &rBitmapColor) const
bool HasPalette() const
BitmapColor GetPixelFromData(const sal_uInt8 *pData, tools::Long nX) const
Scanline GetScanline(tools::Long nY) const
Size GetSizePixel() const
static void ReleaseAccess(BitmapInfoAccess *pAccess)
BitmapReadAccess * AcquireReadAccess()
static ErrCode Import(SvStream &rIStm, Graphic &rGraphic, ConvertDataFormat nFormat=ConvertDataFormat::Unknown)
BitmapEx GetBitmapEx(const GraphicConversionParameters &rParameters=GraphicConversionParameters()) const
void SAL_CALL removeConsumer(const css::uno::Reference< css::awt::XImageConsumer > &rxConsumer) override
Definition: imgprod.cxx:194
bool ImplImportGraphic(Graphic &rGraphic)
Definition: imgprod.cxx:296
void SAL_CALL startProduction() override
Definition: imgprod.cxx:252
OUString SAL_CALL getImplementationName() override
Definition: imgprod.cxx:486
ConsumerList_t maConsList
Definition: imgprod.hxx:48
std::unique_ptr< SvStream > mpStm
Definition: imgprod.hxx:52
void SAL_CALL addConsumer(const css::uno::Reference< css::awt::XImageConsumer > &rxConsumer) override
Definition: imgprod.cxx:186
std::vector< css::uno::Reference< css::awt::XImageConsumer > > ConsumerList_t
Definition: imgprod.hxx:45
bool mbConsInit
Definition: imgprod.hxx:54
sal_uInt32 mnTransIndex
Definition: imgprod.hxx:53
OUString maURL
Definition: imgprod.hxx:47
void ImplUpdateData(const Graphic &rGraphic)
Definition: imgprod.cxx:315
virtual ~ImageProducer() override
Definition: imgprod.cxx:170
void SAL_CALL initialize(const css::uno::Sequence< css::uno::Any > &aArguments) override
Definition: imgprod.cxx:473
void ImplInitConsumer(const Graphic &rGraphic)
Definition: imgprod.cxx:334
css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override
Definition: imgprod.cxx:494
void SetImage(const OUString &rPath)
Definition: imgprod.cxx:203
css::uno::Any SAL_CALL queryInterface(const css::uno::Type &rType) override
Definition: imgprod.cxx:176
void ImplUpdateConsumer(const Graphic &rGraphic)
Definition: imgprod.cxx:360
void NewDataAvailable()
Definition: imgprod.cxx:245
std::optional< Graphic > moGraphic
Definition: imgprod.hxx:50
Link< Graphic *, void > maDoneHdl
Definition: imgprod.hxx:55
sal_Bool SAL_CALL supportsService(OUString const &ServiceName) override
Definition: imgprod.cxx:490
void setImage(css::uno::Reference< css::io::XInputStream > const &rStmRef)
Definition: imgprod.cxx:233
virtual ErrCode WriteAt(sal_uInt64 nPos, const void *pBuffer, std::size_t nCount, std::size_t *pWritten)
virtual ErrCode ReadAt(sal_uInt64 nPos, void *pBuffer, std::size_t nCount, std::size_t *pRead) const
virtual ErrCode Flush() const
virtual ErrCode Stat(SvLockBytesStat *pStat) const
virtual ErrCode SetSize(sal_uInt64 nSize)
static std::unique_ptr< SvStream > CreateStream(const OUString &rFileName, StreamMode eOpenMode, css::uno::Reference< css::awt::XWindow > xParentWin=nullptr)
constexpr ::Color COL_WHITE(0xFF, 0xFF, 0xFF)
constexpr ::Color COL_ALPHA_TRANSPARENT(0x00, 0x00, 0x00)
int nCount
#define DBG_ASSERT(sCon, aError)
URL aURL
#define ERRCODE_IO_PENDING
#define ERRCODE_IO_CANTWRITE
#define ERRCODE_NONE
SAL_DLLPUBLIC_EXPORT css::uno::XInterface * com_sun_star_form_ImageProducer_get_implementation(css::uno::XComponentContext *, css::uno::Sequence< css::uno::Any > const &)
Definition: imgprod.cxx:500
Sequence< PropertyValue > aArguments
short nBitCount
constexpr OUStringLiteral aData
bool CPPUHELPER_DLLPUBLIC supportsService(css::lang::XServiceInfo *implementation, rtl::OUString const &name)
long Long
std::size_t nSize
unsigned char sal_uInt8
unsigned char sal_Bool
signed char sal_Int8