Commit 4d55359f authored by Vincent Povirk's avatar Vincent Povirk Committed by Alexandre Julliard

windowscodecs: Use the BMP decoder to decode ICO frames.

parent 870afcdd
...@@ -68,8 +68,7 @@ typedef struct { ...@@ -68,8 +68,7 @@ typedef struct {
typedef struct { typedef struct {
const IWICBitmapFrameDecodeVtbl *lpVtbl; const IWICBitmapFrameDecodeVtbl *lpVtbl;
LONG ref; LONG ref;
ICONDIRENTRY entry; UINT width, height;
IcoDecoder *parent;
BYTE *bits; BYTE *bits;
} IcoFrameDecode; } IcoFrameDecode;
...@@ -116,7 +115,6 @@ static ULONG WINAPI IcoFrameDecode_Release(IWICBitmapFrameDecode *iface) ...@@ -116,7 +115,6 @@ static ULONG WINAPI IcoFrameDecode_Release(IWICBitmapFrameDecode *iface)
if (ref == 0) if (ref == 0)
{ {
IUnknown_Release((IUnknown*)This->parent);
HeapFree(GetProcessHeap(), 0, This->bits); HeapFree(GetProcessHeap(), 0, This->bits);
HeapFree(GetProcessHeap(), 0, This); HeapFree(GetProcessHeap(), 0, This);
} }
...@@ -129,8 +127,8 @@ static HRESULT WINAPI IcoFrameDecode_GetSize(IWICBitmapFrameDecode *iface, ...@@ -129,8 +127,8 @@ static HRESULT WINAPI IcoFrameDecode_GetSize(IWICBitmapFrameDecode *iface,
{ {
IcoFrameDecode *This = (IcoFrameDecode*)iface; IcoFrameDecode *This = (IcoFrameDecode*)iface;
*puiWidth = This->entry.bWidth ? This->entry.bWidth : 256; *puiWidth = This->width;
*puiHeight = This->entry.bHeight ? This->entry.bHeight : 256; *puiHeight = This->height;
TRACE("(%p) -> (%i,%i)\n", iface, *puiWidth, *puiHeight); TRACE("(%p) -> (%i,%i)\n", iface, *puiWidth, *puiHeight);
...@@ -158,416 +156,193 @@ static HRESULT WINAPI IcoFrameDecode_CopyPalette(IWICBitmapFrameDecode *iface, ...@@ -158,416 +156,193 @@ static HRESULT WINAPI IcoFrameDecode_CopyPalette(IWICBitmapFrameDecode *iface,
return WINCODEC_ERR_PALETTEUNAVAILABLE; 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; IcoFrameDecode *This = (IcoFrameDecode*)iface;
else *pixel |= 0xff000000; 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; TRACE("(%p,%p)\n", iface, ppIMetadataQueryReader);
DWORD colors[256]; return WINCODEC_ERR_UNSUPPORTEDOPERATION;
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;
hr = IStream_Read(This->parent->stream, &bih, sizeof(BITMAPINFOHEADER), &bytesread);
if (FAILED(hr) || bytesread != sizeof(BITMAPINFOHEADER)) goto fail;
if (bih.biBitCount <= 8)
{
/* read the palette */
colorcount = bih.biClrUsed ? bih.biClrUsed : 1 << bih.biBitCount;
hr = IStream_Read(This->parent->stream, colors, sizeof(RGBQUAD)*colorcount, &bytesread); static HRESULT WINAPI IcoFrameDecode_GetColorContexts(IWICBitmapFrameDecode *iface,
if (FAILED(hr) || bytesread != sizeof(RGBQUAD)*colorcount) goto fail; UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount)
} {
TRACE("(%p,%u,%p,%p)\n", iface, cCount, ppIColorContexts, pcActualCount);
return WINCODEC_ERR_UNSUPPORTEDOPERATION;
}
bitsStride = width * 4; static HRESULT WINAPI IcoFrameDecode_GetThumbnail(IWICBitmapFrameDecode *iface,
bitsSize = bitsStride * height; IWICBitmapSource **ppIThumbnail)
{
TRACE("(%p,%p)\n", iface, ppIThumbnail);
return WINCODEC_ERR_CODECNOTHUMBNAIL;
}
/* read the XOR data */ static const IWICBitmapFrameDecodeVtbl IcoFrameDecode_Vtbl = {
switch (bih.biBitCount) IcoFrameDecode_QueryInterface,
{ IcoFrameDecode_AddRef,
case 1: IcoFrameDecode_Release,
{ IcoFrameDecode_GetSize,
UINT xorBytesPerRow = (width+31)/32*4; IcoFrameDecode_GetPixelFormat,
UINT xorBytes = xorBytesPerRow * height; IcoFrameDecode_GetResolution,
INT xorStride; IcoFrameDecode_CopyPalette,
BYTE *xorRow; IcoFrameDecode_CopyPixels,
BYTE *bitsRow; IcoFrameDecode_GetMetadataQueryReader,
UINT x, y; IcoFrameDecode_GetColorContexts,
IcoFrameDecode_GetThumbnail
};
tempdata = HeapAlloc(GetProcessHeap(), 0, xorBytes); static inline void pixel_set_trans(DWORD* pixel, BOOL transparent)
if (!tempdata) {
{ if (transparent) *pixel = 0;
hr = E_OUTOFMEMORY; else *pixel |= 0xff000000;
goto fail; }
}
hr = IStream_Read(This->parent->stream, tempdata, xorBytes, &bytesread); static HRESULT ReadIcoDib(IStream *stream, IcoFrameDecode *result)
if (FAILED(hr) || bytesread != xorBytes) goto fail; {
HRESULT hr;
IWICBitmapDecoder *decoder;
IWICBitmapFrameDecode *framedecode;
WICPixelFormatGUID pixelformat;
IWICBitmapSource *source;
int has_alpha=FALSE; /* if TRUE, alpha data might be in the image data */
WICRect rc;
if (bih.biHeight > 0) /* bottom-up DIB */ hr = IcoDibDecoder_CreateInstance(NULL, &IID_IWICBitmapDecoder, (void**)&decoder);
if (SUCCEEDED(hr))
{ {
xorStride = -xorBytesPerRow; hr = IWICBitmapDecoder_Initialize(decoder, stream, WICDecodeMetadataCacheOnLoad);
xorRow = tempdata + (height-1)*xorBytesPerRow;
}
else /* top-down DIB */
{
xorStride = xorBytesPerRow;
xorRow = tempdata;
}
bits = HeapAlloc(GetProcessHeap(), 0, bitsSize); if (SUCCEEDED(hr))
hr = IWICBitmapDecoder_GetFrame(decoder, 0, &framedecode);
/* 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];
}
xorRow += xorStride;
bitsRow += bitsStride;
}
HeapFree(GetProcessHeap(), 0, tempdata); if (SUCCEEDED(hr))
break;
}
case 4:
{ {
UINT xorBytesPerRow = (width+7)/8*4; hr = IWICBitmapFrameDecode_GetSize(framedecode, &result->width, &result->height);
UINT xorBytes = xorBytesPerRow * height;
INT xorStride;
BYTE *xorRow;
BYTE *bitsRow;
UINT x, y;
tempdata = HeapAlloc(GetProcessHeap(), 0, xorBytes); if (SUCCEEDED(hr))
if (!tempdata)
{ {
hr = E_OUTOFMEMORY; result->bits = HeapAlloc(GetProcessHeap(), 0, result->width * result->height * 4);
goto fail; if (!result->bits) hr = E_OUTOFMEMORY;
} }
hr = IStream_Read(This->parent->stream, tempdata, xorBytes, &bytesread); if (SUCCEEDED(hr))
if (FAILED(hr) || bytesread != xorBytes) goto fail; hr = IWICBitmapFrameDecode_GetPixelFormat(framedecode, &pixelformat);
if (bih.biHeight > 0) /* bottom-up DIB */ if (IsEqualGUID(&pixelformat, &GUID_WICPixelFormat32bppBGR) ||
IsEqualGUID(&pixelformat, &GUID_WICPixelFormat32bppBGRA))
{ {
xorStride = -xorBytesPerRow; source = (IWICBitmapSource*)framedecode;
xorRow = tempdata + (height-1)*xorBytesPerRow; IWICBitmapSource_AddRef(source);
has_alpha = TRUE;
} }
else /* top-down DIB */ else
{ {
xorStride = xorBytesPerRow; hr = WICConvertBitmapSource(&GUID_WICPixelFormat32bppBGRA,
xorRow = tempdata; (IWICBitmapSource*)framedecode, &source);
has_alpha = FALSE;
} }
bits = HeapAlloc(GetProcessHeap(), 0, bitsSize); if (SUCCEEDED(hr))
/* 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];
}
xorRow += xorStride;
bitsRow += bitsStride;
}
HeapFree(GetProcessHeap(), 0, tempdata);
break;
}
case 8:
{ {
UINT xorBytesPerRow = (width+3)/4*4; rc.X = 0;
UINT xorBytes = xorBytesPerRow * height; rc.Y = 0;
INT xorStride; rc.Width = result->width;
BYTE *xorRow; rc.Height = result->height;
BYTE *bitsRow; hr = IWICBitmapSource_CopyPixels(source, &rc, result->width * 4,
UINT x, y; result->width * result->height * 4, result->bits);
tempdata = HeapAlloc(GetProcessHeap(), 0, xorBytes); IWICBitmapSource_Release(source);
if (!tempdata)
{
hr = E_OUTOFMEMORY;
goto fail;
} }
hr = IStream_Read(This->parent->stream, tempdata, xorBytes, &bytesread); IWICBitmapFrameDecode_Release(framedecode);
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); if (SUCCEEDED(hr) && !has_alpha)
/* 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; /* set alpha data based on the AND mask */
UINT xorBytes = xorBytesPerRow * height; UINT andBytesPerRow = (result->width+31)/32*4;
INT xorStride; UINT andBytes = andBytesPerRow * result->height;
BYTE *xorRow; INT andStride;
BYTE *tempdata=NULL;
BYTE *andRow;
BYTE *bitsRow; BYTE *bitsRow;
UINT bitsStride = result->width * 4;
UINT x, y; UINT x, y;
ULONG offset;
ULONG bytesread;
LARGE_INTEGER seek;
int topdown;
tempdata = HeapAlloc(GetProcessHeap(), 0, xorBytes); BmpDecoder_FindIconMask(decoder, &offset, &topdown);
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++)
{
*bitsByte++ = *xorByte++; /* blue */
*bitsByte++ = *xorByte++; /* green */
*bitsByte++ = *xorByte++; /* red */
bitsByte++; /* alpha */
}
xorRow += xorStride;
bitsRow += bitsStride;
}
HeapFree(GetProcessHeap(), 0, tempdata);
break;
}
case 32:
{
UINT xorBytesPerRow = width*4;
UINT xorBytes = xorBytesPerRow * height;
bits = HeapAlloc(GetProcessHeap(), 0, xorBytes); if (offset)
if (!bits)
{ {
hr = E_OUTOFMEMORY; seek.QuadPart = offset;
goto fail;
}
if (bih.biHeight > 0) /* bottom-up DIB */ hr = IStream_Seek(stream, seek, STREAM_SEEK_SET, 0);
{
/* read the rows backwards so we get a top-down DIB */
UINT i;
BYTE *xorRow = bits + xorBytesPerRow * (height-1);
for (i=0; i<height; i++) if (SUCCEEDED(hr))
{
hr = IStream_Read(This->parent->stream, xorRow, xorBytesPerRow, &bytesread);
if (FAILED(hr) || bytesread != xorBytesPerRow) goto fail;
xorRow -= xorBytesPerRow;
}
}
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); tempdata = HeapAlloc(GetProcessHeap(), 0, andBytes);
if (!tempdata) if (!tempdata) hr = E_OUTOFMEMORY;
{
hr = E_OUTOFMEMORY;
goto fail;
} }
hr = IStream_Read(This->parent->stream, tempdata, andBytes, &bytesread); if (SUCCEEDED(hr))
if (FAILED(hr) || bytesread != andBytes) goto fail; hr = IStream_Read(stream, tempdata, andBytes, &bytesread);
if (bih.biHeight > 0) /* bottom-up DIB */ if (SUCCEEDED(hr) && bytesread == andBytes)
{ {
andStride = -andBytesPerRow; if (topdown)
andRow = tempdata + (height-1)*andBytesPerRow;
}
else /* top-down DIB */
{ {
andStride = andBytesPerRow; andStride = andBytesPerRow;
andRow = tempdata; andRow = tempdata;
} }
else
{
andStride = -andBytesPerRow;
andRow = tempdata + (result->height-1)*andBytesPerRow;
}
bitsRow = bits; bitsRow = result->bits;
for (y=0; y<height; y++) { for (y=0; y<result->height; y++) {
BYTE *andByte=andRow; BYTE *andByte=andRow;
DWORD *bitsPixel=(DWORD*)bitsRow; DWORD *bitsPixel=(DWORD*)bitsRow;
for (x=0; x<width; x+=8) { for (x=0; x<result->width; x+=8) {
BYTE andVal=*andByte++; BYTE andVal=*andByte++;
pixel_set_trans(bitsPixel++, andVal>>7&1); pixel_set_trans(bitsPixel++, andVal>>7&1);
if (x+1 < width) pixel_set_trans(bitsPixel++, andVal>>6&1); if (x+1 < result->width) pixel_set_trans(bitsPixel++, andVal>>6&1);
if (x+2 < width) pixel_set_trans(bitsPixel++, andVal>>5&1); if (x+2 < result->width) pixel_set_trans(bitsPixel++, andVal>>5&1);
if (x+3 < width) pixel_set_trans(bitsPixel++, andVal>>4&1); if (x+3 < result->width) pixel_set_trans(bitsPixel++, andVal>>4&1);
if (x+4 < width) pixel_set_trans(bitsPixel++, andVal>>3&1); if (x+4 < result->width) pixel_set_trans(bitsPixel++, andVal>>3&1);
if (x+5 < width) pixel_set_trans(bitsPixel++, andVal>>2&1); if (x+5 < result->width) pixel_set_trans(bitsPixel++, andVal>>2&1);
if (x+6 < width) pixel_set_trans(bitsPixel++, andVal>>1&1); if (x+6 < result->width) pixel_set_trans(bitsPixel++, andVal>>1&1);
if (x+7 < width) pixel_set_trans(bitsPixel++, andVal&1); if (x+7 < result->width) pixel_set_trans(bitsPixel++, andVal&1);
} }
andRow += andStride; andRow += andStride;
bitsRow += bitsStride; bitsRow += bitsStride;
} }
HeapFree(GetProcessHeap(), 0, tempdata);
} }
This->bits = bits;
return S_OK;
fail:
HeapFree(GetProcessHeap(), 0, tempdata); 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)
{
IcoFrameDecode *This = (IcoFrameDecode*)iface;
HRESULT hr=S_OK;
UINT width, height, stride;
TRACE("(%p,%p,%u,%u,%p)\n", iface, prc, cbStride, cbBufferSize, pbBuffer);
EnterCriticalSection(&This->parent->lock);
if (!This->bits)
{
hr = IcoFrameDecode_ReadPixels(This);
} }
LeaveCriticalSection(&This->parent->lock); }
if (FAILED(hr)) return hr;
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, IWICBitmapDecoder_Release(decoder);
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, return hr;
IWICBitmapSource **ppIThumbnail)
{
TRACE("(%p,%p)\n", iface, ppIThumbnail);
return WINCODEC_ERR_CODECNOTHUMBNAIL;
} }
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, static HRESULT WINAPI IcoDecoder_QueryInterface(IWICBitmapDecoder *iface, REFIID iid,
void **ppv) void **ppv)
{ {
...@@ -736,8 +511,12 @@ static HRESULT WINAPI IcoDecoder_GetFrame(IWICBitmapDecoder *iface, ...@@ -736,8 +511,12 @@ static HRESULT WINAPI IcoDecoder_GetFrame(IWICBitmapDecoder *iface,
IcoDecoder *This = (IcoDecoder*)iface; IcoDecoder *This = (IcoDecoder*)iface;
IcoFrameDecode *result=NULL; IcoFrameDecode *result=NULL;
LARGE_INTEGER seek; LARGE_INTEGER seek;
ULARGE_INTEGER offset, length;
HRESULT hr; HRESULT hr;
ULONG bytesread; ULONG bytesread;
ICONDIRENTRY entry;
IWICStream *substream=NULL;
DWORD magic;
TRACE("(%p,%u,%p)\n", iface, index, ppIBitmapFrame); TRACE("(%p,%u,%p)\n", iface, index, ppIBitmapFrame);
EnterCriticalSection(&This->lock); EnterCriticalSection(&This->lock);
...@@ -763,7 +542,6 @@ static HRESULT WINAPI IcoDecoder_GetFrame(IWICBitmapDecoder *iface, ...@@ -763,7 +542,6 @@ static HRESULT WINAPI IcoDecoder_GetFrame(IWICBitmapDecoder *iface,
result->lpVtbl = &IcoFrameDecode_Vtbl; result->lpVtbl = &IcoFrameDecode_Vtbl;
result->ref = 1; result->ref = 1;
result->parent = This;
result->bits = NULL; result->bits = NULL;
/* read the icon entry */ /* read the icon entry */
...@@ -771,10 +549,42 @@ static HRESULT WINAPI IcoDecoder_GetFrame(IWICBitmapDecoder *iface, ...@@ -771,10 +549,42 @@ static HRESULT WINAPI IcoDecoder_GetFrame(IWICBitmapDecoder *iface,
hr = IStream_Seek(This->stream, seek, STREAM_SEEK_SET, 0); hr = IStream_Seek(This->stream, seek, STREAM_SEEK_SET, 0);
if (FAILED(hr)) goto fail; 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; 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;
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:
FIXME("PNG decoding not supported\n");
hr = E_FAIL;
break;
default:
FIXME("Unrecognized ICO frame magic: %x\n", magic);
hr = E_FAIL;
break;
}
if (FAILED(hr)) goto fail;
*ppIBitmapFrame = (IWICBitmapFrameDecode*)result; *ppIBitmapFrame = (IWICBitmapFrameDecode*)result;
...@@ -785,6 +595,7 @@ static HRESULT WINAPI IcoDecoder_GetFrame(IWICBitmapDecoder *iface, ...@@ -785,6 +595,7 @@ static HRESULT WINAPI IcoDecoder_GetFrame(IWICBitmapDecoder *iface,
fail: fail:
LeaveCriticalSection(&This->lock); LeaveCriticalSection(&This->lock);
HeapFree(GetProcessHeap(), 0, result); HeapFree(GetProcessHeap(), 0, result);
if (substream) IStream_Release(substream);
if (SUCCEEDED(hr)) hr = E_FAIL; if (SUCCEEDED(hr)) hr = E_FAIL;
TRACE("<-- %x\n", hr); TRACE("<-- %x\n", hr);
return hr; return hr;
......
...@@ -136,7 +136,7 @@ static void test_bad_icondirentry_size(void) ...@@ -136,7 +136,7 @@ static void test_bad_icondirentry_size(void)
UINT width = 0, height = 0; UINT width = 0, height = 0;
hr = IWICBitmapFrameDecode_GetSize(framedecode, &width, &height); hr = IWICBitmapFrameDecode_GetSize(framedecode, &width, &height);
ok(hr == S_OK, "GetFrameSize failed, hr=%x\n", hr); ok(hr == S_OK, "GetFrameSize failed, hr=%x\n", hr);
todo_wine ok(width == 16 && height == 16, "framesize=%ux%u\n", width, height); ok(width == 16 && height == 16, "framesize=%ux%u\n", width, height);
IWICBitmapFrameDecode_Release(framedecode); IWICBitmapFrameDecode_Release(framedecode);
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment