]>
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 stream
.SeekI(offset
, wxFromStart
);
216 // Load a palette if we have one.
217 if (colorType
== wxTGA_MAPPED
)
219 unsigned char buf
[3];
221 unsigned char* r
= new unsigned char[paletteLength
];
222 unsigned char* g
= new unsigned char[paletteLength
];
223 unsigned char* b
= new unsigned char[paletteLength
];
225 for (int i
= 0; i
< paletteLength
; i
++)
235 // Set the palette of the image.
236 image
->SetPalette(wxPalette(paletteLength
, r
, g
, b
));
237 #endif // wxUSE_PALETTE
244 // Handle the various TGA formats we support.
253 const wxPalette
& palette
= image
->GetPalette();
258 // No compression read the data directly to imageData.
260 stream
.Read(imageData
, imageSize
);
262 // If orientation == 0, then the image is stored upside down.
263 // We need to store it right side up.
265 if (orientation
== 0)
267 FlipTGA(imageData
, width
, height
, pixelSize
);
270 // Handle the different pixel depths.
278 for (unsigned long index
= 0; index
< imageSize
; index
+= pixelSize
)
280 palette
.GetRGB(imageData
[index
], &r
, &g
, &b
);
293 for (unsigned long index
= 0; index
< imageSize
; index
+= pixelSize
)
295 palette
.GetRGB(imageData
[index
], &r
, &g
, &b
);
300 *(alpha
++) = (imageData
[index
+ 1] & 0x80) ? 0 : 255;
306 return wxTGA_INVFORMAT
;
310 #endif // wxUSE_PALETTE
316 // No compression read the data directly to imageData.
318 stream
.Read(imageData
, imageSize
);
320 // If orientation == 0, then the image is stored upside down.
321 // We need to store it right side up.
323 if (orientation
== 0)
325 FlipTGA(imageData
, width
, height
, pixelSize
);
328 // Handle the different pixel depths.
338 for (unsigned long index
= 0; index
< imageSize
; index
+= pixelSize
)
340 temp
= (imageData
[index
+ 1] & 0x7c) << 1;
344 temp
= ((imageData
[index
+ 1] & 0x03) << 6) | ((imageData
[index
] & 0xe0) >> 2);
348 temp
= (imageData
[index
] & 0x1f) << 3;
352 *(alpha
++) = (imageData
[index
+ 1] & 0x80) ? 0 : 255;
361 for (unsigned long index
= 0; index
< imageSize
; index
+= pixelSize
)
363 *(dst
++) = imageData
[index
+ 2];
364 *(dst
++) = imageData
[index
+ 1];
365 *(dst
++) = imageData
[index
];
374 for (unsigned long index
= 0; index
< imageSize
; index
+= pixelSize
)
376 *(dst
++) = imageData
[index
+ 2];
377 *(dst
++) = imageData
[index
+ 1];
378 *(dst
++) = imageData
[index
];
379 *(alpha
++) = imageData
[index
+ 3];
385 return wxTGA_INVFORMAT
;
394 // No compression read the data directly to imageData.
396 stream
.Read(imageData
, imageSize
);
398 // If orientation == 0, then the image is stored upside down.
399 // We need to store it right side up.
401 if (orientation
== 0)
403 FlipTGA(imageData
, width
, height
, pixelSize
);
406 // Handle the different pixel depths.
414 for (unsigned long index
= 0; index
< imageSize
; index
+= pixelSize
)
416 *(dst
++) = imageData
[index
];
417 *(dst
++) = imageData
[index
];
418 *(dst
++) = imageData
[index
];
427 for (unsigned long index
= 0; index
< imageSize
; index
+= pixelSize
)
429 *(dst
++) = imageData
[index
];
430 *(dst
++) = imageData
[index
];
431 *(dst
++) = imageData
[index
];
432 *(alpha
++) = imageData
[index
+ 1];
438 return wxTGA_INVFORMAT
;
448 const wxPalette
& palette
= image
->GetPalette();
453 // Decode the RLE data.
455 int rc
= DecodeRLE(imageData
, imageSize
, pixelSize
, stream
);
456 if ( rc
!= wxTGA_OK
)
459 // If orientation == 0, then the image is stored upside down.
460 // We need to store it right side up.
462 if (orientation
== 0)
464 FlipTGA(imageData
, width
, height
, pixelSize
);
467 // Handle the different pixel depths.
475 for (unsigned long index
= 0; index
< imageSize
; index
+= pixelSize
)
477 palette
.GetRGB(imageData
[index
], &r
, &g
, &b
);
490 for (unsigned long index
= 0; index
< imageSize
; index
+= pixelSize
)
492 palette
.GetRGB(imageData
[index
], &r
, &g
, &b
);
497 *(alpha
++) = (imageData
[index
+ 1] & 0x80) ? 0 : 255;
503 return wxTGA_INVFORMAT
;
507 #endif // wxUSE_PALETTE
513 // Decode the RLE data.
515 int rc
= DecodeRLE(imageData
, imageSize
, pixelSize
, stream
);
516 if ( rc
!= wxTGA_OK
)
519 // If orientation == 0, then the image is stored upside down.
520 // We need to store it right side up.
522 if (orientation
== 0)
524 FlipTGA(imageData
, width
, height
, pixelSize
);
527 // Handle the different pixel depths.
537 for (unsigned long index
= 0; index
< imageSize
; index
+= pixelSize
)
539 temp
= (imageData
[index
+ 1] & 0x7c) << 1;
543 temp
= ((imageData
[index
+ 1] & 0x03) << 6) | ((imageData
[index
] & 0xe0) >> 2);
547 temp
= (imageData
[index
] & 0x1f) << 3;
551 *(alpha
++) = (imageData
[index
+ 1] & 0x80) ? 0 : 255;
560 for (unsigned long index
= 0; index
< imageSize
; index
+= pixelSize
)
562 *(dst
++) = imageData
[index
+ 2];
563 *(dst
++) = imageData
[index
+ 1];
564 *(dst
++) = imageData
[index
];
573 for (unsigned long index
= 0; index
< imageSize
; index
+= pixelSize
)
575 *(dst
++) = imageData
[index
+ 2];
576 *(dst
++) = imageData
[index
+ 1];
577 *(dst
++) = imageData
[index
];
578 *(alpha
++) = imageData
[index
+ 3];
584 return wxTGA_INVFORMAT
;
593 // Decode the RLE data.
595 int rc
= DecodeRLE(imageData
, imageSize
, pixelSize
, stream
);
596 if ( rc
!= wxTGA_OK
)
599 // If orientation == 0, then the image is stored upside down.
600 // We need to store it right side up.
602 if (orientation
== 0)
604 FlipTGA(imageData
, width
, height
, pixelSize
);
607 // Handle the different pixel depths.
615 for (unsigned long index
= 0; index
< imageSize
; index
+= pixelSize
)
617 *(dst
++) = imageData
[index
];
618 *(dst
++) = imageData
[index
];
619 *(dst
++) = imageData
[index
];
628 for (unsigned long index
= 0; index
< imageSize
; index
+= pixelSize
)
630 *(dst
++) = imageData
[index
];
631 *(dst
++) = imageData
[index
];
632 *(dst
++) = imageData
[index
];
633 *(alpha
++) = imageData
[index
+ 1];
639 return wxTGA_INVFORMAT
;
645 return wxTGA_INVFORMAT
;
652 int SaveTGA(wxImage
* WXUNUSED(image
), wxOutputStream
& WXUNUSED(stream
))
654 wxLogError(wxT("Saving in TGA format is not implemented."));
659 // ----------------------------------------------------------------------------
661 // ----------------------------------------------------------------------------
663 bool wxTGAHandler::LoadFile(wxImage
* image
,
664 wxInputStream
& stream
,
668 if ( !CanRead(stream
) )
671 wxLogError(wxT("TGA: this is not a TGA file."));
678 int error
= ReadTGA(image
, stream
);
679 if ( error
!= wxTGA_OK
)
685 case wxTGA_INVFORMAT
:
686 wxLogError(wxT("TGA: image format unsupported."));
690 wxLogError(wxT("TGA: couldn't allocate memory."));
694 wxLogError(wxT("TGA: couldn't read image data."));
698 wxLogError(wxT("TGA: unknown error!"));
710 bool wxTGAHandler::SaveFile(wxImage
* image
, wxOutputStream
& stream
, bool verbose
)
712 int error
= SaveTGA(image
, stream
);
714 if ( error
!= wxTGA_OK
)
720 case wxTGA_INVFORMAT
:
721 wxLogError(wxT("TGA: invalid image."));
725 wxLogError(wxT("TGA: couldn't allocate memory."));
729 wxLogError(wxT("TGA: unknown error!"));
739 bool wxTGAHandler::DoCanRead(wxInputStream
& stream
)
741 // read the fixed-size TGA headers
742 unsigned char hdr
[HDR_SIZE
];
743 stream
.Read(hdr
, HDR_SIZE
);
745 // Check wether we can read the file or not.
747 short colorType
= hdr
[HDR_COLORTYPE
];
748 if ( colorType
!= wxTGA_UNMAPPED
&& colorType
!= wxTGA_MAPPED
)
753 short imageType
= hdr
[HDR_IMAGETYPE
];
754 if ( imageType
== 0 || imageType
== 32 || imageType
== 33 )
759 short bpp
= hdr
[HDR_BPP
];
760 if ( bpp
!= 8 && bpp
!= 16 && bpp
!= 24 && bpp
!= 32 )
768 #endif // wxUSE_STREAMS
770 #endif // wxUSE_IMAGE && wxUSE_TGA