From 3d926ff8a9ce840252003a7acfa49a1b642f48de Mon Sep 17 00:00:00 2001 From: Dimitri Schoolwerth Date: Tue, 28 Dec 2010 22:38:04 +0000 Subject: [PATCH] Added saving support to TGA image handler. Supports saving 24-bit and 32-bit (RGB with alpha). Updated image unit test to verify the alpha channel of saved TGA images. Also removed a condition skipping a test which only was in place for TGA (formerly its saving handler would do nothing yet say saving was succesful). See also #7661. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@66485 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- docs/changes.txt | 1 + interface/wx/image.h | 8 ++--- src/common/imagtga.cpp | 75 ++++++++++++++++++++++++++++++++++++++---- tests/image/image.cpp | 13 ++------ 4 files changed, 76 insertions(+), 21 deletions(-) diff --git a/docs/changes.txt b/docs/changes.txt index b30d607c3b..41de14cffc 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -449,6 +449,7 @@ All (GUI): - Return bool, not void, from wxImage::ConvertAlphaToMask() (troelsk). - Fixed resizing columns in wxGrid when they were reordered. - Added wxImage::Rotate180() (Jeff Tupper). +- Added support for saving TGA files. GTK: diff --git a/interface/wx/image.h b/interface/wx/image.h index 703d247a1a..256a861777 100644 --- a/interface/wx/image.h +++ b/interface/wx/image.h @@ -318,9 +318,9 @@ const unsigned char wxIMAGE_ALPHA_OPAQUE = 0xff; 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 @@ -337,7 +337,7 @@ const unsigned char wxIMAGE_ALPHA_OPAQUE = 0xff; - 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. diff --git a/src/common/imagtga.cpp b/src/common/imagtga.cpp index 62080d22c1..e3b5473995 100644 --- a/src/common/imagtga.cpp +++ b/src/common/imagtga.cpp @@ -650,9 +650,70 @@ int ReadTGA(wxImage* image, wxInputStream& stream) } 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; } @@ -712,7 +773,7 @@ bool wxTGAHandler::LoadFile(wxImage* image, bool wxTGAHandler::SaveFile(wxImage* image, wxOutputStream& stream, bool verbose) { - int error = SaveTGA(image, stream); + int error = SaveTGA(*image, &stream); if ( error != wxTGA_OK ) { @@ -720,14 +781,14 @@ bool wxTGAHandler::SaveFile(wxImage* image, wxOutputStream& stream, bool verbose { 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!")); } diff --git a/tests/image/image.cpp b/tests/image/image.cpp index 2e72d8118c..c39fa8650e 100644 --- a/tests/image/image.cpp +++ b/tests/image/image.cpp @@ -874,13 +874,14 @@ static 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) { @@ -901,14 +902,6 @@ void CompareImage(const wxImageHandler& handler, const wxImage& expected) 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()); -- 2.45.2