blob: 68a8153b2b81e812fd8b2fdd479ed4a3382d58c5 [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_vcl.hxx"
#include <rtl/logfile.hxx>
#include <cppuhelper/compbase1.hxx>
#include <com/sun/star/geometry/RealSize2D.hpp>
#include <com/sun/star/geometry/RealPoint2D.hpp>
#include <com/sun/star/geometry/RealRectangle2D.hpp>
#include <com/sun/star/geometry/IntegerSize2D.hpp>
#include <com/sun/star/geometry/IntegerPoint2D.hpp>
#include <com/sun/star/geometry/IntegerRectangle2D.hpp>
#include <com/sun/star/geometry/RealBezierSegment2D.hpp>
#include <com/sun/star/rendering/ColorSpaceType.hpp>
#include <com/sun/star/rendering/RenderingIntent.hpp>
#include <com/sun/star/rendering/XGraphicDevice.hpp>
#include <com/sun/star/rendering/XBitmap.hpp>
#include <com/sun/star/rendering/XPolyPolygon2D.hpp>
#include <com/sun/star/rendering/IntegerBitmapLayout.hpp>
#include <com/sun/star/rendering/XIntegerBitmap.hpp>
#include <com/sun/star/rendering/ColorComponentTag.hpp>
#include <basegfx/matrix/b2dhommatrix.hxx>
#include <basegfx/vector/b2dsize.hxx>
#include <basegfx/point/b2dpoint.hxx>
#include <basegfx/range/b2drectangle.hxx>
#include <basegfx/vector/b2isize.hxx>
#include <basegfx/point/b2ipoint.hxx>
#include <basegfx/range/b2irectangle.hxx>
// #i79917#
#include <basegfx/polygon/b2dpolygon.hxx>
#include <basegfx/tools/canvastools.hxx>
#include <basegfx/polygon/b2dpolypolygon.hxx>
#include <tools/poly.hxx>
#include <tools/diagnose_ex.h>
#include <rtl/uuid.h>
#include <vcl/salbtype.hxx>
#include <vcl/bmpacc.hxx>
#include <vcl/bitmapex.hxx>
#include <canvasbitmap.hxx>
#include <vcl/canvastools.hxx>
#include <hash_map>
using namespace ::com::sun::star;
namespace vcl
{
namespace unotools
{
// #i79917# removed helpers bezierSequenceFromPolygon and
// pointSequenceFromPolygon here
// Also all helpers using tools Polygon and PolyPolygon will get mapped to the
// B2DPolygon helpers for these cases, see comments with the same TaskID below.
// TODO: Remove those wrapped methods
//---------------------------------------------------------------------------------------
uno::Reference< rendering::XPolyPolygon2D > xPolyPolygonFromPolygon( const uno::Reference< rendering::XGraphicDevice >& xGraphicDevice,
const ::Polygon& inputPolygon )
{
RTL_LOGFILE_CONTEXT( aLog, "::vcl::unotools::xPolyPolygonFromPolygon()" );
// #i79917# map to basegfx
const basegfx::B2DPolygon aB2DPolygon(inputPolygon.getB2DPolygon());
return basegfx::unotools::xPolyPolygonFromB2DPolygon(xGraphicDevice, aB2DPolygon);
}
//---------------------------------------------------------------------------------------
uno::Reference< rendering::XPolyPolygon2D > xPolyPolygonFromPolyPolygon( const uno::Reference< rendering::XGraphicDevice >& xGraphicDevice,
const ::PolyPolygon& inputPolyPolygon )
{
RTL_LOGFILE_CONTEXT( aLog, "::vcl::unotools::xPolyPolygonFromPolyPolygon()" );
// #i79917# map to basegfx
const basegfx::B2DPolyPolygon aB2DPolyPolygon(inputPolyPolygon.getB2DPolyPolygon());
return basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(xGraphicDevice, aB2DPolyPolygon);
}
//---------------------------------------------------------------------------------------
::Polygon polygonFromPoint2DSequence( const uno::Sequence< geometry::RealPoint2D >& points )
{
RTL_LOGFILE_CONTEXT( aLog, "::vcl::unotools::polygonFromPoint2DSequence()" );
const sal_uInt16 nCurrSize( sal::static_int_cast<sal_uInt16>(points.getLength()) );
::Polygon aPoly( nCurrSize );
sal_uInt16 nCurrPoint;
for( nCurrPoint=0; nCurrPoint<nCurrSize; ++nCurrPoint )
aPoly[nCurrPoint] = pointFromRealPoint2D( points[nCurrPoint] );
return aPoly;
}
//---------------------------------------------------------------------------------------
::PolyPolygon polyPolygonFromPoint2DSequenceSequence( const uno::Sequence< uno::Sequence< geometry::RealPoint2D > >& points )
{
RTL_LOGFILE_CONTEXT( aLog, "::vcl::unotools::polyPolygonFromPoint2DSequenceSequence()" );
::PolyPolygon aRes;
int nCurrPoly;
for( nCurrPoly=0; nCurrPoly<points.getLength(); ++nCurrPoly )
{
aRes.Insert( polygonFromPoint2DSequence( points[nCurrPoly] ) );
}
return aRes;
}
//---------------------------------------------------------------------------------------
::Polygon polygonFromBezier2DSequence( const uno::Sequence< geometry::RealBezierSegment2D >& curves )
{
// #i79917# map to basegfx
const basegfx::B2DPolygon aB2DPolygon(basegfx::unotools::polygonFromBezier2DSequence(curves));
return ::Polygon(aB2DPolygon);
}
//---------------------------------------------------------------------------------------
::PolyPolygon polyPolygonFromBezier2DSequenceSequence( const uno::Sequence< uno::Sequence< geometry::RealBezierSegment2D > >& curves )
{
// #i79917# map to basegfx
const basegfx::B2DPolyPolygon aB2DPolyPolygon(basegfx::unotools::polyPolygonFromBezier2DSequenceSequence(curves));
return ::PolyPolygon(aB2DPolyPolygon);
}
//---------------------------------------------------------------------------------------
uno::Reference< rendering::XBitmap > xBitmapFromBitmap( const uno::Reference< rendering::XGraphicDevice >& /*xGraphicDevice*/,
const ::Bitmap& inputBitmap )
{
RTL_LOGFILE_CONTEXT( aLog, "::vcl::unotools::xBitmapFromBitmap()" );
return new vcl::unotools::VclCanvasBitmap( BitmapEx( inputBitmap ) );
}
//---------------------------------------------------------------------------------------
uno::Reference< rendering::XBitmap > xBitmapFromBitmapEx( const uno::Reference< rendering::XGraphicDevice >& /*xGraphicDevice*/,
const ::BitmapEx& inputBitmap )
{
RTL_LOGFILE_CONTEXT( aLog, "::vcl::unotools::xBitmapFromBitmapEx()" );
return new vcl::unotools::VclCanvasBitmap( inputBitmap );
}
//---------------------------------------------------------------------------------------
const uno::Sequence< sal_Int8 > getTunnelIdentifier( TunnelIdentifierType eType )
{
static std::hash_map< int, uno::Sequence< sal_Int8 > > aIds;
std::hash_map< int, uno::Sequence< sal_Int8 > >::iterator it =
aIds.find( eType );
if( it == aIds.end() )
{
uno::Sequence< sal_Int8 > aNewId( 16 );
rtl_createUuid( (sal_uInt8*)aNewId.getArray(), NULL, sal_True );
aIds[ eType ] = aNewId;
it = aIds.find( eType );
}
return it->second;
}
//---------------------------------------------------------------------------------------
namespace
{
inline bool operator==( const rendering::IntegerBitmapLayout& rLHS,
const rendering::IntegerBitmapLayout& rRHS )
{
return
rLHS.ScanLineBytes == rRHS.ScanLineBytes &&
rLHS.ScanLineStride == rRHS.ScanLineStride &&
rLHS.PlaneStride == rRHS.PlaneStride &&
rLHS.ColorSpace == rRHS.ColorSpace &&
rLHS.Palette == rRHS.Palette &&
rLHS.IsMsbFirst == rRHS.IsMsbFirst;
}
bool readBmp( sal_Int32 nWidth,
sal_Int32 nHeight,
const rendering::IntegerBitmapLayout& rLayout,
const uno::Reference< rendering::XIntegerReadOnlyBitmap >& xInputBitmap,
ScopedBitmapWriteAccess& rWriteAcc,
ScopedBitmapWriteAccess& rAlphaAcc )
{
rendering::IntegerBitmapLayout aCurrLayout;
geometry::IntegerRectangle2D aRect;
uno::Sequence<sal_Int8> aPixelData;
uno::Sequence<rendering::RGBColor> aRGBColors;
uno::Sequence<rendering::ARGBColor> aARGBColors;
for( aRect.Y1=0; aRect.Y1<nHeight; ++aRect.Y1 )
{
aRect.X1 = 0; aRect.X2 = nWidth; aRect.Y2 = aRect.Y1+1;
try
{
aPixelData = xInputBitmap->getData(aCurrLayout,aRect);
}
catch( rendering::VolatileContentDestroyedException& )
{
// re-read bmp from the start
return false;
}
if( !(aCurrLayout == rLayout) )
return false; // re-read bmp from the start
if( rAlphaAcc.get() )
{
// read ARGB color
aARGBColors = rLayout.ColorSpace->convertIntegerToARGB(aPixelData);
if( rWriteAcc->HasPalette() )
{
for( sal_Int32 x=0; x<nWidth; ++x )
{
const rendering::ARGBColor& rColor=aARGBColors[x];
rWriteAcc->SetPixelIndex( aRect.Y1, x,
(sal_uInt8) rWriteAcc->GetBestPaletteIndex(
BitmapColor( toByteColor(rColor.Red),
toByteColor(rColor.Green),
toByteColor(rColor.Blue))) );
rAlphaAcc->SetPixel( aRect.Y1, x,
BitmapColor( 255 - toByteColor(rColor.Alpha) ));
}
}
else
{
for( sal_Int32 x=0; x<nWidth; ++x )
{
const rendering::ARGBColor& rColor=aARGBColors[x];
rWriteAcc->SetPixel( aRect.Y1, x,
BitmapColor( toByteColor(rColor.Red),
toByteColor(rColor.Green),
toByteColor(rColor.Blue) ));
rAlphaAcc->SetPixel( aRect.Y1, x,
BitmapColor( 255 - toByteColor(rColor.Alpha) ));
}
}
}
else
{
// read RGB color
aRGBColors = rLayout.ColorSpace->convertIntegerToRGB(aPixelData);
if( rWriteAcc->HasPalette() )
{
for( sal_Int32 x=0; x<nWidth; ++x )
{
const rendering::RGBColor& rColor=aRGBColors[x];
rWriteAcc->SetPixelIndex( aRect.Y1, x,
(sal_uInt8) rWriteAcc->GetBestPaletteIndex(
BitmapColor( toByteColor(rColor.Red),
toByteColor(rColor.Green),
toByteColor(rColor.Blue))) );
}
}
else
{
for( sal_Int32 x=0; x<nWidth; ++x )
{
const rendering::RGBColor& rColor=aRGBColors[x];
rWriteAcc->SetPixel( aRect.Y1, x,
BitmapColor( toByteColor(rColor.Red),
toByteColor(rColor.Green),
toByteColor(rColor.Blue) ));
}
}
}
}
return true;
}
}
::BitmapEx VCL_DLLPUBLIC bitmapExFromXBitmap( const uno::Reference< rendering::XIntegerReadOnlyBitmap >& xInputBitmap )
{
RTL_LOGFILE_CONTEXT( aLog, "::vcl::unotools::bitmapExFromXBitmap()" );
if( !xInputBitmap.is() )
return ::BitmapEx();
// tunnel directly for known implementation
// ----------------------------------------------------------------
VclCanvasBitmap* pImplBitmap = dynamic_cast<VclCanvasBitmap*>(xInputBitmap.get());
if( pImplBitmap )
return pImplBitmap->getBitmapEx();
// retrieve data via UNO interface
// ----------------------------------------------------------------
// volatile bitmaps are a bit more complicated to read
// from..
uno::Reference<rendering::XVolatileBitmap> xVolatileBitmap(
xInputBitmap, uno::UNO_QUERY);
// loop a few times, until successfully read (for XVolatileBitmap)
for( int i=0; i<10; ++i )
{
sal_Int32 nDepth=0;
sal_Int32 nAlphaDepth=0;
const rendering::IntegerBitmapLayout aLayout(
xInputBitmap->getMemoryLayout());
OSL_ENSURE(aLayout.ColorSpace.is(),
"Cannot convert image without color space!");
if( !aLayout.ColorSpace.is() )
return ::BitmapEx();
nDepth = aLayout.ColorSpace->getBitsPerPixel();
if( xInputBitmap->hasAlpha() )
{
// determine alpha channel depth
const uno::Sequence<sal_Int8> aTags(
aLayout.ColorSpace->getComponentTags() );
const uno::Sequence<sal_Int32> aDepths(
aLayout.ColorSpace->getComponentBitCounts() );
const sal_Int8* pStart(aTags.getConstArray());
const sal_Size nLen(aTags.getLength());
const sal_Int8* pEnd(pStart+nLen);
const std::ptrdiff_t nAlphaIndex =
std::find(pStart,pEnd,
rendering::ColorComponentTag::ALPHA) - pStart;
if( nAlphaIndex < sal::static_int_cast<std::ptrdiff_t>(nLen) )
{
nAlphaDepth = aLayout.ColorSpace->getComponentBitCounts()[nAlphaIndex] > 1 ? 8 : 1;
nDepth -= nAlphaDepth;
}
}
BitmapPalette aPalette;
if( aLayout.Palette.is() )
{
uno::Reference< rendering::XColorSpace > xPaletteColorSpace(
aLayout.Palette->getColorSpace());
ENSURE_OR_THROW(xPaletteColorSpace.is(),
"Palette without color space");
const sal_Int32 nEntryCount( aLayout.Palette->getNumberOfEntries() );
if( nEntryCount <= 256 )
{
if( nEntryCount <= 2 )
nDepth = 1;
else
nDepth = 8;
const sal_uInt16 nPaletteEntries(
sal::static_int_cast<sal_uInt16>(
std::min(sal_Int32(255), nEntryCount)));
// copy palette entries
aPalette.SetEntryCount(nPaletteEntries);
uno::Reference<rendering::XBitmapPalette> xPalette( aLayout.Palette );
uno::Reference<rendering::XColorSpace> xPalColorSpace( xPalette->getColorSpace() );
uno::Sequence<double> aPaletteEntry;
for( sal_uInt16 j=0; j<nPaletteEntries; ++j )
{
if( !xPalette->getIndex(aPaletteEntry,j) &&
nAlphaDepth == 0 )
{
nAlphaDepth = 1;
}
uno::Sequence<rendering::RGBColor> aColors=xPalColorSpace->convertToRGB(aPaletteEntry);
ENSURE_OR_THROW(aColors.getLength() == 1,
"Palette returned more or less than one entry");
const rendering::RGBColor& rColor=aColors[0];
aPalette[j] = BitmapColor(toByteColor(rColor.Red),
toByteColor(rColor.Green),
toByteColor(rColor.Blue));
}
}
}
const ::Size aPixelSize(
sizeFromIntegerSize2D(xInputBitmap->getSize()));
// normalize bitcount
nDepth =
( nDepth <= 1 ) ? 1 :
( nDepth <= 4 ) ? 4 :
( nDepth <= 8 ) ? 8 : 24;
::Bitmap aBitmap( aPixelSize,
sal::static_int_cast<sal_uInt16>(nDepth),
aLayout.Palette.is() ? &aPalette : NULL );
::Bitmap aAlpha;
if( nAlphaDepth )
aAlpha = ::Bitmap( aPixelSize,
sal::static_int_cast<sal_uInt16>(nAlphaDepth),
&::Bitmap::GetGreyPalette(
sal::static_int_cast<sal_uInt16>(1L << nAlphaDepth)) );
{ // limit scoped access
ScopedBitmapWriteAccess pWriteAccess( aBitmap.AcquireWriteAccess(),
aBitmap );
ScopedBitmapWriteAccess pAlphaWriteAccess( nAlphaDepth ? aAlpha.AcquireWriteAccess() : NULL,
aAlpha );
ENSURE_OR_THROW(pWriteAccess.get() != NULL,
"Cannot get write access to bitmap");
const sal_Int32 nWidth(aPixelSize.Width());
const sal_Int32 nHeight(aPixelSize.Height());
if( !readBmp(nWidth,nHeight,aLayout,xInputBitmap,
pWriteAccess,pAlphaWriteAccess) )
continue;
} // limit scoped access
if( nAlphaDepth )
return ::BitmapEx( aBitmap,
AlphaMask( aAlpha ) );
else
return ::BitmapEx( aBitmap );
}
// failed to read data 10 times - bail out
return ::BitmapEx();
}
//---------------------------------------------------------------------------------------
geometry::RealSize2D size2DFromSize( const Size& rSize )
{
return geometry::RealSize2D( rSize.Width(),
rSize.Height() );
}
geometry::RealPoint2D point2DFromPoint( const Point& rPoint )
{
return geometry::RealPoint2D( rPoint.X(),
rPoint.Y() );
}
geometry::RealRectangle2D rectangle2DFromRectangle( const Rectangle& rRect )
{
return geometry::RealRectangle2D( rRect.Left(), rRect.Top(),
rRect.Right(), rRect.Bottom() );
}
Size sizeFromRealSize2D( const geometry::RealSize2D& rSize )
{
return Size( static_cast<long>(rSize.Width + .5),
static_cast<long>(rSize.Height + .5) );
}
Point pointFromRealPoint2D( const geometry::RealPoint2D& rPoint )
{
return Point( static_cast<long>(rPoint.X + .5),
static_cast<long>(rPoint.Y + .5) );
}
Rectangle rectangleFromRealRectangle2D( const geometry::RealRectangle2D& rRect )
{
return Rectangle( static_cast<long>(rRect.X1 + .5),
static_cast<long>(rRect.Y1 + .5),
static_cast<long>(rRect.X2 + .5),
static_cast<long>(rRect.Y2 + .5) );
}
::Size sizeFromB2DSize( const ::basegfx::B2DVector& rVec )
{
return ::Size( FRound( rVec.getX() ),
FRound( rVec.getY() ) );
}
::Point pointFromB2DPoint( const ::basegfx::B2DPoint& rPoint )
{
return ::Point( FRound( rPoint.getX() ),
FRound( rPoint.getY() ) );
}
::Rectangle rectangleFromB2DRectangle( const ::basegfx::B2DRange& rRect )
{
return ::Rectangle( FRound( rRect.getMinX() ),
FRound( rRect.getMinY() ),
FRound( rRect.getMaxX() ),
FRound( rRect.getMaxY() ) );
}
Size sizeFromB2ISize( const ::basegfx::B2IVector& rVec )
{
return ::Size( rVec.getX(),
rVec.getY() );
}
Point pointFromB2IPoint( const ::basegfx::B2IPoint& rPoint )
{
return ::Point( rPoint.getX(),
rPoint.getY() );
}
Rectangle rectangleFromB2IRectangle( const ::basegfx::B2IRange& rRect )
{
return ::Rectangle( rRect.getMinX(),
rRect.getMinY(),
rRect.getMaxX(),
rRect.getMaxY() );
}
::basegfx::B2DVector b2DSizeFromSize( const ::Size& rSize )
{
return ::basegfx::B2DVector( rSize.Width(),
rSize.Height() );
}
::basegfx::B2DPoint b2DPointFromPoint( const ::Point& rPoint )
{
return ::basegfx::B2DPoint( rPoint.X(),
rPoint.Y() );
}
::basegfx::B2DRange b2DRectangleFromRectangle( const ::Rectangle& rRect )
{
return ::basegfx::B2DRange( rRect.Left(),
rRect.Top(),
rRect.Right(),
rRect.Bottom() );
}
basegfx::B2IVector b2ISizeFromSize( const Size& rSize )
{
return ::basegfx::B2IVector( rSize.Width(),
rSize.Height() );
}
basegfx::B2IPoint b2IPointFromPoint( const Point& rPoint )
{
return ::basegfx::B2IPoint( rPoint.X(),
rPoint.Y() );
}
basegfx::B2IRange b2IRectangleFromRectangle( const Rectangle& rRect )
{
return ::basegfx::B2IRange( rRect.Left(),
rRect.Top(),
rRect.Right(),
rRect.Bottom() );
}
geometry::IntegerSize2D integerSize2DFromSize( const Size& rSize )
{
return geometry::IntegerSize2D( rSize.Width(),
rSize.Height() );
}
geometry::IntegerPoint2D integerPoint2DFromPoint( const Point& rPoint )
{
return geometry::IntegerPoint2D( rPoint.X(),
rPoint.Y() );
}
geometry::IntegerRectangle2D integerRectangle2DFromRectangle( const Rectangle& rRectangle )
{
return geometry::IntegerRectangle2D( rRectangle.Left(), rRectangle.Top(),
rRectangle.Right(), rRectangle.Bottom() );
}
Size sizeFromIntegerSize2D( const geometry::IntegerSize2D& rSize )
{
return Size( rSize.Width,
rSize.Height );
}
Point pointFromIntegerPoint2D( const geometry::IntegerPoint2D& rPoint )
{
return Point( rPoint.X,
rPoint.Y );
}
Rectangle rectangleFromIntegerRectangle2D( const geometry::IntegerRectangle2D& rRectangle )
{
return Rectangle( rRectangle.X1, rRectangle.Y1,
rRectangle.X2, rRectangle.Y2 );
}
namespace
{
class StandardColorSpace : public cppu::WeakImplHelper1< com::sun::star::rendering::XColorSpace >
{
private:
uno::Sequence< sal_Int8 > m_aComponentTags;
virtual ::sal_Int8 SAL_CALL getType( ) throw (uno::RuntimeException)
{
return rendering::ColorSpaceType::RGB;
}
virtual uno::Sequence< ::sal_Int8 > SAL_CALL getComponentTags( ) throw (uno::RuntimeException)
{
return m_aComponentTags;
}
virtual ::sal_Int8 SAL_CALL getRenderingIntent( ) throw (uno::RuntimeException)
{
return rendering::RenderingIntent::PERCEPTUAL;
}
virtual uno::Sequence< beans::PropertyValue > SAL_CALL getProperties( ) throw (uno::RuntimeException)
{
return uno::Sequence< beans::PropertyValue >();
}
virtual uno::Sequence< double > SAL_CALL convertColorSpace( const uno::Sequence< double >& deviceColor,
const uno::Reference< rendering::XColorSpace >& targetColorSpace ) throw (lang::IllegalArgumentException,
uno::RuntimeException)
{
// TODO(P3): if we know anything about target
// colorspace, this can be greatly sped up
uno::Sequence<rendering::ARGBColor> aIntermediate(
convertToARGB(deviceColor));
return targetColorSpace->convertFromARGB(aIntermediate);
}
virtual uno::Sequence< rendering::RGBColor > SAL_CALL convertToRGB( const uno::Sequence< double >& deviceColor ) throw (lang::IllegalArgumentException, uno::RuntimeException)
{
const double* pIn( deviceColor.getConstArray() );
const sal_Size nLen( deviceColor.getLength() );
ENSURE_ARG_OR_THROW2(nLen%4==0,
"number of channels no multiple of 4",
static_cast<rendering::XColorSpace*>(this), 0);
uno::Sequence< rendering::RGBColor > aRes(nLen/4);
rendering::RGBColor* pOut( aRes.getArray() );
for( sal_Size i=0; i<nLen; i+=4 )
{
*pOut++ = rendering::RGBColor(pIn[0],pIn[1],pIn[2]);
pIn += 4;
}
return aRes;
}
virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertToARGB( const uno::Sequence< double >& deviceColor ) throw (lang::IllegalArgumentException, uno::RuntimeException)
{
const double* pIn( deviceColor.getConstArray() );
const sal_Size nLen( deviceColor.getLength() );
ENSURE_ARG_OR_THROW2(nLen%4==0,
"number of channels no multiple of 4",
static_cast<rendering::XColorSpace*>(this), 0);
uno::Sequence< rendering::ARGBColor > aRes(nLen/4);
rendering::ARGBColor* pOut( aRes.getArray() );
for( sal_Size i=0; i<nLen; i+=4 )
{
*pOut++ = rendering::ARGBColor(pIn[3],pIn[0],pIn[1],pIn[2]);
pIn += 4;
}
return aRes;
}
virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertToPARGB( const uno::Sequence< double >& deviceColor ) throw (lang::IllegalArgumentException, uno::RuntimeException)
{
const double* pIn( deviceColor.getConstArray() );
const sal_Size nLen( deviceColor.getLength() );
ENSURE_ARG_OR_THROW2(nLen%4==0,
"number of channels no multiple of 4",
static_cast<rendering::XColorSpace*>(this), 0);
uno::Sequence< rendering::ARGBColor > aRes(nLen/4);
rendering::ARGBColor* pOut( aRes.getArray() );
for( sal_Size i=0; i<nLen; i+=4 )
{
*pOut++ = rendering::ARGBColor(pIn[3],pIn[3]*pIn[0],pIn[3]*pIn[1],pIn[3]*pIn[2]);
pIn += 4;
}
return aRes;
}
virtual uno::Sequence< double > SAL_CALL convertFromRGB( const uno::Sequence< rendering::RGBColor >& rgbColor ) throw (lang::IllegalArgumentException, uno::RuntimeException)
{
const rendering::RGBColor* pIn( rgbColor.getConstArray() );
const sal_Size nLen( rgbColor.getLength() );
uno::Sequence< double > aRes(nLen*4);
double* pColors=aRes.getArray();
for( sal_Size i=0; i<nLen; ++i )
{
*pColors++ = pIn->Red;
*pColors++ = pIn->Green;
*pColors++ = pIn->Blue;
*pColors++ = 1.0;
++pIn;
}
return aRes;
}
virtual uno::Sequence< double > SAL_CALL convertFromARGB( const uno::Sequence< rendering::ARGBColor >& rgbColor ) throw (lang::IllegalArgumentException, uno::RuntimeException)
{
const rendering::ARGBColor* pIn( rgbColor.getConstArray() );
const sal_Size nLen( rgbColor.getLength() );
uno::Sequence< double > aRes(nLen*4);
double* pColors=aRes.getArray();
for( sal_Size i=0; i<nLen; ++i )
{
*pColors++ = pIn->Red;
*pColors++ = pIn->Green;
*pColors++ = pIn->Blue;
*pColors++ = pIn->Alpha;
++pIn;
}
return aRes;
}
virtual uno::Sequence< double > SAL_CALL convertFromPARGB( const uno::Sequence< rendering::ARGBColor >& rgbColor ) throw (lang::IllegalArgumentException, uno::RuntimeException)
{
const rendering::ARGBColor* pIn( rgbColor.getConstArray() );
const sal_Size nLen( rgbColor.getLength() );
uno::Sequence< double > aRes(nLen*4);
double* pColors=aRes.getArray();
for( sal_Size i=0; i<nLen; ++i )
{
*pColors++ = pIn->Red/pIn->Alpha;
*pColors++ = pIn->Green/pIn->Alpha;
*pColors++ = pIn->Blue/pIn->Alpha;
*pColors++ = pIn->Alpha;
++pIn;
}
return aRes;
}
public:
StandardColorSpace() : m_aComponentTags(4)
{
sal_Int8* pTags = m_aComponentTags.getArray();
pTags[0] = rendering::ColorComponentTag::RGB_RED;
pTags[1] = rendering::ColorComponentTag::RGB_GREEN;
pTags[2] = rendering::ColorComponentTag::RGB_BLUE;
pTags[3] = rendering::ColorComponentTag::ALPHA;
}
};
}
uno::Reference<rendering::XColorSpace> VCL_DLLPUBLIC createStandardColorSpace()
{
return new StandardColorSpace();
}
//---------------------------------------------------------------------------------------
uno::Sequence< double > colorToStdColorSpaceSequence( const Color& rColor )
{
uno::Sequence< double > aRet(4);
double* pRet = aRet.getArray();
pRet[0] = toDoubleColor(rColor.GetRed());
pRet[1] = toDoubleColor(rColor.GetGreen());
pRet[2] = toDoubleColor(rColor.GetBlue());
// VCL's notion of alpha is different from the rest of the world's
pRet[3] = 1.0 - toDoubleColor(rColor.GetTransparency());
return aRet;
}
Color stdColorSpaceSequenceToColor( const uno::Sequence< double >& rColor )
{
ENSURE_ARG_OR_THROW( rColor.getLength() == 4,
"color must have 4 channels" );
Color aColor;
aColor.SetRed ( toByteColor(rColor[0]) );
aColor.SetGreen( toByteColor(rColor[1]) );
aColor.SetBlue ( toByteColor(rColor[2]) );
// VCL's notion of alpha is different from the rest of the world's
aColor.SetTransparency( 255 - toByteColor(rColor[3]) );
return aColor;
}
uno::Sequence< double > VCL_DLLPUBLIC colorToDoubleSequence(
const Color& rColor,
const uno::Reference< rendering::XColorSpace >& xColorSpace )
{
uno::Sequence<rendering::ARGBColor> aSeq(1);
aSeq[0] = rendering::ARGBColor(
1.0-toDoubleColor(rColor.GetTransparency()),
toDoubleColor(rColor.GetRed()),
toDoubleColor(rColor.GetGreen()),
toDoubleColor(rColor.GetBlue()) );
return xColorSpace->convertFromARGB(aSeq);
}
Color VCL_DLLPUBLIC doubleSequenceToColor(
const uno::Sequence< double > rColor,
const uno::Reference< rendering::XColorSpace >& xColorSpace )
{
const rendering::ARGBColor& rARGBColor(
xColorSpace->convertToARGB(rColor)[0]);
return Color( 255-toByteColor(rARGBColor.Alpha),
toByteColor(rARGBColor.Red),
toByteColor(rARGBColor.Green),
toByteColor(rARGBColor.Blue) );
}
//---------------------------------------------------------------------------------------
} // namespace vcltools
} // namespace canvas
// eof