1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
21 #include <vcl/graph.hxx>
22 #include <vcl/bmpacc.hxx>
24 class FilterConfigItem
;
26 //============================ TGAReader ==================================
30 sal_uInt8 nImageIDLength
;
31 sal_uInt8 nColorMapType
;
33 sal_uInt16 nColorMapFirstEntryIndex
;
34 sal_uInt16 nColorMapLength
;
35 sal_uInt8 nColorMapEntrySize
;
36 sal_uInt16 nColorMapXOrigin
;
37 sal_uInt16 nColorMapYOrigin
;
38 sal_uInt16 nImageWidth
;
39 sal_uInt16 nImageHeight
;
40 sal_uInt8 nPixelDepth
;
41 sal_uInt8 nImageDescriptor
;
44 #define SizeOfTGAFileFooter 26
48 sal_uInt32 nExtensionFileOffset
;
49 sal_uInt32 nDeveloperDirectoryOffset
;
50 sal_uInt32 nSignature
[4];
52 sal_uInt8 nStringTerminator
;
55 #define SizeOfTGAExtension 495
59 sal_uInt16 nExtensionSize
;
61 char sAuthorComment
[324];
62 char sDateTimeStamp
[12];
64 sal_uInt16 nJobTime
[3];
66 sal_uInt16 nSoftwareVersionNumber
;
67 sal_uInt8 nSoftwareVersionLetter
;
69 sal_uInt16 nPixelAspectRatioNumerator
;
70 sal_uInt16 nPixelAspectRatioDeNumerator
;
71 sal_uInt16 nGammaValueNumerator
;
72 sal_uInt16 nGammaValueDeNumerator
;
73 sal_uInt32 nColorCorrectionOffset
;
74 sal_uInt32 nPostageStampOffset
;
75 sal_uInt32 nScanLineOffset
;
76 sal_uInt8 nAttributesType
;
85 BitmapWriteAccess
* mpAcc
;
86 TGAFileHeader
* mpFileHeader
;
87 TGAFileFooter
* mpFileFooter
;
88 TGAExtension
* mpExtension
;
89 sal_uInt32
* mpColorMap
;
93 sal_uLong mnTGAVersion
; // Enhanced TGA is defined as Version 2.0
94 sal_uInt16 mnDestBitDepth
;
95 sal_Bool mbIndexing
; // sal_True if source contains indexing color values
96 sal_Bool mbEncoding
; // sal_True if source is compressed
98 sal_Bool
ImplReadHeader();
99 sal_Bool
ImplReadPalette();
100 sal_Bool
ImplReadBody();
103 TGAReader(SvStream
&rTGA
);
105 sal_Bool
ReadTGA(Graphic
&rGraphic
);
108 //=================== Methoden von TGAReader ==============================
110 TGAReader::TGAReader(SvStream
&rTGA
)
119 , mbIndexing(sal_False
)
120 , mbEncoding(sal_False
)
124 TGAReader::~TGAReader()
132 // -------------------------------------------------------------------------------------------
134 sal_Bool
TGAReader::ReadTGA(Graphic
& rGraphic
)
136 if ( m_rTGA
.GetError() )
139 m_rTGA
.SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN
);
143 if ( !m_rTGA
.GetError() )
145 mbStatus
= ImplReadHeader();
150 aBitmap
= Bitmap( Size( mpFileHeader
->nImageWidth
, mpFileHeader
->nImageHeight
), mnDestBitDepth
);
151 mpAcc
= aBitmap
.AcquireWriteAccess();
155 mbStatus
= ImplReadPalette();
157 mbStatus
= ImplReadBody();
160 mbStatus
= sal_False
;
163 aBitmap
.ReleaseAccess ( mpAcc
), mpAcc
= NULL
;
172 // -------------------------------------------------------------------------------------------
174 sal_Bool
TGAReader::ImplReadHeader()
176 mpFileHeader
= new TGAFileHeader
;
177 if ( mpFileHeader
== NULL
)
180 m_rTGA
>> mpFileHeader
->nImageIDLength
>> mpFileHeader
->nColorMapType
>> mpFileHeader
->nImageType
>>
181 mpFileHeader
->nColorMapFirstEntryIndex
>> mpFileHeader
->nColorMapLength
>> mpFileHeader
->nColorMapEntrySize
>>
182 mpFileHeader
->nColorMapXOrigin
>> mpFileHeader
->nColorMapYOrigin
>> mpFileHeader
->nImageWidth
>>
183 mpFileHeader
->nImageHeight
>> mpFileHeader
->nPixelDepth
>> mpFileHeader
->nImageDescriptor
;
188 if ( mpFileHeader
->nColorMapType
> 1 )
190 if ( mpFileHeader
->nColorMapType
== 1 )
191 mbIndexing
= sal_True
;
193 // first we want to get the version
194 mpFileFooter
= new TGAFileFooter
; // read the TGA-File-Footer to determine whether
195 if ( mpFileFooter
) // we got an old TGA format or the new one
197 sal_uLong nCurStreamPos
= m_rTGA
.Tell();
198 m_rTGA
.Seek( STREAM_SEEK_TO_END
);
199 sal_uLong nTemp
= m_rTGA
.Tell();
200 m_rTGA
.Seek( nTemp
- SizeOfTGAFileFooter
);
202 m_rTGA
>> mpFileFooter
->nExtensionFileOffset
>> mpFileFooter
->nDeveloperDirectoryOffset
>>
203 mpFileFooter
->nSignature
[0] >> mpFileFooter
->nSignature
[1] >> mpFileFooter
->nSignature
[2] >>
204 mpFileFooter
->nSignature
[3] >> mpFileFooter
->nPadByte
>> mpFileFooter
->nStringTerminator
;
210 // check for sal_True, VISI, ON-X, FILE in the signatures
211 if ( mpFileFooter
->nSignature
[ 0 ] == (('T'<<24)|('R'<<16)|('U'<<8)|'E') &&
212 mpFileFooter
->nSignature
[ 1 ] == (('V'<<24)|('I'<<16)|('S'<<8)|'I') &&
213 mpFileFooter
->nSignature
[ 2 ] == (('O'<<24)|('N'<<16)|('-'<<8)|'X') &&
214 mpFileFooter
->nSignature
[ 3 ] == (('F'<<24)|('I'<<16)|('L'<<8)|'E') )
216 mpExtension
= new TGAExtension
;
219 m_rTGA
.Seek( mpFileFooter
->nExtensionFileOffset
);
220 m_rTGA
>> mpExtension
->nExtensionSize
;
223 if ( mpExtension
->nExtensionSize
>= SizeOfTGAExtension
)
227 m_rTGA
.Read( mpExtension
->sAuthorName
, 41 );
228 m_rTGA
.Read( mpExtension
->sAuthorComment
, 324 );
229 m_rTGA
.Read( mpExtension
->sDateTimeStamp
, 12 );
230 m_rTGA
.Read( mpExtension
->sJobNameID
, 12 );
231 m_rTGA
>> mpExtension
->sJobNameID
[ 0 ] >> mpExtension
->sJobNameID
[ 1 ] >> mpExtension
->sJobNameID
[ 2 ];
232 m_rTGA
.Read( mpExtension
->sSoftwareID
, 41 );
233 m_rTGA
>> mpExtension
->nSoftwareVersionNumber
>> mpExtension
->nSoftwareVersionLetter
234 >> mpExtension
->nKeyColor
>> mpExtension
->nPixelAspectRatioNumerator
235 >> mpExtension
->nPixelAspectRatioDeNumerator
>> mpExtension
->nGammaValueNumerator
236 >> mpExtension
->nGammaValueDeNumerator
>> mpExtension
->nColorCorrectionOffset
237 >> mpExtension
->nPostageStampOffset
>> mpExtension
->nScanLineOffset
238 >> mpExtension
->nAttributesType
;
245 m_rTGA
.Seek( nCurStreamPos
);
248 // using the TGA file specification this was the correct form but adobe photoshop sets nImageDescriptor
249 // equal to nPixelDepth
250 // mnDestBitDepth = mpFileHeader->nPixelDepth - ( mpFileHeader->nImageDescriptor & 0xf );
251 mnDestBitDepth
= mpFileHeader
->nPixelDepth
;
253 if ( mnDestBitDepth
== 8 ) // this is a patch for grayscale pictures not including a palette
254 mbIndexing
= sal_True
;
256 if ( mnDestBitDepth
> 32 ) // maybe the pixeldepth is invalid
258 else if ( mnDestBitDepth
> 8 )
260 else if ( mnDestBitDepth
> 4 )
262 else if ( mnDestBitDepth
> 2 )
265 if ( !mbIndexing
&& ( mnDestBitDepth
< 15 ) )
268 switch ( mpFileHeader
->nImageType
)
270 case 9 : // encoding for colortype 9, 10, 11
273 mbEncoding
= sal_True
;
277 if ( mpFileHeader
->nImageIDLength
) // skip the Image ID
278 m_rTGA
.SeekRel( mpFileHeader
->nImageIDLength
);
283 // -------------------------------------------------------------------------------------------
285 sal_Bool
TGAReader::ImplReadBody()
288 sal_uInt16 nXCount
, nYCount
, nRGB16
;
289 sal_uInt8 nRed
, nGreen
, nBlue
, nRunCount
, nDummy
, nDepth
;
291 // this four variables match the image direction
292 long nY
, nYAdd
, nX
, nXAdd
, nXStart
;
294 nX
= nXStart
= nY
= 0;
295 nXCount
= nYCount
= 0;
298 if ( mpFileHeader
->nImageDescriptor
& 0x10 )
300 nX
= nXStart
= mpFileHeader
->nImageWidth
- 1;
304 if ( !(mpFileHeader
->nImageDescriptor
& 0x20 ) )
306 nY
= mpFileHeader
->nImageHeight
- 1;
310 nDepth
= mpFileHeader
->nPixelDepth
;
318 // 16 bit encoding + indexing
320 while ( nYCount
< mpFileHeader
->nImageHeight
)
325 if ( nRunCount
& 0x80 ) // a run length packet
328 if ( nRGB16
>= mpFileHeader
->nColorMapLength
)
330 nRed
= (sal_uInt8
)( mpColorMap
[ nRGB16
] >> 16 );
331 nGreen
= (sal_uInt8
)( mpColorMap
[ nRGB16
] >> 8 );
332 nBlue
= (sal_uInt8
)( mpColorMap
[ nRGB16
] );
335 for ( sal_uInt16 i
= 0; i
< ( ( nRunCount
& 0x7f ) + 1 ); i
++ )
337 mpAcc
->SetPixel( nY
, nX
, BitmapColor( nRed
, nGreen
, nBlue
) );
340 if ( nXCount
== mpFileHeader
->nImageWidth
)
347 if( nYCount
>= mpFileHeader
->nImageHeight
)
354 for ( sal_uInt16 i
= 0; i
< ( ( nRunCount
& 0x7f ) + 1 ); i
++ )
359 if ( nRGB16
>= mpFileHeader
->nColorMapLength
)
361 nRed
= (sal_uInt8
)( mpColorMap
[ nRGB16
] >> 16 );
362 nGreen
= (sal_uInt8
)( mpColorMap
[ nRGB16
] >> 8 );
363 nBlue
= (sal_uInt8
)( mpColorMap
[ nRGB16
] );
366 mpAcc
->SetPixel( nY
, nX
, BitmapColor( nRed
, nGreen
, nBlue
) );
369 if ( nXCount
== mpFileHeader
->nImageWidth
)
376 if( nYCount
>= mpFileHeader
->nImageHeight
)
384 // 8 bit encoding + indexing
386 while ( nYCount
< mpFileHeader
->nImageHeight
)
391 if ( nRunCount
& 0x80 ) // a run length packet
396 if ( nDummy
>= mpFileHeader
->nColorMapLength
)
398 for ( sal_uInt16 i
= 0; i
< ( ( nRunCount
& 0x7f ) + 1 ); i
++ )
400 mpAcc
->SetPixelIndex( nY
, nX
, nDummy
);
403 if ( nXCount
== mpFileHeader
->nImageWidth
)
410 if( nYCount
>= mpFileHeader
->nImageHeight
)
417 for ( sal_uInt16 i
= 0; i
< ( ( nRunCount
& 0x7f ) + 1 ); i
++ )
423 if ( nDummy
>= mpFileHeader
->nColorMapLength
)
425 mpAcc
->SetPixelIndex( nY
, nX
, nDummy
);
428 if ( nXCount
== mpFileHeader
->nImageWidth
)
435 if( nYCount
>= mpFileHeader
->nImageHeight
)
450 // 32 bit transparent true color encoding
453 while ( nYCount
< mpFileHeader
->nImageHeight
)
458 if ( nRunCount
& 0x80 ) // a run length packet
460 m_rTGA
>> nBlue
>> nGreen
>> nRed
>> nDummy
;
463 for ( sal_uInt16 i
= 0; i
< ( ( nRunCount
& 0x7f ) + 1 ); i
++ )
465 mpAcc
->SetPixel( nY
, nX
, BitmapColor( nRed
, nGreen
, nBlue
) );
468 if ( nXCount
== mpFileHeader
->nImageWidth
)
475 if( nYCount
>= mpFileHeader
->nImageHeight
)
482 for ( sal_uInt16 i
= 0; i
< ( ( nRunCount
& 0x7f ) + 1 ); i
++ )
484 m_rTGA
>> nBlue
>> nGreen
>> nRed
>> nDummy
;
487 mpAcc
->SetPixel( nY
, nX
, BitmapColor( nRed
, nGreen
, nBlue
) );
490 if ( nXCount
== mpFileHeader
->nImageWidth
)
497 if( nYCount
>= mpFileHeader
->nImageHeight
)
506 // 24 bit true color encoding
508 while ( nYCount
< mpFileHeader
->nImageHeight
)
513 if ( nRunCount
& 0x80 ) // a run length packet
515 m_rTGA
>> nBlue
>> nGreen
>> nRed
;
518 for ( sal_uInt16 i
= 0; i
< ( ( nRunCount
& 0x7f ) + 1 ); i
++ )
520 mpAcc
->SetPixel( nY
, nX
, BitmapColor( nRed
, nGreen
, nBlue
) );
523 if ( nXCount
== mpFileHeader
->nImageWidth
)
530 if( nYCount
>= mpFileHeader
->nImageHeight
)
537 for ( sal_uInt16 i
= 0; i
< ( ( nRunCount
& 0x7f ) + 1 ); i
++ )
539 m_rTGA
>> nBlue
>> nGreen
>> nRed
;
542 mpAcc
->SetPixel( nY
, nX
, BitmapColor( nRed
, nGreen
, nBlue
) );
545 if ( nXCount
== mpFileHeader
->nImageWidth
)
552 if( nYCount
>= mpFileHeader
->nImageHeight
)
560 // 16 bit true color encoding
562 while ( nYCount
< mpFileHeader
->nImageHeight
)
567 if ( nRunCount
& 0x80 ) // a run length packet
572 nRed
= (sal_uInt8
)( nRGB16
>> 7 ) & 0xf8;
573 nGreen
= (sal_uInt8
)( nRGB16
>> 2 ) & 0xf8;
574 nBlue
= (sal_uInt8
)( nRGB16
<< 3 ) & 0xf8;
575 for ( sal_uInt16 i
= 0; i
< ( ( nRunCount
& 0x7f ) + 1 ); i
++ )
577 mpAcc
->SetPixel( nY
, nX
, BitmapColor( nRed
, nGreen
, nBlue
) );
580 if ( nXCount
== mpFileHeader
->nImageWidth
)
587 if( nYCount
>= mpFileHeader
->nImageHeight
)
594 for ( sal_uInt16 i
= 0; i
< ( ( nRunCount
& 0x7f ) + 1 ); i
++ )
599 nRed
= (sal_uInt8
)( nRGB16
>> 7 ) & 0xf8;
600 nGreen
= (sal_uInt8
)( nRGB16
>> 2 ) & 0xf8;
601 nBlue
= (sal_uInt8
)( nRGB16
<< 3 ) & 0xf8;
602 mpAcc
->SetPixel( nY
, nX
, BitmapColor( nRed
, nGreen
, nBlue
) );
605 if ( nXCount
== mpFileHeader
->nImageWidth
)
612 if( nYCount
>= mpFileHeader
->nImageHeight
)
627 for ( nYCount
= 0; nYCount
< mpFileHeader
->nImageHeight
; nYCount
++, nY
+= nYAdd
)
638 for (;nXCount
< mpFileHeader
->nImageWidth
; nXCount
++, nX
+= nXAdd
)
643 if ( nRGB16
>= mpFileHeader
->nColorMapLength
)
645 nRed
= (sal_uInt8
)( mpColorMap
[ nRGB16
] >> 16 );
646 nGreen
= (sal_uInt8
)( mpColorMap
[ nRGB16
] >> 8 );
647 nBlue
= (sal_uInt8
)( mpColorMap
[ nRGB16
] );
648 mpAcc
->SetPixel( nY
, nX
, BitmapColor( nRed
, nGreen
, nBlue
) );
654 for (;nXCount
< mpFileHeader
->nImageWidth
; nXCount
++, nX
+= nXAdd
)
659 if ( nDummy
>= mpFileHeader
->nColorMapLength
)
661 mpAcc
->SetPixelIndex( nY
, nX
, nDummy
);
675 for (;nXCount
< mpFileHeader
->nImageWidth
; nXCount
++, nX
+= nXAdd
)
677 m_rTGA
>> nBlue
>> nGreen
>> nRed
>> nDummy
;
680 mpAcc
->SetPixel( nY
, nX
, BitmapColor( nRed
, nGreen
, nBlue
) );
687 for (;nXCount
< mpFileHeader
->nImageWidth
; nXCount
++, nX
+= nXAdd
)
689 m_rTGA
>> nBlue
>> nGreen
>> nRed
;
692 mpAcc
->SetPixel( nY
, nX
, BitmapColor( nRed
, nGreen
, nBlue
) );
698 for (;nXCount
< mpFileHeader
->nImageWidth
; nXCount
++, nX
+= nXAdd
)
703 nRed
= (sal_uInt8
)( nRGB16
>> 7 ) & 0xf8;
704 nGreen
= (sal_uInt8
)( nRGB16
>> 2 ) & 0xf8;
705 nBlue
= (sal_uInt8
)( nRGB16
<< 3 ) & 0xf8;
706 mpAcc
->SetPixel( nY
, nX
, BitmapColor( nRed
, nGreen
, nBlue
) );
718 // -------------------------------------------------------------------------------------------
720 sal_Bool
TGAReader::ImplReadPalette()
722 if ( mbIndexing
) // read the colormap
724 sal_uInt16 nColors
= mpFileHeader
->nColorMapLength
;
726 if ( !nColors
) // colors == 0 ? -> we will build a grayscale palette
728 if ( mpFileHeader
->nPixelDepth
!= 8 )
731 mpFileHeader
->nColorMapLength
= 256;
732 mpFileHeader
->nColorMapEntrySize
= 0x3f; // patch for the following switch routine
734 mpColorMap
= new sal_uInt32
[ nColors
]; // we will always index dwords
735 if ( mpColorMap
== sal_False
)
736 return sal_False
; // out of memory %&!$&/!"�$
738 switch( mpFileHeader
->nColorMapEntrySize
)
742 for ( sal_uLong i
= 0; i
< nColors
; i
++ )
744 mpColorMap
[ i
] = ( i
<< 16 ) + ( i
<< 8 ) + i
;
750 m_rTGA
.Read( mpColorMap
, 4 * nColors
);
755 for ( sal_uLong i
= 0; i
< nColors
; i
++ )
757 m_rTGA
.Read( &mpColorMap
[ i
], 3 );
765 for ( sal_uLong i
= 0; i
< nColors
; i
++ )
769 if ( !m_rTGA
.good() )
771 mpColorMap
[ i
] = ( ( nTemp
& 0x7c00 ) << 9 ) + ( ( nTemp
& 0x01e0 ) << 6 ) +
772 ( ( nTemp
& 0x1f ) << 3 );
780 if ( mnDestBitDepth
<= 8 )
782 sal_uInt16 nDestColors
= ( 1 << mnDestBitDepth
);
783 if ( nColors
> nDestColors
)
786 mpAcc
->SetPaletteEntryCount( nColors
);
787 for ( sal_uInt16 i
= 0; i
< nColors
; i
++ )
789 mpAcc
->SetPaletteColor( i
, Color( (sal_uInt8
)( mpColorMap
[ i
] >> 16 ),
790 (sal_uInt8
)( mpColorMap
[ i
] >> 8 ), (sal_uInt8
)(mpColorMap
[ i
] ) ) );
798 //================== GraphicImport - die exportierte Funktion ================
800 // this needs to be kept in sync with
801 // ImpFilterLibCacheEntry::GetImportFunction() from
802 // vcl/source/filter/graphicfilter.cxx
803 #if defined(DISABLE_DYNLOADING)
804 #define GraphicImport itgGraphicImport
807 extern "C" SAL_DLLPUBLIC_EXPORT sal_Bool SAL_CALL
808 GraphicImport(SvStream
& rStream
, Graphic
& rGraphic
, FilterConfigItem
*, sal_Bool
)
810 TGAReader
aTGAReader(rStream
);
812 return aTGAReader
.ReadTGA(rGraphic
);
815 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */