From 915df87aa5048734046c9889dba4f2fdf6298c1b Mon Sep 17 00:00:00 2001 From: Dmitry Timoshkov Date: Fri, 21 Sep 2012 19:58:20 +0900 Subject: [PATCH] gdiplus: Add an ability to cache bitmap properties and use distinct metadata loaders for different image formats. --- dlls/gdiplus/gdiplus_private.h | 2 + dlls/gdiplus/image.c | 115 ++++++++++++++++++++++++++++++--- 2 files changed, 109 insertions(+), 8 deletions(-) diff --git a/dlls/gdiplus/gdiplus_private.h b/dlls/gdiplus/gdiplus_private.h index d44c9699288..53f978c098b 100644 --- a/dlls/gdiplus/gdiplus_private.h +++ b/dlls/gdiplus/gdiplus_private.h @@ -311,6 +311,8 @@ struct GpBitmap{ BYTE *own_bits; /* image bits that need to be freed with this object */ INT lockx, locky; /* X and Y coordinates of the rect when a bitmap is locked for writing. */ IWICMetadataReader *metadata_reader; /* NULL if there is no metadata */ + UINT prop_count; + PropertyItem *prop_item; /* cached image properties */ }; struct GpCachedBitmap{ diff --git a/dlls/gdiplus/image.c b/dlls/gdiplus/image.c index b657969ce9e..c6018ab26b9 100644 --- a/dlls/gdiplus/image.c +++ b/dlls/gdiplus/image.c @@ -1911,6 +1911,8 @@ GpStatus WINGDIPAPI GdipCreateBitmapFromScan0(INT width, INT height, INT stride, (*bitmap)->stride = stride; (*bitmap)->own_bits = own_bits; (*bitmap)->metadata_reader = NULL; + (*bitmap)->prop_count = 0; + (*bitmap)->prop_item = NULL; /* set format-related flags */ if (format & (PixelFormatAlpha|PixelFormatPAlpha|PixelFormatIndexed)) @@ -2123,6 +2125,9 @@ static void move_bitmap(GpBitmap *dst, GpBitmap *src, BOOL clobber_palette) if (dst->metadata_reader) IWICMetadataReader_Release(dst->metadata_reader); dst->metadata_reader = src->metadata_reader; + GdipFree(dst->prop_item); + dst->prop_item = src->prop_item; + dst->prop_count = src->prop_count; if (dst->image.stream) IStream_Release(dst->image.stream); dst->image.stream = src->image.stream; @@ -2147,6 +2152,7 @@ static GpStatus free_image_data(GpImage *image) DeleteObject(((GpBitmap*)image)->hbitmap); if (((GpBitmap*)image)->metadata_reader) IWICMetadataReader_Release(((GpBitmap*)image)->metadata_reader); + GdipFree(((GpBitmap*)image)->prop_item); } else if (image->type == ImageTypeMetafile) { @@ -2509,6 +2515,12 @@ GpStatus WINGDIPAPI GdipGetPropertyCount(GpImage *image, UINT *num) if (image->type == ImageTypeBitmap) { + if (((GpBitmap *)image)->prop_item) + { + *num = ((GpBitmap *)image)->prop_count; + return Ok; + } + if (((GpBitmap *)image)->metadata_reader) IWICMetadataReader_GetCount(((GpBitmap *)image)->metadata_reader, num); } @@ -2533,6 +2545,18 @@ GpStatus WINGDIPAPI GdipGetPropertyIdList(GpImage *image, UINT num, PROPID *list return NotImplemented; } + if (((GpBitmap *)image)->prop_item) + { + if (num != ((GpBitmap *)image)->prop_count) return InvalidParameter; + + for (i = 0; i < num; i++) + { + list[i] = ((GpBitmap *)image)->prop_item[i].id; + } + + return Ok; + } + reader = ((GpBitmap *)image)->metadata_reader; if (!reader) { @@ -2621,6 +2645,22 @@ GpStatus WINGDIPAPI GdipGetPropertyItemSize(GpImage *image, PROPID propid, UINT return NotImplemented; } + if (((GpBitmap *)image)->prop_item) + { + UINT i; + + for (i = 0; i < ((GpBitmap *)image)->prop_count; i++) + { + if (propid == ((GpBitmap *)image)->prop_item[i].id) + { + *size = sizeof(PropertyItem) + ((GpBitmap *)image)->prop_item[i].length; + return Ok; + } + } + + return PropertyNotFound; + } + reader = ((GpBitmap *)image)->metadata_reader; if (!reader) return PropertyNotFound; @@ -2753,6 +2793,27 @@ GpStatus WINGDIPAPI GdipGetPropertyItem(GpImage *image, PROPID propid, UINT size return NotImplemented; } + if (((GpBitmap *)image)->prop_item) + { + UINT i; + + for (i = 0; i < ((GpBitmap *)image)->prop_count; i++) + { + if (propid == ((GpBitmap *)image)->prop_item[i].id) + { + if (size != sizeof(PropertyItem) + ((GpBitmap *)image)->prop_item[i].length) + return InvalidParameter; + + *buffer = ((GpBitmap *)image)->prop_item[i]; + buffer->value = buffer + 1; + memcpy(buffer->value, ((GpBitmap *)image)->prop_item[i].value, buffer->length); + return Ok; + } + } + + return PropertyNotFound; + } + reader = ((GpBitmap *)image)->metadata_reader; if (!reader) return PropertyNotFound; @@ -2785,6 +2846,19 @@ GpStatus WINGDIPAPI GdipGetPropertySize(GpImage *image, UINT *size, UINT *count) return NotImplemented; } + if (((GpBitmap *)image)->prop_item) + { + *count = ((GpBitmap *)image)->prop_count; + *size = 0; + + for (i = 0; i < ((GpBitmap *)image)->prop_count; i++) + { + *size += sizeof(PropertyItem) + ((GpBitmap *)image)->prop_item[i].length; + } + + return Ok; + } + reader = ((GpBitmap *)image)->metadata_reader; if (!reader) return PropertyNotFound; @@ -2850,6 +2924,21 @@ GpStatus WINGDIPAPI GdipGetAllPropertyItems(GpImage *image, UINT size, if (prop_count != count || prop_size != size) return InvalidParameter; + if (((GpBitmap *)image)->prop_item) + { + memcpy(buf, ((GpBitmap *)image)->prop_item, prop_size); + + item_value = (char *)(buf + prop_count); + + for (i = 0; i < prop_count; i++) + { + buf[i].value = item_value; + item_value += buf[i].length; + } + + return Ok; + } + reader = ((GpBitmap *)image)->metadata_reader; if (!reader) return PropertyNotFound; @@ -3011,7 +3100,14 @@ GpStatus WINGDIPAPI GdipLoadImageFromFileICM(GDIPCONST WCHAR* filename,GpImage * return GdipLoadImageFromFile(filename, image); } -static GpStatus decode_image_wic(IStream* stream, REFCLSID clsid, UINT active_frame, GpImage **image) +static void gif_metadata_reader(GpBitmap *bitmap, IWICBitmapDecoder *decoder, UINT frame) +{ +} + +typedef void (*metadata_reader_func)(GpBitmap *bitmap, IWICBitmapDecoder *decoder, UINT frame); + +static GpStatus decode_image_wic(IStream *stream, GDIPCONST CLSID *clsid, + UINT active_frame, metadata_reader_func metadata_reader, GpImage **image) { GpStatus status=Ok; GpBitmap *bitmap; @@ -3126,7 +3222,10 @@ static GpStatus decode_image_wic(IStream* stream, REFCLSID clsid, UINT active_fr if (SUCCEEDED(hr)) { bitmap->metadata_reader = NULL; - if (IWICBitmapFrameDecode_QueryInterface(frame, &IID_IWICMetadataBlockReader, (void **)&block_reader) == S_OK) + + if (metadata_reader) + metadata_reader(bitmap, decoder, active_frame); + else if (IWICBitmapFrameDecode_QueryInterface(frame, &IID_IWICMetadataBlockReader, (void **)&block_reader) == S_OK) { UINT block_count = 0; if (IWICMetadataBlockReader_GetCount(block_reader, &block_count) == S_OK && block_count) @@ -3172,7 +3271,7 @@ end: static GpStatus decode_image_icon(IStream* stream, REFCLSID clsid, UINT active_frame, GpImage **image) { - return decode_image_wic(stream, &CLSID_WICIcoDecoder, active_frame, image); + return decode_image_wic(stream, &CLSID_WICIcoDecoder, active_frame, NULL, image); } static GpStatus decode_image_bmp(IStream* stream, REFCLSID clsid, UINT active_frame, GpImage **image) @@ -3180,7 +3279,7 @@ static GpStatus decode_image_bmp(IStream* stream, REFCLSID clsid, UINT active_fr GpStatus status; GpBitmap* bitmap; - status = decode_image_wic(stream, &CLSID_WICBmpDecoder, active_frame, image); + status = decode_image_wic(stream, &CLSID_WICBmpDecoder, active_frame, NULL, image); bitmap = (GpBitmap*)*image; @@ -3195,22 +3294,22 @@ static GpStatus decode_image_bmp(IStream* stream, REFCLSID clsid, UINT active_fr static GpStatus decode_image_jpeg(IStream* stream, REFCLSID clsid, UINT active_frame, GpImage **image) { - return decode_image_wic(stream, &CLSID_WICJpegDecoder, active_frame, image); + return decode_image_wic(stream, &CLSID_WICJpegDecoder, active_frame, NULL, image); } static GpStatus decode_image_png(IStream* stream, REFCLSID clsid, UINT active_frame, GpImage **image) { - return decode_image_wic(stream, &CLSID_WICPngDecoder, active_frame, image); + return decode_image_wic(stream, &CLSID_WICPngDecoder, active_frame, NULL, image); } static GpStatus decode_image_gif(IStream* stream, REFCLSID clsid, UINT active_frame, GpImage **image) { - return decode_image_wic(stream, &CLSID_WICGifDecoder, active_frame, image); + return decode_image_wic(stream, &CLSID_WICGifDecoder, active_frame, gif_metadata_reader, image); } static GpStatus decode_image_tiff(IStream* stream, REFCLSID clsid, UINT active_frame, GpImage **image) { - return decode_image_wic(stream, &CLSID_WICTiffDecoder, active_frame, image); + return decode_image_wic(stream, &CLSID_WICTiffDecoder, active_frame, NULL, image); } static GpStatus decode_image_olepicture_metafile(IStream* stream, REFCLSID clsid, UINT active_frame, GpImage **image)