From 5b7de464ca1d93ce92201bc6c0484ba6550fe073 Mon Sep 17 00:00:00 2001 From: Vincent Povirk Date: Wed, 1 Jul 2009 15:48:56 -0500 Subject: [PATCH] windowscodecs: Implement CopyPixels for BMP decoder. --- dlls/windowscodecs/bmpdecode.c | 97 +++++++++++++++++++++++++- dlls/windowscodecs/main.c | 53 ++++++++++++++ dlls/windowscodecs/tests/bmpformat.c | 42 +++++++++++ dlls/windowscodecs/wincodecs_private.h | 4 ++ 4 files changed, 193 insertions(+), 3 deletions(-) diff --git a/dlls/windowscodecs/bmpdecode.c b/dlls/windowscodecs/bmpdecode.c index 8391a1b3400..a6b75770b7f 100644 --- a/dlls/windowscodecs/bmpdecode.c +++ b/dlls/windowscodecs/bmpdecode.c @@ -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; diff --git a/dlls/windowscodecs/main.c b/dlls/windowscodecs/main.c index e3912b8462a..ac636031c6c 100644 --- a/dlls/windowscodecs/main.c +++ b/dlls/windowscodecs/main.c @@ -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; + } +} diff --git a/dlls/windowscodecs/tests/bmpformat.c b/dlls/windowscodecs/tests/bmpformat.c index 11c5a67e321..c266dda143c 100644 --- a/dlls/windowscodecs/tests/bmpformat.c +++ b/dlls/windowscodecs/tests/bmpformat.c @@ -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); } diff --git a/dlls/windowscodecs/wincodecs_private.h b/dlls/windowscodecs/wincodecs_private.h index 0070bfcceb7..313dca53366 100644 --- a/dlls/windowscodecs/wincodecs_private.h +++ b/dlls/windowscodecs/wincodecs_private.h @@ -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 */