windowscodecs: Implement CopyPixels for BMP decoder.

This commit is contained in:
Vincent Povirk 2009-07-01 15:48:56 -05:00 committed by Alexandre Julliard
parent 07538b79cb
commit 5b7de464ca
4 changed files with 193 additions and 3 deletions

View file

@ -58,7 +58,10 @@ typedef struct {
DWORD bc2AppData;
} BITMAPCOREHEADER2;
typedef struct {
struct BmpFrameDecode;
typedef HRESULT (*ReadDataFunc)(struct BmpFrameDecode* This);
typedef struct BmpFrameDecode {
const IWICBitmapFrameDecodeVtbl *lpVtbl;
LONG ref;
IStream *stream;
@ -66,6 +69,10 @@ typedef struct {
BITMAPV5HEADER bih;
const WICPixelFormatGUID *pixelformat;
int bitsperpixel;
ReadDataFunc read_data_func;
INT stride;
BYTE *imagedata;
BYTE *imagedatastart;
} BmpFrameDecode;
static HRESULT WINAPI BmpFrameDecode_QueryInterface(IWICBitmapFrameDecode *iface, REFIID iid,
@ -112,6 +119,7 @@ static ULONG WINAPI BmpFrameDecode_Release(IWICBitmapFrameDecode *iface)
if (ref == 0)
{
IStream_Release(This->stream);
HeapFree(GetProcessHeap(), 0, This->imagedata);
HeapFree(GetProcessHeap(), 0, This);
}
@ -188,8 +196,23 @@ static HRESULT WINAPI BmpFrameDecode_CopyPalette(IWICBitmapFrameDecode *iface,
static HRESULT WINAPI BmpFrameDecode_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;
BmpFrameDecode *This = (BmpFrameDecode*)iface;
HRESULT hr;
UINT width, height;
TRACE("(%p,%p,%u,%u,%p)\n", iface, prc, cbStride, cbBufferSize, pbBuffer);
if (!This->imagedata)
{
hr = This->read_data_func(This);
if (FAILED(hr)) return hr;
}
hr = BmpFrameDecode_GetSize(iface, &width, &height);
if (FAILED(hr)) return hr;
return copy_pixels(This->bitsperpixel, This->imagedatastart,
width, height, This->stride,
prc, cbStride, cbBufferSize, pbBuffer);
}
static HRESULT WINAPI BmpFrameDecode_GetMetadataQueryReader(IWICBitmapFrameDecode *iface,
@ -213,6 +236,68 @@ static HRESULT WINAPI BmpFrameDecode_GetThumbnail(IWICBitmapFrameDecode *iface,
return E_NOTIMPL;
}
static HRESULT BmpFrameDecode_ReadUncompressed(BmpFrameDecode* This)
{
UINT bytesperrow;
UINT width, height;
UINT datasize;
int bottomup;
HRESULT hr;
LARGE_INTEGER offbits;
ULONG bytesread;
if (This->bih.bV5Size == sizeof(BITMAPCOREHEADER))
{
BITMAPCOREHEADER *bch = (BITMAPCOREHEADER*)&This->bih;
width = bch->bcWidth;
height = bch->bcHeight;
bottomup = 1;
}
else
{
width = This->bih.bV5Width;
height = abs(This->bih.bV5Height);
bottomup = (This->bih.bV5Height > 0);
}
/* row sizes in BMP files must be divisible by 4 bytes */
bytesperrow = (((width * This->bitsperpixel)+31)/32)*4;
datasize = bytesperrow * height;
This->imagedata = HeapAlloc(GetProcessHeap(), 0, datasize);
if (!This->imagedata) return E_OUTOFMEMORY;
offbits.QuadPart = This->bfh.bfOffBits;
hr = IStream_Seek(This->stream, offbits, STREAM_SEEK_SET, NULL);
if (FAILED(hr)) goto fail;
hr = IStream_Read(This->stream, This->imagedata, datasize, &bytesread);
if (FAILED(hr) || bytesread != datasize) goto fail;
if (bottomup)
{
This->imagedatastart = This->imagedata + (height-1) * bytesperrow;
This->stride = -bytesperrow;
}
else
{
This->imagedatastart = This->imagedata;
This->stride = bytesperrow;
}
return S_OK;
fail:
HeapFree(GetProcessHeap(), 0, This->imagedata);
This->imagedata = NULL;
if (SUCCEEDED(hr)) hr = E_FAIL;
return hr;
}
static HRESULT BmpFrameDecode_ReadUnsupported(BmpFrameDecode* This)
{
return E_FAIL;
}
static const IWICBitmapFrameDecodeVtbl BmpFrameDecode_Vtbl = {
BmpFrameDecode_QueryInterface,
BmpFrameDecode_AddRef,
@ -237,6 +322,7 @@ typedef struct {
BmpFrameDecode *framedecode;
const WICPixelFormatGUID *pixelformat;
int bitsperpixel;
ReadDataFunc read_data_func;
} BmpDecoder;
static HRESULT BmpDecoder_ReadHeaders(BmpDecoder* This, IStream *stream)
@ -271,6 +357,7 @@ static HRESULT BmpDecoder_ReadHeaders(BmpDecoder* This, IStream *stream)
BITMAPCOREHEADER *bch = (BITMAPCOREHEADER*)&This->bih;
TRACE("BITMAPCOREHEADER with depth=%i\n", bch->bcBitCount);
This->bitsperpixel = bch->bcBitCount;
This->read_data_func = BmpFrameDecode_ReadUncompressed;
switch(bch->bcBitCount)
{
case 1:
@ -301,6 +388,7 @@ static HRESULT BmpDecoder_ReadHeaders(BmpDecoder* This, IStream *stream)
{
case BI_RGB:
This->bitsperpixel = This->bih.bV5BitCount;
This->read_data_func = BmpFrameDecode_ReadUncompressed;
switch(This->bih.bV5BitCount)
{
case 1:
@ -331,6 +419,7 @@ static HRESULT BmpDecoder_ReadHeaders(BmpDecoder* This, IStream *stream)
break;
default:
This->bitsperpixel = 0;
This->read_data_func = BmpFrameDecode_ReadUnsupported;
This->pixelformat = &GUID_WICPixelFormatUndefined;
FIXME("unsupported bitmap type header=%i compression=%i depth=%i\n", This->bih.bV5Size, This->bih.bV5Compression, This->bih.bV5BitCount);
break;
@ -493,6 +582,8 @@ static HRESULT WINAPI BmpDecoder_GetFrame(IWICBitmapDecoder *iface,
This->framedecode->bih = This->bih;
This->framedecode->pixelformat = This->pixelformat;
This->framedecode->bitsperpixel = This->bitsperpixel;
This->framedecode->read_data_func = This->read_data_func;
This->framedecode->imagedata = NULL;
}
*ppIBitmapFrame = (IWICBitmapFrameDecode*)This->framedecode;

View file

@ -23,6 +23,14 @@
#include "windef.h"
#include "winbase.h"
#include "objbase.h"
#include "wincodec.h"
#include "wincodecs_private.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
@ -40,3 +48,48 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
return TRUE;
}
HRESULT copy_pixels(UINT bpp, const BYTE *srcbuffer,
UINT srcwidth, UINT srcheight, INT srcstride,
const WICRect *rc, UINT dststride, UINT dstbuffersize, BYTE *dstbuffer)
{
UINT bytesperrow;
UINT row_offset; /* number of bits into the source rows where the data starts */
if (rc->X < 0 || rc->Y < 0 || rc->X+rc->Width > srcwidth || rc->Y+rc->Height > srcheight)
return E_INVALIDARG;
bytesperrow = ((bpp * rc->Width)+7)/8;
if (dststride < bytesperrow)
return E_INVALIDARG;
if ((dststride * rc->Height) > dstbuffersize)
return E_INVALIDARG;
row_offset = rc->X * bpp;
if (row_offset % 8 == 0)
{
/* everything lines up on a byte boundary */
UINT row;
const BYTE *src;
BYTE *dst;
src = srcbuffer + (row_offset / 8);
dst = dstbuffer;
for (row=0; row < rc->Height; row++)
{
memcpy(dst, src, bytesperrow);
src += srcstride;
dst += dststride;
}
return S_OK;
}
else
{
/* we have to do a weird bitwise copy. eww. */
FIXME("cannot reliably copy bitmap data if bpp < 8\n");
return E_FAIL;
}
}

View file

@ -56,6 +56,12 @@ static void test_decode_24bpp(void)
GUID guidresult;
UINT count=0, width=0, height=0;
double dpiX, dpiY;
BYTE imagedata[36] = {1};
const BYTE expected_imagedata[36] = {
255,0,255, 255,255,255,
255,0,0, 255,255,0,
0,0,0, 0,255,0};
WICRect rc;
hr = CoCreateInstance(&CLSID_WICBmpDecoder, NULL, CLSCTX_INPROC_SERVER,
&IID_IWICBitmapDecoder, (void**)&decoder);
@ -106,6 +112,42 @@ static void test_decode_24bpp(void)
ok(SUCCEEDED(hr), "GetPixelFormat failed, hr=%x\n", hr);
ok(IsEqualGUID(&guidresult, &GUID_WICPixelFormat24bppBGR), "unexpected pixel format\n");
rc.X = 0;
rc.Y = 0;
rc.Width = 3;
rc.Height = 3;
hr = IWICBitmapFrameDecode_CopyPixels(framedecode, &rc, 6, sizeof(imagedata), imagedata);
ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got %x\n", hr);
rc.X = -1;
rc.Y = 0;
rc.Width = 2;
rc.Height = 3;
hr = IWICBitmapFrameDecode_CopyPixels(framedecode, &rc, 6, sizeof(imagedata), imagedata);
ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got %x\n", hr);
rc.X = 0;
rc.Y = 0;
rc.Width = 2;
rc.Height = 3;
hr = IWICBitmapFrameDecode_CopyPixels(framedecode, &rc, 4, sizeof(imagedata), imagedata);
ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got %x\n", hr);
rc.X = 0;
rc.Y = 0;
rc.Width = 2;
rc.Height = 3;
hr = IWICBitmapFrameDecode_CopyPixels(framedecode, &rc, 4, 5, imagedata);
ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got %x\n", hr);
rc.X = 0;
rc.Y = 0;
rc.Width = 2;
rc.Height = 3;
hr = IWICBitmapFrameDecode_CopyPixels(framedecode, &rc, 6, sizeof(imagedata), imagedata);
ok(SUCCEEDED(hr), "CopyPixels failed, hr=%x\n", hr);
ok(!memcmp(imagedata, expected_imagedata, sizeof(imagedata)), "unexpected image data\n");
IWICBitmapFrameDecode_Release(framedecode);
}

View file

@ -22,4 +22,8 @@
extern HRESULT ImagingFactory_CreateInstance(IUnknown *pUnkOuter, REFIID riid, void** ppv);
extern HRESULT BmpDecoder_CreateInstance(IUnknown *pUnkOuter, REFIID riid, void** ppv);
extern HRESULT copy_pixels(UINT bpp, const BYTE *srcbuffer,
UINT srcwidth, UINT srcheight, INT srcstride,
const WICRect *rc, UINT dststride, UINT dstbuffersize, BYTE *dstbuffer);
#endif /* WINCODECS_PRIVATE_H */