* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
-#include "config.h"
-
-#include <stdarg.h>
-
-#define COBJMACROS
-
-#include "windef.h"
-#include "winbase.h"
-#include "wingdi.h"
-#include "objbase.h"
-#include "wincodec.h"
-
#include "wincodecs_private.h"
-#include "wine/debug.h"
-
-WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
-
-#include "pshpack1.h"
+#include <pshpack1.h>
typedef struct {
BYTE bWidth;
WORD idCount;
} ICONHEADER;
-#include "poppack.h"
+#include <poppack.h>
typedef struct {
- const IWICBitmapDecoderVtbl *lpVtbl;
+ IWICBitmapDecoder IWICBitmapDecoder_iface;
LONG ref;
BOOL initialized;
IStream *stream;
} IcoDecoder;
typedef struct {
- const IWICBitmapFrameDecodeVtbl *lpVtbl;
+ IWICBitmapFrameDecode IWICBitmapFrameDecode_iface;
LONG ref;
- ICONDIRENTRY entry;
- IcoDecoder *parent;
+ UINT width, height;
+ double dpiX, dpiY;
BYTE *bits;
} IcoFrameDecode;
+static inline IcoDecoder *impl_from_IWICBitmapDecoder(IWICBitmapDecoder *iface)
+{
+ return CONTAINING_RECORD(iface, IcoDecoder, IWICBitmapDecoder_iface);
+}
+
+static inline IcoFrameDecode *impl_from_IWICBitmapFrameDecode(IWICBitmapFrameDecode *iface)
+{
+ return CONTAINING_RECORD(iface, IcoFrameDecode, IWICBitmapFrameDecode_iface);
+}
+
static HRESULT WINAPI IcoFrameDecode_QueryInterface(IWICBitmapFrameDecode *iface, REFIID iid,
void **ppv)
{
- IcoFrameDecode *This = (IcoFrameDecode*)iface;
+ IcoFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
if (!ppv) return E_INVALIDARG;
IsEqualIID(&IID_IWICBitmapSource, iid) ||
IsEqualIID(&IID_IWICBitmapFrameDecode, iid))
{
- *ppv = This;
+ *ppv = &This->IWICBitmapFrameDecode_iface;
}
else
{
static ULONG WINAPI IcoFrameDecode_AddRef(IWICBitmapFrameDecode *iface)
{
- IcoFrameDecode *This = (IcoFrameDecode*)iface;
+ IcoFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
ULONG ref = InterlockedIncrement(&This->ref);
TRACE("(%p) refcount=%u\n", iface, ref);
static ULONG WINAPI IcoFrameDecode_Release(IWICBitmapFrameDecode *iface)
{
- IcoFrameDecode *This = (IcoFrameDecode*)iface;
+ IcoFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
ULONG ref = InterlockedDecrement(&This->ref);
TRACE("(%p) refcount=%u\n", iface, ref);
if (ref == 0)
{
- IUnknown_Release((IUnknown*)This->parent);
HeapFree(GetProcessHeap(), 0, This->bits);
HeapFree(GetProcessHeap(), 0, This);
}
static HRESULT WINAPI IcoFrameDecode_GetSize(IWICBitmapFrameDecode *iface,
UINT *puiWidth, UINT *puiHeight)
{
- IcoFrameDecode *This = (IcoFrameDecode*)iface;
+ IcoFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
- *puiWidth = This->entry.bWidth ? This->entry.bWidth : 256;
- *puiHeight = This->entry.bHeight ? This->entry.bHeight : 256;
+ *puiWidth = This->width;
+ *puiHeight = This->height;
TRACE("(%p) -> (%i,%i)\n", iface, *puiWidth, *puiHeight);
static HRESULT WINAPI IcoFrameDecode_GetResolution(IWICBitmapFrameDecode *iface,
double *pDpiX, double *pDpiY)
{
- FIXME("(%p,%p,%p): stub\n", iface, pDpiX, pDpiY);
- return E_NOTIMPL;
+ IcoFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
+
+ *pDpiX = This->dpiX;
+ *pDpiY = This->dpiY;
+
+ TRACE("(%p) -> (%f,%f)\n", iface, *pDpiX, *pDpiY);
+
+ return S_OK;
}
static HRESULT WINAPI IcoFrameDecode_CopyPalette(IWICBitmapFrameDecode *iface,
return WINCODEC_ERR_PALETTEUNAVAILABLE;
}
-static inline void pixel_set_trans(DWORD* pixel, BOOL transparent)
+static HRESULT WINAPI IcoFrameDecode_CopyPixels(IWICBitmapFrameDecode *iface,
+ const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer)
{
- if (transparent) *pixel = 0;
- else *pixel |= 0xff000000;
+ IcoFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
+ TRACE("(%p,%p,%u,%u,%p)\n", iface, prc, cbStride, cbBufferSize, pbBuffer);
+
+ return copy_pixels(32, This->bits, This->width, This->height, This->width * 4,
+ prc, cbStride, cbBufferSize, pbBuffer);
}
-static HRESULT IcoFrameDecode_ReadPixels(IcoFrameDecode *This)
+static HRESULT WINAPI IcoFrameDecode_GetMetadataQueryReader(IWICBitmapFrameDecode *iface,
+ IWICMetadataQueryReader **ppIMetadataQueryReader)
{
- BITMAPINFOHEADER bih;
- DWORD colors[256];
- UINT colorcount=0;
- LARGE_INTEGER seek;
- ULONG bytesread;
- HRESULT hr;
- BYTE *tempdata = NULL;
- BYTE *bits = NULL;
- UINT bitsStride;
- UINT bitsSize;
- UINT width, height;
-
- width = This->entry.bWidth ? This->entry.bWidth : 256;
- height = This->entry.bHeight ? This->entry.bHeight : 256;
-
- /* read the BITMAPINFOHEADER */
- seek.QuadPart = This->entry.dwDIBOffset;
- hr = IStream_Seek(This->parent->stream, seek, STREAM_SEEK_SET, NULL);
- if (FAILED(hr)) goto fail;
+ TRACE("(%p,%p)\n", iface, ppIMetadataQueryReader);
+ return WINCODEC_ERR_UNSUPPORTEDOPERATION;
+}
- hr = IStream_Read(This->parent->stream, &bih, sizeof(BITMAPINFOHEADER), &bytesread);
- if (FAILED(hr) || bytesread != sizeof(BITMAPINFOHEADER)) goto fail;
+static HRESULT WINAPI IcoFrameDecode_GetColorContexts(IWICBitmapFrameDecode *iface,
+ UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount)
+{
+ TRACE("(%p,%u,%p,%p)\n", iface, cCount, ppIColorContexts, pcActualCount);
+ return WINCODEC_ERR_UNSUPPORTEDOPERATION;
+}
- if (bih.biBitCount <= 8)
- {
- /* read the palette */
- colorcount = bih.biClrUsed ? bih.biClrUsed : 1 << bih.biBitCount;
+static HRESULT WINAPI IcoFrameDecode_GetThumbnail(IWICBitmapFrameDecode *iface,
+ IWICBitmapSource **ppIThumbnail)
+{
+ TRACE("(%p,%p)\n", iface, ppIThumbnail);
+ return IWICBitmapFrameDecode_QueryInterface(iface, &IID_IWICBitmapSource, (void **)ppIThumbnail);
+}
- hr = IStream_Read(This->parent->stream, colors, sizeof(RGBQUAD)*colorcount, &bytesread);
- if (FAILED(hr) || bytesread != sizeof(RGBQUAD)*colorcount) goto fail;
- }
+static const IWICBitmapFrameDecodeVtbl IcoFrameDecode_Vtbl = {
+ IcoFrameDecode_QueryInterface,
+ IcoFrameDecode_AddRef,
+ IcoFrameDecode_Release,
+ IcoFrameDecode_GetSize,
+ IcoFrameDecode_GetPixelFormat,
+ IcoFrameDecode_GetResolution,
+ IcoFrameDecode_CopyPalette,
+ IcoFrameDecode_CopyPixels,
+ IcoFrameDecode_GetMetadataQueryReader,
+ IcoFrameDecode_GetColorContexts,
+ IcoFrameDecode_GetThumbnail
+};
- bitsStride = width * 4;
- bitsSize = bitsStride * height;
+static inline void pixel_set_trans(DWORD* pixel, BOOL transparent)
+{
+ if (transparent) *pixel = 0;
+ else *pixel |= 0xff000000;
+}
- /* read the XOR data */
- switch (bih.biBitCount)
- {
- case 1:
+static HRESULT ReadIcoDib(IStream *stream, IcoFrameDecode *result)
+{
+ HRESULT hr;
+ BmpDecoder *bmp_decoder;
+ IWICBitmapDecoder *decoder;
+ IWICBitmapFrameDecode *framedecode;
+ WICPixelFormatGUID pixelformat;
+ IWICBitmapSource *source;
+ BOOL has_alpha=FALSE; /* if TRUE, alpha data might be in the image data */
+ WICRect rc;
+
+ hr = IcoDibDecoder_CreateInstance(&bmp_decoder);
+ if (SUCCEEDED(hr))
{
- UINT xorBytesPerRow = (width+31)/32*4;
- UINT xorBytes = xorBytesPerRow * height;
- INT xorStride;
- BYTE *xorRow;
- BYTE *bitsRow;
- UINT x, y;
-
- tempdata = HeapAlloc(GetProcessHeap(), 0, xorBytes);
- if (!tempdata)
- {
- hr = E_OUTOFMEMORY;
- goto fail;
- }
+ BmpDecoder_GetWICDecoder(bmp_decoder, &decoder);
+ hr = IWICBitmapDecoder_Initialize(decoder, stream, WICDecodeMetadataCacheOnLoad);
- hr = IStream_Read(This->parent->stream, tempdata, xorBytes, &bytesread);
- if (FAILED(hr) || bytesread != xorBytes) goto fail;
+ if (SUCCEEDED(hr))
+ hr = IWICBitmapDecoder_GetFrame(decoder, 0, &framedecode);
- if (bih.biHeight > 0) /* bottom-up DIB */
- {
- xorStride = -xorBytesPerRow;
- xorRow = tempdata + (height-1)*xorBytesPerRow;
- }
- else /* top-down DIB */
+ if (SUCCEEDED(hr))
{
- xorStride = xorBytesPerRow;
- xorRow = tempdata;
- }
+ hr = IWICBitmapFrameDecode_GetSize(framedecode, &result->width, &result->height);
- bits = HeapAlloc(GetProcessHeap(), 0, bitsSize);
-
- /* palette-map the 1-bit data */
- bitsRow = bits;
- for (y=0; y<height; y++) {
- BYTE *xorByte=xorRow;
- DWORD *bitsPixel=(DWORD*)bitsRow;
- for (x=0; x<width; x+=8) {
- BYTE xorVal;
- xorVal=*xorByte++;
- *bitsPixel++ = colors[xorVal>>7];
- if (x+1 < width) *bitsPixel++ = colors[xorVal>>6&1];
- if (x+2 < width) *bitsPixel++ = colors[xorVal>>5&1];
- if (x+3 < width) *bitsPixel++ = colors[xorVal>>4&1];
- if (x+4 < width) *bitsPixel++ = colors[xorVal>>3&1];
- if (x+5 < width) *bitsPixel++ = colors[xorVal>>2&1];
- if (x+6 < width) *bitsPixel++ = colors[xorVal>>1&1];
- if (x+7 < width) *bitsPixel++ = colors[xorVal&1];
+ if (SUCCEEDED(hr))
+ {
+ result->bits = HeapAlloc(GetProcessHeap(), 0, result->width * result->height * 4);
+ if (!result->bits) hr = E_OUTOFMEMORY;
}
- xorRow += xorStride;
- bitsRow += bitsStride;
- }
- HeapFree(GetProcessHeap(), 0, tempdata);
- break;
- }
- case 4:
- {
- UINT xorBytesPerRow = (width+7)/8*4;
- UINT xorBytes = xorBytesPerRow * height;
- INT xorStride;
- BYTE *xorRow;
- BYTE *bitsRow;
- UINT x, y;
-
- tempdata = HeapAlloc(GetProcessHeap(), 0, xorBytes);
- if (!tempdata)
- {
- hr = E_OUTOFMEMORY;
- goto fail;
- }
-
- hr = IStream_Read(This->parent->stream, tempdata, xorBytes, &bytesread);
- if (FAILED(hr) || bytesread != xorBytes) goto fail;
-
- if (bih.biHeight > 0) /* bottom-up DIB */
- {
- xorStride = -xorBytesPerRow;
- xorRow = tempdata + (height-1)*xorBytesPerRow;
- }
- else /* top-down DIB */
- {
- xorStride = xorBytesPerRow;
- xorRow = tempdata;
- }
+ if (SUCCEEDED(hr))
+ hr = IWICBitmapFrameDecode_GetPixelFormat(framedecode, &pixelformat);
- bits = HeapAlloc(GetProcessHeap(), 0, bitsSize);
-
- /* palette-map the 4-bit data */
- bitsRow = bits;
- for (y=0; y<height; y++) {
- BYTE *xorByte=xorRow;
- DWORD *bitsPixel=(DWORD*)bitsRow;
- for (x=0; x<width; x+=2) {
- BYTE xorVal;
- xorVal=*xorByte++;
- *bitsPixel++ = colors[xorVal>>4];
- if (x+1 < width) *bitsPixel++ = colors[xorVal&0xf];
+ if (IsEqualGUID(&pixelformat, &GUID_WICPixelFormat32bppBGR) ||
+ IsEqualGUID(&pixelformat, &GUID_WICPixelFormat32bppBGRA))
+ {
+ source = (IWICBitmapSource*)framedecode;
+ IWICBitmapSource_AddRef(source);
+ has_alpha = TRUE;
+ }
+ else
+ {
+ hr = WICConvertBitmapSource(&GUID_WICPixelFormat32bppBGRA,
+ (IWICBitmapSource*)framedecode, &source);
+ has_alpha = FALSE;
}
- xorRow += xorStride;
- bitsRow += bitsStride;
- }
-
- HeapFree(GetProcessHeap(), 0, tempdata);
- break;
- }
- case 8:
- {
- UINT xorBytesPerRow = (width+3)/4*4;
- UINT xorBytes = xorBytesPerRow * height;
- INT xorStride;
- BYTE *xorRow;
- BYTE *bitsRow;
- UINT x, y;
-
- tempdata = HeapAlloc(GetProcessHeap(), 0, xorBytes);
- if (!tempdata)
- {
- hr = E_OUTOFMEMORY;
- goto fail;
- }
-
- hr = IStream_Read(This->parent->stream, tempdata, xorBytes, &bytesread);
- if (FAILED(hr) || bytesread != xorBytes) goto fail;
-
- if (bih.biHeight > 0) /* bottom-up DIB */
- {
- xorStride = -xorBytesPerRow;
- xorRow = tempdata + (height-1)*xorBytesPerRow;
- }
- else /* top-down DIB */
- {
- xorStride = xorBytesPerRow;
- xorRow = tempdata;
- }
-
- bits = HeapAlloc(GetProcessHeap(), 0, bitsSize);
-
- /* palette-map the 8-bit data */
- bitsRow = bits;
- for (y=0; y<height; y++) {
- BYTE *xorByte=xorRow;
- DWORD *bitsPixel=(DWORD*)bitsRow;
- for (x=0; x<width; x++)
- *bitsPixel++ = colors[*xorByte++];
- xorRow += xorStride;
- bitsRow += bitsStride;
- }
-
- HeapFree(GetProcessHeap(), 0, tempdata);
- break;
- }
- case 24:
- {
- UINT xorBytesPerRow = (width*3+3)/4*4;
- UINT xorBytes = xorBytesPerRow * height;
- INT xorStride;
- BYTE *xorRow;
- BYTE *bitsRow;
- UINT x, y;
-
- tempdata = HeapAlloc(GetProcessHeap(), 0, xorBytes);
- if (!tempdata)
- {
- hr = E_OUTOFMEMORY;
- goto fail;
- }
-
- hr = IStream_Read(This->parent->stream, tempdata, xorBytes, &bytesread);
- if (FAILED(hr) || bytesread != xorBytes) goto fail;
-
- if (bih.biHeight > 0) /* bottom-up DIB */
- {
- xorStride = -xorBytesPerRow;
- xorRow = tempdata + (height-1)*xorBytesPerRow;
- }
- else /* top-down DIB */
- {
- xorStride = xorBytesPerRow;
- xorRow = tempdata;
- }
-
- bits = HeapAlloc(GetProcessHeap(), 0, bitsSize);
- /* copy BGR->BGRA */
- bitsRow = bits;
- for (y=0; y<height; y++) {
- BYTE *xorByte=xorRow;
- BYTE *bitsByte=bitsRow;
- for (x=0; x<width; x++)
+ if (SUCCEEDED(hr))
{
- *bitsByte++ = *xorByte++; /* blue */
- *bitsByte++ = *xorByte++; /* green */
- *bitsByte++ = *xorByte++; /* red */
- bitsByte++; /* alpha */
+ rc.X = 0;
+ rc.Y = 0;
+ rc.Width = result->width;
+ rc.Height = result->height;
+ hr = IWICBitmapSource_CopyPixels(source, &rc, result->width * 4,
+ result->width * result->height * 4, result->bits);
+
+ IWICBitmapSource_Release(source);
}
- xorRow += xorStride;
- bitsRow += bitsStride;
- }
- HeapFree(GetProcessHeap(), 0, tempdata);
- break;
- }
- case 32:
- {
- UINT xorBytesPerRow = width*4;
- UINT xorBytes = xorBytesPerRow * height;
+ if (SUCCEEDED(hr))
+ hr = IWICBitmapFrameDecode_GetResolution(framedecode, &result->dpiX, &result->dpiY);
- bits = HeapAlloc(GetProcessHeap(), 0, xorBytes);
- if (!bits)
- {
- hr = E_OUTOFMEMORY;
- goto fail;
+ IWICBitmapFrameDecode_Release(framedecode);
}
- if (bih.biHeight > 0) /* bottom-up DIB */
+ if (SUCCEEDED(hr) && has_alpha)
{
- /* read the rows backwards so we get a top-down DIB */
+ /* If the alpha channel is fully transparent, we should ignore it. */
+ int nonzero_alpha = 0;
UINT i;
- BYTE *xorRow = bits + xorBytesPerRow * (height-1);
- for (i=0; i<height; i++)
+ for (i=0; i<(result->height*result->width); i++)
{
- hr = IStream_Read(This->parent->stream, xorRow, xorBytesPerRow, &bytesread);
- if (FAILED(hr) || bytesread != xorBytesPerRow) goto fail;
- xorRow -= xorBytesPerRow;
+ if (result->bits[i*4+3] != 0)
+ {
+ nonzero_alpha = 1;
+ break;
+ }
}
- }
- else /* top-down DIB */
- {
- hr = IStream_Read(This->parent->stream, bits, xorBytes, &bytesread);
- if (FAILED(hr) || bytesread != xorBytes) goto fail;
- }
- break;
- }
- default:
- FIXME("unsupported bitcount: %u\n", bih.biBitCount);
- goto fail;
- }
- if (bih.biBitCount < 32)
- {
- /* set alpha data based on the AND mask */
- UINT andBytesPerRow = (width+31)/32*4;
- UINT andBytes = andBytesPerRow * height;
- INT andStride;
- BYTE *andRow;
- BYTE *bitsRow;
- UINT x, y;
-
- tempdata = HeapAlloc(GetProcessHeap(), 0, andBytes);
- if (!tempdata)
- {
- hr = E_OUTOFMEMORY;
- goto fail;
- }
-
- hr = IStream_Read(This->parent->stream, tempdata, andBytes, &bytesread);
- if (FAILED(hr) || bytesread != andBytes) goto fail;
+ if (!nonzero_alpha)
+ {
+ for (i=0; i<(result->height*result->width); i++)
+ result->bits[i*4+3] = 0xff;
- if (bih.biHeight > 0) /* bottom-up DIB */
- {
- andStride = -andBytesPerRow;
- andRow = tempdata + (height-1)*andBytesPerRow;
- }
- else /* top-down DIB */
- {
- andStride = andBytesPerRow;
- andRow = tempdata;
+ has_alpha = FALSE;
+ }
}
- bitsRow = bits;
- for (y=0; y<height; y++) {
- BYTE *andByte=andRow;
- DWORD *bitsPixel=(DWORD*)bitsRow;
- for (x=0; x<width; x+=8) {
- BYTE andVal=*andByte++;
- pixel_set_trans(bitsPixel++, andVal>>7&1);
- if (x+1 < width) pixel_set_trans(bitsPixel++, andVal>>6&1);
- if (x+2 < width) pixel_set_trans(bitsPixel++, andVal>>5&1);
- if (x+3 < width) pixel_set_trans(bitsPixel++, andVal>>4&1);
- if (x+4 < width) pixel_set_trans(bitsPixel++, andVal>>3&1);
- if (x+5 < width) pixel_set_trans(bitsPixel++, andVal>>2&1);
- if (x+6 < width) pixel_set_trans(bitsPixel++, andVal>>1&1);
- if (x+7 < width) pixel_set_trans(bitsPixel++, andVal&1);
+ if (SUCCEEDED(hr) && !has_alpha)
+ {
+ /* set alpha data based on the AND mask */
+ UINT andBytesPerRow = (result->width+31)/32*4;
+ UINT andBytes = andBytesPerRow * result->height;
+ INT andStride;
+ BYTE *tempdata=NULL;
+ BYTE *andRow;
+ BYTE *bitsRow;
+ UINT bitsStride = result->width * 4;
+ UINT x, y;
+ ULONG offset;
+ ULONG bytesread;
+ LARGE_INTEGER seek;
+ int topdown;
+
+ BmpDecoder_FindIconMask(bmp_decoder, &offset, &topdown);
+
+ if (offset)
+ {
+ seek.QuadPart = offset;
+
+ hr = IStream_Seek(stream, seek, STREAM_SEEK_SET, 0);
+
+ if (SUCCEEDED(hr))
+ {
+ tempdata = HeapAlloc(GetProcessHeap(), 0, andBytes);
+ if (!tempdata) hr = E_OUTOFMEMORY;
+ }
+
+ if (SUCCEEDED(hr))
+ hr = IStream_Read(stream, tempdata, andBytes, &bytesread);
+
+ if (SUCCEEDED(hr) && bytesread == andBytes)
+ {
+ if (topdown)
+ {
+ andStride = andBytesPerRow;
+ andRow = tempdata;
+ }
+ else
+ {
+ andStride = -andBytesPerRow;
+ andRow = tempdata + (result->height-1)*andBytesPerRow;
+ }
+
+ bitsRow = result->bits;
+ for (y=0; y<result->height; y++) {
+ BYTE *andByte=andRow;
+ DWORD *bitsPixel=(DWORD*)bitsRow;
+ for (x=0; x<result->width; x+=8) {
+ BYTE andVal=*andByte++;
+ pixel_set_trans(bitsPixel++, andVal>>7&1);
+ if (x+1 < result->width) pixel_set_trans(bitsPixel++, andVal>>6&1);
+ if (x+2 < result->width) pixel_set_trans(bitsPixel++, andVal>>5&1);
+ if (x+3 < result->width) pixel_set_trans(bitsPixel++, andVal>>4&1);
+ if (x+4 < result->width) pixel_set_trans(bitsPixel++, andVal>>3&1);
+ if (x+5 < result->width) pixel_set_trans(bitsPixel++, andVal>>2&1);
+ if (x+6 < result->width) pixel_set_trans(bitsPixel++, andVal>>1&1);
+ if (x+7 < result->width) pixel_set_trans(bitsPixel++, andVal&1);
+ }
+ andRow += andStride;
+ bitsRow += bitsStride;
+ }
+ }
+
+ HeapFree(GetProcessHeap(), 0, tempdata);
}
- andRow += andStride;
- bitsRow += bitsStride;
}
- HeapFree(GetProcessHeap(), 0, tempdata);
+ IWICBitmapDecoder_Release(decoder);
}
- This->bits = bits;
-
- return S_OK;
-
-fail:
- HeapFree(GetProcessHeap(), 0, tempdata);
- HeapFree(GetProcessHeap(), 0, bits);
- if (SUCCEEDED(hr)) hr = E_FAIL;
- TRACE("<-- %x\n", hr);
return hr;
}
-static HRESULT WINAPI IcoFrameDecode_CopyPixels(IWICBitmapFrameDecode *iface,
- const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer)
+static HRESULT ReadIcoPng(IStream *stream, IcoFrameDecode *result)
{
- IcoFrameDecode *This = (IcoFrameDecode*)iface;
- HRESULT hr=S_OK;
- UINT width, height, stride;
- TRACE("(%p,%p,%u,%u,%p)\n", iface, prc, cbStride, cbBufferSize, pbBuffer);
+ IWICBitmapDecoder *decoder = NULL;
+ IWICBitmapFrameDecode *sourceFrame = NULL;
+ IWICBitmapSource *sourceBitmap = NULL;
+ WICRect rect;
+ HRESULT hr;
- EnterCriticalSection(&This->parent->lock);
- if (!This->bits)
+ hr = PngDecoder_CreateInstance(&IID_IWICBitmapDecoder, (void**)&decoder);
+ if (FAILED(hr))
+ goto end;
+ hr = IWICBitmapDecoder_Initialize(decoder, stream, WICDecodeMetadataCacheOnLoad);
+ 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;
+ hr = IWICBitmapFrameDecode_GetSize(sourceFrame, &result->width, &result->height);
+ if (FAILED(hr))
+ goto end;
+ hr = IWICBitmapFrameDecode_GetResolution(sourceFrame, &result->dpiX, &result->dpiY);
+ if (FAILED(hr))
+ goto end;
+ result->bits = HeapAlloc(GetProcessHeap(), 0, 4 * result->width * result->height);
+ if (result->bits == NULL)
{
- hr = IcoFrameDecode_ReadPixels(This);
+ hr = E_OUTOFMEMORY;
+ goto end;
}
- LeaveCriticalSection(&This->parent->lock);
- if (FAILED(hr)) return hr;
+ rect.X = 0;
+ rect.Y = 0;
+ rect.Width = result->width;
+ rect.Height = result->height;
+ hr = IWICBitmapSource_CopyPixels(sourceBitmap, &rect, 4*result->width,
+ 4*result->width*result->height, result->bits);
- width = This->entry.bWidth ? This->entry.bWidth : 256;
- height = This->entry.bHeight ? This->entry.bHeight : 256;
- stride = width * 4;
-
- return copy_pixels(32, This->bits, width, height, stride,
- prc, cbStride, cbBufferSize, pbBuffer);
-}
-
-static HRESULT WINAPI IcoFrameDecode_GetMetadataQueryReader(IWICBitmapFrameDecode *iface,
- IWICMetadataQueryReader **ppIMetadataQueryReader)
-{
- TRACE("(%p,%p)\n", iface, ppIMetadataQueryReader);
- return WINCODEC_ERR_UNSUPPORTEDOPERATION;
-}
-
-static HRESULT WINAPI IcoFrameDecode_GetColorContexts(IWICBitmapFrameDecode *iface,
- UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount)
-{
- TRACE("(%p,%u,%p,%p)\n", iface, cCount, ppIColorContexts, pcActualCount);
- return WINCODEC_ERR_UNSUPPORTEDOPERATION;
-}
-
-static HRESULT WINAPI IcoFrameDecode_GetThumbnail(IWICBitmapFrameDecode *iface,
- IWICBitmapSource **ppIThumbnail)
-{
- TRACE("(%p,%p)\n", iface, ppIThumbnail);
- return WINCODEC_ERR_CODECNOTHUMBNAIL;
+end:
+ if (decoder != NULL)
+ IWICBitmapDecoder_Release(decoder);
+ if (sourceFrame != NULL)
+ IWICBitmapFrameDecode_Release(sourceFrame);
+ if (sourceBitmap != NULL)
+ IWICBitmapSource_Release(sourceBitmap);
+ return hr;
}
-static const IWICBitmapFrameDecodeVtbl IcoFrameDecode_Vtbl = {
- IcoFrameDecode_QueryInterface,
- IcoFrameDecode_AddRef,
- IcoFrameDecode_Release,
- IcoFrameDecode_GetSize,
- IcoFrameDecode_GetPixelFormat,
- IcoFrameDecode_GetResolution,
- IcoFrameDecode_CopyPalette,
- IcoFrameDecode_CopyPixels,
- IcoFrameDecode_GetMetadataQueryReader,
- IcoFrameDecode_GetColorContexts,
- IcoFrameDecode_GetThumbnail
-};
-
static HRESULT WINAPI IcoDecoder_QueryInterface(IWICBitmapDecoder *iface, REFIID iid,
void **ppv)
{
- IcoDecoder *This = (IcoDecoder*)iface;
+ IcoDecoder *This = impl_from_IWICBitmapDecoder(iface);
TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
if (!ppv) return E_INVALIDARG;
- if (IsEqualIID(&IID_IUnknown, iid) || IsEqualIID(&IID_IWICBitmapDecoder, iid))
+ if (IsEqualIID(&IID_IUnknown, iid) ||
+ IsEqualIID(&IID_IWICBitmapDecoder, iid))
{
- *ppv = This;
+ *ppv = &This->IWICBitmapDecoder_iface;
}
else
{
static ULONG WINAPI IcoDecoder_AddRef(IWICBitmapDecoder *iface)
{
- IcoDecoder *This = (IcoDecoder*)iface;
+ IcoDecoder *This = impl_from_IWICBitmapDecoder(iface);
ULONG ref = InterlockedIncrement(&This->ref);
TRACE("(%p) refcount=%u\n", iface, ref);
static ULONG WINAPI IcoDecoder_Release(IWICBitmapDecoder *iface)
{
- IcoDecoder *This = (IcoDecoder*)iface;
+ IcoDecoder *This = impl_from_IWICBitmapDecoder(iface);
ULONG ref = InterlockedDecrement(&This->ref);
TRACE("(%p) refcount=%u\n", iface, ref);
return ref;
}
-static HRESULT WINAPI IcoDecoder_QueryCapability(IWICBitmapDecoder *iface, IStream *pIStream,
- DWORD *pdwCapability)
+static HRESULT WINAPI IcoDecoder_QueryCapability(IWICBitmapDecoder *iface, IStream *stream,
+ DWORD *capability)
{
- FIXME("(%p,%p,%p): stub\n", iface, pIStream, pdwCapability);
- return E_NOTIMPL;
+ HRESULT hr;
+
+ TRACE("(%p,%p,%p)\n", iface, stream, capability);
+
+ if (!stream || !capability) return E_INVALIDARG;
+
+ hr = IWICBitmapDecoder_Initialize(iface, stream, WICDecodeMetadataCacheOnDemand);
+ if (hr != S_OK) return hr;
+
+ *capability = WICBitmapDecoderCapabilityCanDecodeAllImages;
+ return S_OK;
}
static HRESULT WINAPI IcoDecoder_Initialize(IWICBitmapDecoder *iface, IStream *pIStream,
WICDecodeOptions cacheOptions)
{
- IcoDecoder *This = (IcoDecoder*)iface;
+ IcoDecoder *This = impl_from_IWICBitmapDecoder(iface);
LARGE_INTEGER seek;
HRESULT hr;
ULONG bytesread;
static HRESULT WINAPI IcoDecoder_GetContainerFormat(IWICBitmapDecoder *iface,
GUID *pguidContainerFormat)
{
- FIXME("(%p,%p): stub\n", iface, pguidContainerFormat);
- return E_NOTIMPL;
+ memcpy(pguidContainerFormat, &GUID_ContainerFormatIco, sizeof(GUID));
+ return S_OK;
}
static HRESULT WINAPI IcoDecoder_GetDecoderInfo(IWICBitmapDecoder *iface,
IWICBitmapDecoderInfo **ppIDecoderInfo)
{
- FIXME("(%p,%p): stub\n", iface, ppIDecoderInfo);
- return E_NOTIMPL;
+ HRESULT hr;
+ IWICComponentInfo *compinfo;
+
+ TRACE("(%p,%p)\n", iface, ppIDecoderInfo);
+
+ hr = CreateComponentInfo(&CLSID_WICIcoDecoder, &compinfo);
+ if (FAILED(hr)) return hr;
+
+ hr = IWICComponentInfo_QueryInterface(compinfo, &IID_IWICBitmapDecoderInfo,
+ (void**)ppIDecoderInfo);
+
+ IWICComponentInfo_Release(compinfo);
+
+ return hr;
}
static HRESULT WINAPI IcoDecoder_CopyPalette(IWICBitmapDecoder *iface,
static HRESULT WINAPI IcoDecoder_GetFrameCount(IWICBitmapDecoder *iface,
UINT *pCount)
{
- IcoDecoder *This = (IcoDecoder*)iface;
- TRACE("(%p,%p)\n", iface, pCount);
+ IcoDecoder *This = impl_from_IWICBitmapDecoder(iface);
- if (!This->initialized) return WINCODEC_ERR_NOTINITIALIZED;
+ if (!pCount) return E_INVALIDARG;
- *pCount = This->header.idCount;
- TRACE("<-- %u\n", *pCount);
+ EnterCriticalSection(&This->lock);
+ *pCount = This->initialized ? This->header.idCount : 0;
+ LeaveCriticalSection(&This->lock);
+
+ TRACE("(%p) <-- %d\n", iface, *pCount);
return S_OK;
}
static HRESULT WINAPI IcoDecoder_GetFrame(IWICBitmapDecoder *iface,
UINT index, IWICBitmapFrameDecode **ppIBitmapFrame)
{
- IcoDecoder *This = (IcoDecoder*)iface;
+ IcoDecoder *This = impl_from_IWICBitmapDecoder(iface);
IcoFrameDecode *result=NULL;
LARGE_INTEGER seek;
+ ULARGE_INTEGER offset, length;
HRESULT hr;
ULONG bytesread;
+ ICONDIRENTRY entry;
+ IWICStream *substream=NULL;
+ DWORD magic;
TRACE("(%p,%u,%p)\n", iface, index, ppIBitmapFrame);
EnterCriticalSection(&This->lock);
if (!This->initialized)
{
- hr = WINCODEC_ERR_NOTINITIALIZED;
+ hr = WINCODEC_ERR_FRAMEMISSING;
goto fail;
}
goto fail;
}
- result->lpVtbl = &IcoFrameDecode_Vtbl;
+ result->IWICBitmapFrameDecode_iface.lpVtbl = &IcoFrameDecode_Vtbl;
result->ref = 1;
- result->parent = This;
result->bits = NULL;
/* read the icon entry */
hr = IStream_Seek(This->stream, seek, STREAM_SEEK_SET, 0);
if (FAILED(hr)) goto fail;
- hr = IStream_Read(This->stream, &result->entry, sizeof(ICONDIRENTRY), &bytesread);
+ hr = IStream_Read(This->stream, &entry, sizeof(ICONDIRENTRY), &bytesread);
if (FAILED(hr) || bytesread != sizeof(ICONDIRENTRY)) goto fail;
- IWICBitmapDecoder_AddRef(iface);
+ /* create a stream object for this icon */
+ hr = StreamImpl_Create(&substream);
+ if (FAILED(hr)) goto fail;
- *ppIBitmapFrame = (IWICBitmapFrameDecode*)result;
+ offset.QuadPart = entry.dwDIBOffset;
+ length.QuadPart = entry.dwDIBSize;
+ hr = IWICStream_InitializeFromIStreamRegion(substream, This->stream, offset, length);
+ if (FAILED(hr)) goto fail;
+
+ /* read the bitmapinfo size or magic number */
+ hr = IWICStream_Read(substream, &magic, sizeof(magic), &bytesread);
+ if (FAILED(hr) || bytesread != sizeof(magic)) goto fail;
+
+ /* forward to the appropriate decoding function based on the magic number */
+ switch (magic)
+ {
+ case sizeof(BITMAPCOREHEADER):
+ case 64: /* sizeof(BITMAPCOREHEADER2) */
+ case sizeof(BITMAPINFOHEADER):
+ case sizeof(BITMAPV4HEADER):
+ case sizeof(BITMAPV5HEADER):
+ hr = ReadIcoDib((IStream*)substream, result);
+ break;
+ case 0x474e5089:
+ hr = ReadIcoPng((IStream*)substream, result);
+ break;
+ default:
+ FIXME("Unrecognized ICO frame magic: %x\n", magic);
+ hr = E_FAIL;
+ break;
+ }
+ if (FAILED(hr)) goto fail;
+
+ *ppIBitmapFrame = &result->IWICBitmapFrameDecode_iface;
LeaveCriticalSection(&This->lock);
+ IWICStream_Release(substream);
+
return S_OK;
fail:
LeaveCriticalSection(&This->lock);
HeapFree(GetProcessHeap(), 0, result);
+ if (substream) IWICStream_Release(substream);
if (SUCCEEDED(hr)) hr = E_FAIL;
TRACE("<-- %x\n", hr);
return hr;
IcoDecoder_GetFrame
};
-HRESULT IcoDecoder_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv)
+HRESULT IcoDecoder_CreateInstance(REFIID iid, void** ppv)
{
IcoDecoder *This;
HRESULT ret;
- TRACE("(%p,%s,%p)\n", pUnkOuter, debugstr_guid(iid), ppv);
+ TRACE("(%s,%p)\n", debugstr_guid(iid), ppv);
*ppv = NULL;
- if (pUnkOuter) return CLASS_E_NOAGGREGATION;
-
This = HeapAlloc(GetProcessHeap(), 0, sizeof(IcoDecoder));
if (!This) return E_OUTOFMEMORY;
- This->lpVtbl = &IcoDecoder_Vtbl;
+ This->IWICBitmapDecoder_iface.lpVtbl = &IcoDecoder_Vtbl;
This->ref = 1;
This->stream = NULL;
This->initialized = FALSE;
InitializeCriticalSection(&This->lock);
This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": IcoDecoder.lock");
- ret = IUnknown_QueryInterface((IUnknown*)This, iid, ppv);
- IUnknown_Release((IUnknown*)This);
+ ret = IWICBitmapDecoder_QueryInterface(&This->IWICBitmapDecoder_iface, iid, ppv);
+ IWICBitmapDecoder_Release(&This->IWICBitmapDecoder_iface);
return ret;
}