bump product version to 7.2.5.1
[LibreOffice.git] / vcl / source / bitmap / salbmp.cxx
bloba1fc7de7a60acbf332cfdf1f88e41d38be02245d
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 <salbmp.hxx>
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 );
32 return nCrc;
35 void SalBitmap::updateChecksum() const
37 if (mbChecksumValid)
38 return;
40 BitmapChecksum nCrc = 0;
41 SalBitmap* pThis = const_cast<SalBitmap*>(this);
42 BitmapBuffer* pBuf = pThis->AcquireBuffer(BitmapAccessMode::Read);
43 if (pBuf)
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 ];
58 break;
60 case ScanlineFormat::N1BitLsbPal:
62 static const sal_uInt8 mask1Bit[] = { 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff };
63 extraBitsMask = mask1Bit[ extraBitsCount ];
64 break;
66 default:
67 break;
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;
87 else
89 pThis->mbChecksumValid = false;
93 namespace
96 class ImplPixelFormat
98 protected:
99 const sal_uInt8* mpData;
100 public:
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
110 private:
111 const BitmapPalette& mrPalette;
113 public:
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
127 private:
128 const BitmapPalette& mrPalette;
129 sal_uInt32 mnX;
130 sal_uInt32 mnShift;
132 public:
133 explicit ImplPixelFormat4( const BitmapPalette& rPalette )
134 : mrPalette( rPalette )
135 , mnX(0)
136 , mnShift(4)
139 virtual void StartLine( const sal_uInt8* pLine ) override
141 mpData = pLine;
142 mnX = 0;
143 mnShift = 4;
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];
150 mnX++;
151 mnShift ^= 4;
152 return rColor;
156 class ImplPixelFormat1 : public ImplPixelFormat
158 private:
159 const BitmapPalette& mrPalette;
160 sal_uInt32 mnX;
162 public:
163 explicit ImplPixelFormat1( const BitmapPalette& rPalette )
164 : mrPalette(rPalette)
165 , mnX(0)
168 virtual void StartLine( const sal_uInt8* pLine ) override
170 mpData = pLine;
171 mnX = 0;
173 virtual const BitmapColor& ReadPixel() override
175 const BitmapColor& rColor = mrPalette[ (mpData[mnX >> 3 ] >> ( 7 - ( mnX & 7 ) )) & 1];
176 mnX++;
177 return rColor;
181 ImplPixelFormat* ImplPixelFormat::GetFormat( sal_uInt16 nBits, const BitmapPalette& rPalette )
183 switch( nBits )
185 case 1: return new ImplPixelFormat1( rPalette );
186 case 4: return new ImplPixelFormat4( rPalette );
187 case 8: return new ImplPixelFormat8( rPalette );
190 return nullptr;
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 )
207 dst[0] = 0x00;
208 dst[1] = 0x00;
209 dst[2] = 0x00;
210 dst[3] = 0xff;
211 dst += 4;
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;
221 int xsize = width;
222 while( xsize >= 64 )
224 // TODO alignment?
225 const sal_uInt64* src64 = reinterpret_cast< const sal_uInt64* >( src );
226 if( *src64 == 0x00 )
227 funcBlack( dst, 64 );
228 else if( *src64 == static_cast< sal_uInt64 >( -1 ))
229 funcWhite( dst, 64 );
230 else
231 break;
232 src += sizeof( sal_uInt64 );
233 xsize -= 64;
235 while( xsize >= 8 )
237 if( *src == 0x00 ) // => eight black pixels
238 funcBlack( dst, 8 );
239 else if( *src == 0xff ) // => eight white pixels
240 funcWhite( dst, 8 );
241 else
242 for( int bit = 7; bit >= 0; --bit )
243 func(( *src >> bit ) & 1 ? 0xff : 0, dst );
244 ++src;
245 xsize -= 8;
247 for( int bit = 7; bit > 7 - xsize; --bit )
248 func(( *src >> bit ) & 1 ? 0xff : 0, dst );
249 ++src;
250 src = srcLine + bytesPerRow;
254 } // namespace
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 );
267 return data;
270 if(bitCount == 1 && palette.GetEntryCount() == 2 && palette[ 0 ] == COL_BLACK && palette[ 1 ] == COL_WHITE)
272 switch( type )
274 case BitConvert::A8 :
275 writeBlackWhiteData< writeColorA8, writeBlackA8, writeWhiteA8 >
276 ( src, data.get(), width, height, bytesPerRow );
277 return data;
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 );
283 return data;
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;
293 while( nY-- )
295 pSrcFormat->StartLine( pSrcData );
297 sal_uInt32 nX = width;
298 switch( type )
300 case BitConvert::A8 :
301 while( nX-- )
303 const BitmapColor& c = pSrcFormat->ReadPixel();
304 *pDstData++ = c.GetBlue();
306 break;
307 case BitConvert::BGRA :
308 while( nX-- )
310 const BitmapColor& c = pSrcFormat->ReadPixel();
311 *pDstData++ = c.GetBlue();
312 *pDstData++ = c.GetGreen();
313 *pDstData++ = c.GetRed();
314 *pDstData++ = 0xff;
316 break;
317 case BitConvert::RGBA :
318 while( nX-- )
320 const BitmapColor& c = pSrcFormat->ReadPixel();
321 *pDstData++ = c.GetRed();
322 *pDstData++ = c.GetGreen();
323 *pDstData++ = c.GetBlue();
324 *pDstData++ = 0xff;
326 break;
329 pSrcData += bytesPerRow;
331 return data;
334 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */