1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: salbmp.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_vcl.hxx"
34 #include "tools/color.hxx"
36 #include "vcl/bitmap.hxx" // for BitmapSystemData
37 #include "vcl/salbtype.hxx"
38 #include "vcl/bmpfast.hxx"
40 #include "basebmp/scanlineformats.hxx"
41 #include "basebmp/color.hxx"
42 #include "basegfx/vector/b2ivector.hxx"
44 #include <boost/bind.hpp>
48 // =======================================================================
50 static bool isValidBitCount( sal_uInt16 nBitCount
)
52 return (nBitCount
== 1) || (nBitCount
== 4) || (nBitCount
== 8) || (nBitCount
== 16) || (nBitCount
== 24) || (nBitCount
== 32);
55 // =======================================================================
57 AquaSalBitmap::AquaSalBitmap()
58 : mxGraphicContext( NULL
)
59 , mxCachedImage( NULL
)
67 // ------------------------------------------------------------------
69 AquaSalBitmap::~AquaSalBitmap()
74 // ------------------------------------------------------------------
76 bool AquaSalBitmap::Create( CGLayerRef xLayer
, int nBitmapBits
,
77 int nX
, int nY
, int nWidth
, int nHeight
, bool /*bMirrorVert*/ )
79 DBG_ASSERT( xLayer
, "AquaSalBitmap::Create() from non-layered context" );
81 // sanitize input parameters
85 nHeight
+= nY
, nY
= 0;
86 const CGSize aLayerSize
= CGLayerGetSize( xLayer
);
87 if( nWidth
>= (int)aLayerSize
.width
- nX
)
88 nWidth
= (int)aLayerSize
.width
- nX
;
89 if( nHeight
>= (int)aLayerSize
.height
- nY
)
90 nHeight
= (int)aLayerSize
.height
- nY
;
91 if( (nWidth
< 0) || (nHeight
< 0) )
94 // initialize properties
97 mnBits
= nBitmapBits
? nBitmapBits
: 32;
99 // initialize drawing context
102 // copy layer content into the bitmap buffer
103 const CGPoint aSrcPoint
= { -nX
, -nY
};
104 ::CGContextDrawLayerAtPoint( mxGraphicContext
, aSrcPoint
, xLayer
);
108 // ------------------------------------------------------------------
110 bool AquaSalBitmap::Create( const Size
& rSize
, USHORT nBits
, const BitmapPalette
& rBitmapPalette
)
112 if( !isValidBitCount( nBits
) )
114 maPalette
= rBitmapPalette
;
116 mnWidth
= rSize
.Width();
117 mnHeight
= rSize
.Height();
118 return AllocateUserData();
121 // ------------------------------------------------------------------
123 bool AquaSalBitmap::Create( const SalBitmap
& rSalBmp
)
125 return Create( rSalBmp
, rSalBmp
.GetBitCount() );
128 // ------------------------------------------------------------------
130 bool AquaSalBitmap::Create( const SalBitmap
& rSalBmp
, SalGraphics
* pGraphics
)
132 return Create( rSalBmp
, pGraphics
? pGraphics
->GetBitCount() : rSalBmp
.GetBitCount() );
135 // ------------------------------------------------------------------
137 bool AquaSalBitmap::Create( const SalBitmap
& rSalBmp
, USHORT nNewBitCount
)
139 const AquaSalBitmap
& rSourceBitmap
= static_cast<const AquaSalBitmap
&>(rSalBmp
);
141 if( isValidBitCount( nNewBitCount
) && rSourceBitmap
.maUserBuffer
.get() )
143 mnBits
= nNewBitCount
;
144 mnWidth
= rSourceBitmap
.mnWidth
;
145 mnHeight
= rSourceBitmap
.mnHeight
;
146 maPalette
= rSourceBitmap
.maPalette
;
148 if( AllocateUserData() )
150 ConvertBitmapData( mnWidth
, mnHeight
, mnBits
, mnBytesPerRow
, maPalette
, maUserBuffer
.get(), rSourceBitmap
.mnBits
, rSourceBitmap
.mnBytesPerRow
, rSourceBitmap
.maPalette
, rSourceBitmap
.maUserBuffer
.get() );
157 // ------------------------------------------------------------------
159 bool AquaSalBitmap::Create( const ::com::sun::star::uno::Reference
< ::com::sun::star::rendering::XBitmapCanvas
> /*xBitmapCanvas*/, Size
& /*rSize*/, bool /*bMask*/ )
164 // ------------------------------------------------------------------
166 void AquaSalBitmap::Destroy()
169 maUserBuffer
.reset();
172 // ------------------------------------------------------------------
174 void AquaSalBitmap::DestroyContext()
176 CGImageRelease( mxCachedImage
);
177 mxCachedImage
= NULL
;
179 if( mxGraphicContext
)
181 CGContextRelease( mxGraphicContext
);
182 mxGraphicContext
= NULL
;
183 maContextBuffer
.reset();
187 // ------------------------------------------------------------------
189 bool AquaSalBitmap::CreateContext()
193 // prepare graphics context
194 // convert image from user input if available
195 const bool bSkipConversion
= !maUserBuffer
;
196 if( bSkipConversion
)
199 // default to RGBA color space
200 CGColorSpaceRef aCGColorSpace
= GetSalData()->mxRGBSpace
;
201 CGBitmapInfo aCGBmpInfo
= kCGImageAlphaNoneSkipFirst
;
203 // convert data into something accepted by CGBitmapContextCreate()
204 size_t bitsPerComponent
= (mnBits
== 16) ? 5 : 8;
205 sal_uInt32 nContextBytesPerRow
= mnBytesPerRow
;
206 if( (mnBits
== 16) || (mnBits
== 32) )
208 // no conversion needed for truecolor
209 maContextBuffer
= maUserBuffer
;
211 else if( (mnBits
== 8) && maPalette
.IsGreyPalette() )
213 // no conversion needed for grayscale
214 maContextBuffer
= maUserBuffer
;
215 aCGColorSpace
= GetSalData()->mxGraySpace
;
216 aCGBmpInfo
= kCGImageAlphaNone
;
217 bitsPerComponent
= mnBits
;
219 // TODO: is special handling for 1bit input buffers worth it?
222 // convert user data to 32 bit
223 nContextBytesPerRow
= mnWidth
<< 2;
226 maContextBuffer
.reset( new sal_uInt8
[ mnHeight
* nContextBytesPerRow
] );
228 if( !bSkipConversion
)
229 ConvertBitmapData( mnWidth
, mnHeight
,
230 32, nContextBytesPerRow
, maPalette
, maContextBuffer
.get(),
231 mnBits
, mnBytesPerRow
, maPalette
, maUserBuffer
.get() );
233 catch( std::bad_alloc
)
235 mxGraphicContext
= 0;
239 if( maContextBuffer
.get() )
241 mxGraphicContext
= ::CGBitmapContextCreate( maContextBuffer
.get(), mnWidth
, mnHeight
,
242 bitsPerComponent
, nContextBytesPerRow
, aCGColorSpace
, aCGBmpInfo
);
245 if( !mxGraphicContext
)
246 maContextBuffer
.reset();
248 return mxGraphicContext
!= NULL
;
251 // ------------------------------------------------------------------
253 bool AquaSalBitmap::AllocateUserData()
257 if( mnWidth
&& mnHeight
)
263 case 1: mnBytesPerRow
= (mnWidth
+ 7) >> 3; break;
264 case 4: mnBytesPerRow
= (mnWidth
+ 1) >> 1; break;
265 case 8: mnBytesPerRow
= mnWidth
; break;
266 case 16: mnBytesPerRow
= mnWidth
<< 1; break;
267 case 24: mnBytesPerRow
= (mnWidth
<< 1) + mnWidth
; break;
268 case 32: mnBytesPerRow
= mnWidth
<< 2; break;
270 DBG_ERROR("vcl::AquaSalBitmap::AllocateUserData(), illegal bitcount!");
277 maUserBuffer
.reset( new sal_uInt8
[mnBytesPerRow
* mnHeight
] );
279 catch( const std::bad_alloc
& )
281 DBG_ERROR( "vcl::AquaSalBitmap::AllocateUserData: bad alloc" );
282 maUserBuffer
.reset( NULL
);
286 return maUserBuffer
.get() != 0;
289 // ------------------------------------------------------------------
291 class ImplPixelFormat
296 static ImplPixelFormat
* GetFormat( sal_uInt16 nBits
, const BitmapPalette
& rPalette
);
298 virtual void StartLine( sal_uInt8
* pLine
) { pData
= pLine
; }
299 virtual void SkipPixel( sal_uInt32 nPixel
) = 0;
300 virtual ColorData
ReadPixel() = 0;
301 virtual void WritePixel( ColorData nColor
) = 0;
304 class ImplPixelFormat32
: public ImplPixelFormat
305 // currently ARGB-format for 32bit depth
308 virtual void SkipPixel( sal_uInt32 nPixel
)
310 pData
+= nPixel
<< 2;
312 virtual ColorData
ReadPixel()
314 const ColorData c
= RGB_COLORDATA( pData
[1], pData
[2], pData
[3] );
318 virtual void WritePixel( ColorData nColor
)
321 *pData
++ = COLORDATA_RED( nColor
);
322 *pData
++ = COLORDATA_GREEN( nColor
);
323 *pData
++ = COLORDATA_BLUE( nColor
);
327 class ImplPixelFormat24
: public ImplPixelFormat
328 // currently BGR-format for 24bit depth
331 virtual void SkipPixel( sal_uInt32 nPixel
)
333 pData
+= (nPixel
<< 1) + nPixel
;
335 virtual ColorData
ReadPixel()
337 const ColorData c
= RGB_COLORDATA( pData
[2], pData
[1], pData
[0] );
341 virtual void WritePixel( ColorData nColor
)
343 *pData
++ = COLORDATA_BLUE( nColor
);
344 *pData
++ = COLORDATA_GREEN( nColor
);
345 *pData
++ = COLORDATA_RED( nColor
);
349 class ImplPixelFormat16
: public ImplPixelFormat
350 // currently R5G6B5-format for 16bit depth
356 virtual void StartLine( sal_uInt8
* pLine
)
358 pData16
= (sal_uInt16
*)pLine
;
360 virtual void SkipPixel( sal_uInt32 nPixel
)
364 virtual ColorData
ReadPixel()
366 const ColorData c
= RGB_COLORDATA( (*pData
& 0x7c00) >> 7, (*pData
& 0x03e0) >> 2 , (*pData
& 0x001f) << 3 );
370 virtual void WritePixel( ColorData nColor
)
372 *pData
++ = ((COLORDATA_RED( nColor
) & 0xf8 ) << 7 ) ||
373 ((COLORDATA_GREEN( nColor
) & 0xf8 ) << 2 ) ||
374 ((COLORDATA_BLUE( nColor
) & 0xf8 ) >> 3 );
378 class ImplPixelFormat8
: public ImplPixelFormat
381 const BitmapPalette
& mrPalette
;
384 ImplPixelFormat8( const BitmapPalette
& rPalette
)
385 : mrPalette( rPalette
)
388 virtual void SkipPixel( sal_uInt32 nPixel
)
392 virtual ColorData
ReadPixel()
394 return mrPalette
[ *pData
++ ].operator Color().GetColor();
396 virtual void WritePixel( ColorData nColor
)
398 const BitmapColor
aColor( COLORDATA_RED( nColor
), COLORDATA_GREEN( nColor
), COLORDATA_BLUE( nColor
) );
399 *pData
++ = static_cast< sal_uInt8
>( mrPalette
.GetBestIndex( aColor
) );
403 class ImplPixelFormat4
: public ImplPixelFormat
406 const BitmapPalette
& mrPalette
;
411 ImplPixelFormat4( const BitmapPalette
& rPalette
)
412 : mrPalette( rPalette
)
415 virtual void SkipPixel( sal_uInt32 nPixel
)
421 virtual void StartLine( sal_uInt8
* pLine
)
427 virtual ColorData
ReadPixel()
429 const BitmapColor
& rColor
= mrPalette
[( pData
[mnX
>> 1] >> mnShift
) & 0x0f];
432 return rColor
.operator Color().GetColor();
434 virtual void WritePixel( ColorData nColor
)
436 const BitmapColor
aColor( COLORDATA_RED( nColor
), COLORDATA_GREEN( nColor
), COLORDATA_BLUE( nColor
) );
437 pData
[mnX
>>1] &= (0xf0 >> mnShift
);
438 pData
[mnX
>>1] |= (static_cast< sal_uInt8
>( mrPalette
.GetBestIndex( aColor
) ) & 0x0f);
444 class ImplPixelFormat1
: public ImplPixelFormat
447 const BitmapPalette
& mrPalette
;
451 ImplPixelFormat1( const BitmapPalette
& rPalette
)
452 : mrPalette( rPalette
)
455 virtual void SkipPixel( sal_uInt32 nPixel
)
459 virtual void StartLine( sal_uInt8
* pLine
)
464 virtual ColorData
ReadPixel()
466 const BitmapColor
& rColor
= mrPalette
[ (pData
[mnX
>> 3 ] >> ( 7 - ( mnX
& 7 ) )) & 1];
468 return rColor
.operator Color().GetColor();
470 virtual void WritePixel( ColorData nColor
)
472 const BitmapColor
aColor( COLORDATA_RED( nColor
), COLORDATA_GREEN( nColor
), COLORDATA_BLUE( nColor
) );
473 if( mrPalette
.GetBestIndex( aColor
) & 1 )
474 pData
[ mnX
>> 3 ] |= 1 << ( 7 - ( mnX
& 7 ) );
476 pData
[ mnX
>> 3 ] &= ~( 1 << ( 7 - ( mnX
& 7 ) ) );
481 ImplPixelFormat
* ImplPixelFormat::GetFormat( sal_uInt16 nBits
, const BitmapPalette
& rPalette
)
485 case 1: return new ImplPixelFormat1( rPalette
);
486 case 4: return new ImplPixelFormat4( rPalette
);
487 case 8: return new ImplPixelFormat8( rPalette
);
488 case 16: return new ImplPixelFormat16
;
489 case 24: return new ImplPixelFormat24
;
490 case 32: return new ImplPixelFormat32
;
496 void AquaSalBitmap::ConvertBitmapData( sal_uInt32 nWidth
, sal_uInt32 nHeight
,
497 sal_uInt16 nDestBits
, sal_uInt32 nDestBytesPerRow
, const BitmapPalette
& rDestPalette
, sal_uInt8
* pDestData
,
498 sal_uInt16 nSrcBits
, sal_uInt32 nSrcBytesPerRow
, const BitmapPalette
& rSrcPalette
, sal_uInt8
* pSrcData
)
501 if( (nDestBytesPerRow
== nSrcBytesPerRow
) && (nDestBits
== nSrcBits
) && ((nSrcBits
!= 8) || (rDestPalette
.operator==( rSrcPalette
))) )
503 // simple case, same format, so just copy
504 memcpy( pDestData
, pSrcData
, nHeight
* nDestBytesPerRow
);
508 // try accelerated conversion if possible
509 // TODO: are other truecolor conversions except BGR->ARGB worth it?
510 bool bConverted
= false;
511 if( (nSrcBits
== 24) && (nDestBits
== 32) )
513 // TODO: extend bmpfast.cxx with a method that can be directly used here
514 BitmapBuffer aSrcBuf
;
515 aSrcBuf
.mnFormat
= BMP_FORMAT_24BIT_TC_BGR
;
516 aSrcBuf
.mpBits
= pSrcData
;
517 aSrcBuf
.mnBitCount
= nSrcBits
;
518 aSrcBuf
.mnScanlineSize
= nSrcBytesPerRow
;
519 BitmapBuffer aDstBuf
;
520 aDstBuf
.mnFormat
= BMP_FORMAT_32BIT_TC_ARGB
;
521 aDstBuf
.mpBits
= pDestData
;
522 aSrcBuf
.mnBitCount
= nDestBits
;
523 aDstBuf
.mnScanlineSize
= nDestBytesPerRow
;
525 aSrcBuf
.mnWidth
= aDstBuf
.mnWidth
= nWidth
;
526 aSrcBuf
.mnHeight
= aDstBuf
.mnHeight
= nHeight
;
528 SalTwoRect aTwoRects
;
529 aTwoRects
.mnSrcX
= aTwoRects
.mnDestX
= 0;
530 aTwoRects
.mnSrcY
= aTwoRects
.mnDestY
= 0;
531 aTwoRects
.mnSrcWidth
= aTwoRects
.mnDestWidth
= mnWidth
;
532 aTwoRects
.mnSrcHeight
= aTwoRects
.mnDestHeight
= mnHeight
;
533 bConverted
= ::ImplFastBitmapConversion( aDstBuf
, aSrcBuf
, aTwoRects
);
538 // TODO: this implementation is for clarety, not for speed
540 ImplPixelFormat
* pD
= ImplPixelFormat::GetFormat( nDestBits
, rDestPalette
);
541 ImplPixelFormat
* pS
= ImplPixelFormat::GetFormat( nSrcBits
, rSrcPalette
);
545 sal_uInt32 nY
= nHeight
;
548 pD
->StartLine( pDestData
);
549 pS
->StartLine( pSrcData
);
551 sal_uInt32 nX
= nWidth
;
553 pD
->WritePixel( pS
->ReadPixel() );
555 pSrcData
+= nSrcBytesPerRow
;
556 pDestData
+= nDestBytesPerRow
;
564 // ------------------------------------------------------------------
566 Size
AquaSalBitmap::GetSize() const
568 return Size( mnWidth
, mnHeight
);
571 // ------------------------------------------------------------------
573 USHORT
AquaSalBitmap::GetBitCount() const
578 // ------------------------------------------------------------------
580 static struct pal_entry
586 const aImplSalSysPalEntryAry
[ 16 ] =
595 { 0x80, 0x80, 0x80 },
596 { 0xC0, 0xC0, 0xC0 },
606 const BitmapPalette
& GetDefaultPalette( int mnBits
, bool bMonochrome
)
609 return Bitmap::GetGreyPalette( 1U << mnBits
);
611 // at this point we should provide some kind of default palette
612 // since all other platforms do so, too.
613 static bool bDefPalInit
= false;
614 static BitmapPalette aDefPalette256
;
615 static BitmapPalette aDefPalette16
;
616 static BitmapPalette aDefPalette2
;
620 aDefPalette256
.SetEntryCount( 256 );
621 aDefPalette16
.SetEntryCount( 16 );
622 aDefPalette2
.SetEntryCount( 2 );
626 for( i
= 0; i
< 16; i
++ )
629 aDefPalette256
[i
] = BitmapColor( aImplSalSysPalEntryAry
[i
].mnRed
,
630 aImplSalSysPalEntryAry
[i
].mnGreen
,
631 aImplSalSysPalEntryAry
[i
].mnBlue
);
634 aDefPalette2
[0] = BitmapColor( 0, 0, 0 );
635 aDefPalette2
[1] = BitmapColor( 0xff, 0xff, 0xff );
637 // own palette (6/6/6)
638 const int DITHER_PAL_STEPS
= 6;
639 const BYTE DITHER_PAL_DELTA
= 51;
641 BYTE nRed
, nGreen
, nBlue
;
642 for( nB
=0, nBlue
=0; nB
< DITHER_PAL_STEPS
; nB
++, nBlue
+= DITHER_PAL_DELTA
)
644 for( nG
=0, nGreen
=0; nG
< DITHER_PAL_STEPS
; nG
++, nGreen
+= DITHER_PAL_DELTA
)
646 for( nR
=0, nRed
=0; nR
< DITHER_PAL_STEPS
; nR
++, nRed
+= DITHER_PAL_DELTA
)
648 aDefPalette256
[ i
] = BitmapColor( nRed
, nGreen
, nBlue
);
655 // now fill in appropriate palette
658 case 1: return aDefPalette2
;
659 case 4: return aDefPalette16
;
660 case 8: return aDefPalette256
;
664 const static BitmapPalette aEmptyPalette
;
665 return aEmptyPalette
;
668 BitmapBuffer
* AquaSalBitmap::AcquireBuffer( bool bReadOnly
)
670 if( !maUserBuffer
.get() )
671 // || maContextBuffer.get() && (maUserBuffer.get() != maContextBuffer.get()) )
673 fprintf(stderr
,"ASB::Acq(%dx%d,d=%d)\n",mnWidth
,mnHeight
,mnBits
);
674 // TODO: AllocateUserData();
678 BitmapBuffer
* pBuffer
= new BitmapBuffer
;
679 pBuffer
->mnWidth
= mnWidth
;
680 pBuffer
->mnHeight
= mnHeight
;
681 pBuffer
->maPalette
= maPalette
;
682 pBuffer
->mnScanlineSize
= mnBytesPerRow
;
683 pBuffer
->mpBits
= maUserBuffer
.get();
684 pBuffer
->mnBitCount
= mnBits
;
687 case 1: pBuffer
->mnFormat
= BMP_FORMAT_1BIT_MSB_PAL
; break;
688 case 4: pBuffer
->mnFormat
= BMP_FORMAT_4BIT_MSN_PAL
; break;
689 case 8: pBuffer
->mnFormat
= BMP_FORMAT_8BIT_PAL
; break;
690 case 16: pBuffer
->mnFormat
= BMP_FORMAT_16BIT_TC_MSB_MASK
;
691 pBuffer
->maColorMask
= ColorMask( k16BitRedColorMask
, k16BitGreenColorMask
, k16BitBlueColorMask
);
693 case 24: pBuffer
->mnFormat
= BMP_FORMAT_24BIT_TC_BGR
; break;
694 case 32: pBuffer
->mnFormat
= BMP_FORMAT_32BIT_TC_ARGB
;
695 pBuffer
->maColorMask
= ColorMask( k32BitRedColorMask
, k32BitGreenColorMask
, k32BitBlueColorMask
);
698 pBuffer
->mnFormat
|= BMP_FORMAT_BOTTOM_UP
;
700 // some BitmapBuffer users depend on a complete palette
701 if( (mnBits
<= 8) && !maPalette
)
702 pBuffer
->maPalette
= GetDefaultPalette( mnBits
, true );
707 // ------------------------------------------------------------------
709 void AquaSalBitmap::ReleaseBuffer( BitmapBuffer
* pBuffer
, bool bReadOnly
)
711 // invalidate graphic context if we have different data
714 maPalette
= pBuffer
->maPalette
;
715 if( mxGraphicContext
)
722 // ------------------------------------------------------------------
724 CGImageRef
AquaSalBitmap::CreateCroppedImage( int nX
, int nY
, int nNewWidth
, int nNewHeight
) const
728 if( !mxGraphicContext
)
729 if( !const_cast<AquaSalBitmap
*>(this)->CreateContext() )
732 mxCachedImage
= CGBitmapContextCreateImage( mxGraphicContext
);
735 CGImageRef xCroppedImage
= NULL
;
736 // short circuit if there is nothing to crop
737 if( !nX
&& !nY
&& (mnWidth
== nNewWidth
) && (mnHeight
== nNewHeight
) )
739 xCroppedImage
= mxCachedImage
;
740 CFRetain( xCroppedImage
);
744 nY
= mnHeight
- (nY
+ nNewHeight
); // adjust for y-mirrored context
745 const CGRect aCropRect
= {{nX
, nY
}, {nNewWidth
, nNewHeight
}};
746 xCroppedImage
= CGImageCreateWithImageInRect( mxCachedImage
, aCropRect
);
749 return xCroppedImage
;
752 // ------------------------------------------------------------------
754 static void CFRTLFree(void* /*info*/, const void* data
, size_t /*size*/)
756 rtl_freeMemory( const_cast<void*>(data
) );
759 CGImageRef
AquaSalBitmap::CreateWithMask( const AquaSalBitmap
& rMask
,
760 int nX
, int nY
, int nWidth
, int nHeight
) const
762 CGImageRef
xImage( CreateCroppedImage( nX
, nY
, nWidth
, nHeight
) );
766 CGImageRef xMask
= rMask
.CreateCroppedImage( nX
, nY
, nWidth
, nHeight
);
770 // CGImageCreateWithMask() only likes masks or greyscale images => convert if needed
771 // TODO: isolate in an extra method?
772 if( !CGImageIsMask(xMask
) || (CGImageGetColorSpace(xMask
) != GetSalData()->mxGraySpace
) )
774 const CGRect xImageRect
=CGRectMake( 0, 0, nWidth
, nHeight
);//the rect has no offset
776 // create the alpha mask image fitting our image
777 // TODO: is caching the full mask or the subimage mask worth it?
778 int nMaskBytesPerRow
= ((nWidth
+ 3) & ~3);
779 void* pMaskMem
= rtl_allocateMemory( nMaskBytesPerRow
* nHeight
);
780 CGContextRef xMaskContext
= CGBitmapContextCreate( pMaskMem
,
781 nWidth
, nHeight
, 8, nMaskBytesPerRow
, GetSalData()->mxGraySpace
, kCGImageAlphaNone
);
782 CGContextDrawImage( xMaskContext
, xImageRect
, xMask
);
784 CGDataProviderRef
xDataProvider( CGDataProviderCreateWithData( NULL
,
785 pMaskMem
, nHeight
* nMaskBytesPerRow
, &CFRTLFree
) );
786 static const float* pDecode
= NULL
;
787 xMask
= CGImageMaskCreate( nWidth
, nHeight
, 8, 8, nMaskBytesPerRow
, xDataProvider
, pDecode
, false );
788 CFRelease( xDataProvider
);
789 CFRelease( xMaskContext
);
795 // combine image and alpha mask
796 CGImageRef xMaskedImage
= CGImageCreateWithMask( xImage
, xMask
);
802 // ------------------------------------------------------------------
804 /** creates an image from the given rectangle, replacing all black pixels with nMaskColor and make all other full transparent */
805 CGImageRef
AquaSalBitmap::CreateColorMask( int nX
, int nY
, int nWidth
, int nHeight
, SalColor nMaskColor
) const
807 CGImageRef xMask
= 0;
808 if( maUserBuffer
.get() && (nX
+ nWidth
<= mnWidth
) && (nY
+ nHeight
<= mnHeight
) )
810 const sal_uInt32 nDestBytesPerRow
= nWidth
<< 2;
811 sal_uInt32
* pMaskBuffer
= static_cast<sal_uInt32
*>( rtl_allocateMemory( nHeight
* nDestBytesPerRow
) );
812 sal_uInt32
* pDest
= pMaskBuffer
;
814 ImplPixelFormat
* pSourcePixels
= ImplPixelFormat::GetFormat( mnBits
, maPalette
);
816 if( pMaskBuffer
&& pSourcePixels
)
819 reinterpret_cast<sal_uInt8
*>(&nColor
)[0] = 0xff;
820 reinterpret_cast<sal_uInt8
*>(&nColor
)[1] = SALCOLOR_RED( nMaskColor
);
821 reinterpret_cast<sal_uInt8
*>(&nColor
)[2] = SALCOLOR_GREEN( nMaskColor
);
822 reinterpret_cast<sal_uInt8
*>(&nColor
)[3] = SALCOLOR_BLUE( nMaskColor
);
824 sal_uInt8
* pSource
= maUserBuffer
.get();
826 pSource
+= nY
* mnBytesPerRow
;
831 pSourcePixels
->StartLine( pSource
);
832 pSourcePixels
->SkipPixel(nX
);
833 sal_uInt32 x
= nWidth
;
836 *pDest
++ = ( pSourcePixels
->ReadPixel() == 0 ) ? nColor
: 0;
838 pSource
+= mnBytesPerRow
;
841 CGDataProviderRef
xDataProvider( CGDataProviderCreateWithData(NULL
, pMaskBuffer
, nHeight
* nDestBytesPerRow
, &CFRTLFree
) );
842 xMask
= CGImageCreate(nWidth
, nHeight
, 8, 32, nDestBytesPerRow
, GetSalData()->mxRGBSpace
, kCGImageAlphaPremultipliedFirst
, xDataProvider
, NULL
, true, kCGRenderingIntentDefault
);
843 CFRelease(xDataProvider
);
850 delete pSourcePixels
;
855 // =======================================================================
857 /** AquaSalBitmap::GetSystemData Get platform native image data from existing image
859 * @param rData struct BitmapSystemData, defined in vcl/inc/bitmap.hxx
860 * @return true if successful
862 bool AquaSalBitmap::GetSystemData( BitmapSystemData
& rData
)
866 if( !mxGraphicContext
)
869 if ( mxGraphicContext
)
874 if ((CGBitmapContextGetBitsPerPixel(mxGraphicContext
) == 32) &&
875 (CGBitmapContextGetBitmapInfo(mxGraphicContext
) & kCGBitmapByteOrderMask
) != kCGBitmapByteOrder32Host
) {
877 * We need to hack things because VCL does not use kCGBitmapByteOrder32Host, while Cairo requires it.
879 OSL_TRACE("AquaSalBitmap::%s(): kCGBitmapByteOrder32Host not found => inserting it.",__func__
);
881 CGImageRef xImage
= CGBitmapContextCreateImage (mxGraphicContext
);
883 // re-create the context with single change: include kCGBitmapByteOrder32Host flag.
884 CGContextRef mxGraphicContextNew
= CGBitmapContextCreate( CGBitmapContextGetData(mxGraphicContext
),
885 CGBitmapContextGetWidth(mxGraphicContext
),
886 CGBitmapContextGetHeight(mxGraphicContext
),
887 CGBitmapContextGetBitsPerComponent(mxGraphicContext
),
888 CGBitmapContextGetBytesPerRow(mxGraphicContext
),
889 CGBitmapContextGetColorSpace(mxGraphicContext
),
890 CGBitmapContextGetBitmapInfo(mxGraphicContext
) | kCGBitmapByteOrder32Host
);
891 CFRelease(mxGraphicContext
);
893 // Needs to be flipped
894 CGContextSaveGState( mxGraphicContextNew
);
895 CGContextTranslateCTM (mxGraphicContextNew
, 0, CGBitmapContextGetHeight(mxGraphicContextNew
));
896 CGContextScaleCTM (mxGraphicContextNew
, 1.0, -1.0);
898 CGContextDrawImage(mxGraphicContextNew
, CGRectMake( 0, 0, CGImageGetWidth(xImage
), CGImageGetHeight(xImage
)), xImage
);
901 CGContextRestoreGState( mxGraphicContextNew
);
903 CGImageRelease( xImage
);
904 mxGraphicContext
= mxGraphicContextNew
;
908 rData
.rImageContext
= (void *) mxGraphicContext
;
909 rData
.mnWidth
= mnWidth
;
910 rData
.mnHeight
= mnHeight
;