channel with wxImage::HasAlpha. Currently the BMP, PNG, and TIFF format
handlers have full alpha channel support for loading so if you want to use
alpha you have to use one of these formats. If you initialize the image
- alpha channel yourself using wxImage::SetAlpha, you should save it in PNG
- format to avoid losing it as this is the only handler that currently
- supports saving with alpha.
+ alpha channel yourself using wxImage::SetAlpha, you should save it in
+ either PNG or TGA format to avoid losing it as these are the only handlers
+ that currently support saving with alpha.
@section image_handlers Available image handlers
- wxPCXHandler: For loading and saving (see below).
- wxPNMHandler: For loading and saving (see below).
- wxTIFFHandler: For loading (including alpha support) and saving.
- - wxTGAHandler: For loading only.
+ - wxTGAHandler: For loading and saving. Includes alpha support.
- wxIFFHandler: For loading only.
- wxXPMHandler: For loading and saving.
- wxICOHandler: For loading and saving.
}
static
-int SaveTGA(wxImage* WXUNUSED(image), wxOutputStream& WXUNUSED(stream))
+int SaveTGA(const wxImage& image, wxOutputStream *stream)
{
- wxLogError(wxT("Saving in TGA format is not implemented."));
+ 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;
}
bool wxTGAHandler::SaveFile(wxImage* image, wxOutputStream& stream, bool verbose)
{
- int error = SaveTGA(image, stream);
+ int error = SaveTGA(*image, &stream);
if ( error != wxTGA_OK )
{
{
switch ( error )
{
- case wxTGA_INVFORMAT:
- wxLogError(wxT("TGA: invalid image."));
- break;
-
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!"));
}
void CompareImage(const wxImageHandler& handler, const wxImage& expected)
{
bool testAlpha = expected.HasAlpha();
- if (testAlpha && type != wxBITMAP_TYPE_PNG)
+ wxBitmapType type = handler.GetType();
+ if (testAlpha
+ && !(type == wxBITMAP_TYPE_PNG || type == wxBITMAP_TYPE_TGA) )
{
// don't test images with alpha if this handler doesn't support alpha
return;
}
- wxBitmapType type = handler.GetType();
if (type == wxBITMAP_TYPE_JPEG /* skip lossy JPEG */
|| type == wxBITMAP_TYPE_TIF)
{
return;
}
- if ( !memOut.GetSize() )
- {
- // A handler that does not support saving can return true during
- // SaveFile, in that case the stream is empty.
- return;
- }
-
-
wxMemoryInputStream memIn(memOut);
CPPUNIT_ASSERT(memIn.IsOk());