[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