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