]> git.saurik.com Git - wxWidgets.git/blame - src/common/imagtga.cpp
Made all bitmaps 16x16
[wxWidgets.git] / src / common / imagtga.cpp
CommitLineData
3af706cc
VZ
1/////////////////////////////////////////////////////////////////////////////
2// Name: imagtga.cpp
3// Purpose: wxImage TGA handler
4// Author: Seth Jackson
5// CVS-ID: $Id$
6// Copyright: (c) 2005 Seth Jackson
7// Licence: wxWindows licence
8/////////////////////////////////////////////////////////////////////////////
9
10// ============================================================================
11// declarations
12// ============================================================================
13
14// ----------------------------------------------------------------------------
15// headers
16// ----------------------------------------------------------------------------
17
18// For compilers that support precompilation, includes "wx.h".
19#include "wx/wxprec.h"
20
21#ifdef __BORLANDC__
22 #pragma hdrstop
23#endif
24
25#if wxUSE_IMAGE && wxUSE_TGA
26
27#ifndef WX_PRECOMP
28 #include "wx/palette.h"
29#endif
30
31#include "wx/imagtga.h"
32#include "wx/log.h"
33
34// ----------------------------------------------------------------------------
35// constants
36// ----------------------------------------------------------------------------
37
38// TGA error codes.
39enum
40{
41 wxTGA_OK = 0,
42 wxTGA_INVFORMAT = 1,
43 wxTGA_MEMERR = 2
44};
45
46// TGA header bytes.
47enum
48{
49 HDR_OFFSET = 0,
50 HDR_COLORTYPE = 1,
51 HDR_IMAGETYPE = 2,
52 HDR_PALETTESTART = 3,
53 HDR_PALETTELENGTH = 5,
54 HDR_PALETTEBITS = 7,
55 HDR_XORIGIN = 8,
56 HDR_YORIGIN = 10,
57 HDR_WIDTH = 12,
58 HDR_HEIGHT = 14,
59 HDR_BPP = 16,
60 HDR_ORIENTATION = 17,
61 HDR_SIZE
62};
63
64// TGA color types.
65enum
66{
67 wxTGA_UNMAPPED = 0,
68 wxTGA_MAPPED = 1
69};
70
71// ============================================================================
72// implementation
73// ============================================================================
74
75IMPLEMENT_DYNAMIC_CLASS(wxTGAHandler, wxImageHandler)
76
77#if wxUSE_STREAMS
78
79// ----------------------------------------------------------------------------
80// worker functions
81// ----------------------------------------------------------------------------
82
83static
84void FlipTGA(unsigned char* imageData, int width, int height, short pixelSize)
85{
86 int lineLength = width * pixelSize;
87 unsigned char *line1 = imageData;
88 unsigned char *line2 = &imageData[lineLength * (height - 1)];
89
90 unsigned char temp;
91 for ( ; line1 < line2; line2 -= (lineLength * 2))
92 {
93 for (int index = 0; index < lineLength; line1++, line2++, index++)
94 {
95 temp = *line1;
96 *line1 = *line2;
97 *line2 = temp;
98 }
99 }
100}
101
102static
103void DecodeRLE(unsigned char* imageData, unsigned long imageSize,
104 short pixelSize, wxInputStream& stream)
105{
106 unsigned long index = 0;
107 unsigned char current;
108 unsigned int length;
109 unsigned char buf[4];
110
111 while (index < imageSize)
112 {
113 current = stream.GetC();
114
115 // RLE packet.
116 if ( current & 0x80 )
117 {
118 // Get the run length of the packet.
119 current &= 0x7f;
120
121 current++;
122
123 length = current;
124
125 index += current * pixelSize;
126
127 // Repeat the pixel length times.
128 stream.Read(buf, pixelSize);
129
130 for (unsigned int i = 0; i < length; i++)
131 {
132 memcpy(imageData, buf, pixelSize);
133
134 imageData += pixelSize;
135 }
136 }
137 else // Raw packet.
138 {
139 // Get the run length of the packet.
140 current++;
141
142 length = current * pixelSize;
143
144 index += length;
145
146 // Write the next length pixels directly to the image data.
147 stream.Read(imageData, length);
148
149 imageData += length;
150 }
151 }
152}
153
154static
155int ReadTGA(wxImage* image, wxInputStream& stream)
156{
157 // Read in the TGA header
158 unsigned char hdr[HDR_SIZE];
159 stream.Read(hdr, HDR_SIZE);
160
161 short offset = hdr[HDR_OFFSET] + HDR_SIZE;
162 short colorType = hdr[HDR_COLORTYPE];
163 short imageType = hdr[HDR_IMAGETYPE];
164 int paletteLength = hdr[HDR_PALETTELENGTH] + 256 * hdr[HDR_PALETTELENGTH + 1];
165 int width = (hdr[HDR_WIDTH] + 256 * hdr[HDR_WIDTH + 1]) -
166 (hdr[HDR_XORIGIN] + 256 * hdr[HDR_XORIGIN + 1]);
167 int height = (hdr[HDR_HEIGHT] + 256 * hdr[HDR_HEIGHT + 1]) -
168 (hdr[HDR_YORIGIN] + 256 * hdr[HDR_YORIGIN + 1]);
169 short bpp = hdr[HDR_BPP];
170 short orientation = hdr[HDR_ORIENTATION] & 0x20;
171
172 image->Create(width, height);
173
174 if (!image->Ok())
175 {
176 return wxTGA_MEMERR;
177 }
178
179 const short pixelSize = bpp / 8;
180
181 const unsigned long imageSize = width * height * pixelSize;
182
183 unsigned char *imageData = (unsigned char* )malloc(imageSize);
184
185 if (!imageData)
186 {
187 return wxTGA_MEMERR;
188 }
189
190 unsigned char *dst = image->GetData();
191
192 unsigned char* alpha = NULL;
193 if (bpp == 16 || bpp == 32)
194 {
195 image->SetAlpha();
196
197 alpha = image->GetAlpha();
198 }
199
200 // Seek from the offset we got from the TGA header.
201 stream.SeekI(offset, wxFromStart);
202
203 // Load a palette if we have one.
204 if (colorType == wxTGA_MAPPED)
205 {
206 unsigned char buf[3];
207
208 unsigned char* r = new unsigned char[paletteLength];
209 unsigned char* g = new unsigned char[paletteLength];
210 unsigned char* b = new unsigned char[paletteLength];
211
212 for (int i = 0; i < paletteLength; i++)
213 {
214 stream.Read(buf, 3);
215
216 r[i] = buf[2];
217 g[i] = buf[1];
218 b[i] = buf[0];
219 }
220
221 #if wxUSE_PALETTE
222
223 // Set the palette of the image.
224
225 image->SetPalette(wxPalette(paletteLength, r, g, b));
226
227 #endif // wxUSE_PALETTE
228
229 delete[] r;
230 delete[] g;
231 delete[] b;
232 }
233
234 // Handle the various TGA formats we support.
235
236 switch (imageType)
237 {
238 // Raw indexed.
239
240 case 1:
241 {
242 const wxPalette& palette = image->GetPalette();
243 unsigned char r;
244 unsigned char g;
245 unsigned char b;
246
247 // No compression read the data directly to imageData.
248
249 stream.Read(imageData, imageSize);
250
251 // If orientation == 0, then the image is stored upside down.
252 // We need to store it right side up.
253
254 if (orientation == 0)
255 {
256 FlipTGA(imageData, width, height, pixelSize);
257 }
258
259 // Handle the different pixel depths.
260
261 switch (bpp)
262 {
263 // 8 bpp.
264
265 case 8:
266 {
267 for (unsigned long index = 0; index < imageSize; index += pixelSize)
268 {
269 palette.GetRGB(imageData[index], &r, &g, &b);
270
271 *(dst++) = r;
272 *(dst++) = g;
273 *(dst++) = b;
274 }
275 }
276 break;
277
278 // 16 bpp.
279
280 case 16:
281 {
282 for (unsigned long index = 0; index < imageSize; index += pixelSize)
283 {
284 palette.GetRGB(imageData[index], &r, &g, &b);
285
286 *(dst++) = r;
287 *(dst++) = g;
288 *(dst++) = b;
289 *(alpha++) = (imageData[index + 1] & 0x80) ? 0 : 255;
290 }
291 }
292 break;
293
294 default:
295 return wxTGA_INVFORMAT;
296 }
297 }
298 break;
299
300 // Raw RGB.
301
302 case 2:
303 {
304 // No compression read the data directly to imageData.
305
306 stream.Read(imageData, imageSize);
307
308 // If orientation == 0, then the image is stored upside down.
309 // We need to store it right side up.
310
311 if (orientation == 0)
312 {
313 FlipTGA(imageData, width, height, pixelSize);
314 }
315
316 // Handle the different pixel depths.
317
318 switch (bpp)
319 {
320 //16 bpp.
321
322 case 16:
323 {
324 unsigned char temp;
325
326 for (unsigned long index = 0; index < imageSize; index += pixelSize)
327 {
328 temp = (imageData[index + 1] & 0x7c) << 1;
329 temp |= temp >> 5;
330 *(dst++) = temp;
331
332 temp = ((imageData[index + 1] & 0x03) << 6) | ((imageData[index] & 0xe0) >> 2);
333 temp |= temp >> 5;
334 *(dst++) = temp;
335
336 temp = (imageData[index] & 0x1f) << 3;
337 temp |= temp >> 5;
338 *(dst++) = temp;
339
340 *(alpha++) = (imageData[index + 1] & 0x80) ? 0 : 255;
341 }
342 }
343 break;
344
345 // 24 bpp.
346
347 case 24:
348 {
349 for (unsigned long index = 0; index < imageSize; index += pixelSize)
350 {
351 *(dst++) = imageData[index + 2];
352 *(dst++) = imageData[index + 1];
353 *(dst++) = imageData[index];
354 }
355 }
356 break;
357
358 // 32 bpp.
359
360 case 32:
361 {
362 for (unsigned long index = 0; index < imageSize; index += pixelSize)
363 {
364 *(dst++) = imageData[index + 2];
365 *(dst++) = imageData[index + 1];
366 *(dst++) = imageData[index];
367 *(alpha++) = imageData[index + 3];
368 }
369 }
370 break;
371
372 default:
373 return wxTGA_INVFORMAT;
374 }
375 }
376 break;
377
378 // Raw grayscale.
379
380 case 3:
381 {
382 // No compression read the data directly to imageData.
383
384 stream.Read(imageData, imageSize);
385
386 // If orientation == 0, then the image is stored upside down.
387 // We need to store it right side up.
388
389 if (orientation == 0)
390 {
391 FlipTGA(imageData, width, height, pixelSize);
392 }
393
394 // Handle the different pixel depths.
395
396 switch (bpp)
397 {
398 // 8 bpp.
399
400 case 8:
401 {
402 for (unsigned long index = 0; index < imageSize; index += pixelSize)
403 {
404 *(dst++) = imageData[index];
405 *(dst++) = imageData[index];
406 *(dst++) = imageData[index];
407 }
408 }
409 break;
410
411 // 16 bpp.
412
413 case 16:
414 {
415 for (unsigned long index = 0; index < imageSize; index += pixelSize)
416 {
417 *(dst++) = imageData[index];
418 *(dst++) = imageData[index];
419 *(dst++) = imageData[index];
420 *(alpha++) = imageData[index + 1];
421 }
422 }
423 break;
424
425 default:
426 return wxTGA_INVFORMAT;
427 }
428 }
429 break;
430
431 // RLE indexed.
432
433 case 9:
434 {
435 const wxPalette& palette = image->GetPalette();
436 unsigned char r;
437 unsigned char g;
438 unsigned char b;
439
440 // Decode the RLE data.
441
442 DecodeRLE(imageData, imageSize, pixelSize, stream);
443
444 // If orientation == 0, then the image is stored upside down.
445 // We need to store it right side up.
446
447 if (orientation == 0)
448 {
449 FlipTGA(imageData, width, height, pixelSize);
450 }
451
452 // Handle the different pixel depths.
453
454 switch (bpp)
455 {
456 // 8 bpp.
457
458 case 8:
459 {
460 for (unsigned long index = 0; index < imageSize; index += pixelSize)
461 {
462 palette.GetRGB(imageData[index], &r, &g, &b);
463
464 *(dst++) = r;
465 *(dst++) = g;
466 *(dst++) = b;
467 }
468 }
469 break;
470
471 // 16 bpp.
472
473 case 16:
474 {
475 for (unsigned long index = 0; index < imageSize; index += pixelSize)
476 {
477 palette.GetRGB(imageData[index], &r, &g, &b);
478
479 *(dst++) = r;
480 *(dst++) = g;
481 *(dst++) = b;
482 *(alpha++) = (imageData[index + 1] & 0x80) ? 0 : 255;
483 }
484 }
485 break;
486
487 default:
488 return wxTGA_INVFORMAT;
489 }
490 }
491 break;
492
493 // RLE RGB.
494
495 case 10:
496 {
497 // Decode the RLE data.
498
499 DecodeRLE(imageData, imageSize, pixelSize, stream);
500
501 // If orientation == 0, then the image is stored upside down.
502 // We need to store it right side up.
503
504 if (orientation == 0)
505 {
506 FlipTGA(imageData, width, height, pixelSize);
507 }
508
509 // Handle the different pixel depths.
510
511 switch (bpp)
512 {
513 //16 bpp.
514
515 case 16:
516 {
517 unsigned char temp;
518
519 for (unsigned long index = 0; index < imageSize; index += pixelSize)
520 {
521 temp = (imageData[index + 1] & 0x7c) << 1;
522 temp |= temp >> 5;
523 *(dst++) = temp;
524
525 temp = ((imageData[index + 1] & 0x03) << 6) | ((imageData[index] & 0xe0) >> 2);
526 temp |= temp >> 5;
527 *(dst++) = temp;
528
529 temp = (imageData[index] & 0x1f) << 3;
530 temp |= temp >> 5;
531 *(dst++) = temp;
532
533 *(alpha++) = (imageData[index + 1] & 0x80) ? 0 : 255;
534 }
535 }
536 break;
537
538 // 24 bpp.
539
540 case 24:
541 {
542 for (unsigned long index = 0; index < imageSize; index += pixelSize)
543 {
544 *(dst++) = imageData[index + 2];
545 *(dst++) = imageData[index + 1];
546 *(dst++) = imageData[index];
547 }
548 }
549 break;
550
551 // 32 bpp.
552
553 case 32:
554 {
555 for (unsigned long index = 0; index < imageSize; index += pixelSize)
556 {
557 *(dst++) = imageData[index + 2];
558 *(dst++) = imageData[index + 1];
559 *(dst++) = imageData[index];
560 *(alpha++) = imageData[index + 3];
561 }
562 }
563 break;
564
565 default:
566 return wxTGA_INVFORMAT;
567 }
568 }
569 break;
570
571 // RLE grayscale.
572
573 case 11:
574 {
575 // Decode the RLE data.
576
577 DecodeRLE(imageData, imageSize, pixelSize, stream);
578
579 // If orientation == 0, then the image is stored upside down.
580 // We need to store it right side up.
581
582 if (orientation == 0)
583 {
584 FlipTGA(imageData, width, height, pixelSize);
585 }
586
587 // Handle the different pixel depths.
588
589 switch (bpp)
590 {
591 // 8 bpp.
592
593 case 8:
594 {
595 for (unsigned long index = 0; index < imageSize; index += pixelSize)
596 {
597 *(dst++) = imageData[index];
598 *(dst++) = imageData[index];
599 *(dst++) = imageData[index];
600 }
601 }
602 break;
603
604 // 16 bpp.
605
606 case 16:
607 {
608 for (unsigned long index = 0; index < imageSize; index += pixelSize)
609 {
610 *(dst++) = imageData[index];
611 *(dst++) = imageData[index];
612 *(dst++) = imageData[index];
613 *(alpha++) = imageData[index + 1];
614 }
615 }
616 break;
617
618 default:
619 return wxTGA_INVFORMAT;
620 }
621 }
622 break;
623
624 default:
625 return wxTGA_INVFORMAT;
626 }
627
628 free(imageData);
629
630 return wxTGA_OK;
631}
632
633static
634int SaveTGA(wxImage* WXUNUSED(image), wxOutputStream& WXUNUSED(stream))
635{
636 wxLogError(wxT("Saving in TGA format is not implemented."));
637
638 return wxTGA_OK;
639}
640
641// ----------------------------------------------------------------------------
642// wxTGAHandler
643// ----------------------------------------------------------------------------
644
645bool wxTGAHandler::LoadFile(wxImage* image,
646 wxInputStream& stream,
647 bool verbose,
648 int WXUNUSED(index))
649{
650 if ( !CanRead(stream) )
651 {
652 if ( verbose )
653 wxLogError(wxT("TGA: this is not a TGA file."));
654
655 return false;
656 }
657
658 image->Destroy();
659
660 int error = ReadTGA(image, stream);
661 if ( error != wxTGA_OK )
662 {
663 if ( verbose )
664 {
665 switch ( error )
666 {
667 case wxTGA_INVFORMAT:
668 wxLogError(wxT("TGA: image format unsupported."));
669 break;
670
671 case wxTGA_MEMERR:
672 wxLogError(wxT("TGA: couldn't allocate memory."));
673 break;
674
675 default:
676 wxLogError(wxT("TGA: unknown error!"));
677 }
678 }
679
680 image->Destroy();
681
682 return false;
683 }
684
685 return true;
686}
687
688bool wxTGAHandler::SaveFile(wxImage* image, wxOutputStream& stream, bool verbose)
689{
690 int error = SaveTGA(image, stream);
691
692 if ( error != wxTGA_OK )
693 {
694 if ( verbose )
695 {
696 switch ( error )
697 {
698 case wxTGA_INVFORMAT:
699 wxLogError(wxT("TGA: invalid image."));
700 break;
701
702 case wxTGA_MEMERR:
703 wxLogError(wxT("TGA: couldn't allocate memory."));
704 break;
705
706 default:
707 wxLogError(wxT("TGA: unknown error!"));
708 }
709 }
710
711 return false;
712 }
713
714 return true;
715}
716
717bool wxTGAHandler::DoCanRead(wxInputStream& stream)
718{
719 // read the fixed-size TGA headers
720 unsigned char hdr[HDR_SIZE];
721 stream.Read(hdr, HDR_SIZE);
722
723 // Check wether we can read the file or not.
724
725 short colorType = hdr[HDR_COLORTYPE];
726 if ( colorType != wxTGA_UNMAPPED && colorType != wxTGA_MAPPED )
727 {
728 return false;
729 }
730
731 short imageType = hdr[HDR_IMAGETYPE];
732 if ( imageType == 0 || imageType == 32 || imageType == 33 )
733 {
734 return false;
735 }
736
737 short bpp = hdr[HDR_BPP];
738 if ( bpp != 8 && bpp != 16 && bpp != 24 && bpp != 32 )
739 {
740 return false;
741 }
742
743 return true;
744}
745
746#endif // wxUSE_STREAMS
747
748#endif // wxUSE_IMAGE && wxUSE_TGA