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