From 9f1c7522f05ee842451dd8ac810b0f3af6f631f5 Mon Sep 17 00:00:00 2001 From: Vincent Povirk Date: Mon, 16 Aug 2010 18:00:49 -0500 Subject: [PATCH 2/2] gdiplus: Implement multi-frame image loading. --- dlls/gdiplus/gdiplus_private.h | 3 + dlls/gdiplus/image.c | 107 +++++++++++++++++++++++++++++++++++---- dlls/gdiplus/tests/image.c | 9 ++- 3 files changed, 105 insertions(+), 14 deletions(-) diff --git a/dlls/gdiplus/gdiplus_private.h b/dlls/gdiplus/gdiplus_private.h index eafed7c..d65d9cd 100644 --- a/dlls/gdiplus/gdiplus_private.h +++ b/dlls/gdiplus/gdiplus_private.h @@ -269,6 +269,9 @@ struct GpBitmap{ HDC hdc; BYTE *bits; /* actual image bits if this is a DIB */ INT stride; /* stride of bits if this is a DIB */ + GpBitmap **frames; + UINT framecount; /* valid only if frames is non-NULL */ + UINT active_frame; /* valid only if frames is non-NULL */ }; struct GpCachedBitmap{ diff --git a/dlls/gdiplus/image.c b/dlls/gdiplus/image.c index 30c433d..ead9cb9 100644 --- a/dlls/gdiplus/image.c +++ b/dlls/gdiplus/image.c @@ -1890,7 +1890,7 @@ GpStatus WINGDIPAPI GdipEmfToWmfBits(HENHMETAFILE hemf, UINT cbData16, } /* Internal utility function: Replace the image data of dst with that of src, - * and free src. */ + * and free src. src must not be a multi-frame bitmap. */ static void move_bitmap(GpBitmap *dst, GpBitmap *src, BOOL clobber_palette) { GdipFree(dst->bitmapbits); @@ -1922,6 +1922,8 @@ static void move_bitmap(GpBitmap *dst, GpBitmap *src, BOOL clobber_palette) GpStatus WINGDIPAPI GdipDisposeImage(GpImage *image) { + UINT i; + TRACE("%p\n", image); if(!image) @@ -1934,6 +1936,12 @@ GpStatus WINGDIPAPI GdipDisposeImage(GpImage *image) GdipFree(((GpBitmap*)image)->bitmapbits); DeleteDC(((GpBitmap*)image)->hdc); DeleteObject(((GpBitmap*)image)->hbitmap); + if (((GpBitmap*)image)->frames) + { + for (i=0; i<((GpBitmap*)image)->framecount; i++) + GdipDisposeImage((GpImage*)(((GpBitmap*)image)->frames[i])); + GdipFree(((GpBitmap*)image)->frames); + } } GdipFree(image->palette_entries); GdipFree(image); @@ -2355,21 +2363,20 @@ struct image_format_dimension image_format_dimensions[] = {NULL} }; -/* FIXME: Need to handle multi-framed images */ GpStatus WINGDIPAPI GdipImageGetFrameCount(GpImage *image, GDIPCONST GUID* dimensionID, UINT* count) { - static int calls; - TRACE("(%p,%s,%p)\n", image, debugstr_guid(dimensionID), count); if(!image || !count) return InvalidParameter; - if(!(calls++)) - FIXME("returning frame count of 1\n"); + /* FIXME: Validate dimensionID. */ - *count = 1; + if (image->type == ImageTypeBitmap && ((GpBitmap*)image)->frames) + *count = ((GpBitmap*)image)->framecount; + else + *count = 1; return Ok; } @@ -2420,17 +2427,43 @@ GpStatus WINGDIPAPI GdipImageGetFrameDimensionsList(GpImage* image, GpStatus WINGDIPAPI GdipImageSelectActiveFrame(GpImage *image, GDIPCONST GUID* dimensionID, UINT frameidx) { - static int calls; + GpStatus stat = Ok; + GpImage *clone; TRACE("(%p, %s, %u)\n", image, debugstr_guid(dimensionID), frameidx); if(!image || !dimensionID) return InvalidParameter; - if(!(calls++)) - FIXME("not implemented\n"); + /* FIXME: Validate dimensionID. */ - return Ok; + if (image->type == ImageTypeBitmap && ((GpBitmap*)image)->frames) + { + if (frameidx >= ((GpBitmap*)image)->framecount) + return Win32Error; + + if (frameidx == ((GpBitmap*)image)->active_frame) + return Ok; + + /* switch frames */ + stat = GdipCloneImage((GpImage*)(((GpBitmap*)image)->frames[frameidx]), &clone); + + if (stat == Ok) + { + move_bitmap((GpBitmap*)image, (GpBitmap*)clone, TRUE); + ((GpBitmap*)image)->active_frame = frameidx; + } + } + else + { + /* Not a multi-frame image. */ + if (frameidx != 0) + return Win32Error; + else + return Ok; + } + + return stat; } GpStatus WINGDIPAPI GdipLoadImageFromFile(GDIPCONST WCHAR* filename, @@ -2568,6 +2601,7 @@ static GpStatus decode_image_wic(IStream* stream, REFCLSID clsid, GpImage **imag IWICBitmapDecoder *decoder; IWICBitmapFrameDecode *frame; HRESULT initresult; + UINT framecount, i; initresult = CoInitialize(NULL); @@ -2586,6 +2620,57 @@ static GpStatus decode_image_wic(IStream* stream, REFCLSID clsid, GpImage **imag IWICBitmapFrameDecode_Release(frame); } + if (SUCCEEDED(hr) && status == Ok) + { + hr = IWICBitmapDecoder_GetFrameCount(decoder, &framecount); + + if (SUCCEEDED(hr) && status == Ok && framecount > 1) + { + GpBitmap* first_frame; + + status = GdipCloneImage(*image, (GpImage**)&first_frame); + + if (SUCCEEDED(hr) && status == Ok) + { + ((GpBitmap*)*image)->framecount = framecount; + ((GpBitmap*)*image)->active_frame = 0; + ((GpBitmap*)*image)->frames = GdipAlloc(sizeof(GpBitmap*) * framecount); + + if (!((GpBitmap*)*image)->frames) + { + status = OutOfMemory; + GdipDisposeImage((GpImage*)first_frame); + } + + if (SUCCEEDED(hr) && status == Ok) + { + ((GpBitmap*)*image)->frames[0] = first_frame; + + for (i=1; iframes[i]); + + IWICBitmapFrameDecode_Release(frame); + } + + if (FAILED(hr) || status != Ok) + break; + } + } + } + } + + if (FAILED(hr) || status != Ok) + { + GdipDisposeImage(*image); + *image = NULL; + } + } + IWICBitmapDecoder_Release(decoder); end: diff --git a/dlls/gdiplus/tests/image.c b/dlls/gdiplus/tests/image.c index 0e33049..24bde74 100644 --- a/dlls/gdiplus/tests/image.c +++ b/dlls/gdiplus/tests/image.c @@ -1806,7 +1806,7 @@ static void test_multiframegif(void) count = 12345; stat = GdipImageGetFrameCount((GpImage*)bmp, &dimension, &count); expect(Ok, stat); - todo_wine expect(2, count); + expect(2, count); /* SelectActiveFrame overwrites our current data */ stat = GdipImageSelectActiveFrame((GpImage*)bmp, &dimension, 1); @@ -1815,7 +1815,7 @@ static void test_multiframegif(void) color = 0xdeadbeef; GdipBitmapGetPixel(bmp, 0, 0, &color); expect(Ok, stat); - todo_wine expect(0xff000000, color); + expect(0xff000000, color); stat = GdipImageSelectActiveFrame((GpImage*)bmp, &dimension, 0); expect(Ok, stat); @@ -1846,7 +1846,10 @@ static void test_multiframegif(void) stat = GdipBitmapGetPixel(bmp, 0, 0, &color); expect(Ok, stat); - todo_wine expect(0xffffffff, color); + expect(0xffffffff, color); + + stat = GdipImageSelectActiveFrame((GpImage*)bmp, &dimension, 2); + expect(Win32Error, stat); GdipDisposeImage((GpImage*)bmp); IStream_Release(stream); -- 1.7.0.4