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
27 #include <vcl/salbtype.hxx>
28 #include <vcl/bitmap.hxx>
29 #include <vcl/bmpacc.hxx>
30
31 #include <impbmp.hxx>
32
33 #include <string.h>
34
35 // --------------------
36 // - BitmapReadAccess -
37 // --------------------
38
BitmapReadAccess(Bitmap & rBitmap,sal_Bool bModify)39 BitmapReadAccess::BitmapReadAccess( Bitmap& rBitmap, sal_Bool bModify ) :
40 mpBuffer ( NULL ),
41 mpScanBuf ( NULL ),
42 mFncGetPixel ( NULL ),
43 mFncSetPixel ( NULL ),
44 mbModify ( bModify )
45 {
46 ImplCreate( rBitmap );
47 }
48
49 // ------------------------------------------------------------------
50
BitmapReadAccess(Bitmap & rBitmap)51 BitmapReadAccess::BitmapReadAccess( Bitmap& rBitmap ) :
52 mpBuffer ( NULL ),
53 mpScanBuf ( NULL ),
54 mFncGetPixel ( NULL ),
55 mFncSetPixel ( NULL ),
56 mbModify ( sal_False )
57 {
58 ImplCreate( rBitmap );
59 }
60
61 // ------------------------------------------------------------------
62
~BitmapReadAccess()63 BitmapReadAccess::~BitmapReadAccess()
64 {
65 ImplDestroy();
66 }
67
68 // ------------------------------------------------------------------
69
ImplCreate(Bitmap & rBitmap)70 void BitmapReadAccess::ImplCreate( Bitmap& rBitmap )
71 {
72 ImpBitmap* pImpBmp = rBitmap.ImplGetImpBitmap();
73
74 DBG_ASSERT( pImpBmp, "Forbidden Access to empty bitmap!" );
75
76 if( pImpBmp )
77 {
78 if( mbModify && !maBitmap.ImplGetImpBitmap() )
79 {
80 rBitmap.ImplMakeUnique();
81 pImpBmp = rBitmap.ImplGetImpBitmap();
82 }
83 else
84 {
85 DBG_ASSERT( !mbModify || pImpBmp->ImplGetRefCount() == 2,
86 "Unpredictable results: bitmap is referenced more than once!" );
87 }
88
89 mpBuffer = pImpBmp->ImplAcquireBuffer( !mbModify );
90
91 if( !mpBuffer )
92 {
93 ImpBitmap* pNewImpBmp = new ImpBitmap;
94
95 if( pNewImpBmp->ImplCreate( *pImpBmp, rBitmap.GetBitCount() ) )
96 {
97 pImpBmp = pNewImpBmp;
98 rBitmap.ImplSetImpBitmap( pImpBmp );
99 mpBuffer = pImpBmp->ImplAcquireBuffer( !mbModify );
100 }
101 else
102 delete pNewImpBmp;
103 }
104
105 if( mpBuffer )
106 {
107 const long nHeight = mpBuffer->mnHeight;
108 Scanline pTmpLine = mpBuffer->mpBits;
109
110 mpScanBuf = new Scanline[ nHeight ];
111 maColorMask = mpBuffer->maColorMask;
112
113 if( BMP_SCANLINE_ADJUSTMENT( mpBuffer->mnFormat ) == BMP_FORMAT_TOP_DOWN )
114 {
115 for( long nY = 0L; nY < nHeight; nY++, pTmpLine += mpBuffer->mnScanlineSize )
116 mpScanBuf[ nY ] = pTmpLine;
117 }
118 else
119 {
120 for( long nY = nHeight - 1; nY >= 0; nY--, pTmpLine += mpBuffer->mnScanlineSize )
121 mpScanBuf[ nY ] = pTmpLine;
122 }
123
124 if( !ImplSetAccessPointers( BMP_SCANLINE_FORMAT( mpBuffer->mnFormat ) ) )
125 {
126 delete[] mpScanBuf;
127 mpScanBuf = NULL;
128
129 pImpBmp->ImplReleaseBuffer( mpBuffer, !mbModify );
130 mpBuffer = NULL;
131 }
132 else
133 maBitmap = rBitmap;
134 }
135 }
136 }
137
138 // ------------------------------------------------------------------
139
ImplDestroy()140 void BitmapReadAccess::ImplDestroy()
141 {
142 ImpBitmap* pImpBmp = maBitmap.ImplGetImpBitmap();
143
144 delete[] mpScanBuf;
145 mpScanBuf = NULL;
146
147 if( mpBuffer && pImpBmp )
148 {
149 pImpBmp->ImplReleaseBuffer( mpBuffer, !mbModify );
150 mpBuffer = NULL;
151 }
152 }
153
154 // ------------------------------------------------------------------
155
ImplSetAccessPointers(sal_uLong nFormat)156 sal_Bool BitmapReadAccess::ImplSetAccessPointers( sal_uLong nFormat )
157 {
158 sal_Bool bRet = sal_True;
159
160 switch( nFormat )
161 {
162 CASE_FORMAT( _1BIT_MSB_PAL )
163 CASE_FORMAT( _1BIT_LSB_PAL )
164 CASE_FORMAT( _4BIT_MSN_PAL )
165 CASE_FORMAT( _4BIT_LSN_PAL )
166 CASE_FORMAT( _8BIT_PAL )
167 CASE_FORMAT( _8BIT_TC_MASK )
168 CASE_FORMAT( _16BIT_TC_MSB_MASK )
169 CASE_FORMAT( _16BIT_TC_LSB_MASK )
170 CASE_FORMAT( _24BIT_TC_BGR )
171 CASE_FORMAT( _24BIT_TC_RGB )
172 CASE_FORMAT( _24BIT_TC_MASK )
173 CASE_FORMAT( _32BIT_TC_ABGR )
174 CASE_FORMAT( _32BIT_TC_ARGB )
175 CASE_FORMAT( _32BIT_TC_BGRA )
176 CASE_FORMAT( _32BIT_TC_RGBA )
177 CASE_FORMAT( _32BIT_TC_MASK )
178
179 default:
180 bRet = sal_False;
181 break;
182 }
183
184 return bRet;
185 }
186
187 // ------------------------------------------------------------------
188
ImplZeroInitUnusedBits()189 void BitmapReadAccess::ImplZeroInitUnusedBits()
190 {
191 const sal_uInt32 nWidth = Width(), nHeight = Height(), nScanSize = GetScanlineSize();
192
193 if( nWidth && nHeight && nScanSize && GetBuffer() )
194 {
195 sal_uInt32 nBits;
196 bool bMsb;
197
198 const sal_uLong nScanlineFormat = GetScanlineFormat();
199 switch( nScanlineFormat )
200 {
201 case( BMP_FORMAT_1BIT_MSB_PAL ):
202 nBits = 1;
203 bMsb = true;
204 break;
205
206 case( BMP_FORMAT_1BIT_LSB_PAL ):
207 nBits = 1;
208 bMsb = false;
209 break;
210
211 case( BMP_FORMAT_4BIT_MSN_PAL ):
212 nBits = 4;
213 bMsb = true;
214 break;
215
216 case( BMP_FORMAT_4BIT_LSN_PAL ):
217 nBits = 4;
218 bMsb = false;
219 break;
220
221 case( BMP_FORMAT_8BIT_PAL ):
222 case( BMP_FORMAT_8BIT_TC_MASK ):
223 bMsb = true;
224 nBits = 8;
225 break;
226
227 case( BMP_FORMAT_16BIT_TC_MSB_MASK ):
228 case( BMP_FORMAT_16BIT_TC_LSB_MASK ):
229 bMsb = true;
230 nBits = 16;
231 break;
232
233 case( BMP_FORMAT_24BIT_TC_BGR ):
234 case( BMP_FORMAT_24BIT_TC_RGB ):
235 case( BMP_FORMAT_24BIT_TC_MASK ):
236 bMsb = true;
237 nBits = 24;
238 break;
239
240 case( BMP_FORMAT_32BIT_TC_ABGR ):
241 case( BMP_FORMAT_32BIT_TC_ARGB ):
242 case( BMP_FORMAT_32BIT_TC_BGRA ):
243 case( BMP_FORMAT_32BIT_TC_RGBA ):
244 case( BMP_FORMAT_32BIT_TC_MASK ):
245 bMsb = true;
246 nBits = 32;
247 break;
248
249 default:
250 {
251 DBG_ERROR( "BitmapWriteAccess::ZeroInitUnusedBits: Unsupported pixel format");
252 nBits = 0;
253 bMsb = true;
254 }
255 break;
256 }
257
258 nBits *= nWidth;
259 if( nScanSize % 4 || !bMsb )
260 {
261 DBG_ASSERT( 8*nScanSize >= nBits,
262 "BitmapWriteAccess::ZeroInitUnusedBits: span size smaller than width?!");
263 const sal_uInt32 nLeftOverBits = 8*sizeof(sal_uInt8)*nScanSize - nBits;
264 if( nLeftOverBits != 0 ) // else there is really nothing to do
265 {
266 const sal_uInt32 nBytes = (nLeftOverBits + 7U) >> 3U;
267 sal_uInt8 nMask;
268
269 if( bMsb )
270 nMask = static_cast<sal_uInt8>(0xffU << (nLeftOverBits & 3UL));
271 else
272 nMask = static_cast<sal_uInt8>(0xffU >> (nLeftOverBits & 3UL));
273
274 sal_uInt8* pLastBytes = (sal_uInt8*)GetBuffer() + ( nScanSize - nBytes );
275 for( sal_uInt32 i = 0; i < nHeight; i++, pLastBytes += nScanSize )
276 {
277 *pLastBytes &= nMask;
278 for( sal_uInt32 j = 1; j < nBytes; j++ )
279 pLastBytes[j] = 0;
280 }
281 }
282 }
283 else if( nBits & 0x1f )
284 {
285 sal_uInt32 nMask = 0xffffffff << ( ( nScanSize << 3 ) - nBits );
286 sal_uInt8* pLast4Bytes = (sal_uInt8*) GetBuffer() + ( nScanSize - 4 );
287
288 #ifdef OSL_LITENDIAN
289 nMask = SWAPLONG( nMask );
290 #endif
291 for( sal_uInt32 i = 0; i < nHeight; i++, pLast4Bytes += nScanSize )
292 ( *(sal_uInt32*) pLast4Bytes ) &= nMask;
293 }
294 }
295 }
296
297 // ------------------------------------------------------------------
298
Flush()299 void BitmapReadAccess::Flush()
300 {
301 ImplDestroy();
302 }
303
304 // ------------------------------------------------------------------
305
ReAccess(sal_Bool bModify)306 void BitmapReadAccess::ReAccess( sal_Bool bModify )
307 {
308 const ImpBitmap* pImpBmp = maBitmap.ImplGetImpBitmap();
309
310 DBG_ASSERT( !mpBuffer, "No ReAccess possible while bitmap is being accessed!" );
311 DBG_ASSERT( pImpBmp && ( pImpBmp->ImplGetRefCount() > 1UL ), "Accessed bitmap does not exist anymore!" );
312
313 if( !mpBuffer && pImpBmp && ( pImpBmp->ImplGetRefCount() > 1UL ) )
314 {
315 mbModify = bModify;
316 ImplCreate( maBitmap );
317 }
318 }
319
320 // ------------------------------------------------------------------
321
GetBestPaletteIndex(const BitmapColor & rBitmapColor) const322 sal_uInt16 BitmapReadAccess::GetBestPaletteIndex( const BitmapColor& rBitmapColor ) const
323 {
324 return( HasPalette() ? mpBuffer->maPalette.GetBestIndex( rBitmapColor ) : 0 );
325 }
326
GetInterpolatedColorWithFallback(double fY,double fX,const BitmapColor & rFallback) const327 BitmapColor BitmapReadAccess::GetInterpolatedColorWithFallback( double fY, double fX, const BitmapColor& rFallback ) const
328 {
329 // ask directly doubles >= 0.0 here to avoid rounded values of 0 at small negative
330 // double values, e.g. static_cast< sal_Int32 >(-0.25) is 0, not -1, but *has* to be outside (!)
331 if(mpBuffer && fX >= 0.0 && fY >= 0.0)
332 {
333 const sal_Int32 nX(static_cast< sal_Int32 >(fX));
334 const sal_Int32 nY(static_cast< sal_Int32 >(fY));
335
336 if(nX < mpBuffer->mnWidth && nY < mpBuffer->mnHeight)
337 {
338 // get base-return value from inside pixel
339 BitmapColor aRetval(GetColor(nY, nX));
340
341 // calculate deltas and indices for neighbour accesses
342 sal_Int16 nDeltaX((fX - (nX + 0.5)) * 255.0); // [-255 .. 255]
343 sal_Int16 nDeltaY((fY - (nY + 0.5)) * 255.0); // [-255 .. 255]
344 sal_Int16 nIndX(0);
345 sal_Int16 nIndY(0);
346
347 if(nDeltaX > 0)
348 {
349 nIndX = nX + 1;
350 }
351 else
352 {
353 nIndX = nX - 1;
354 nDeltaX = -nDeltaX;
355 }
356
357 if(nDeltaY > 0)
358 {
359 nIndY = nY + 1;
360 }
361 else
362 {
363 nIndY = nY - 1;
364 nDeltaY = -nDeltaY;
365 }
366
367 // get right/left neighbour
368 BitmapColor aXCol(rFallback);
369
370 if(nDeltaX && nIndX >= 0 && nIndX < mpBuffer->mnWidth)
371 {
372 aXCol = GetColor(nY, nIndX);
373 }
374
375 // get top/bottom neighbour
376 BitmapColor aYCol(rFallback);
377
378 if(nDeltaY && nIndY >= 0 && nIndY < mpBuffer->mnHeight)
379 {
380 aYCol = GetColor(nIndY, nX);
381 }
382
383 // get one of four edge neighbours
384 BitmapColor aXYCol(rFallback);
385
386 if(nDeltaX && nDeltaY && nIndX >=0 && nIndY >= 0 && nIndX < mpBuffer->mnWidth && nIndY < mpBuffer->mnHeight)
387 {
388 aXYCol = GetColor(nIndY, nIndX);
389 }
390
391 // merge return value with right/left neighbour
392 if(aXCol != aRetval)
393 {
394 aRetval.Merge(aXCol, 255 - nDeltaX);
395 }
396
397 // merge top/bottom neighbour with edge
398 if(aYCol != aXYCol)
399 {
400 aYCol.Merge(aXYCol, 255 - nDeltaX);
401 }
402
403 // merge return value with already merged top/bottom neighbour
404 if(aRetval != aYCol)
405 {
406 aRetval.Merge(aYCol, 255 - nDeltaY);
407 }
408
409 return aRetval;
410 }
411 }
412
413 return rFallback;
414 }
415
GetColorWithFallback(double fY,double fX,const BitmapColor & rFallback) const416 BitmapColor BitmapReadAccess::GetColorWithFallback( double fY, double fX, const BitmapColor& rFallback ) const
417 {
418 // ask directly doubles >= 0.0 here to avoid rounded values of 0 at small negative
419 // double values, e.g. static_cast< sal_Int32 >(-0.25) is 0, not -1, but *has* to be outside (!)
420 if(mpBuffer && fX >= 0.0 && fY >= 0.0)
421 {
422 const sal_Int32 nX(static_cast< sal_Int32 >(fX));
423 const sal_Int32 nY(static_cast< sal_Int32 >(fY));
424
425 if(nX < mpBuffer->mnWidth && nY < mpBuffer->mnHeight)
426 {
427 return GetColor(nY, nX);
428 }
429 }
430
431 return rFallback;
432 }
433
GetColorWithFallback(long nY,long nX,const BitmapColor & rFallback) const434 BitmapColor BitmapReadAccess::GetColorWithFallback( long nY, long nX, const BitmapColor& rFallback ) const
435 {
436 if(mpBuffer)
437 {
438 if(nX >= 0 && nY >= 0 && nX < mpBuffer->mnWidth && nY < mpBuffer->mnHeight)
439 {
440 return GetColor(nY, nX);
441 }
442 }
443
444 return rFallback;
445 }
446
447 // ---------------------
448 // - BitmapWriteAccess -
449 // ---------------------
450
BitmapWriteAccess(Bitmap & rBitmap)451 BitmapWriteAccess::BitmapWriteAccess( Bitmap& rBitmap ) :
452 BitmapReadAccess( rBitmap, sal_True ),
453 mpLineColor ( NULL ),
454 mpFillColor ( NULL )
455 {
456 }
457
458 // ------------------------------------------------------------------
459
~BitmapWriteAccess()460 BitmapWriteAccess::~BitmapWriteAccess()
461 {
462 delete mpLineColor;
463 delete mpFillColor;
464 }
465
466 // ------------------------------------------------------------------
467
CopyScanline(long nY,const BitmapReadAccess & rReadAcc)468 void BitmapWriteAccess::CopyScanline( long nY, const BitmapReadAccess& rReadAcc )
469 {
470 DBG_ASSERT( ( nY >= 0 ) && ( nY < mpBuffer->mnHeight ), "y-coordinate in destination out of range!" );
471 DBG_ASSERT( nY < rReadAcc.Height(), "y-coordinate in source out of range!" );
472 DBG_ASSERT( ( HasPalette() && rReadAcc.HasPalette() ) || ( !HasPalette() && !rReadAcc.HasPalette() ), "No copying possible between palette bitmap and TC bitmap!" );
473
474 if( ( GetScanlineFormat() == rReadAcc.GetScanlineFormat() ) &&
475 ( GetScanlineSize() >= rReadAcc.GetScanlineSize() ) )
476 {
477 memcpy( mpScanBuf[ nY ], rReadAcc.GetScanline( nY ), rReadAcc.GetScanlineSize() );
478 }
479 else
480 // TODO: use fastbmp infrastructure
481 for( long nX = 0L, nWidth = Min( mpBuffer->mnWidth, rReadAcc.Width() ); nX < nWidth; nX++ )
482 SetPixel( nY, nX, rReadAcc.GetPixel( nY, nX ) );
483 }
484
485 // ------------------------------------------------------------------
486
CopyScanline(long nY,ConstScanline aSrcScanline,sal_uLong nSrcScanlineFormat,sal_uLong nSrcScanlineSize)487 void BitmapWriteAccess::CopyScanline( long nY, ConstScanline aSrcScanline,
488 sal_uLong nSrcScanlineFormat, sal_uLong nSrcScanlineSize )
489 {
490 const sal_uLong nFormat = BMP_SCANLINE_FORMAT( nSrcScanlineFormat );
491
492 DBG_ASSERT( ( nY >= 0 ) && ( nY < mpBuffer->mnHeight ), "y-coordinate in destination out of range!" );
493 DBG_ASSERT( ( HasPalette() && nFormat <= BMP_FORMAT_8BIT_PAL ) ||
494 ( !HasPalette() && nFormat > BMP_FORMAT_8BIT_PAL ),
495 "No copying possible between palette and non palette scanlines!" );
496
497 const sal_uLong nCount = Min( GetScanlineSize(), nSrcScanlineSize );
498
499 if( nCount )
500 {
501 if( GetScanlineFormat() == BMP_SCANLINE_FORMAT( nSrcScanlineFormat ) )
502 memcpy( mpScanBuf[ nY ], aSrcScanline, nCount );
503 else
504 {
505 DBG_ASSERT( nFormat != BMP_FORMAT_8BIT_TC_MASK &&
506 nFormat != BMP_FORMAT_16BIT_TC_MSB_MASK && nFormat != BMP_FORMAT_16BIT_TC_LSB_MASK &&
507 nFormat != BMP_FORMAT_24BIT_TC_MASK && nFormat != BMP_FORMAT_32BIT_TC_MASK,
508 "No support for pixel formats with color masks yet!" );
509
510 // TODO: use fastbmp infrastructure
511 FncGetPixel pFncGetPixel;
512
513 switch( nFormat )
514 {
515 case( BMP_FORMAT_1BIT_MSB_PAL ): pFncGetPixel = GetPixelFor_1BIT_MSB_PAL; break;
516 case( BMP_FORMAT_1BIT_LSB_PAL ): pFncGetPixel = GetPixelFor_1BIT_LSB_PAL; break;
517 case( BMP_FORMAT_4BIT_MSN_PAL ): pFncGetPixel = GetPixelFor_4BIT_MSN_PAL; break;
518 case( BMP_FORMAT_4BIT_LSN_PAL ): pFncGetPixel = GetPixelFor_4BIT_LSN_PAL; break;
519 case( BMP_FORMAT_8BIT_PAL ): pFncGetPixel = GetPixelFor_8BIT_PAL; break;
520 case( BMP_FORMAT_8BIT_TC_MASK ): pFncGetPixel = GetPixelFor_8BIT_TC_MASK; break;
521 case( BMP_FORMAT_16BIT_TC_MSB_MASK ): pFncGetPixel = GetPixelFor_16BIT_TC_MSB_MASK; break;
522 case( BMP_FORMAT_16BIT_TC_LSB_MASK ): pFncGetPixel = GetPixelFor_16BIT_TC_LSB_MASK; break;
523 case( BMP_FORMAT_24BIT_TC_BGR ): pFncGetPixel = GetPixelFor_24BIT_TC_BGR; break;
524 case( BMP_FORMAT_24BIT_TC_RGB ): pFncGetPixel = GetPixelFor_24BIT_TC_RGB; break;
525 case( BMP_FORMAT_24BIT_TC_MASK ): pFncGetPixel = GetPixelFor_24BIT_TC_MASK; break;
526 case( BMP_FORMAT_32BIT_TC_ABGR ): pFncGetPixel = GetPixelFor_32BIT_TC_ABGR; break;
527 case( BMP_FORMAT_32BIT_TC_ARGB ): pFncGetPixel = GetPixelFor_32BIT_TC_ARGB; break;
528 case( BMP_FORMAT_32BIT_TC_BGRA ): pFncGetPixel = GetPixelFor_32BIT_TC_BGRA; break;
529 case( BMP_FORMAT_32BIT_TC_RGBA ): pFncGetPixel = GetPixelFor_32BIT_TC_RGBA; break;
530 case( BMP_FORMAT_32BIT_TC_MASK ): pFncGetPixel = GetPixelFor_32BIT_TC_MASK; break;
531
532 default:
533 pFncGetPixel = NULL;
534 break;
535 }
536
537 if( pFncGetPixel )
538 {
539 const ColorMask aDummyMask;
540
541 for( long nX = 0L, nWidth = mpBuffer->mnWidth; nX < nWidth; nX++ )
542 SetPixel( nY, nX, pFncGetPixel( aSrcScanline, nX, aDummyMask ) );
543 }
544 }
545 }
546 }
547
548
549 // ------------------------------------------------------------------
550
CopyBuffer(const BitmapReadAccess & rReadAcc)551 void BitmapWriteAccess::CopyBuffer( const BitmapReadAccess& rReadAcc )
552 {
553 DBG_ASSERT( ( HasPalette() && rReadAcc.HasPalette() ) || ( !HasPalette() && !rReadAcc.HasPalette() ), "No copying possible between palette bitmap and TC bitmap!" );
554
555 if( ( GetScanlineFormat() == rReadAcc.GetScanlineFormat() ) &&
556 ( GetScanlineSize() == rReadAcc.GetScanlineSize() ) )
557 {
558 const long nHeight = Min( mpBuffer->mnHeight, rReadAcc.Height() );
559 const sal_uLong nCount = nHeight * mpBuffer->mnScanlineSize;
560
561 memcpy( mpBuffer->mpBits, rReadAcc.GetBuffer(), nCount );
562 }
563 else
564 for( long nY = 0L, nHeight = Min( mpBuffer->mnHeight, rReadAcc.Height() ); nY < nHeight; nY++ )
565 CopyScanline( nY, rReadAcc );
566 }
567