From a83a9c1da143ceec7a4189501431b35f178ec78a Mon Sep 17 00:00:00 2001 From: Damjan Jovanovic Date: Fri, 21 May 2010 07:44:22 +0200 Subject: [PATCH] winemenubuilder: Generate .png even for paletted icons. --- programs/winemenubuilder/winemenubuilder.c | 146 ++++++++++++++++++++- 1 file changed, 145 insertions(+), 1 deletion(-) diff --git a/programs/winemenubuilder/winemenubuilder.c b/programs/winemenubuilder/winemenubuilder.c index 9f10fdb262b..eba21efbffb 100644 --- a/programs/winemenubuilder/winemenubuilder.c +++ b/programs/winemenubuilder/winemenubuilder.c @@ -242,7 +242,7 @@ static void user_warning_fn(png_structp png_ptr, png_const_charp warning_message WINE_WARN("PNG warning: %s\n", wine_dbgstr_an(warning_message, -1)); } -static BOOL SaveIconResAsPNG(const BITMAPINFO *pIcon, const char *png_filename, LPCWSTR commentW) +static BOOL SaveTrueColorIconResAsPNG(const BITMAPINFO *pIcon, const char *png_filename, LPCWSTR commentW) { static const char comment_key[] = "Created from"; FILE *fp; @@ -373,6 +373,150 @@ static BOOL SaveIconResAsPNG(const BITMAPINFO *pIcon, const char *png_filename, HeapFree(GetProcessHeap(), 0, comment.text); return FALSE; } + +static BOOL SavePalettedIconResAsPNG(const BITMAPINFO *pIcon, const char *png_filename, LPCWSTR commentW) +{ + static const char comment_key[] = "Created from"; + FILE *pngFile = NULL; + int i, j; + int nHeight; + int nXORWidthBytes; + int nANDWidthBytes; + BOOL b8BitColors; + int nColors; + const BYTE *pXOR; + const BYTE *pAND; + png_structp png_ptr; + png_infop info_ptr; + png_text comment; + jmp_buf jmpbuf; + unsigned char *row = NULL; + BOOL ret = FALSE; + + comment.text = NULL; + + if (!((pIcon->bmiHeader.biBitCount == 4) || (pIcon->bmiHeader.biBitCount == 8))) + { + WINE_FIXME("Unsupported color depth %d-bit\n", pIcon->bmiHeader.biBitCount); + goto done; + } + + if (!(pngFile = fopen(png_filename, "w"))) + { + WINE_TRACE("Unable to open '%s' for writing: %s\n", png_filename, strerror(errno)); + goto done; + } + + nHeight = pIcon->bmiHeader.biHeight / 2; + nXORWidthBytes = 4 * ((pIcon->bmiHeader.biWidth * pIcon->bmiHeader.biBitCount / 32) + + ((pIcon->bmiHeader.biWidth * pIcon->bmiHeader.biBitCount % 32) > 0)); + nANDWidthBytes = 4 * ((pIcon->bmiHeader.biWidth / 32) + + ((pIcon->bmiHeader.biWidth % 32) > 0)); + b8BitColors = pIcon->bmiHeader.biBitCount == 8; + nColors = pIcon->bmiHeader.biClrUsed ? pIcon->bmiHeader.biClrUsed + : 1 << pIcon->bmiHeader.biBitCount; + pXOR = (const BYTE*) pIcon + sizeof (BITMAPINFOHEADER) + (nColors * sizeof (RGBQUAD)); + pAND = pXOR + nHeight * nXORWidthBytes; + + row = HeapAlloc(GetProcessHeap(), 0, 4 * pIcon->bmiHeader.biWidth); + if (row == NULL) + { + WINE_ERR("out of memory\n"); + goto done; + } + + if (!libpng_handle && !load_libpng()) + { + WINE_WARN("Unable to load libpng\n"); + goto done; + } + + if (!(png_ptr = ppng_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL)) || + !(info_ptr = ppng_create_info_struct(png_ptr))) + goto done; + + if (setjmp(jmpbuf)) + { + /* All future errors jump here */ + goto done; + } + ppng_set_error_fn(png_ptr, &jmpbuf, user_error_fn, user_warning_fn); + + ppng_init_io(png_ptr, pngFile); + ppng_set_IHDR(png_ptr, info_ptr, pIcon->bmiHeader.biWidth, nHeight, 8, + PNG_COLOR_TYPE_RGB_ALPHA, + PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_DEFAULT, + PNG_FILTER_TYPE_DEFAULT); + + /* Set comment */ + comment.compression = PNG_TEXT_COMPRESSION_NONE; + comment.key = (png_charp)comment_key; + i = WideCharToMultiByte(CP_UNIXCP, 0, commentW, -1, NULL, 0, NULL, NULL); + comment.text = HeapAlloc(GetProcessHeap(), 0, i); + if (comment.text == NULL) + { + WINE_ERR("out of memory\n"); + goto done; + } + WideCharToMultiByte(CP_UNIXCP, 0, commentW, -1, comment.text, i, NULL, NULL); + comment.text_length = i - 1; + ppng_set_text(png_ptr, info_ptr, &comment, 1); + + ppng_write_info(png_ptr, info_ptr); + for (i = 0; i < nHeight; i++) + { + unsigned char *p = row; + for (j = 0; j < pIcon->bmiHeader.biWidth; j++) + { + if MASK(j,i) + { + *p++ = 0; + *p++ = 0; + *p++ = 0; + *p++ = 0; + } + else + { +#define COLOR(x,y) (b8BitColors ? pXOR[(x) + (nHeight - (y) - 1) * nXORWidthBytes] : (x) % 2 ? pXOR[(x) / 2 + (nHeight - (y) - 1) * nXORWidthBytes] & 0xF : (pXOR[(x) / 2 + (nHeight - (y) - 1) * nXORWidthBytes] & 0xF0) >> 4) + *p++ = pIcon->bmiColors[COLOR(j,i)].rgbRed; + *p++ = pIcon->bmiColors[COLOR(j,i)].rgbGreen; + *p++ = pIcon->bmiColors[COLOR(j,i)].rgbBlue; + *p++ = 0xFF; +#undef COLOR + } + } + ppng_write_row(png_ptr, (png_bytep)row); + } + ppng_write_end(png_ptr, info_ptr); + ret = TRUE; + +done: + ppng_destroy_write_struct(&png_ptr, &info_ptr); + if (pngFile != NULL) + fclose(pngFile); + HeapFree(GetProcessHeap(), 0, comment.text); + HeapFree(GetProcessHeap(), 0, row); + return ret; +} + +static BOOL SaveIconResAsPNG(const BITMAPINFO *pIcon, const char *png_filename, LPCWSTR commentW) +{ + switch (pIcon->bmiHeader.biBitCount) + { + case 4: + return SavePalettedIconResAsPNG(pIcon, png_filename, commentW); + case 8: + return SavePalettedIconResAsPNG(pIcon, png_filename, commentW); + case 24: + return SaveTrueColorIconResAsPNG(pIcon, png_filename, commentW); + case 32: + return SaveTrueColorIconResAsPNG(pIcon, png_filename, commentW); + default: + WINE_FIXME("unsupported bpp %d, please report", pIcon->bmiHeader.biBitCount); + return FALSE; + } +} #endif /* SONAME_LIBPNG */ static BOOL SaveIconResAsXPM(const BITMAPINFO *pIcon, const char *szXPMFileName, LPCWSTR commentW)