[1/2] windowscodecs: support ICO files with embedded PNGs (try 2)

Damjan Jovanovic damjan.jov at gmail.com
Tue Sep 14 00:20:10 CDT 2010


Changelog:
* windowscodecs: support ICO files with embedded PNGs

Try 2 uses IWICStream regions instead of reading the file into memory.

Damjan Jovanovic
-------------- next part --------------
diff --git a/dlls/windowscodecs/icoformat.c b/dlls/windowscodecs/icoformat.c
index 8012b4e..3f03658 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,79 @@ static inline void pixel_set_trans(DWORD* pixel, BOOL transparent)
     else *pixel |= 0xff000000;
 }
 
+static HRESULT IcoFrameDecode_ReadPNGPixels(IcoFrameDecode *This, UINT width, UINT height)
+{
+    IWICImagingFactory *factory = NULL;
+    IWICStream *pngStream = NULL;
+    ULARGE_INTEGER offset, size;
+    IWICBitmapDecoder *decoder = NULL;
+    IWICBitmapFrameDecode *sourceFrame = NULL;
+    IWICBitmapSource *sourceBitmap = NULL;
+    BYTE *bits = NULL;
+    WICRect rect;
+    HRESULT hr;
+
+    hr = CoCreateInstance(&CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER,
+        &IID_IWICImagingFactory, (void**)&factory);
+    if (FAILED(hr))
+        goto end;
+    hr = IWICImagingFactory_CreateStream(factory, &pngStream);
+    if (FAILED(hr))
+        goto end;
+    offset.QuadPart = This->entry.dwDIBOffset;
+    size.QuadPart = This->entry.dwDIBSize;
+    hr = IWICStream_InitializeFromIStreamRegion(pngStream, This->parent->stream, offset, size);
+    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, (IStream*)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 (factory)
+        IWICImagingFactory_Release(factory);
+    if (pngStream)
+        IWICStream_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 +258,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