1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <vcl/salbtype.hxx>
21 #include <vcl/bitmap.hxx>
22 #include <vcl/bmpacc.hxx>
26 #include <osl/diagnose.h>
30 BitmapInfoAccess::BitmapInfoAccess( Bitmap
& rBitmap
, BitmapAccessMode nMode
) :
32 mnAccessMode ( nMode
)
34 ImplCreate( rBitmap
);
37 BitmapInfoAccess::BitmapInfoAccess( Bitmap
& rBitmap
) :
39 mnAccessMode ( BITMAP_INFO_ACCESS
)
41 ImplCreate( rBitmap
);
44 BitmapInfoAccess::~BitmapInfoAccess()
49 void BitmapInfoAccess::ImplCreate( Bitmap
& rBitmap
)
51 ImpBitmap
* pImpBmp
= rBitmap
.ImplGetImpBitmap();
53 DBG_ASSERT( pImpBmp
, "Forbidden Access to empty bitmap!" );
57 if( mnAccessMode
== BITMAP_WRITE_ACCESS
&& !maBitmap
.ImplGetImpBitmap() )
59 rBitmap
.ImplMakeUnique();
60 pImpBmp
= rBitmap
.ImplGetImpBitmap();
64 DBG_ASSERT( mnAccessMode
!= BITMAP_WRITE_ACCESS
||
65 pImpBmp
->ImplGetRefCount() == 2,
66 "Unpredictable results: bitmap is referenced more than once!" );
69 mpBuffer
= pImpBmp
->ImplAcquireBuffer( mnAccessMode
);
73 ImpBitmap
* pNewImpBmp
= new ImpBitmap
;
75 if( pNewImpBmp
->ImplCreate( *pImpBmp
, rBitmap
.GetBitCount() ) )
78 rBitmap
.ImplSetImpBitmap( pImpBmp
);
79 mpBuffer
= pImpBmp
->ImplAcquireBuffer( mnAccessMode
);
89 void BitmapInfoAccess::ImplDestroy()
91 ImpBitmap
* pImpBmp
= maBitmap
.ImplGetImpBitmap();
93 if( mpBuffer
&& pImpBmp
)
95 pImpBmp
->ImplReleaseBuffer( mpBuffer
, mnAccessMode
);
100 sal_uInt16
BitmapInfoAccess::GetBestPaletteIndex( const BitmapColor
& rBitmapColor
) const
102 return( HasPalette() ? mpBuffer
->maPalette
.GetBestIndex( rBitmapColor
) : 0 );
105 BitmapReadAccess::BitmapReadAccess( Bitmap
& rBitmap
, BitmapAccessMode nMode
) :
106 BitmapInfoAccess( rBitmap
, nMode
),
108 mFncGetPixel ( NULL
),
109 mFncSetPixel ( NULL
)
111 ImplInitScanBuffer( rBitmap
);
114 BitmapReadAccess::BitmapReadAccess( Bitmap
& rBitmap
) :
115 BitmapInfoAccess( rBitmap
, BITMAP_READ_ACCESS
),
117 mFncGetPixel ( NULL
),
118 mFncSetPixel ( NULL
)
120 ImplInitScanBuffer( rBitmap
);
123 BitmapReadAccess::~BitmapReadAccess()
125 ImplClearScanBuffer();
128 void BitmapReadAccess::ImplInitScanBuffer( Bitmap
& rBitmap
)
130 ImpBitmap
* pImpBmp
= rBitmap
.ImplGetImpBitmap();
132 if( pImpBmp
&& mpBuffer
)
134 const long nHeight
= mpBuffer
->mnHeight
;
135 Scanline pTmpLine
= mpBuffer
->mpBits
;
137 mpScanBuf
= new Scanline
[ nHeight
];
138 maColorMask
= mpBuffer
->maColorMask
;
140 if( BMP_SCANLINE_ADJUSTMENT( mpBuffer
->mnFormat
) == BMP_FORMAT_TOP_DOWN
)
142 for( long nY
= 0L; nY
< nHeight
; nY
++, pTmpLine
+= mpBuffer
->mnScanlineSize
)
143 mpScanBuf
[ nY
] = pTmpLine
;
147 for( long nY
= nHeight
- 1; nY
>= 0; nY
--, pTmpLine
+= mpBuffer
->mnScanlineSize
)
148 mpScanBuf
[ nY
] = pTmpLine
;
151 if( !ImplSetAccessPointers( BMP_SCANLINE_FORMAT( mpBuffer
->mnFormat
) ) )
156 pImpBmp
->ImplReleaseBuffer( mpBuffer
, mnAccessMode
);
162 void BitmapReadAccess::ImplClearScanBuffer()
168 bool BitmapReadAccess::ImplSetAccessPointers( sal_uLong nFormat
)
174 case BMP_FORMAT_1BIT_MSB_PAL
:
176 mFncGetPixel
= GetPixelFor_1BIT_MSB_PAL
;
177 mFncSetPixel
= SetPixelFor_1BIT_MSB_PAL
;
180 case BMP_FORMAT_1BIT_LSB_PAL
:
182 mFncGetPixel
= GetPixelFor_1BIT_LSB_PAL
;
183 mFncSetPixel
= SetPixelFor_1BIT_LSB_PAL
;
186 case BMP_FORMAT_4BIT_MSN_PAL
:
188 mFncGetPixel
= GetPixelFor_4BIT_MSN_PAL
;
189 mFncSetPixel
= SetPixelFor_4BIT_MSN_PAL
;
192 case BMP_FORMAT_4BIT_LSN_PAL
:
194 mFncGetPixel
= GetPixelFor_4BIT_LSN_PAL
;
195 mFncSetPixel
= SetPixelFor_4BIT_LSN_PAL
;
198 case BMP_FORMAT_8BIT_PAL
:
200 mFncGetPixel
= GetPixelFor_8BIT_PAL
;
201 mFncSetPixel
= SetPixelFor_8BIT_PAL
;
204 case BMP_FORMAT_8BIT_TC_MASK
:
206 mFncGetPixel
= GetPixelFor_8BIT_TC_MASK
;
207 mFncSetPixel
= SetPixelFor_8BIT_TC_MASK
;
210 case BMP_FORMAT_16BIT_TC_MSB_MASK
:
212 mFncGetPixel
= GetPixelFor_16BIT_TC_MSB_MASK
;
213 mFncSetPixel
= SetPixelFor_16BIT_TC_MSB_MASK
;
216 case BMP_FORMAT_16BIT_TC_LSB_MASK
:
218 mFncGetPixel
= GetPixelFor_16BIT_TC_LSB_MASK
;
219 mFncSetPixel
= SetPixelFor_16BIT_TC_LSB_MASK
;
222 case BMP_FORMAT_24BIT_TC_BGR
:
224 mFncGetPixel
= GetPixelFor_24BIT_TC_BGR
;
225 mFncSetPixel
= SetPixelFor_24BIT_TC_BGR
;
228 case BMP_FORMAT_24BIT_TC_RGB
:
230 mFncGetPixel
= GetPixelFor_24BIT_TC_RGB
;
231 mFncSetPixel
= SetPixelFor_24BIT_TC_RGB
;
234 case BMP_FORMAT_24BIT_TC_MASK
:
236 mFncGetPixel
= GetPixelFor_24BIT_TC_MASK
;
237 mFncSetPixel
= SetPixelFor_24BIT_TC_MASK
;
240 case BMP_FORMAT_32BIT_TC_ABGR
:
242 mFncGetPixel
= GetPixelFor_32BIT_TC_ABGR
;
243 mFncSetPixel
= SetPixelFor_32BIT_TC_ABGR
;
246 case BMP_FORMAT_32BIT_TC_ARGB
:
248 mFncGetPixel
= GetPixelFor_32BIT_TC_ARGB
;
249 mFncSetPixel
= SetPixelFor_32BIT_TC_ARGB
;
252 case BMP_FORMAT_32BIT_TC_BGRA
:
254 mFncGetPixel
= GetPixelFor_32BIT_TC_BGRA
;
255 mFncSetPixel
= SetPixelFor_32BIT_TC_BGRA
;
258 case BMP_FORMAT_32BIT_TC_RGBA
:
260 mFncGetPixel
= GetPixelFor_32BIT_TC_RGBA
;
261 mFncSetPixel
= SetPixelFor_32BIT_TC_RGBA
;
264 case BMP_FORMAT_32BIT_TC_MASK
:
266 mFncGetPixel
= GetPixelFor_32BIT_TC_MASK
;
267 mFncSetPixel
= SetPixelFor_32BIT_TC_MASK
;
279 void BitmapReadAccess::ImplZeroInitUnusedBits()
281 const sal_uInt32 nWidth
= Width(), nHeight
= Height(), nScanSize
= GetScanlineSize();
283 if( nWidth
&& nHeight
&& nScanSize
&& GetBuffer() )
288 const sal_uLong nScanlineFormat
= GetScanlineFormat();
289 switch( nScanlineFormat
)
291 case( BMP_FORMAT_1BIT_MSB_PAL
):
296 case( BMP_FORMAT_1BIT_LSB_PAL
):
301 case( BMP_FORMAT_4BIT_MSN_PAL
):
306 case( BMP_FORMAT_4BIT_LSN_PAL
):
311 case( BMP_FORMAT_8BIT_PAL
):
312 case( BMP_FORMAT_8BIT_TC_MASK
):
317 case( BMP_FORMAT_16BIT_TC_MSB_MASK
):
318 case( BMP_FORMAT_16BIT_TC_LSB_MASK
):
323 case( BMP_FORMAT_24BIT_TC_BGR
):
324 case( BMP_FORMAT_24BIT_TC_RGB
):
325 case( BMP_FORMAT_24BIT_TC_MASK
):
330 case( BMP_FORMAT_32BIT_TC_ABGR
):
331 case( BMP_FORMAT_32BIT_TC_ARGB
):
332 case( BMP_FORMAT_32BIT_TC_BGRA
):
333 case( BMP_FORMAT_32BIT_TC_RGBA
):
334 case( BMP_FORMAT_32BIT_TC_MASK
):
341 OSL_FAIL( "BitmapWriteAccess::ZeroInitUnusedBits: Unsupported pixel format");
349 if( nScanSize
% 4 || !bMsb
)
351 DBG_ASSERT( 8*nScanSize
>= nBits
,
352 "BitmapWriteAccess::ZeroInitUnusedBits: span size smaller than width?!");
353 const sal_uInt32 nLeftOverBits
= 8*sizeof(sal_uInt8
)*nScanSize
- nBits
;
354 if( nLeftOverBits
!= 0 ) // else there is really nothing to do
356 const sal_uInt32 nBytes
= (nLeftOverBits
+ 7U) >> 3U;
360 nMask
= static_cast<sal_uInt8
>(0xffU
<< (nLeftOverBits
& 3UL));
362 nMask
= static_cast<sal_uInt8
>(0xffU
>> (nLeftOverBits
& 3UL));
364 sal_uInt8
* pLastBytes
= (sal_uInt8
*)GetBuffer() + ( nScanSize
- nBytes
);
365 for( sal_uInt32 i
= 0; i
< nHeight
; i
++, pLastBytes
+= nScanSize
)
367 *pLastBytes
&= nMask
;
368 for( sal_uInt32 j
= 1; j
< nBytes
; j
++ )
373 else if( nBits
& 0x1f )
375 sal_uInt32 nMask
= 0xffffffff << ( ( nScanSize
<< 3 ) - nBits
);
376 sal_uInt8
* pLast4Bytes
= (sal_uInt8
*) GetBuffer() + ( nScanSize
- 4 );
379 nMask
= OSL_SWAPDWORD( nMask
);
381 for( sal_uInt32 i
= 0; i
< nHeight
; i
++, pLast4Bytes
+= nScanSize
)
382 *reinterpret_cast<sal_uInt32
*>(pLast4Bytes
) &= nMask
;
387 BitmapColor
BitmapReadAccess::GetInterpolatedColorWithFallback( double fY
, double fX
, const BitmapColor
& rFallback
) const
389 // ask directly doubles >= 0.0 here to avoid rounded values of 0 at small negative
390 // double values, e.g. static_cast< sal_Int32 >(-0.25) is 0, not -1, but *has* to be outside (!)
391 if(mpBuffer
&& fX
>= 0.0 && fY
>= 0.0)
393 const sal_Int32
nX(static_cast< sal_Int32
>(fX
));
394 const sal_Int32
nY(static_cast< sal_Int32
>(fY
));
396 if(nX
< mpBuffer
->mnWidth
&& nY
< mpBuffer
->mnHeight
)
398 // get base-return value from inside pixel
399 BitmapColor
aRetval(GetColor(nY
, nX
));
401 // calculate deltas and indices for neighbour accesses
402 sal_Int16
nDeltaX((fX
- (nX
+ 0.5)) * 255.0); // [-255 .. 255]
403 sal_Int16
nDeltaY((fY
- (nY
+ 0.5)) * 255.0); // [-255 .. 255]
427 // get right/left neighbour
428 BitmapColor
aXCol(rFallback
);
430 if(nDeltaX
&& nIndX
>= 0 && nIndX
< mpBuffer
->mnWidth
)
432 aXCol
= GetColor(nY
, nIndX
);
435 // get top/bottom neighbour
436 BitmapColor
aYCol(rFallback
);
438 if(nDeltaY
&& nIndY
>= 0 && nIndY
< mpBuffer
->mnHeight
)
440 aYCol
= GetColor(nIndY
, nX
);
443 // get one of four edge neighbours
444 BitmapColor
aXYCol(rFallback
);
446 if(nDeltaX
&& nDeltaY
&& nIndX
>=0 && nIndY
>= 0 && nIndX
< mpBuffer
->mnWidth
&& nIndY
< mpBuffer
->mnHeight
)
448 aXYCol
= GetColor(nIndY
, nIndX
);
451 // merge return value with right/left neighbour
454 aRetval
.Merge(aXCol
, 255 - nDeltaX
);
457 // merge top/bottom neighbour with edge
460 aYCol
.Merge(aXYCol
, 255 - nDeltaX
);
463 // merge return value with already merged top/bottom neighbour
466 aRetval
.Merge(aYCol
, 255 - nDeltaY
);
476 BitmapColor
BitmapReadAccess::GetColorWithFallback( double fY
, double fX
, const BitmapColor
& rFallback
) const
478 // ask directly doubles >= 0.0 here to avoid rounded values of 0 at small negative
479 // double values, e.g. static_cast< sal_Int32 >(-0.25) is 0, not -1, but *has* to be outside (!)
480 if(mpBuffer
&& fX
>= 0.0 && fY
>= 0.0)
482 const sal_Int32
nX(static_cast< sal_Int32
>(fX
));
483 const sal_Int32
nY(static_cast< sal_Int32
>(fY
));
485 if(nX
< mpBuffer
->mnWidth
&& nY
< mpBuffer
->mnHeight
)
487 return GetColor(nY
, nX
);
494 BitmapWriteAccess::BitmapWriteAccess(Bitmap
& rBitmap
)
495 : BitmapReadAccess(rBitmap
, BITMAP_WRITE_ACCESS
)
501 BitmapWriteAccess::~BitmapWriteAccess()
505 void BitmapWriteAccess::CopyScanline( long nY
, const BitmapReadAccess
& rReadAcc
)
507 assert(nY
>= 0 && nY
< mpBuffer
->mnHeight
&& "y-coordinate in destination out of range!");
508 DBG_ASSERT( nY
< rReadAcc
.Height(), "y-coordinate in source out of range!" );
509 DBG_ASSERT( ( HasPalette() && rReadAcc
.HasPalette() ) || ( !HasPalette() && !rReadAcc
.HasPalette() ), "No copying possible between palette bitmap and TC bitmap!" );
511 if( ( GetScanlineFormat() == rReadAcc
.GetScanlineFormat() ) &&
512 ( GetScanlineSize() >= rReadAcc
.GetScanlineSize() ) )
514 memcpy( mpScanBuf
[ nY
], rReadAcc
.GetScanline( nY
), rReadAcc
.GetScanlineSize() );
517 // TODO: use fastbmp infrastructure
518 for( long nX
= 0L, nWidth
= std::min( mpBuffer
->mnWidth
, rReadAcc
.Width() ); nX
< nWidth
; nX
++ )
519 SetPixel( nY
, nX
, rReadAcc
.GetPixel( nY
, nX
) );
522 void BitmapWriteAccess::CopyScanline( long nY
, ConstScanline aSrcScanline
,
523 sal_uLong nSrcScanlineFormat
, sal_uLong nSrcScanlineSize
)
525 const sal_uLong nFormat
= BMP_SCANLINE_FORMAT( nSrcScanlineFormat
);
527 assert(nY
>= 0 && nY
< mpBuffer
->mnHeight
&& "y-coordinate in destination out of range!");
528 DBG_ASSERT( ( HasPalette() && nFormat
<= BMP_FORMAT_8BIT_PAL
) ||
529 ( !HasPalette() && nFormat
> BMP_FORMAT_8BIT_PAL
),
530 "No copying possible between palette and non palette scanlines!" );
532 const sal_uLong nCount
= std::min( GetScanlineSize(), nSrcScanlineSize
);
536 if( GetScanlineFormat() == BMP_SCANLINE_FORMAT( nSrcScanlineFormat
) )
537 memcpy( mpScanBuf
[ nY
], aSrcScanline
, nCount
);
540 DBG_ASSERT( nFormat
!= BMP_FORMAT_8BIT_TC_MASK
&&
541 nFormat
!= BMP_FORMAT_16BIT_TC_MSB_MASK
&& nFormat
!= BMP_FORMAT_16BIT_TC_LSB_MASK
&&
542 nFormat
!= BMP_FORMAT_24BIT_TC_MASK
&& nFormat
!= BMP_FORMAT_32BIT_TC_MASK
,
543 "No support for pixel formats with color masks yet!" );
545 // TODO: use fastbmp infrastructure
546 FncGetPixel pFncGetPixel
;
550 case( BMP_FORMAT_1BIT_MSB_PAL
): pFncGetPixel
= GetPixelFor_1BIT_MSB_PAL
; break;
551 case( BMP_FORMAT_1BIT_LSB_PAL
): pFncGetPixel
= GetPixelFor_1BIT_LSB_PAL
; break;
552 case( BMP_FORMAT_4BIT_MSN_PAL
): pFncGetPixel
= GetPixelFor_4BIT_MSN_PAL
; break;
553 case( BMP_FORMAT_4BIT_LSN_PAL
): pFncGetPixel
= GetPixelFor_4BIT_LSN_PAL
; break;
554 case( BMP_FORMAT_8BIT_PAL
): pFncGetPixel
= GetPixelFor_8BIT_PAL
; break;
555 case( BMP_FORMAT_8BIT_TC_MASK
): pFncGetPixel
= GetPixelFor_8BIT_TC_MASK
; break;
556 case( BMP_FORMAT_16BIT_TC_MSB_MASK
): pFncGetPixel
= GetPixelFor_16BIT_TC_MSB_MASK
; break;
557 case( BMP_FORMAT_16BIT_TC_LSB_MASK
): pFncGetPixel
= GetPixelFor_16BIT_TC_LSB_MASK
; break;
558 case( BMP_FORMAT_24BIT_TC_BGR
): pFncGetPixel
= GetPixelFor_24BIT_TC_BGR
; break;
559 case( BMP_FORMAT_24BIT_TC_RGB
): pFncGetPixel
= GetPixelFor_24BIT_TC_RGB
; break;
560 case( BMP_FORMAT_24BIT_TC_MASK
): pFncGetPixel
= GetPixelFor_24BIT_TC_MASK
; break;
561 case( BMP_FORMAT_32BIT_TC_ABGR
): pFncGetPixel
= GetPixelFor_32BIT_TC_ABGR
; break;
562 case( BMP_FORMAT_32BIT_TC_ARGB
): pFncGetPixel
= GetPixelFor_32BIT_TC_ARGB
; break;
563 case( BMP_FORMAT_32BIT_TC_BGRA
): pFncGetPixel
= GetPixelFor_32BIT_TC_BGRA
; break;
564 case( BMP_FORMAT_32BIT_TC_RGBA
): pFncGetPixel
= GetPixelFor_32BIT_TC_RGBA
; break;
565 case( BMP_FORMAT_32BIT_TC_MASK
): pFncGetPixel
= GetPixelFor_32BIT_TC_MASK
; break;
574 const ColorMask aDummyMask
;
576 for( long nX
= 0L, nWidth
= mpBuffer
->mnWidth
; nX
< nWidth
; nX
++ )
577 SetPixel( nY
, nX
, pFncGetPixel( aSrcScanline
, nX
, aDummyMask
) );
583 void BitmapWriteAccess::CopyBuffer( const BitmapReadAccess
& rReadAcc
)
585 DBG_ASSERT( ( HasPalette() && rReadAcc
.HasPalette() ) || ( !HasPalette() && !rReadAcc
.HasPalette() ), "No copying possible between palette bitmap and TC bitmap!" );
587 if( ( GetScanlineFormat() == rReadAcc
.GetScanlineFormat() ) &&
588 ( GetScanlineSize() == rReadAcc
.GetScanlineSize() ) )
590 const long nHeight
= std::min( mpBuffer
->mnHeight
, rReadAcc
.Height() );
591 const sal_uLong nCount
= nHeight
* mpBuffer
->mnScanlineSize
;
593 memcpy( mpBuffer
->mpBits
, rReadAcc
.GetBuffer(), nCount
);
596 for( long nY
= 0L, nHeight
= std::min( mpBuffer
->mnHeight
, rReadAcc
.Height() ); nY
< nHeight
; nY
++ )
597 CopyScanline( nY
, rReadAcc
);
600 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */