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 .
22 static BitmapChecksum
scanlineChecksum(BitmapChecksum nCrc
, const sal_uInt8
* bits
, int lineBitsCount
, sal_uInt8 extraBitsMask
)
24 if( lineBitsCount
/ 8 > 0 )
25 nCrc
= vcl_get_checksum( nCrc
, bits
, lineBitsCount
/ 8 );
26 if( extraBitsMask
!= 0 )
28 sal_uInt8 extraByte
= bits
[ lineBitsCount
/ 8 ] & extraBitsMask
;
29 nCrc
= vcl_get_checksum( nCrc
, &extraByte
, 1 );
34 void SalBitmap::updateChecksum() const
39 BitmapChecksum nCrc
= 0;
40 SalBitmap
* pThis
= const_cast<SalBitmap
*>(this);
41 BitmapBuffer
* pBuf
= pThis
->AcquireBuffer(BitmapAccessMode::Read
);
44 nCrc
= pBuf
->maPalette
.GetChecksum();
45 const int lineBitsCount
= pBuf
->mnWidth
* pBuf
->mnBitCount
;
46 // With 1bpp/4bpp format we need to check only used bits in the last byte.
47 sal_uInt8 extraBitsMask
= 0;
48 if( lineBitsCount
% 8 != 0 )
50 const int extraBitsCount
= lineBitsCount
% 8;
51 switch( RemoveScanline( pBuf
->mnFormat
))
53 case ScanlineFormat::N1BitMsbPal
:
55 static const sal_uInt8 mask1Bit
[] = { 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff };
56 extraBitsMask
= mask1Bit
[ extraBitsCount
];
59 case ScanlineFormat::N1BitLsbPal
:
61 static const sal_uInt8 mask1Bit
[] = { 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff };
62 extraBitsMask
= mask1Bit
[ extraBitsCount
];
65 case ScanlineFormat::N4BitMsnPal
:
66 assert(extraBitsCount
== 4);
69 case ScanlineFormat::N4BitLsnPal
:
70 assert(extraBitsCount
== 4);
77 if( pBuf
->mnFormat
& ScanlineFormat::TopDown
)
79 if( pBuf
->mnScanlineSize
== lineBitsCount
/ 8 )
80 nCrc
= vcl_get_checksum(nCrc
, pBuf
->mpBits
, pBuf
->mnScanlineSize
* pBuf
->mnHeight
);
81 else // Do not include padding with undefined content in the checksum.
82 for( tools::Long y
= 0; y
< pBuf
->mnHeight
; ++y
)
83 nCrc
= scanlineChecksum(nCrc
, pBuf
->mpBits
+ y
* pBuf
->mnScanlineSize
, lineBitsCount
, extraBitsMask
);
85 else // Compute checksum in the order of scanlines, to make it consistent between different bitmap implementations.
87 for( tools::Long y
= pBuf
->mnHeight
- 1; y
>= 0; --y
)
88 nCrc
= scanlineChecksum(nCrc
, pBuf
->mpBits
+ y
* pBuf
->mnScanlineSize
, lineBitsCount
, extraBitsMask
);
90 pThis
->ReleaseBuffer(pBuf
, BitmapAccessMode::Read
);
91 pThis
->mnChecksum
= nCrc
;
92 pThis
->mbChecksumValid
= true;
96 pThis
->mbChecksumValid
= false;
103 class ImplPixelFormat
106 const sal_uInt8
* mpData
;
108 static ImplPixelFormat
* GetFormat( sal_uInt16 nBits
, const BitmapPalette
& rPalette
);
110 virtual void StartLine( const sal_uInt8
* pLine
) { mpData
= pLine
; }
111 virtual const BitmapColor
& ReadPixel() = 0;
112 virtual ~ImplPixelFormat() { }
115 class ImplPixelFormat8
: public ImplPixelFormat
118 const BitmapPalette
& mrPalette
;
121 explicit ImplPixelFormat8( const BitmapPalette
& rPalette
)
122 : mrPalette( rPalette
)
125 virtual const BitmapColor
& ReadPixel() override
127 assert( mrPalette
.GetEntryCount() > *mpData
);
128 return mrPalette
[ *mpData
++ ];
132 class ImplPixelFormat4
: public ImplPixelFormat
135 const BitmapPalette
& mrPalette
;
140 explicit ImplPixelFormat4( const BitmapPalette
& rPalette
)
141 : mrPalette( rPalette
)
146 virtual void StartLine( const sal_uInt8
* pLine
) override
152 virtual const BitmapColor
& ReadPixel() override
154 sal_uInt32 nIdx
= ( mpData
[mnX
>> 1] >> mnShift
) & 0x0f;
155 assert( mrPalette
.GetEntryCount() > nIdx
);
156 const BitmapColor
& rColor
= mrPalette
[nIdx
];
163 class ImplPixelFormat1
: public ImplPixelFormat
166 const BitmapPalette
& mrPalette
;
170 explicit ImplPixelFormat1( const BitmapPalette
& rPalette
)
171 : mrPalette(rPalette
)
175 virtual void StartLine( const sal_uInt8
* pLine
) override
180 virtual const BitmapColor
& ReadPixel() override
182 const BitmapColor
& rColor
= mrPalette
[ (mpData
[mnX
>> 3 ] >> ( 7 - ( mnX
& 7 ) )) & 1];
188 ImplPixelFormat
* ImplPixelFormat::GetFormat( sal_uInt16 nBits
, const BitmapPalette
& rPalette
)
192 case 1: return new ImplPixelFormat1( rPalette
);
193 case 4: return new ImplPixelFormat4( rPalette
);
194 case 8: return new ImplPixelFormat8( rPalette
);
200 // Optimized conversion from 1bpp. Currently LO uses 1bpp bitmaps for masks, which is nowadays
201 // a lousy obsolete format, as the memory saved is just not worth the cost of fiddling with the bits.
202 // Ideally LO should move to RGBA bitmaps. Until then, try to be faster with 1bpp bitmaps.
203 typedef void(*WriteColorFunction
)( sal_uInt8 color8Bit
, sal_uInt8
*& dst
);
204 void writeColorA8(sal_uInt8 color8Bit
, sal_uInt8
*& dst
) { *dst
++ = color8Bit
; };
205 void writeColorRGB(sal_uInt8 color8Bit
, sal_uInt8
*& dst
) { *dst
++ = color8Bit
; *dst
++ = color8Bit
; *dst
++ = color8Bit
; };
206 void writeColorRGBA(sal_uInt8 color8Bit
, sal_uInt8
*& dst
) { *dst
++ = color8Bit
; *dst
++ = color8Bit
; *dst
++ = color8Bit
; *dst
++ = 0xff; };
207 typedef void(*WriteBlackWhiteFunction
)( sal_uInt8
*& dst
, int count
);
208 void writeBlackA8(sal_uInt8
*& dst
, int count
) { memset( dst
, 0, count
); dst
+= count
; };
209 void writeWhiteA8(sal_uInt8
*& dst
, int count
) { memset( dst
, 0xff, count
); dst
+= count
; };
210 void writeBlackRGB(sal_uInt8
*& dst
, int count
) { memset( dst
, 0, count
* 3 ); dst
+= count
* 3; };
211 void writeWhiteRGB(sal_uInt8
*& dst
, int count
) { memset( dst
, 0xff, count
* 3 ); dst
+= count
* 3; };
212 void writeWhiteRGBA(sal_uInt8
*& dst
, int count
) { memset( dst
, 0xff, count
* 4 ); dst
+= count
* 4; };
213 void writeBlackRGBA(sal_uInt8
*& dst
, int count
)
215 for( int i
= 0; i
< count
; ++i
)
225 template< WriteColorFunction func
, WriteBlackWhiteFunction funcBlack
, WriteBlackWhiteFunction funcWhite
>
226 void writeBlackWhiteData( const sal_uInt8
* src
, sal_uInt8
* dst
, int width
, int height
, int bytesPerRow
)
228 for( int y
= 0; y
< height
; ++y
)
230 const sal_uInt8
* srcLine
= src
;
235 const sal_uInt64
* src64
= reinterpret_cast< const sal_uInt64
* >( src
);
237 funcBlack( dst
, 64 );
238 else if( *src64
== static_cast< sal_uInt64
>( -1 ))
239 funcWhite( dst
, 64 );
242 src
+= sizeof( sal_uInt64
);
247 if( *src
== 0x00 ) // => eight black pixels
249 else if( *src
== 0xff ) // => eight white pixels
252 for( int bit
= 7; bit
>= 0; --bit
)
253 func(( *src
>> bit
) & 1 ? 0xff : 0, dst
);
257 for( int bit
= 7; bit
> 7 - xsize
; --bit
)
258 func(( *src
>> bit
) & 1 ? 0xff : 0, dst
);
260 src
= srcLine
+ bytesPerRow
;
266 std::unique_ptr
< sal_uInt8
[] > SalBitmap::convertDataBitCount( const sal_uInt8
* src
,
267 int width
, int height
, int bitCount
, int bytesPerRow
, const BitmapPalette
& palette
, BitConvert type
)
269 assert( bitCount
== 1 || bitCount
== 4 || bitCount
== 8 );
270 static const int bpp
[] = { 1, 3, 3, 4, 4 };
271 std::unique_ptr
< sal_uInt8
[] > data( new sal_uInt8
[width
* height
* bpp
[ static_cast<int>(type
) ]] );
273 if(type
== BitConvert::A8
&& bitCount
== 8 && palette
.IsGreyPalette8Bit())
274 { // no actual data conversion
275 for( int y
= 0; y
< height
; ++y
)
276 memcpy( data
.get() + y
* width
, src
+ y
* bytesPerRow
, width
);
280 if(bitCount
== 1 && palette
.GetEntryCount() == 2 && palette
[ 0 ] == COL_BLACK
&& palette
[ 1 ] == COL_WHITE
)
284 case BitConvert::A8
:
285 writeBlackWhiteData
< writeColorA8
, writeBlackA8
, writeWhiteA8
>
286 ( src
, data
.get(), width
, height
, bytesPerRow
);
288 case BitConvert::BGR
:
289 case BitConvert::RGB
:
290 // BGR/RGB is the same, all 3 values get the same value
291 writeBlackWhiteData
< writeColorRGB
, writeBlackRGB
, writeWhiteRGB
>
292 ( src
, data
.get(), width
, height
, bytesPerRow
);
294 case BitConvert::BGRA
:
295 case BitConvert::RGBA
:
296 // BGRA/RGBA is the same, all 3 values get the same value
297 writeBlackWhiteData
< writeColorRGBA
, writeBlackRGBA
, writeWhiteRGBA
>
298 ( src
, data
.get(), width
, height
, bytesPerRow
);
303 std::unique_ptr
<ImplPixelFormat
> pSrcFormat(ImplPixelFormat::GetFormat(bitCount
, palette
));
305 const sal_uInt8
* pSrcData
= src
;
306 sal_uInt8
* pDstData
= data
.get();
308 sal_uInt32 nY
= height
;
311 pSrcFormat
->StartLine( pSrcData
);
313 sal_uInt32 nX
= width
;
316 case BitConvert::A8
:
319 const BitmapColor
& c
= pSrcFormat
->ReadPixel();
320 *pDstData
++ = c
.GetBlue();
323 case BitConvert::BGR
:
326 const BitmapColor
& c
= pSrcFormat
->ReadPixel();
327 *pDstData
++ = c
.GetBlue();
328 *pDstData
++ = c
.GetGreen();
329 *pDstData
++ = c
.GetRed();
332 case BitConvert::RGB
:
335 const BitmapColor
& c
= pSrcFormat
->ReadPixel();
336 *pDstData
++ = c
.GetRed();
337 *pDstData
++ = c
.GetGreen();
338 *pDstData
++ = c
.GetBlue();
341 case BitConvert::BGRA
:
344 const BitmapColor
& c
= pSrcFormat
->ReadPixel();
345 *pDstData
++ = c
.GetBlue();
346 *pDstData
++ = c
.GetGreen();
347 *pDstData
++ = c
.GetRed();
351 case BitConvert::RGBA
:
354 const BitmapColor
& c
= pSrcFormat
->ReadPixel();
355 *pDstData
++ = c
.GetRed();
356 *pDstData
++ = c
.GetGreen();
357 *pDstData
++ = c
.GetBlue();
363 pSrcData
+= bytesPerRow
;
368 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */