LibreOffice Module vcl (master)  1
xpmread.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 <filter/XpmReader.hxx>
21 
22 #include <vcl/graph.hxx>
23 #include <tools/stream.hxx>
24 
27 
28 #include "rgbtable.hxx"
29 
30 #include <cstring>
31 #include <array>
32 #include <map>
33 
34 #define XPMTEMPBUFSIZE 0x00008000
35 #define XPMSTRINGBUF 0x00008000
36 
37 #define XPMIDENTIFIER 0x00000001 // mnIdentifier includes one of the six phases
38 #define XPMDEFINITION 0x00000002 // the XPM format consists of
39 #define XPMVALUES 0x00000003
40 #define XPMCOLORS 0x00000004
41 #define XPMPIXELS 0x00000005
42 #define XPMEXTENSIONS 0x00000006
43 #define XPMENDEXT 0x00000007
44 
45 #define XPMREMARK 0x00000001 // defines used by mnStatus
46 #define XPMDOUBLE 0x00000002
47 #define XPMSTRING 0x00000004
48 #define XPMFINISHED 0x00000008
49 
50 namespace {
51 
53 {
54  XPMREAD_OK,
55  XPMREAD_ERROR,
56  XPMREAD_NEED_MORE
57 };
58 
59 }
60 
61 class BitmapWriteAccess;
62 class Graphic;
63 
64 namespace {
65 
66 class XPMReader : public GraphicReader
67 {
68 private:
69 
70  SvStream& mrIStm;
71  Bitmap maBmp;
73  Bitmap maMaskBmp;
74  BitmapScopedWriteAccess mpMaskAcc;
75  tools::Long mnLastPos;
76 
79  sal_uLong mnColors;
80  sal_uInt32 mnCpp; // characters per pix
81  bool mbTransparent;
82  bool mbStatus;
83  sal_uLong mnStatus;
84  sal_uLong mnIdentifier;
85  sal_uInt8 mcThisByte;
86  sal_uInt8 mcLastByte;
87  sal_uLong mnTempAvail;
88  sal_uInt8* mpTempBuf;
89  sal_uInt8* mpTempPtr;
90  // each key is ( mnCpp )Byte(s)-> ASCII entry assigned to the colour
91  // each colordata is
92  // 1 Byte -> 0xFF if colour is transparent
93  // 3 Bytes -> RGB value of the colour
94  typedef std::array<sal_uInt8,4> colordata;
95  typedef std::map<OString, colordata> colormap;
96  colormap maColMap;
97  sal_uLong mnStringSize;
98  sal_uInt8* mpStringBuf;
99  sal_uLong mnParaSize;
100  sal_uInt8* mpPara;
101 
102  bool ImplGetString();
103  bool ImplGetColor();
104  bool ImplGetScanLine( sal_uLong );
105  bool ImplGetColSub(colordata &rDest);
106  bool ImplGetColKey( sal_uInt8 );
107  void ImplGetRGBHex(colordata &rDest, sal_uLong);
108  bool ImplGetPara( sal_uLong numb );
109  static bool ImplCompare(sal_uInt8 const *, sal_uInt8 const *, sal_uLong);
110  sal_uLong ImplGetULONG( sal_uLong nPara );
111 
112 public:
113  explicit XPMReader( SvStream& rStm );
114 
115  ReadState ReadXPM( Graphic& rGraphic );
116 };
117 
118 }
119 
120 XPMReader::XPMReader(SvStream& rStm)
121  : mrIStm(rStm)
122  , mnLastPos(rStm.Tell())
123  , mnWidth(0)
124  , mnHeight(0)
125  , mnColors(0)
126  , mnCpp(0)
127  , mbTransparent(false)
128  , mbStatus(true)
129  , mnStatus( 0 )
130  , mnIdentifier(XPMIDENTIFIER)
131  , mcThisByte(0)
132  , mcLastByte(0)
133  , mnTempAvail(0)
134  , mpTempBuf(nullptr)
135  , mpTempPtr(nullptr)
136  , mnStringSize(0)
137  , mpStringBuf(nullptr)
138  , mnParaSize(0)
139  , mpPara(nullptr)
140 {
141 }
142 
143 ReadState XPMReader::ReadXPM( Graphic& rGraphic )
144 {
145  ReadState eReadState;
146  sal_uInt8 cDummy;
147 
148  // check if we can real ALL
149  mrIStm.Seek( STREAM_SEEK_TO_END );
150  mrIStm.ReadUChar( cDummy );
151 
152  // if we could not read all
153  // return and wait for new data
154  if ( mrIStm.GetError() != ERRCODE_IO_PENDING )
155  {
156  mrIStm.Seek( mnLastPos );
157  mbStatus = true;
158 
159  if ( mbStatus )
160  {
161  mpStringBuf = new sal_uInt8 [ XPMSTRINGBUF ];
162  mpTempBuf = new sal_uInt8 [ XPMTEMPBUFSIZE ];
163 
164  mbStatus = ImplGetString();
165  if ( mbStatus )
166  {
167  mnIdentifier = XPMVALUES; // fetch Bitmap information
168  mnWidth = ImplGetULONG( 0 );
169  mnHeight = ImplGetULONG( 1 );
170  mnColors = ImplGetULONG( 2 );
171  mnCpp = ImplGetULONG( 3 );
172  }
173  if ( mnColors > ( SAL_MAX_UINT32 / ( 4 + mnCpp ) ) )
174  mbStatus = false;
175  if ( ( mnWidth * mnCpp ) >= XPMSTRINGBUF )
176  mbStatus = false;
177  //xpms are a minimum of one character (one byte) per pixel, so if the file isn't
178  //even that long, it's not all there
179  if (mrIStm.remainingSize() + mnTempAvail < static_cast<sal_uInt64>(mnWidth) * mnHeight)
180  mbStatus = false;
181  if ( mbStatus && mnWidth && mnHeight && mnColors && mnCpp )
182  {
183  mnIdentifier = XPMCOLORS;
184 
185  for (sal_uLong i = 0; i < mnColors; ++i)
186  {
187  if (!ImplGetColor())
188  {
189  mbStatus = false;
190  break;
191  }
192  }
193 
194  if ( mbStatus )
195  {
196  // create a 24bit graphic when more as 256 colours present
197  auto ePixelFormat = vcl::PixelFormat::INVALID;
198  if ( mnColors > 256 )
199  ePixelFormat = vcl::PixelFormat::N24_BPP;
200  else if ( mnColors > 2 )
201  ePixelFormat = vcl::PixelFormat::N8_BPP;
202  else
203  ePixelFormat = vcl::PixelFormat::N1_BPP;
204 
205  maBmp = Bitmap(Size(mnWidth, mnHeight), ePixelFormat);
206  mpAcc = BitmapScopedWriteAccess(maBmp);
207 
208  // mbTransparent is TRUE if at least one colour is transparent
209  if ( mbTransparent )
210  {
211  maMaskBmp = Bitmap(Size(mnWidth, mnHeight), vcl::PixelFormat::N1_BPP);
212  mpMaskAcc = BitmapScopedWriteAccess(maMaskBmp);
213  if ( !mpMaskAcc )
214  mbStatus = false;
215  }
216  if( mpAcc && mbStatus )
217  {
218  if (mnColors <= 256) // palette is only needed by using less than 257
219  { // colors
220  sal_uInt8 i = 0;
221  for (auto& elem : maColMap)
222  {
223  mpAcc->SetPaletteColor(i, Color(elem.second[1], elem.second[2], elem.second[3]));
224  //reuse map entry, overwrite color with palette index
225  elem.second[1] = i;
226  i++;
227  }
228  }
229 
230  // now we get the bitmap data
231  mnIdentifier = XPMPIXELS;
232  for (sal_uLong i = 0; i < mnHeight; ++i)
233  {
234  if ( !ImplGetScanLine( i ) )
235  {
236  mbStatus = false;
237  break;
238  }
239  }
240  mnIdentifier = XPMEXTENSIONS;
241  }
242  }
243  }
244 
245  delete[] mpStringBuf;
246  delete[] mpTempBuf;
247 
248  }
249  if( mbStatus )
250  {
251  mpAcc.reset();
252  if ( mpMaskAcc )
253  {
254  mpMaskAcc.reset();
255  rGraphic = Graphic( BitmapEx( maBmp, maMaskBmp ) );
256  }
257  else
258  {
259  rGraphic = BitmapEx(maBmp);
260  }
261  eReadState = XPMREAD_OK;
262  }
263  else
264  {
265  mpMaskAcc.reset();
266  mpAcc.reset();
267 
268  eReadState = XPMREAD_ERROR;
269  }
270  }
271  else
272  {
273  mrIStm.ResetError();
274  eReadState = XPMREAD_NEED_MORE;
275  }
276  return eReadState;
277 }
278 
279 // ImplGetColor returns various colour values,
280 // returns TRUE if various colours could be assigned
281 bool XPMReader::ImplGetColor()
282 {
283  sal_uInt8* pString = mpStringBuf;
284  if (!ImplGetString())
285  return false;
286 
287  if (mnStringSize < mnCpp)
288  return false;
289 
290  OString aKey(reinterpret_cast<char*>(pString), mnCpp);
291  colordata aValue;
292  bool bStatus = ImplGetColSub(aValue);
293  if (bStatus)
294  {
295  maColMap[aKey] = aValue;
296  }
297  return bStatus;
298 }
299 
300 // ImpGetScanLine reads the string mpBufSize and writes the pixel in the
301 // Bitmap. Parameter nY is the horizontal position.
302 bool XPMReader::ImplGetScanLine( sal_uLong nY )
303 {
304  bool bStatus = ImplGetString();
305  sal_uInt8* pString = mpStringBuf;
306  BitmapColor aWhite;
307  BitmapColor aBlack;
308 
309  if ( bStatus )
310  {
311  if ( mpMaskAcc )
312  {
313  aWhite = mpMaskAcc->GetBestMatchingColor( COL_WHITE );
314  aBlack = mpMaskAcc->GetBestMatchingColor( COL_BLACK );
315  }
316  if ( mnStringSize != ( mnWidth * mnCpp ))
317  bStatus = false;
318  else
319  {
320  Scanline pScanline = mpAcc->GetScanline(nY);
321  Scanline pMaskScanline = mpMaskAcc ? mpMaskAcc->GetScanline(nY) : nullptr;
322  for (sal_uLong i = 0; i < mnWidth; ++i)
323  {
324  OString aKey(reinterpret_cast<char*>(pString), mnCpp);
325  auto it = maColMap.find(aKey);
326  if (it != maColMap.end())
327  {
328  if (mnColors > 256)
329  mpAcc->SetPixelOnData(pScanline, i, Color(it->second[1], it->second[2], it->second[3]));
330  else
331  mpAcc->SetPixelOnData(pScanline, i, BitmapColor(it->second[1]));
332  if (pMaskScanline)
333  mpMaskAcc->SetPixelOnData(pMaskScanline, i, it->second[0] ? aWhite : aBlack);
334  }
335  pString += mnCpp;
336  }
337  }
338  }
339  return bStatus;
340 }
341 
342 // tries to determine a colour value from mpStringBuf
343 // if a colour was found the RGB value is written a pDest[1]..pDest[2]
344 // pDest[0] contains 0xFF if the colour is transparent otherwise 0
345 
346 bool XPMReader::ImplGetColSub(colordata &rDest)
347 {
348  unsigned char cTransparent[] = "None";
349 
350  bool bColStatus = false;
351 
352  if ( ImplGetColKey( 'c' ) || ImplGetColKey( 'm' ) || ImplGetColKey( 'g' ) )
353  {
354  // hexentry for RGB or HSV color ?
355  if (*mpPara == '#')
356  {
357  rDest[0] = 0;
358  bColStatus = true;
359  switch ( mnParaSize )
360  {
361  case 25 :
362  ImplGetRGBHex(rDest, 6);
363  break;
364  case 13 :
365  ImplGetRGBHex(rDest, 2);
366  break;
367  case 7 :
368  ImplGetRGBHex(rDest, 0);
369  break;
370  default:
371  bColStatus = false;
372  break;
373  }
374  }
375  // maybe pixel is transparent
376  else if ( ImplCompare( &cTransparent[0], mpPara, 4 ))
377  {
378  rDest[0] = 0xff;
379  bColStatus = true;
380  mbTransparent = true;
381  }
382  // last we will try to get the colorname
383  else if ( mnParaSize > 2 ) // name must enlarge the minimum size
384  {
385  sal_uLong i = 0;
386  while ( true )
387  {
388  if ( pRGBTable[ i ].name == nullptr )
389  break;
390  if ( std::strlen(pRGBTable[i].name) > mnParaSize &&
391  pRGBTable[ i ].name[ mnParaSize ] == 0 )
392  {
393  if ( ImplCompare ( reinterpret_cast<unsigned char const *>(pRGBTable[ i ].name),
394  mpPara, mnParaSize ) )
395  {
396  bColStatus = true;
397  rDest[0] = 0;
398  rDest[1] = pRGBTable[i].red;
399  rDest[2] = pRGBTable[i].green;
400  rDest[3] = pRGBTable[i].blue;
401  break;
402  }
403  }
404  i++;
405  }
406  }
407  }
408  return bColStatus;
409 }
410 
411 // ImplGetColKey searches string mpStringBuf for a parameter 'nKey'
412 // and returns a boolean. (if TRUE mpPara and mnParaSize will be set)
413 
414 bool XPMReader::ImplGetColKey( sal_uInt8 nKey )
415 {
416  sal_uInt8 nTemp, nPrev = ' ';
417 
418  if (mnStringSize < mnCpp + 1)
419  return false;
420 
421  mpPara = mpStringBuf + mnCpp + 1;
422  mnParaSize = 0;
423 
424  while ( *mpPara != 0 )
425  {
426  if ( *mpPara == nKey )
427  {
428  nTemp = *( mpPara + 1 );
429  if ( nTemp == ' ' || nTemp == 0x09 )
430  {
431  if ( nPrev == ' ' || nPrev == 0x09 )
432  break;
433  }
434  }
435  nPrev = *mpPara;
436  mpPara++;
437  }
438  if ( *mpPara )
439  {
440  mpPara++;
441  while ( (*mpPara == ' ') || (*mpPara == 0x09) )
442  {
443  mpPara++;
444  }
445  if ( *mpPara != 0 )
446  {
447  while ( *(mpPara+mnParaSize) != ' ' && *(mpPara+mnParaSize) != 0x09 &&
448  *(mpPara+mnParaSize) != 0 )
449  {
450  mnParaSize++;
451  }
452  }
453  }
454  return mnParaSize != 0;
455 }
456 
457 // ImplGetRGBHex translates the ASCII-Hexadecimalvalue belonging to mpPara
458 // in a RGB value and writes this to rDest
459 // below formats should be contained in mpPara:
460 // if nAdd = 0 : '#12ab12' -> RGB = 0x12, 0xab, 0x12
461 // 2 : '#1234abcd1234' " " " "
462 // 6 : '#12345678abcdefab12345678' " " " "
463 
464 void XPMReader::ImplGetRGBHex(colordata &rDest, sal_uLong nAdd)
465 {
466  sal_uInt8* pPtr = mpPara+1;
467 
468  for (sal_uLong i = 1; i < 4; ++i)
469  {
470  sal_uInt8 nHex = (*pPtr++) - '0';
471  if ( nHex > 9 )
472  nHex = ((nHex - 'A' + '0') & 7) + 10;
473 
474  sal_uInt8 nTemp = (*pPtr++) - '0';
475  if ( nTemp > 9 )
476  nTemp = ((nTemp - 'A' + '0') & 7) + 10;
477  nHex = ( nHex << 4 ) + nTemp;
478 
479  pPtr += nAdd;
480  rDest[i] = nHex;
481  }
482 }
483 
484 // ImplGetUlong returns the value of a up to 6-digit long ASCII-decimal number.
485 
486 sal_uLong XPMReader::ImplGetULONG( sal_uLong nPara )
487 {
488  if ( ImplGetPara ( nPara ) )
489  {
490  sal_uLong nRetValue = 0;
491  sal_uInt8* pPtr = mpPara;
492 
493  if ( ( mnParaSize > 6 ) || ( mnParaSize == 0 ) ) return 0;
494  for ( sal_uLong i = 0; i < mnParaSize; i++ )
495  {
496  sal_uInt8 j = (*pPtr++) - 48;
497  if ( j > 9 ) return 0; // ascii is invalid
498  nRetValue*=10;
499  nRetValue+=j;
500  }
501  return nRetValue;
502  }
503  else return 0;
504 }
505 
506 bool XPMReader::ImplCompare(sal_uInt8 const * pSource, sal_uInt8 const * pDest, sal_uLong nSize)
507 {
508  for (sal_uLong i = 0; i < nSize; ++i)
509  {
510  if ( ( pSource[i]&~0x20 ) != ( pDest[i]&~0x20 ) )
511  {
512  return false;
513  }
514  }
515  return true;
516 }
517 
518 // ImplGetPara tries to retrieve nNumb (0...x) parameters from mpStringBuf.
519 // Parameters are separated by spaces or tabs.
520 // If a parameter was found then the return value is TRUE and mpPara + mnParaSize
521 // are set.
522 
523 bool XPMReader::ImplGetPara ( sal_uLong nNumb )
524 {
525  sal_uInt8 nByte;
526  sal_uLong nSize = 0;
527  sal_uInt8* pPtr = mpStringBuf;
528  sal_uLong nCount = 0;
529 
530  if ( ( *pPtr != ' ' ) && ( *pPtr != 0x09 ) )
531  {
532  mpPara = pPtr;
533  mnParaSize = 0;
534  nCount = 0;
535  }
536  else
537  {
538  mpPara = nullptr;
539  nCount = 0xffffffff;
540  }
541 
542  while ( nSize < mnStringSize )
543  {
544  nByte = *pPtr;
545 
546  if ( mpPara )
547  {
548  if ( ( nByte == ' ' ) || ( nByte == 0x09 ) )
549  {
550  if ( nCount == nNumb )
551  break;
552  else
553  mpPara = nullptr;
554  }
555  else
556  mnParaSize++;
557  }
558  else
559  {
560  if ( ( nByte != ' ' ) && ( nByte != 0x09 ) )
561  {
562  mpPara = pPtr;
563  mnParaSize = 1;
564  nCount++;
565  }
566  }
567  nSize++;
568  pPtr++;
569  }
570  return ( ( nCount == nNumb ) && mpPara );
571 }
572 
573 // The next string is read and stored in mpStringBuf (terminated with 0);
574 // mnStringSize contains the size of the string read.
575 // Comments like '//' and '/*...*/' are skipped.
576 
577 bool XPMReader::ImplGetString()
578 {
579  sal_uInt8 const sID[] = "/* XPM */";
580  sal_uInt8* pString = mpStringBuf;
581 
582  mnStringSize = 0;
583  mpStringBuf[0] = 0;
584 
585  while( mbStatus && ( mnStatus != XPMFINISHED ) )
586  {
587  if ( mnTempAvail == 0 )
588  {
589  mnTempAvail = mrIStm.ReadBytes( mpTempBuf, XPMTEMPBUFSIZE );
590  if ( mnTempAvail == 0 )
591  break;
592 
593  mpTempPtr = mpTempBuf;
594 
595  if ( mnIdentifier == XPMIDENTIFIER )
596  {
597  if ( mnTempAvail <= 50 )
598  {
599  mbStatus = false; // file is too short to be a correct XPM format
600  break;
601  }
602  for ( int i = 0; i < 9; i++ ) // searching for "/* XPM */"
603  if ( *mpTempPtr++ != sID[i] )
604  {
605  mbStatus = false;
606  break;
607  }
608  mnTempAvail-=9;
609  mnIdentifier++;
610  }
611  }
612  mcLastByte = mcThisByte;
613  mcThisByte = *mpTempPtr++;
614  mnTempAvail--;
615 
616  if ( mnStatus & XPMDOUBLE )
617  {
618  if ( mcThisByte == 0x0a )
619  mnStatus &=~XPMDOUBLE;
620  continue;
621  }
622  if ( mnStatus & XPMREMARK )
623  {
624  if ( ( mcThisByte == '/' ) && ( mcLastByte == '*' ) )
625  mnStatus &=~XPMREMARK;
626  continue;
627  }
628  if ( mnStatus & XPMSTRING ) // characters in string
629  {
630  if ( mcThisByte == '"' )
631  {
632  mnStatus &=~XPMSTRING; // end of parameter by eol
633  break;
634  }
635  if ( mnStringSize >= ( XPMSTRINGBUF - 1 ) )
636  {
637  mbStatus = false;
638  break;
639  }
640  *pString++ = mcThisByte;
641  pString[0] = 0;
642  mnStringSize++;
643  continue;
644  }
645  else
646  { // characters beside string
647  switch ( mcThisByte )
648  {
649  case '*' :
650  if ( mcLastByte == '/' ) mnStatus |= XPMREMARK;
651  break;
652  case '/' :
653  if ( mcLastByte == '/' ) mnStatus |= XPMDOUBLE;
654  break;
655  case '"' : mnStatus |= XPMSTRING;
656  break;
657  case '{' :
658  if ( mnIdentifier == XPMDEFINITION )
659  mnIdentifier++;
660  break;
661  case '}' :
662  if ( mnIdentifier == XPMENDEXT )
663  mnStatus = XPMFINISHED;
664  break;
665  }
666  }
667  }
668  return mbStatus;
669 }
670 
671 
672 VCL_DLLPUBLIC bool ImportXPM( SvStream& rStm, Graphic& rGraphic )
673 {
674  std::shared_ptr<GraphicReader> pContext = rGraphic.GetReaderContext();
675  rGraphic.SetReaderContext(nullptr);
676  XPMReader* pXPMReader = dynamic_cast<XPMReader*>( pContext.get() );
677  if (!pXPMReader)
678  {
679  pContext = std::make_shared<XPMReader>( rStm );
680  pXPMReader = static_cast<XPMReader*>( pContext.get() );
681  }
682 
683  bool bRet = true;
684 
685  ReadState eReadState = pXPMReader->ReadXPM( rGraphic );
686 
687  if( eReadState == XPMREAD_ERROR )
688  {
689  bRet = false;
690  }
691  else if( eReadState == XPMREAD_NEED_MORE )
692  rGraphic.SetReaderContext( pContext );
693 
694  return bRet;
695 }
696 
697 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
double mnHeight
#define XPMIDENTIFIER
Definition: xpmread.cxx:37
#define XPMENDEXT
Definition: xpmread.cxx:43
#define VCL_DLLPUBLIC
Definition: dllapi.h:29
sal_uIntPtr sal_uLong
#define XPMSTRINGBUF
Definition: xpmread.cxx:35
long Long
#define XPMDEFINITION
Definition: xpmread.cxx:38
ReadState
Definition: gifread.cxx:44
This template handles BitmapAccess the RAII way.
vcl::ScopedBitmapAccess< BitmapWriteAccess, Bitmap,&Bitmap::AcquireWriteAccess > BitmapScopedWriteAccess
void SetReaderContext(const std::shared_ptr< GraphicReader > &pReader)
Definition: graph.cxx:482
const XPMRGBTab pRGBTable[]
Definition: rgbtable.hxx:33
int nCount
VCL_DLLPUBLIC bool ImportXPM(SvStream &rStm, Graphic &rGraphic)
Definition: xpmread.cxx:672
#define XPMEXTENSIONS
Definition: xpmread.cxx:42
sal_uInt8 * Scanline
Definition: Scanline.hxx:26
#define XPMDOUBLE
Definition: xpmread.cxx:46
int i
#define XPMCOLORS
Definition: xpmread.cxx:40
#define XPMFINISHED
Definition: xpmread.cxx:48
#define XPMSTRING
Definition: xpmread.cxx:47
#define XPMTEMPBUFSIZE
Definition: xpmread.cxx:34
#define XPMREMARK
Definition: xpmread.cxx:45
sal_uInt8 blue
Definition: rgbtable.hxx:30
sal_uInt8 red
Definition: rgbtable.hxx:28
unsigned char sal_uInt8
std::shared_ptr< GraphicReader > & GetReaderContext()
Definition: graph.cxx:477
double mnWidth
#define XPMVALUES
Definition: xpmread.cxx:39
#define ERRCODE_IO_PENDING
Definition: errcode.hxx:225
#define XPMPIXELS
Definition: xpmread.cxx:41
sal_uInt8 green
Definition: rgbtable.hxx:29