xref: /trunk/main/vcl/source/gdi/salmisc.cxx (revision 9921ef17)
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 <rtl/memory.h>
27 #include <vcl/bmpacc.hxx>
28 #include <vcl/salbtype.hxx>
29 #include <bmpfast.hxx>
30 
31 // -----------
32 // - Defines -
33 // -----------
34 
35 #define IMPL_CASE_GET_FORMAT( Format )							\
36 case( BMP_FORMAT##Format ):									\
37 	pFncGetPixel = BitmapReadAccess::GetPixelFor##Format;		\
38 break
39 
40 // -----------------------------------------------------------------------------
41 
42 #define IMPL_CASE_SET_FORMAT( Format, BitCount )				\
43 case( BMP_FORMAT##Format ):									\
44 {																\
45 	pFncSetPixel = BitmapReadAccess::SetPixelFor##Format;		\
46 	pDstBuffer->mnBitCount = BitCount;							\
47 }																\
48 break
49 
50 // -----------------------------------------------------------------------------
51 
52 #define DOUBLE_SCANLINES()														\
53 while( ( nActY < nHeight1 ) && ( pMapY[ nActY + 1 ] == nMapY ) )				\
54 {																				\
55 	memcpy( pDstScanMap[ nActY + 1L ], pDstScan, rDstBuffer.mnScanlineSize );	\
56 	nActY++;																	\
57 }
58 
59 // -----------
60 // - Inlines -
61 // -----------
62 
63 #define TC_TO_PAL_COLORS	4096
64 
ImplIndexFromColor(const BitmapColor & rCol)65 static long ImplIndexFromColor( const BitmapColor& rCol )
66 {
67 #if TC_TO_PAL_COLORS == 4096
68 
69 	return( ( ( (long) rCol.GetBlue() >> 4L) << 8L ) |
70 			( ( (long) rCol.GetGreen() >> 4L ) << 4L ) |
71 			( (long) rCol.GetRed() >> 4L ) );
72 
73 #elif TC_TO_PAL_COLORS == 32768
74 
75 	return( ( ( (long) rCol.GetBlue() >> 3L) << 10L ) |
76 			( ( (long) rCol.GetGreen() >> 3L ) << 5L ) |
77 			( (long) rCol.GetRed() >> 3L ) );
78 
79 #endif
80 }
81 
82 
83 #define COLOR_TO_INDEX( _def_rCol )
84 
85 // ------------------------
86 // - conversion functions -
87 // ------------------------
88 
ImplPALToPAL(const BitmapBuffer & rSrcBuffer,BitmapBuffer & rDstBuffer,FncGetPixel pFncGetPixel,FncSetPixel pFncSetPixel,Scanline * pSrcScanMap,Scanline * pDstScanMap,long * pMapX,long * pMapY)89 static void	ImplPALToPAL( const BitmapBuffer& rSrcBuffer, BitmapBuffer& rDstBuffer,
90 						  FncGetPixel pFncGetPixel, FncSetPixel pFncSetPixel,
91 						  Scanline* pSrcScanMap, Scanline* pDstScanMap, long* pMapX, long* pMapY )
92 {
93 	const long			nWidth = rDstBuffer.mnWidth, nHeight = rDstBuffer.mnHeight, nHeight1 = nHeight - 1;
94 	const ColorMask&	rSrcMask = rSrcBuffer.maColorMask;
95 	const ColorMask&	rDstMask = rDstBuffer.maColorMask;
96 	BitmapPalette		aColMap( rSrcBuffer.maPalette.GetEntryCount() );
97 	BitmapColor*		pColMapBuf = aColMap.ImplGetColorBuffer();
98 	BitmapColor			aIndex( 0 );
99 
100 	for( sal_uInt16 i = 0, nSrcCount = aColMap.GetEntryCount(), nDstCount = rDstBuffer.maPalette.GetEntryCount(); i < nSrcCount; i++ )
101 	{
102 	    if( ( i < nDstCount ) && ( rSrcBuffer.maPalette[ i ] == rDstBuffer.maPalette[ i ] ) )
103 		    aIndex.SetIndex( sal::static_int_cast<sal_uInt8>(i) );
104 		else
105 			aIndex.SetIndex( sal::static_int_cast<sal_uInt8>(rDstBuffer.maPalette.GetBestIndex( rSrcBuffer.maPalette[ i ] )) );
106 
107 		pColMapBuf[ i ] = aIndex;
108 	}
109 
110 	for( long nActY = 0, nMapY; nActY < nHeight; nActY++ )
111 	{
112 		Scanline pSrcScan( pSrcScanMap[ nMapY = pMapY[ nActY ] ] ), pDstScan( pDstScanMap[ nActY ] );
113 
114 		for( long nX = 0L; nX < nWidth; nX++ )
115 			pFncSetPixel( pDstScan, nX, pColMapBuf[ pFncGetPixel( pSrcScan, pMapX[ nX ], rSrcMask ).GetIndex() ], rDstMask );
116 
117 		DOUBLE_SCANLINES();
118 	}
119 }
120 
121 // -----------------------------------------------------------------------------
122 
ImplPALToTC(const BitmapBuffer & rSrcBuffer,BitmapBuffer & rDstBuffer,FncGetPixel pFncGetPixel,FncSetPixel pFncSetPixel,Scanline * pSrcScanMap,Scanline * pDstScanMap,long * pMapX,long * pMapY)123 static void	ImplPALToTC( const BitmapBuffer& rSrcBuffer, BitmapBuffer& rDstBuffer,
124 						 FncGetPixel pFncGetPixel, FncSetPixel pFncSetPixel,
125 						 Scanline* pSrcScanMap, Scanline* pDstScanMap, long* pMapX, long* pMapY )
126 {
127 	const long			nWidth = rDstBuffer.mnWidth, nHeight = rDstBuffer.mnHeight, nHeight1 = nHeight - 1;
128 	const ColorMask&	rSrcMask = rSrcBuffer.maColorMask;
129 	const ColorMask&	rDstMask = rDstBuffer.maColorMask;
130 	const BitmapColor*	pColBuf = rSrcBuffer.maPalette.ImplGetColorBuffer();
131 
132 	if( BMP_SCANLINE_FORMAT( rSrcBuffer.mnFormat ) == BMP_FORMAT_1BIT_MSB_PAL )
133 	{
134 		const BitmapColor	aCol0( pColBuf[ 0 ] );
135 		const BitmapColor	aCol1( pColBuf[ 1 ] );
136 		long				nMapX;
137 
138 		for( long nActY = 0, nMapY; nActY < nHeight; nActY++ )
139 		{
140 			Scanline pSrcScan( pSrcScanMap[ nMapY = pMapY[ nActY ] ] ), pDstScan( pDstScanMap[ nActY ] );
141 
142 			for( long nX = 0L; nX < nWidth; )
143 			{
144 				nMapX = pMapX[ nX ];
145 				pFncSetPixel( pDstScan, nX++,
146 							  pSrcScan[ nMapX >> 3 ] & ( 1 << ( 7 - ( nMapX & 7 ) ) ) ? aCol1 : aCol0,
147 							  rDstMask );
148 			}
149 
150 			DOUBLE_SCANLINES();
151 		}
152 	}
153 	else if( BMP_SCANLINE_FORMAT( rSrcBuffer.mnFormat ) == BMP_FORMAT_4BIT_MSN_PAL )
154 	{
155 		long nMapX;
156 
157 		for( long nActY = 0, nMapY; nActY < nHeight; nActY++ )
158 		{
159 			Scanline pSrcScan( pSrcScanMap[ nMapY = pMapY[ nActY ] ] ), pDstScan( pDstScanMap[ nActY ] );
160 
161 			for( long nX = 0L; nX < nWidth; )
162 			{
163 				nMapX = pMapX[ nX ];
164 				pFncSetPixel( pDstScan, nX++,
165 							  pColBuf[ ( pSrcScan[ nMapX >> 1 ] >> ( nMapX & 1 ? 0 : 4 ) ) & 0x0f ],
166 							  rDstMask );
167 			}
168 
169 			DOUBLE_SCANLINES();
170 		}
171 	}
172 	else if( BMP_SCANLINE_FORMAT( rSrcBuffer.mnFormat ) == BMP_FORMAT_8BIT_PAL )
173 	{
174 		for( long nActY = 0, nMapY; nActY < nHeight; nActY++ )
175 		{
176 			Scanline pSrcScan( pSrcScanMap[ nMapY = pMapY[ nActY ] ] ), pDstScan( pDstScanMap[ nActY ] );
177 
178 			for( long nX = 0L; nX < nWidth; nX++ )
179 				pFncSetPixel( pDstScan, nX, pColBuf[ pSrcScan[ pMapX[ nX ] ] ], rDstMask );
180 
181 			DOUBLE_SCANLINES();
182 		}
183 	}
184 	else
185 	{
186 		for( long nActY = 0, nMapY; nActY < nHeight; nActY++ )
187 		{
188 			Scanline pSrcScan( pSrcScanMap[ nMapY = pMapY[ nActY ] ] ), pDstScan( pDstScanMap[ nActY ] );
189 
190 			for( long nX = 0L; nX < nWidth; nX++ )
191 				pFncSetPixel( pDstScan, nX, pColBuf[ pFncGetPixel( pSrcScan, pMapX[ nX ], rSrcMask ).GetIndex() ], rDstMask );
192 
193 			DOUBLE_SCANLINES();
194 		}
195 	}
196 }
197 
198 // -----------------------------------------------------------------------------
199 
ImplTCToTC(const BitmapBuffer & rSrcBuffer,BitmapBuffer & rDstBuffer,FncGetPixel pFncGetPixel,FncSetPixel pFncSetPixel,Scanline * pSrcScanMap,Scanline * pDstScanMap,long * pMapX,long * pMapY)200 static void	ImplTCToTC( const BitmapBuffer& rSrcBuffer, BitmapBuffer& rDstBuffer,
201 						FncGetPixel pFncGetPixel, FncSetPixel pFncSetPixel,
202 						Scanline* pSrcScanMap, Scanline* pDstScanMap, long* pMapX, long* pMapY )
203 {
204 	const long			nWidth = rDstBuffer.mnWidth, nHeight = rDstBuffer.mnHeight, nHeight1 = nHeight - 1;
205 	const ColorMask&	rSrcMask = rSrcBuffer.maColorMask;
206 	const ColorMask&	rDstMask = rDstBuffer.maColorMask;
207 
208 	if( BMP_SCANLINE_FORMAT( rSrcBuffer.mnFormat ) == BMP_FORMAT_24BIT_TC_BGR )
209 	{
210 		BitmapColor aCol;
211 		sal_uInt8*		pPixel;
212 
213 		for( long nActY = 0, nMapY; nActY < nHeight; nActY++ )
214 		{
215 			Scanline pSrcScan( pSrcScanMap[ nMapY = pMapY[ nActY ] ] ), pDstScan( pDstScanMap[ nActY ] );
216 
217 			for( long nX = 0L; nX < nWidth; nX++ )
218 			{
219 				aCol.SetBlue( *( pPixel = ( pSrcScan + pMapX[ nX ] * 3 ) )++ );
220 				aCol.SetGreen( *pPixel++ );
221 				aCol.SetRed( *pPixel );
222 				pFncSetPixel( pDstScan, nX, aCol, rDstMask );
223 			}
224 
225 			DOUBLE_SCANLINES()
226 		}
227 	}
228 	else
229 	{
230 		for( long nActY = 0, nMapY; nActY < nHeight; nActY++ )
231 		{
232 			Scanline pSrcScan( pSrcScanMap[ nMapY = pMapY[ nActY ] ] ), pDstScan( pDstScanMap[ nActY ] );
233 
234 			for( long nX = 0L; nX < nWidth; nX++ )
235 				pFncSetPixel( pDstScan, nX, pFncGetPixel( pSrcScan, pMapX[ nX ], rSrcMask ), rDstMask );
236 
237 			DOUBLE_SCANLINES();
238 		}
239 	}
240 }
241 
242 // -----------------------------------------------------------------------------
243 
ImplTCToPAL(const BitmapBuffer & rSrcBuffer,BitmapBuffer & rDstBuffer,FncGetPixel pFncGetPixel,FncSetPixel pFncSetPixel,Scanline * pSrcScanMap,Scanline * pDstScanMap,long * pMapX,long * pMapY)244 static void	ImplTCToPAL( const BitmapBuffer& rSrcBuffer, BitmapBuffer& rDstBuffer,
245 						 FncGetPixel pFncGetPixel, FncSetPixel pFncSetPixel,
246 						 Scanline* pSrcScanMap, Scanline* pDstScanMap, long* pMapX, long* pMapY )
247 {
248 	const long			nWidth = rDstBuffer.mnWidth, nHeight = rDstBuffer.mnHeight, nHeight1 = nHeight - 1;
249 	const ColorMask&	rSrcMask = rSrcBuffer.maColorMask;
250 	const ColorMask&	rDstMask = rDstBuffer.maColorMask;
251 	BitmapPalette		aColMap( rSrcBuffer.maPalette.GetEntryCount() );
252 	sal_uInt8*				pColToPalMap = new sal_uInt8[ TC_TO_PAL_COLORS ];
253 	BitmapColor			aIndex( 0 );
254 
255 	for( long nR = 0; nR < 16; nR++ )
256 	{
257 		for( long nG = 0; nG < 16; nG++ )
258 		{
259 			for( long nB = 0; nB < 16; nB++ )
260 			{
261 				BitmapColor aCol( sal::static_int_cast<sal_uInt8>(nR << 4),
262                                   sal::static_int_cast<sal_uInt8>(nG << 4),
263                                   sal::static_int_cast<sal_uInt8>(nB << 4) );
264 				pColToPalMap[ ImplIndexFromColor( aCol ) ] = (sal_uInt8) rDstBuffer.maPalette.GetBestIndex( aCol );
265 			}
266 		}
267 	}
268 
269 	for( long nActY = 0, nMapY; nActY < nHeight; nActY++ )
270 	{
271 		Scanline pSrcScan( pSrcScanMap[ nMapY = pMapY[ nActY ] ] ), pDstScan( pDstScanMap[ nActY ] );
272 
273 		for( long nX = 0L; nX < nWidth; nX++ )
274 		{
275 			aIndex.SetIndex( pColToPalMap[ ImplIndexFromColor( pFncGetPixel( pSrcScan, pMapX[ nX ], rSrcMask ) ) ] );
276 			pFncSetPixel( pDstScan, nX, aIndex, rDstMask );
277 		}
278 
279 		DOUBLE_SCANLINES();
280 	}
281 
282 	delete[] pColToPalMap;
283 }
284 
285 // -----------------------------------------------------------------------------
286 
287 // ---------------------
288 // - StretchAndConvert -
289 // ---------------------
290 
StretchAndConvert(const BitmapBuffer & rSrcBuffer,const SalTwoRect & rTwoRect,sal_uLong nDstBitmapFormat,const BitmapPalette * pDstPal,const ColorMask * pDstMask)291 BitmapBuffer* StretchAndConvert(
292     const BitmapBuffer& rSrcBuffer, const SalTwoRect& rTwoRect,
293 	sal_uLong nDstBitmapFormat, const BitmapPalette* pDstPal, const ColorMask* pDstMask )
294 {
295     FncGetPixel		pFncGetPixel;
296     FncSetPixel		pFncSetPixel;
297 	BitmapBuffer*	pDstBuffer = new BitmapBuffer;
298     long            i;
299 
300 	// set function for getting pixels
301 	switch( BMP_SCANLINE_FORMAT( rSrcBuffer.mnFormat ) )
302 	{
303 		IMPL_CASE_GET_FORMAT( _1BIT_MSB_PAL );
304 		IMPL_CASE_GET_FORMAT( _1BIT_LSB_PAL );
305 		IMPL_CASE_GET_FORMAT( _4BIT_MSN_PAL );
306 		IMPL_CASE_GET_FORMAT( _4BIT_LSN_PAL );
307 		IMPL_CASE_GET_FORMAT( _8BIT_PAL );
308 		IMPL_CASE_GET_FORMAT( _8BIT_TC_MASK );
309 		IMPL_CASE_GET_FORMAT( _16BIT_TC_MSB_MASK );
310 		IMPL_CASE_GET_FORMAT( _16BIT_TC_LSB_MASK );
311 		IMPL_CASE_GET_FORMAT( _24BIT_TC_BGR );
312 		IMPL_CASE_GET_FORMAT( _24BIT_TC_RGB );
313 		IMPL_CASE_GET_FORMAT( _24BIT_TC_MASK );
314 		IMPL_CASE_GET_FORMAT( _32BIT_TC_ABGR );
315 		IMPL_CASE_GET_FORMAT( _32BIT_TC_ARGB );
316 		IMPL_CASE_GET_FORMAT( _32BIT_TC_BGRA );
317 		IMPL_CASE_GET_FORMAT( _32BIT_TC_RGBA );
318 		IMPL_CASE_GET_FORMAT( _32BIT_TC_MASK );
319 
320 		default:
321             // should never come here
322             // initialize pFncGetPixel to something valid that is
323             // least likely to crash
324             pFncGetPixel = BitmapReadAccess::GetPixelFor_1BIT_MSB_PAL;
325 			DBG_ERROR( "unknown read format" );
326 		break;
327 	}
328 
329 	// set function for setting pixels
330     const sal_uLong nDstScanlineFormat = BMP_SCANLINE_FORMAT( nDstBitmapFormat );
331 	switch( nDstScanlineFormat )
332 	{
333 		IMPL_CASE_SET_FORMAT( _1BIT_MSB_PAL, 1 );
334 		IMPL_CASE_SET_FORMAT( _1BIT_LSB_PAL, 1 );
335 		IMPL_CASE_SET_FORMAT( _4BIT_MSN_PAL, 1 );
336 		IMPL_CASE_SET_FORMAT( _4BIT_LSN_PAL, 4 );
337 		IMPL_CASE_SET_FORMAT( _8BIT_PAL, 8 );
338 		IMPL_CASE_SET_FORMAT( _8BIT_TC_MASK, 8 );
339 		IMPL_CASE_SET_FORMAT( _16BIT_TC_MSB_MASK, 16 );
340 		IMPL_CASE_SET_FORMAT( _16BIT_TC_LSB_MASK, 16 );
341 		IMPL_CASE_SET_FORMAT( _24BIT_TC_BGR, 24 );
342 		IMPL_CASE_SET_FORMAT( _24BIT_TC_RGB, 24 );
343 		IMPL_CASE_SET_FORMAT( _24BIT_TC_MASK, 24 );
344 		IMPL_CASE_SET_FORMAT( _32BIT_TC_ABGR, 32 );
345 		IMPL_CASE_SET_FORMAT( _32BIT_TC_ARGB, 32 );
346 		IMPL_CASE_SET_FORMAT( _32BIT_TC_BGRA, 32 );
347 		IMPL_CASE_SET_FORMAT( _32BIT_TC_RGBA, 32 );
348 		IMPL_CASE_SET_FORMAT( _32BIT_TC_MASK, 32 );
349 
350 		default:
351             // should never come here
352             // initialize pFncSetPixel to something valid that is
353             // least likely to crash
354             pFncSetPixel = BitmapReadAccess::SetPixelFor_1BIT_MSB_PAL;
355             pDstBuffer->mnBitCount = 1;
356 			DBG_ERROR( "unknown write format" );
357 		break;
358 	}
359 
360 	// fill destination buffer
361 	pDstBuffer->mnFormat = nDstBitmapFormat;
362 	pDstBuffer->mnWidth = rTwoRect.mnDestWidth;
363 	pDstBuffer->mnHeight = rTwoRect.mnDestHeight;
364 	pDstBuffer->mnScanlineSize = AlignedWidth4Bytes( pDstBuffer->mnBitCount * pDstBuffer->mnWidth );
365     try
366     {
367         pDstBuffer->mpBits = new sal_uInt8[ pDstBuffer->mnScanlineSize * pDstBuffer->mnHeight ];
368     }
369     catch( const std::bad_alloc& )
370     {
371         // memory exception, clean up
372         pDstBuffer->mpBits = NULL;
373         delete pDstBuffer;
374         return NULL;
375     }
376 
377 	// do we need a destination palette or color mask?
378 	if( ( nDstScanlineFormat == BMP_FORMAT_1BIT_MSB_PAL ) ||
379 		( nDstScanlineFormat == BMP_FORMAT_1BIT_LSB_PAL ) ||
380 		( nDstScanlineFormat == BMP_FORMAT_4BIT_MSN_PAL ) ||
381 		( nDstScanlineFormat == BMP_FORMAT_4BIT_LSN_PAL ) ||
382 		( nDstScanlineFormat == BMP_FORMAT_8BIT_PAL ) )
383 	{
384 		DBG_ASSERT( pDstPal, "destination buffer requires palette" );
385 		pDstBuffer->maPalette = *pDstPal;
386 	}
387 	else if( ( nDstScanlineFormat == BMP_FORMAT_8BIT_TC_MASK ) ||
388 			 ( nDstScanlineFormat == BMP_FORMAT_16BIT_TC_MSB_MASK ) ||
389 			 ( nDstScanlineFormat == BMP_FORMAT_16BIT_TC_LSB_MASK ) ||
390 			 ( nDstScanlineFormat == BMP_FORMAT_24BIT_TC_MASK ) ||
391 			 ( nDstScanlineFormat == BMP_FORMAT_32BIT_TC_MASK ) )
392 	{
393 		DBG_ASSERT( pDstMask, "destination buffer requires color mask" );
394 		pDstBuffer->maColorMask = *pDstMask;
395 	}
396 
397     // short circuit the most important conversions
398     bool bFastConvert = ImplFastBitmapConversion( *pDstBuffer, rSrcBuffer, rTwoRect );
399     if( bFastConvert )
400         return pDstBuffer;
401 
402     const long      nSrcX = rTwoRect.mnSrcX, nSrcY = rTwoRect.mnSrcY;
403     const long      nSrcDX = rTwoRect.mnSrcWidth, nSrcDY = rTwoRect.mnSrcHeight;
404     const long      nDstDX = rTwoRect.mnDestWidth, nDstDY = rTwoRect.mnDestHeight;
405     Scanline*       pSrcScan = NULL;
406     Scanline*       pDstScan = NULL;
407     long*           pMapX = NULL;
408     long*           pMapY = NULL;
409     long            nTmp, nOffset;
410 
411     try
412     {
413         pSrcScan = new Scanline[ rSrcBuffer.mnHeight ];
414         pDstScan = new Scanline[ nDstDY ];
415         pMapX = new long[ nDstDX ];
416         pMapY = new long[ nDstDY ];
417     }
418     catch( const std::bad_alloc& )
419     {
420         // memory exception, clean up
421         // remark: the buffer ptr causing the exception
422         // is still NULL here
423         delete[] pSrcScan;
424         delete[] pDstScan;
425         delete[] pMapX;
426         delete[] pMapY;
427         delete pDstBuffer;
428         return NULL;
429     }
430 
431 	// horizontal mapping table
432 	if( (nDstDX != nSrcDX) && (nDstDX != 0) )
433 	{
434 		const double fFactorX = (double)nSrcDX / nDstDX;
435 
436 		for( i = 0L; i < nDstDX; i++ )
437 			pMapX[ i ] = nSrcX + static_cast<int>( i * fFactorX );
438 	}
439 	else
440 	{
441 		for( i = 0L, nTmp = nSrcX; i < nDstDX; i++ )
442 			pMapX[ i ] = nTmp++;
443 	}
444 
445 	// vertical mapping table
446 	if( (nDstDY != nSrcDY) && (nDstDY != 0) )
447 	{
448 		const double fFactorY = (double)nSrcDY / nDstDY;
449 
450 		for( i = 0L; i < nDstDY; i++ )
451 			pMapY[ i ] = nSrcY + static_cast<int>( i * fFactorY );
452 	}
453 	else
454 	{
455 		for( i = 0L, nTmp = nSrcY; i < nDstDY; i++ )
456 			pMapY[ i ] = nTmp++;
457 	}
458 
459 	// source scanline buffer
460     Scanline pTmpScan;
461 	if( BMP_SCANLINE_ADJUSTMENT( rSrcBuffer.mnFormat ) == BMP_FORMAT_TOP_DOWN )
462 		pTmpScan = rSrcBuffer.mpBits, nOffset = rSrcBuffer.mnScanlineSize;
463 	else
464 	{
465 		pTmpScan = rSrcBuffer.mpBits + ( rSrcBuffer.mnHeight - 1 ) * rSrcBuffer.mnScanlineSize;
466 		nOffset = -rSrcBuffer.mnScanlineSize;
467 	}
468 
469 	for( i = 0L; i < rSrcBuffer.mnHeight; i++, pTmpScan += nOffset )
470 		pSrcScan[ i ] = pTmpScan;
471 
472 	// destination scanline buffer
473 	if( BMP_SCANLINE_ADJUSTMENT( pDstBuffer->mnFormat ) == BMP_FORMAT_TOP_DOWN )
474 		pTmpScan = pDstBuffer->mpBits, nOffset = pDstBuffer->mnScanlineSize;
475 	else
476 	{
477 		pTmpScan = pDstBuffer->mpBits + ( nDstDY - 1 ) * pDstBuffer->mnScanlineSize;
478 		nOffset = -pDstBuffer->mnScanlineSize;
479 	}
480 
481 	for( i = 0L; i < nDstDY; i++, pTmpScan += nOffset )
482 		pDstScan[ i ] = pTmpScan;
483 
484 	// do buffer scaling and conversion
485 	if( rSrcBuffer.mnBitCount <= 8 && pDstBuffer->mnBitCount <= 8 )
486 	{
487 		ImplPALToPAL( rSrcBuffer, *pDstBuffer, pFncGetPixel, pFncSetPixel,
488 					  pSrcScan, pDstScan, pMapX, pMapY );
489 	}
490 	else if( rSrcBuffer.mnBitCount <= 8 && pDstBuffer->mnBitCount > 8 )
491 	{
492 		ImplPALToTC( rSrcBuffer, *pDstBuffer, pFncGetPixel, pFncSetPixel,
493 					 pSrcScan, pDstScan, pMapX, pMapY );
494 	}
495 	else if( rSrcBuffer.mnBitCount > 8 && pDstBuffer->mnBitCount > 8 )
496 	{
497 		ImplTCToTC( rSrcBuffer, *pDstBuffer, pFncGetPixel, pFncSetPixel,
498 					pSrcScan, pDstScan, pMapX, pMapY );
499 	}
500 	else
501 	{
502 		ImplTCToPAL( rSrcBuffer, *pDstBuffer, pFncGetPixel, pFncSetPixel,
503 					 pSrcScan, pDstScan, pMapX, pMapY );
504 	}
505 
506 	// cleanup
507 	delete[] pSrcScan;
508 	delete[] pDstScan;
509 	delete[] pMapX;
510 	delete[] pMapY;
511 
512 	return pDstBuffer;
513 }
514