LibreOffice Module vcl (master) 1
salbmp.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20#include <salbmp.hxx>
21#include <o3tl/enumarray.hxx>
22
23static BitmapChecksum scanlineChecksum(BitmapChecksum nCrc, const sal_uInt8* bits, int lineBitsCount, sal_uInt8 extraBitsMask)
24{
25 if( lineBitsCount / 8 > 0 )
26 nCrc = vcl_get_checksum( nCrc, bits, lineBitsCount / 8 );
27 if( extraBitsMask != 0 )
28 {
29 sal_uInt8 extraByte = bits[ lineBitsCount / 8 ] & extraBitsMask;
30 nCrc = vcl_get_checksum( nCrc, &extraByte, 1 );
31 }
32 return nCrc;
33}
34
36{
38 return;
39
40 BitmapChecksum nCrc = 0;
41 SalBitmap* pThis = const_cast<SalBitmap*>(this);
43 if (pBuf)
44 {
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 )
50 {
51 const int extraBitsCount = lineBitsCount % 8;
52 switch( RemoveScanline( pBuf->mnFormat ))
53 {
55 {
56 static const sal_uInt8 mask1Bit[] = { 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff };
57 extraBitsMask = mask1Bit[ extraBitsCount ];
58 break;
59 }
60 default:
61 break;
62 }
63 }
65 {
66 if( pBuf->mnScanlineSize == lineBitsCount / 8 )
67 nCrc = vcl_get_checksum(nCrc, pBuf->mpBits, pBuf->mnScanlineSize * pBuf->mnHeight);
68 else // Do not include padding with undefined content in the checksum.
69 for( tools::Long y = 0; y < pBuf->mnHeight; ++y )
70 nCrc = scanlineChecksum(nCrc, pBuf->mpBits + y * pBuf->mnScanlineSize, lineBitsCount, extraBitsMask);
71 }
72 else // Compute checksum in the order of scanlines, to make it consistent between different bitmap implementations.
73 {
74 for( tools::Long y = pBuf->mnHeight - 1; y >= 0; --y )
75 nCrc = scanlineChecksum(nCrc, pBuf->mpBits + y * pBuf->mnScanlineSize, lineBitsCount, extraBitsMask);
76 }
78 pThis->mnChecksum = nCrc;
79 pThis->mbChecksumValid = true;
80 }
81 else
82 {
83 pThis->mbChecksumValid = false;
84 }
85}
86
87namespace
88{
89
90class ImplPixelFormat
91{
92protected:
93 const sal_uInt8* mpData;
94public:
95 static ImplPixelFormat* GetFormat( sal_uInt16 nBits, const BitmapPalette& rPalette );
96
97 virtual void StartLine( const sal_uInt8* pLine ) { mpData = pLine; }
98 virtual const BitmapColor& ReadPixel() = 0;
99 virtual ~ImplPixelFormat() { }
100};
101
102class ImplPixelFormat8 : public ImplPixelFormat
103{
104private:
105 const BitmapPalette& mrPalette;
106
107public:
108 explicit ImplPixelFormat8( const BitmapPalette& rPalette )
109 : mrPalette( rPalette )
110 {
111 }
112 virtual const BitmapColor& ReadPixel() override
113 {
114 assert( mrPalette.GetEntryCount() > *mpData );
115 return mrPalette[ *mpData++ ];
116 }
117};
118
119class ImplPixelFormat4 : public ImplPixelFormat
120{
121private:
122 const BitmapPalette& mrPalette;
123 sal_uInt32 mnX;
124 sal_uInt32 mnShift;
125
126public:
127 explicit ImplPixelFormat4( const BitmapPalette& rPalette )
128 : mrPalette( rPalette )
129 , mnX(0)
130 , mnShift(4)
131 {
132 }
133 virtual void StartLine( const sal_uInt8* pLine ) override
134 {
135 mpData = pLine;
136 mnX = 0;
137 mnShift = 4;
138 }
139 virtual const BitmapColor& ReadPixel() override
140 {
141 sal_uInt32 nIdx = ( mpData[mnX >> 1] >> mnShift) & 0x0f;
142 assert( mrPalette.GetEntryCount() > nIdx );
143 const BitmapColor& rColor = mrPalette[nIdx];
144 mnX++;
145 mnShift ^= 4;
146 return rColor;
147 }
148};
149
150class ImplPixelFormat1 : public ImplPixelFormat
151{
152private:
153 const BitmapPalette& mrPalette;
154 sal_uInt32 mnX;
155
156public:
157 explicit ImplPixelFormat1( const BitmapPalette& rPalette )
158 : mrPalette(rPalette)
159 , mnX(0)
160 {
161 }
162 virtual void StartLine( const sal_uInt8* pLine ) override
163 {
164 mpData = pLine;
165 mnX = 0;
166 }
167 virtual const BitmapColor& ReadPixel() override
168 {
169 const BitmapColor& rColor = mrPalette[ (mpData[mnX >> 3 ] >> ( 7 - ( mnX & 7 ) )) & 1];
170 mnX++;
171 return rColor;
172 }
173};
174
175ImplPixelFormat* ImplPixelFormat::GetFormat( sal_uInt16 nBits, const BitmapPalette& rPalette )
176{
177 switch( nBits )
178 {
179 case 1: return new ImplPixelFormat1( rPalette );
180 case 4: return new ImplPixelFormat4( rPalette );
181 case 8: return new ImplPixelFormat8( rPalette );
182 }
183
184 return nullptr;
185}
186
187// Optimized conversion from 1bpp. Currently LO uses 1bpp bitmaps for masks, which is nowadays
188// a lousy obsolete format, as the memory saved is just not worth the cost of fiddling with the bits.
189// Ideally LO should move to RGBA bitmaps. Until then, try to be faster with 1bpp bitmaps.
190typedef void(*WriteColorFunction)( sal_uInt8 color8Bit, sal_uInt8*& dst );
191void writeColorA8(sal_uInt8 color8Bit, sal_uInt8*& dst ) { *dst++ = color8Bit; };
192void writeColorRGBA(sal_uInt8 color8Bit, sal_uInt8*& dst ) { *dst++ = color8Bit; *dst++ = color8Bit; *dst++ = color8Bit; *dst++ = 0xff; };
193typedef void(*WriteBlackWhiteFunction)( sal_uInt8*& dst, int count );
194void writeBlackA8(sal_uInt8*& dst, int count ) { memset( dst, 0, count ); dst += count; };
195void writeWhiteA8(sal_uInt8*& dst, int count ) { memset( dst, 0xff, count ); dst += count; };
196void writeWhiteRGBA(sal_uInt8*& dst, int count ) { memset( dst, 0xff, count * 4 ); dst += count * 4; };
197void writeBlackRGBA(sal_uInt8*& dst, int count )
198{
199 for( int i = 0; i < count; ++i )
200 {
201 dst[0] = 0x00;
202 dst[1] = 0x00;
203 dst[2] = 0x00;
204 dst[3] = 0xff;
205 dst += 4;
206 }
207};
208
209template< WriteColorFunction func, WriteBlackWhiteFunction funcBlack, WriteBlackWhiteFunction funcWhite >
210void writeBlackWhiteData( const sal_uInt8* src, sal_uInt8* dst, int width, int height, int bytesPerRow )
211{
212 for( int y = 0; y < height; ++y )
213 {
214 const sal_uInt8* srcLine = src;
215 int xsize = width;
216 while( xsize >= 64 )
217 {
218 // TODO alignment?
219 const sal_uInt64* src64 = reinterpret_cast< const sal_uInt64* >( src );
220 if( *src64 == 0x00 )
221 funcBlack( dst, 64 );
222 else if( *src64 == static_cast< sal_uInt64 >( -1 ))
223 funcWhite( dst, 64 );
224 else
225 break;
226 src += sizeof( sal_uInt64 );
227 xsize -= 64;
228 }
229 while( xsize >= 8 )
230 {
231 if( *src == 0x00 ) // => eight black pixels
232 funcBlack( dst, 8 );
233 else if( *src == 0xff ) // => eight white pixels
234 funcWhite( dst, 8 );
235 else
236 for( int bit = 7; bit >= 0; --bit )
237 func(( *src >> bit ) & 1 ? 0xff : 0, dst );
238 ++src;
239 xsize -= 8;
240 }
241 for( int bit = 7; bit > 7 - xsize; --bit )
242 func(( *src >> bit ) & 1 ? 0xff : 0, dst );
243 ++src;
244 src = srcLine + bytesPerRow;
245 }
246}
247
248} // namespace
249
250std::unique_ptr< sal_uInt8[] > SalBitmap::convertDataBitCount( const sal_uInt8* src,
251 int width, int height, int bitCount, int bytesPerRow, const BitmapPalette& palette, BitConvert type )
252{
253 assert( bitCount == 1 || bitCount == 4 || bitCount == 8 );
254 static const o3tl::enumarray<BitConvert, int> bpp = { 1, 4, 4 };
255 std::unique_ptr< sal_uInt8[] > data( new sal_uInt8[width * height * bpp[ type ]] );
256
257 if(type == BitConvert::A8 && bitCount == 8 && palette.IsGreyPalette8Bit())
258 { // no actual data conversion
259 for( int y = 0; y < height; ++y )
260 memcpy( data.get() + y * width, src + y * bytesPerRow, width );
261 return data;
262 }
263
264 if(bitCount == 1 && palette.GetEntryCount() == 2 && palette[ 0 ] == COL_BLACK && palette[ 1 ] == COL_WHITE)
265 {
266 switch( type )
267 {
268 case BitConvert::A8 :
269 writeBlackWhiteData< writeColorA8, writeBlackA8, writeWhiteA8 >
270 ( src, data.get(), width, height, bytesPerRow );
271 return data;
272 case BitConvert::BGRA :
273 case BitConvert::RGBA :
274 // BGRA/RGBA is the same, all 3 values get the same value
275 writeBlackWhiteData< writeColorRGBA, writeBlackRGBA, writeWhiteRGBA >
276 ( src, data.get(), width, height, bytesPerRow );
277 return data;
278 }
279 }
280
281 std::unique_ptr<ImplPixelFormat> pSrcFormat(ImplPixelFormat::GetFormat(bitCount, palette));
282
283 const sal_uInt8* pSrcData = src;
284 sal_uInt8* pDstData = data.get();
285
286 sal_uInt32 nY = height;
287 while( nY-- )
288 {
289 pSrcFormat->StartLine( pSrcData );
290
291 sal_uInt32 nX = width;
292 switch( type )
293 {
294 case BitConvert::A8 :
295 while( nX-- )
296 {
297 const BitmapColor& c = pSrcFormat->ReadPixel();
298 *pDstData++ = c.GetBlue();
299 }
300 break;
301 case BitConvert::BGRA :
302 while( nX-- )
303 {
304 const BitmapColor& c = pSrcFormat->ReadPixel();
305 *pDstData++ = c.GetBlue();
306 *pDstData++ = c.GetGreen();
307 *pDstData++ = c.GetRed();
308 *pDstData++ = 0xff;
309 }
310 break;
311 case BitConvert::RGBA :
312 while( nX-- )
313 {
314 const BitmapColor& c = pSrcFormat->ReadPixel();
315 *pDstData++ = c.GetRed();
316 *pDstData++ = c.GetGreen();
317 *pDstData++ = c.GetBlue();
318 *pDstData++ = 0xff;
319 }
320 break;
321 }
322
323 pSrcData += bytesPerRow;
324 }
325 return data;
326}
327
329{
330 // default has no support, returns nullptr
331 return nullptr;
332}
333
334/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
ScanlineFormat RemoveScanline(ScanlineFormat nFormat)
Definition: Scanline.hxx:53
sal_uInt64 BitmapChecksum
Definition: checksum.hxx:30
BitmapChecksum vcl_get_checksum(BitmapChecksum Checksum, const void *Data, sal_uInt32 DatLen)
Definition: checksum.hxx:72
BitmapChecksum GetChecksum() const
sal_uInt16 GetEntryCount() const
bool IsGreyPalette8Bit() const
Returns true if the palette is 8-bit grey palette.
sal_uInt8 GetBlue() const
sal_uInt8 GetRed() const
sal_uInt8 GetGreen() const
BitmapChecksum mnChecksum
Definition: salbmp.hxx:192
void updateChecksum() const
Definition: salbmp.cxx:35
bool mbChecksumValid
Definition: salbmp.hxx:193
virtual void ReleaseBuffer(BitmapBuffer *pBuffer, BitmapAccessMode nMode)=0
static std::unique_ptr< sal_uInt8[] > convertDataBitCount(const sal_uInt8 *src, int width, int height, int bitCount, int bytesPerRow, const BitmapPalette &palette, BitConvert type)
Definition: salbmp.cxx:250
virtual const basegfx::SystemDependentDataHolder * accessSystemDependentDataHolder() const
Definition: salbmp.cxx:328
virtual BitmapBuffer * AcquireBuffer(BitmapAccessMode nMode)=0
constexpr ::Color COL_WHITE(0xFF, 0xFF, 0xFF)
constexpr ::Color COL_BLACK(0x00, 0x00, 0x00)
virtual SotClipboardFormatId GetFormat(const TransferableDataHelper &aHelper) override
float y
int i
long Long
static BitmapChecksum scanlineChecksum(BitmapChecksum nCrc, const sal_uInt8 *bits, int lineBitsCount, sal_uInt8 extraBitsMask)
Definition: salbmp.cxx:23
BitmapPalette maPalette
tools::Long mnWidth
sal_uInt8 * mpBits
tools::Long mnScanlineSize
sal_uInt16 mnBitCount
ScanlineFormat mnFormat
tools::Long mnHeight
unsigned char sal_uInt8
ResultType type
#define bit(name)