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