LibreOffice Module vcl (master)  1
iras.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 
21 #include <vcl/graph.hxx>
22 #include <vcl/BitmapTools.hxx>
23 #include <sal/log.hxx>
24 #include <tools/stream.hxx>
25 #include <filter/RasReader.hxx>
26 
27 class FilterConfigItem;
28 
29 #define RAS_TYPE_OLD 0x00000000 // supported formats by this filter
30 #define RAS_TYPE_STANDARD 0x00000001
31 #define RAS_TYPE_BYTE_ENCODED 0x00000002
32 #define RAS_TYPE_RGB_FORMAT 0x00000003
33 
34 #define RAS_COLOR_NO_MAP 0x00000000
35 #define RAS_COLOR_RGB_MAP 0x00000001
36 #define RAS_COLOR_RAW_MAP 0x00000002
37 
38 #define SUNRASTER_MAGICNUMBER 0x59a66a95
39 
40 //============================ RASReader ==================================
41 
42 namespace {
43 
44 class RASReader {
45 
46 private:
47 
48  SvStream& m_rRAS; // the RAS file to be read in
49 
50  bool mbStatus;
51  sal_Int32 mnWidth, mnHeight; // image dimensions in pixels
52  sal_uInt16 mnDstBitsPerPix;
53  sal_uInt16 mnDstColors;
54  sal_Int32 mnDepth, mnImageDatSize, mnType;
55  sal_Int32 mnColorMapType, mnColorMapSize;
56  sal_uInt8 mnRepCount, mnRepVal; // RLE Decoding
57 
58  bool ImplReadBody(vcl::bitmap::RawBitmap&, std::vector<Color> const & rvPalette);
59  bool ImplReadHeader();
60  sal_uInt8 ImplGetByte();
61 
62 public:
63  explicit RASReader(SvStream &rRAS);
64  bool ReadRAS(Graphic & rGraphic);
65 };
66 
67 }
68 
69 //=================== Methods of RASReader ==============================
70 
71 RASReader::RASReader(SvStream &rRAS)
72  : m_rRAS(rRAS)
73  , mbStatus(true)
74  , mnWidth(0)
75  , mnHeight(0)
76  , mnDstBitsPerPix(0)
77  , mnDstColors(0)
78  , mnDepth(0)
79  , mnImageDatSize(0)
80  , mnType(0)
81  , mnColorMapType(0)
82  , mnColorMapSize(0)
83  , mnRepCount(0)
84  , mnRepVal(0)
85 {
86 }
87 
88 bool RASReader::ReadRAS(Graphic & rGraphic)
89 {
90  sal_uInt32 nMagicNumber;
91 
92  if ( m_rRAS.GetError() )
93  return false;
94 
95  m_rRAS.SetEndian( SvStreamEndian::BIG );
96  m_rRAS.ReadUInt32( nMagicNumber );
97  if (!m_rRAS.good() || nMagicNumber != SUNRASTER_MAGICNUMBER)
98  return false;
99 
100  // Kopf einlesen:
101 
102  mbStatus = ImplReadHeader();
103  if ( !mbStatus )
104  return false;
105 
106  std::vector<Color> aPalette;
107  bool bOk = true;
108 
109  if ( mnDstBitsPerPix <= 8 ) // pallets pictures
110  {
111  bool bPalette(false);
112 
113  if ( mnColorMapType == RAS_COLOR_RAW_MAP ) // RAW color map is skipped
114  {
115  sal_uInt64 nCurPos = m_rRAS.Tell();
116  bOk = checkSeek(m_rRAS, nCurPos + mnColorMapSize);
117  }
118  else if ( mnColorMapType == RAS_COLOR_RGB_MAP ) // we can read out the RGB
119  {
120  mnDstColors = static_cast<sal_uInt16>( mnColorMapSize / 3 );
121 
122  if ( ( 1 << mnDstBitsPerPix ) < mnDstColors )
123  return false;
124 
125  if ( ( mnDstColors >= 2 ) && ( ( mnColorMapSize % 3 ) == 0 ) )
126  {
127  aPalette.resize(mnDstColors);
128  sal_uInt16 i;
129  sal_uInt8 nRed[256], nGreen[256], nBlue[256];
130  for ( i = 0; i < mnDstColors; i++ ) m_rRAS.ReadUChar( nRed[ i ] );
131  for ( i = 0; i < mnDstColors; i++ ) m_rRAS.ReadUChar( nGreen[ i ] );
132  for ( i = 0; i < mnDstColors; i++ ) m_rRAS.ReadUChar( nBlue[ i ] );
133  for ( i = 0; i < mnDstColors; i++ )
134  {
135  aPalette[i] = Color(nRed[ i ], nGreen[ i ], nBlue[ i ]);
136  }
137  bPalette = true;
138  }
139  else
140  return false;
141 
142  }
143  else if ( mnColorMapType != RAS_COLOR_NO_MAP ) // everything else is not standard
144  return false;
145 
146  if (!bPalette)
147  {
148  mnDstColors = 1 << mnDstBitsPerPix;
149  aPalette.resize(mnDstColors);
150  for ( sal_uInt16 i = 0; i < mnDstColors; i++ )
151  {
152  sal_uInt8 nCount = 255 - ( 255 * i / ( mnDstColors - 1 ) );
153  aPalette[i] = Color(nCount, nCount, nCount);
154  }
155  }
156  }
157  else
158  {
159  if ( mnColorMapType != RAS_COLOR_NO_MAP ) // when graphic has more than 256 colors and a color map we skip
160  { // the colormap
161  sal_uInt64 nCurPos = m_rRAS.Tell();
162  bOk = checkSeek(m_rRAS, nCurPos + mnColorMapSize);
163  }
164  }
165 
166  if (!bOk)
167  return false;
168 
169  //The RLE packets are typically three bytes in size:
170  //The first byte is a Flag Value indicating the type of RLE packet.
171  //The second byte is the Run Count.
172  //The third byte is the Run Value.
173  //
174  //for the sake of simplicity we'll assume that RAS_TYPE_BYTE_ENCODED can
175  //describe data 255 times larger than the data stored
176  size_t nMaxCompression = mnType != RAS_TYPE_BYTE_ENCODED ? 1 : 255;
177  sal_Int32 nBitSize;
178  if (o3tl::checked_multiply<sal_Int32>(mnWidth, mnHeight, nBitSize) || o3tl::checked_multiply<sal_Int32>(nBitSize, mnDepth, nBitSize))
179  return false;
180  if (m_rRAS.remainingSize() * nMaxCompression < static_cast<sal_uInt32>(nBitSize) / 8)
181  return false;
182 
183  vcl::bitmap::RawBitmap aBmp(Size(mnWidth, mnHeight), 24);
184 
185  // read in the bitmap data
186  mbStatus = ImplReadBody(aBmp, aPalette);
187 
188  if ( mbStatus )
189  rGraphic = vcl::bitmap::CreateFromData(std::move(aBmp));
190 
191  return mbStatus;
192 }
193 
194 bool RASReader::ImplReadHeader()
195 {
196  m_rRAS.ReadInt32(mnWidth).ReadInt32(mnHeight).ReadInt32(mnDepth).ReadInt32(mnImageDatSize).ReadInt32(mnType).ReadInt32(mnColorMapType).ReadInt32(mnColorMapSize);
197 
198  if (!m_rRAS.good() || mnWidth <= 0 || mnHeight <= 0 || mnImageDatSize <= 0)
199  mbStatus = false;
200 
201  switch ( mnDepth )
202  {
203  case 24 :
204  case 8 :
205  case 1 :
206  mnDstBitsPerPix = static_cast<sal_uInt16>(mnDepth);
207  break;
208  case 32 :
209  mnDstBitsPerPix = 24;
210  break;
211 
212  default :
213  mbStatus = false;
214  }
215 
216  switch ( mnType )
217  {
218  case RAS_TYPE_OLD :
219  case RAS_TYPE_STANDARD :
220  case RAS_TYPE_RGB_FORMAT :
221  case RAS_TYPE_BYTE_ENCODED : // this type will be supported later
222  break;
223 
224  default:
225  mbStatus = false;
226  }
227  return mbStatus;
228 }
229 
230 namespace
231 {
232  const Color& SanitizePaletteIndex(std::vector<Color> const & rvPalette, sal_uInt8 nIndex)
233  {
234  if (nIndex >= rvPalette.size())
235  {
236  auto nSanitizedIndex = nIndex % rvPalette.size();
237  SAL_WARN_IF(nIndex != nSanitizedIndex, "filter.ras", "invalid colormap index: "
238  << static_cast<unsigned int>(nIndex) << ", colormap len is: "
239  << rvPalette.size());
240  nIndex = nSanitizedIndex;
241  }
242  return rvPalette[nIndex];
243  }
244 }
245 
246 bool RASReader::ImplReadBody(vcl::bitmap::RawBitmap& rBitmap, std::vector<Color> const & rvPalette)
247 {
248  sal_Int32 x, y;
249  sal_uInt8 nRed, nGreen, nBlue;
250  switch ( mnDstBitsPerPix )
251  {
252  case 1 :
253  {
254  sal_uInt8 nDat = 0;
255  for (y = 0; y < mnHeight && mbStatus; ++y)
256  {
257  for (x = 0; x < mnWidth && mbStatus; ++x)
258  {
259  if (!(x & 7))
260  {
261  nDat = ImplGetByte();
262  if (!m_rRAS.good())
263  mbStatus = false;
264  }
265  rBitmap.SetPixel(y, x, SanitizePaletteIndex(rvPalette,
266  sal::static_int_cast< sal_uInt8 >(
267  nDat >> ( ( x & 7 ) ^ 7 ))));
268  }
269  if (!( ( x - 1 ) & 0x8 ) )
270  {
271  ImplGetByte(); // WORD ALIGNMENT ???
272  if (!m_rRAS.good())
273  mbStatus = false;
274  }
275  }
276  break;
277  }
278 
279  case 8 :
280  for (y = 0; y < mnHeight && mbStatus; ++y)
281  {
282  for (x = 0; x < mnWidth && mbStatus; ++x)
283  {
284  sal_uInt8 nDat = ImplGetByte();
285  rBitmap.SetPixel(y, x, SanitizePaletteIndex(rvPalette, nDat));
286  if (!m_rRAS.good())
287  mbStatus = false;
288  }
289  if ( x & 1 )
290  {
291  ImplGetByte(); // WORD ALIGNMENT ???
292  if (!m_rRAS.good())
293  mbStatus = false;
294  }
295  }
296  break;
297 
298  case 24 :
299  switch ( mnDepth )
300  {
301 
302  case 24 :
303  for (y = 0; y < mnHeight && mbStatus; ++y)
304  {
305  for (x = 0; x < mnWidth && mbStatus; ++x)
306  {
307  if ( mnType == RAS_TYPE_RGB_FORMAT )
308  {
309  nRed = ImplGetByte();
310  nGreen = ImplGetByte();
311  nBlue = ImplGetByte();
312  }
313  else
314  {
315  nBlue = ImplGetByte();
316  nGreen = ImplGetByte();
317  nRed = ImplGetByte();
318  }
319  rBitmap.SetPixel(y, x, Color(nRed, nGreen, nBlue));
320  if (!m_rRAS.good())
321  mbStatus = false;
322  }
323  if ( x & 1 )
324  {
325  ImplGetByte(); // WORD ALIGNMENT ???
326  if (!m_rRAS.good())
327  mbStatus = false;
328  }
329  }
330  break;
331 
332  case 32 :
333  for (y = 0; y < mnHeight && mbStatus; ++y)
334  {
335  for (x = 0; x < mnWidth && mbStatus; ++x)
336  {
337  ImplGetByte(); // pad byte > nil
338  if ( mnType == RAS_TYPE_RGB_FORMAT )
339  {
340  nRed = ImplGetByte();
341  nGreen = ImplGetByte();
342  nBlue = ImplGetByte();
343  }
344  else
345  {
346  nBlue = ImplGetByte();
347  nGreen = ImplGetByte();
348  nRed = ImplGetByte();
349  }
350  rBitmap.SetPixel(y, x, Color(nRed, nGreen, nBlue));
351  if (!m_rRAS.good())
352  mbStatus = false;
353  }
354  }
355  break;
356  }
357  break;
358 
359  default:
360  mbStatus = false;
361  break;
362  }
363  return mbStatus;
364 }
365 
366 sal_uInt8 RASReader::ImplGetByte()
367 {
368  sal_uInt8 nRetVal(0);
369  if ( mnType != RAS_TYPE_BYTE_ENCODED )
370  {
371  m_rRAS.ReadUChar( nRetVal );
372  return nRetVal;
373  }
374  else
375  {
376  if ( mnRepCount )
377  {
378  mnRepCount--;
379  return mnRepVal;
380  }
381  else
382  {
383  m_rRAS.ReadUChar( nRetVal );
384  if ( nRetVal != 0x80 )
385  return nRetVal;
386  m_rRAS.ReadUChar( nRetVal );
387  if ( nRetVal == 0 )
388  return 0x80;
389  mnRepCount = nRetVal ;
390  m_rRAS.ReadUChar( mnRepVal );
391  return mnRepVal;
392  }
393  }
394 }
395 
396 //================== GraphicImport - the exported function ================
397 
398 bool ImportRasGraphic( SvStream & rStream, Graphic & rGraphic)
399 {
400  bool bRet = false;
401 
402  try
403  {
404  RASReader aRASReader(rStream);
405  bRet = aRASReader.ReadRAS(rGraphic );
406  }
407  catch (...)
408  {
409  }
410 
411  return bRet;
412 }
413 
414 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
double mnHeight
#define RAS_TYPE_OLD
Definition: iras.cxx:29
#define SUNRASTER_MAGICNUMBER
Definition: iras.cxx:38
#define RAS_COLOR_RGB_MAP
Definition: iras.cxx:35
float x
bool ImportRasGraphic(SvStream &rStream, Graphic &rGraphic)
Definition: iras.cxx:398
int nCount
float y
#define RAS_COLOR_RAW_MAP
Definition: iras.cxx:36
#define RAS_TYPE_STANDARD
Definition: iras.cxx:30
sal_Int32 mnDepth
bool checkSeek(SvStream &rSt, sal_uInt64 nOffset)
int i
sal_Int32 mnType
Intended to be used to feed into CreateFromData to create a BitmapEx.
Definition: RawBitmap.hxx:21
#define RAS_COLOR_NO_MAP
Definition: iras.cxx:34
#define SAL_WARN_IF(condition, area, stream)
unsigned char sal_uInt8
#define RAS_TYPE_BYTE_ENCODED
Definition: iras.cxx:31
#define RAS_TYPE_RGB_FORMAT
Definition: iras.cxx:32
double mnWidth
BitmapEx CreateFromData(sal_uInt8 const *pData, sal_Int32 nWidth, sal_Int32 nHeight, sal_Int32 nStride, vcl::PixelFormat ePixelFormat, bool bReversColors, bool bReverseAlpha)
Copy block of image data into the bitmap.
void SetPixel(tools::Long nY, tools::Long nX, Color nColor)
Definition: RawBitmap.hxx:47