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
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
42namespace {
43
44class RASReader {
45
46private:
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
62public:
63 explicit RASReader(SvStream &rRAS);
64 bool ReadRAS(Graphic & rGraphic);
65};
66
67}
68
69//=================== Methods of RASReader ==============================
70
71RASReader::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
88bool 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
194bool 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 :
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
230namespace
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
246bool 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
366sal_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
398bool 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: */
sal_Int32 mnDepth
Intended to be used to feed into CreateFromData to create a BitmapEx.
Definition: RawBitmap.hxx:22
void SetPixel(tools::Long nY, tools::Long nX, Color nColor)
Definition: RawBitmap.hxx:47
int nCount
float y
float x
sal_Int32 nIndex
#define RAS_TYPE_RGB_FORMAT
Definition: iras.cxx:32
#define RAS_COLOR_RGB_MAP
Definition: iras.cxx:35
bool ImportRasGraphic(SvStream &rStream, Graphic &rGraphic)
Definition: iras.cxx:398
#define RAS_TYPE_OLD
Definition: iras.cxx:29
#define RAS_COLOR_RAW_MAP
Definition: iras.cxx:36
#define SUNRASTER_MAGICNUMBER
Definition: iras.cxx:38
#define RAS_COLOR_NO_MAP
Definition: iras.cxx:34
#define RAS_TYPE_BYTE_ENCODED
Definition: iras.cxx:31
#define RAS_TYPE_STANDARD
Definition: iras.cxx:30
#define SAL_WARN_IF(condition, area, stream)
int i
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.
sal_Int32 mnType
double mnWidth
double mnHeight
TOOLS_DLLPUBLIC bool checkSeek(SvStream &rSt, sal_uInt64 nOffset)
unsigned char sal_uInt8