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 
23 static 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 {
37  if (mbChecksumValid)
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  }
61  {
62  static const sal_uInt8 mask1Bit[] = { 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff };
63  extraBitsMask = mask1Bit[ extraBitsCount ];
64  break;
65  }
67  assert(extraBitsCount == 4);
68  extraBitsMask = 0xf0;
69  break;
71  assert(extraBitsCount == 4);
72  extraBitsMask = 0x0f;
73  break;
74  default:
75  break;
76  }
77  }
78  if( pBuf->mnFormat & ScanlineFormat::TopDown )
79  {
80  if( pBuf->mnScanlineSize == lineBitsCount / 8 )
81  nCrc = vcl_get_checksum(nCrc, pBuf->mpBits, pBuf->mnScanlineSize * pBuf->mnHeight);
82  else // Do not include padding with undefined content in the checksum.
83  for( tools::Long y = 0; y < pBuf->mnHeight; ++y )
84  nCrc = scanlineChecksum(nCrc, pBuf->mpBits + y * pBuf->mnScanlineSize, lineBitsCount, extraBitsMask);
85  }
86  else // Compute checksum in the order of scanlines, to make it consistent between different bitmap implementations.
87  {
88  for( tools::Long y = pBuf->mnHeight - 1; y >= 0; --y )
89  nCrc = scanlineChecksum(nCrc, pBuf->mpBits + y * pBuf->mnScanlineSize, lineBitsCount, extraBitsMask);
90  }
92  pThis->mnChecksum = nCrc;
93  pThis->mbChecksumValid = true;
94  }
95  else
96  {
97  pThis->mbChecksumValid = false;
98  }
99 }
100 
101 namespace
102 {
103 
104 class ImplPixelFormat
105 {
106 protected:
107  const sal_uInt8* mpData;
108 public:
109  static ImplPixelFormat* GetFormat( sal_uInt16 nBits, const BitmapPalette& rPalette );
110 
111  virtual void StartLine( const sal_uInt8* pLine ) { mpData = pLine; }
112  virtual const BitmapColor& ReadPixel() = 0;
113  virtual ~ImplPixelFormat() { }
114 };
115 
116 class ImplPixelFormat8 : public ImplPixelFormat
117 {
118 private:
119  const BitmapPalette& mrPalette;
120 
121 public:
122  explicit ImplPixelFormat8( const BitmapPalette& rPalette )
123  : mrPalette( rPalette )
124  {
125  }
126  virtual const BitmapColor& ReadPixel() override
127  {
128  assert( mrPalette.GetEntryCount() > *mpData );
129  return mrPalette[ *mpData++ ];
130  }
131 };
132 
133 class ImplPixelFormat4 : public ImplPixelFormat
134 {
135 private:
136  const BitmapPalette& mrPalette;
137  sal_uInt32 mnX;
138  sal_uInt32 mnShift;
139 
140 public:
141  explicit ImplPixelFormat4( const BitmapPalette& rPalette )
142  : mrPalette( rPalette )
143  , mnX(0)
144  , mnShift(4)
145  {
146  }
147  virtual void StartLine( const sal_uInt8* pLine ) override
148  {
149  mpData = pLine;
150  mnX = 0;
151  mnShift = 4;
152  }
153  virtual const BitmapColor& ReadPixel() override
154  {
155  sal_uInt32 nIdx = ( mpData[mnX >> 1] >> mnShift) & 0x0f;
156  assert( mrPalette.GetEntryCount() > nIdx );
157  const BitmapColor& rColor = mrPalette[nIdx];
158  mnX++;
159  mnShift ^= 4;
160  return rColor;
161  }
162 };
163 
164 class ImplPixelFormat1 : public ImplPixelFormat
165 {
166 private:
167  const BitmapPalette& mrPalette;
168  sal_uInt32 mnX;
169 
170 public:
171  explicit ImplPixelFormat1( const BitmapPalette& rPalette )
172  : mrPalette(rPalette)
173  , mnX(0)
174  {
175  }
176  virtual void StartLine( const sal_uInt8* pLine ) override
177  {
178  mpData = pLine;
179  mnX = 0;
180  }
181  virtual const BitmapColor& ReadPixel() override
182  {
183  const BitmapColor& rColor = mrPalette[ (mpData[mnX >> 3 ] >> ( 7 - ( mnX & 7 ) )) & 1];
184  mnX++;
185  return rColor;
186  }
187 };
188 
189 ImplPixelFormat* ImplPixelFormat::GetFormat( sal_uInt16 nBits, const BitmapPalette& rPalette )
190 {
191  switch( nBits )
192  {
193  case 1: return new ImplPixelFormat1( rPalette );
194  case 4: return new ImplPixelFormat4( rPalette );
195  case 8: return new ImplPixelFormat8( rPalette );
196  }
197 
198  return nullptr;
199 }
200 
201 // Optimized conversion from 1bpp. Currently LO uses 1bpp bitmaps for masks, which is nowadays
202 // a lousy obsolete format, as the memory saved is just not worth the cost of fiddling with the bits.
203 // Ideally LO should move to RGBA bitmaps. Until then, try to be faster with 1bpp bitmaps.
204 typedef void(*WriteColorFunction)( sal_uInt8 color8Bit, sal_uInt8*& dst );
205 void writeColorA8(sal_uInt8 color8Bit, sal_uInt8*& dst ) { *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 writeWhiteRGBA(sal_uInt8*& dst, int count ) { memset( dst, 0xff, count * 4 ); dst += count * 4; };
211 void writeBlackRGBA(sal_uInt8*& dst, int count )
212 {
213  for( int i = 0; i < count; ++i )
214  {
215  dst[0] = 0x00;
216  dst[1] = 0x00;
217  dst[2] = 0x00;
218  dst[3] = 0xff;
219  dst += 4;
220  }
221 };
222 
223 template< WriteColorFunction func, WriteBlackWhiteFunction funcBlack, WriteBlackWhiteFunction funcWhite >
224 void writeBlackWhiteData( const sal_uInt8* src, sal_uInt8* dst, int width, int height, int bytesPerRow )
225 {
226  for( int y = 0; y < height; ++y )
227  {
228  const sal_uInt8* srcLine = src;
229  int xsize = width;
230  while( xsize >= 64 )
231  {
232  // TODO alignment?
233  const sal_uInt64* src64 = reinterpret_cast< const sal_uInt64* >( src );
234  if( *src64 == 0x00 )
235  funcBlack( dst, 64 );
236  else if( *src64 == static_cast< sal_uInt64 >( -1 ))
237  funcWhite( dst, 64 );
238  else
239  break;
240  src += sizeof( sal_uInt64 );
241  xsize -= 64;
242  }
243  while( xsize >= 8 )
244  {
245  if( *src == 0x00 ) // => eight black pixels
246  funcBlack( dst, 8 );
247  else if( *src == 0xff ) // => eight white pixels
248  funcWhite( dst, 8 );
249  else
250  for( int bit = 7; bit >= 0; --bit )
251  func(( *src >> bit ) & 1 ? 0xff : 0, dst );
252  ++src;
253  xsize -= 8;
254  }
255  for( int bit = 7; bit > 7 - xsize; --bit )
256  func(( *src >> bit ) & 1 ? 0xff : 0, dst );
257  ++src;
258  src = srcLine + bytesPerRow;
259  }
260 }
261 
262 } // namespace
263 
264 std::unique_ptr< sal_uInt8[] > SalBitmap::convertDataBitCount( const sal_uInt8* src,
265  int width, int height, int bitCount, int bytesPerRow, const BitmapPalette& palette, BitConvert type )
266 {
267  assert( bitCount == 1 || bitCount == 4 || bitCount == 8 );
268  static const o3tl::enumarray<BitConvert, int> bpp = { 1, 4, 4 };
269  std::unique_ptr< sal_uInt8[] > data( new sal_uInt8[width * height * bpp[ type ]] );
270 
271  if(type == BitConvert::A8 && bitCount == 8 && palette.IsGreyPalette8Bit())
272  { // no actual data conversion
273  for( int y = 0; y < height; ++y )
274  memcpy( data.get() + y * width, src + y * bytesPerRow, width );
275  return data;
276  }
277 
278  if(bitCount == 1 && palette.GetEntryCount() == 2 && palette[ 0 ] == COL_BLACK && palette[ 1 ] == COL_WHITE)
279  {
280  switch( type )
281  {
282  case BitConvert::A8 :
283  writeBlackWhiteData< writeColorA8, writeBlackA8, writeWhiteA8 >
284  ( src, data.get(), width, height, bytesPerRow );
285  return data;
286  case BitConvert::BGRA :
287  case BitConvert::RGBA :
288  // BGRA/RGBA is the same, all 3 values get the same value
289  writeBlackWhiteData< writeColorRGBA, writeBlackRGBA, writeWhiteRGBA >
290  ( src, data.get(), width, height, bytesPerRow );
291  return data;
292  }
293  }
294 
295  std::unique_ptr<ImplPixelFormat> pSrcFormat(ImplPixelFormat::GetFormat(bitCount, palette));
296 
297  const sal_uInt8* pSrcData = src;
298  sal_uInt8* pDstData = data.get();
299 
300  sal_uInt32 nY = height;
301  while( nY-- )
302  {
303  pSrcFormat->StartLine( pSrcData );
304 
305  sal_uInt32 nX = width;
306  switch( type )
307  {
308  case BitConvert::A8 :
309  while( nX-- )
310  {
311  const BitmapColor& c = pSrcFormat->ReadPixel();
312  *pDstData++ = c.GetBlue();
313  }
314  break;
315  case BitConvert::BGRA :
316  while( nX-- )
317  {
318  const BitmapColor& c = pSrcFormat->ReadPixel();
319  *pDstData++ = c.GetBlue();
320  *pDstData++ = c.GetGreen();
321  *pDstData++ = c.GetRed();
322  *pDstData++ = 0xff;
323  }
324  break;
325  case BitConvert::RGBA :
326  while( nX-- )
327  {
328  const BitmapColor& c = pSrcFormat->ReadPixel();
329  *pDstData++ = c.GetRed();
330  *pDstData++ = c.GetGreen();
331  *pDstData++ = c.GetBlue();
332  *pDstData++ = 0xff;
333  }
334  break;
335  }
336 
337  pSrcData += bytesPerRow;
338  }
339  return data;
340 }
341 
342 /* 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.
sal_uInt8 GetRed() const
BitmapChecksum GetChecksum() const
void updateChecksum() const
Definition: salbmp.cxx:35
bool mbChecksumValid
Definition: salbmp.hxx:115
tools::Long mnHeight
long Long
BitmapChecksum mnChecksum
Definition: salbmp.hxx:114
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:23
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:264
sal_uInt8 * mpBits
exports com.sun.star.chart2. data
sal_uInt8 GetGreen() const
tools::Long mnScanlineSize
unsigned char sal_uInt8
const ::std::vector< Color > ImpSvNumberformatScan::StandardColor COL_WHITE
const ::std::vector< Color > ImpSvNumberformatScan::StandardColor COL_BLACK
ScanlineFormat RemoveScanline(ScanlineFormat nFormat)
Definition: Scanline.hxx:56
BitmapPalette maPalette
virtual void ReleaseBuffer(BitmapBuffer *pBuffer, BitmapAccessMode nMode)=0
tools::Long mnWidth
virtual BitmapBuffer * AcquireBuffer(BitmapAccessMode nMode)=0
typedef void(CALLTYPE *GetFuncDataPtr)(sal_uInt16 &nNo