1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: xpmread.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_svtools.hxx"
35 #include <vcl/bmpacc.hxx>
38 #include <vcl/graph.hxx>
40 #include "rgbtable.hxx"
42 #include "xpmread.hxx"
48 XPMReader::XPMReader( SvStream
& rStm
) :
52 mnLastPos ( rStm
.Tell() ),
57 mbTransparent ( FALSE
),
60 mnIdentifier ( XPMIDENTIFIER
),
63 mpFastColorTable( NULL
),
69 // ------------------------------------------------------------------------
71 XPMReader::~XPMReader()
74 maBmp
.ReleaseAccess( mpAcc
);
77 // ------------------------------------------------------------------------
80 #pragma optimize ("",off)
83 ReadState
XPMReader::ReadXPM( Graphic
& rGraphic
)
88 // sehen, ob wir _alles_ lesen koennen
89 mrIStm
.Seek( STREAM_SEEK_TO_END
);
92 // falls wir nicht alles lesen koennen
93 // kehren wir zurueck und warten auf neue Daten
94 if ( mrIStm
.GetError() != ERRCODE_IO_PENDING
)
96 mrIStm
.Seek( mnLastPos
);
101 mpStringBuf
= new BYTE
[ XPMSTRINGBUF
];
102 mpTempBuf
= new BYTE
[ XPMTEMPBUFSIZE
];
104 if ( ( mbStatus
= ImplGetString() ) == TRUE
)
106 mnIdentifier
= XPMVALUES
; // Bitmap informationen einholen
107 mnWidth
= ImplGetULONG( 0 );
108 mnHeight
= ImplGetULONG( 1 );
109 mnColors
= ImplGetULONG( 2 );
110 mnCpp
= ImplGetULONG( 3 );
112 if ( mbStatus
&& mnWidth
&& mnHeight
&& mnColors
&& mnCpp
)
114 mnIdentifier
= XPMCOLORS
;
116 // mpColMap beinhaltet fuer jede vorhandene
117 // Farbe: ( mnCpp )Byte(s)-> ASCII Eintrag der der Farbe zugeordnet ist
118 // 1 Byte -> 0xff wenn Farbe transparent ist
119 // 3 Bytes -> RGB Wert der Farbe
120 mpColMap
= new BYTE
[ mnColors
* ( 4 + mnCpp
) ];
122 for ( ULONG i
= 0; i
< mnColors
; i
++ )
124 if ( ImplGetColor( i
) == FALSE
)
132 // bei mehr als 256 Farben wird eine 24 Bit Grafik erstellt
133 sal_uInt16 nBits
= 1;
134 if ( mnColors
> 256 )
136 else if ( mnColors
> 16 )
138 else if ( mnColors
> 2 )
143 maBmp
= Bitmap( Size( mnWidth
, mnHeight
), nBits
);
144 mpAcc
= maBmp
.AcquireWriteAccess();
146 // mbTransparent ist TRUE wenn mindestens eine Farbe Transparent ist
149 maMaskBmp
= Bitmap( Size( mnWidth
, mnHeight
), 1 );
150 if ( ( mpMaskAcc
= maMaskBmp
.AcquireWriteAccess() ) == NULL
)
153 if( mpAcc
&& mbStatus
)
156 if ( mnColors
<=256 ) // palette is only needed by using less than 257
159 BYTE
* pPtr
= &mpColMap
[mnCpp
];
161 for ( i
= 0; i
< mnColors
; i
++ )
163 mpAcc
->SetPaletteColor( (BYTE
)i
, Color( pPtr
[1], pPtr
[2], pPtr
[3] ) );
164 pPtr
+= ( mnCpp
+ 4 );
166 // using 2 charakters per pixel and less than 257 Colors we speed up
167 if ( mnCpp
== 2 ) // by using a 64kb indexing table
169 mpFastColorTable
= new BYTE
[ 256 * 256 ];
170 for ( pPtr
= mpColMap
, i
= 0; i
< mnColors
; i
++, pPtr
+= mnCpp
+ 4 )
172 ULONG j
= pPtr
[ 0 ] << 8;
174 mpFastColorTable
[ j
] = (BYTE
)i
;
178 // now we get the bitmap data
179 mnIdentifier
= XPMPIXELS
;
180 for ( i
= 0; i
< mnHeight
; i
++ )
182 if ( ImplGetScanLine( i
) == FALSE
)
188 mnIdentifier
= XPMEXTENSIONS
;
193 delete[] mpFastColorTable
;
195 delete[] mpStringBuf
;
203 maMaskBmp
.ReleaseAccess ( mpMaskAcc
), mpMaskAcc
= NULL
;
204 maBmp
.ReleaseAccess( mpAcc
), mpAcc
= NULL
;
205 rGraphic
= Graphic( BitmapEx( maBmp
, maMaskBmp
) );
209 maBmp
.ReleaseAccess( mpAcc
), mpAcc
= NULL
;
212 eReadState
= XPMREAD_OK
;
216 if ( mpMaskAcc
) maMaskBmp
.ReleaseAccess ( mpMaskAcc
), mpMaskAcc
= NULL
;
217 if ( mpAcc
) maBmp
.ReleaseAccess( mpAcc
), mpAcc
= NULL
;
218 eReadState
= XPMREAD_ERROR
;
224 eReadState
= XPMREAD_NEED_MORE
;
230 #pragma optimize ("",on)
233 // ------------------------------------------------------------------------
234 // ImplGetColor ermittelt saemtliche Farbwerte,
235 // die Rueckgabe ist TRUE wenn saemtliche Farben zugeordnet werden konnten
237 BOOL
XPMReader::ImplGetColor( ULONG nNumb
)
239 BYTE
* pString
= mpStringBuf
;
240 BYTE
* pPtr
= ( mpColMap
+ nNumb
* ( 4 + mnCpp
) );
241 BOOL bStatus
= ImplGetString();
245 for ( ULONG i
= 0; i
< mnCpp
; i
++ )
246 *pPtr
++ = *pString
++;
247 bStatus
= ImplGetColSub ( pPtr
);
252 // ------------------------------------------------------------------------
253 // ImpGetScanLine liest den String mpBufSize aus und schreibt die Pixel in die
254 // Bitmap. Der Parameter nY gibt die horizontale Position an.
256 BOOL
XPMReader::ImplGetScanLine( ULONG nY
)
258 BOOL bStatus
= ImplGetString();
259 BYTE
* pString
= mpStringBuf
;
268 aWhite
= mpMaskAcc
->GetBestMatchingColor( Color( COL_WHITE
) );
269 aBlack
= mpMaskAcc
->GetBestMatchingColor( Color( COL_BLACK
) );
271 if ( mnStringSize
!= ( mnWidth
* mnCpp
))
276 if ( mpFastColorTable
)
278 for ( i
= 0; i
< mnWidth
; i
++ )
280 j
= (*pString
++) << 8;
282 BYTE k
= (BYTE
)mpFastColorTable
[ j
];
283 mpAcc
->SetPixel( nY
, i
, BitmapColor( (BYTE
)k
) );
286 mpMaskAcc
->SetPixel( nY
, i
,
287 ( mpColMap
[ k
* (mnCpp
+ 4) + mnCpp
] ) ? aWhite
: aBlack
);
290 else for ( i
= 0; i
< mnWidth
; i
++ )
293 for ( j
= 0; j
< mnColors
; j
++ )
295 if ( ImplCompare( pString
, pColor
, mnCpp
, XPMCASESENSITIVE
) == TRUE
)
297 if ( mnColors
> 256 )
298 mpAcc
->SetPixel( nY
, i
, Color ( pColor
[3], pColor
[4], pColor
[5] ) );
300 mpAcc
->SetPixel( nY
, i
, BitmapColor( (BYTE
) j
) );
303 mpMaskAcc
->SetPixel( nY
, i
, (
304 pColor
[ mnCpp
] ) ? aWhite
: aBlack
);
308 pColor
+= ( mnCpp
+ 4 );
318 // ------------------------------------------------------------------------
319 // versucht aus mpStringBuf einen Farbwert zu uebermitteln
320 // wurde eine Farbe gefunden wird an pDest[1]..pDest[2] der RGB wert geschrieben
321 // pDest[0] enthaelt 0xff wenn die Farbe transparent ist sonst 0
323 BOOL
XPMReader::ImplGetColSub( BYTE
* pDest
)
325 unsigned char cTransparent
[] = "None";
327 BOOL bColStatus
= FALSE
;
329 if ( ImplGetColKey( 'c' ) || ImplGetColKey( 'm' ) || ImplGetColKey( 'g' ) )
331 // hexentry for RGB or HSV color ?
332 if ( *mpPara
== '#' )
336 switch ( mnParaSize
)
339 ImplGetRGBHex ( pDest
, 6 );
342 ImplGetRGBHex ( pDest
, 2 );
345 ImplGetRGBHex ( pDest
, 0 );
352 // maybe pixel is transparent
353 else if ( ImplCompare( &cTransparent
[0], mpPara
, 4 ))
357 mbTransparent
= TRUE
;
359 // last we will try to get the colorname
360 else if ( mnParaSize
> 2 ) // name must enlarge the minimum size
365 if ( pRGBTable
[ i
].name
== NULL
)
367 if ( pRGBTable
[ i
].name
[ mnParaSize
] == 0 )
369 if ( ImplCompare ( (unsigned char*)pRGBTable
[ i
].name
,
370 mpPara
, mnParaSize
, XPMCASENONSENSITIVE
) )
374 *pDest
++ = pRGBTable
[ i
].red
;
375 *pDest
++ = pRGBTable
[ i
].green
;
376 *pDest
++ = pRGBTable
[ i
].blue
;
386 // ------------------------------------------------------------------------
387 // ImplGetColKey durchsuch den String mpStringBuf nach einem Parameter 'nKey'
388 // und gibt einen BOOL zurueck. ( wenn TRUE werden mpPara und mnParaSize gesetzt )
390 BOOL
XPMReader::ImplGetColKey( BYTE nKey
)
392 BYTE nTemp
, nPrev
= ' ';
394 mpPara
= mpStringBuf
+ mnCpp
+ 1;
397 while ( *mpPara
!= 0 )
399 if ( *mpPara
== nKey
)
401 nTemp
= *( mpPara
+ 1 );
402 if ( nTemp
== ' ' || nTemp
== 0x09 )
404 if ( nPrev
== ' ' || nPrev
== 0x09 )
414 while ( (*mpPara
== ' ') || (*mpPara
== 0x09) )
420 while ( *(mpPara
+mnParaSize
) != ' ' && *(mpPara
+mnParaSize
) != 0x09 &&
421 *(mpPara
+mnParaSize
) != 0 )
427 return ( mnParaSize
) ? TRUE
: FALSE
;
430 // ------------------------------------------------------------------------
431 // ImplGetRGBHex uebersetzt den ASCII-Hexadezimalwert der sich bei mpPara befindet
432 // in einen RGB wert und schreibt diesen nach pDest
433 // folgende Formate muessen sich bei mpPara befinden:
434 // wenn nAdd = 0 : '#12ab12' -> RGB = 0x12, 0xab, 0x12
435 // 2 : '#1234abcd1234' " " " "
436 // 6 : '#12345678abcdefab12345678' " " " "
439 void XPMReader::ImplGetRGBHex( BYTE
* pDest
,ULONG nAdd
)
441 BYTE
* pPtr
= mpPara
+1;
444 for ( ULONG i
= 0; i
< 3; i
++ )
446 nHex
= (*pPtr
++) - '0';
448 nHex
= ((nHex
- 'A' + '0') & 7) + 10;
450 nTemp
= (*pPtr
++) - '0';
452 nTemp
= ((nTemp
- 'A' + '0') & 7) + 10;
453 nHex
= ( nHex
<< 4 ) + nTemp
;
456 *pDest
++ = (BYTE
)nHex
;
460 // ------------------------------------------------------------------------
461 // ImplGetUlong gibt den wert einer bis zu 6stelligen ASCII-Dezimalzahl zurueck.
463 ULONG
XPMReader::ImplGetULONG( ULONG nPara
)
465 if ( ImplGetPara ( nPara
) )
470 if ( ( mnParaSize
> 6 ) || ( mnParaSize
== 0 ) ) return 0;
471 for ( ULONG i
= 0; i
< mnParaSize
; i
++ )
473 BYTE j
= (*pPtr
++) - 48;
474 if ( j
> 9 ) return 0; // ascii is invalid
483 // ------------------------------------------------------------------------
485 BOOL
XPMReader::ImplCompare( BYTE
* pSource
, BYTE
* pDest
, ULONG nSize
, ULONG nMode
)
489 if ( nMode
== XPMCASENONSENSITIVE
)
491 for ( ULONG i
= 0; i
< nSize
; i
++ )
493 if ( ( pSource
[i
]&~0x20 ) != ( pDest
[i
]&~0x20 ) )
502 for ( ULONG i
= 0; i
< nSize
; i
++ )
504 if ( pSource
[i
] != pDest
[i
] )
514 // ------------------------------------------------------------------------
515 // ImplGetPara versucht den nNumb ( 0...x ) Parameter aus mpStringBuf zu ermitteln.
516 // Ein Parameter ist durch Spaces oder Tabs von den anderen getrennt.
517 // Konnte der Parameter gefunden werden ist der Rueckgabewert TRUE und mpPara + mnParaSize
520 BOOL
XPMReader::ImplGetPara ( ULONG nNumb
)
524 BYTE
* pPtr
= mpStringBuf
;
527 if ( ( *pPtr
!= ' ' ) && ( *pPtr
!= 0x09 ) )
539 while ( pSize
< mnStringSize
)
545 if ( ( nByte
== ' ' ) || ( nByte
== 0x09 ) )
547 if ( nCount
== nNumb
)
557 if ( ( nByte
!= ' ' ) && ( nByte
!= 0x09 ) )
567 return ( ( nCount
== nNumb
) && ( mpPara
) ) ? TRUE
: FALSE
;
570 // ------------------------------------------------------------------------
571 // Der naechste String wird ausgelesen und in mpStringBuf (mit 0 abgeschlossen) abgelegt;
572 // mnStringSize enthaelt die Groesse des gelesenen Strings.
573 // Bemerkungen wie '//' und '/*.....*/' werden uebersprungen.
575 BOOL
XPMReader::ImplGetString( void )
577 BYTE sID
[] = "/* XPM */";
578 BYTE
* pString
= mpStringBuf
;
583 while( mbStatus
&& ( mnStatus
!= XPMFINISHED
) )
585 if ( mnTempAvail
== 0 )
587 mnTempAvail
= mrIStm
.Read( mpTempBuf
, XPMTEMPBUFSIZE
);
588 if ( mnTempAvail
== 0 )
591 mpTempPtr
= mpTempBuf
;
593 if ( mnIdentifier
== XPMIDENTIFIER
)
595 if ( mnTempAvail
<= 50 )
597 mbStatus
= FALSE
; // file is too short to be a correct XPM format
600 for ( int i
= 0; i
< 9; i
++ ) // searching for "/* XPM */"
601 if ( *mpTempPtr
++ != sID
[i
] )
610 mcLastByte
= mcThisByte
;
611 mcThisByte
= *mpTempPtr
++;
614 if ( mnStatus
& XPMDOUBLE
)
616 if ( mcThisByte
== 0x0a )
617 mnStatus
&=~XPMDOUBLE
;
620 if ( mnStatus
& XPMREMARK
)
622 if ( ( mcThisByte
== '/' ) && ( mcLastByte
== '*' ) )
623 mnStatus
&=~XPMREMARK
;
626 if ( mnStatus
& XPMSTRING
) // characters in string
628 if ( mcThisByte
== '"' )
630 mnStatus
&=~XPMSTRING
; // end of parameter by eol
633 if ( mnStringSize
>= XPMSTRINGBUF
)
638 *pString
++ = mcThisByte
;
644 { // characters beside string
645 switch ( mcThisByte
)
648 if ( mcLastByte
== '/' ) mnStatus
|= XPMREMARK
;
651 if ( mcLastByte
== '/' ) mnStatus
|= XPMDOUBLE
;
653 case '"' : mnStatus
|= XPMSTRING
;
656 if ( mnIdentifier
== XPMDEFINITION
)
660 if ( mnIdentifier
== XPMENDEXT
)
661 mnStatus
= XPMFINISHED
;
673 BOOL
ImportXPM( SvStream
& rStm
, Graphic
& rGraphic
)
675 XPMReader
* pXPMReader
= (XPMReader
*) rGraphic
.GetContext();
676 ReadState eReadState
;
680 pXPMReader
= new XPMReader( rStm
);
682 rGraphic
.SetContext( NULL
);
683 eReadState
= pXPMReader
->ReadXPM( rGraphic
);
685 if( eReadState
== XPMREAD_ERROR
)
690 else if( eReadState
== XPMREAD_OK
)
693 rGraphic
.SetContext( pXPMReader
);