windowscodecs: support ICO files with embedded PNGs
Damjan Jovanovic
damjan.jov at gmail.com
Fri Aug 27 00:30:05 CDT 2010
Changelog:
* windowscodecs: support ICO files with embedded PNGs
Closes #23708.
Damjan Jovanovic
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.winehq.org/pipermail/wine-patches/attachments/20100827/a5f830a5/attachment-0001.htm>
-------------- next part --------------
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)
{
More information about the wine-patches
mailing list