]>
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(wxImage
* WXUNUSED(image
), wxOutputStream
& WXUNUSED(stream
))
655 wxLogError(wxT("Saving in TGA format is not implemented."));
660 // ----------------------------------------------------------------------------
662 // ----------------------------------------------------------------------------
664 bool wxTGAHandler::LoadFile(wxImage
* image
,
665 wxInputStream
& stream
,
669 if ( !CanRead(stream
) )
673 wxLogError(wxT("TGA: this is not a TGA file."));
681 int error
= ReadTGA(image
, stream
);
682 if ( error
!= wxTGA_OK
)
688 case wxTGA_INVFORMAT
:
689 wxLogError(wxT("TGA: image format unsupported."));
693 wxLogError(wxT("TGA: couldn't allocate memory."));
697 wxLogError(wxT("TGA: couldn't read image data."));
701 wxLogError(wxT("TGA: unknown error!"));
713 bool wxTGAHandler::SaveFile(wxImage
* image
, wxOutputStream
& stream
, bool verbose
)
715 int error
= SaveTGA(image
, stream
);
717 if ( error
!= wxTGA_OK
)
723 case wxTGA_INVFORMAT
:
724 wxLogError(wxT("TGA: invalid image."));
728 wxLogError(wxT("TGA: couldn't allocate memory."));
732 wxLogError(wxT("TGA: unknown error!"));
742 bool wxTGAHandler::DoCanRead(wxInputStream
& stream
)
744 // read the fixed-size TGA headers
745 unsigned char hdr
[HDR_SIZE
];
746 stream
.Read(hdr
, HDR_SIZE
); // it's ok to modify the stream position here
748 // Check wether we can read the file or not.
750 short colorType
= hdr
[HDR_COLORTYPE
];
751 if ( colorType
!= wxTGA_UNMAPPED
&& colorType
!= wxTGA_MAPPED
)
756 short imageType
= hdr
[HDR_IMAGETYPE
];
757 if ( imageType
== 0 || imageType
== 32 || imageType
== 33 )
762 short bpp
= hdr
[HDR_BPP
];
763 if ( bpp
!= 8 && bpp
!= 16 && bpp
!= 24 && bpp
!= 32 )
771 #endif // wxUSE_STREAMS
773 #endif // wxUSE_IMAGE && wxUSE_TGA