windowscodecs: Implement CopyPixels for 8-bit ICO icons.

This commit is contained in:
Vincent Povirk 2009-08-20 11:58:49 -05:00 committed by Alexandre Julliard
parent ccc4c2d5d2
commit 1c25ee8ce7
1 changed files with 183 additions and 2 deletions

View File

@ -24,6 +24,7 @@
#include "windef.h"
#include "winbase.h"
#include "wingdi.h"
#include "objbase.h"
#include "wincodec.h"
@ -68,6 +69,7 @@ typedef struct {
LONG ref;
ICONDIRENTRY entry;
IcoDecoder *parent;
BYTE *bits;
} IcoFrameDecode;
static HRESULT WINAPI IcoFrameDecode_QueryInterface(IWICBitmapFrameDecode *iface, REFIID iid,
@ -114,6 +116,7 @@ static ULONG WINAPI IcoFrameDecode_Release(IWICBitmapFrameDecode *iface)
if (ref == 0)
{
IUnknown_Release((IUnknown*)This->parent);
HeapFree(GetProcessHeap(), 0, This->bits);
HeapFree(GetProcessHeap(), 0, This);
}
@ -154,11 +157,188 @@ static HRESULT WINAPI IcoFrameDecode_CopyPalette(IWICBitmapFrameDecode *iface,
return WINCODEC_ERR_PALETTEUNAVAILABLE;
}
static inline void pixel_set_trans(DWORD* pixel, BOOL transparent)
{
if (transparent) *pixel = 0;
else *pixel |= 0xff000000;
}
static HRESULT IcoFrameDecode_ReadPixels(IcoFrameDecode *This)
{
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;
hr = IStream_Read(This->parent->stream, &bih, sizeof(BITMAPINFOHEADER), &bytesread);
if (FAILED(hr) || bytesread != sizeof(BITMAPINFOHEADER)) goto fail;
if (This->entry.wBitCount <= 8)
{
/* read the palette */
colorcount = This->entry.bColorCount ? This->entry.bColorCount : 256;
hr = IStream_Read(This->parent->stream, colors, sizeof(RGBQUAD)*colorcount, &bytesread);
if (FAILED(hr) || bytesread != sizeof(RGBQUAD)*colorcount) goto fail;
}
bitsStride = width * 4;
bitsSize = bitsStride * height;
/* read the XOR data */
switch (This->entry.wBitCount)
{
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;
}
default:
FIXME("unsupported bitcount: %u\n", This->entry.wBitCount);
goto fail;
}
if (This->entry.wBitCount < 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 (bih.biHeight > 0) /* bottom-up DIB */
{
andStride = -andBytesPerRow;
andRow = tempdata + (height-1)*andBytesPerRow;
}
else /* top-down DIB */
{
andStride = andBytesPerRow;
andRow = tempdata;
}
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);
}
andRow += andStride;
bitsRow += bitsStride;
}
HeapFree(GetProcessHeap(), 0, tempdata);
}
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)
{
FIXME("(%p,%p,%u,%u,%p): stub\n", iface, prc, cbStride, cbBufferSize, pbBuffer);
return E_NOTIMPL;
IcoFrameDecode *This = (IcoFrameDecode*)iface;
HRESULT hr;
UINT width, height, stride;
TRACE("(%p,%p,%u,%u,%p)\n", iface, prc, cbStride, cbBufferSize, pbBuffer);
if (!This->bits)
{
hr = IcoFrameDecode_ReadPixels(This);
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,
@ -362,6 +542,7 @@ static HRESULT WINAPI IcoDecoder_GetFrame(IWICBitmapDecoder *iface,
result->lpVtbl = &IcoFrameDecode_Vtbl;
result->ref = 1;
result->parent = This;
result->bits = NULL;
/* read the icon entry */
seek.QuadPart = sizeof(ICONHEADER) + sizeof(ICONDIRENTRY) * index;