3f66f6a5b3
This keyword is not expanded by Git which means it's not replaced with the correct revision value in the releases made using git-based scripts and it's confusing to have lines with unexpanded "$Id$" in the released files. As expanding them with Git is not that simple (it could be done with git archive and export-subst attribute) and there are not many benefits in having them in the first place, just remove all these lines. If nothing else, this will make an eventual transition to Git simpler. Closes #14487. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@74602 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
874 lines
23 KiB
C++
874 lines
23 KiB
C++
/////////////////////////////////////////////////////////////////////////////
|
|
// Name: src/common/imagtga.cpp
|
|
// Purpose: wxImage TGA handler
|
|
// Author: Seth Jackson
|
|
// Copyright: (c) 2005 Seth Jackson
|
|
// Licence: wxWindows licence
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
// ============================================================================
|
|
// declarations
|
|
// ============================================================================
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// headers
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// For compilers that support precompilation, includes "wx.h".
|
|
#include "wx/wxprec.h"
|
|
|
|
#ifdef __BORLANDC__
|
|
#pragma hdrstop
|
|
#endif
|
|
|
|
#if wxUSE_IMAGE && wxUSE_TGA
|
|
|
|
#ifndef WX_PRECOMP
|
|
#include "wx/palette.h"
|
|
#endif
|
|
|
|
#include "wx/imagtga.h"
|
|
#include "wx/log.h"
|
|
#include "wx/scopeguard.h"
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// constants
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// TGA error codes.
|
|
enum
|
|
{
|
|
wxTGA_OK,
|
|
wxTGA_INVFORMAT,
|
|
wxTGA_MEMERR,
|
|
wxTGA_IOERR
|
|
};
|
|
|
|
// TGA header bytes.
|
|
enum
|
|
{
|
|
HDR_OFFSET = 0,
|
|
HDR_COLORTYPE = 1,
|
|
HDR_IMAGETYPE = 2,
|
|
HDR_PALETTESTART = 3,
|
|
HDR_PALETTELENGTH = 5,
|
|
HDR_PALETTEBITS = 7,
|
|
HDR_XORIGIN = 8,
|
|
HDR_YORIGIN = 10,
|
|
HDR_WIDTH = 12,
|
|
HDR_HEIGHT = 14,
|
|
HDR_BPP = 16,
|
|
HDR_ORIENTATION = 17,
|
|
HDR_SIZE
|
|
};
|
|
|
|
// TGA color types.
|
|
enum
|
|
{
|
|
wxTGA_UNMAPPED = 0,
|
|
wxTGA_MAPPED = 1
|
|
};
|
|
|
|
// ============================================================================
|
|
// implementation
|
|
// ============================================================================
|
|
|
|
IMPLEMENT_DYNAMIC_CLASS(wxTGAHandler, wxImageHandler)
|
|
|
|
#if wxUSE_STREAMS
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// worker functions
|
|
// ----------------------------------------------------------------------------
|
|
|
|
static
|
|
void FlipTGA(unsigned char* imageData, int width, int height, short pixelSize)
|
|
{
|
|
int lineLength = width * pixelSize;
|
|
unsigned char *line1 = imageData;
|
|
unsigned char *line2 = &imageData[lineLength * (height - 1)];
|
|
|
|
unsigned char temp;
|
|
for ( ; line1 < line2; line2 -= (lineLength * 2))
|
|
{
|
|
for (int index = 0; index < lineLength; line1++, line2++, index++)
|
|
{
|
|
temp = *line1;
|
|
*line1 = *line2;
|
|
*line2 = temp;
|
|
}
|
|
}
|
|
}
|
|
|
|
// return wxTGA_OK or wxTGA_IOERR
|
|
static
|
|
int DecodeRLE(unsigned char* imageData, unsigned long imageSize,
|
|
short pixelSize, wxInputStream& stream)
|
|
{
|
|
unsigned long index = 0;
|
|
unsigned char current;
|
|
unsigned int length;
|
|
unsigned char buf[4];
|
|
|
|
while (index < imageSize)
|
|
{
|
|
int ch = stream.GetC();
|
|
if ( ch == wxEOF )
|
|
return wxTGA_IOERR;
|
|
|
|
current = ch;
|
|
|
|
// RLE packet.
|
|
if ( current & 0x80 )
|
|
{
|
|
// Get the run length of the packet.
|
|
current &= 0x7f;
|
|
|
|
current++;
|
|
|
|
length = current;
|
|
|
|
index += current * pixelSize;
|
|
|
|
if (index >= imageSize)
|
|
{
|
|
return wxTGA_IOERR;
|
|
}
|
|
|
|
// Repeat the pixel length times.
|
|
if ( !stream.Read(buf, pixelSize) )
|
|
return wxTGA_IOERR;
|
|
|
|
for (unsigned int i = 0; i < length; i++)
|
|
{
|
|
memcpy(imageData, buf, pixelSize);
|
|
|
|
imageData += pixelSize;
|
|
}
|
|
}
|
|
else // Raw packet.
|
|
{
|
|
// Get the run length of the packet.
|
|
current++;
|
|
|
|
length = current * pixelSize;
|
|
|
|
index += length;
|
|
|
|
if (index >= imageSize)
|
|
{
|
|
return wxTGA_IOERR;
|
|
}
|
|
|
|
// Write the next length pixels directly to the image data.
|
|
if ( !stream.Read(imageData, length) )
|
|
return wxTGA_IOERR;
|
|
|
|
imageData += length;
|
|
}
|
|
}
|
|
|
|
return wxTGA_OK;
|
|
}
|
|
|
|
/*
|
|
Mimic the behaviour of wxPalette.GetRGB and the way the TGA image handler
|
|
used it. That is: don't check the return value of GetRGB and continue decoding
|
|
using previous RGB values.
|
|
|
|
It might be better to check for palette index bounds and stop decoding if
|
|
it's out of range (and add something like wxTGA_DATAERR to indicate unexpected
|
|
pixel data).
|
|
*/
|
|
static
|
|
void Palette_GetRGB(const unsigned char *palette, unsigned int paletteCount,
|
|
unsigned int index,
|
|
unsigned char *red, unsigned char *green, unsigned char *blue)
|
|
{
|
|
if (index >= paletteCount)
|
|
{
|
|
return;
|
|
}
|
|
|
|
*red = palette[index];
|
|
*green = palette[(paletteCount * 1) + index];
|
|
*blue = palette[(paletteCount * 2) + index];
|
|
}
|
|
|
|
static
|
|
void Palette_SetRGB(unsigned char *palette, unsigned int paletteCount,
|
|
unsigned int index,
|
|
unsigned char red, unsigned char green, unsigned char blue)
|
|
{
|
|
palette[index] = red;
|
|
palette[(paletteCount * 1) + index] = green;
|
|
palette[(paletteCount * 2) + index] = blue;
|
|
}
|
|
|
|
static
|
|
int ReadTGA(wxImage* image, wxInputStream& stream)
|
|
{
|
|
// Read in the TGA header
|
|
unsigned char hdr[HDR_SIZE];
|
|
stream.Read(hdr, HDR_SIZE);
|
|
|
|
short offset = hdr[HDR_OFFSET] + HDR_SIZE;
|
|
short colorType = hdr[HDR_COLORTYPE];
|
|
short imageType = hdr[HDR_IMAGETYPE];
|
|
unsigned int paletteLength = hdr[HDR_PALETTELENGTH]
|
|
+ 256 * hdr[HDR_PALETTELENGTH + 1];
|
|
int width = (hdr[HDR_WIDTH] + 256 * hdr[HDR_WIDTH + 1]) -
|
|
(hdr[HDR_XORIGIN] + 256 * hdr[HDR_XORIGIN + 1]);
|
|
int height = (hdr[HDR_HEIGHT] + 256 * hdr[HDR_HEIGHT + 1]) -
|
|
(hdr[HDR_YORIGIN] + 256 * hdr[HDR_YORIGIN + 1]);
|
|
short bpp = hdr[HDR_BPP];
|
|
short orientation = hdr[HDR_ORIENTATION] & 0x20;
|
|
|
|
image->Create(width, height);
|
|
|
|
if (!image->IsOk())
|
|
{
|
|
return wxTGA_MEMERR;
|
|
}
|
|
|
|
const short pixelSize = bpp / 8;
|
|
|
|
const unsigned long imageSize = width * height * pixelSize;
|
|
|
|
unsigned char *imageData = (unsigned char* )malloc(imageSize);
|
|
|
|
if (!imageData)
|
|
{
|
|
return wxTGA_MEMERR;
|
|
}
|
|
|
|
wxON_BLOCK_EXIT1(free, imageData);
|
|
|
|
unsigned char *dst = image->GetData();
|
|
|
|
unsigned char* alpha = NULL;
|
|
if (bpp == 16 || bpp == 32)
|
|
{
|
|
image->SetAlpha();
|
|
|
|
alpha = image->GetAlpha();
|
|
}
|
|
|
|
// Seek from the offset we got from the TGA header.
|
|
if (stream.SeekI(offset, wxFromStart) == wxInvalidOffset)
|
|
return wxTGA_INVFORMAT;
|
|
|
|
unsigned char *palette = NULL;
|
|
// Load a palette if we have one.
|
|
if (colorType == wxTGA_MAPPED)
|
|
{
|
|
unsigned char buf[3];
|
|
|
|
palette = (unsigned char *) malloc(paletteLength * 3);
|
|
|
|
for (unsigned int i = 0; i < paletteLength; i++)
|
|
{
|
|
stream.Read(buf, 3);
|
|
|
|
Palette_SetRGB(palette, paletteLength, i, buf[2], buf[1], buf[0]);
|
|
}
|
|
|
|
#if wxUSE_PALETTE
|
|
// Set the palette of the image.
|
|
image->SetPalette(wxPalette((int) paletteLength, &palette[0],
|
|
&palette[paletteLength * 1], &palette[paletteLength * 2]));
|
|
#endif // wxUSE_PALETTE
|
|
|
|
}
|
|
|
|
wxON_BLOCK_EXIT1(free, palette);
|
|
|
|
// Handle the various TGA formats we support.
|
|
|
|
switch (imageType)
|
|
{
|
|
// Raw indexed.
|
|
|
|
case 1:
|
|
{
|
|
unsigned char r = 0;
|
|
unsigned char g = 0;
|
|
unsigned char b = 0;
|
|
|
|
// No compression read the data directly to imageData.
|
|
|
|
stream.Read(imageData, imageSize);
|
|
|
|
// If orientation == 0, then the image is stored upside down.
|
|
// We need to store it right side up.
|
|
|
|
if (orientation == 0)
|
|
{
|
|
FlipTGA(imageData, width, height, pixelSize);
|
|
}
|
|
|
|
// Handle the different pixel depths.
|
|
|
|
switch (bpp)
|
|
{
|
|
// 8 bpp.
|
|
|
|
case 8:
|
|
{
|
|
for (unsigned long index = 0; index < imageSize; index += pixelSize)
|
|
{
|
|
Palette_GetRGB(palette, paletteLength,
|
|
imageData[index], &r, &g, &b);
|
|
|
|
*(dst++) = r;
|
|
*(dst++) = g;
|
|
*(dst++) = b;
|
|
}
|
|
}
|
|
break;
|
|
|
|
// 16 bpp.
|
|
|
|
case 16:
|
|
{
|
|
for (unsigned long index = 0; index < imageSize; index += pixelSize)
|
|
{
|
|
Palette_GetRGB(palette, paletteLength,
|
|
imageData[index], &r, &g, &b);
|
|
|
|
*(dst++) = r;
|
|
*(dst++) = g;
|
|
*(dst++) = b;
|
|
*(alpha++) = (imageData[index + 1] & 0x80) ? 0 : 255;
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return wxTGA_INVFORMAT;
|
|
}
|
|
}
|
|
break;
|
|
|
|
// Raw RGB.
|
|
|
|
case 2:
|
|
{
|
|
// No compression read the data directly to imageData.
|
|
|
|
stream.Read(imageData, imageSize);
|
|
|
|
// If orientation == 0, then the image is stored upside down.
|
|
// We need to store it right side up.
|
|
|
|
if (orientation == 0)
|
|
{
|
|
FlipTGA(imageData, width, height, pixelSize);
|
|
}
|
|
|
|
// Handle the different pixel depths.
|
|
|
|
switch (bpp)
|
|
{
|
|
//16 bpp.
|
|
|
|
case 16:
|
|
{
|
|
unsigned char temp;
|
|
|
|
for (unsigned long index = 0; index < imageSize; index += pixelSize)
|
|
{
|
|
temp = (imageData[index + 1] & 0x7c) << 1;
|
|
temp |= temp >> 5;
|
|
*(dst++) = temp;
|
|
|
|
temp = ((imageData[index + 1] & 0x03) << 6) | ((imageData[index] & 0xe0) >> 2);
|
|
temp |= temp >> 5;
|
|
*(dst++) = temp;
|
|
|
|
temp = (imageData[index] & 0x1f) << 3;
|
|
temp |= temp >> 5;
|
|
*(dst++) = temp;
|
|
|
|
*(alpha++) = (imageData[index + 1] & 0x80) ? 0 : 255;
|
|
}
|
|
}
|
|
break;
|
|
|
|
// 24 bpp.
|
|
|
|
case 24:
|
|
{
|
|
for (unsigned long index = 0; index < imageSize; index += pixelSize)
|
|
{
|
|
*(dst++) = imageData[index + 2];
|
|
*(dst++) = imageData[index + 1];
|
|
*(dst++) = imageData[index];
|
|
}
|
|
}
|
|
break;
|
|
|
|
// 32 bpp.
|
|
|
|
case 32:
|
|
{
|
|
for (unsigned long index = 0; index < imageSize; index += pixelSize)
|
|
{
|
|
*(dst++) = imageData[index + 2];
|
|
*(dst++) = imageData[index + 1];
|
|
*(dst++) = imageData[index];
|
|
*(alpha++) = imageData[index + 3];
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return wxTGA_INVFORMAT;
|
|
}
|
|
}
|
|
break;
|
|
|
|
// Raw grayscale.
|
|
|
|
case 3:
|
|
{
|
|
// No compression read the data directly to imageData.
|
|
|
|
stream.Read(imageData, imageSize);
|
|
|
|
// If orientation == 0, then the image is stored upside down.
|
|
// We need to store it right side up.
|
|
|
|
if (orientation == 0)
|
|
{
|
|
FlipTGA(imageData, width, height, pixelSize);
|
|
}
|
|
|
|
// Handle the different pixel depths.
|
|
|
|
switch (bpp)
|
|
{
|
|
// 8 bpp.
|
|
|
|
case 8:
|
|
{
|
|
for (unsigned long index = 0; index < imageSize; index += pixelSize)
|
|
{
|
|
*(dst++) = imageData[index];
|
|
*(dst++) = imageData[index];
|
|
*(dst++) = imageData[index];
|
|
}
|
|
}
|
|
break;
|
|
|
|
// 16 bpp.
|
|
|
|
case 16:
|
|
{
|
|
for (unsigned long index = 0; index < imageSize; index += pixelSize)
|
|
{
|
|
*(dst++) = imageData[index];
|
|
*(dst++) = imageData[index];
|
|
*(dst++) = imageData[index];
|
|
*(alpha++) = imageData[index + 1];
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return wxTGA_INVFORMAT;
|
|
}
|
|
}
|
|
break;
|
|
|
|
// RLE indexed.
|
|
|
|
case 9:
|
|
{
|
|
unsigned char r = 0;
|
|
unsigned char g = 0;
|
|
unsigned char b = 0;
|
|
|
|
// Decode the RLE data.
|
|
|
|
int rc = DecodeRLE(imageData, imageSize, pixelSize, stream);
|
|
if ( rc != wxTGA_OK )
|
|
return rc;
|
|
|
|
// If orientation == 0, then the image is stored upside down.
|
|
// We need to store it right side up.
|
|
|
|
if (orientation == 0)
|
|
{
|
|
FlipTGA(imageData, width, height, pixelSize);
|
|
}
|
|
|
|
// Handle the different pixel depths.
|
|
|
|
switch (bpp)
|
|
{
|
|
// 8 bpp.
|
|
|
|
case 8:
|
|
{
|
|
for (unsigned long index = 0; index < imageSize; index += pixelSize)
|
|
{
|
|
Palette_GetRGB(palette, paletteLength,
|
|
imageData[index], &r, &g, &b);
|
|
|
|
*(dst++) = r;
|
|
*(dst++) = g;
|
|
*(dst++) = b;
|
|
}
|
|
}
|
|
break;
|
|
|
|
// 16 bpp.
|
|
|
|
case 16:
|
|
{
|
|
for (unsigned long index = 0; index < imageSize; index += pixelSize)
|
|
{
|
|
Palette_GetRGB(palette, paletteLength,
|
|
imageData[index], &r, &g, &b);
|
|
|
|
*(dst++) = r;
|
|
*(dst++) = g;
|
|
*(dst++) = b;
|
|
*(alpha++) = (imageData[index + 1] & 0x80) ? 0 : 255;
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return wxTGA_INVFORMAT;
|
|
}
|
|
}
|
|
break;
|
|
|
|
// RLE RGB.
|
|
|
|
case 10:
|
|
{
|
|
// Decode the RLE data.
|
|
|
|
int rc = DecodeRLE(imageData, imageSize, pixelSize, stream);
|
|
if ( rc != wxTGA_OK )
|
|
return rc;
|
|
|
|
// If orientation == 0, then the image is stored upside down.
|
|
// We need to store it right side up.
|
|
|
|
if (orientation == 0)
|
|
{
|
|
FlipTGA(imageData, width, height, pixelSize);
|
|
}
|
|
|
|
// Handle the different pixel depths.
|
|
|
|
switch (bpp)
|
|
{
|
|
//16 bpp.
|
|
|
|
case 16:
|
|
{
|
|
unsigned char temp;
|
|
|
|
for (unsigned long index = 0; index < imageSize; index += pixelSize)
|
|
{
|
|
temp = (imageData[index + 1] & 0x7c) << 1;
|
|
temp |= temp >> 5;
|
|
*(dst++) = temp;
|
|
|
|
temp = ((imageData[index + 1] & 0x03) << 6) | ((imageData[index] & 0xe0) >> 2);
|
|
temp |= temp >> 5;
|
|
*(dst++) = temp;
|
|
|
|
temp = (imageData[index] & 0x1f) << 3;
|
|
temp |= temp >> 5;
|
|
*(dst++) = temp;
|
|
|
|
*(alpha++) = (imageData[index + 1] & 0x80) ? 0 : 255;
|
|
}
|
|
}
|
|
break;
|
|
|
|
// 24 bpp.
|
|
|
|
case 24:
|
|
{
|
|
for (unsigned long index = 0; index < imageSize; index += pixelSize)
|
|
{
|
|
*(dst++) = imageData[index + 2];
|
|
*(dst++) = imageData[index + 1];
|
|
*(dst++) = imageData[index];
|
|
}
|
|
}
|
|
break;
|
|
|
|
// 32 bpp.
|
|
|
|
case 32:
|
|
{
|
|
for (unsigned long index = 0; index < imageSize; index += pixelSize)
|
|
{
|
|
*(dst++) = imageData[index + 2];
|
|
*(dst++) = imageData[index + 1];
|
|
*(dst++) = imageData[index];
|
|
*(alpha++) = imageData[index + 3];
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return wxTGA_INVFORMAT;
|
|
}
|
|
}
|
|
break;
|
|
|
|
// RLE grayscale.
|
|
|
|
case 11:
|
|
{
|
|
// Decode the RLE data.
|
|
|
|
int rc = DecodeRLE(imageData, imageSize, pixelSize, stream);
|
|
if ( rc != wxTGA_OK )
|
|
return rc;
|
|
|
|
// If orientation == 0, then the image is stored upside down.
|
|
// We need to store it right side up.
|
|
|
|
if (orientation == 0)
|
|
{
|
|
FlipTGA(imageData, width, height, pixelSize);
|
|
}
|
|
|
|
// Handle the different pixel depths.
|
|
|
|
switch (bpp)
|
|
{
|
|
// 8 bpp.
|
|
|
|
case 8:
|
|
{
|
|
for (unsigned long index = 0; index < imageSize; index += pixelSize)
|
|
{
|
|
*(dst++) = imageData[index];
|
|
*(dst++) = imageData[index];
|
|
*(dst++) = imageData[index];
|
|
}
|
|
}
|
|
break;
|
|
|
|
// 16 bpp.
|
|
|
|
case 16:
|
|
{
|
|
for (unsigned long index = 0; index < imageSize; index += pixelSize)
|
|
{
|
|
*(dst++) = imageData[index];
|
|
*(dst++) = imageData[index];
|
|
*(dst++) = imageData[index];
|
|
*(alpha++) = imageData[index + 1];
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return wxTGA_INVFORMAT;
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return wxTGA_INVFORMAT;
|
|
}
|
|
|
|
return wxTGA_OK;
|
|
}
|
|
|
|
static
|
|
int SaveTGA(const wxImage& image, wxOutputStream *stream)
|
|
{
|
|
bool hasAlpha = image.HasAlpha();
|
|
unsigned bytesPerPixel = 3 + (hasAlpha ? 1 : 0);
|
|
wxSize size = image.GetSize();
|
|
size_t scanlineSize = size.x * bytesPerPixel;
|
|
unsigned char *scanlineData = (unsigned char *) malloc(scanlineSize);
|
|
if (!scanlineData)
|
|
{
|
|
return wxTGA_MEMERR;
|
|
}
|
|
|
|
wxON_BLOCK_EXIT1(free, scanlineData);
|
|
|
|
// Compose and write the TGA header
|
|
unsigned char hdr[HDR_SIZE];
|
|
(void) memset(&hdr, 0, HDR_SIZE);
|
|
|
|
hdr[HDR_COLORTYPE] = wxTGA_UNMAPPED;
|
|
hdr[HDR_IMAGETYPE] = 2 /* Uncompressed truecolour */;
|
|
|
|
hdr[HDR_WIDTH] = size.x & 0xFF;
|
|
hdr[HDR_WIDTH + 1] = (size.x >> 8) & 0xFF;
|
|
|
|
hdr[HDR_HEIGHT] = size.y & 0xFF;
|
|
hdr[HDR_HEIGHT + 1] = (size.y >> 8) & 0xFF;
|
|
|
|
hdr[HDR_BPP] = hasAlpha ? 32 : 24;
|
|
hdr[HDR_ORIENTATION] = 1 << 5; // set bit to indicate top-down order
|
|
if (hasAlpha)
|
|
{
|
|
hdr[HDR_ORIENTATION] |= 8; // number of alpha bits
|
|
}
|
|
|
|
if ( !stream->Write(hdr, HDR_SIZE) )
|
|
{
|
|
return wxTGA_IOERR;
|
|
}
|
|
|
|
|
|
// Write image data, converting RGB to BGR and adding alpha if applicable
|
|
|
|
unsigned char *src = image.GetData();
|
|
unsigned char *alpha = image.GetAlpha();
|
|
for (int y = 0; y < size.y; ++y)
|
|
{
|
|
unsigned char *dst = scanlineData;
|
|
for (int x = 0; x < size.x; ++x)
|
|
{
|
|
dst[0] = src[2];
|
|
dst[1] = src[1];
|
|
dst[2] = src[0];
|
|
if (alpha)
|
|
{
|
|
dst[3] = *(alpha++);
|
|
}
|
|
src += 3;
|
|
dst += bytesPerPixel;
|
|
}
|
|
if ( !stream->Write(scanlineData, scanlineSize) )
|
|
{
|
|
return wxTGA_IOERR;
|
|
}
|
|
}
|
|
|
|
return wxTGA_OK;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// wxTGAHandler
|
|
// ----------------------------------------------------------------------------
|
|
|
|
bool wxTGAHandler::LoadFile(wxImage* image,
|
|
wxInputStream& stream,
|
|
bool verbose,
|
|
int WXUNUSED(index))
|
|
{
|
|
if ( !CanRead(stream) )
|
|
{
|
|
if ( verbose )
|
|
{
|
|
wxLogError(wxT("TGA: this is not a TGA file."));
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
image->Destroy();
|
|
|
|
int error = ReadTGA(image, stream);
|
|
if ( error != wxTGA_OK )
|
|
{
|
|
if ( verbose )
|
|
{
|
|
switch ( error )
|
|
{
|
|
case wxTGA_INVFORMAT:
|
|
wxLogError(wxT("TGA: image format unsupported."));
|
|
break;
|
|
|
|
case wxTGA_MEMERR:
|
|
wxLogError(wxT("TGA: couldn't allocate memory."));
|
|
break;
|
|
|
|
case wxTGA_IOERR:
|
|
wxLogError(wxT("TGA: couldn't read image data."));
|
|
break;
|
|
|
|
default:
|
|
wxLogError(wxT("TGA: unknown error!"));
|
|
}
|
|
}
|
|
|
|
image->Destroy();
|
|
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool wxTGAHandler::SaveFile(wxImage* image, wxOutputStream& stream, bool verbose)
|
|
{
|
|
int error = SaveTGA(*image, &stream);
|
|
|
|
if ( error != wxTGA_OK )
|
|
{
|
|
if ( verbose )
|
|
{
|
|
switch ( error )
|
|
{
|
|
case wxTGA_MEMERR:
|
|
wxLogError(wxT("TGA: couldn't allocate memory."));
|
|
break;
|
|
|
|
case wxTGA_IOERR:
|
|
wxLogError(wxT("TGA: couldn't write image data."));
|
|
break;
|
|
|
|
default:
|
|
wxLogError(wxT("TGA: unknown error!"));
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool wxTGAHandler::DoCanRead(wxInputStream& stream)
|
|
{
|
|
// read the fixed-size TGA headers
|
|
unsigned char hdr[HDR_SIZE];
|
|
stream.Read(hdr, HDR_SIZE); // it's ok to modify the stream position here
|
|
|
|
// Check whether we can read the file or not.
|
|
|
|
short colorType = hdr[HDR_COLORTYPE];
|
|
if ( colorType != wxTGA_UNMAPPED && colorType != wxTGA_MAPPED )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
short imageType = hdr[HDR_IMAGETYPE];
|
|
if ( imageType == 0 || imageType == 32 || imageType == 33 )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
short bpp = hdr[HDR_BPP];
|
|
if ( bpp != 8 && bpp != 16 && bpp != 24 && bpp != 32 )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
#endif // wxUSE_STREAMS
|
|
|
|
#endif // wxUSE_IMAGE && wxUSE_TGA
|