Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include <vcl/salbtype.hxx>
21 : #include <vcl/bitmap.hxx>
22 : #include <vcl/bmpacc.hxx>
23 :
24 : #include <impbmp.hxx>
25 :
26 : #include <string.h>
27 :
28 0 : BitmapReadAccess::BitmapReadAccess( Bitmap& rBitmap, bool bModify ) :
29 : mpBuffer ( NULL ),
30 : mpScanBuf ( NULL ),
31 : mFncGetPixel ( NULL ),
32 : mFncSetPixel ( NULL ),
33 0 : mbModify ( bModify )
34 : {
35 0 : ImplCreate( rBitmap );
36 0 : }
37 :
38 0 : BitmapReadAccess::BitmapReadAccess( Bitmap& rBitmap ) :
39 : mpBuffer ( NULL ),
40 : mpScanBuf ( NULL ),
41 : mFncGetPixel ( NULL ),
42 : mFncSetPixel ( NULL ),
43 0 : mbModify ( false )
44 : {
45 0 : ImplCreate( rBitmap );
46 0 : }
47 :
48 0 : BitmapReadAccess::~BitmapReadAccess()
49 : {
50 0 : ImplDestroy();
51 0 : }
52 :
53 0 : void BitmapReadAccess::ImplCreate( Bitmap& rBitmap )
54 : {
55 0 : ImpBitmap* pImpBmp = rBitmap.ImplGetImpBitmap();
56 :
57 : DBG_ASSERT( pImpBmp, "Forbidden Access to empty bitmap!" );
58 :
59 0 : if( pImpBmp )
60 : {
61 0 : if( mbModify && !maBitmap.ImplGetImpBitmap() )
62 : {
63 0 : rBitmap.ImplMakeUnique();
64 0 : pImpBmp = rBitmap.ImplGetImpBitmap();
65 : }
66 : else
67 : {
68 : DBG_ASSERT( !mbModify || pImpBmp->ImplGetRefCount() == 2,
69 : "Unpredictable results: bitmap is referenced more than once!" );
70 : }
71 :
72 0 : mpBuffer = pImpBmp->ImplAcquireBuffer( !mbModify );
73 :
74 0 : if( !mpBuffer )
75 : {
76 0 : ImpBitmap* pNewImpBmp = new ImpBitmap;
77 :
78 0 : if( pNewImpBmp->ImplCreate( *pImpBmp, rBitmap.GetBitCount() ) )
79 : {
80 0 : pImpBmp = pNewImpBmp;
81 0 : rBitmap.ImplSetImpBitmap( pImpBmp );
82 0 : mpBuffer = pImpBmp->ImplAcquireBuffer( !mbModify );
83 : }
84 : else
85 0 : delete pNewImpBmp;
86 : }
87 :
88 0 : if( mpBuffer )
89 : {
90 0 : const long nHeight = mpBuffer->mnHeight;
91 0 : Scanline pTmpLine = mpBuffer->mpBits;
92 :
93 0 : mpScanBuf = new Scanline[ nHeight ];
94 0 : maColorMask = mpBuffer->maColorMask;
95 :
96 0 : if( BMP_SCANLINE_ADJUSTMENT( mpBuffer->mnFormat ) == BMP_FORMAT_TOP_DOWN )
97 : {
98 0 : for( long nY = 0L; nY < nHeight; nY++, pTmpLine += mpBuffer->mnScanlineSize )
99 0 : mpScanBuf[ nY ] = pTmpLine;
100 : }
101 : else
102 : {
103 0 : for( long nY = nHeight - 1; nY >= 0; nY--, pTmpLine += mpBuffer->mnScanlineSize )
104 0 : mpScanBuf[ nY ] = pTmpLine;
105 : }
106 :
107 0 : if( !ImplSetAccessPointers( BMP_SCANLINE_FORMAT( mpBuffer->mnFormat ) ) )
108 : {
109 0 : delete[] mpScanBuf;
110 0 : mpScanBuf = NULL;
111 :
112 0 : pImpBmp->ImplReleaseBuffer( mpBuffer, !mbModify );
113 0 : mpBuffer = NULL;
114 : }
115 : else
116 0 : maBitmap = rBitmap;
117 : }
118 : }
119 0 : }
120 :
121 0 : void BitmapReadAccess::ImplDestroy()
122 : {
123 0 : ImpBitmap* pImpBmp = maBitmap.ImplGetImpBitmap();
124 :
125 0 : delete[] mpScanBuf;
126 0 : mpScanBuf = NULL;
127 :
128 0 : if( mpBuffer && pImpBmp )
129 : {
130 0 : pImpBmp->ImplReleaseBuffer( mpBuffer, !mbModify );
131 0 : mpBuffer = NULL;
132 : }
133 0 : }
134 :
135 0 : bool BitmapReadAccess::ImplSetAccessPointers( sal_uLong nFormat )
136 : {
137 0 : bool bRet = true;
138 :
139 0 : switch( nFormat )
140 : {
141 0 : CASE_FORMAT( _1BIT_MSB_PAL )
142 0 : CASE_FORMAT( _1BIT_LSB_PAL )
143 0 : CASE_FORMAT( _4BIT_MSN_PAL )
144 0 : CASE_FORMAT( _4BIT_LSN_PAL )
145 0 : CASE_FORMAT( _8BIT_PAL )
146 0 : CASE_FORMAT( _8BIT_TC_MASK )
147 0 : CASE_FORMAT( _16BIT_TC_MSB_MASK )
148 0 : CASE_FORMAT( _16BIT_TC_LSB_MASK )
149 0 : CASE_FORMAT( _24BIT_TC_BGR )
150 0 : CASE_FORMAT( _24BIT_TC_RGB )
151 0 : CASE_FORMAT( _24BIT_TC_MASK )
152 0 : CASE_FORMAT( _32BIT_TC_ABGR )
153 0 : CASE_FORMAT( _32BIT_TC_ARGB )
154 0 : CASE_FORMAT( _32BIT_TC_BGRA )
155 0 : CASE_FORMAT( _32BIT_TC_RGBA )
156 0 : CASE_FORMAT( _32BIT_TC_MASK )
157 :
158 : default:
159 0 : bRet = false;
160 0 : break;
161 : }
162 :
163 0 : return bRet;
164 : }
165 :
166 0 : void BitmapReadAccess::ImplZeroInitUnusedBits()
167 : {
168 0 : const sal_uInt32 nWidth = Width(), nHeight = Height(), nScanSize = GetScanlineSize();
169 :
170 0 : if( nWidth && nHeight && nScanSize && GetBuffer() )
171 : {
172 : sal_uInt32 nBits;
173 : bool bMsb;
174 :
175 0 : const sal_uLong nScanlineFormat = GetScanlineFormat();
176 0 : switch( nScanlineFormat )
177 : {
178 : case( BMP_FORMAT_1BIT_MSB_PAL ):
179 0 : nBits = 1;
180 0 : bMsb = true;
181 0 : break;
182 :
183 : case( BMP_FORMAT_1BIT_LSB_PAL ):
184 0 : nBits = 1;
185 0 : bMsb = false;
186 0 : break;
187 :
188 : case( BMP_FORMAT_4BIT_MSN_PAL ):
189 0 : nBits = 4;
190 0 : bMsb = true;
191 0 : break;
192 :
193 : case( BMP_FORMAT_4BIT_LSN_PAL ):
194 0 : nBits = 4;
195 0 : bMsb = false;
196 0 : break;
197 :
198 : case( BMP_FORMAT_8BIT_PAL ):
199 : case( BMP_FORMAT_8BIT_TC_MASK ):
200 0 : bMsb = true;
201 0 : nBits = 8;
202 0 : break;
203 :
204 : case( BMP_FORMAT_16BIT_TC_MSB_MASK ):
205 : case( BMP_FORMAT_16BIT_TC_LSB_MASK ):
206 0 : bMsb = true;
207 0 : nBits = 16;
208 0 : break;
209 :
210 : case( BMP_FORMAT_24BIT_TC_BGR ):
211 : case( BMP_FORMAT_24BIT_TC_RGB ):
212 : case( BMP_FORMAT_24BIT_TC_MASK ):
213 0 : bMsb = true;
214 0 : nBits = 24;
215 0 : break;
216 :
217 : case( BMP_FORMAT_32BIT_TC_ABGR ):
218 : case( BMP_FORMAT_32BIT_TC_ARGB ):
219 : case( BMP_FORMAT_32BIT_TC_BGRA ):
220 : case( BMP_FORMAT_32BIT_TC_RGBA ):
221 : case( BMP_FORMAT_32BIT_TC_MASK ):
222 0 : bMsb = true;
223 0 : nBits = 32;
224 0 : break;
225 :
226 : default:
227 : {
228 : OSL_FAIL( "BitmapWriteAccess::ZeroInitUnusedBits: Unsupported pixel format");
229 0 : nBits = 0;
230 0 : bMsb = true;
231 : }
232 0 : break;
233 : }
234 :
235 0 : nBits *= nWidth;
236 0 : if( nScanSize % 4 || !bMsb )
237 : {
238 : DBG_ASSERT( 8*nScanSize >= nBits,
239 : "BitmapWriteAccess::ZeroInitUnusedBits: span size smaller than width?!");
240 0 : const sal_uInt32 nLeftOverBits = 8*sizeof(sal_uInt8)*nScanSize - nBits;
241 0 : if( nLeftOverBits != 0 ) // else there is really nothing to do
242 : {
243 0 : const sal_uInt32 nBytes = (nLeftOverBits + 7U) >> 3U;
244 : sal_uInt8 nMask;
245 :
246 0 : if( bMsb )
247 0 : nMask = static_cast<sal_uInt8>(0xffU << (nLeftOverBits & 3UL));
248 : else
249 0 : nMask = static_cast<sal_uInt8>(0xffU >> (nLeftOverBits & 3UL));
250 :
251 0 : sal_uInt8* pLastBytes = (sal_uInt8*)GetBuffer() + ( nScanSize - nBytes );
252 0 : for( sal_uInt32 i = 0; i < nHeight; i++, pLastBytes += nScanSize )
253 : {
254 0 : *pLastBytes &= nMask;
255 0 : for( sal_uInt32 j = 1; j < nBytes; j++ )
256 0 : pLastBytes[j] = 0;
257 : }
258 0 : }
259 : }
260 0 : else if( nBits & 0x1f )
261 : {
262 0 : sal_uInt32 nMask = 0xffffffff << ( ( nScanSize << 3 ) - nBits );
263 0 : sal_uInt8* pLast4Bytes = (sal_uInt8*) GetBuffer() + ( nScanSize - 4 );
264 :
265 : #ifdef OSL_LITENDIAN
266 0 : nMask = OSL_SWAPDWORD( nMask );
267 : #endif
268 0 : for( sal_uInt32 i = 0; i < nHeight; i++, pLast4Bytes += nScanSize )
269 0 : ( *(sal_uInt32*) pLast4Bytes ) &= nMask;
270 : }
271 : }
272 0 : }
273 :
274 0 : sal_uInt16 BitmapReadAccess::GetBestPaletteIndex( const BitmapColor& rBitmapColor ) const
275 : {
276 0 : return( HasPalette() ? mpBuffer->maPalette.GetBestIndex( rBitmapColor ) : 0 );
277 : }
278 :
279 0 : BitmapColor BitmapReadAccess::GetInterpolatedColorWithFallback( double fY, double fX, const BitmapColor& rFallback ) const
280 : {
281 : // ask directly doubles >= 0.0 here to avoid rounded values of 0 at small negative
282 : // double values, e.g. static_cast< sal_Int32 >(-0.25) is 0, not -1, but *has* to be outside (!)
283 0 : if(mpBuffer && fX >= 0.0 && fY >= 0.0)
284 : {
285 0 : const sal_Int32 nX(static_cast< sal_Int32 >(fX));
286 0 : const sal_Int32 nY(static_cast< sal_Int32 >(fY));
287 :
288 0 : if(nX < mpBuffer->mnWidth && nY < mpBuffer->mnHeight)
289 : {
290 : // get base-return value from inside pixel
291 0 : BitmapColor aRetval(GetColor(nY, nX));
292 :
293 : // calculate deltas and indices for neighbour accesses
294 0 : sal_Int16 nDeltaX((fX - (nX + 0.5)) * 255.0); // [-255 .. 255]
295 0 : sal_Int16 nDeltaY((fY - (nY + 0.5)) * 255.0); // [-255 .. 255]
296 0 : sal_Int16 nIndX(0);
297 0 : sal_Int16 nIndY(0);
298 :
299 0 : if(nDeltaX > 0)
300 : {
301 0 : nIndX = nX + 1;
302 : }
303 : else
304 : {
305 0 : nIndX = nX - 1;
306 0 : nDeltaX = -nDeltaX;
307 : }
308 :
309 0 : if(nDeltaY > 0)
310 : {
311 0 : nIndY = nY + 1;
312 : }
313 : else
314 : {
315 0 : nIndY = nY - 1;
316 0 : nDeltaY = -nDeltaY;
317 : }
318 :
319 : // get right/left neighbour
320 0 : BitmapColor aXCol(rFallback);
321 :
322 0 : if(nDeltaX && nIndX >= 0 && nIndX < mpBuffer->mnWidth)
323 : {
324 0 : aXCol = GetColor(nY, nIndX);
325 : }
326 :
327 : // get top/bottom neighbour
328 0 : BitmapColor aYCol(rFallback);
329 :
330 0 : if(nDeltaY && nIndY >= 0 && nIndY < mpBuffer->mnHeight)
331 : {
332 0 : aYCol = GetColor(nIndY, nX);
333 : }
334 :
335 : // get one of four edge neighbours
336 0 : BitmapColor aXYCol(rFallback);
337 :
338 0 : if(nDeltaX && nDeltaY && nIndX >=0 && nIndY >= 0 && nIndX < mpBuffer->mnWidth && nIndY < mpBuffer->mnHeight)
339 : {
340 0 : aXYCol = GetColor(nIndY, nIndX);
341 : }
342 :
343 : // merge return value with right/left neighbour
344 0 : if(aXCol != aRetval)
345 : {
346 0 : aRetval.Merge(aXCol, 255 - nDeltaX);
347 : }
348 :
349 : // merge top/bottom neighbour with edge
350 0 : if(aYCol != aXYCol)
351 : {
352 0 : aYCol.Merge(aXYCol, 255 - nDeltaX);
353 : }
354 :
355 : // merge return value with already merged top/bottom neighbour
356 0 : if(aRetval != aYCol)
357 : {
358 0 : aRetval.Merge(aYCol, 255 - nDeltaY);
359 : }
360 :
361 0 : return aRetval;
362 : }
363 : }
364 :
365 0 : return rFallback;
366 : }
367 :
368 0 : BitmapColor BitmapReadAccess::GetColorWithFallback( double fY, double fX, const BitmapColor& rFallback ) const
369 : {
370 : // ask directly doubles >= 0.0 here to avoid rounded values of 0 at small negative
371 : // double values, e.g. static_cast< sal_Int32 >(-0.25) is 0, not -1, but *has* to be outside (!)
372 0 : if(mpBuffer && fX >= 0.0 && fY >= 0.0)
373 : {
374 0 : const sal_Int32 nX(static_cast< sal_Int32 >(fX));
375 0 : const sal_Int32 nY(static_cast< sal_Int32 >(fY));
376 :
377 0 : if(nX < mpBuffer->mnWidth && nY < mpBuffer->mnHeight)
378 : {
379 0 : return GetColor(nY, nX);
380 : }
381 : }
382 :
383 0 : return rFallback;
384 : }
385 :
386 0 : BitmapWriteAccess::BitmapWriteAccess( Bitmap& rBitmap ) :
387 : BitmapReadAccess( rBitmap, true ),
388 : mpLineColor ( NULL ),
389 0 : mpFillColor ( NULL )
390 : {
391 0 : }
392 :
393 0 : BitmapWriteAccess::~BitmapWriteAccess()
394 : {
395 0 : delete mpLineColor;
396 0 : delete mpFillColor;
397 0 : }
398 :
399 0 : void BitmapWriteAccess::CopyScanline( long nY, const BitmapReadAccess& rReadAcc )
400 : {
401 : DBG_ASSERT( ( nY >= 0 ) && ( nY < mpBuffer->mnHeight ), "y-coordinate in destination out of range!" );
402 : DBG_ASSERT( nY < rReadAcc.Height(), "y-coordinate in source out of range!" );
403 : DBG_ASSERT( ( HasPalette() && rReadAcc.HasPalette() ) || ( !HasPalette() && !rReadAcc.HasPalette() ), "No copying possible between palette bitmap and TC bitmap!" );
404 :
405 0 : if( ( GetScanlineFormat() == rReadAcc.GetScanlineFormat() ) &&
406 0 : ( GetScanlineSize() >= rReadAcc.GetScanlineSize() ) )
407 : {
408 0 : memcpy( mpScanBuf[ nY ], rReadAcc.GetScanline( nY ), rReadAcc.GetScanlineSize() );
409 : }
410 : else
411 : // TODO: use fastbmp infrastructure
412 0 : for( long nX = 0L, nWidth = std::min( mpBuffer->mnWidth, rReadAcc.Width() ); nX < nWidth; nX++ )
413 0 : SetPixel( nY, nX, rReadAcc.GetPixel( nY, nX ) );
414 0 : }
415 :
416 0 : void BitmapWriteAccess::CopyScanline( long nY, ConstScanline aSrcScanline,
417 : sal_uLong nSrcScanlineFormat, sal_uLong nSrcScanlineSize )
418 : {
419 0 : const sal_uLong nFormat = BMP_SCANLINE_FORMAT( nSrcScanlineFormat );
420 :
421 : DBG_ASSERT( ( nY >= 0 ) && ( nY < mpBuffer->mnHeight ), "y-coordinate in destination out of range!" );
422 : DBG_ASSERT( ( HasPalette() && nFormat <= BMP_FORMAT_8BIT_PAL ) ||
423 : ( !HasPalette() && nFormat > BMP_FORMAT_8BIT_PAL ),
424 : "No copying possible between palette and non palette scanlines!" );
425 :
426 0 : const sal_uLong nCount = std::min( GetScanlineSize(), nSrcScanlineSize );
427 :
428 0 : if( nCount )
429 : {
430 0 : if( GetScanlineFormat() == BMP_SCANLINE_FORMAT( nSrcScanlineFormat ) )
431 0 : memcpy( mpScanBuf[ nY ], aSrcScanline, nCount );
432 : else
433 : {
434 : DBG_ASSERT( nFormat != BMP_FORMAT_8BIT_TC_MASK &&
435 : nFormat != BMP_FORMAT_16BIT_TC_MSB_MASK && nFormat != BMP_FORMAT_16BIT_TC_LSB_MASK &&
436 : nFormat != BMP_FORMAT_24BIT_TC_MASK && nFormat != BMP_FORMAT_32BIT_TC_MASK,
437 : "No support for pixel formats with color masks yet!" );
438 :
439 : // TODO: use fastbmp infrastructure
440 : FncGetPixel pFncGetPixel;
441 :
442 0 : switch( nFormat )
443 : {
444 0 : case( BMP_FORMAT_1BIT_MSB_PAL ): pFncGetPixel = GetPixelFor_1BIT_MSB_PAL; break;
445 0 : case( BMP_FORMAT_1BIT_LSB_PAL ): pFncGetPixel = GetPixelFor_1BIT_LSB_PAL; break;
446 0 : case( BMP_FORMAT_4BIT_MSN_PAL ): pFncGetPixel = GetPixelFor_4BIT_MSN_PAL; break;
447 0 : case( BMP_FORMAT_4BIT_LSN_PAL ): pFncGetPixel = GetPixelFor_4BIT_LSN_PAL; break;
448 0 : case( BMP_FORMAT_8BIT_PAL ): pFncGetPixel = GetPixelFor_8BIT_PAL; break;
449 0 : case( BMP_FORMAT_8BIT_TC_MASK ): pFncGetPixel = GetPixelFor_8BIT_TC_MASK; break;
450 0 : case( BMP_FORMAT_16BIT_TC_MSB_MASK ): pFncGetPixel = GetPixelFor_16BIT_TC_MSB_MASK; break;
451 0 : case( BMP_FORMAT_16BIT_TC_LSB_MASK ): pFncGetPixel = GetPixelFor_16BIT_TC_LSB_MASK; break;
452 0 : case( BMP_FORMAT_24BIT_TC_BGR ): pFncGetPixel = GetPixelFor_24BIT_TC_BGR; break;
453 0 : case( BMP_FORMAT_24BIT_TC_RGB ): pFncGetPixel = GetPixelFor_24BIT_TC_RGB; break;
454 0 : case( BMP_FORMAT_24BIT_TC_MASK ): pFncGetPixel = GetPixelFor_24BIT_TC_MASK; break;
455 0 : case( BMP_FORMAT_32BIT_TC_ABGR ): pFncGetPixel = GetPixelFor_32BIT_TC_ABGR; break;
456 0 : case( BMP_FORMAT_32BIT_TC_ARGB ): pFncGetPixel = GetPixelFor_32BIT_TC_ARGB; break;
457 0 : case( BMP_FORMAT_32BIT_TC_BGRA ): pFncGetPixel = GetPixelFor_32BIT_TC_BGRA; break;
458 0 : case( BMP_FORMAT_32BIT_TC_RGBA ): pFncGetPixel = GetPixelFor_32BIT_TC_RGBA; break;
459 0 : case( BMP_FORMAT_32BIT_TC_MASK ): pFncGetPixel = GetPixelFor_32BIT_TC_MASK; break;
460 :
461 : default:
462 0 : pFncGetPixel = NULL;
463 0 : break;
464 : }
465 :
466 0 : if( pFncGetPixel )
467 : {
468 0 : const ColorMask aDummyMask;
469 :
470 0 : for( long nX = 0L, nWidth = mpBuffer->mnWidth; nX < nWidth; nX++ )
471 0 : SetPixel( nY, nX, pFncGetPixel( aSrcScanline, nX, aDummyMask ) );
472 : }
473 : }
474 : }
475 0 : }
476 :
477 0 : void BitmapWriteAccess::CopyBuffer( const BitmapReadAccess& rReadAcc )
478 : {
479 : DBG_ASSERT( ( HasPalette() && rReadAcc.HasPalette() ) || ( !HasPalette() && !rReadAcc.HasPalette() ), "No copying possible between palette bitmap and TC bitmap!" );
480 :
481 0 : if( ( GetScanlineFormat() == rReadAcc.GetScanlineFormat() ) &&
482 0 : ( GetScanlineSize() == rReadAcc.GetScanlineSize() ) )
483 : {
484 0 : const long nHeight = std::min( mpBuffer->mnHeight, rReadAcc.Height() );
485 0 : const sal_uLong nCount = nHeight * mpBuffer->mnScanlineSize;
486 :
487 0 : memcpy( mpBuffer->mpBits, rReadAcc.GetBuffer(), nCount );
488 : }
489 : else
490 0 : for( long nY = 0L, nHeight = std::min( mpBuffer->mnHeight, rReadAcc.Height() ); nY < nHeight; nY++ )
491 0 : CopyScanline( nY, rReadAcc );
492 0 : }
493 :
494 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|