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 <boost/scoped_array.hpp>
22 #include <osl/file.hxx>
23 #include <tools/debug.hxx>
24 #include <tools/stream.hxx>
26 #include <tools/rc.hxx>
27 #include <tools/resmgr.hxx>
28 #include <vcl/settings.hxx>
29 #include <vcl/outdev.hxx>
30 #include <vcl/graph.hxx>
31 #include <vcl/graphicfilter.hxx>
32 #include <vcl/svapp.hxx>
33 #include <vcl/image.hxx>
34 #include <vcl/imagerepository.hxx>
35 #include <vcl/implimagetree.hxx>
38 #if OSL_DEBUG_LEVEL > 0
39 #include <rtl/strbuf.hxx>
42 using namespace ::com::sun::star
;
49 Image::Image( const ResId
& rResId
) :
53 rResId
.SetRT( RSC_IMAGE
);
55 ResMgr
* pResMgr
= rResId
.GetResMgr();
56 if( pResMgr
&& pResMgr
->GetResource( rResId
) )
58 pResMgr
->Increment( sizeof( RSHEADER_TYPE
) );
61 sal_uLong nObjMask
= pResMgr
->ReadLong();
63 if( nObjMask
& RSC_IMAGE_IMAGEBITMAP
)
65 aBmpEx
= BitmapEx( ResId( static_cast<RSHEADER_TYPE
*>(pResMgr
->GetClass()), *pResMgr
) );
66 pResMgr
->Increment( ResMgr::GetObjSize( static_cast<RSHEADER_TYPE
*>(pResMgr
->GetClass()) ) );
69 if( nObjMask
& RSC_IMAGE_MASKBITMAP
)
71 if( !aBmpEx
.IsEmpty() && aBmpEx
.GetTransparentType() == TRANSPARENT_NONE
)
73 const Bitmap
aMaskBitmap( ResId( static_cast<RSHEADER_TYPE
*>(pResMgr
->GetClass()), *pResMgr
) );
74 aBmpEx
= BitmapEx( aBmpEx
.GetBitmap(), aMaskBitmap
);
77 pResMgr
->Increment( ResMgr::GetObjSize( static_cast<RSHEADER_TYPE
*>(pResMgr
->GetClass()) ) );
80 if( nObjMask
& RSC_IMAGE_MASKCOLOR
)
82 if( !aBmpEx
.IsEmpty() && aBmpEx
.GetTransparentType() == TRANSPARENT_NONE
)
84 const Color
aMaskColor( ResId( static_cast<RSHEADER_TYPE
*>(pResMgr
->GetClass()), *pResMgr
) );
85 aBmpEx
= BitmapEx( aBmpEx
.GetBitmap(), aMaskColor
);
88 pResMgr
->Increment( ResMgr::GetObjSize( static_cast<RSHEADER_TYPE
*>(pResMgr
->GetClass()) ) );
90 if( ! aBmpEx
.IsEmpty() )
95 Image::Image( const Image
& rImage
) :
96 mpImplData( rImage
.mpImplData
)
100 ++mpImplData
->mnRefCount
;
103 Image::Image( const BitmapEx
& rBitmapEx
) :
107 ImplInit( rBitmapEx
);
110 Image::Image( const Bitmap
& rBitmap
) :
117 Image::Image( const Bitmap
& rBitmap
, const Bitmap
& rMaskBitmap
) :
121 const BitmapEx
aBmpEx( rBitmap
, rMaskBitmap
);
126 Image::Image( const Bitmap
& rBitmap
, const Color
& rColor
) :
130 const BitmapEx
aBmpEx( rBitmap
, rColor
);
135 Image::Image( const uno::Reference
< graphic::XGraphic
>& rxGraphic
) :
139 const Graphic
aGraphic( rxGraphic
);
140 ImplInit( aGraphic
.GetBitmapEx() );
143 Image::Image( const OUString
&rFileUrl
) :
147 osl::FileBase::getSystemPathFromFileURL( rFileUrl
, aTmp
);
149 const OUString
aFilterName( IMP_PNG
);
150 if( GRFILTER_OK
== GraphicFilter::LoadGraphic( aTmp
, aFilterName
, aGraphic
) )
152 ImplInit( aGraphic
.GetBitmapEx() );
159 if( mpImplData
&& ( 0 == --mpImplData
->mnRefCount
) )
163 void Image::ImplInit( const BitmapEx
& rBmpEx
)
165 if( !rBmpEx
.IsEmpty() )
167 mpImplData
= new ImplImage
;
169 if( rBmpEx
.GetTransparentType() == TRANSPARENT_NONE
)
171 mpImplData
->meType
= IMAGETYPE_BITMAP
;
172 mpImplData
->mpData
= new Bitmap( rBmpEx
.GetBitmap() );
176 mpImplData
->meType
= IMAGETYPE_IMAGE
;
177 mpImplData
->mpData
= new ImplImageData( rBmpEx
);
182 Size
Image::GetSizePixel() const
189 switch( mpImplData
->meType
)
191 case IMAGETYPE_BITMAP
:
192 aRet
= static_cast< Bitmap
* >( mpImplData
->mpData
)->GetSizePixel();
195 case IMAGETYPE_IMAGE
:
196 aRet
= static_cast< ImplImageData
* >( mpImplData
->mpData
)->maBmpEx
.GetSizePixel();
204 BitmapEx
Image::GetBitmapEx() const
211 switch( mpImplData
->meType
)
213 case IMAGETYPE_BITMAP
:
214 aRet
= *static_cast< Bitmap
* >( mpImplData
->mpData
);
217 case IMAGETYPE_IMAGE
:
218 aRet
= static_cast< ImplImageData
* >( mpImplData
->mpData
)->maBmpEx
;
226 uno::Reference
< graphic::XGraphic
> Image::GetXGraphic() const
228 const Graphic
aGraphic( GetBitmapEx() );
230 return aGraphic
.GetXGraphic();
233 Image
& Image::operator=( const Image
& rImage
)
236 if( rImage
.mpImplData
)
237 ++rImage
.mpImplData
->mnRefCount
;
239 if( mpImplData
&& ( 0 == --mpImplData
->mnRefCount
) )
242 mpImplData
= rImage
.mpImplData
;
247 bool Image::operator==( const Image
& rImage
) const
252 if( rImage
.mpImplData
== mpImplData
)
254 else if( !rImage
.mpImplData
|| !mpImplData
)
256 else if( rImage
.mpImplData
->mpData
== mpImplData
->mpData
)
258 else if( rImage
.mpImplData
->meType
== mpImplData
->meType
)
260 switch( mpImplData
->meType
)
262 case IMAGETYPE_BITMAP
:
263 bRet
= ( *static_cast< Bitmap
* >( rImage
.mpImplData
->mpData
) == *static_cast< Bitmap
* >( mpImplData
->mpData
) );
266 case IMAGETYPE_IMAGE
:
267 bRet
= static_cast< ImplImageData
* >( rImage
.mpImplData
->mpData
)->IsEqual( *static_cast< ImplImageData
* >( mpImplData
->mpData
) );
279 ImageList::ImageList( sal_uInt16 nInit
, sal_uInt16 nGrow
) :
286 ImageList::ImageList( const ResId
& rResId
) :
291 SAL_INFO( "vcl.gdi", "vcl: ImageList::ImageList( const ResId& rResId )" );
293 rResId
.SetRT( RSC_IMAGELIST
);
295 ResMgr
* pResMgr
= rResId
.GetResMgr();
297 if( pResMgr
&& pResMgr
->GetResource( rResId
) )
299 pResMgr
->Increment( sizeof( RSHEADER_TYPE
) );
301 sal_uLong nObjMask
= pResMgr
->ReadLong();
302 pResMgr
->ReadString(); //skip string
303 std::unique_ptr
< Color
> xMaskColor
;
305 if( nObjMask
& RSC_IMAGE_MASKCOLOR
)
306 xMaskColor
.reset( new Color( ResId( static_cast<RSHEADER_TYPE
*>(pResMgr
->GetClass()), *pResMgr
) ) );
308 pResMgr
->Increment( ResMgr::GetObjSize( static_cast<RSHEADER_TYPE
*>(pResMgr
->GetClass()) ) );
310 if( nObjMask
& RSC_IMAGELIST_IDLIST
)
312 for( sal_Int32 i
= 0, nCount
= pResMgr
->ReadLong(); i
< nCount
; ++i
)
316 sal_Int32 nCount
= pResMgr
->ReadLong();
317 ImplInit( static_cast< sal_uInt16
>( nCount
), Size() );
320 for( sal_Int32 i
= 0; i
< nCount
; ++i
)
322 OUString aName
= pResMgr
->ReadString();
323 sal_uInt16 nId
= static_cast< sal_uInt16
>( pResMgr
->ReadLong() );
324 mpImplData
->AddImage( aName
, nId
, aEmpty
);
327 if( nObjMask
& RSC_IMAGELIST_IDCOUNT
)
328 pResMgr
->ReadShort();
332 ImageList::ImageList( const ::std::vector
< OUString
>& rNameVector
,
333 const OUString
& rPrefix
,
339 SAL_INFO( "vcl.gdi", "vcl: ImageList::ImageList(const vector< OUString >& ..." );
341 ImplInit( sal::static_int_cast
< sal_uInt16
>( rNameVector
.size() ), Size() );
343 mpImplData
->maPrefix
= rPrefix
;
344 for( sal_uInt32 i
= 0; i
< rNameVector
.size(); ++i
)
346 mpImplData
->AddImage( rNameVector
[ i
], static_cast< sal_uInt16
>( i
) + 1, BitmapEx() );
350 ImageList::ImageList( const ImageList
& rImageList
) :
351 mpImplData( rImageList
.mpImplData
),
352 mnInitSize( rImageList
.mnInitSize
),
353 mnGrowSize( rImageList
.mnGrowSize
)
357 ++mpImplData
->mnRefCount
;
360 ImageList::~ImageList()
362 if( mpImplData
&& ( 0 == --mpImplData
->mnRefCount
) )
366 void ImageList::ImplInit( sal_uInt16 nItems
, const Size
&rSize
)
368 mpImplData
= new ImplImageList
;
369 mpImplData
->maImages
.reserve( nItems
);
370 mpImplData
->maImageSize
= rSize
;
373 void ImageAryData::Load(const OUString
&rPrefix
)
375 OUString aIconTheme
= Application::GetSettings().GetStyleSettings().DetermineIconTheme();
379 OUString aFileName
= rPrefix
;
381 #if OSL_DEBUG_LEVEL > 0
384 ImplImageTree::get().loadImage(aFileName
, aIconTheme
, maBitmapEx
, true);
385 #if OSL_DEBUG_LEVEL > 0
388 OStringBuffer aMessage
;
389 aMessage
.append( "ImageAryData::Load: failed to load image '" );
390 aMessage
.append( OUStringToOString( aFileName
, RTL_TEXTENCODING_UTF8
).getStr() );
391 aMessage
.append( "'" );
392 OSL_FAIL( aMessage
.makeStringAndClear().getStr() );
397 // FIXME: Rather a performance hazard
398 BitmapEx
ImageList::GetAsHorizontalStrip() const
400 Size
aSize( mpImplData
->maImageSize
);
401 sal_uInt16 nCount
= GetImageCount();
404 aSize
.Width() *= nCount
;
406 // Load any stragglers
407 for (sal_uInt16 nIdx
= 0; nIdx
< nCount
; nIdx
++)
409 ImageAryData
*pData
= mpImplData
->maImages
[ nIdx
];
410 if( pData
->IsLoadable() )
411 pData
->Load( mpImplData
->maPrefix
);
414 BitmapEx aTempl
= mpImplData
->maImages
[ 0 ]->maBitmapEx
;
416 Bitmap
aPixels( aSize
, aTempl
.GetBitmap().GetBitCount() );
417 if( aTempl
.IsAlpha() )
418 aResult
= BitmapEx( aPixels
, AlphaMask( aSize
) );
419 else if( aTempl
.IsTransparent() )
420 aResult
= BitmapEx( aPixels
, Bitmap( aSize
, aTempl
.GetMask().GetBitCount() ) );
422 aResult
= BitmapEx( aPixels
);
424 Rectangle
aSrcRect( Point( 0, 0 ), mpImplData
->maImageSize
);
425 for (sal_uInt16 nIdx
= 0; nIdx
< nCount
; nIdx
++)
427 Rectangle
aDestRect( Point( nIdx
* mpImplData
->maImageSize
.Width(), 0 ),
428 mpImplData
->maImageSize
);
429 ImageAryData
*pData
= mpImplData
->maImages
[ nIdx
];
430 aResult
.CopyPixel( aDestRect
, aSrcRect
, &pData
->maBitmapEx
);
436 void ImageList::InsertFromHorizontalStrip( const BitmapEx
&rBitmapEx
,
437 const std::vector
< OUString
> &rNameVector
)
439 sal_uInt16 nItems
= sal::static_int_cast
< sal_uInt16
>( rNameVector
.size() );
444 Size
aSize( rBitmapEx
.GetSizePixel() );
445 DBG_ASSERT (rBitmapEx
.GetSizePixel().Width() % nItems
== 0,
446 "ImageList::InsertFromHorizontalStrip - very odd size");
447 aSize
.Width() /= nItems
;
448 ImplInit( nItems
, aSize
);
450 for (sal_uInt16 nIdx
= 0; nIdx
< nItems
; nIdx
++)
452 BitmapEx
aBitmap( rBitmapEx
, Point( nIdx
* aSize
.Width(), 0 ), aSize
);
453 mpImplData
->AddImage( rNameVector
[ nIdx
], nIdx
+ 1, aBitmap
);
457 void ImageList::InsertFromHorizontalBitmap( const ResId
& rResId
,
459 const Color
*pMaskColor
,
460 const Color
*pSearchColors
,
461 const Color
*pReplaceColors
,
462 sal_uLong nColorCount
)
464 BitmapEx
aBmpEx( rResId
);
465 if (!aBmpEx
.IsTransparent())
468 aBmpEx
= BitmapEx( aBmpEx
.GetBitmap(), *pMaskColor
);
470 aBmpEx
= BitmapEx( aBmpEx
.GetBitmap() );
472 if ( nColorCount
&& pSearchColors
&& pReplaceColors
)
473 aBmpEx
.Replace( pSearchColors
, pReplaceColors
, nColorCount
);
475 std::vector
< OUString
> aNames( nCount
);
476 InsertFromHorizontalStrip( aBmpEx
, aNames
);
479 sal_uInt16
ImageList::ImplGetImageId( const OUString
& rImageName
) const
482 ImageAryData
*pImg
= mpImplData
->maNameHash
[ rImageName
];
489 void ImageList::AddImage( const OUString
& rImageName
, const Image
& rImage
)
491 DBG_ASSERT( GetImagePos( rImageName
) == IMAGELIST_IMAGE_NOTFOUND
, "ImageList::AddImage() - ImageName already exists" );
494 ImplInit( 0, rImage
.GetSizePixel() );
496 mpImplData
->AddImage( rImageName
, GetImageCount() + 1,
497 rImage
.GetBitmapEx() );
500 void ImageList::ReplaceImage( const OUString
& rImageName
, const Image
& rImage
)
502 const sal_uInt16 nId
= ImplGetImageId( rImageName
);
506 //Just replace the bitmap rather than doing RemoveImage / AddImage
507 //which breaks index-based iteration.
508 ImageAryData
*pImg
= mpImplData
->maNameHash
[ rImageName
];
509 pImg
->maBitmapEx
= rImage
.GetBitmapEx();
513 void ImageList::RemoveImage( sal_uInt16 nId
)
516 for( sal_uInt32 i
= 0; i
< mpImplData
->maImages
.size(); ++i
)
518 if( mpImplData
->maImages
[ i
]->mnId
== nId
)
520 mpImplData
->RemoveImage( static_cast< sal_uInt16
>( i
) );
526 Image
ImageList::GetImage( sal_uInt16 nId
) const
533 std::vector
<ImageAryData
*>::iterator aIter
;
534 for( aIter
= mpImplData
->maImages
.begin();
535 aIter
!= mpImplData
->maImages
.end(); ++aIter
)
537 if ((*aIter
)->mnId
== nId
)
539 if( (*aIter
)->IsLoadable() )
540 (*aIter
)->Load( mpImplData
->maPrefix
);
542 aRet
= Image( (*aIter
)->maBitmapEx
);
550 bool res
= vcl::ImageRepository::loadDefaultImage(rBitmap
);
552 aRet
= Image(rBitmap
);
558 Image
ImageList::GetImage( const OUString
& rImageName
) const
562 ImageAryData
*pImg
= mpImplData
->maNameHash
[ rImageName
];
566 if( pImg
->IsLoadable() )
567 pImg
->Load( mpImplData
->maPrefix
);
568 return Image( pImg
->maBitmapEx
);
575 sal_uInt16
ImageList::GetImageCount() const
578 return mpImplData
? static_cast< sal_uInt16
>( mpImplData
->maImages
.size() ) : 0;
581 sal_uInt16
ImageList::GetImagePos( sal_uInt16 nId
) const
584 if( mpImplData
&& nId
)
586 for( sal_uInt32 i
= 0; i
< mpImplData
->maImages
.size(); ++i
)
588 if (mpImplData
->maImages
[ i
]->mnId
== nId
)
589 return static_cast< sal_uInt16
>( i
);
593 return IMAGELIST_IMAGE_NOTFOUND
;
596 bool ImageList::HasImageAtPos( sal_uInt16 nId
) const
598 return GetImagePos( nId
) != IMAGELIST_IMAGE_NOTFOUND
;
601 sal_uInt16
ImageList::GetImagePos( const OUString
& rImageName
) const
604 if( mpImplData
&& !rImageName
.isEmpty() )
606 for( sal_uInt32 i
= 0; i
< mpImplData
->maImages
.size(); i
++ )
608 if (mpImplData
->maImages
[i
]->maName
== rImageName
)
609 return static_cast< sal_uInt16
>( i
);
613 return IMAGELIST_IMAGE_NOTFOUND
;
616 sal_uInt16
ImageList::GetImageId( sal_uInt16 nPos
) const
619 if( mpImplData
&& (nPos
< GetImageCount()) )
620 return mpImplData
->maImages
[ nPos
]->mnId
;
625 OUString
ImageList::GetImageName( sal_uInt16 nPos
) const
628 if( mpImplData
&& (nPos
< GetImageCount()) )
629 return mpImplData
->maImages
[ nPos
]->maName
;
634 void ImageList::GetImageNames( ::std::vector
< OUString
>& rNames
) const
636 SAL_INFO( "vcl.gdi", "vcl: ImageList::GetImageNames" );
638 rNames
= ::std::vector
< OUString
>();
642 for( sal_uInt32 i
= 0; i
< mpImplData
->maImages
.size(); i
++ )
644 const OUString
& rName( mpImplData
->maImages
[ i
]->maName
);
645 if( !rName
.isEmpty())
646 rNames
.push_back( rName
);
651 Size
ImageList::GetImageSize() const
658 aRet
= mpImplData
->maImageSize
;
660 // force load of 1st image to see - uncommon case.
661 if( aRet
.Width() == 0 && aRet
.Height() == 0 &&
662 !mpImplData
->maImages
.empty() )
664 Image aTmp
= GetImage( mpImplData
->maImages
[ 0 ]->mnId
);
665 aRet
= mpImplData
->maImageSize
= aTmp
.GetSizePixel();
671 ImageList
& ImageList::operator=( const ImageList
& rImageList
)
674 if( rImageList
.mpImplData
)
675 ++rImageList
.mpImplData
->mnRefCount
;
677 if( mpImplData
&& ( 0 == --mpImplData
->mnRefCount
) )
680 mpImplData
= rImageList
.mpImplData
;
685 bool ImageList::operator==( const ImageList
& rImageList
) const
690 if( rImageList
.mpImplData
== mpImplData
)
692 else if( !rImageList
.mpImplData
|| !mpImplData
)
694 else if( rImageList
.GetImageCount() == GetImageCount() &&
695 rImageList
.mpImplData
->maImageSize
== mpImplData
->maImageSize
)
696 bRet
= true; // strange semantic
701 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */