From: Damjan Jovanovic Subject: windowscodecs: support ICO files with embedded PNGs Message-Id: Date: Fri, 27 Aug 2010 07:30:05 +0200 Changelog: * windowscodecs: support ICO files with embedded PNGs Closes #23708. Damjan Jovanovic Changelog:
* windowscodecs: support ICO files with embedded PNGs

Closes #23708.

Damjan Jovanovic

diff --git a/dlls/windowscodecs/icoformat.c b/dlls/windowscodecs/icoformat.c index 8012b4e..c2a15ea 100644 --- a/dlls/windowscodecs/icoformat.c +++ b/dlls/windowscodecs/icoformat.c @@ -26,6 +26,7 @@ #include "winbase.h" #include "wingdi.h" #include "objbase.h" +#include "ole2.h" #include "wincodec.h" #include "wincodecs_private.h" @@ -164,8 +165,90 @@ static inline void pixel_set_trans(DWORD* pixel, BOOL transparent) else *pixel |= 0xff000000; } +static HRESULT IcoFrameDecode_ReadPNGPixels(IcoFrameDecode *This, UINT width, UINT height) +{ + IStream *pngStream = NULL; + ULONG bytesCopied = 0; + LARGE_INTEGER zero; + IWICBitmapDecoder *decoder = NULL; + IWICBitmapFrameDecode *sourceFrame = NULL; + IWICBitmapSource *sourceBitmap = NULL; + BYTE *bits = NULL; + WICRect rect; + HRESULT hr; + + hr = CreateStreamOnHGlobal(NULL, TRUE, &pngStream); + if (FAILED(hr)) + goto end; + while (bytesCopied < This->entry.dwDIBSize) + { + BYTE buffer[4096]; + ULONG bytesRead = 0; + ULONG bytesWritten = 0; + ULONG toRead = This->entry.dwDIBSize - bytesCopied; + if (toRead > sizeof(buffer)) + toRead = sizeof(buffer); + hr = IStream_Read(This->parent->stream, buffer, toRead, &bytesRead); + if (FAILED(hr)) + goto end; + hr = IStream_Write(pngStream, buffer, bytesRead, &bytesWritten); + if (SUCCEEDED(hr) && bytesWritten != bytesRead) + hr = E_FAIL; + if (FAILED(hr)) + goto end; + bytesCopied += bytesWritten; + } + zero.QuadPart = 0; + hr = IStream_Seek(pngStream, zero, STREAM_SEEK_SET, NULL); + if (FAILED(hr)) + goto end; + + hr = CoCreateInstance(&CLSID_WICPngDecoder, NULL, CLSCTX_INPROC_SERVER, + &IID_IWICBitmapDecoder, (void**)&decoder); + if (FAILED(hr)) + goto end; + hr = IWICBitmapDecoder_Initialize(decoder, pngStream, WICDecodeMetadataCacheOnDemand); + if (FAILED(hr)) + goto end; + hr = IWICBitmapDecoder_GetFrame(decoder, 0, &sourceFrame); + if (FAILED(hr)) + goto end; + hr = WICConvertBitmapSource(&GUID_WICPixelFormat32bppBGRA, (IWICBitmapSource*)sourceFrame, &sourceBitmap); + if (FAILED(hr)) + goto end; + bits = HeapAlloc(GetProcessHeap(), 0, 4*width*height); + if (bits == NULL) + { + hr = E_OUTOFMEMORY; + goto end; + } + rect.X = 0; + rect.Y = 0; + rect.Width = width; + rect.Height = height; + hr = IWICBitmapSource_CopyPixels(sourceBitmap, &rect, 4*width, 4*width*height, bits); + if (FAILED(hr)) + goto end; + +end: + if (pngStream) + IStream_Release(pngStream); + if (decoder) + IWICBitmapDecoder_Release(decoder); + if (sourceFrame) + IWICBitmapFrameDecode_Release(sourceFrame); + if (sourceBitmap) + IWICBitmapSource_Release(sourceBitmap); + if (SUCCEEDED(hr)) + This->bits = bits; + else + HeapFree(GetProcessHeap(), 0, bits); + return hr; +} + static HRESULT IcoFrameDecode_ReadPixels(IcoFrameDecode *This) { + BYTE signature[8]; BITMAPINFOHEADER bih; DWORD colors[256]; UINT colorcount=0; @@ -186,8 +269,29 @@ static HRESULT IcoFrameDecode_ReadPixels(IcoFrameDecode *This) hr = IStream_Seek(This->parent->stream, seek, STREAM_SEEK_SET, NULL); if (FAILED(hr)) goto fail; - hr = IStream_Read(This->parent->stream, &bih, sizeof(BITMAPINFOHEADER), &bytesread); - if (FAILED(hr) || bytesread != sizeof(BITMAPINFOHEADER)) goto fail; + hr = IStream_Read(This->parent->stream, signature, sizeof(signature), &bytesread); + if (FAILED(hr) || bytesread != sizeof(signature)) goto fail; + if (signature[0] == 137 && + signature[1] == 80 /* P */ && + signature[2] == 78 /* N */ && + signature[3] == 71 /* G */ && + signature[4] == 13 && + signature[5] == 10 && + signature[6] == 26 && + signature[7] == 10) + { + /* Vista-style ICO with embedded PNG + * http://social.msdn.microsoft.com/Forums/en-US/windowsgeneraldevelopmentissues/thread/2c807b02-ea85-497d-8342-a971c6a3c4a6 + */ + hr = IStream_Seek(This->parent->stream, seek, STREAM_SEEK_SET, NULL); + if (FAILED(hr)) goto fail; + return IcoFrameDecode_ReadPNGPixels(This, width, height); + } + else + memcpy(&bih, signature, sizeof(signature)); + + hr = IStream_Read(This->parent->stream, ((BYTE*)&bih) + sizeof(signature), sizeof(BITMAPINFOHEADER) - sizeof(signature), &bytesread); + if (FAILED(hr) || bytesread != sizeof(BITMAPINFOHEADER) - sizeof(signature)) goto fail; if (bih.biBitCount <= 8) {