1*cdf0e10cSrcweir /************************************************************************* 2*cdf0e10cSrcweir * 3*cdf0e10cSrcweir * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4*cdf0e10cSrcweir * 5*cdf0e10cSrcweir * Copyright 2000, 2010 Oracle and/or its affiliates. 6*cdf0e10cSrcweir * 7*cdf0e10cSrcweir * OpenOffice.org - a multi-platform office productivity suite 8*cdf0e10cSrcweir * 9*cdf0e10cSrcweir * This file is part of OpenOffice.org. 10*cdf0e10cSrcweir * 11*cdf0e10cSrcweir * OpenOffice.org is free software: you can redistribute it and/or modify 12*cdf0e10cSrcweir * it under the terms of the GNU Lesser General Public License version 3 13*cdf0e10cSrcweir * only, as published by the Free Software Foundation. 14*cdf0e10cSrcweir * 15*cdf0e10cSrcweir * OpenOffice.org is distributed in the hope that it will be useful, 16*cdf0e10cSrcweir * but WITHOUT ANY WARRANTY; without even the implied warranty of 17*cdf0e10cSrcweir * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18*cdf0e10cSrcweir * GNU Lesser General Public License version 3 for more details 19*cdf0e10cSrcweir * (a copy is included in the LICENSE file that accompanied this code). 20*cdf0e10cSrcweir * 21*cdf0e10cSrcweir * You should have received a copy of the GNU Lesser General Public License 22*cdf0e10cSrcweir * version 3 along with OpenOffice.org. If not, see 23*cdf0e10cSrcweir * <http://www.openoffice.org/license.html> 24*cdf0e10cSrcweir * for a copy of the LGPLv3 License. 25*cdf0e10cSrcweir * 26*cdf0e10cSrcweir ************************************************************************/ 27*cdf0e10cSrcweir 28*cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove 29*cdf0e10cSrcweir #include "precompiled_canvas.hxx" 30*cdf0e10cSrcweir 31*cdf0e10cSrcweir #include <canvas/debug.hxx> 32*cdf0e10cSrcweir #include <tools/diagnose_ex.h> 33*cdf0e10cSrcweir 34*cdf0e10cSrcweir #include <rtl/math.hxx> 35*cdf0e10cSrcweir #include <rtl/logfile.hxx> 36*cdf0e10cSrcweir 37*cdf0e10cSrcweir #include <com/sun/star/geometry/RealSize2D.hpp> 38*cdf0e10cSrcweir #include <com/sun/star/geometry/RealPoint2D.hpp> 39*cdf0e10cSrcweir #include <com/sun/star/geometry/RealRectangle2D.hpp> 40*cdf0e10cSrcweir #include <com/sun/star/rendering/RenderState.hpp> 41*cdf0e10cSrcweir #include <com/sun/star/rendering/XCanvas.hpp> 42*cdf0e10cSrcweir #include <com/sun/star/rendering/XBitmap.hpp> 43*cdf0e10cSrcweir #include <com/sun/star/rendering/XPolyPolygon2D.hpp> 44*cdf0e10cSrcweir #include <com/sun/star/geometry/RealBezierSegment2D.hpp> 45*cdf0e10cSrcweir #include <com/sun/star/rendering/XIntegerBitmap.hpp> 46*cdf0e10cSrcweir 47*cdf0e10cSrcweir #include <vcl/salbtype.hxx> 48*cdf0e10cSrcweir #include <vcl/bmpacc.hxx> 49*cdf0e10cSrcweir #include <vcl/bitmapex.hxx> 50*cdf0e10cSrcweir #include <vcl/metric.hxx> 51*cdf0e10cSrcweir #include <vcl/canvastools.hxx> 52*cdf0e10cSrcweir 53*cdf0e10cSrcweir #include <basegfx/point/b2dpoint.hxx> 54*cdf0e10cSrcweir #include <basegfx/tuple/b2dtuple.hxx> 55*cdf0e10cSrcweir #include <basegfx/polygon/b2dpolygontools.hxx> 56*cdf0e10cSrcweir #include <basegfx/range/b2drectangle.hxx> 57*cdf0e10cSrcweir #include <basegfx/matrix/b2dhommatrix.hxx> 58*cdf0e10cSrcweir #include <basegfx/tools/canvastools.hxx> 59*cdf0e10cSrcweir #include <basegfx/numeric/ftools.hxx> 60*cdf0e10cSrcweir 61*cdf0e10cSrcweir #include <canvas/canvastools.hxx> 62*cdf0e10cSrcweir 63*cdf0e10cSrcweir #include "impltools.hxx" 64*cdf0e10cSrcweir #include "canvasbitmap.hxx" 65*cdf0e10cSrcweir 66*cdf0e10cSrcweir #include <numeric> 67*cdf0e10cSrcweir 68*cdf0e10cSrcweir 69*cdf0e10cSrcweir using namespace ::com::sun::star; 70*cdf0e10cSrcweir 71*cdf0e10cSrcweir namespace vclcanvas 72*cdf0e10cSrcweir { 73*cdf0e10cSrcweir namespace tools 74*cdf0e10cSrcweir { 75*cdf0e10cSrcweir ::BitmapEx bitmapExFromXBitmap( const uno::Reference< rendering::XBitmap >& xBitmap ) 76*cdf0e10cSrcweir { 77*cdf0e10cSrcweir // TODO(F3): CanvasCustomSprite should also be tunnelled 78*cdf0e10cSrcweir // through (also implements XIntegerBitmap interface) 79*cdf0e10cSrcweir CanvasBitmap* pBitmapImpl = dynamic_cast< CanvasBitmap* >( xBitmap.get() ); 80*cdf0e10cSrcweir 81*cdf0e10cSrcweir if( pBitmapImpl ) 82*cdf0e10cSrcweir { 83*cdf0e10cSrcweir return pBitmapImpl->getBitmap(); 84*cdf0e10cSrcweir } 85*cdf0e10cSrcweir else 86*cdf0e10cSrcweir { 87*cdf0e10cSrcweir SpriteCanvas* pCanvasImpl = dynamic_cast< SpriteCanvas* >( xBitmap.get() ); 88*cdf0e10cSrcweir if( pCanvasImpl && pCanvasImpl->getBackBuffer() ) 89*cdf0e10cSrcweir { 90*cdf0e10cSrcweir // TODO(F3): mind the plain Canvas impl. Consolidate with CWS canvas05 91*cdf0e10cSrcweir const ::OutputDevice& rDev( pCanvasImpl->getBackBuffer()->getOutDev() ); 92*cdf0e10cSrcweir const ::Point aEmptyPoint; 93*cdf0e10cSrcweir return rDev.GetBitmapEx( aEmptyPoint, 94*cdf0e10cSrcweir rDev.GetOutputSizePixel() ); 95*cdf0e10cSrcweir } 96*cdf0e10cSrcweir 97*cdf0e10cSrcweir // TODO(F2): add support for floating point bitmap formats 98*cdf0e10cSrcweir uno::Reference< rendering::XIntegerReadOnlyBitmap > xIntBmp( 99*cdf0e10cSrcweir xBitmap, uno::UNO_QUERY_THROW ); 100*cdf0e10cSrcweir 101*cdf0e10cSrcweir ::BitmapEx aBmpEx = ::vcl::unotools::bitmapExFromXBitmap( xIntBmp ); 102*cdf0e10cSrcweir if( !!aBmpEx ) 103*cdf0e10cSrcweir return aBmpEx; 104*cdf0e10cSrcweir 105*cdf0e10cSrcweir // TODO(F1): extract pixel from XBitmap interface 106*cdf0e10cSrcweir ENSURE_OR_THROW( false, 107*cdf0e10cSrcweir "bitmapExFromXBitmap(): could not extract bitmap" ); 108*cdf0e10cSrcweir } 109*cdf0e10cSrcweir 110*cdf0e10cSrcweir return ::BitmapEx(); 111*cdf0e10cSrcweir } 112*cdf0e10cSrcweir 113*cdf0e10cSrcweir bool setupFontTransform( ::Point& o_rPoint, 114*cdf0e10cSrcweir ::Font& io_rVCLFont, 115*cdf0e10cSrcweir const rendering::ViewState& rViewState, 116*cdf0e10cSrcweir const rendering::RenderState& rRenderState, 117*cdf0e10cSrcweir ::OutputDevice& rOutDev ) 118*cdf0e10cSrcweir { 119*cdf0e10cSrcweir ::basegfx::B2DHomMatrix aMatrix; 120*cdf0e10cSrcweir 121*cdf0e10cSrcweir ::canvas::tools::mergeViewAndRenderTransform(aMatrix, 122*cdf0e10cSrcweir rViewState, 123*cdf0e10cSrcweir rRenderState); 124*cdf0e10cSrcweir 125*cdf0e10cSrcweir ::basegfx::B2DTuple aScale; 126*cdf0e10cSrcweir ::basegfx::B2DTuple aTranslate; 127*cdf0e10cSrcweir double nRotate, nShearX; 128*cdf0e10cSrcweir 129*cdf0e10cSrcweir aMatrix.decompose( aScale, aTranslate, nRotate, nShearX ); 130*cdf0e10cSrcweir 131*cdf0e10cSrcweir // #i72417# detecting the 180 degree rotation case manually here. 132*cdf0e10cSrcweir if( aScale.getX() < 0.0 && 133*cdf0e10cSrcweir aScale.getY() < 0.0 && 134*cdf0e10cSrcweir basegfx::fTools::equalZero(nRotate) ) 135*cdf0e10cSrcweir { 136*cdf0e10cSrcweir aScale *= -1.0; 137*cdf0e10cSrcweir nRotate += M_PI; 138*cdf0e10cSrcweir } 139*cdf0e10cSrcweir 140*cdf0e10cSrcweir // query font metric _before_ tampering with width and height 141*cdf0e10cSrcweir if( !::rtl::math::approxEqual(aScale.getX(), aScale.getY()) ) 142*cdf0e10cSrcweir { 143*cdf0e10cSrcweir // retrieve true font width 144*cdf0e10cSrcweir const sal_Int32 nFontWidth( rOutDev.GetFontMetric( io_rVCLFont ).GetWidth() ); 145*cdf0e10cSrcweir 146*cdf0e10cSrcweir const sal_Int32 nScaledFontWidth( ::basegfx::fround(nFontWidth * aScale.getX()) ); 147*cdf0e10cSrcweir 148*cdf0e10cSrcweir if( !nScaledFontWidth ) 149*cdf0e10cSrcweir { 150*cdf0e10cSrcweir // scale is smaller than one pixel - disable text 151*cdf0e10cSrcweir // output altogether 152*cdf0e10cSrcweir return false; 153*cdf0e10cSrcweir } 154*cdf0e10cSrcweir 155*cdf0e10cSrcweir io_rVCLFont.SetWidth( nScaledFontWidth ); 156*cdf0e10cSrcweir } 157*cdf0e10cSrcweir 158*cdf0e10cSrcweir if( !::rtl::math::approxEqual(aScale.getY(), 1.0) ) 159*cdf0e10cSrcweir { 160*cdf0e10cSrcweir const sal_Int32 nFontHeight( io_rVCLFont.GetHeight() ); 161*cdf0e10cSrcweir io_rVCLFont.SetHeight( ::basegfx::fround(nFontHeight * aScale.getY()) ); 162*cdf0e10cSrcweir } 163*cdf0e10cSrcweir 164*cdf0e10cSrcweir io_rVCLFont.SetOrientation( static_cast< short >( ::basegfx::fround(-fmod(nRotate, 2*M_PI)*(1800.0/M_PI)) ) ); 165*cdf0e10cSrcweir 166*cdf0e10cSrcweir // TODO(F2): Missing functionality in VCL: shearing 167*cdf0e10cSrcweir o_rPoint.X() = ::basegfx::fround(aTranslate.getX()); 168*cdf0e10cSrcweir o_rPoint.Y() = ::basegfx::fround(aTranslate.getY()); 169*cdf0e10cSrcweir 170*cdf0e10cSrcweir return true; 171*cdf0e10cSrcweir } 172*cdf0e10cSrcweir 173*cdf0e10cSrcweir bool isRectangle( const PolyPolygon& rPolyPoly ) 174*cdf0e10cSrcweir { 175*cdf0e10cSrcweir // exclude some cheap cases first 176*cdf0e10cSrcweir if( rPolyPoly.Count() != 1 ) 177*cdf0e10cSrcweir return false; 178*cdf0e10cSrcweir 179*cdf0e10cSrcweir const ::Polygon& rPoly( rPolyPoly[0] ); 180*cdf0e10cSrcweir 181*cdf0e10cSrcweir sal_uInt16 nCount( rPoly.GetSize() ); 182*cdf0e10cSrcweir if( nCount < 4 ) 183*cdf0e10cSrcweir return false; 184*cdf0e10cSrcweir 185*cdf0e10cSrcweir // delegate to basegfx 186*cdf0e10cSrcweir return ::basegfx::tools::isRectangle( rPoly.getB2DPolygon() ); 187*cdf0e10cSrcweir } 188*cdf0e10cSrcweir 189*cdf0e10cSrcweir 190*cdf0e10cSrcweir // VCL-Canvas related 191*cdf0e10cSrcweir //--------------------------------------------------------------------- 192*cdf0e10cSrcweir 193*cdf0e10cSrcweir ::Point mapRealPoint2D( const geometry::RealPoint2D& rPoint, 194*cdf0e10cSrcweir const rendering::ViewState& rViewState, 195*cdf0e10cSrcweir const rendering::RenderState& rRenderState ) 196*cdf0e10cSrcweir { 197*cdf0e10cSrcweir ::basegfx::B2DPoint aPoint( ::basegfx::unotools::b2DPointFromRealPoint2D(rPoint) ); 198*cdf0e10cSrcweir 199*cdf0e10cSrcweir ::basegfx::B2DHomMatrix aMatrix; 200*cdf0e10cSrcweir aPoint *= ::canvas::tools::mergeViewAndRenderTransform(aMatrix, 201*cdf0e10cSrcweir rViewState, 202*cdf0e10cSrcweir rRenderState); 203*cdf0e10cSrcweir 204*cdf0e10cSrcweir return ::vcl::unotools::pointFromB2DPoint( aPoint ); 205*cdf0e10cSrcweir } 206*cdf0e10cSrcweir 207*cdf0e10cSrcweir ::PolyPolygon mapPolyPolygon( const ::basegfx::B2DPolyPolygon& rPoly, 208*cdf0e10cSrcweir const rendering::ViewState& rViewState, 209*cdf0e10cSrcweir const rendering::RenderState& rRenderState ) 210*cdf0e10cSrcweir { 211*cdf0e10cSrcweir ::basegfx::B2DHomMatrix aMatrix; 212*cdf0e10cSrcweir ::canvas::tools::mergeViewAndRenderTransform(aMatrix, 213*cdf0e10cSrcweir rViewState, 214*cdf0e10cSrcweir rRenderState); 215*cdf0e10cSrcweir 216*cdf0e10cSrcweir ::basegfx::B2DPolyPolygon aTemp( rPoly ); 217*cdf0e10cSrcweir 218*cdf0e10cSrcweir aTemp.transform( aMatrix ); 219*cdf0e10cSrcweir 220*cdf0e10cSrcweir return ::PolyPolygon( aTemp ); 221*cdf0e10cSrcweir } 222*cdf0e10cSrcweir 223*cdf0e10cSrcweir ::BitmapEx transformBitmap( const BitmapEx& rBitmap, 224*cdf0e10cSrcweir const ::basegfx::B2DHomMatrix& rTransform, 225*cdf0e10cSrcweir const uno::Sequence< double >& rDeviceColor, 226*cdf0e10cSrcweir ModulationMode eModulationMode ) 227*cdf0e10cSrcweir { 228*cdf0e10cSrcweir RTL_LOGFILE_CONTEXT( aLog, "::vclcanvas::tools::transformBitmap()" ); 229*cdf0e10cSrcweir RTL_LOGFILE_CONTEXT_TRACE1( aLog, "::vclcanvas::tools::transformBitmap: 0x%X", &rBitmap ); 230*cdf0e10cSrcweir 231*cdf0e10cSrcweir // calc transformation and size of bitmap to be 232*cdf0e10cSrcweir // generated. Note, that the translational components are 233*cdf0e10cSrcweir // deleted from the transformation; this can be handled by 234*cdf0e10cSrcweir // an offset when painting the bitmap 235*cdf0e10cSrcweir const Size aBmpSize( rBitmap.GetSizePixel() ); 236*cdf0e10cSrcweir ::basegfx::B2DRectangle aDestRect; 237*cdf0e10cSrcweir 238*cdf0e10cSrcweir bool bCopyBack( false ); 239*cdf0e10cSrcweir 240*cdf0e10cSrcweir // calc effective transformation for bitmap 241*cdf0e10cSrcweir const ::basegfx::B2DRectangle aSrcRect( 0, 0, 242*cdf0e10cSrcweir aBmpSize.Width(), 243*cdf0e10cSrcweir aBmpSize.Height() ); 244*cdf0e10cSrcweir ::canvas::tools::calcTransformedRectBounds( aDestRect, 245*cdf0e10cSrcweir aSrcRect, 246*cdf0e10cSrcweir rTransform ); 247*cdf0e10cSrcweir 248*cdf0e10cSrcweir // re-center bitmap, such that it's left, top border is 249*cdf0e10cSrcweir // aligned with (0,0). The method takes the given 250*cdf0e10cSrcweir // rectangle, and calculates a transformation that maps 251*cdf0e10cSrcweir // this rectangle unscaled to the origin. 252*cdf0e10cSrcweir ::basegfx::B2DHomMatrix aLocalTransform; 253*cdf0e10cSrcweir ::canvas::tools::calcRectToOriginTransform( aLocalTransform, 254*cdf0e10cSrcweir aSrcRect, 255*cdf0e10cSrcweir rTransform ); 256*cdf0e10cSrcweir 257*cdf0e10cSrcweir const bool bModulateColors( eModulationMode == MODULATE_WITH_DEVICECOLOR && 258*cdf0e10cSrcweir rDeviceColor.getLength() > 2 ); 259*cdf0e10cSrcweir const double nRedModulation( bModulateColors ? rDeviceColor[0] : 1.0 ); 260*cdf0e10cSrcweir const double nGreenModulation( bModulateColors ? rDeviceColor[1] : 1.0 ); 261*cdf0e10cSrcweir const double nBlueModulation( bModulateColors ? rDeviceColor[2] : 1.0 ); 262*cdf0e10cSrcweir const double nAlphaModulation( bModulateColors && rDeviceColor.getLength() > 3 ? 263*cdf0e10cSrcweir rDeviceColor[3] : 1.0 ); 264*cdf0e10cSrcweir 265*cdf0e10cSrcweir Bitmap aSrcBitmap( rBitmap.GetBitmap() ); 266*cdf0e10cSrcweir Bitmap aSrcAlpha; 267*cdf0e10cSrcweir 268*cdf0e10cSrcweir // differentiate mask and alpha channel (on-off 269*cdf0e10cSrcweir // vs. multi-level transparency) 270*cdf0e10cSrcweir if( rBitmap.IsTransparent() ) 271*cdf0e10cSrcweir { 272*cdf0e10cSrcweir if( rBitmap.IsAlpha() ) 273*cdf0e10cSrcweir aSrcAlpha = rBitmap.GetAlpha().GetBitmap(); 274*cdf0e10cSrcweir else 275*cdf0e10cSrcweir aSrcAlpha = rBitmap.GetMask(); 276*cdf0e10cSrcweir } 277*cdf0e10cSrcweir 278*cdf0e10cSrcweir ScopedBitmapReadAccess pReadAccess( aSrcBitmap.AcquireReadAccess(), 279*cdf0e10cSrcweir aSrcBitmap ); 280*cdf0e10cSrcweir ScopedBitmapReadAccess pAlphaReadAccess( rBitmap.IsTransparent() ? 281*cdf0e10cSrcweir aSrcAlpha.AcquireReadAccess() : 282*cdf0e10cSrcweir (BitmapReadAccess*)NULL, 283*cdf0e10cSrcweir aSrcAlpha ); 284*cdf0e10cSrcweir 285*cdf0e10cSrcweir if( pReadAccess.get() == NULL || 286*cdf0e10cSrcweir (pAlphaReadAccess.get() == NULL && rBitmap.IsTransparent()) ) 287*cdf0e10cSrcweir { 288*cdf0e10cSrcweir // TODO(E2): Error handling! 289*cdf0e10cSrcweir ENSURE_OR_THROW( false, 290*cdf0e10cSrcweir "transformBitmap(): could not access source bitmap" ); 291*cdf0e10cSrcweir } 292*cdf0e10cSrcweir 293*cdf0e10cSrcweir // mapping table, to translate pAlphaReadAccess' pixel 294*cdf0e10cSrcweir // values into destination alpha values (needed e.g. for 295*cdf0e10cSrcweir // paletted 1-bit masks). 296*cdf0e10cSrcweir sal_uInt8 aAlphaMap[256]; 297*cdf0e10cSrcweir 298*cdf0e10cSrcweir if( rBitmap.IsTransparent() ) 299*cdf0e10cSrcweir { 300*cdf0e10cSrcweir if( rBitmap.IsAlpha() ) 301*cdf0e10cSrcweir { 302*cdf0e10cSrcweir // source already has alpha channel - 1:1 mapping, 303*cdf0e10cSrcweir // i.e. aAlphaMap[0]=0,...,aAlphaMap[255]=255. 304*cdf0e10cSrcweir ::std::iota( aAlphaMap, &aAlphaMap[256], 0 ); 305*cdf0e10cSrcweir } 306*cdf0e10cSrcweir else 307*cdf0e10cSrcweir { 308*cdf0e10cSrcweir // mask transparency - determine used palette colors 309*cdf0e10cSrcweir const BitmapColor& rCol0( pAlphaReadAccess->GetPaletteColor( 0 ) ); 310*cdf0e10cSrcweir const BitmapColor& rCol1( pAlphaReadAccess->GetPaletteColor( 1 ) ); 311*cdf0e10cSrcweir 312*cdf0e10cSrcweir // shortcut for true luminance calculation 313*cdf0e10cSrcweir // (assumes that palette is grey-level) 314*cdf0e10cSrcweir aAlphaMap[0] = rCol0.GetRed(); 315*cdf0e10cSrcweir aAlphaMap[1] = rCol1.GetRed(); 316*cdf0e10cSrcweir } 317*cdf0e10cSrcweir } 318*cdf0e10cSrcweir // else: mapping table is not used 319*cdf0e10cSrcweir 320*cdf0e10cSrcweir const Size aDestBmpSize( ::basegfx::fround( aDestRect.getWidth() ), 321*cdf0e10cSrcweir ::basegfx::fround( aDestRect.getHeight() ) ); 322*cdf0e10cSrcweir 323*cdf0e10cSrcweir if( aDestBmpSize.Width() == 0 || aDestBmpSize.Height() == 0 ) 324*cdf0e10cSrcweir return BitmapEx(); 325*cdf0e10cSrcweir 326*cdf0e10cSrcweir Bitmap aDstBitmap( aDestBmpSize, aSrcBitmap.GetBitCount(), &pReadAccess->GetPalette() ); 327*cdf0e10cSrcweir Bitmap aDstAlpha( AlphaMask( aDestBmpSize ).GetBitmap() ); 328*cdf0e10cSrcweir 329*cdf0e10cSrcweir { 330*cdf0e10cSrcweir // just to be on the safe side: let the 331*cdf0e10cSrcweir // ScopedAccessors get destructed before 332*cdf0e10cSrcweir // copy-constructing the resulting bitmap. This will 333*cdf0e10cSrcweir // rule out the possibility that cached accessor data 334*cdf0e10cSrcweir // is not yet written back. 335*cdf0e10cSrcweir ScopedBitmapWriteAccess pWriteAccess( aDstBitmap.AcquireWriteAccess(), 336*cdf0e10cSrcweir aDstBitmap ); 337*cdf0e10cSrcweir ScopedBitmapWriteAccess pAlphaWriteAccess( aDstAlpha.AcquireWriteAccess(), 338*cdf0e10cSrcweir aDstAlpha ); 339*cdf0e10cSrcweir 340*cdf0e10cSrcweir 341*cdf0e10cSrcweir if( pWriteAccess.get() != NULL && 342*cdf0e10cSrcweir pAlphaWriteAccess.get() != NULL && 343*cdf0e10cSrcweir rTransform.isInvertible() ) 344*cdf0e10cSrcweir { 345*cdf0e10cSrcweir // we're doing inverse mapping here, i.e. mapping 346*cdf0e10cSrcweir // points from the destination bitmap back to the 347*cdf0e10cSrcweir // source 348*cdf0e10cSrcweir ::basegfx::B2DHomMatrix aTransform( aLocalTransform ); 349*cdf0e10cSrcweir aTransform.invert(); 350*cdf0e10cSrcweir 351*cdf0e10cSrcweir // for the time being, always read as ARGB 352*cdf0e10cSrcweir for( int y=0; y<aDestBmpSize.Height(); ++y ) 353*cdf0e10cSrcweir { 354*cdf0e10cSrcweir if( bModulateColors ) 355*cdf0e10cSrcweir { 356*cdf0e10cSrcweir // TODO(P2): Have different branches for 357*cdf0e10cSrcweir // alpha-only modulation (color 358*cdf0e10cSrcweir // modulations eq. 1.0) 359*cdf0e10cSrcweir 360*cdf0e10cSrcweir // modulate all color channels with given 361*cdf0e10cSrcweir // values 362*cdf0e10cSrcweir 363*cdf0e10cSrcweir // differentiate mask and alpha channel (on-off 364*cdf0e10cSrcweir // vs. multi-level transparency) 365*cdf0e10cSrcweir if( rBitmap.IsTransparent() ) 366*cdf0e10cSrcweir { 367*cdf0e10cSrcweir // Handling alpha and mask just the same... 368*cdf0e10cSrcweir for( int x=0; x<aDestBmpSize.Width(); ++x ) 369*cdf0e10cSrcweir { 370*cdf0e10cSrcweir ::basegfx::B2DPoint aPoint(x,y); 371*cdf0e10cSrcweir aPoint *= aTransform; 372*cdf0e10cSrcweir 373*cdf0e10cSrcweir const int nSrcX( ::basegfx::fround( aPoint.getX() ) ); 374*cdf0e10cSrcweir const int nSrcY( ::basegfx::fround( aPoint.getY() ) ); 375*cdf0e10cSrcweir if( nSrcX < 0 || nSrcX >= aBmpSize.Width() || 376*cdf0e10cSrcweir nSrcY < 0 || nSrcY >= aBmpSize.Height() ) 377*cdf0e10cSrcweir { 378*cdf0e10cSrcweir pAlphaWriteAccess->SetPixel( y, x, BitmapColor(255) ); 379*cdf0e10cSrcweir } 380*cdf0e10cSrcweir else 381*cdf0e10cSrcweir { 382*cdf0e10cSrcweir // modulate alpha with 383*cdf0e10cSrcweir // nAlphaModulation. This is a 384*cdf0e10cSrcweir // little bit verbose, formula 385*cdf0e10cSrcweir // is 255 - (255-pixAlpha)*nAlphaModulation 386*cdf0e10cSrcweir // (invert 'alpha' pixel value, 387*cdf0e10cSrcweir // to get the standard alpha 388*cdf0e10cSrcweir // channel behaviour) 389*cdf0e10cSrcweir pAlphaWriteAccess->SetPixel( y, x, 390*cdf0e10cSrcweir BitmapColor( 391*cdf0e10cSrcweir 255U - 392*cdf0e10cSrcweir static_cast<sal_uInt8>( 393*cdf0e10cSrcweir nAlphaModulation* 394*cdf0e10cSrcweir (255U 395*cdf0e10cSrcweir - aAlphaMap[ pAlphaReadAccess->GetPixel( 396*cdf0e10cSrcweir nSrcY, 397*cdf0e10cSrcweir nSrcX ).GetIndex() ] ) + .5 ) ) ); 398*cdf0e10cSrcweir 399*cdf0e10cSrcweir BitmapColor aColor( pReadAccess->GetPixel( nSrcY, 400*cdf0e10cSrcweir nSrcX ) ); 401*cdf0e10cSrcweir 402*cdf0e10cSrcweir aColor.SetRed( 403*cdf0e10cSrcweir static_cast<sal_uInt8>( 404*cdf0e10cSrcweir nRedModulation * 405*cdf0e10cSrcweir aColor.GetRed() + .5 )); 406*cdf0e10cSrcweir aColor.SetGreen( 407*cdf0e10cSrcweir static_cast<sal_uInt8>( 408*cdf0e10cSrcweir nGreenModulation * 409*cdf0e10cSrcweir aColor.GetGreen() + .5 )); 410*cdf0e10cSrcweir aColor.SetBlue( 411*cdf0e10cSrcweir static_cast<sal_uInt8>( 412*cdf0e10cSrcweir nBlueModulation * 413*cdf0e10cSrcweir aColor.GetBlue() + .5 )); 414*cdf0e10cSrcweir 415*cdf0e10cSrcweir pWriteAccess->SetPixel( y, x, 416*cdf0e10cSrcweir aColor ); 417*cdf0e10cSrcweir } 418*cdf0e10cSrcweir } 419*cdf0e10cSrcweir } 420*cdf0e10cSrcweir else 421*cdf0e10cSrcweir { 422*cdf0e10cSrcweir for( int x=0; x<aDestBmpSize.Width(); ++x ) 423*cdf0e10cSrcweir { 424*cdf0e10cSrcweir ::basegfx::B2DPoint aPoint(x,y); 425*cdf0e10cSrcweir aPoint *= aTransform; 426*cdf0e10cSrcweir 427*cdf0e10cSrcweir const int nSrcX( ::basegfx::fround( aPoint.getX() ) ); 428*cdf0e10cSrcweir const int nSrcY( ::basegfx::fround( aPoint.getY() ) ); 429*cdf0e10cSrcweir if( nSrcX < 0 || nSrcX >= aBmpSize.Width() || 430*cdf0e10cSrcweir nSrcY < 0 || nSrcY >= aBmpSize.Height() ) 431*cdf0e10cSrcweir { 432*cdf0e10cSrcweir pAlphaWriteAccess->SetPixel( y, x, BitmapColor(255) ); 433*cdf0e10cSrcweir } 434*cdf0e10cSrcweir else 435*cdf0e10cSrcweir { 436*cdf0e10cSrcweir // modulate alpha with 437*cdf0e10cSrcweir // nAlphaModulation. This is a 438*cdf0e10cSrcweir // little bit verbose, formula 439*cdf0e10cSrcweir // is 255 - 255*nAlphaModulation 440*cdf0e10cSrcweir // (invert 'alpha' pixel value, 441*cdf0e10cSrcweir // to get the standard alpha 442*cdf0e10cSrcweir // channel behaviour) 443*cdf0e10cSrcweir pAlphaWriteAccess->SetPixel( y, x, 444*cdf0e10cSrcweir BitmapColor( 445*cdf0e10cSrcweir 255U - 446*cdf0e10cSrcweir static_cast<sal_uInt8>( 447*cdf0e10cSrcweir nAlphaModulation*255.0 448*cdf0e10cSrcweir + .5 ) ) ); 449*cdf0e10cSrcweir 450*cdf0e10cSrcweir BitmapColor aColor( pReadAccess->GetPixel( nSrcY, 451*cdf0e10cSrcweir nSrcX ) ); 452*cdf0e10cSrcweir 453*cdf0e10cSrcweir aColor.SetRed( 454*cdf0e10cSrcweir static_cast<sal_uInt8>( 455*cdf0e10cSrcweir nRedModulation * 456*cdf0e10cSrcweir aColor.GetRed() + .5 )); 457*cdf0e10cSrcweir aColor.SetGreen( 458*cdf0e10cSrcweir static_cast<sal_uInt8>( 459*cdf0e10cSrcweir nGreenModulation * 460*cdf0e10cSrcweir aColor.GetGreen() + .5 )); 461*cdf0e10cSrcweir aColor.SetBlue( 462*cdf0e10cSrcweir static_cast<sal_uInt8>( 463*cdf0e10cSrcweir nBlueModulation * 464*cdf0e10cSrcweir aColor.GetBlue() + .5 )); 465*cdf0e10cSrcweir 466*cdf0e10cSrcweir pWriteAccess->SetPixel( y, x, 467*cdf0e10cSrcweir aColor ); 468*cdf0e10cSrcweir } 469*cdf0e10cSrcweir } 470*cdf0e10cSrcweir } 471*cdf0e10cSrcweir } 472*cdf0e10cSrcweir else 473*cdf0e10cSrcweir { 474*cdf0e10cSrcweir // differentiate mask and alpha channel (on-off 475*cdf0e10cSrcweir // vs. multi-level transparency) 476*cdf0e10cSrcweir if( rBitmap.IsTransparent() ) 477*cdf0e10cSrcweir { 478*cdf0e10cSrcweir // Handling alpha and mask just the same... 479*cdf0e10cSrcweir for( int x=0; x<aDestBmpSize.Width(); ++x ) 480*cdf0e10cSrcweir { 481*cdf0e10cSrcweir ::basegfx::B2DPoint aPoint(x,y); 482*cdf0e10cSrcweir aPoint *= aTransform; 483*cdf0e10cSrcweir 484*cdf0e10cSrcweir const int nSrcX( ::basegfx::fround( aPoint.getX() ) ); 485*cdf0e10cSrcweir const int nSrcY( ::basegfx::fround( aPoint.getY() ) ); 486*cdf0e10cSrcweir if( nSrcX < 0 || nSrcX >= aBmpSize.Width() || 487*cdf0e10cSrcweir nSrcY < 0 || nSrcY >= aBmpSize.Height() ) 488*cdf0e10cSrcweir { 489*cdf0e10cSrcweir pAlphaWriteAccess->SetPixel( y, x, BitmapColor(255) ); 490*cdf0e10cSrcweir } 491*cdf0e10cSrcweir else 492*cdf0e10cSrcweir { 493*cdf0e10cSrcweir pAlphaWriteAccess->SetPixel( y, x, 494*cdf0e10cSrcweir aAlphaMap[ 495*cdf0e10cSrcweir pAlphaReadAccess->GetPixel( nSrcY, 496*cdf0e10cSrcweir nSrcX ) ] ); 497*cdf0e10cSrcweir 498*cdf0e10cSrcweir pWriteAccess->SetPixel( y, x, pReadAccess->GetPixel( nSrcY, 499*cdf0e10cSrcweir nSrcX ) ); 500*cdf0e10cSrcweir } 501*cdf0e10cSrcweir } 502*cdf0e10cSrcweir } 503*cdf0e10cSrcweir else 504*cdf0e10cSrcweir { 505*cdf0e10cSrcweir for( int x=0; x<aDestBmpSize.Width(); ++x ) 506*cdf0e10cSrcweir { 507*cdf0e10cSrcweir ::basegfx::B2DPoint aPoint(x,y); 508*cdf0e10cSrcweir aPoint *= aTransform; 509*cdf0e10cSrcweir 510*cdf0e10cSrcweir const int nSrcX( ::basegfx::fround( aPoint.getX() ) ); 511*cdf0e10cSrcweir const int nSrcY( ::basegfx::fround( aPoint.getY() ) ); 512*cdf0e10cSrcweir if( nSrcX < 0 || nSrcX >= aBmpSize.Width() || 513*cdf0e10cSrcweir nSrcY < 0 || nSrcY >= aBmpSize.Height() ) 514*cdf0e10cSrcweir { 515*cdf0e10cSrcweir pAlphaWriteAccess->SetPixel( y, x, BitmapColor(255) ); 516*cdf0e10cSrcweir } 517*cdf0e10cSrcweir else 518*cdf0e10cSrcweir { 519*cdf0e10cSrcweir pAlphaWriteAccess->SetPixel( y, x, BitmapColor(0) ); 520*cdf0e10cSrcweir pWriteAccess->SetPixel( y, x, pReadAccess->GetPixel( nSrcY, 521*cdf0e10cSrcweir nSrcX ) ); 522*cdf0e10cSrcweir } 523*cdf0e10cSrcweir } 524*cdf0e10cSrcweir } 525*cdf0e10cSrcweir } 526*cdf0e10cSrcweir } 527*cdf0e10cSrcweir 528*cdf0e10cSrcweir bCopyBack = true; 529*cdf0e10cSrcweir } 530*cdf0e10cSrcweir else 531*cdf0e10cSrcweir { 532*cdf0e10cSrcweir // TODO(E2): Error handling! 533*cdf0e10cSrcweir ENSURE_OR_THROW( false, 534*cdf0e10cSrcweir "transformBitmap(): could not access bitmap" ); 535*cdf0e10cSrcweir } 536*cdf0e10cSrcweir } 537*cdf0e10cSrcweir 538*cdf0e10cSrcweir if( bCopyBack ) 539*cdf0e10cSrcweir return BitmapEx( aDstBitmap, AlphaMask( aDstAlpha ) ); 540*cdf0e10cSrcweir else 541*cdf0e10cSrcweir return BitmapEx(); 542*cdf0e10cSrcweir } 543*cdf0e10cSrcweir } 544*cdf0e10cSrcweir } 545