xref: /AOO41X/main/vcl/source/helper/canvastools.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
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_vcl.hxx"
30 
31 #include <rtl/logfile.hxx>
32 #include <cppuhelper/compbase1.hxx>
33 
34 #include <com/sun/star/geometry/RealSize2D.hpp>
35 #include <com/sun/star/geometry/RealPoint2D.hpp>
36 #include <com/sun/star/geometry/RealRectangle2D.hpp>
37 #include <com/sun/star/geometry/IntegerSize2D.hpp>
38 #include <com/sun/star/geometry/IntegerPoint2D.hpp>
39 #include <com/sun/star/geometry/IntegerRectangle2D.hpp>
40 #include <com/sun/star/geometry/RealBezierSegment2D.hpp>
41 
42 #include <com/sun/star/rendering/ColorSpaceType.hpp>
43 #include <com/sun/star/rendering/RenderingIntent.hpp>
44 #include <com/sun/star/rendering/XGraphicDevice.hpp>
45 #include <com/sun/star/rendering/XBitmap.hpp>
46 #include <com/sun/star/rendering/XPolyPolygon2D.hpp>
47 #include <com/sun/star/rendering/IntegerBitmapLayout.hpp>
48 #include <com/sun/star/rendering/XIntegerBitmap.hpp>
49 #include <com/sun/star/rendering/ColorComponentTag.hpp>
50 
51 #include <basegfx/matrix/b2dhommatrix.hxx>
52 #include <basegfx/vector/b2dsize.hxx>
53 #include <basegfx/point/b2dpoint.hxx>
54 #include <basegfx/range/b2drectangle.hxx>
55 #include <basegfx/vector/b2isize.hxx>
56 #include <basegfx/point/b2ipoint.hxx>
57 #include <basegfx/range/b2irectangle.hxx>
58 
59 // #i79917#
60 #include <basegfx/polygon/b2dpolygon.hxx>
61 #include <basegfx/tools/canvastools.hxx>
62 #include <basegfx/polygon/b2dpolypolygon.hxx>
63 
64 #include <tools/poly.hxx>
65 #include <tools/diagnose_ex.h>
66 #include <rtl/uuid.h>
67 
68 #include <vcl/salbtype.hxx>
69 #include <vcl/bmpacc.hxx>
70 #include <vcl/bitmapex.hxx>
71 
72 #include <canvasbitmap.hxx>
73 #include <vcl/canvastools.hxx>
74 #include <hash_map>
75 
76 
77 using namespace ::com::sun::star;
78 
79 namespace vcl
80 {
81     namespace unotools
82     {
83         // #i79917# removed helpers bezierSequenceFromPolygon and
84 		// pointSequenceFromPolygon here
85 		// Also all helpers using tools Polygon and PolyPolygon will get mapped to the
86 		// B2DPolygon helpers for these cases, see comments with the same TaskID below.
87 		// TODO: Remove those wrapped methods
88 
89         //---------------------------------------------------------------------------------------
90 
91         uno::Reference< rendering::XPolyPolygon2D > xPolyPolygonFromPolygon( const uno::Reference< rendering::XGraphicDevice >& 	xGraphicDevice,
92                                                                              const ::Polygon&										inputPolygon )
93         {
94             RTL_LOGFILE_CONTEXT( aLog, "::vcl::unotools::xPolyPolygonFromPolygon()" );
95 
96 			// #i79917# map to basegfx
97 			const basegfx::B2DPolygon aB2DPolygon(inputPolygon.getB2DPolygon());
98 			return basegfx::unotools::xPolyPolygonFromB2DPolygon(xGraphicDevice, aB2DPolygon);
99         }
100 
101         //---------------------------------------------------------------------------------------
102 
103         uno::Reference< rendering::XPolyPolygon2D > xPolyPolygonFromPolyPolygon( const uno::Reference< rendering::XGraphicDevice >& xGraphicDevice,
104                                                                                  const ::PolyPolygon&								inputPolyPolygon )
105         {
106             RTL_LOGFILE_CONTEXT( aLog, "::vcl::unotools::xPolyPolygonFromPolyPolygon()" );
107 
108 			// #i79917# map to basegfx
109 			const basegfx::B2DPolyPolygon aB2DPolyPolygon(inputPolyPolygon.getB2DPolyPolygon());
110 	        return basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(xGraphicDevice, aB2DPolyPolygon);
111         }
112 
113         //---------------------------------------------------------------------------------------
114 
115         ::Polygon polygonFromPoint2DSequence( const uno::Sequence< geometry::RealPoint2D >& points )
116         {
117             RTL_LOGFILE_CONTEXT( aLog, "::vcl::unotools::polygonFromPoint2DSequence()" );
118 
119             const sal_uInt16 nCurrSize( sal::static_int_cast<sal_uInt16>(points.getLength()) );
120 
121             ::Polygon aPoly( nCurrSize );
122 
123             sal_uInt16 nCurrPoint;
124             for( nCurrPoint=0; nCurrPoint<nCurrSize; ++nCurrPoint )
125                 aPoly[nCurrPoint] = pointFromRealPoint2D( points[nCurrPoint] );
126 
127             return aPoly;
128         }
129 
130         //---------------------------------------------------------------------------------------
131 
132         ::PolyPolygon polyPolygonFromPoint2DSequenceSequence( const uno::Sequence< uno::Sequence< geometry::RealPoint2D > >& points )
133         {
134             RTL_LOGFILE_CONTEXT( aLog, "::vcl::unotools::polyPolygonFromPoint2DSequenceSequence()" );
135 
136             ::PolyPolygon aRes;
137 
138             int nCurrPoly;
139             for( nCurrPoly=0; nCurrPoly<points.getLength(); ++nCurrPoly )
140             {
141                 aRes.Insert( polygonFromPoint2DSequence( points[nCurrPoly] ) );
142             }
143 
144             return aRes;
145         }
146 
147         //---------------------------------------------------------------------------------------
148 
149         ::Polygon polygonFromBezier2DSequence( const uno::Sequence< geometry::RealBezierSegment2D >& curves )
150         {
151 			// #i79917# map to basegfx
152 			const basegfx::B2DPolygon aB2DPolygon(basegfx::unotools::polygonFromBezier2DSequence(curves));
153 			return ::Polygon(aB2DPolygon);
154         }
155 
156         //---------------------------------------------------------------------------------------
157 
158         ::PolyPolygon polyPolygonFromBezier2DSequenceSequence( const uno::Sequence< uno::Sequence< geometry::RealBezierSegment2D > >& curves )
159         {
160 			// #i79917# map to basegfx
161 	        const basegfx::B2DPolyPolygon aB2DPolyPolygon(basegfx::unotools::polyPolygonFromBezier2DSequenceSequence(curves));
162 			return ::PolyPolygon(aB2DPolyPolygon);
163         }
164 
165         //---------------------------------------------------------------------------------------
166 
167         uno::Reference< rendering::XBitmap > xBitmapFromBitmap( const uno::Reference< rendering::XGraphicDevice >& 	/*xGraphicDevice*/,
168                                                                 const ::Bitmap&										inputBitmap )
169         {
170             RTL_LOGFILE_CONTEXT( aLog, "::vcl::unotools::xBitmapFromBitmap()" );
171 
172             return new vcl::unotools::VclCanvasBitmap( BitmapEx( inputBitmap ) );
173         }
174 
175         //---------------------------------------------------------------------------------------
176 
177         uno::Reference< rendering::XBitmap > xBitmapFromBitmapEx( const uno::Reference< rendering::XGraphicDevice >& 	/*xGraphicDevice*/,
178                                                                   const ::BitmapEx&										inputBitmap )
179         {
180             RTL_LOGFILE_CONTEXT( aLog, "::vcl::unotools::xBitmapFromBitmapEx()" );
181 
182             return new vcl::unotools::VclCanvasBitmap( inputBitmap );
183         }
184 
185         //---------------------------------------------------------------------------------------
186 
187         const uno::Sequence< sal_Int8 > getTunnelIdentifier( TunnelIdentifierType eType )
188         {
189             static std::hash_map< int, uno::Sequence< sal_Int8 > > aIds;
190             std::hash_map< int, uno::Sequence< sal_Int8 > >::iterator it =
191                 aIds.find( eType );
192             if( it == aIds.end() )
193             {
194                 uno::Sequence< sal_Int8 > aNewId( 16 );
195                 rtl_createUuid( (sal_uInt8*)aNewId.getArray(), NULL, sal_True );
196                 aIds[ eType ] = aNewId;
197                 it = aIds.find( eType );
198             }
199             return it->second;
200         }
201 
202         //---------------------------------------------------------------------------------------
203 
204         namespace
205         {
206             inline bool operator==( const rendering::IntegerBitmapLayout& rLHS,
207                                     const rendering::IntegerBitmapLayout& rRHS )
208             {
209                 return
210                     rLHS.ScanLineBytes       == rRHS.ScanLineBytes &&
211                     rLHS.ScanLineStride      == rRHS.ScanLineStride &&
212                     rLHS.PlaneStride         == rRHS.PlaneStride &&
213                     rLHS.ColorSpace          == rRHS.ColorSpace &&
214                     rLHS.Palette             == rRHS.Palette &&
215                     rLHS.IsMsbFirst          == rRHS.IsMsbFirst;
216             }
217 
218             bool readBmp( sal_Int32                                                  nWidth,
219                           sal_Int32                                                  nHeight,
220                           const rendering::IntegerBitmapLayout&                      rLayout,
221                           const uno::Reference< rendering::XIntegerReadOnlyBitmap >& xInputBitmap,
222                           ScopedBitmapWriteAccess&                                   rWriteAcc,
223                           ScopedBitmapWriteAccess&                                   rAlphaAcc )
224             {
225                 rendering::IntegerBitmapLayout      aCurrLayout;
226                 geometry::IntegerRectangle2D        aRect;
227                 uno::Sequence<sal_Int8>             aPixelData;
228                 uno::Sequence<rendering::RGBColor>  aRGBColors;
229                 uno::Sequence<rendering::ARGBColor> aARGBColors;
230 
231                 for( aRect.Y1=0; aRect.Y1<nHeight; ++aRect.Y1 )
232                 {
233                     aRect.X1 = 0; aRect.X2 = nWidth; aRect.Y2 = aRect.Y1+1;
234                     try
235                     {
236                         aPixelData = xInputBitmap->getData(aCurrLayout,aRect);
237                     }
238                     catch( rendering::VolatileContentDestroyedException& )
239                     {
240                         // re-read bmp from the start
241                         return false;
242                     }
243                     if( !(aCurrLayout == rLayout) )
244                         return false; // re-read bmp from the start
245 
246                     if( rAlphaAcc.get() )
247                     {
248                         // read ARGB color
249                         aARGBColors = rLayout.ColorSpace->convertIntegerToARGB(aPixelData);
250 
251                         if( rWriteAcc->HasPalette() )
252                         {
253                             for( sal_Int32 x=0; x<nWidth; ++x )
254                             {
255                                 const rendering::ARGBColor& rColor=aARGBColors[x];
256                                 rWriteAcc->SetPixel( aRect.Y1, x,
257                                                      (sal_uInt8)rWriteAcc->GetBestPaletteIndex(
258                                                          BitmapColor( toByteColor(rColor.Red),
259                                                                       toByteColor(rColor.Green),
260                                                                       toByteColor(rColor.Blue))) );
261                                 rAlphaAcc->SetPixel( aRect.Y1, x,
262                                                      BitmapColor( 255 - toByteColor(rColor.Alpha) ));
263                             }
264                         }
265                         else
266                         {
267                             for( sal_Int32 x=0; x<nWidth; ++x )
268                             {
269                                 const rendering::ARGBColor& rColor=aARGBColors[x];
270                                 rWriteAcc->SetPixel( aRect.Y1, x,
271                                                      BitmapColor( toByteColor(rColor.Red),
272                                                                   toByteColor(rColor.Green),
273                                                                   toByteColor(rColor.Blue) ));
274                                 rAlphaAcc->SetPixel( aRect.Y1, x,
275                                                      BitmapColor( 255 - toByteColor(rColor.Alpha) ));
276                             }
277                         }
278                     }
279                     else
280                     {
281                         // read RGB color
282                         aRGBColors = rLayout.ColorSpace->convertIntegerToRGB(aPixelData);
283                         if( rWriteAcc->HasPalette() )
284                         {
285                             for( sal_Int32 x=0; x<nWidth; ++x )
286                             {
287                                 const rendering::RGBColor& rColor=aRGBColors[x];
288                                 rWriteAcc->SetPixel( aRect.Y1, x,
289                                                      (sal_uInt8)rWriteAcc->GetBestPaletteIndex(
290                                                          BitmapColor( toByteColor(rColor.Red),
291                                                                       toByteColor(rColor.Green),
292                                                                       toByteColor(rColor.Blue))) );
293                             }
294                         }
295                         else
296                         {
297                             for( sal_Int32 x=0; x<nWidth; ++x )
298                             {
299                                 const rendering::RGBColor& rColor=aRGBColors[x];
300                                 rWriteAcc->SetPixel( aRect.Y1, x,
301                                                      BitmapColor( toByteColor(rColor.Red),
302                                                                   toByteColor(rColor.Green),
303                                                                   toByteColor(rColor.Blue) ));
304                             }
305                         }
306                     }
307                 }
308 
309                 return true;
310             }
311         }
312 
313         ::BitmapEx VCL_DLLPUBLIC bitmapExFromXBitmap( const uno::Reference< rendering::XIntegerReadOnlyBitmap >& xInputBitmap )
314         {
315             RTL_LOGFILE_CONTEXT( aLog, "::vcl::unotools::bitmapExFromXBitmap()" );
316 
317             if( !xInputBitmap.is() )
318                 return ::BitmapEx();
319 
320             // tunnel directly for known implementation
321             // ----------------------------------------------------------------
322             VclCanvasBitmap* pImplBitmap = dynamic_cast<VclCanvasBitmap*>(xInputBitmap.get());
323             if( pImplBitmap )
324                 return pImplBitmap->getBitmapEx();
325 
326             // retrieve data via UNO interface
327             // ----------------------------------------------------------------
328 
329             // volatile bitmaps are a bit more complicated to read
330             // from..
331             uno::Reference<rendering::XVolatileBitmap> xVolatileBitmap(
332                 xInputBitmap, uno::UNO_QUERY);
333 
334             // loop a few times, until successfully read (for XVolatileBitmap)
335             for( int i=0; i<10; ++i )
336             {
337                 sal_Int32 nDepth=0;
338                 sal_Int32 nAlphaDepth=0;
339                 const rendering::IntegerBitmapLayout aLayout(
340                     xInputBitmap->getMemoryLayout());
341 
342                 OSL_ENSURE(aLayout.ColorSpace.is(),
343                            "Cannot convert image without color space!");
344                 if( !aLayout.ColorSpace.is() )
345                     return ::BitmapEx();
346 
347                 nDepth = aLayout.ColorSpace->getBitsPerPixel();
348 
349                 if( xInputBitmap->hasAlpha() )
350                 {
351                     // determine alpha channel depth
352                     const uno::Sequence<sal_Int8> aTags(
353                         aLayout.ColorSpace->getComponentTags() );
354                     const uno::Sequence<sal_Int32> aDepths(
355                         aLayout.ColorSpace->getComponentBitCounts() );
356                     const sal_Int8* pStart(aTags.getConstArray());
357                     const sal_Size  nLen(aTags.getLength());
358                     const sal_Int8* pEnd(pStart+nLen);
359 
360                     const std::ptrdiff_t nAlphaIndex =
361                         std::find(pStart,pEnd,
362                                   rendering::ColorComponentTag::ALPHA) - pStart;
363 
364                     if( nAlphaIndex < sal::static_int_cast<std::ptrdiff_t>(nLen) )
365                     {
366                         nAlphaDepth = aLayout.ColorSpace->getComponentBitCounts()[nAlphaIndex] > 1 ? 8 : 1;
367                         nDepth -= nAlphaDepth;
368                     }
369                 }
370 
371                 BitmapPalette aPalette;
372                 if( aLayout.Palette.is() )
373                 {
374                     uno::Reference< rendering::XColorSpace > xPaletteColorSpace(
375                         aLayout.Palette->getColorSpace());
376                     ENSURE_OR_THROW(xPaletteColorSpace.is(),
377                                     "Palette without color space");
378 
379                     const sal_Int32 nEntryCount( aLayout.Palette->getNumberOfEntries() );
380                     if( nEntryCount <= 256 )
381                     {
382                         if( nEntryCount <= 2 )
383                             nDepth = 1;
384                         else
385                             nDepth = 8;
386 
387                         const sal_uInt16 nPaletteEntries(
388                             sal::static_int_cast<sal_uInt16>(
389                                 std::min(sal_Int32(255), nEntryCount)));
390 
391                         // copy palette entries
392                         aPalette.SetEntryCount(nPaletteEntries);
393                         uno::Reference<rendering::XBitmapPalette> xPalette( aLayout.Palette );
394                         uno::Reference<rendering::XColorSpace>    xPalColorSpace( xPalette->getColorSpace() );
395 
396                         uno::Sequence<double> aPaletteEntry;
397                         for( sal_uInt16 j=0; j<nPaletteEntries; ++j )
398                         {
399                             if( !xPalette->getIndex(aPaletteEntry,j) &&
400                                 nAlphaDepth == 0 )
401                             {
402                                 nAlphaDepth = 1;
403                             }
404                             uno::Sequence<rendering::RGBColor> aColors=xPalColorSpace->convertToRGB(aPaletteEntry);
405                             ENSURE_OR_THROW(aColors.getLength() == 1,
406                                             "Palette returned more or less than one entry");
407                             const rendering::RGBColor& rColor=aColors[0];
408                             aPalette[j] = BitmapColor(toByteColor(rColor.Red),
409                                                       toByteColor(rColor.Green),
410                                                       toByteColor(rColor.Blue));
411                         }
412                     }
413                 }
414 
415                 const ::Size aPixelSize(
416                     sizeFromIntegerSize2D(xInputBitmap->getSize()));
417 
418                 // normalize bitcount
419                 nDepth =
420                     ( nDepth <= 1 ) ? 1 :
421                     ( nDepth <= 4 ) ? 4 :
422                     ( nDepth <= 8 ) ? 8 : 24;
423 
424                 ::Bitmap aBitmap( aPixelSize,
425                                   sal::static_int_cast<sal_uInt16>(nDepth),
426                                   aLayout.Palette.is() ? &aPalette : NULL );
427                 ::Bitmap aAlpha;
428                 if( nAlphaDepth )
429                     aAlpha = ::Bitmap( aPixelSize,
430                                        sal::static_int_cast<sal_uInt16>(nAlphaDepth),
431                                        &::Bitmap::GetGreyPalette(
432                                            sal::static_int_cast<sal_uInt16>(1L << nAlphaDepth)) );
433 
434                 { // limit scoped access
435                     ScopedBitmapWriteAccess pWriteAccess( aBitmap.AcquireWriteAccess(),
436                                                           aBitmap );
437                     ScopedBitmapWriteAccess pAlphaWriteAccess( nAlphaDepth ? aAlpha.AcquireWriteAccess() : NULL,
438                                                                aAlpha );
439 
440                     ENSURE_OR_THROW(pWriteAccess.get() != NULL,
441                                     "Cannot get write access to bitmap");
442 
443                     const sal_Int32 nWidth(aPixelSize.Width());
444                     const sal_Int32 nHeight(aPixelSize.Height());
445 
446                     if( !readBmp(nWidth,nHeight,aLayout,xInputBitmap,
447                                  pWriteAccess,pAlphaWriteAccess) )
448                         continue;
449                 } // limit scoped access
450 
451                 if( nAlphaDepth )
452                     return ::BitmapEx( aBitmap,
453                                        AlphaMask( aAlpha ) );
454                 else
455                     return ::BitmapEx( aBitmap );
456             }
457 
458             // failed to read data 10 times - bail out
459             return ::BitmapEx();
460         }
461 
462         //---------------------------------------------------------------------------------------
463 
464         geometry::RealSize2D size2DFromSize( const Size& rSize )
465         {
466             return geometry::RealSize2D( rSize.Width(),
467                                          rSize.Height() );
468         }
469 
470         geometry::RealPoint2D point2DFromPoint( const Point& rPoint )
471         {
472             return geometry::RealPoint2D( rPoint.X(),
473                                           rPoint.Y() );
474         }
475 
476         geometry::RealRectangle2D rectangle2DFromRectangle( const Rectangle& rRect )
477         {
478             return geometry::RealRectangle2D( rRect.Left(), rRect.Top(),
479                                               rRect.Right(), rRect.Bottom() );
480         }
481 
482         Size sizeFromRealSize2D( const geometry::RealSize2D& rSize )
483         {
484             return Size( static_cast<long>(rSize.Width + .5),
485                          static_cast<long>(rSize.Height + .5) );
486         }
487 
488         Point pointFromRealPoint2D( const geometry::RealPoint2D& rPoint )
489         {
490             return Point( static_cast<long>(rPoint.X + .5),
491                           static_cast<long>(rPoint.Y + .5) );
492         }
493 
494         Rectangle rectangleFromRealRectangle2D( const geometry::RealRectangle2D& rRect )
495         {
496             return Rectangle( static_cast<long>(rRect.X1 + .5),
497                               static_cast<long>(rRect.Y1 + .5),
498                               static_cast<long>(rRect.X2 + .5),
499                               static_cast<long>(rRect.Y2 + .5) );
500         }
501 
502         ::Size sizeFromB2DSize( const ::basegfx::B2DVector& rVec )
503         {
504             return ::Size( FRound( rVec.getX() ),
505                            FRound( rVec.getY() ) );
506         }
507 
508         ::Point pointFromB2DPoint( const ::basegfx::B2DPoint& rPoint )
509         {
510             return ::Point( FRound( rPoint.getX() ),
511                             FRound( rPoint.getY() ) );
512         }
513 
514         ::Rectangle rectangleFromB2DRectangle( const ::basegfx::B2DRange& rRect )
515         {
516             return ::Rectangle( FRound( rRect.getMinX() ),
517                                 FRound( rRect.getMinY() ),
518                                 FRound( rRect.getMaxX() ),
519                                 FRound( rRect.getMaxY() ) );
520         }
521 
522         Size sizeFromB2ISize( const ::basegfx::B2IVector& rVec )
523         {
524             return ::Size( rVec.getX(),
525                            rVec.getY() );
526         }
527 
528         Point pointFromB2IPoint( const ::basegfx::B2IPoint& rPoint )
529         {
530             return ::Point( rPoint.getX(),
531                             rPoint.getY() );
532         }
533 
534         Rectangle rectangleFromB2IRectangle( const ::basegfx::B2IRange& rRect )
535         {
536             return ::Rectangle( rRect.getMinX(),
537                                 rRect.getMinY(),
538                                 rRect.getMaxX(),
539                                 rRect.getMaxY() );
540         }
541 
542         ::basegfx::B2DVector b2DSizeFromSize( const ::Size& rSize )
543         {
544             return ::basegfx::B2DVector( rSize.Width(),
545                                          rSize.Height() );
546         }
547 
548         ::basegfx::B2DPoint b2DPointFromPoint( const ::Point& rPoint )
549         {
550             return ::basegfx::B2DPoint( rPoint.X(),
551                                         rPoint.Y() );
552         }
553 
554         ::basegfx::B2DRange b2DRectangleFromRectangle( const ::Rectangle& rRect )
555         {
556             return ::basegfx::B2DRange( rRect.Left(),
557                                         rRect.Top(),
558                                         rRect.Right(),
559                                         rRect.Bottom() );
560         }
561 
562         basegfx::B2IVector b2ISizeFromSize( const Size& rSize )
563         {
564             return ::basegfx::B2IVector( rSize.Width(),
565                                          rSize.Height() );
566         }
567 
568         basegfx::B2IPoint b2IPointFromPoint( const Point& rPoint )
569         {
570             return ::basegfx::B2IPoint( rPoint.X(),
571                                         rPoint.Y() );
572         }
573 
574         basegfx::B2IRange b2IRectangleFromRectangle( const Rectangle& rRect )
575         {
576             return ::basegfx::B2IRange( rRect.Left(),
577                                         rRect.Top(),
578                                         rRect.Right(),
579                                         rRect.Bottom() );
580         }
581 
582         geometry::IntegerSize2D integerSize2DFromSize( const Size& rSize )
583         {
584             return geometry::IntegerSize2D( rSize.Width(),
585                                             rSize.Height() );
586         }
587 
588         geometry::IntegerPoint2D integerPoint2DFromPoint( const Point& rPoint )
589         {
590             return geometry::IntegerPoint2D( rPoint.X(),
591                                              rPoint.Y() );
592         }
593 
594         geometry::IntegerRectangle2D integerRectangle2DFromRectangle( const Rectangle& rRectangle )
595         {
596             return geometry::IntegerRectangle2D( rRectangle.Left(), rRectangle.Top(),
597                                                  rRectangle.Right(), rRectangle.Bottom() );
598         }
599 
600         Size sizeFromIntegerSize2D( const geometry::IntegerSize2D& rSize )
601         {
602             return Size( rSize.Width,
603                          rSize.Height );
604         }
605 
606         Point pointFromIntegerPoint2D( const geometry::IntegerPoint2D& rPoint )
607         {
608             return Point( rPoint.X,
609                           rPoint.Y );
610         }
611 
612         Rectangle rectangleFromIntegerRectangle2D( const geometry::IntegerRectangle2D& rRectangle )
613         {
614             return Rectangle( rRectangle.X1, rRectangle.Y1,
615                               rRectangle.X2, rRectangle.Y2 );
616         }
617 
618         namespace
619         {
620             class StandardColorSpace : public cppu::WeakImplHelper1< com::sun::star::rendering::XColorSpace >
621             {
622             private:
623                 uno::Sequence< sal_Int8 > m_aComponentTags;
624 
625                 virtual ::sal_Int8 SAL_CALL getType(  ) throw (uno::RuntimeException)
626                 {
627                     return rendering::ColorSpaceType::RGB;
628                 }
629                 virtual uno::Sequence< ::sal_Int8 > SAL_CALL getComponentTags(  ) throw (uno::RuntimeException)
630                 {
631                     return m_aComponentTags;
632                 }
633                 virtual ::sal_Int8 SAL_CALL getRenderingIntent(  ) throw (uno::RuntimeException)
634                 {
635                     return rendering::RenderingIntent::PERCEPTUAL;
636                 }
637                 virtual uno::Sequence< beans::PropertyValue > SAL_CALL getProperties(  ) throw (uno::RuntimeException)
638                 {
639                     return uno::Sequence< beans::PropertyValue >();
640                 }
641                 virtual uno::Sequence< double > SAL_CALL convertColorSpace( const uno::Sequence< double >& deviceColor,
642                                                                             const uno::Reference< rendering::XColorSpace >& targetColorSpace ) throw (lang::IllegalArgumentException,
643                                                                                                                                                       uno::RuntimeException)
644                 {
645                     // TODO(P3): if we know anything about target
646                     // colorspace, this can be greatly sped up
647                     uno::Sequence<rendering::ARGBColor> aIntermediate(
648                         convertToARGB(deviceColor));
649                     return targetColorSpace->convertFromARGB(aIntermediate);
650                 }
651                 virtual uno::Sequence< rendering::RGBColor > SAL_CALL convertToRGB( const uno::Sequence< double >& deviceColor ) throw (lang::IllegalArgumentException, uno::RuntimeException)
652                 {
653                     const double*  pIn( deviceColor.getConstArray() );
654                     const sal_Size nLen( deviceColor.getLength() );
655                     ENSURE_ARG_OR_THROW2(nLen%4==0,
656                                          "number of channels no multiple of 4",
657                                          static_cast<rendering::XColorSpace*>(this), 0);
658 
659                     uno::Sequence< rendering::RGBColor > aRes(nLen/4);
660                     rendering::RGBColor* pOut( aRes.getArray() );
661                     for( sal_Size i=0; i<nLen; i+=4 )
662                     {
663                         *pOut++ = rendering::RGBColor(pIn[0],pIn[1],pIn[2]);
664                         pIn += 4;
665                     }
666                     return aRes;
667                 }
668                 virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertToARGB( const uno::Sequence< double >& deviceColor ) throw (lang::IllegalArgumentException, uno::RuntimeException)
669                 {
670                     const double*  pIn( deviceColor.getConstArray() );
671                     const sal_Size nLen( deviceColor.getLength() );
672                     ENSURE_ARG_OR_THROW2(nLen%4==0,
673                                          "number of channels no multiple of 4",
674                                          static_cast<rendering::XColorSpace*>(this), 0);
675 
676                     uno::Sequence< rendering::ARGBColor > aRes(nLen/4);
677                     rendering::ARGBColor* pOut( aRes.getArray() );
678                     for( sal_Size i=0; i<nLen; i+=4 )
679                     {
680                         *pOut++ = rendering::ARGBColor(pIn[3],pIn[0],pIn[1],pIn[2]);
681                         pIn += 4;
682                     }
683                     return aRes;
684                 }
685                 virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertToPARGB( const uno::Sequence< double >& deviceColor ) throw (lang::IllegalArgumentException, uno::RuntimeException)
686                 {
687                     const double*  pIn( deviceColor.getConstArray() );
688                     const sal_Size nLen( deviceColor.getLength() );
689                     ENSURE_ARG_OR_THROW2(nLen%4==0,
690                                          "number of channels no multiple of 4",
691                                          static_cast<rendering::XColorSpace*>(this), 0);
692 
693                     uno::Sequence< rendering::ARGBColor > aRes(nLen/4);
694                     rendering::ARGBColor* pOut( aRes.getArray() );
695                     for( sal_Size i=0; i<nLen; i+=4 )
696                     {
697                         *pOut++ = rendering::ARGBColor(pIn[3],pIn[3]*pIn[0],pIn[3]*pIn[1],pIn[3]*pIn[2]);
698                         pIn += 4;
699                     }
700                     return aRes;
701                 }
702                 virtual uno::Sequence< double > SAL_CALL convertFromRGB( const uno::Sequence< rendering::RGBColor >& rgbColor ) throw (lang::IllegalArgumentException, uno::RuntimeException)
703                 {
704                     const rendering::RGBColor* pIn( rgbColor.getConstArray() );
705                     const sal_Size             nLen( rgbColor.getLength() );
706 
707                     uno::Sequence< double > aRes(nLen*4);
708                     double* pColors=aRes.getArray();
709                     for( sal_Size i=0; i<nLen; ++i )
710                     {
711                         *pColors++ = pIn->Red;
712                         *pColors++ = pIn->Green;
713                         *pColors++ = pIn->Blue;
714                         *pColors++ = 1.0;
715                         ++pIn;
716                     }
717                     return aRes;
718                 }
719                 virtual uno::Sequence< double > SAL_CALL convertFromARGB( const uno::Sequence< rendering::ARGBColor >& rgbColor ) throw (lang::IllegalArgumentException, uno::RuntimeException)
720                 {
721                     const rendering::ARGBColor* pIn( rgbColor.getConstArray() );
722                     const sal_Size              nLen( rgbColor.getLength() );
723 
724                     uno::Sequence< double > aRes(nLen*4);
725                     double* pColors=aRes.getArray();
726                     for( sal_Size i=0; i<nLen; ++i )
727                     {
728                         *pColors++ = pIn->Red;
729                         *pColors++ = pIn->Green;
730                         *pColors++ = pIn->Blue;
731                         *pColors++ = pIn->Alpha;
732                         ++pIn;
733                     }
734                     return aRes;
735                 }
736                 virtual uno::Sequence< double > SAL_CALL convertFromPARGB( const uno::Sequence< rendering::ARGBColor >& rgbColor ) throw (lang::IllegalArgumentException, uno::RuntimeException)
737                 {
738                     const rendering::ARGBColor* pIn( rgbColor.getConstArray() );
739                     const sal_Size              nLen( rgbColor.getLength() );
740 
741                     uno::Sequence< double > aRes(nLen*4);
742                     double* pColors=aRes.getArray();
743                     for( sal_Size i=0; i<nLen; ++i )
744                     {
745                         *pColors++ = pIn->Red/pIn->Alpha;
746                         *pColors++ = pIn->Green/pIn->Alpha;
747                         *pColors++ = pIn->Blue/pIn->Alpha;
748                         *pColors++ = pIn->Alpha;
749                         ++pIn;
750                     }
751                     return aRes;
752                 }
753 
754             public:
755                 StandardColorSpace() : m_aComponentTags(4)
756                 {
757                     sal_Int8* pTags = m_aComponentTags.getArray();
758                     pTags[0] = rendering::ColorComponentTag::RGB_RED;
759                     pTags[1] = rendering::ColorComponentTag::RGB_GREEN;
760                     pTags[2] = rendering::ColorComponentTag::RGB_BLUE;
761                     pTags[3] = rendering::ColorComponentTag::ALPHA;
762                 }
763             };
764         }
765 
766         uno::Reference<rendering::XColorSpace> VCL_DLLPUBLIC createStandardColorSpace()
767         {
768             return new StandardColorSpace();
769         }
770 
771         //---------------------------------------------------------------------------------------
772 
773         uno::Sequence< double > colorToStdColorSpaceSequence( const Color& rColor )
774         {
775             uno::Sequence< double > aRet(4);
776             double* pRet = aRet.getArray();
777 
778             pRet[0] = toDoubleColor(rColor.GetRed());
779             pRet[1] = toDoubleColor(rColor.GetGreen());
780             pRet[2] = toDoubleColor(rColor.GetBlue());
781 
782             // VCL's notion of alpha is different from the rest of the world's
783             pRet[3] = 1.0 - toDoubleColor(rColor.GetTransparency());
784 
785             return aRet;
786         }
787 
788         Color stdColorSpaceSequenceToColor( const uno::Sequence< double >& rColor		 )
789         {
790             ENSURE_ARG_OR_THROW( rColor.getLength() == 4,
791                                  "color must have 4 channels" );
792 
793             Color aColor;
794 
795             aColor.SetRed  ( toByteColor(rColor[0]) );
796             aColor.SetGreen( toByteColor(rColor[1]) );
797             aColor.SetBlue ( toByteColor(rColor[2]) );
798             // VCL's notion of alpha is different from the rest of the world's
799             aColor.SetTransparency( 255 - toByteColor(rColor[3]) );
800 
801             return aColor;
802         }
803 
804         uno::Sequence< double > VCL_DLLPUBLIC colorToDoubleSequence(
805             const Color&                                    rColor,
806             const uno::Reference< rendering::XColorSpace >& xColorSpace )
807         {
808             uno::Sequence<rendering::ARGBColor> aSeq(1);
809             aSeq[0] = rendering::ARGBColor(
810                     1.0-toDoubleColor(rColor.GetTransparency()),
811                     toDoubleColor(rColor.GetRed()),
812                     toDoubleColor(rColor.GetGreen()),
813                     toDoubleColor(rColor.GetBlue()) );
814 
815             return xColorSpace->convertFromARGB(aSeq);
816         }
817 
818         Color VCL_DLLPUBLIC doubleSequenceToColor(
819             const uno::Sequence< double >                   rColor,
820             const uno::Reference< rendering::XColorSpace >& xColorSpace )
821         {
822             const rendering::ARGBColor& rARGBColor(
823                 xColorSpace->convertToARGB(rColor)[0]);
824 
825             return Color( 255-toByteColor(rARGBColor.Alpha),
826                           toByteColor(rARGBColor.Red),
827                           toByteColor(rARGBColor.Green),
828                           toByteColor(rARGBColor.Blue) );
829         }
830 
831         //---------------------------------------------------------------------------------------
832 
833     } // namespace vcltools
834 
835 } // namespace canvas
836 
837 // eof
838