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 
22 static BitmapChecksum scanlineChecksum(BitmapChecksum nCrc, const sal_uInt8* bits, int lineBitsCount, sal_uInt8 extraBitsMask)
23 {
24  if( lineBitsCount / 8 > 0 )
25  nCrc = vcl_get_checksum( nCrc, bits, lineBitsCount / 8 );
26  if( extraBitsMask != 0 )
27  {
28  sal_uInt8 extraByte = bits[ lineBitsCount / 8 ] & extraBitsMask;
29  nCrc = vcl_get_checksum( nCrc, &extraByte, 1 );
30  }
31  return nCrc;
32 }
33 
35 {
36  if (mbChecksumValid)
37  return;
38 
39  BitmapChecksum nCrc = 0;
40  SalBitmap* pThis = const_cast<SalBitmap*>(this);
42  if (pBuf)
43  {
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 )
49  {
50  const int extraBitsCount = lineBitsCount % 8;
51  switch( RemoveScanline( pBuf->mnFormat ))
52  {
54  {
55  static const sal_uInt8 mask1Bit[] = { 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff };
56  extraBitsMask = mask1Bit[ extraBitsCount ];
57  break;
58  }
60  {
61  static const sal_uInt8 mask1Bit[] = { 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff };
62  extraBitsMask = mask1Bit[ extraBitsCount ];
63  break;
64  }
66  assert(extraBitsCount == 4);
67  extraBitsMask = 0xf0;
68  break;
70  assert(extraBitsCount == 4);
71  extraBitsMask = 0x0f;
72  break;
73  default:
74  break;
75  }
76  }
77  if( pBuf->mnFormat & ScanlineFormat::TopDown )
78  {
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( long y = 0; y < pBuf->mnHeight; ++y )
83  nCrc = scanlineChecksum(nCrc, pBuf->mpBits + y * pBuf->mnScanlineSize, lineBitsCount, extraBitsMask);
84  }
85  else // Compute checksum in the order of scanlines, to make it consistent between different bitmap implementations.
86  {
87  for( long y = pBuf->mnHeight - 1; y >= 0; --y )
88  nCrc = scanlineChecksum(nCrc, pBuf->mpBits + y * pBuf->mnScanlineSize, lineBitsCount, extraBitsMask);
89  }
91  pThis->mnChecksum = nCrc;
92  pThis->mbChecksumValid = true;
93  }
94  else
95  {
96  pThis->mbChecksumValid = false;
97  }
98 }
99 
100 namespace
101 {
102 
103 class ImplPixelFormat
104 {
105 protected:
106  const sal_uInt8* mpData;
107 public:
108  static ImplPixelFormat* GetFormat( sal_uInt16 nBits, const BitmapPalette& rPalette );
109 
110  virtual void StartLine( const sal_uInt8* pLine ) { mpData = pLine; }
111  virtual const BitmapColor& ReadPixel() = 0;
112  virtual ~ImplPixelFormat() { }
113 };
114 
115 class ImplPixelFormat8 : public ImplPixelFormat
116 {
117 private:
118  const BitmapPalette& mrPalette;
119 
120 public:
121  explicit ImplPixelFormat8( const BitmapPalette& rPalette )
122  : mrPalette( rPalette )
123  {
124  }
125  virtual const BitmapColor& ReadPixel() override
126  {
127  assert( mrPalette.GetEntryCount() > *mpData );
128  return mrPalette[ *mpData++ ];
129  }
130 };
131 
132 class ImplPixelFormat4 : public ImplPixelFormat
133 {
134 private:
135  const BitmapPalette& mrPalette;
136  sal_uInt32 mnX;
137  sal_uInt32 mnShift;
138 
139 public:
140  explicit ImplPixelFormat4( const BitmapPalette& rPalette )
141  : mrPalette( rPalette )
142  , mnX(0)
143  , mnShift(4)
144  {
145  }
146  virtual void StartLine( const sal_uInt8* pLine ) override
147  {
148  mpData = pLine;
149  mnX = 0;
150  mnShift = 4;
151  }
152  virtual const BitmapColor& ReadPixel() override
153  {
154  sal_uInt32 nIdx = ( mpData[mnX >> 1] >> mnShift) & 0x0f;
155  assert( mrPalette.GetEntryCount() > nIdx );
156  const BitmapColor& rColor = mrPalette[nIdx];
157  mnX++;
158  mnShift ^= 4;
159  return rColor;
160  }
161 };
162 
163 class ImplPixelFormat1 : public ImplPixelFormat
164 {
165 private:
166  const BitmapPalette& mrPalette;
167  sal_uInt32 mnX;
168 
169 public:
170  explicit ImplPixelFormat1( const BitmapPalette& rPalette )
171  : mrPalette(rPalette)
172  , mnX(0)
173  {
174  }
175  virtual void StartLine( const sal_uInt8* pLine ) override
176  {
177  mpData = pLine;
178  mnX = 0;
179  }
180  virtual const BitmapColor& ReadPixel() override
181  {
182  const BitmapColor& rColor = mrPalette[ (mpData[mnX >> 3 ] >> ( 7 - ( mnX & 7 ) )) & 1];
183  mnX++;
184  return rColor;
185  }
186 };
187 
188 ImplPixelFormat* ImplPixelFormat::GetFormat( sal_uInt16 nBits, const BitmapPalette& rPalette )
189 {
190  switch( nBits )
191  {
192  case 1: return new ImplPixelFormat1( rPalette );
193  case 4: return new ImplPixelFormat4( rPalette );
194  case 8: return new ImplPixelFormat8( rPalette );
195  }
196 
197  return nullptr;
198 }
199 
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 )
214 {
215  for( int i = 0; i < count; ++i )
216  {
217  dst[0] = 0x00;
218  dst[1] = 0x00;
219  dst[2] = 0x00;
220  dst[3] = 0xff;
221  dst += 4;
222  }
223 };
224 
225 template< WriteColorFunction func, WriteBlackWhiteFunction funcBlack, WriteBlackWhiteFunction funcWhite >
226 void writeBlackWhiteData( const sal_uInt8* src, sal_uInt8* dst, int width, int height, int bytesPerRow )
227 {
228  for( int y = 0; y < height; ++y )
229  {
230  const sal_uInt8* srcLine = src;
231  int xsize = width;
232  while( xsize >= 64 )
233  {
234  // TODO alignment?
235  const sal_uInt64* src64 = reinterpret_cast< const sal_uInt64* >( src );
236  if( *src64 == 0x00 )
237  funcBlack( dst, 64 );
238  else if( *src64 == static_cast< sal_uInt64 >( -1 ))
239  funcWhite( dst, 64 );
240  else
241  break;
242  src += sizeof( sal_uInt64 );
243  xsize -= 64;
244  }
245  while( xsize >= 8 )
246  {
247  if( *src == 0x00 ) // => eight black pixels
248  funcBlack( dst, 8 );
249  else if( *src == 0xff ) // => eight white pixels
250  funcWhite( dst, 8 );
251  else
252  for( int bit = 7; bit >= 0; --bit )
253  func(( *src >> bit ) & 1 ? 0xff : 0, dst );
254  ++src;
255  xsize -= 8;
256  }
257  for( int bit = 7; bit > 7 - xsize; --bit )
258  func(( *src >> bit ) & 1 ? 0xff : 0, dst );
259  ++src;
260  src = srcLine + bytesPerRow;
261  }
262 }
263 
264 } // namespace
265 
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 )
268 {
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) ]] );
272 
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 );
277  return data;
278  }
279 
280  if(bitCount == 1 && palette.GetEntryCount() == 2 && palette[ 0 ] == COL_BLACK && palette[ 1 ] == COL_WHITE)
281  {
282  switch( type )
283  {
284  case BitConvert::A8 :
285  writeBlackWhiteData< writeColorA8, writeBlackA8, writeWhiteA8 >
286  ( src, data.get(), width, height, bytesPerRow );
287  return data;
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 );
293  return data;
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 );
299  return data;
300  }
301  }
302 
303  std::unique_ptr<ImplPixelFormat> pSrcFormat(ImplPixelFormat::GetFormat(bitCount, palette));
304 
305  const sal_uInt8* pSrcData = src;
306  sal_uInt8* pDstData = data.get();
307 
308  sal_uInt32 nY = height;
309  while( nY-- )
310  {
311  pSrcFormat->StartLine( pSrcData );
312 
313  sal_uInt32 nX = width;
314  switch( type )
315  {
316  case BitConvert::A8 :
317  while( nX-- )
318  {
319  const BitmapColor& c = pSrcFormat->ReadPixel();
320  *pDstData++ = c.GetBlue();
321  }
322  break;
323  case BitConvert::BGR :
324  while( nX-- )
325  {
326  const BitmapColor& c = pSrcFormat->ReadPixel();
327  *pDstData++ = c.GetBlue();
328  *pDstData++ = c.GetGreen();
329  *pDstData++ = c.GetRed();
330  }
331  break;
332  case BitConvert::RGB :
333  while( nX-- )
334  {
335  const BitmapColor& c = pSrcFormat->ReadPixel();
336  *pDstData++ = c.GetRed();
337  *pDstData++ = c.GetGreen();
338  *pDstData++ = c.GetBlue();
339  }
340  break;
341  case BitConvert::BGRA :
342  while( nX-- )
343  {
344  const BitmapColor& c = pSrcFormat->ReadPixel();
345  *pDstData++ = c.GetBlue();
346  *pDstData++ = c.GetGreen();
347  *pDstData++ = c.GetRed();
348  *pDstData++ = 0xff;
349  }
350  break;
351  case BitConvert::RGBA :
352  while( nX-- )
353  {
354  const BitmapColor& c = pSrcFormat->ReadPixel();
355  *pDstData++ = c.GetRed();
356  *pDstData++ = c.GetGreen();
357  *pDstData++ = c.GetBlue();
358  *pDstData++ = 0xff;
359  }
360  break;
361  }
362 
363  pSrcData += bytesPerRow;
364  }
365  return data;
366 }
367 
368 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
sal_uInt64 BitmapChecksum
Definition: checksum.hxx:30
const size_t count(pCandidateA->getBorderLines().size())
bool IsGreyPalette8Bit() const
Returns true if the palette is 8-bit grey palette.
constexpr::Color COL_BLACK(0x00, 0x00, 0x00)
sal_uInt8 GetRed() const
BitmapChecksum GetChecksum() const
virtual void updateChecksum() const
Definition: salbmp.cxx:34
bool mbChecksumValid
Definition: salbmp.hxx:110
BitmapChecksum mnChecksum
Definition: salbmp.hxx:109
BitmapChecksum vcl_get_checksum(BitmapChecksum Checksum, const void *Data, sal_uInt32 DatLen)
Definition: checksum.hxx:72
sal_uInt16 mnBitCount
static BitmapChecksum scanlineChecksum(BitmapChecksum nCrc, const sal_uInt8 *bits, int lineBitsCount, sal_uInt8 extraBitsMask)
Definition: salbmp.cxx:22
const BorderLinePrimitive2D *pCandidateB assert(pCandidateA)
#define bit(name)
sal_uInt8 GetBlue() const
ScanlineFormat mnFormat
float y
sal_uInt16 GetEntryCount() const
int i
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:266
sal_uInt8 * mpBits
exports com.sun.star.chart2. data
sal_uInt8 GetGreen() const
unsigned char sal_uInt8
constexpr::Color COL_WHITE(0xFF, 0xFF, 0xFF)
ScanlineFormat RemoveScanline(ScanlineFormat nFormat)
Definition: Scanline.hxx:57
BitmapPalette maPalette
virtual void ReleaseBuffer(BitmapBuffer *pBuffer, BitmapAccessMode nMode)=0
virtual BitmapBuffer * AcquireBuffer(BitmapAccessMode nMode)=0
typedef void(CALLTYPE *GetFuncDataPtr)(sal_uInt16 &nNo