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 .
21 #include <o3tl/enumarray.hxx>
23 static BitmapChecksum
scanlineChecksum(BitmapChecksum nCrc
, const sal_uInt8
* bits
, int lineBitsCount
, sal_uInt8 extraBitsMask
)
25 if( lineBitsCount
/ 8 > 0 )
26 nCrc
= vcl_get_checksum( nCrc
, bits
, lineBitsCount
/ 8 );
27 if( extraBitsMask
!= 0 )
29 sal_uInt8 extraByte
= bits
[ lineBitsCount
/ 8 ] & extraBitsMask
;
30 nCrc
= vcl_get_checksum( nCrc
, &extraByte
, 1 );
35 void SalBitmap::updateChecksum() const
40 BitmapChecksum nCrc
= 0;
41 SalBitmap
* pThis
= const_cast<SalBitmap
*>(this);
42 BitmapBuffer
* pBuf
= pThis
->AcquireBuffer(BitmapAccessMode::Read
);
45 nCrc
= pBuf
->maPalette
.GetChecksum();
46 const int lineBitsCount
= pBuf
->mnWidth
* pBuf
->mnBitCount
;
47 // With 1bpp/4bpp format we need to check only used bits in the last byte.
48 sal_uInt8 extraBitsMask
= 0;
49 if( lineBitsCount
% 8 != 0 )
51 const int extraBitsCount
= lineBitsCount
% 8;
52 switch( RemoveScanline( pBuf
->mnFormat
))
54 case ScanlineFormat::N1BitMsbPal
:
56 static const sal_uInt8 mask1Bit
[] = { 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff };
57 extraBitsMask
= mask1Bit
[ extraBitsCount
];
60 case ScanlineFormat::N1BitLsbPal
:
62 static const sal_uInt8 mask1Bit
[] = { 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff };
63 extraBitsMask
= mask1Bit
[ extraBitsCount
];
70 if( pBuf
->mnFormat
& ScanlineFormat::TopDown
)
72 if( pBuf
->mnScanlineSize
== lineBitsCount
/ 8 )
73 nCrc
= vcl_get_checksum(nCrc
, pBuf
->mpBits
, pBuf
->mnScanlineSize
* pBuf
->mnHeight
);
74 else // Do not include padding with undefined content in the checksum.
75 for( tools::Long y
= 0; y
< pBuf
->mnHeight
; ++y
)
76 nCrc
= scanlineChecksum(nCrc
, pBuf
->mpBits
+ y
* pBuf
->mnScanlineSize
, lineBitsCount
, extraBitsMask
);
78 else // Compute checksum in the order of scanlines, to make it consistent between different bitmap implementations.
80 for( tools::Long y
= pBuf
->mnHeight
- 1; y
>= 0; --y
)
81 nCrc
= scanlineChecksum(nCrc
, pBuf
->mpBits
+ y
* pBuf
->mnScanlineSize
, lineBitsCount
, extraBitsMask
);
83 pThis
->ReleaseBuffer(pBuf
, BitmapAccessMode::Read
);
84 pThis
->mnChecksum
= nCrc
;
85 pThis
->mbChecksumValid
= true;
89 pThis
->mbChecksumValid
= false;
99 const sal_uInt8
* mpData
;
101 static ImplPixelFormat
* GetFormat( sal_uInt16 nBits
, const BitmapPalette
& rPalette
);
103 virtual void StartLine( const sal_uInt8
* pLine
) { mpData
= pLine
; }
104 virtual const BitmapColor
& ReadPixel() = 0;
105 virtual ~ImplPixelFormat() { }
108 class ImplPixelFormat8
: public ImplPixelFormat
111 const BitmapPalette
& mrPalette
;
114 explicit ImplPixelFormat8( const BitmapPalette
& rPalette
)
115 : mrPalette( rPalette
)
118 virtual const BitmapColor
& ReadPixel() override
120 assert( mrPalette
.GetEntryCount() > *mpData
);
121 return mrPalette
[ *mpData
++ ];
125 class ImplPixelFormat4
: public ImplPixelFormat
128 const BitmapPalette
& mrPalette
;
133 explicit ImplPixelFormat4( const BitmapPalette
& rPalette
)
134 : mrPalette( rPalette
)
139 virtual void StartLine( const sal_uInt8
* pLine
) override
145 virtual const BitmapColor
& ReadPixel() override
147 sal_uInt32 nIdx
= ( mpData
[mnX
>> 1] >> mnShift
) & 0x0f;
148 assert( mrPalette
.GetEntryCount() > nIdx
);
149 const BitmapColor
& rColor
= mrPalette
[nIdx
];
156 class ImplPixelFormat1
: public ImplPixelFormat
159 const BitmapPalette
& mrPalette
;
163 explicit ImplPixelFormat1( const BitmapPalette
& rPalette
)
164 : mrPalette(rPalette
)
168 virtual void StartLine( const sal_uInt8
* pLine
) override
173 virtual const BitmapColor
& ReadPixel() override
175 const BitmapColor
& rColor
= mrPalette
[ (mpData
[mnX
>> 3 ] >> ( 7 - ( mnX
& 7 ) )) & 1];
181 ImplPixelFormat
* ImplPixelFormat::GetFormat( sal_uInt16 nBits
, const BitmapPalette
& rPalette
)
185 case 1: return new ImplPixelFormat1( rPalette
);
186 case 4: return new ImplPixelFormat4( rPalette
);
187 case 8: return new ImplPixelFormat8( rPalette
);
193 // Optimized conversion from 1bpp. Currently LO uses 1bpp bitmaps for masks, which is nowadays
194 // a lousy obsolete format, as the memory saved is just not worth the cost of fiddling with the bits.
195 // Ideally LO should move to RGBA bitmaps. Until then, try to be faster with 1bpp bitmaps.
196 typedef void(*WriteColorFunction
)( sal_uInt8 color8Bit
, sal_uInt8
*& dst
);
197 void writeColorA8(sal_uInt8 color8Bit
, sal_uInt8
*& dst
) { *dst
++ = color8Bit
; };
198 void writeColorRGBA(sal_uInt8 color8Bit
, sal_uInt8
*& dst
) { *dst
++ = color8Bit
; *dst
++ = color8Bit
; *dst
++ = color8Bit
; *dst
++ = 0xff; };
199 typedef void(*WriteBlackWhiteFunction
)( sal_uInt8
*& dst
, int count
);
200 void writeBlackA8(sal_uInt8
*& dst
, int count
) { memset( dst
, 0, count
); dst
+= count
; };
201 void writeWhiteA8(sal_uInt8
*& dst
, int count
) { memset( dst
, 0xff, count
); dst
+= count
; };
202 void writeWhiteRGBA(sal_uInt8
*& dst
, int count
) { memset( dst
, 0xff, count
* 4 ); dst
+= count
* 4; };
203 void writeBlackRGBA(sal_uInt8
*& dst
, int count
)
205 for( int i
= 0; i
< count
; ++i
)
215 template< WriteColorFunction func
, WriteBlackWhiteFunction funcBlack
, WriteBlackWhiteFunction funcWhite
>
216 void writeBlackWhiteData( const sal_uInt8
* src
, sal_uInt8
* dst
, int width
, int height
, int bytesPerRow
)
218 for( int y
= 0; y
< height
; ++y
)
220 const sal_uInt8
* srcLine
= src
;
225 const sal_uInt64
* src64
= reinterpret_cast< const sal_uInt64
* >( src
);
227 funcBlack( dst
, 64 );
228 else if( *src64
== static_cast< sal_uInt64
>( -1 ))
229 funcWhite( dst
, 64 );
232 src
+= sizeof( sal_uInt64
);
237 if( *src
== 0x00 ) // => eight black pixels
239 else if( *src
== 0xff ) // => eight white pixels
242 for( int bit
= 7; bit
>= 0; --bit
)
243 func(( *src
>> bit
) & 1 ? 0xff : 0, dst
);
247 for( int bit
= 7; bit
> 7 - xsize
; --bit
)
248 func(( *src
>> bit
) & 1 ? 0xff : 0, dst
);
250 src
= srcLine
+ bytesPerRow
;
256 std::unique_ptr
< sal_uInt8
[] > SalBitmap::convertDataBitCount( const sal_uInt8
* src
,
257 int width
, int height
, int bitCount
, int bytesPerRow
, const BitmapPalette
& palette
, BitConvert type
)
259 assert( bitCount
== 1 || bitCount
== 4 || bitCount
== 8 );
260 static const o3tl::enumarray
<BitConvert
, int> bpp
= { 1, 4, 4 };
261 std::unique_ptr
< sal_uInt8
[] > data( new sal_uInt8
[width
* height
* bpp
[ type
]] );
263 if(type
== BitConvert::A8
&& bitCount
== 8 && palette
.IsGreyPalette8Bit())
264 { // no actual data conversion
265 for( int y
= 0; y
< height
; ++y
)
266 memcpy( data
.get() + y
* width
, src
+ y
* bytesPerRow
, width
);
270 if(bitCount
== 1 && palette
.GetEntryCount() == 2 && palette
[ 0 ] == COL_BLACK
&& palette
[ 1 ] == COL_WHITE
)
274 case BitConvert::A8
:
275 writeBlackWhiteData
< writeColorA8
, writeBlackA8
, writeWhiteA8
>
276 ( src
, data
.get(), width
, height
, bytesPerRow
);
278 case BitConvert::BGRA
:
279 case BitConvert::RGBA
:
280 // BGRA/RGBA is the same, all 3 values get the same value
281 writeBlackWhiteData
< writeColorRGBA
, writeBlackRGBA
, writeWhiteRGBA
>
282 ( src
, data
.get(), width
, height
, bytesPerRow
);
287 std::unique_ptr
<ImplPixelFormat
> pSrcFormat(ImplPixelFormat::GetFormat(bitCount
, palette
));
289 const sal_uInt8
* pSrcData
= src
;
290 sal_uInt8
* pDstData
= data
.get();
292 sal_uInt32 nY
= height
;
295 pSrcFormat
->StartLine( pSrcData
);
297 sal_uInt32 nX
= width
;
300 case BitConvert::A8
:
303 const BitmapColor
& c
= pSrcFormat
->ReadPixel();
304 *pDstData
++ = c
.GetBlue();
307 case BitConvert::BGRA
:
310 const BitmapColor
& c
= pSrcFormat
->ReadPixel();
311 *pDstData
++ = c
.GetBlue();
312 *pDstData
++ = c
.GetGreen();
313 *pDstData
++ = c
.GetRed();
317 case BitConvert::RGBA
:
320 const BitmapColor
& c
= pSrcFormat
->ReadPixel();
321 *pDstData
++ = c
.GetRed();
322 *pDstData
++ = c
.GetGreen();
323 *pDstData
++ = c
.GetBlue();
329 pSrcData
+= bytesPerRow
;
334 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */