added support for saving grey and grey-red PNG images (patch 985447)

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@32414 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin 2005-02-27 15:24:50 +00:00
parent 04d4e6846e
commit a4efa72179
3 changed files with 156 additions and 33 deletions

View File

@ -619,6 +619,22 @@ If the given option is not present, the function returns $0$. Use
\helpref{wxImage::HasOption}{wximagehasoption} is $0$ is a possibly valid value
for the option.
Options for wxPNGHandler
\twocolwidtha{5cm}%
\begin{twocollist}
\twocolitem{wxIMAGE\_OPTION\_PNG\_FORMAT}{Format for saving a PNG file.}
\twocolitem{wxIMAGE\_OPTION\_PNG\_BITDEPTH}{Bit depth for every channel (R/G/B/A).}
\end{twocollist}
Supported values for wxIMAGE\_OPTION\_PNG\_FORMAT:
\twocolwidtha{5cm}%
\begin{twocollist}
\twocolitem{wxPNG\_TYPE\_COLOUR}{Stores RGB image.}
\twocolitem{wxPNG\_TYPE\_GREY}{Stores grey image, converts from RGB.}
\twocolitem{wxPNG\_TYPE\_GREY\_RED}{Stores grey image, uses red value as grey.}
\end{twocollist}
\wxheading{See also}
\helpref{wxImage::SetOption}{wximagesetoption},\rtfsp

View File

@ -21,6 +21,17 @@
//-----------------------------------------------------------------------------
#if wxUSE_LIBPNG
#define wxIMAGE_OPTION_PNG_FORMAT wxT("PngFormat")
#define wxIMAGE_OPTION_PNG_BITDEPTH wxT("PngBitDepth")
enum
{
wxPNG_TYPE_COLOUR = 0,
wxPNG_TYPE_GREY = 2,
wxPNG_TYPE_GREY_RED = 3,
};
class WXDLLEXPORT wxPNGHandler: public wxImageHandler
{
public:

View File

@ -664,57 +664,153 @@ bool wxPNGHandler::SaveFile( wxImage *image, wxOutputStream& stream, bool verbos
// explanation why this line is mandatory
png_set_write_fn( png_ptr, &wxinfo, wx_PNG_stream_writer, NULL);
const bool usesAlpha = (image->HasAlpha() || image->HasMask() );
const int bytesPerPixel = usesAlpha ? 4 : 3;
png_set_IHDR( png_ptr, info_ptr, image->GetWidth(), image->GetHeight(), 8,
usesAlpha ? PNG_COLOR_TYPE_RGB_ALPHA : PNG_COLOR_TYPE_RGB,
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
const int iColorType = image->HasOption(wxIMAGE_OPTION_PNG_FORMAT)
? image->GetOptionInt(wxIMAGE_OPTION_PNG_FORMAT)
: wxPNG_TYPE_COLOUR;
const int iBitDepth = image->HasOption(wxIMAGE_OPTION_PNG_BITDEPTH)
? image->GetOptionInt(wxIMAGE_OPTION_PNG_BITDEPTH)
: 8;
wxASSERT_MSG( iBitDepth == 8 || iBitDepth == 16,
_T("PNG bit depth must be 8 or 16") );
bool bHasAlpha = image->HasAlpha();
bool bHasMask = image->HasMask();
bool bUseAlpha = bHasAlpha || bHasMask;
int iPngColorType;
if ( iColorType==wxPNG_TYPE_COLOUR )
{
iPngColorType = bUseAlpha ? PNG_COLOR_TYPE_RGB_ALPHA
: PNG_COLOR_TYPE_RGB;
}
else
{
iPngColorType = bUseAlpha ? PNG_COLOR_TYPE_GRAY_ALPHA
: PNG_COLOR_TYPE_GRAY;
}
png_set_IHDR( png_ptr, info_ptr, image->GetWidth(), image->GetHeight(),
iBitDepth, iPngColorType,
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE,
PNG_FILTER_TYPE_BASE);
int iElements;
png_color_8 sig_bit;
sig_bit.red = 8;
sig_bit.green = 8;
sig_bit.blue = 8;
sig_bit.alpha = 8;
if ( iPngColorType & PNG_COLOR_MASK_COLOR )
{
sig_bit.red =
sig_bit.green =
sig_bit.blue = (png_byte)iBitDepth;
iElements = 3;
}
else // grey
{
sig_bit.gray = (png_byte)iBitDepth;
iElements = 1;
}
if ( iPngColorType & PNG_COLOR_MASK_ALPHA )
{
sig_bit.alpha = (png_byte)iBitDepth;
iElements++;
}
png_set_sBIT( png_ptr, info_ptr, &sig_bit );
png_write_info( png_ptr, info_ptr );
png_set_shift( png_ptr, &sig_bit );
png_set_packing( png_ptr );
unsigned char *data = (unsigned char *)malloc( image->GetWidth()*bytesPerPixel );
if (!data)
unsigned char *
data = (unsigned char *)malloc( image->GetWidth() * iElements );
if ( !data )
{
png_destroy_write_struct( &png_ptr, (png_infopp)NULL );
return false;
}
for (int y = 0; y < image->GetHeight(); y++)
{
unsigned char *ptr = image->GetData() + (y * image->GetWidth() * 3);
for (int x = 0; x < image->GetWidth(); x++)
{
register const int index = x * bytesPerPixel;
data[index + 0] = *ptr++;
data[index + 1] = *ptr++;
data[index + 2] = *ptr++;
unsigned char *
pAlpha = (unsigned char *)(bHasAlpha ? image->GetAlpha() : NULL);
int iHeight = image->GetHeight();
int iWidth = image->GetWidth();
if (usesAlpha)
unsigned char uchMaskRed = bHasMask ? image->GetMaskRed() : 0;
unsigned char uchMaskGreen = bHasMask ? image->GetMaskGreen() : 0;
unsigned char uchMaskBlue = bHasMask ? image->GetMaskBlue() : 0;
unsigned char *pColors = image->GetData();
for (int y = 0; y != iHeight; ++y)
{
unsigned char *pData = data;
for (int x = 0; x != iWidth; x++)
{
unsigned char uchRed = *pColors++;
unsigned char uchGreen = *pColors++;
unsigned char uchBlue = *pColors++;
switch ( iColorType )
{
if ( image->HasAlpha() )
default:
wxFAIL_MSG( _T("unknown wxPNG_TYPE_XXX") );
// fall through
case wxPNG_TYPE_COLOUR:
*pData++ = uchRed;
if (iBitDepth > 8)
*pData++ = 0;
*pData++ = uchGreen;
if (iBitDepth > 8)
*pData++ = 0;
*pData++ = uchBlue;
if (iBitDepth > 8)
*pData++ = 0;
break;
case wxPNG_TYPE_GREY:
{
unsigned uiColor =
(unsigned) (76.544*(unsigned)uchRed +
150.272*(unsigned)uchGreen +
36.864*(unsigned)uchBlue);
uiColor >>= (16 - iBitDepth);
if (iBitDepth > 8)
{
*pData++ = (unsigned char)((uiColor >> 8) & 0xFF);
*pData++ = (unsigned char)(uiColor & 0xFF);
} else {
*pData++ = (unsigned char)(uiColor & 0xFF);
}
}
break;
case wxPNG_TYPE_GREY_RED:
*pData++ = uchRed;
if (iBitDepth > 8)
*pData++ = 0;
break;
}
if ( bUseAlpha )
{
unsigned char uchAlpha = 255;
if ( bHasAlpha )
uchAlpha = *pAlpha++;
if ( bHasMask )
{
data[index + 3] = image->GetAlpha(x, y);
}
else if ( (data[index + 0] != image->GetMaskRed())
|| (data[index + 1] != image->GetMaskGreen())
|| (data[index + 2] != image->GetMaskBlue()) )
{
data[index + 3] = 255;
}
else
{
data[index + 3] = 0;
if ( (uchRed == uchMaskRed)
&& (uchGreen == uchMaskGreen)
&& (uchBlue == uchMaskBlue) )
uchAlpha = 0;
}
*pData++ = uchAlpha;
if (iBitDepth > 8)
*pData++ = 0;
}
}
png_bytep row_ptr = data;
png_write_rows( png_ptr, &row_ptr, 1 );
}