20#include <com/sun/star/geometry/RealSize2D.hpp>
21#include <com/sun/star/geometry/IntegerSize2D.hpp>
22#include <com/sun/star/geometry/IntegerPoint2D.hpp>
23#include <com/sun/star/geometry/IntegerRectangle2D.hpp>
25#include <com/sun/star/rendering/ColorSpaceType.hpp>
26#include <com/sun/star/rendering/RenderingIntent.hpp>
27#include <com/sun/star/rendering/VolatileContentDestroyedException.hpp>
28#include <com/sun/star/rendering/XBitmap.hpp>
29#include <com/sun/star/rendering/IntegerBitmapLayout.hpp>
30#include <com/sun/star/rendering/ColorComponentTag.hpp>
44#include <canvasbitmap.hxx>
54 SAL_INFO(
"vcl.helper",
"vcl::unotools::xBitmapFromBitmapEx()" );
61 bool equalsLayout(
const rendering::IntegerBitmapLayout& rLHS,
62 const rendering::IntegerBitmapLayout& rRHS )
65 rLHS.ScanLineBytes == rRHS.ScanLineBytes &&
66 rLHS.ScanLineStride == rRHS.ScanLineStride &&
67 rLHS.PlaneStride == rRHS.PlaneStride &&
68 rLHS.ColorSpace == rRHS.ColorSpace &&
69 rLHS.Palette == rRHS.Palette &&
70 rLHS.IsMsbFirst == rRHS.IsMsbFirst;
72 bool readBmp( sal_Int32 nWidth,
74 const rendering::IntegerBitmapLayout& rLayout,
75 const uno::Reference< rendering::XIntegerReadOnlyBitmap >& xInputBitmap,
79 rendering::IntegerBitmapLayout aCurrLayout;
80 geometry::IntegerRectangle2D aRect;
81 uno::Sequence<sal_Int8> aPixelData;
82 uno::Sequence<rendering::RGBColor> aRGBColors;
83 uno::Sequence<rendering::ARGBColor> aARGBColors;
85 for( aRect.Y1=0; aRect.Y1<nHeight; ++aRect.Y1 )
87 aRect.X1 = 0; aRect.X2 = nWidth; aRect.Y2 = aRect.Y1+1;
90 aPixelData = xInputBitmap->getData(aCurrLayout,aRect);
92 catch( rendering::VolatileContentDestroyedException& )
97 if( !equalsLayout(aCurrLayout, rLayout) )
100 Scanline pScanline = rWriteAcc->GetScanline( aRect.Y1 );
101 if( rAlphaAcc.
get() )
103 Scanline pScanlineAlpha = rAlphaAcc->GetScanline( aRect.Y1 );
105 aARGBColors = rLayout.ColorSpace->convertIntegerToARGB(aPixelData);
107 if( rWriteAcc->HasPalette() )
109 for( sal_Int32 x=0;
x<nWidth; ++
x )
111 const rendering::ARGBColor& rColor=aARGBColors[
x];
112 rWriteAcc->SetPixelOnData( pScanline, x,
117 rAlphaAcc->SetPixelOnData( pScanlineAlpha, x,
123 for( sal_Int32 x=0;
x<nWidth; ++
x )
125 const rendering::ARGBColor& rColor=aARGBColors[
x];
126 rWriteAcc->SetPixelOnData( pScanline, x,
130 rAlphaAcc->SetPixelOnData( pScanlineAlpha, x,
138 aRGBColors = rLayout.ColorSpace->convertIntegerToRGB(aPixelData);
139 if( rWriteAcc->HasPalette() )
141 for( sal_Int32 x=0;
x<nWidth; ++
x )
143 const rendering::RGBColor& rColor=aRGBColors[
x];
144 rWriteAcc->SetPixelOnData( pScanline, x,
153 for( sal_Int32 x=0;
x<nWidth; ++
x )
155 const rendering::RGBColor& rColor=aRGBColors[
x];
156 rWriteAcc->SetPixelOnData( pScanline, x,
171 SAL_INFO(
"vcl.helper",
"vcl::unotools::bitmapExFromXBitmap()" );
173 if( !xInputBitmap.is() )
187 for(
int i=0;
i<10; ++
i )
190 sal_Int32 nAlphaDepth=0;
191 const rendering::IntegerBitmapLayout aLayout(
192 xInputBitmap->getMemoryLayout());
194 OSL_ENSURE(aLayout.ColorSpace.is(),
195 "Cannot convert image without color space!");
196 if( !aLayout.ColorSpace.is() )
199 nDepth = aLayout.ColorSpace->getBitsPerPixel();
201 if( xInputBitmap->hasAlpha() )
204 const uno::Sequence<sal_Int8> aTags(
205 aLayout.ColorSpace->getComponentTags() );
206 const sal_Int8* pStart(aTags.getConstArray());
207 const std::size_t nLen(aTags.getLength());
210 const std::ptrdiff_t nAlphaIndex =
211 std::find(pStart,pEnd,
212 rendering::ColorComponentTag::ALPHA) - pStart;
214 if( nAlphaIndex < sal::static_int_cast<std::ptrdiff_t>(nLen) )
216 nAlphaDepth = aLayout.ColorSpace->getComponentBitCounts()[nAlphaIndex] > 1 ? 8 : 1;
217 nDepth -= nAlphaDepth;
222 if( aLayout.Palette.is() )
224 uno::Reference< rendering::XColorSpace > xPaletteColorSpace(
225 aLayout.Palette->getColorSpace());
227 "Palette without color space");
229 const sal_Int32 nEntryCount( aLayout.Palette->getNumberOfEntries() );
230 if( nEntryCount <= 256 )
232 if( nEntryCount <= 2 )
237 const sal_uInt16 nPaletteEntries(
238 sal::static_int_cast<sal_uInt16>(
239 std::min(sal_Int32(255), nEntryCount)));
243 uno::Reference<rendering::XBitmapPalette> xPalette( aLayout.Palette );
244 uno::Reference<rendering::XColorSpace> xPalColorSpace( xPalette->getColorSpace() );
246 uno::Sequence<double> aPaletteEntry;
247 for( sal_uInt16 j=0; j<nPaletteEntries; ++j )
249 if( !xPalette->getIndex(aPaletteEntry,j) &&
254 uno::Sequence<rendering::RGBColor> aColors=xPalColorSpace->convertToRGB(aPaletteEntry);
256 "Palette returned more or less than one entry");
257 const rendering::RGBColor& rColor=aColors[0];
265 const ::Size aPixelSize(
276 aLayout.Palette.is() ? &aPalette :
nullptr );
279 aAlpha =
Bitmap(aPixelSize,
282 sal::static_int_cast<sal_uInt16>(1 << nAlphaDepth)) );
290 "Cannot get write access to bitmap");
292 const sal_Int32 nWidth(aPixelSize.Width());
293 const sal_Int32 nHeight(aPixelSize.Height());
295 if( !readBmp(nWidth,nHeight,aLayout,xInputBitmap,
296 pWriteAccess,pAlphaWriteAccess) )
301 return ::BitmapEx( aBitmap,
304 return ::BitmapEx( aBitmap );
313 return geometry::RealSize2D( rSize.
Width(),
341 return ::Point( rPoint.
getX(),
352 return ::tools::Rectangle( rRect.
getMinX(),
390 if (rRect.IsWidthEmpty() && rRect.IsHeightEmpty())
394 rRect.IsWidthEmpty() ? rRect.Left() : rRect.Right(),
395 rRect.IsHeightEmpty() ? rRect.Top() : rRect.Bottom() );
400 return geometry::IntegerSize2D( rSize.
Width(),
406 return Size( rSize.Width,
412 return Point( rPoint.X,
419 rRectangle.X2, rRectangle.Y2 );
424 class StandardColorSpace :
public cppu::WeakImplHelper< css::rendering::XColorSpace >
429 virtual ::sal_Int8 SAL_CALL
getType( )
override
431 return rendering::ColorSpaceType::RGB;
433 virtual uno::Sequence< ::sal_Int8 > SAL_CALL getComponentTags( )
override
437 virtual ::sal_Int8 SAL_CALL getRenderingIntent( )
override
439 return rendering::RenderingIntent::PERCEPTUAL;
441 virtual uno::Sequence< beans::PropertyValue > SAL_CALL getProperties( )
override
443 return uno::Sequence< beans::PropertyValue >();
445 virtual uno::Sequence< double > SAL_CALL convertColorSpace(
const uno::Sequence< double >& deviceColor,
446 const uno::Reference< rendering::XColorSpace >& targetColorSpace )
override
450 uno::Sequence<rendering::ARGBColor> aIntermediate(
451 convertToARGB(deviceColor));
452 return targetColorSpace->convertFromARGB(aIntermediate);
454 virtual uno::Sequence< rendering::RGBColor > SAL_CALL convertToRGB(
const uno::Sequence< double >& deviceColor )
override
456 const double* pIn( deviceColor.getConstArray() );
457 const std::size_t nLen( deviceColor.getLength() );
459 "number of channels no multiple of 4",
460 static_cast<rendering::XColorSpace*
>(
this), 0);
462 uno::Sequence< rendering::RGBColor > aRes(nLen/4);
463 rendering::RGBColor*
pOut( aRes.getArray() );
464 for( std::size_t i=0;
i<nLen;
i+=4 )
466 *
pOut++ = rendering::RGBColor(pIn[0],pIn[1],pIn[2]);
471 virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertToARGB(
const uno::Sequence< double >& deviceColor )
override
473 const double* pIn( deviceColor.getConstArray() );
474 const std::size_t nLen( deviceColor.getLength() );
476 "number of channels no multiple of 4",
477 static_cast<rendering::XColorSpace*
>(
this), 0);
479 uno::Sequence< rendering::ARGBColor > aRes(nLen/4);
480 rendering::ARGBColor*
pOut( aRes.getArray() );
481 for( std::size_t i=0;
i<nLen;
i+=4 )
483 *
pOut++ = rendering::ARGBColor(pIn[3],pIn[0],pIn[1],pIn[2]);
488 virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertToPARGB(
const uno::Sequence< double >& deviceColor )
override
490 const double* pIn( deviceColor.getConstArray() );
491 const std::size_t nLen( deviceColor.getLength() );
493 "number of channels no multiple of 4",
494 static_cast<rendering::XColorSpace*
>(
this), 0);
496 uno::Sequence< rendering::ARGBColor > aRes(nLen/4);
497 rendering::ARGBColor*
pOut( aRes.getArray() );
498 for( std::size_t i=0;
i<nLen;
i+=4 )
500 *
pOut++ = rendering::ARGBColor(pIn[3],pIn[3]*pIn[0],pIn[3]*pIn[1],pIn[3]*pIn[2]);
505 virtual uno::Sequence< double > SAL_CALL convertFromRGB(
const uno::Sequence< rendering::RGBColor >& rgbColor )
override
507 const std::size_t nLen( rgbColor.getLength() );
509 uno::Sequence< double > aRes(nLen*4);
510 double* pColors=aRes.getArray();
511 for(
const auto& rIn : rgbColor )
513 *pColors++ = rIn.Red;
514 *pColors++ = rIn.Green;
515 *pColors++ = rIn.Blue;
520 virtual uno::Sequence< double > SAL_CALL convertFromARGB(
const uno::Sequence< rendering::ARGBColor >& rgbColor )
override
522 const std::size_t nLen( rgbColor.getLength() );
524 uno::Sequence< double > aRes(nLen*4);
525 double* pColors=aRes.getArray();
526 for(
const auto& rIn : rgbColor )
528 *pColors++ = rIn.Red;
529 *pColors++ = rIn.Green;
530 *pColors++ = rIn.Blue;
531 *pColors++ = rIn.Alpha;
535 virtual uno::Sequence< double > SAL_CALL convertFromPARGB(
const uno::Sequence< rendering::ARGBColor >& rgbColor )
override
537 const std::size_t nLen( rgbColor.getLength() );
539 uno::Sequence< double > aRes(nLen*4);
540 double* pColors=aRes.getArray();
541 for(
const auto& rIn : rgbColor )
543 *pColors++ = rIn.Red/rIn.Alpha;
544 *pColors++ = rIn.Green/rIn.Alpha;
545 *pColors++ = rIn.Blue/rIn.Alpha;
546 *pColors++ = rIn.Alpha;
555 pTags[0] = rendering::ColorComponentTag::RGB_RED;
556 pTags[1] = rendering::ColorComponentTag::RGB_GREEN;
557 pTags[2] = rendering::ColorComponentTag::RGB_BLUE;
558 pTags[3] = rendering::ColorComponentTag::ALPHA;
565 return new StandardColorSpace();
582 "color must have 4 channels" );
596 const uno::Reference< rendering::XColorSpace >& xColorSpace )
598 uno::Sequence<rendering::ARGBColor>
aSeq
608 return xColorSpace->convertFromARGB(
aSeq);
612 const uno::Sequence< double >& rColor,
613 const uno::Reference< rendering::XColorSpace >& xColorSpace )
615 const rendering::ARGBColor aARGBColor(
616 xColorSpace->convertToARGB(rColor)[0]);
void SetEntryCount(sal_uInt16 nCount)
BitmapWriteAccess * AcquireWriteAccess()
static const BitmapPalette & GetGreyPalette(int nEntries)
sal_uInt8 GetBlue() const
void SetGreen(sal_uInt8 nGreen)
void SetRed(sal_uInt8 nRed)
sal_uInt8 GetAlpha() const
sal_uInt8 GetGreen() const
void SetAlpha(sal_uInt8 nAlpha)
void SetBlue(sal_uInt8 nBlue)
constexpr tools::Long Y() const
constexpr tools::Long X() const
constexpr tools::Long Height() const
constexpr tools::Long Width() const
This template handles BitmapAccess the RAII way.
#define ENSURE_ARG_OR_THROW2(c, m, ifc, arg)
#define ENSURE_OR_THROW(c, m)
#define ENSURE_ARG_OR_THROW(c, m)
tools::Long FRound(double fVal)
Sequence< sal_Int8 > aSeq
#define SAL_INFO(area, stream)
B2IRange fround(const B2DRange &rRange)
bool getType(BSTR name, Type &type)