xref: /trunk/main/vcl/source/gdi/alpha.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 #include <tools/debug.hxx>
31 #include <vcl/bmpacc.hxx>
32 #include <tools/color.hxx>
33 #include <vcl/alpha.hxx>
34 
35 // -------------
36 // - AlphaMask -
37 // -------------
38 
39 AlphaMask::AlphaMask()
40 {
41 }
42 
43 // -----------------------------------------------------------------------------
44 
45 AlphaMask::AlphaMask( const Bitmap& rBitmap ) :
46     Bitmap( rBitmap )
47 {
48     if( !!rBitmap )
49         Bitmap::Convert( BMP_CONVERSION_8BIT_GREYS );
50 }
51 
52 // -----------------------------------------------------------------------------
53 
54 AlphaMask::AlphaMask( const AlphaMask& rAlphaMask ) :
55     Bitmap( rAlphaMask )
56 {
57 }
58 
59 // -----------------------------------------------------------------------------
60 
61 AlphaMask::AlphaMask( const Size& rSizePixel, sal_uInt8* pEraseTransparency ) :
62     Bitmap( rSizePixel, 8, &Bitmap::GetGreyPalette( 256 ) )
63 {
64     if( pEraseTransparency )
65         Bitmap::Erase( Color( *pEraseTransparency, *pEraseTransparency, *pEraseTransparency ) );
66 }
67 
68 // -----------------------------------------------------------------------------
69 
70 AlphaMask::~AlphaMask()
71 {
72 }
73 
74 // -----------------------------------------------------------------------------
75 
76 AlphaMask& AlphaMask::operator=( const Bitmap& rBitmap )
77 {
78     *(Bitmap*) this = rBitmap;
79 
80     if( !!rBitmap )
81         Bitmap::Convert( BMP_CONVERSION_8BIT_GREYS );
82 
83     return *this;
84 }
85 
86 // -----------------------------------------------------------------------------
87 
88 const Bitmap& AlphaMask::ImplGetBitmap() const
89 {
90     return( (const Bitmap&) *this );
91 }
92 
93 // -----------------------------------------------------------------------------
94 
95 void AlphaMask::ImplSetBitmap( const Bitmap& rBitmap )
96 {
97     DBG_ASSERT( ( 8 == rBitmap.GetBitCount() ) && rBitmap.HasGreyPalette(), "AlphaMask::ImplSetBitmap: invalid bitmap" );
98     *(Bitmap*) this = rBitmap;
99 }
100 
101 // -----------------------------------------------------------------------------
102 
103 Bitmap AlphaMask::GetBitmap() const
104 {
105     return ImplGetBitmap();
106 }
107 
108 // -----------------------------------------------------------------------------
109 
110 sal_Bool AlphaMask::Crop( const Rectangle& rRectPixel )
111 {
112     return Bitmap::Crop( rRectPixel );
113 }
114 
115 // -----------------------------------------------------------------------------
116 
117 sal_Bool AlphaMask::Expand( sal_uLong nDX, sal_uLong nDY, sal_uInt8* pInitTransparency )
118 {
119     Color aColor;
120 
121     if( pInitTransparency )
122         aColor = Color( *pInitTransparency, *pInitTransparency, *pInitTransparency );
123 
124     return Bitmap::Expand( nDX, nDY, pInitTransparency ? &aColor : NULL );
125 }
126 
127 // -----------------------------------------------------------------------------
128 
129 sal_Bool AlphaMask::CopyPixel( const Rectangle& rRectDst, const Rectangle& rRectSrc,
130                            const AlphaMask* pAlphaSrc )
131 {
132     // Note: this code is copied from Bitmap::CopyPixel but avoids any palette lookups
133     // this optimization is possible because the palettes of AlphaMasks are always identical (8bit GreyPalette, see ctor)
134 
135     const Size  aSizePix( GetSizePixel() );
136     Rectangle   aRectDst( rRectDst );
137     sal_Bool        bRet = sal_False;
138 
139     aRectDst.Intersection( Rectangle( Point(), aSizePix ) );
140 
141     if( !aRectDst.IsEmpty() )
142     {
143         if( pAlphaSrc && ( *pAlphaSrc != *this ) )
144         {
145             Bitmap*         pSrc = (Bitmap*) pAlphaSrc;
146             const Size      aCopySizePix( pSrc->GetSizePixel() );
147             Rectangle       aRectSrc( rRectSrc );
148 
149             aRectSrc.Intersection( Rectangle( Point(), aCopySizePix ) );
150 
151             if( !aRectSrc.IsEmpty() )
152             {
153                 BitmapReadAccess* pReadAcc = pSrc->AcquireReadAccess();
154 
155                 if( pReadAcc )
156                 {
157                     BitmapWriteAccess* pWriteAcc = AcquireWriteAccess();
158 
159                     if( pWriteAcc )
160                     {
161                         const long  nWidth = Min( aRectSrc.GetWidth(), aRectDst.GetWidth() );
162                         const long  nHeight = Min( aRectSrc.GetHeight(), aRectDst.GetHeight() );
163                         const long  nSrcEndX = aRectSrc.Left() + nWidth;
164                         const long  nSrcEndY = aRectSrc.Top() + nHeight;
165                         long        nDstY = aRectDst.Top();
166 
167                         for( long nSrcY = aRectSrc.Top(); nSrcY < nSrcEndY; nSrcY++, nDstY++ )
168                             for( long nSrcX = aRectSrc.Left(), nDstX = aRectDst.Left(); nSrcX < nSrcEndX; nSrcX++, nDstX++ )
169                                 pWriteAcc->SetPixel( nDstY, nDstX, pReadAcc->GetPixel( nSrcY, nSrcX ) );
170 
171                         ReleaseAccess( pWriteAcc );
172                         bRet = ( nWidth > 0L ) && ( nHeight > 0L );
173                     }
174 
175                     pSrc->ReleaseAccess( pReadAcc );
176                 }
177             }
178         }
179         else
180         {
181             Rectangle aRectSrc( rRectSrc );
182 
183             aRectSrc.Intersection( Rectangle( Point(), aSizePix ) );
184 
185             if( !aRectSrc.IsEmpty() && ( aRectSrc != aRectDst ) )
186             {
187                 BitmapWriteAccess*  pWriteAcc = AcquireWriteAccess();
188 
189                 if( pWriteAcc )
190                 {
191                     const long  nWidth = Min( aRectSrc.GetWidth(), aRectDst.GetWidth() );
192                     const long  nHeight = Min( aRectSrc.GetHeight(), aRectDst.GetHeight() );
193                     const long  nSrcX = aRectSrc.Left();
194                     const long  nSrcY = aRectSrc.Top();
195                     const long  nSrcEndX1 = nSrcX + nWidth - 1L;
196                     const long  nSrcEndY1 = nSrcY + nHeight - 1L;
197                     const long  nDstX = aRectDst.Left();
198                     const long  nDstY = aRectDst.Top();
199                     const long  nDstEndX1 = nDstX + nWidth - 1L;
200                     const long  nDstEndY1 = nDstY + nHeight - 1L;
201 
202                     if( ( nDstX <= nSrcX ) && ( nDstY <= nSrcY ) )
203                     {
204                         for( long nY = nSrcY, nYN = nDstY; nY <= nSrcEndY1; nY++, nYN++ )
205                             for( long nX = nSrcX, nXN = nDstX; nX <= nSrcEndX1; nX++, nXN++ )
206                                 pWriteAcc->SetPixel( nYN, nXN, pWriteAcc->GetPixel( nY, nX ) );
207                     }
208                     else if( ( nDstX <= nSrcX ) && ( nDstY >= nSrcY ) )
209                     {
210                         for( long nY = nSrcEndY1, nYN = nDstEndY1; nY >= nSrcY; nY--, nYN-- )
211                             for( long nX = nSrcX, nXN = nDstX; nX <= nSrcEndX1; nX++, nXN++ )
212                                 pWriteAcc->SetPixel( nYN, nXN, pWriteAcc->GetPixel( nY, nX ) );
213                     }
214                     else if( ( nDstX >= nSrcX ) && ( nDstY <= nSrcY ) )
215                     {
216                         for( long nY = nSrcY, nYN = nDstY; nY <= nSrcEndY1; nY++, nYN++ )
217                             for( long nX = nSrcEndX1, nXN = nDstEndX1; nX >= nSrcX; nX--, nXN-- )
218                                 pWriteAcc->SetPixel( nYN, nXN, pWriteAcc->GetPixel( nY, nX ) );
219                     }
220                     else
221                     {
222                         for( long nY = nSrcEndY1, nYN = nDstEndY1; nY >= nSrcY; nY--, nYN-- )
223                             for( long nX = nSrcEndX1, nXN = nDstEndX1; nX >= nSrcX; nX--, nXN-- )
224                                 pWriteAcc->SetPixel( nYN, nXN, pWriteAcc->GetPixel( nY, nX ) );
225                     }
226 
227                     ReleaseAccess( pWriteAcc );
228                     bRet = sal_True;
229                 }
230             }
231         }
232     }
233 
234     return bRet;
235 
236 }
237 
238 // -----------------------------------------------------------------------------
239 
240 sal_Bool AlphaMask::Erase( sal_uInt8 cTransparency )
241 {
242     return Bitmap::Erase( Color( cTransparency, cTransparency, cTransparency ) );
243 }
244 
245 // -----------------------------------------------------------------------------
246 
247 sal_Bool AlphaMask::Invert()
248 {
249     BitmapWriteAccess*  pAcc = AcquireWriteAccess();
250     sal_Bool                bRet = sal_False;
251 
252     if( pAcc && pAcc->GetBitCount() == 8 )
253     {
254         BitmapColor aCol( 0 );
255         const long  nWidth = pAcc->Width(), nHeight = pAcc->Height();
256         sal_uInt8*      pMap = new sal_uInt8[ 256 ];
257 
258         for( long i = 0; i < 256; i++ )
259             pMap[ i ] = ~(sal_uInt8) i;
260 
261         for( long nY = 0L; nY < nHeight; nY++ )
262         {
263             for( long nX = 0L; nX < nWidth; nX++ )
264             {
265                 aCol.SetIndex( pMap[ pAcc->GetPixel( nY, nX ).GetIndex() ] );
266                 pAcc->SetPixel( nY, nX, aCol );
267             }
268         }
269 
270         delete[] pMap;
271         bRet = sal_True;
272     }
273 
274     if( pAcc )
275         ReleaseAccess( pAcc );
276 
277     return bRet;
278 }
279 
280 // -----------------------------------------------------------------------------
281 
282 sal_Bool AlphaMask::Mirror( sal_uLong nMirrorFlags )
283 {
284     return Bitmap::Mirror( nMirrorFlags );
285 }
286 
287 // -----------------------------------------------------------------------------
288 
289 sal_Bool AlphaMask::Scale( const Size& rNewSize, sal_uLong nScaleFlag )
290 {
291     sal_Bool bRet = Bitmap::Scale( rNewSize, nScaleFlag );
292 
293     if( bRet && ( nScaleFlag == BMP_SCALE_INTERPOLATE ) )
294         Bitmap::Convert( BMP_CONVERSION_8BIT_GREYS );
295 
296     return bRet;
297 }
298 
299 // -----------------------------------------------------------------------------
300 
301 sal_Bool AlphaMask::Scale( const double& rScaleX, const double& rScaleY, sal_uLong nScaleFlag )
302 {
303     sal_Bool bRet = Bitmap::Scale( rScaleX, rScaleY, nScaleFlag );
304 
305     if( bRet && ( nScaleFlag == BMP_SCALE_INTERPOLATE ) )
306         Bitmap::Convert( BMP_CONVERSION_8BIT_GREYS );
307 
308     return bRet;
309 }
310 
311 // -----------------------------------------------------------------------------
312 
313 sal_Bool AlphaMask::Rotate( long nAngle10, sal_uInt8 cFillTransparency )
314 {
315     return Bitmap::Rotate( nAngle10, Color( cFillTransparency, cFillTransparency, cFillTransparency ) );
316 }
317 
318 // -----------------------------------------------------------------------------
319 
320 sal_Bool AlphaMask::Replace( const Bitmap& rMask, sal_uInt8 cReplaceTransparency )
321 {
322     BitmapReadAccess*   pMaskAcc = ( (Bitmap&) rMask ).AcquireReadAccess();
323     BitmapWriteAccess*  pAcc = AcquireWriteAccess();
324     sal_Bool                bRet = sal_False;
325 
326     if( pMaskAcc && pAcc )
327     {
328         const BitmapColor   aReplace( cReplaceTransparency );
329         const long          nWidth = Min( pMaskAcc->Width(), pAcc->Width() );
330         const long          nHeight = Min( pMaskAcc->Height(), pAcc->Height() );
331         const BitmapColor   aMaskWhite( pMaskAcc->GetBestMatchingColor( Color( COL_WHITE ) ) );
332 
333         for( long nY = 0L; nY < nHeight; nY++ )
334             for( long nX = 0L; nX < nWidth; nX++ )
335                 if( pMaskAcc->GetPixel( nY, nX ) == aMaskWhite )
336                     pAcc->SetPixel( nY, nX, aReplace );
337     }
338 
339     ( (Bitmap&) rMask ).ReleaseAccess( pMaskAcc );
340     ReleaseAccess( pAcc );
341 
342     return bRet;
343 }
344 
345 // -----------------------------------------------------------------------------
346 
347 sal_Bool AlphaMask::Replace( sal_uInt8 cSearchTransparency, sal_uInt8 cReplaceTransparency, sal_uLong
348 #ifdef DBG_UTIL
349 nTol
350 #endif
351 )
352 {
353     BitmapWriteAccess*  pAcc = AcquireWriteAccess();
354     sal_Bool                bRet = sal_False;
355 
356     DBG_ASSERT( !nTol, "AlphaMask::Replace: nTol not used yet" );
357 
358     if( pAcc && pAcc->GetBitCount() == 8 )
359     {
360         const long nWidth = pAcc->Width(), nHeight = pAcc->Height();
361 
362         if( pAcc->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL )
363         {
364             for( long nY = 0L; nY < nHeight; nY++ )
365             {
366                 Scanline pScan = pAcc->GetScanline( nY );
367 
368                 for( long nX = 0L; nX < nWidth; nX++, pScan++ )
369                 {
370                     if( *pScan == cSearchTransparency )
371                         *pScan = cReplaceTransparency;
372                 }
373             }
374         }
375         else
376         {
377             BitmapColor aReplace( cReplaceTransparency );
378 
379             for( long nY = 0L; nY < nHeight; nY++ )
380             {
381                 for( long nX = 0L; nX < nWidth; nX++ )
382                 {
383                     if( pAcc->GetPixel( nY, nX ).GetIndex() == cSearchTransparency )
384                         pAcc->SetPixel( nY, nX, aReplace );
385                 }
386             }
387         }
388 
389         bRet = sal_True;
390     }
391 
392     if( pAcc )
393         ReleaseAccess( pAcc );
394 
395     return bRet;
396 }
397 
398 // -----------------------------------------------------------------------------
399 
400 sal_Bool AlphaMask::Replace( sal_uInt8* pSearchTransparencies, sal_uInt8* pReplaceTransparencies,
401                          sal_uLong nColorCount, sal_uLong* pTols )
402 {
403     Color*  pSearchColors = new Color[ nColorCount ];
404     Color*  pReplaceColors = new Color[ nColorCount ];
405     sal_Bool    bRet;
406 
407     for( sal_uLong i = 0; i < nColorCount; i++ )
408     {
409         const sal_uInt8 cSearchTransparency = pSearchTransparencies[ i ];
410         const sal_uInt8 cReplaceTransparency = pReplaceTransparencies[ i ];
411 
412         pSearchColors[ i ] = Color( cSearchTransparency, cSearchTransparency, cSearchTransparency );
413         pReplaceColors[ i ] = Color( cReplaceTransparency, cReplaceTransparency, cReplaceTransparency );
414     }
415 
416     bRet = Bitmap::Replace( pSearchColors, pReplaceColors, nColorCount, pTols ) &&
417            Bitmap::Convert( BMP_CONVERSION_8BIT_GREYS );
418 
419     delete[] pSearchColors;
420     delete[] pReplaceColors;
421 
422     return bRet;
423 }
424 
425 // -----------------------------------------------------------------------------
426 
427 void AlphaMask::ReleaseAccess( BitmapReadAccess* pAccess )
428 {
429     if( pAccess )
430     {
431         Bitmap::ReleaseAccess( pAccess );
432         Bitmap::Convert( BMP_CONVERSION_8BIT_GREYS );
433     }
434 }
435