1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_canvas.hxx" 30 31 #include <ctype.h> // don't ask. msdev breaks otherwise... 32 #include <basegfx/numeric/ftools.hxx> 33 34 #include <canvas/debug.hxx> 35 #include <canvas/verbosetrace.hxx> 36 #include <tools/diagnose_ex.h> 37 38 #include <com/sun/star/lang/XServiceInfo.hpp> 39 #include <com/sun/star/lang/XUnoTunnel.hpp> 40 #include <com/sun/star/geometry/RealPoint2D.hpp> 41 #include <com/sun/star/geometry/IntegerRectangle2D.hpp> 42 43 #include <basegfx/matrix/b2dhommatrix.hxx> 44 #include <basegfx/range/b2irectangle.hxx> 45 #include <basegfx/range/b2drectangle.hxx> 46 #include <basegfx/polygon/b2dpolygon.hxx> 47 #include <basegfx/polygon/b2dpolypolygon.hxx> 48 #include <basegfx/tools/canvastools.hxx> 49 50 #include <canvas/canvastools.hxx> 51 #include <canvas/verifyinput.hxx> 52 53 #include "dx_impltools.hxx" 54 #include "dx_vcltools.hxx" 55 #include "dx_linepolypolygon.hxx" 56 #include "dx_canvasbitmap.hxx" 57 #include "dx_canvasfont.hxx" 58 #include "dx_canvas.hxx" 59 #include "dx_spritecanvas.hxx" 60 61 #include <boost/scoped_array.hpp> 62 63 #include <vector> 64 #include <algorithm> 65 66 67 using namespace ::com::sun::star; 68 69 70 namespace dxcanvas 71 { 72 namespace tools 73 { 74 ::basegfx::B2DPolyPolygon polyPolygonFromXPolyPolygon2D( const uno::Reference< rendering::XPolyPolygon2D >& xPoly ) 75 { 76 LinePolyPolygon* pPolyImpl = dynamic_cast< LinePolyPolygon* >( xPoly.get() ); 77 78 if( pPolyImpl ) 79 { 80 return pPolyImpl->getPolyPolygon(); 81 } 82 else 83 { 84 const sal_Int32 nPolys( xPoly->getNumberOfPolygons() ); 85 86 // not a known implementation object - try data source 87 // interfaces 88 uno::Reference< rendering::XBezierPolyPolygon2D > xBezierPoly( 89 xPoly, 90 uno::UNO_QUERY ); 91 92 if( xBezierPoly.is() ) 93 { 94 return ::basegfx::unotools::polyPolygonFromBezier2DSequenceSequence( 95 xBezierPoly->getBezierSegments( 0, 96 nPolys, 97 0, 98 -1 ) ); 99 } 100 else 101 { 102 uno::Reference< rendering::XLinePolyPolygon2D > xLinePoly( 103 xPoly, 104 uno::UNO_QUERY ); 105 106 // no implementation class and no data provider 107 // found - contract violation. 108 ENSURE_ARG_OR_THROW( xLinePoly.is(), 109 "VCLCanvas::polyPolygonFromXPolyPolygon2D(): Invalid input " 110 "poly-polygon, cannot retrieve vertex data" ); 111 112 return ::basegfx::unotools::polyPolygonFromPoint2DSequenceSequence( 113 xLinePoly->getPoints( 0, 114 nPolys, 115 0, 116 -1 ) ); 117 } 118 } 119 } 120 121 void setupGraphics( Gdiplus::Graphics& rGraphics ) 122 { 123 // setup graphics with (somewhat arbitrary) defaults 124 //rGraphics.SetCompositingQuality( Gdiplus::CompositingQualityHighQuality ); 125 rGraphics.SetCompositingQuality( Gdiplus::CompositingQualityHighSpeed ); 126 //rGraphics.SetInterpolationMode( Gdiplus::InterpolationModeHighQualityBilinear ); // with prefiltering for shrinks 127 rGraphics.SetInterpolationMode( Gdiplus::InterpolationModeBilinear ); 128 129 // #122683# Switched precedence of pixel offset 130 // mode. Seemingly, polygon stroking needs 131 // PixelOffsetModeNone to achieve visually pleasing 132 // results, whereas all other operations (e.g. polygon 133 // fills, bitmaps) look better with PixelOffsetModeHalf. 134 rGraphics.SetPixelOffsetMode( Gdiplus::PixelOffsetModeHalf ); // Pixel center at (0.5, 0.5) etc. 135 //rGraphics.SetPixelOffsetMode( Gdiplus::PixelOffsetModeNone ); 136 137 //rGraphics.SetSmoothingMode( Gdiplus::SmoothingModeHighSpeed ); // no line/curve antialiasing 138 //rGraphics.SetSmoothingMode( Gdiplus::SmoothingModeHighQuality ); 139 rGraphics.SetSmoothingMode( Gdiplus::SmoothingModeAntiAlias ); 140 //rGraphics.SetTextRenderingHint( Gdiplus::TextRenderingHintAntiAlias ); 141 rGraphics.SetTextRenderingHint( Gdiplus::TextRenderingHintSystemDefault ); 142 rGraphics.SetPageUnit(Gdiplus::UnitPixel); 143 } 144 145 Gdiplus::Graphics* createGraphicsFromHDC(HDC aHDC) 146 { 147 Gdiplus::Graphics* pRet = new Gdiplus::Graphics(aHDC); 148 if( pRet ) 149 setupGraphics( *pRet ); 150 return pRet; 151 } 152 153 Gdiplus::Graphics* createGraphicsFromBitmap(const BitmapSharedPtr& rBitmap) 154 { 155 Gdiplus::Graphics* pRet = Gdiplus::Graphics::FromImage(rBitmap.get()); 156 if( pRet ) 157 setupGraphics( *pRet ); 158 return pRet; 159 } 160 161 void gdiPlusMatrixFromB2DHomMatrix( Gdiplus::Matrix& rGdiplusMatrix, const ::basegfx::B2DHomMatrix& rMatrix ) 162 { 163 rGdiplusMatrix.SetElements( static_cast<Gdiplus::REAL>(rMatrix.get(0,0)), 164 static_cast<Gdiplus::REAL>(rMatrix.get(1,0)), 165 static_cast<Gdiplus::REAL>(rMatrix.get(0,1)), 166 static_cast<Gdiplus::REAL>(rMatrix.get(1,1)), 167 static_cast<Gdiplus::REAL>(rMatrix.get(0,2)), 168 static_cast<Gdiplus::REAL>(rMatrix.get(1,2)) ); 169 } 170 171 void gdiPlusMatrixFromAffineMatrix2D( Gdiplus::Matrix& rGdiplusMatrix, 172 const geometry::AffineMatrix2D& rMatrix ) 173 { 174 rGdiplusMatrix.SetElements( static_cast<Gdiplus::REAL>(rMatrix.m00), 175 static_cast<Gdiplus::REAL>(rMatrix.m10), 176 static_cast<Gdiplus::REAL>(rMatrix.m01), 177 static_cast<Gdiplus::REAL>(rMatrix.m11), 178 static_cast<Gdiplus::REAL>(rMatrix.m02), 179 static_cast<Gdiplus::REAL>(rMatrix.m12) ); 180 } 181 182 namespace 183 { 184 // TODO(P2): Check whether this gets inlined. If not, make functor 185 // out of it 186 inline Gdiplus::PointF implGdiPlusPointFromRealPoint2D( const ::com::sun::star::geometry::RealPoint2D& rPoint ) 187 { 188 return Gdiplus::PointF( static_cast<Gdiplus::REAL>(rPoint.X), 189 static_cast<Gdiplus::REAL>(rPoint.Y) ); 190 } 191 192 void graphicsPathFromB2DPolygon( GraphicsPathSharedPtr& rOutput, 193 ::std::vector< Gdiplus::PointF >& rPoints, 194 const ::basegfx::B2DPolygon& rPoly, 195 bool bNoLineJoin) 196 { 197 const sal_uInt32 nPoints( rPoly.count() ); 198 199 if( nPoints < 2 ) 200 return; 201 202 rOutput->StartFigure(); 203 204 const bool bClosedPolygon( rPoly.isClosed() ); 205 206 if( rPoly.areControlPointsUsed() ) 207 { 208 // control points used -> for now, add all 209 // segments as curves to GraphicsPath 210 211 // If the polygon is closed, we need to add the 212 // first point, thus, one more (can't simply 213 // GraphicsPath::CloseFigure() it, since the last 214 // point cannot have any control points for GDI+) 215 rPoints.resize( 3*nPoints + bClosedPolygon ); 216 217 sal_uInt32 nCurrOutput=0; 218 for( sal_uInt32 nCurrPoint=0; nCurrPoint<nPoints; ++nCurrPoint ) 219 { 220 const ::basegfx::B2DPoint& rPoint( rPoly.getB2DPoint( nCurrPoint ) ); 221 rPoints[nCurrOutput++] = Gdiplus::PointF( static_cast<Gdiplus::REAL>(rPoint.getX()), 222 static_cast<Gdiplus::REAL>(rPoint.getY()) ); 223 224 const ::basegfx::B2DPoint& rControlPointA( rPoly.getNextControlPoint( nCurrPoint ) ); 225 rPoints[nCurrOutput++] = Gdiplus::PointF( static_cast<Gdiplus::REAL>(rControlPointA.getX()), 226 static_cast<Gdiplus::REAL>(rControlPointA.getY()) ); 227 228 const ::basegfx::B2DPoint& rControlPointB( rPoly.getPrevControlPoint( (nCurrPoint + 1) % nPoints) ); 229 rPoints[nCurrOutput++] = Gdiplus::PointF( static_cast<Gdiplus::REAL>(rControlPointB.getX()), 230 static_cast<Gdiplus::REAL>(rControlPointB.getY()) ); 231 } 232 233 if( bClosedPolygon ) 234 { 235 // add first point again (to be able to pass 236 // control points for the last point, see 237 // above) 238 const ::basegfx::B2DPoint& rPoint( rPoly.getB2DPoint(0) ); 239 rPoints[nCurrOutput++] = Gdiplus::PointF( static_cast<Gdiplus::REAL>(rPoint.getX()), 240 static_cast<Gdiplus::REAL>(rPoint.getY()) ); 241 242 if(bNoLineJoin && nCurrOutput > 7) 243 { 244 for(sal_uInt32 a(3); a < nCurrOutput; a+=3) 245 { 246 rOutput->StartFigure(); 247 rOutput->AddBezier(rPoints[a - 3], rPoints[a - 2], rPoints[a - 1], rPoints[a]); 248 } 249 } 250 else 251 { 252 rOutput->AddBeziers( &rPoints[0], nCurrOutput ); 253 } 254 } 255 else 256 { 257 // GraphicsPath expects 3(n-1)+1 points (i.e. the 258 // last point must not have any trailing control 259 // points after it). 260 // Therefore, simply don't pass the last two 261 // points here. 262 if( nCurrOutput > 3 ) 263 { 264 if(bNoLineJoin && nCurrOutput > 7) 265 { 266 for(sal_uInt32 a(3); a < nCurrOutput; a+=3) 267 { 268 rOutput->StartFigure(); 269 rOutput->AddBezier(rPoints[a - 3], rPoints[a - 2], rPoints[a - 1], rPoints[a]); 270 } 271 } 272 else 273 { 274 rOutput->AddBeziers( &rPoints[0], nCurrOutput-2 ); 275 } 276 } 277 } 278 } 279 else 280 { 281 // no control points -> no curves, simply add 282 // straigt lines to GraphicsPath 283 rPoints.resize( nPoints ); 284 285 for( sal_uInt32 nCurrPoint=0; nCurrPoint<nPoints; ++nCurrPoint ) 286 { 287 const ::basegfx::B2DPoint& rPoint( rPoly.getB2DPoint( nCurrPoint ) ); 288 rPoints[nCurrPoint] = Gdiplus::PointF( static_cast<Gdiplus::REAL>(rPoint.getX()), 289 static_cast<Gdiplus::REAL>(rPoint.getY()) ); 290 } 291 292 if(bNoLineJoin && nPoints > 2) 293 { 294 for(sal_uInt32 a(1); a < nPoints; a++) 295 { 296 rOutput->StartFigure(); 297 rOutput->AddLine(rPoints[a - 1], rPoints[a]); 298 } 299 300 if(bClosedPolygon) 301 { 302 rOutput->StartFigure(); 303 rOutput->AddLine(rPoints[nPoints - 1], rPoints[0]); 304 } 305 } 306 else 307 { 308 rOutput->AddLines( &rPoints[0], nPoints ); 309 } 310 } 311 312 if( bClosedPolygon && !bNoLineJoin ) 313 rOutput->CloseFigure(); 314 } 315 } 316 317 Gdiplus::PointF gdiPlusPointFromRealPoint2D( const ::com::sun::star::geometry::RealPoint2D& rPoint ) 318 { 319 return implGdiPlusPointFromRealPoint2D( rPoint ); 320 } 321 322 Gdiplus::Rect gdiPlusRectFromIntegerRectangle2D( const geometry::IntegerRectangle2D& rRect ) 323 { 324 return Gdiplus::Rect( rRect.X1, 325 rRect.Y1, 326 rRect.X2 - rRect.X1, 327 rRect.Y2 - rRect.Y1 ); 328 } 329 330 Gdiplus::RectF gdiPlusRectFFromRectangle2D( const geometry::RealRectangle2D& rRect ) 331 { 332 return Gdiplus::RectF( static_cast<Gdiplus::REAL>(rRect.X1), 333 static_cast<Gdiplus::REAL>(rRect.Y1), 334 static_cast<Gdiplus::REAL>(rRect.X2 - rRect.X1), 335 static_cast<Gdiplus::REAL>(rRect.Y2 - rRect.Y1) ); 336 } 337 338 RECT gdiRectFromB2IRect( const ::basegfx::B2IRange& rRect ) 339 { 340 RECT aRect = {rRect.getMinX(), 341 rRect.getMinY(), 342 rRect.getMaxX(), 343 rRect.getMaxY()}; 344 345 return aRect; 346 } 347 348 geometry::RealPoint2D realPoint2DFromGdiPlusPointF( const Gdiplus::PointF& rPoint ) 349 { 350 return geometry::RealPoint2D( rPoint.X, rPoint.Y ); 351 } 352 353 geometry::RealRectangle2D realRectangle2DFromGdiPlusRectF( const Gdiplus::RectF& rRect ) 354 { 355 return geometry::RealRectangle2D( rRect.X, rRect.Y, 356 rRect.X + rRect.Width, 357 rRect.Y + rRect.Height ); 358 } 359 360 ::basegfx::B2DPoint b2dPointFromGdiPlusPointF( const Gdiplus::PointF& rPoint ) 361 { 362 return ::basegfx::B2DPoint( rPoint.X, rPoint.Y ); 363 } 364 365 ::basegfx::B2DRange b2dRangeFromGdiPlusRectF( const Gdiplus::RectF& rRect ) 366 { 367 return ::basegfx::B2DRange( rRect.X, rRect.Y, 368 rRect.X + rRect.Width, 369 rRect.Y + rRect.Height ); 370 } 371 372 uno::Sequence< double > argbToDoubleSequence( const Gdiplus::ARGB& rColor ) 373 { 374 // TODO(F1): handle color space conversions, when defined on canvas/graphicDevice 375 uno::Sequence< double > aRet(4); 376 377 aRet[0] = ((rColor >> 16) & 0xFF) / 255.0; // red 378 aRet[1] = ((rColor >> 8) & 0xFF) / 255.0; // green 379 aRet[2] = (rColor & 0xFF) / 255.0; // blue 380 aRet[3] = ((rColor >> 24) & 0xFF) / 255.0; // alpha 381 382 return aRet; 383 } 384 385 uno::Sequence< sal_Int8 > argbToIntSequence( const Gdiplus::ARGB& rColor ) 386 { 387 // TODO(F1): handle color space conversions, when defined on canvas/graphicDevice 388 uno::Sequence< sal_Int8 > aRet(4); 389 390 aRet[0] = static_cast<sal_Int8>((rColor >> 16) & 0xFF); // red 391 aRet[1] = static_cast<sal_Int8>((rColor >> 8) & 0xFF); // green 392 aRet[2] = static_cast<sal_Int8>(rColor & 0xFF); // blue 393 aRet[3] = static_cast<sal_Int8>((rColor >> 24) & 0xFF); // alpha 394 395 return aRet; 396 } 397 398 Gdiplus::ARGB sequenceToArgb( const uno::Sequence< sal_Int8 >& rColor ) 399 { 400 ENSURE_OR_THROW( rColor.getLength() > 2, 401 "sequenceToArgb: need at least three channels" ); 402 403 // TODO(F1): handle color space conversions, when defined on canvas/graphicDevice 404 Gdiplus::ARGB aColor; 405 406 aColor = (static_cast<sal_uInt8>(rColor[0]) << 16) | (static_cast<sal_uInt8>(rColor[1]) << 8) | static_cast<sal_uInt8>(rColor[2]); 407 408 if( rColor.getLength() > 3 ) 409 aColor |= static_cast<sal_uInt8>(rColor[3]) << 24; 410 411 return aColor; 412 } 413 414 Gdiplus::ARGB sequenceToArgb( const uno::Sequence< double >& rColor ) 415 { 416 ENSURE_OR_THROW( rColor.getLength() > 2, 417 "sequenceToColor: need at least three channels" ); 418 419 // TODO(F1): handle color space conversions, when defined on canvas/graphicDevice 420 Gdiplus::ARGB aColor; 421 422 ::canvas::tools::verifyRange(rColor[0],0.0,1.0); 423 ::canvas::tools::verifyRange(rColor[1],0.0,1.0); 424 ::canvas::tools::verifyRange(rColor[2],0.0,1.0); 425 426 aColor = 427 (static_cast<sal_uInt8>( ::basegfx::fround( 255*rColor[0] ) ) << 16) | 428 (static_cast<sal_uInt8>( ::basegfx::fround( 255*rColor[1] ) ) << 8) | 429 static_cast<sal_uInt8>( ::basegfx::fround( 255*rColor[2] ) ); 430 431 if( rColor.getLength() > 3 ) 432 { 433 ::canvas::tools::verifyRange(rColor[3],0.0,1.0); 434 aColor |= static_cast<sal_uInt8>( ::basegfx::fround( 255*rColor[3] ) ) << 24; 435 } 436 437 return aColor; 438 } 439 440 GraphicsPathSharedPtr graphicsPathFromRealPoint2DSequence( const uno::Sequence< uno::Sequence< geometry::RealPoint2D > >& points ) 441 { 442 GraphicsPathSharedPtr pRes( new Gdiplus::GraphicsPath() ); 443 ::std::vector< Gdiplus::PointF > aPoints; 444 445 sal_Int32 nCurrPoly; 446 for( nCurrPoly=0; nCurrPoly<points.getLength(); ++nCurrPoly ) 447 { 448 const sal_Int32 nCurrSize( points[nCurrPoly].getLength() ); 449 if( nCurrSize ) 450 { 451 aPoints.resize( nCurrSize ); 452 453 // TODO(F1): Closed/open polygons 454 455 // convert from RealPoint2D array to Gdiplus::PointF array 456 ::std::transform( const_cast< uno::Sequence< geometry::RealPoint2D >& >(points[nCurrPoly]).getArray(), 457 const_cast< uno::Sequence< geometry::RealPoint2D >& >(points[nCurrPoly]).getArray()+nCurrSize, 458 aPoints.begin(), 459 implGdiPlusPointFromRealPoint2D ); 460 461 pRes->AddLines( &aPoints[0], nCurrSize ); 462 } 463 } 464 465 return pRes; 466 } 467 468 GraphicsPathSharedPtr graphicsPathFromB2DPolygon( const ::basegfx::B2DPolygon& rPoly, bool bNoLineJoin ) 469 { 470 GraphicsPathSharedPtr pRes( new Gdiplus::GraphicsPath() ); 471 ::std::vector< Gdiplus::PointF > aPoints; 472 473 graphicsPathFromB2DPolygon( pRes, aPoints, rPoly, bNoLineJoin ); 474 475 return pRes; 476 } 477 478 GraphicsPathSharedPtr graphicsPathFromB2DPolyPolygon( const ::basegfx::B2DPolyPolygon& rPoly, bool bNoLineJoin ) 479 { 480 GraphicsPathSharedPtr pRes( new Gdiplus::GraphicsPath() ); 481 ::std::vector< Gdiplus::PointF > aPoints; 482 483 const sal_uInt32 nPolies( rPoly.count() ); 484 for( sal_uInt32 nCurrPoly=0; nCurrPoly<nPolies; ++nCurrPoly ) 485 { 486 graphicsPathFromB2DPolygon( pRes, 487 aPoints, 488 rPoly.getB2DPolygon( nCurrPoly ), 489 bNoLineJoin); 490 } 491 492 return pRes; 493 } 494 495 GraphicsPathSharedPtr graphicsPathFromXPolyPolygon2D( const uno::Reference< rendering::XPolyPolygon2D >& xPoly, bool bNoLineJoin ) 496 { 497 LinePolyPolygon* pPolyImpl = dynamic_cast< LinePolyPolygon* >( xPoly.get() ); 498 499 if( pPolyImpl ) 500 { 501 return pPolyImpl->getGraphicsPath( bNoLineJoin ); 502 } 503 else 504 { 505 return tools::graphicsPathFromB2DPolyPolygon( 506 polyPolygonFromXPolyPolygon2D( xPoly ), bNoLineJoin ); 507 } 508 } 509 510 bool drawGdiPlusBitmap( const GraphicsSharedPtr& rGraphics, 511 const BitmapSharedPtr& rBitmap ) 512 { 513 Gdiplus::PointF aPoint; 514 return (Gdiplus::Ok == rGraphics->DrawImage( rBitmap.get(), 515 aPoint ) ); 516 } 517 518 bool drawDIBits( const GraphicsSharedPtr& rGraphics, 519 const BITMAPINFO& rBI, 520 const void* pBits ) 521 { 522 BitmapSharedPtr pBitmap( 523 Gdiplus::Bitmap::FromBITMAPINFO( &rBI, 524 (void*)pBits ) ); 525 526 return drawGdiPlusBitmap( rGraphics, 527 pBitmap ); 528 } 529 530 bool drawRGBABits( const GraphicsSharedPtr& rGraphics, 531 const RawRGBABitmap& rRawRGBAData ) 532 { 533 BitmapSharedPtr pBitmap( new Gdiplus::Bitmap( rRawRGBAData.mnWidth, 534 rRawRGBAData.mnHeight, 535 PixelFormat32bppARGB ) ); 536 537 Gdiplus::BitmapData aBmpData; 538 aBmpData.Width = rRawRGBAData.mnWidth; 539 aBmpData.Height = rRawRGBAData.mnHeight; 540 aBmpData.Stride = 4*aBmpData.Width; // bottom-up format 541 aBmpData.PixelFormat = PixelFormat32bppARGB; 542 aBmpData.Scan0 = rRawRGBAData.mpBitmapData.get(); 543 544 const Gdiplus::Rect aRect( 0,0,aBmpData.Width,aBmpData.Height ); 545 if( Gdiplus::Ok != pBitmap->LockBits( &aRect, 546 Gdiplus::ImageLockModeWrite | Gdiplus::ImageLockModeUserInputBuf, 547 PixelFormat32bppARGB, 548 &aBmpData ) ) 549 { 550 return false; 551 } 552 553 // commit data to bitmap 554 pBitmap->UnlockBits( &aBmpData ); 555 556 return drawGdiPlusBitmap( rGraphics, 557 pBitmap ); 558 } 559 560 BitmapSharedPtr bitmapFromXBitmap( const uno::Reference< rendering::XBitmap >& xBitmap ) 561 { 562 BitmapProvider* pBitmapProvider = dynamic_cast< BitmapProvider* >(xBitmap.get()); 563 564 if( pBitmapProvider ) 565 { 566 IBitmapSharedPtr pBitmap( pBitmapProvider->getBitmap() ); 567 return pBitmap->getBitmap(); 568 } 569 else 570 { 571 // not a native CanvasBitmap, extract VCL bitmap and 572 // render into GDI+ bitmap of similar size 573 // ================================================= 574 575 const geometry::IntegerSize2D aBmpSize( xBitmap->getSize() ); 576 BitmapSharedPtr pBitmap; 577 578 if( xBitmap->hasAlpha() ) 579 { 580 // TODO(P2): At least for the alpha bitmap case, it 581 // would be possible to generate the corresponding 582 // bitmap directly 583 pBitmap.reset( new Gdiplus::Bitmap( aBmpSize.Width, 584 aBmpSize.Height, 585 PixelFormat32bppARGB ) ); 586 } 587 else 588 { 589 // TODO(F2): Might be wise to create bitmap compatible 590 // to the VCL bitmap. Also, check whether the VCL 591 // bitmap's system handles can be used to create the 592 // GDI+ bitmap (currently, it does not seem so). 593 pBitmap.reset( new Gdiplus::Bitmap( aBmpSize.Width, 594 aBmpSize.Height, 595 PixelFormat24bppRGB ) ); 596 } 597 598 GraphicsSharedPtr pGraphics(createGraphicsFromBitmap(pBitmap)); 599 tools::setupGraphics(*pGraphics); 600 if( !drawVCLBitmapFromXBitmap( 601 pGraphics, 602 xBitmap) ) 603 { 604 pBitmap.reset(); 605 } 606 607 return pBitmap; 608 } 609 } 610 611 CanvasFont::ImplRef canvasFontFromXFont( const uno::Reference< rendering::XCanvasFont >& xFont ) 612 { 613 CanvasFont* pCanvasFont = dynamic_cast< CanvasFont* >(xFont.get()); 614 615 ENSURE_ARG_OR_THROW( pCanvasFont, 616 "canvasFontFromXFont(): Invalid XFont (or incompatible font for this XCanvas)" ); 617 618 return CanvasFont::ImplRef( pCanvasFont ); 619 } 620 621 void setModulateImageAttributes( Gdiplus::ImageAttributes& o_rAttr, 622 double nRedModulation, 623 double nGreenModulation, 624 double nBlueModulation, 625 double nAlphaModulation ) 626 { 627 // This gets rather verbose, but we have to setup a color 628 // transformation matrix, in order to incorporate the global 629 // alpha value mfAlpha into the bitmap rendering. 630 Gdiplus::ColorMatrix aColorMatrix; 631 632 aColorMatrix.m[0][0] = static_cast<Gdiplus::REAL>(nRedModulation); 633 aColorMatrix.m[0][1] = 0.0; 634 aColorMatrix.m[0][2] = 0.0; 635 aColorMatrix.m[0][3] = 0.0; 636 aColorMatrix.m[0][4] = 0.0; 637 638 aColorMatrix.m[1][0] = 0.0; 639 aColorMatrix.m[1][1] = static_cast<Gdiplus::REAL>(nGreenModulation); 640 aColorMatrix.m[1][2] = 0.0; 641 aColorMatrix.m[1][3] = 0.0; 642 aColorMatrix.m[1][4] = 0.0; 643 644 aColorMatrix.m[2][0] = 0.0; 645 aColorMatrix.m[2][1] = 0.0; 646 aColorMatrix.m[2][2] = static_cast<Gdiplus::REAL>(nBlueModulation); 647 aColorMatrix.m[2][3] = 0.0; 648 aColorMatrix.m[2][4] = 0.0; 649 650 aColorMatrix.m[3][0] = 0.0; 651 aColorMatrix.m[3][1] = 0.0; 652 aColorMatrix.m[3][2] = 0.0; 653 aColorMatrix.m[3][3] = static_cast<Gdiplus::REAL>(nAlphaModulation); 654 aColorMatrix.m[3][4] = 0.0; 655 656 aColorMatrix.m[4][0] = 0.0; 657 aColorMatrix.m[4][1] = 0.0; 658 aColorMatrix.m[4][2] = 0.0; 659 aColorMatrix.m[4][3] = 0.0; 660 aColorMatrix.m[4][4] = 1.0; 661 662 o_rAttr.SetColorMatrix( &aColorMatrix, 663 Gdiplus::ColorMatrixFlagsDefault, 664 Gdiplus::ColorAdjustTypeDefault ); 665 } 666 667 } // namespace tools 668 } // namespace dxcanvas 669