]>
git.saurik.com Git - wxWidgets.git/blob - src/common/imagtga.cpp
1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: wxImage TGA handler
4 // Author: Seth Jackson
6 // Copyright: (c) 2005 Seth Jackson
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
10 // ============================================================================
12 // ============================================================================
14 // ----------------------------------------------------------------------------
16 // ----------------------------------------------------------------------------
18 // For compilers that support precompilation, includes "wx.h".
19 #include "wx/wxprec.h"
25 #if wxUSE_IMAGE && wxUSE_TGA
28 #include "wx/palette.h"
31 #include "wx/imagtga.h"
33 #include "wx/scopeguard.h"
35 // ----------------------------------------------------------------------------
37 // ----------------------------------------------------------------------------
55 HDR_PALETTELENGTH
= 5,
73 // ============================================================================
75 // ============================================================================
77 IMPLEMENT_DYNAMIC_CLASS(wxTGAHandler
, wxImageHandler
)
81 // ----------------------------------------------------------------------------
83 // ----------------------------------------------------------------------------
86 void FlipTGA(unsigned char* imageData
, int width
, int height
, short pixelSize
)
88 int lineLength
= width
* pixelSize
;
89 unsigned char *line1
= imageData
;
90 unsigned char *line2
= &imageData
[lineLength
* (height
- 1)];
93 for ( ; line1
< line2
; line2
-= (lineLength
* 2))
95 for (int index
= 0; index
< lineLength
; line1
++, line2
++, index
++)
104 // return wxTGA_OK or wxTGA_IOERR
106 int DecodeRLE(unsigned char* imageData
, unsigned long imageSize
,
107 short pixelSize
, wxInputStream
& stream
)
109 unsigned long index
= 0;
110 unsigned char current
;
112 unsigned char buf
[4];
114 while (index
< imageSize
)
116 int ch
= stream
.GetC();
123 if ( current
& 0x80 )
125 // Get the run length of the packet.
132 index
+= current
* pixelSize
;
134 // Repeat the pixel length times.
135 if ( !stream
.Read(buf
, pixelSize
) )
138 for (unsigned int i
= 0; i
< length
; i
++)
140 memcpy(imageData
, buf
, pixelSize
);
142 imageData
+= pixelSize
;
147 // Get the run length of the packet.
150 length
= current
* pixelSize
;
154 // Write the next length pixels directly to the image data.
155 if ( !stream
.Read(imageData
, length
) )
166 int ReadTGA(wxImage
* image
, wxInputStream
& stream
)
168 // Read in the TGA header
169 unsigned char hdr
[HDR_SIZE
];
170 stream
.Read(hdr
, HDR_SIZE
);
172 short offset
= hdr
[HDR_OFFSET
] + HDR_SIZE
;
173 short colorType
= hdr
[HDR_COLORTYPE
];
174 short imageType
= hdr
[HDR_IMAGETYPE
];
175 int paletteLength
= hdr
[HDR_PALETTELENGTH
] + 256 * hdr
[HDR_PALETTELENGTH
+ 1];
176 int width
= (hdr
[HDR_WIDTH
] + 256 * hdr
[HDR_WIDTH
+ 1]) -
177 (hdr
[HDR_XORIGIN
] + 256 * hdr
[HDR_XORIGIN
+ 1]);
178 int height
= (hdr
[HDR_HEIGHT
] + 256 * hdr
[HDR_HEIGHT
+ 1]) -
179 (hdr
[HDR_YORIGIN
] + 256 * hdr
[HDR_YORIGIN
+ 1]);
180 short bpp
= hdr
[HDR_BPP
];
181 short orientation
= hdr
[HDR_ORIENTATION
] & 0x20;
183 image
->Create(width
, height
);
190 const short pixelSize
= bpp
/ 8;
192 const unsigned long imageSize
= width
* height
* pixelSize
;
194 unsigned char *imageData
= (unsigned char* )malloc(imageSize
);
201 wxON_BLOCK_EXIT1(free
, imageData
);
203 unsigned char *dst
= image
->GetData();
205 unsigned char* alpha
= NULL
;
206 if (bpp
== 16 || bpp
== 32)
210 alpha
= image
->GetAlpha();
213 // Seek from the offset we got from the TGA header.
214 if (stream
.SeekI(offset
, wxFromStart
) == wxInvalidOffset
)
215 return wxTGA_INVFORMAT
;
217 // Load a palette if we have one.
218 if (colorType
== wxTGA_MAPPED
)
220 unsigned char buf
[3];
222 unsigned char* r
= new unsigned char[paletteLength
];
223 unsigned char* g
= new unsigned char[paletteLength
];
224 unsigned char* b
= new unsigned char[paletteLength
];
226 for (int i
= 0; i
< paletteLength
; i
++)
236 // Set the palette of the image.
237 image
->SetPalette(wxPalette(paletteLength
, r
, g
, b
));
238 #endif // wxUSE_PALETTE
245 // Handle the various TGA formats we support.
254 const wxPalette
& palette
= image
->GetPalette();
259 // No compression read the data directly to imageData.
261 stream
.Read(imageData
, imageSize
);
263 // If orientation == 0, then the image is stored upside down.
264 // We need to store it right side up.
266 if (orientation
== 0)
268 FlipTGA(imageData
, width
, height
, pixelSize
);
271 // Handle the different pixel depths.
279 for (unsigned long index
= 0; index
< imageSize
; index
+= pixelSize
)
281 palette
.GetRGB(imageData
[index
], &r
, &g
, &b
);
294 for (unsigned long index
= 0; index
< imageSize
; index
+= pixelSize
)
296 palette
.GetRGB(imageData
[index
], &r
, &g
, &b
);
301 *(alpha
++) = (imageData
[index
+ 1] & 0x80) ? 0 : 255;
307 return wxTGA_INVFORMAT
;
311 #endif // wxUSE_PALETTE
317 // No compression read the data directly to imageData.
319 stream
.Read(imageData
, imageSize
);
321 // If orientation == 0, then the image is stored upside down.
322 // We need to store it right side up.
324 if (orientation
== 0)
326 FlipTGA(imageData
, width
, height
, pixelSize
);
329 // Handle the different pixel depths.
339 for (unsigned long index
= 0; index
< imageSize
; index
+= pixelSize
)
341 temp
= (imageData
[index
+ 1] & 0x7c) << 1;
345 temp
= ((imageData
[index
+ 1] & 0x03) << 6) | ((imageData
[index
] & 0xe0) >> 2);
349 temp
= (imageData
[index
] & 0x1f) << 3;
353 *(alpha
++) = (imageData
[index
+ 1] & 0x80) ? 0 : 255;
362 for (unsigned long index
= 0; index
< imageSize
; index
+= pixelSize
)
364 *(dst
++) = imageData
[index
+ 2];
365 *(dst
++) = imageData
[index
+ 1];
366 *(dst
++) = imageData
[index
];
375 for (unsigned long index
= 0; index
< imageSize
; index
+= pixelSize
)
377 *(dst
++) = imageData
[index
+ 2];
378 *(dst
++) = imageData
[index
+ 1];
379 *(dst
++) = imageData
[index
];
380 *(alpha
++) = imageData
[index
+ 3];
386 return wxTGA_INVFORMAT
;
395 // No compression read the data directly to imageData.
397 stream
.Read(imageData
, imageSize
);
399 // If orientation == 0, then the image is stored upside down.
400 // We need to store it right side up.
402 if (orientation
== 0)
404 FlipTGA(imageData
, width
, height
, pixelSize
);
407 // Handle the different pixel depths.
415 for (unsigned long index
= 0; index
< imageSize
; index
+= pixelSize
)
417 *(dst
++) = imageData
[index
];
418 *(dst
++) = imageData
[index
];
419 *(dst
++) = imageData
[index
];
428 for (unsigned long index
= 0; index
< imageSize
; index
+= pixelSize
)
430 *(dst
++) = imageData
[index
];
431 *(dst
++) = imageData
[index
];
432 *(dst
++) = imageData
[index
];
433 *(alpha
++) = imageData
[index
+ 1];
439 return wxTGA_INVFORMAT
;
449 const wxPalette
& palette
= image
->GetPalette();
454 // Decode the RLE data.
456 int rc
= DecodeRLE(imageData
, imageSize
, pixelSize
, stream
);
457 if ( rc
!= wxTGA_OK
)
460 // If orientation == 0, then the image is stored upside down.
461 // We need to store it right side up.
463 if (orientation
== 0)
465 FlipTGA(imageData
, width
, height
, pixelSize
);
468 // Handle the different pixel depths.
476 for (unsigned long index
= 0; index
< imageSize
; index
+= pixelSize
)
478 palette
.GetRGB(imageData
[index
], &r
, &g
, &b
);
491 for (unsigned long index
= 0; index
< imageSize
; index
+= pixelSize
)
493 palette
.GetRGB(imageData
[index
], &r
, &g
, &b
);
498 *(alpha
++) = (imageData
[index
+ 1] & 0x80) ? 0 : 255;
504 return wxTGA_INVFORMAT
;
508 #endif // wxUSE_PALETTE
514 // Decode the RLE data.
516 int rc
= DecodeRLE(imageData
, imageSize
, pixelSize
, stream
);
517 if ( rc
!= wxTGA_OK
)
520 // If orientation == 0, then the image is stored upside down.
521 // We need to store it right side up.
523 if (orientation
== 0)
525 FlipTGA(imageData
, width
, height
, pixelSize
);
528 // Handle the different pixel depths.
538 for (unsigned long index
= 0; index
< imageSize
; index
+= pixelSize
)
540 temp
= (imageData
[index
+ 1] & 0x7c) << 1;
544 temp
= ((imageData
[index
+ 1] & 0x03) << 6) | ((imageData
[index
] & 0xe0) >> 2);
548 temp
= (imageData
[index
] & 0x1f) << 3;
552 *(alpha
++) = (imageData
[index
+ 1] & 0x80) ? 0 : 255;
561 for (unsigned long index
= 0; index
< imageSize
; index
+= pixelSize
)
563 *(dst
++) = imageData
[index
+ 2];
564 *(dst
++) = imageData
[index
+ 1];
565 *(dst
++) = imageData
[index
];
574 for (unsigned long index
= 0; index
< imageSize
; index
+= pixelSize
)
576 *(dst
++) = imageData
[index
+ 2];
577 *(dst
++) = imageData
[index
+ 1];
578 *(dst
++) = imageData
[index
];
579 *(alpha
++) = imageData
[index
+ 3];
585 return wxTGA_INVFORMAT
;
594 // Decode the RLE data.
596 int rc
= DecodeRLE(imageData
, imageSize
, pixelSize
, stream
);
597 if ( rc
!= wxTGA_OK
)
600 // If orientation == 0, then the image is stored upside down.
601 // We need to store it right side up.
603 if (orientation
== 0)
605 FlipTGA(imageData
, width
, height
, pixelSize
);
608 // Handle the different pixel depths.
616 for (unsigned long index
= 0; index
< imageSize
; index
+= pixelSize
)
618 *(dst
++) = imageData
[index
];
619 *(dst
++) = imageData
[index
];
620 *(dst
++) = imageData
[index
];
629 for (unsigned long index
= 0; index
< imageSize
; index
+= pixelSize
)
631 *(dst
++) = imageData
[index
];
632 *(dst
++) = imageData
[index
];
633 *(dst
++) = imageData
[index
];
634 *(alpha
++) = imageData
[index
+ 1];
640 return wxTGA_INVFORMAT
;
646 return wxTGA_INVFORMAT
;
653 int SaveTGA(const wxImage
& image
, wxOutputStream
*stream
)
655 bool hasAlpha
= image
.HasAlpha();
656 unsigned bytesPerPixel
= 3 + (hasAlpha
? 1 : 0);
657 wxSize size
= image
.GetSize();
658 size_t scanlineSize
= size
.x
* bytesPerPixel
;
659 unsigned char *scanlineData
= (unsigned char *) malloc(scanlineSize
);
665 wxON_BLOCK_EXIT1(free
, scanlineData
);
667 // Compose and write the TGA header
668 unsigned char hdr
[HDR_SIZE
];
669 (void) memset(&hdr
, 0, HDR_SIZE
);
671 hdr
[HDR_COLORTYPE
] = wxTGA_UNMAPPED
;
672 hdr
[HDR_IMAGETYPE
] = 2 /* Uncompressed truecolour */;
674 hdr
[HDR_WIDTH
] = size
.x
& 0xFF;
675 hdr
[HDR_WIDTH
+ 1] = (size
.x
>> 8) & 0xFF;
677 hdr
[HDR_HEIGHT
] = size
.y
& 0xFF;
678 hdr
[HDR_HEIGHT
+ 1] = (size
.y
>> 8) & 0xFF;
680 hdr
[HDR_BPP
] = hasAlpha
? 32 : 24;
681 hdr
[HDR_ORIENTATION
] = 1 << 5; // set bit to indicate top-down order
684 hdr
[HDR_ORIENTATION
] |= 8; // number of alpha bits
687 if ( !stream
->Write(hdr
, HDR_SIZE
) )
693 // Write image data, converting RGB to BGR and adding alpha if applicable
695 unsigned char *src
= image
.GetData();
696 unsigned char *alpha
= image
.GetAlpha();
697 for (int y
= 0; y
< size
.y
; ++y
)
699 unsigned char *dst
= scanlineData
;
700 for (int x
= 0; x
< size
.x
; ++x
)
710 dst
+= bytesPerPixel
;
712 if ( !stream
->Write(scanlineData
, scanlineSize
) )
721 // ----------------------------------------------------------------------------
723 // ----------------------------------------------------------------------------
725 bool wxTGAHandler::LoadFile(wxImage
* image
,
726 wxInputStream
& stream
,
730 if ( !CanRead(stream
) )
734 wxLogError(wxT("TGA: this is not a TGA file."));
742 int error
= ReadTGA(image
, stream
);
743 if ( error
!= wxTGA_OK
)
749 case wxTGA_INVFORMAT
:
750 wxLogError(wxT("TGA: image format unsupported."));
754 wxLogError(wxT("TGA: couldn't allocate memory."));
758 wxLogError(wxT("TGA: couldn't read image data."));
762 wxLogError(wxT("TGA: unknown error!"));
774 bool wxTGAHandler::SaveFile(wxImage
* image
, wxOutputStream
& stream
, bool verbose
)
776 int error
= SaveTGA(*image
, &stream
);
778 if ( error
!= wxTGA_OK
)
785 wxLogError(wxT("TGA: couldn't allocate memory."));
789 wxLogError(wxT("TGA: couldn't write image data."));
793 wxLogError(wxT("TGA: unknown error!"));
803 bool wxTGAHandler::DoCanRead(wxInputStream
& stream
)
805 // read the fixed-size TGA headers
806 unsigned char hdr
[HDR_SIZE
];
807 stream
.Read(hdr
, HDR_SIZE
); // it's ok to modify the stream position here
809 // Check wether we can read the file or not.
811 short colorType
= hdr
[HDR_COLORTYPE
];
812 if ( colorType
!= wxTGA_UNMAPPED
&& colorType
!= wxTGA_MAPPED
)
817 short imageType
= hdr
[HDR_IMAGETYPE
];
818 if ( imageType
== 0 || imageType
== 32 || imageType
== 33 )
823 short bpp
= hdr
[HDR_BPP
];
824 if ( bpp
!= 8 && bpp
!= 16 && bpp
!= 24 && bpp
!= 32 )
832 #endif // wxUSE_STREAMS
834 #endif // wxUSE_IMAGE && wxUSE_TGA