LibreOffice Module vcl (master) 1
itga.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 <tools/stream.hxx>
24#include <memory>
25#include <filter/TgaReader.hxx>
26
28
29//============================ TGAReader ==================================
30
31namespace {
32
33struct TGAFileHeader
34{
35 sal_uInt8 nImageIDLength;
36 sal_uInt8 nColorMapType;
37 sal_uInt8 nImageType;
38 sal_uInt16 nColorMapFirstEntryIndex;
39 sal_uInt16 nColorMapLength;
40 sal_uInt8 nColorMapEntrySize;
41 sal_uInt16 nColorMapXOrigin;
42 sal_uInt16 nColorMapYOrigin;
43 sal_uInt16 nImageWidth;
44 sal_uInt16 nImageHeight;
45 sal_uInt8 nPixelDepth;
46 sal_uInt8 nImageDescriptor;
47};
48
49#define SizeOfTGAFileFooter 26
50
51struct TGAFileFooter
52{
53 sal_uInt32 nExtensionFileOffset;
54 sal_uInt32 nDeveloperDirectoryOffset;
55 sal_uInt32 nSignature[4];
56 sal_uInt8 nPadByte;
57 sal_uInt8 nStringTerminator;
58};
59
60#define SizeOfTGAExtension 495
61
62struct TGAExtension
63{
64 sal_uInt16 nExtensionSize;
65 char sAuthorName[41];
66 char sAuthorComment[324];
67 char sDateTimeStamp[12];
68 char sJobNameID[41];
69 char sSoftwareID[41];
70 sal_uInt16 nSoftwareVersionNumber;
71 sal_uInt8 nSoftwareVersionLetter;
72 sal_uInt32 nKeyColor;
73 sal_uInt16 nPixelAspectRatioNumerator;
74 sal_uInt16 nPixelAspectRatioDeNumerator;
75 sal_uInt16 nGammaValueNumerator;
76 sal_uInt16 nGammaValueDeNumerator;
77 sal_uInt32 nColorCorrectionOffset;
78 sal_uInt32 nPostageStampOffset;
79 sal_uInt32 nScanLineOffset;
80 sal_uInt8 nAttributesType;
81};
82
83class TGAReader {
84
85private:
86
87 SvStream& m_rTGA;
88
89 std::unique_ptr<vcl::bitmap::RawBitmap> mpBitmap;
90 std::vector<Color> mvPalette;
91 std::unique_ptr<TGAFileHeader>
92 mpFileHeader;
93 std::unique_ptr<TGAFileFooter>
94 mpFileFooter;
95 std::unique_ptr<TGAExtension>
96 mpExtension;
97 std::unique_ptr<sal_uInt32[]>
98 mpColorMap;
99
100 bool mbStatus;
101
102 sal_uInt8 mnTGAVersion; // Enhanced TGA is defined as Version 2.0
103 sal_uInt16 mnDestBitDepth;
104 bool mbIndexing; // sal_True if source contains indexing color values
105 bool mbEncoding; // sal_True if source is compressed
106
107 bool ImplReadHeader();
108 bool ImplReadPalette();
109 bool ImplReadBody();
110
111public:
112 explicit TGAReader(SvStream &rTGA);
113 bool ReadTGA(Graphic &rGraphic);
114};
115
116}
117
118//=================== Methods of TGAReader ==============================
119
120TGAReader::TGAReader(SvStream &rTGA)
121 : m_rTGA(rTGA)
122 , mbStatus(true)
123 , mnTGAVersion(1)
124 , mnDestBitDepth(8)
125 , mbIndexing(false)
126 , mbEncoding(false)
127{
128}
129
130bool TGAReader::ReadTGA(Graphic & rGraphic)
131{
132 if ( m_rTGA.GetError() )
133 return false;
134
135 m_rTGA.SetEndian( SvStreamEndian::LITTLE );
136
137 // Kopf einlesen:
138
139 if ( !m_rTGA.GetError() )
140 {
141 mbStatus = ImplReadHeader();
142 if (mbStatus)
143 mbStatus = mpFileHeader->nImageWidth && mpFileHeader->nImageHeight;
144 if (mbStatus)
145 {
146 sal_Size nSize = mpFileHeader->nImageWidth;
147 nSize *= mpFileHeader->nImageHeight;
148 if (nSize > SAL_MAX_INT32/2/3)
149 return false;
150
151 mpBitmap.reset( new vcl::bitmap::RawBitmap( Size( mpFileHeader->nImageWidth, mpFileHeader->nImageHeight ), 24 ) );
152 if ( mbIndexing )
153 mbStatus = ImplReadPalette();
154 if ( mbStatus )
155 mbStatus = ImplReadBody();
156
157 if ( mbStatus )
158 rGraphic = vcl::bitmap::CreateFromData(std::move(*mpBitmap));
159 }
160 }
161 return mbStatus;
162}
163
164
165bool TGAReader::ImplReadHeader()
166{
167 mpFileHeader.reset( new TGAFileHeader );
168
169 m_rTGA.ReadUChar( mpFileHeader->nImageIDLength ).ReadUChar( mpFileHeader->nColorMapType ).ReadUChar( mpFileHeader->nImageType ). ReadUInt16( mpFileHeader->nColorMapFirstEntryIndex ).ReadUInt16( mpFileHeader->nColorMapLength ).ReadUChar( mpFileHeader->nColorMapEntrySize ). ReadUInt16( mpFileHeader->nColorMapXOrigin ).ReadUInt16( mpFileHeader->nColorMapYOrigin ).ReadUInt16( mpFileHeader->nImageWidth ). ReadUInt16( mpFileHeader->nImageHeight ).ReadUChar( mpFileHeader->nPixelDepth ).ReadUChar( mpFileHeader->nImageDescriptor );
170
171 if ( !m_rTGA.good())
172 return false;
173
174 if ( mpFileHeader->nColorMapType > 1 )
175 return false;
176 if ( mpFileHeader->nColorMapType == 1 )
177 mbIndexing = true;
178
179 // first we want to get the version
180 mpFileFooter.reset( new TGAFileFooter ); // read the TGA-File-Footer to determine whether
181 // we got an old TGA format or the new one
182
183 sal_uInt64 nCurStreamPos = m_rTGA.Tell();
184 m_rTGA.Seek( STREAM_SEEK_TO_END );
185 sal_uInt64 nTemp = m_rTGA.Tell();
186 m_rTGA.Seek( nTemp - SizeOfTGAFileFooter );
187
188 m_rTGA.ReadUInt32( mpFileFooter->nExtensionFileOffset ).ReadUInt32( mpFileFooter->nDeveloperDirectoryOffset ). ReadUInt32( mpFileFooter->nSignature[0] ).ReadUInt32( mpFileFooter->nSignature[1] ).ReadUInt32( mpFileFooter->nSignature[2] ). ReadUInt32( mpFileFooter->nSignature[3] ).ReadUChar( mpFileFooter->nPadByte ).ReadUChar( mpFileFooter->nStringTerminator );
189
190
191 if ( !m_rTGA.good())
192 return false;
193
194 // check for sal_True, VISI, ON-X, FILE in the signatures
195 if ( mpFileFooter->nSignature[ 0 ] == (('T'<<24)|('R'<<16)|('U'<<8)|'E') &&
196 mpFileFooter->nSignature[ 1 ] == (('V'<<24)|('I'<<16)|('S'<<8)|'I') &&
197 mpFileFooter->nSignature[ 2 ] == (('O'<<24)|('N'<<16)|('-'<<8)|'X') &&
198 mpFileFooter->nSignature[ 3 ] == (('F'<<24)|('I'<<16)|('L'<<8)|'E') )
199 {
200 mpExtension.reset( new TGAExtension );
201
202 m_rTGA.Seek( mpFileFooter->nExtensionFileOffset );
203 m_rTGA.ReadUInt16( mpExtension->nExtensionSize );
204 if ( !m_rTGA.good())
205 return false;
206 if ( mpExtension->nExtensionSize >= SizeOfTGAExtension )
207 {
208 mnTGAVersion = 2;
209
210 m_rTGA.ReadBytes(mpExtension->sAuthorName, 41);
211 m_rTGA.ReadBytes(mpExtension->sAuthorComment, 324);
212 m_rTGA.ReadBytes(mpExtension->sDateTimeStamp, 12);
213 m_rTGA.ReadBytes(mpExtension->sJobNameID, 12);
214 m_rTGA.ReadChar( mpExtension->sJobNameID[ 0 ] ).ReadChar( mpExtension->sJobNameID[ 1 ] ).ReadChar( mpExtension->sJobNameID[ 2 ] );
215 m_rTGA.ReadBytes(mpExtension->sSoftwareID, 41);
216 m_rTGA.ReadUInt16( mpExtension->nSoftwareVersionNumber ).ReadUChar( mpExtension->nSoftwareVersionLetter )
217 .ReadUInt32( mpExtension->nKeyColor ).ReadUInt16( mpExtension->nPixelAspectRatioNumerator )
218 .ReadUInt16( mpExtension->nPixelAspectRatioDeNumerator ).ReadUInt16( mpExtension->nGammaValueNumerator )
219 .ReadUInt16( mpExtension->nGammaValueDeNumerator ).ReadUInt32( mpExtension->nColorCorrectionOffset )
220 .ReadUInt32( mpExtension->nPostageStampOffset ).ReadUInt32( mpExtension->nScanLineOffset )
221 .ReadUChar( mpExtension->nAttributesType );
222
223 if ( !m_rTGA.good())
224 return false;
225 }
226 }
227 m_rTGA.Seek( nCurStreamPos );
228
229 // using the TGA file specification this was the correct form but adobe photoshop sets nImageDescriptor
230 // equal to nPixelDepth
231 // mnDestBitDepth = mpFileHeader->nPixelDepth - ( mpFileHeader->nImageDescriptor & 0xf );
232 mnDestBitDepth = mpFileHeader->nPixelDepth;
233
234 if ( mnDestBitDepth == 8 ) // this is a patch for grayscale pictures not including a palette
235 mbIndexing = true;
236
237 if ( mnDestBitDepth > 32 ) // maybe the pixeldepth is invalid
238 return false;
239 else if ( mnDestBitDepth > 8 )
240 mnDestBitDepth = 24;
241 else if ( mnDestBitDepth > 4 )
242 mnDestBitDepth = 8;
243 else if ( mnDestBitDepth > 2 )
244 mnDestBitDepth = 4;
245
246 if ( !mbIndexing && ( mnDestBitDepth < 15 ) )
247 return false;
248
249 switch ( mpFileHeader->nImageType )
250 {
251 case 9 : // encoding for colortype 9, 10, 11
252 case 10 :
253 case 11 :
254 mbEncoding = true;
255 break;
256 }
257
258 if ( mpFileHeader->nImageIDLength ) // skip the Image ID
259 m_rTGA.SeekRel( mpFileHeader->nImageIDLength );
260
261 return mbStatus;
262}
263
264
265bool TGAReader::ImplReadBody()
266{
267
268 sal_uInt16 nXCount, nYCount, nRGB16;
269 sal_uInt8 nRed, nGreen, nBlue, nRunCount, nDummy, nDepth;
270
271 // this four variables match the image direction
272 tools::Long nY, nYAdd, nX, nXAdd, nXStart;
273
274 nX = nXStart = nY = 0;
275 nXCount = nYCount = 0;
276 nYAdd = nXAdd = 1;
277
278 if ( mpFileHeader->nImageDescriptor & 0x10 )
279 {
280 nX = nXStart = mpFileHeader->nImageWidth - 1;
281 nXAdd -= 2;
282 }
283
284 if ( !(mpFileHeader->nImageDescriptor & 0x20 ) )
285 {
286 nY = mpFileHeader->nImageHeight - 1;
287 nYAdd -=2;
288 }
289
290 nDepth = mpFileHeader->nPixelDepth;
291
292 if ( mbEncoding )
293 {
294 if ( mbIndexing )
295 {
296 switch( nDepth )
297 {
298 // 16 bit encoding + indexing
299 case 16 :
300 while ( nYCount < mpFileHeader->nImageHeight )
301 {
302 m_rTGA.ReadUChar( nRunCount );
303 if ( !m_rTGA.good())
304 return false;
305 if ( nRunCount & 0x80 ) // a run length packet
306 {
307 m_rTGA.ReadUInt16( nRGB16 );
308 if (!m_rTGA.good())
309 return false;
310 if ( nRGB16 >= mpFileHeader->nColorMapLength )
311 return false;
312 nRed = static_cast<sal_uInt8>( mpColorMap[ nRGB16 ] >> 16 );
313 nGreen = static_cast<sal_uInt8>( mpColorMap[ nRGB16 ] >> 8 );
314 nBlue = static_cast<sal_uInt8>( mpColorMap[ nRGB16 ] );
315 for ( sal_uInt16 i = 0; i < ( ( nRunCount & 0x7f ) + 1 ); i++ )
316 {
317 mpBitmap->SetPixel( nY, nX, Color( nRed, nGreen, nBlue ) );
318 nX += nXAdd;
319 nXCount++;
320 if ( nXCount == mpFileHeader->nImageWidth )
321 {
322 nX = nXStart;
323 nXCount = 0;
324 nY += nYAdd;
325 nYCount++;
326
327 if( nYCount >= mpFileHeader->nImageHeight )
328 break;
329 }
330 }
331 }
332 else // a raw packet
333 {
334 for ( sal_uInt16 i = 0; i < ( ( nRunCount & 0x7f ) + 1 ); i++ )
335 {
336 m_rTGA.ReadUInt16( nRGB16 );
337 if ( !m_rTGA.good())
338 return false;
339 if ( nRGB16 >= mpFileHeader->nColorMapLength )
340 return false;
341 nRed = static_cast<sal_uInt8>( mpColorMap[ nRGB16 ] >> 16 );
342 nGreen = static_cast<sal_uInt8>( mpColorMap[ nRGB16 ] >> 8 );
343 nBlue = static_cast<sal_uInt8>( mpColorMap[ nRGB16 ] );
344 if ( !m_rTGA.good())
345 return false;
346 mpBitmap->SetPixel( nY, nX, Color( nRed, nGreen, nBlue ) );
347 nX += nXAdd;
348 nXCount++;
349 if ( nXCount == mpFileHeader->nImageWidth )
350 {
351 nX = nXStart;
352 nXCount = 0;
353 nY += nYAdd;
354 nYCount++;
355
356 if( nYCount >= mpFileHeader->nImageHeight )
357 break;
358 }
359 }
360 }
361 }
362 break;
363
364 // 8 bit encoding + indexing
365 case 8 :
366 while ( nYCount < mpFileHeader->nImageHeight )
367 {
368 m_rTGA.ReadUChar( nRunCount );
369 if ( !m_rTGA.good())
370 return false;
371 if ( nRunCount & 0x80 ) // a run length packet
372 {
373 m_rTGA.ReadUChar( nDummy );
374 if ( !m_rTGA.good())
375 return false;
376 if ( nDummy >= mpFileHeader->nColorMapLength )
377 return false;
378 for ( sal_uInt16 i = 0; i < ( ( nRunCount & 0x7f ) + 1 ); i++ )
379 {
380 mpBitmap->SetPixel( nY, nX, mvPalette[nDummy] );
381 nX += nXAdd;
382 nXCount++;
383 if ( nXCount == mpFileHeader->nImageWidth )
384 {
385 nX = nXStart;
386 nXCount = 0;
387 nY += nYAdd;
388 nYCount++;
389
390 if( nYCount >= mpFileHeader->nImageHeight )
391 break;
392 }
393 }
394 }
395 else // a raw packet
396 {
397 for ( sal_uInt16 i = 0; i < ( ( nRunCount & 0x7f ) + 1 ); i++ )
398 {
399 m_rTGA.ReadUChar( nDummy );
400 if ( !m_rTGA.good())
401 return false;
402 if ( nDummy >= mpFileHeader->nColorMapLength )
403 return false;
404 mpBitmap->SetPixel( nY, nX, mvPalette[nDummy] );
405 nX += nXAdd;
406 nXCount++;
407 if ( nXCount == mpFileHeader->nImageWidth )
408 {
409 nX = nXStart;
410 nXCount = 0;
411 nY += nYAdd;
412 nYCount++;
413
414 if( nYCount >= mpFileHeader->nImageHeight )
415 break;
416 }
417 }
418 }
419 }
420 break;
421 default:
422 return false;
423 }
424 }
425 else
426 {
427 switch( nDepth )
428 {
429 // 32 bit transparent true color encoding
430 case 32 :
431 {
432 while ( nYCount < mpFileHeader->nImageHeight )
433 {
434 m_rTGA.ReadUChar( nRunCount );
435 if ( !m_rTGA.good())
436 return false;
437 if ( nRunCount & 0x80 ) // a run length packet
438 {
439 m_rTGA.ReadUChar( nBlue ).ReadUChar( nGreen ).ReadUChar( nRed ).ReadUChar( nDummy );
440 if ( !m_rTGA.good())
441 return false;
442 for ( sal_uInt16 i = 0; i < ( ( nRunCount & 0x7f ) + 1 ); i++ )
443 {
444 mpBitmap->SetPixel( nY, nX, Color( nRed, nGreen, nBlue ) );
445 nX += nXAdd;
446 nXCount++;
447 if ( nXCount == mpFileHeader->nImageWidth )
448 {
449 nX = nXStart;
450 nXCount = 0;
451 nY += nYAdd;
452 nYCount++;
453
454 if( nYCount >= mpFileHeader->nImageHeight )
455 break;
456 }
457 }
458 }
459 else // a raw packet
460 {
461 for ( sal_uInt16 i = 0; i < ( ( nRunCount & 0x7f ) + 1 ); i++ )
462 {
463 m_rTGA.ReadUChar( nBlue ).ReadUChar( nGreen ).ReadUChar( nRed ).ReadUChar( nDummy );
464 if ( !m_rTGA.good())
465 return false;
466 mpBitmap->SetPixel( nY, nX, Color( nRed, nGreen, nBlue ) );
467 nX += nXAdd;
468 nXCount++;
469 if ( nXCount == mpFileHeader->nImageWidth )
470 {
471 nX = nXStart;
472 nXCount = 0;
473 nY += nYAdd;
474 nYCount++;
475
476 if( nYCount >= mpFileHeader->nImageHeight )
477 break;
478 }
479 }
480 }
481 }
482 }
483 break;
484
485 // 24 bit true color encoding
486 case 24 :
487 while ( nYCount < mpFileHeader->nImageHeight )
488 {
489 m_rTGA.ReadUChar( nRunCount );
490 if ( !m_rTGA.good())
491 return false;
492 if ( nRunCount & 0x80 ) // a run length packet
493 {
494 m_rTGA.ReadUChar( nBlue ).ReadUChar( nGreen ).ReadUChar( nRed );
495 if ( !m_rTGA.good())
496 return false;
497 for ( sal_uInt16 i = 0; i < ( ( nRunCount & 0x7f ) + 1 ); i++ )
498 {
499 mpBitmap->SetPixel( nY, nX, Color( nRed, nGreen, nBlue ) );
500 nX += nXAdd;
501 nXCount++;
502 if ( nXCount == mpFileHeader->nImageWidth )
503 {
504 nX = nXStart;
505 nXCount = 0;
506 nY += nYAdd;
507 nYCount++;
508
509 if( nYCount >= mpFileHeader->nImageHeight )
510 break;
511 }
512 }
513 }
514 else // a raw packet
515 {
516 for ( sal_uInt16 i = 0; i < ( ( nRunCount & 0x7f ) + 1 ); i++ )
517 {
518 m_rTGA.ReadUChar( nBlue ).ReadUChar( nGreen ).ReadUChar( nRed );
519 if ( !m_rTGA.good())
520 return false;
521 mpBitmap->SetPixel( nY, nX, Color( nRed, nGreen, nBlue ) );
522 nX += nXAdd;
523 nXCount++;
524 if ( nXCount == mpFileHeader->nImageWidth )
525 {
526 nX = nXStart;
527 nXCount = 0;
528 nY += nYAdd;
529 nYCount++;
530
531 if( nYCount >= mpFileHeader->nImageHeight )
532 break;
533 }
534 }
535 }
536 }
537 break;
538
539 // 16 bit true color encoding
540 case 16 :
541 while ( nYCount < mpFileHeader->nImageHeight )
542 {
543 m_rTGA.ReadUChar( nRunCount );
544 if ( !m_rTGA.good())
545 return false;
546 if ( nRunCount & 0x80 ) // a run length packet
547 {
548 m_rTGA.ReadUInt16( nRGB16 );
549 if ( !m_rTGA.good())
550 return false;
551 nRed = static_cast<sal_uInt8>( nRGB16 >> 7 ) & 0xf8;
552 nGreen = static_cast<sal_uInt8>( nRGB16 >> 2 ) & 0xf8;
553 nBlue = static_cast<sal_uInt8>( nRGB16 << 3 ) & 0xf8;
554 for ( sal_uInt16 i = 0; i < ( ( nRunCount & 0x7f ) + 1 ); i++ )
555 {
556 mpBitmap->SetPixel( nY, nX, Color( nRed, nGreen, nBlue ) );
557 nX += nXAdd;
558 nXCount++;
559 if ( nXCount == mpFileHeader->nImageWidth )
560 {
561 nX = nXStart;
562 nXCount = 0;
563 nY += nYAdd;
564 nYCount++;
565
566 if( nYCount >= mpFileHeader->nImageHeight )
567 break;
568 }
569 }
570 }
571 else // a raw packet
572 {
573 for ( sal_uInt16 i = 0; i < ( ( nRunCount & 0x7f ) + 1 ); i++ )
574 {
575 m_rTGA.ReadUInt16( nRGB16 );
576 if ( !m_rTGA.good())
577 return false;
578 nRed = static_cast<sal_uInt8>( nRGB16 >> 7 ) & 0xf8;
579 nGreen = static_cast<sal_uInt8>( nRGB16 >> 2 ) & 0xf8;
580 nBlue = static_cast<sal_uInt8>( nRGB16 << 3 ) & 0xf8;
581 mpBitmap->SetPixel( nY, nX, Color( nRed, nGreen, nBlue ) );
582 nX += nXAdd;
583 nXCount++;
584 if ( nXCount == mpFileHeader->nImageWidth )
585 {
586 nX = nXStart;
587 nXCount = 0;
588 nY += nYAdd;
589 nYCount++;
590
591 if( nYCount >= mpFileHeader->nImageHeight )
592 break;
593 }
594 }
595 }
596 }
597 break;
598
599 default:
600 return false;
601 }
602 }
603 }
604 else
605 {
606 for ( nYCount = 0; nYCount < mpFileHeader->nImageHeight; nYCount++, nY += nYAdd )
607 {
608 nX = nXStart;
609 nXCount = 0;
610
611 if ( mbIndexing )
612 {
613 switch( nDepth )
614 {
615 // 16 bit indexing
616 case 16 :
617 for (;nXCount < mpFileHeader->nImageWidth; nXCount++, nX += nXAdd )
618 {
619 m_rTGA.ReadUInt16( nRGB16 );
620 if ( !m_rTGA.good())
621 return false;
622 if ( nRGB16 >= mpFileHeader->nColorMapLength )
623 return false;
624 nRed = static_cast<sal_uInt8>( mpColorMap[ nRGB16 ] >> 16 );
625 nGreen = static_cast<sal_uInt8>( mpColorMap[ nRGB16 ] >> 8 );
626 nBlue = static_cast<sal_uInt8>( mpColorMap[ nRGB16 ] );
627 mpBitmap->SetPixel( nY, nX, Color( nRed, nGreen, nBlue ) );
628 }
629 break;
630
631 // 8 bit indexing
632 case 8 :
633 for (;nXCount < mpFileHeader->nImageWidth; nXCount++, nX += nXAdd )
634 {
635 m_rTGA.ReadUChar( nDummy );
636 if ( !m_rTGA.good())
637 return false;
638 if ( nDummy >= mpFileHeader->nColorMapLength )
639 return false;
640 mpBitmap->SetPixel( nY, nX, Color(ColorTransparency, nDummy) );
641 }
642 break;
643 default:
644 return false;
645 }
646 }
647 else
648 {
649 switch( nDepth )
650 {
651 // 32 bit true color
652 case 32 :
653 {
654 for (;nXCount < mpFileHeader->nImageWidth; nXCount++, nX += nXAdd )
655 {
656 m_rTGA.ReadUChar( nBlue ).ReadUChar( nGreen ).ReadUChar( nRed ).ReadUChar( nDummy );
657 if ( !m_rTGA.good())
658 return false;
659 mpBitmap->SetPixel( nY, nX, Color( nRed, nGreen, nBlue ) );
660 }
661 }
662 break;
663
664 // 24 bit true color
665 case 24 :
666 for (;nXCount < mpFileHeader->nImageWidth; nXCount++, nX += nXAdd )
667 {
668 m_rTGA.ReadUChar( nBlue ).ReadUChar( nGreen ).ReadUChar( nRed );
669 if ( !m_rTGA.good())
670 return false;
671 mpBitmap->SetPixel( nY, nX, Color( nRed, nGreen, nBlue ) );
672 }
673 break;
674
675 // 16 bit true color
676 case 16 :
677 for (;nXCount < mpFileHeader->nImageWidth; nXCount++, nX += nXAdd )
678 {
679 m_rTGA.ReadUInt16( nRGB16 );
680 if ( !m_rTGA.good())
681 return false;
682 nRed = static_cast<sal_uInt8>( nRGB16 >> 7 ) & 0xf8;
683 nGreen = static_cast<sal_uInt8>( nRGB16 >> 2 ) & 0xf8;
684 nBlue = static_cast<sal_uInt8>( nRGB16 << 3 ) & 0xf8;
685 mpBitmap->SetPixel( nY, nX, Color( nRed, nGreen, nBlue ) );
686 }
687 break;
688 default:
689 return false;
690 }
691 }
692 }
693 }
694 return mbStatus;
695}
696
697
698bool TGAReader::ImplReadPalette()
699{
700 if ( mbIndexing ) // read the colormap
701 {
702 sal_uInt16 nColors = mpFileHeader->nColorMapLength;
703
704 if ( !nColors ) // colors == 0 ? -> we will build a grayscale palette
705 {
706 if ( mpFileHeader->nPixelDepth != 8 )
707 return false;
708 nColors = 256;
709 mpFileHeader->nColorMapLength = 256;
710 mpFileHeader->nColorMapEntrySize = 0x3f; // patch for the following switch routine
711 }
712 mpColorMap.reset( new sal_uInt32[ nColors ] ); // we will always index dwords
713
714 switch( mpFileHeader->nColorMapEntrySize )
715 {
716 case 0x3f :
717 {
718 for (sal_uInt32 i = 0; i < nColors; ++i)
719 {
720 mpColorMap[ i ] = ( i << 16 ) + ( i << 8 ) + i;
721 }
722 }
723 break;
724
725 case 32 :
726 for (sal_uInt16 i = 0; i < nColors; i++)
727 {
728 m_rTGA.ReadUInt32(mpColorMap[i]);
729 }
730 break;
731
732 case 24 :
733 {
734 for ( sal_uInt16 i = 0; i < nColors; i++ )
735 {
736 sal_uInt8 nBlue;
737 sal_uInt8 nGreen;
738 sal_uInt8 nRed;
739 m_rTGA.ReadUChar(nBlue).ReadUChar(nGreen).ReadUChar(nRed);
740 mpColorMap[i] = (nRed << 16) | (nGreen << 8) | nBlue;
741 }
742 }
743 break;
744
745 case 15 :
746 case 16 :
747 {
748 for ( sal_uInt16 i = 0; i < nColors; i++ )
749 {
750 sal_uInt16 nTemp;
751 m_rTGA.ReadUInt16( nTemp );
752 if ( !m_rTGA.good() )
753 return false;
754 mpColorMap[ i ] = ( ( nTemp & 0x7c00 ) << 9 ) + ( ( nTemp & 0x01e0 ) << 6 ) +
755 ( ( nTemp & 0x1f ) << 3 );
756 }
757 }
758 break;
759
760 default :
761 return false;
762 }
763 if ( mnDestBitDepth <= 8 )
764 {
765 sal_uInt16 nDestColors = ( 1 << mnDestBitDepth );
766 if ( nColors > nDestColors )
767 return false;
768
769 mvPalette.resize( nColors );
770 for ( sal_uInt16 i = 0; i < nColors; i++ )
771 {
772 mvPalette[i] = Color( static_cast<sal_uInt8>( mpColorMap[ i ] >> 16 ),
773 static_cast<sal_uInt8>( mpColorMap[ i ] >> 8 ), static_cast<sal_uInt8>(mpColorMap[ i ] ) );
774 }
775 }
776 }
777
778 return mbStatus;
779}
780
781//================== GraphicImport - the exported function ================
782
783bool ImportTgaGraphic(SvStream & rStream, Graphic & rGraphic)
784{
785 TGAReader aTGAReader(rStream);
786
787 return aTGAReader.ReadTGA(rGraphic);
788}
789
790/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
FPDF_BITMAP mpBitmap
Intended to be used to feed into CreateFromData to create a BitmapEx.
Definition: RawBitmap.hxx:22
#define SizeOfTGAFileFooter
Definition: itga.cxx:49
bool ImportTgaGraphic(SvStream &rStream, Graphic &rGraphic)
Definition: itga.cxx:783
#define SizeOfTGAExtension
Definition: itga.cxx:60
int i
long Long
BitmapEx CreateFromData(sal_uInt8 const *pData, sal_Int32 nWidth, sal_Int32 nHeight, sal_Int32 nStride, sal_Int8 nBitCount, bool bReversColors, bool bReverseAlpha)
Copy block of image data into the bitmap.
unsigned char sal_uInt8