gdiplus: Don't create new instance of IWICBitmapDecoder to encode every frame of animation.
This commit is contained in:
parent
e889dd8eaa
commit
a181997855
|
@ -271,6 +271,7 @@ struct GpAdustableArrowCap{
|
|||
struct GpImage{
|
||||
IPicture *picture;
|
||||
IStream *stream; /* source stream */
|
||||
IWICBitmapDecoder *decoder;
|
||||
ImageType type;
|
||||
GUID format;
|
||||
UINT flags;
|
||||
|
|
|
@ -1872,6 +1872,7 @@ GpStatus WINGDIPAPI GdipCreateBitmapFromScan0(INT width, INT height, INT stride,
|
|||
(*bitmap)->format = format;
|
||||
(*bitmap)->image.picture = NULL;
|
||||
(*bitmap)->image.stream = NULL;
|
||||
(*bitmap)->image.decoder = NULL;
|
||||
(*bitmap)->hbitmap = hbitmap;
|
||||
(*bitmap)->hdc = NULL;
|
||||
(*bitmap)->bits = bits;
|
||||
|
@ -2091,6 +2092,9 @@ static void move_bitmap(GpBitmap *dst, GpBitmap *src, BOOL clobber_palette)
|
|||
if (dst->image.stream)
|
||||
IStream_Release(dst->image.stream);
|
||||
dst->image.stream = src->image.stream;
|
||||
if (dst->image.decoder)
|
||||
IWICBitmapDecoder_Release(dst->image.decoder);
|
||||
dst->image.decoder = src->image.decoder;
|
||||
dst->image.frame_count = src->image.frame_count;
|
||||
dst->image.current_frame = src->image.current_frame;
|
||||
dst->image.format = src->image.format;
|
||||
|
@ -2138,6 +2142,8 @@ static GpStatus free_image_data(GpImage *image)
|
|||
IPicture_Release(image->picture);
|
||||
if (image->stream)
|
||||
IStream_Release(image->stream);
|
||||
if (image->decoder)
|
||||
IWICBitmapDecoder_Release(image->decoder);
|
||||
GdipFree(image->palette);
|
||||
|
||||
return Ok;
|
||||
|
@ -3401,16 +3407,32 @@ static void gif_metadata_reader(GpBitmap *bitmap, IWICBitmapDecoder *decoder, UI
|
|||
IWICBitmapFrameDecode_Release(frame);
|
||||
}
|
||||
|
||||
static GpStatus initialize_decoder_wic(IStream *stream, REFGUID container, IWICBitmapDecoder **decoder)
|
||||
{
|
||||
IWICImagingFactory *factory;
|
||||
HRESULT hr;
|
||||
|
||||
TRACE("%p,%s\n", stream, wine_dbgstr_guid(container));
|
||||
|
||||
hr = WICCreateImagingFactory_Proxy(WINCODEC_SDK_VERSION, &factory);
|
||||
if (FAILED(hr)) hresult_to_status(hr);
|
||||
hr = IWICImagingFactory_CreateDecoder(factory, container, NULL, decoder);
|
||||
IWICImagingFactory_Release(factory);
|
||||
if (FAILED(hr)) hresult_to_status(hr);
|
||||
|
||||
hr = IWICBitmapDecoder_Initialize(*decoder, stream, WICDecodeMetadataCacheOnLoad);
|
||||
if (FAILED(hr)) hresult_to_status(hr);
|
||||
return Ok;
|
||||
}
|
||||
|
||||
typedef void (*metadata_reader_func)(GpBitmap *bitmap, IWICBitmapDecoder *decoder, UINT frame);
|
||||
|
||||
static GpStatus decode_image_wic(IStream *stream, REFGUID container,
|
||||
static GpStatus decode_frame_wic(IStream *stream, IWICBitmapDecoder *decoder,
|
||||
UINT active_frame, metadata_reader_func metadata_reader, GpImage **image)
|
||||
{
|
||||
GpStatus status=Ok;
|
||||
GpBitmap *bitmap;
|
||||
HRESULT hr;
|
||||
IWICImagingFactory *factory;
|
||||
IWICBitmapDecoder *decoder;
|
||||
IWICBitmapFrameDecode *frame;
|
||||
IWICBitmapSource *source=NULL;
|
||||
IWICMetadataBlockReader *block_reader;
|
||||
|
@ -3423,21 +3445,10 @@ static GpStatus decode_image_wic(IStream *stream, REFGUID container,
|
|||
BitmapData lockeddata;
|
||||
WICRect wrc;
|
||||
|
||||
TRACE("%p,%s,%u,%p\n", stream, wine_dbgstr_guid(container), active_frame, image);
|
||||
|
||||
hr = WICCreateImagingFactory_Proxy(WINCODEC_SDK_VERSION, &factory);
|
||||
if (FAILED(hr)) goto end;
|
||||
hr = IWICImagingFactory_CreateDecoder(factory, container, NULL, &decoder);
|
||||
IWICImagingFactory_Release(factory);
|
||||
if (FAILED(hr)) goto end;
|
||||
|
||||
hr = IWICBitmapDecoder_Initialize(decoder, stream, WICDecodeMetadataCacheOnLoad);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
IWICBitmapDecoder_GetFrameCount(decoder, &frame_count);
|
||||
hr = IWICBitmapDecoder_GetFrame(decoder, active_frame, &frame);
|
||||
}
|
||||
TRACE("%p,%u,%p\n", decoder, active_frame, image);
|
||||
|
||||
IWICBitmapDecoder_GetFrameCount(decoder, &frame_count);
|
||||
hr = IWICBitmapDecoder_GetFrame(decoder, active_frame, &frame);
|
||||
if (SUCCEEDED(hr)) /* got frame */
|
||||
{
|
||||
hr = IWICBitmapFrameDecode_GetPixelFormat(frame, &wic_format);
|
||||
|
@ -3537,9 +3548,6 @@ static GpStatus decode_image_wic(IStream *stream, REFGUID container,
|
|||
}
|
||||
}
|
||||
|
||||
IWICBitmapDecoder_Release(decoder);
|
||||
|
||||
end:
|
||||
if (FAILED(hr) && status == Ok) status = hresult_to_status(hr);
|
||||
|
||||
if (status == Ok)
|
||||
|
@ -3549,6 +3557,8 @@ end:
|
|||
bitmap->image.frame_count = frame_count;
|
||||
bitmap->image.current_frame = active_frame;
|
||||
bitmap->image.stream = stream;
|
||||
bitmap->image.decoder = decoder;
|
||||
IWICBitmapDecoder_AddRef(decoder);
|
||||
if (palette)
|
||||
{
|
||||
GdipFree(bitmap->image.palette);
|
||||
|
@ -3567,17 +3577,72 @@ end:
|
|||
return status;
|
||||
}
|
||||
|
||||
static GpStatus decode_image_icon(IStream* stream, REFCLSID clsid, UINT active_frame, GpImage **image)
|
||||
static GpStatus decode_image_wic(IStream *stream, REFGUID container,
|
||||
metadata_reader_func metadata_reader, GpImage **image)
|
||||
{
|
||||
return decode_image_wic(stream, &GUID_ContainerFormatIco, active_frame, NULL, image);
|
||||
IWICBitmapDecoder *decoder;
|
||||
GpStatus status;
|
||||
|
||||
status = initialize_decoder_wic(stream, container, &decoder);
|
||||
if(status != Ok)
|
||||
return status;
|
||||
|
||||
status = decode_frame_wic(stream, decoder, 0, metadata_reader, image);
|
||||
IWICBitmapDecoder_Release(decoder);
|
||||
return status;
|
||||
}
|
||||
|
||||
static GpStatus decode_image_bmp(IStream* stream, REFCLSID clsid, UINT active_frame, GpImage **image)
|
||||
static GpStatus select_frame_wic(GpImage *image, UINT active_frame)
|
||||
{
|
||||
GpImage *new_image;
|
||||
GpStatus status;
|
||||
|
||||
status = decode_frame_wic(image->stream, image->decoder, active_frame, NULL, &new_image);
|
||||
if(status != Ok)
|
||||
return status;
|
||||
|
||||
memcpy(&new_image->format, &image->format, sizeof(GUID));
|
||||
free_image_data(image);
|
||||
if (image->type == ImageTypeBitmap)
|
||||
*(GpBitmap *)image = *(GpBitmap *)new_image;
|
||||
else if (image->type == ImageTypeMetafile)
|
||||
*(GpMetafile *)image = *(GpMetafile *)new_image;
|
||||
new_image->type = ~0;
|
||||
GdipFree(new_image);
|
||||
return Ok;
|
||||
}
|
||||
|
||||
static GpStatus select_frame_gif(GpImage *image, UINT active_frame)
|
||||
{
|
||||
GpImage *new_image;
|
||||
GpStatus status;
|
||||
|
||||
status = decode_frame_wic(image->stream, image->decoder, active_frame, gif_metadata_reader, &new_image);
|
||||
if(status != Ok)
|
||||
return status;
|
||||
|
||||
memcpy(&new_image->format, &image->format, sizeof(GUID));
|
||||
free_image_data(image);
|
||||
if (image->type == ImageTypeBitmap)
|
||||
*(GpBitmap *)image = *(GpBitmap *)new_image;
|
||||
else if (image->type == ImageTypeMetafile)
|
||||
*(GpMetafile *)image = *(GpMetafile *)new_image;
|
||||
new_image->type = ~0;
|
||||
GdipFree(new_image);
|
||||
return Ok;
|
||||
}
|
||||
|
||||
static GpStatus decode_image_icon(IStream* stream, GpImage **image)
|
||||
{
|
||||
return decode_image_wic(stream, &GUID_ContainerFormatIco, NULL, image);
|
||||
}
|
||||
|
||||
static GpStatus decode_image_bmp(IStream* stream, GpImage **image)
|
||||
{
|
||||
GpStatus status;
|
||||
GpBitmap* bitmap;
|
||||
|
||||
status = decode_image_wic(stream, &GUID_ContainerFormatBmp, active_frame, NULL, image);
|
||||
status = decode_image_wic(stream, &GUID_ContainerFormatBmp, NULL, image);
|
||||
|
||||
bitmap = (GpBitmap*)*image;
|
||||
|
||||
|
@ -3590,27 +3655,27 @@ static GpStatus decode_image_bmp(IStream* stream, REFCLSID clsid, UINT active_fr
|
|||
return status;
|
||||
}
|
||||
|
||||
static GpStatus decode_image_jpeg(IStream* stream, REFCLSID clsid, UINT active_frame, GpImage **image)
|
||||
static GpStatus decode_image_jpeg(IStream* stream, GpImage **image)
|
||||
{
|
||||
return decode_image_wic(stream, &GUID_ContainerFormatJpeg, active_frame, NULL, image);
|
||||
return decode_image_wic(stream, &GUID_ContainerFormatJpeg, NULL, image);
|
||||
}
|
||||
|
||||
static GpStatus decode_image_png(IStream* stream, REFCLSID clsid, UINT active_frame, GpImage **image)
|
||||
static GpStatus decode_image_png(IStream* stream, GpImage **image)
|
||||
{
|
||||
return decode_image_wic(stream, &GUID_ContainerFormatPng, active_frame, NULL, image);
|
||||
return decode_image_wic(stream, &GUID_ContainerFormatPng, NULL, image);
|
||||
}
|
||||
|
||||
static GpStatus decode_image_gif(IStream* stream, REFCLSID clsid, UINT active_frame, GpImage **image)
|
||||
static GpStatus decode_image_gif(IStream* stream, GpImage **image)
|
||||
{
|
||||
return decode_image_wic(stream, &GUID_ContainerFormatGif, active_frame, gif_metadata_reader, image);
|
||||
return decode_image_wic(stream, &GUID_ContainerFormatGif, gif_metadata_reader, image);
|
||||
}
|
||||
|
||||
static GpStatus decode_image_tiff(IStream* stream, REFCLSID clsid, UINT active_frame, GpImage **image)
|
||||
static GpStatus decode_image_tiff(IStream* stream, GpImage **image)
|
||||
{
|
||||
return decode_image_wic(stream, &GUID_ContainerFormatTiff, active_frame, NULL, image);
|
||||
return decode_image_wic(stream, &GUID_ContainerFormatTiff, NULL, image);
|
||||
}
|
||||
|
||||
static GpStatus decode_image_olepicture_metafile(IStream* stream, REFCLSID clsid, UINT active_frame, GpImage **image)
|
||||
static GpStatus decode_image_olepicture_metafile(IStream* stream, GpImage **image)
|
||||
{
|
||||
IPicture *pic;
|
||||
|
||||
|
@ -3629,7 +3694,7 @@ static GpStatus decode_image_olepicture_metafile(IStream* stream, REFCLSID clsid
|
|||
*image = GdipAlloc(sizeof(GpMetafile));
|
||||
if(!*image) return OutOfMemory;
|
||||
(*image)->type = ImageTypeMetafile;
|
||||
(*image)->stream = NULL;
|
||||
(*image)->decoder = NULL;
|
||||
(*image)->picture = pic;
|
||||
(*image)->flags = ImageFlagsNone;
|
||||
(*image)->frame_count = 1;
|
||||
|
@ -3644,12 +3709,15 @@ static GpStatus decode_image_olepicture_metafile(IStream* stream, REFCLSID clsid
|
|||
typedef GpStatus (*encode_image_func)(GpImage *image, IStream* stream,
|
||||
GDIPCONST CLSID* clsid, GDIPCONST EncoderParameters* params);
|
||||
|
||||
typedef GpStatus (*decode_image_func)(IStream *stream, REFCLSID clsid, UINT active_frame, GpImage **image);
|
||||
typedef GpStatus (*decode_image_func)(IStream *stream, GpImage **image);
|
||||
|
||||
typedef GpStatus (*select_image_func)(GpImage *image, UINT active_frame);
|
||||
|
||||
typedef struct image_codec {
|
||||
ImageCodecInfo info;
|
||||
encode_image_func encode_func;
|
||||
decode_image_func decode_func;
|
||||
select_image_func select_func;
|
||||
} image_codec;
|
||||
|
||||
typedef enum {
|
||||
|
@ -3718,10 +3786,7 @@ GpStatus WINGDIPAPI GdipImageSelectActiveFrame(GpImage *image, GDIPCONST GUID *d
|
|||
UINT frame)
|
||||
{
|
||||
GpStatus stat;
|
||||
LARGE_INTEGER seek;
|
||||
HRESULT hr;
|
||||
const struct image_codec *codec = NULL;
|
||||
GpImage *new_image;
|
||||
|
||||
TRACE("(%p,%s,%u)\n", image, debugstr_guid(dimensionID), frame);
|
||||
|
||||
|
@ -3749,6 +3814,12 @@ GpStatus WINGDIPAPI GdipImageSelectActiveFrame(GpImage *image, GDIPCONST GUID *d
|
|||
return Ok;
|
||||
}
|
||||
|
||||
if (!image->decoder)
|
||||
{
|
||||
TRACE("image doesn't have an associated decoder\n");
|
||||
return Ok;
|
||||
}
|
||||
|
||||
/* choose an appropriate image decoder */
|
||||
stat = get_decoder_info(image->stream, &codec);
|
||||
if (stat != Ok)
|
||||
|
@ -3757,29 +3828,7 @@ GpStatus WINGDIPAPI GdipImageSelectActiveFrame(GpImage *image, GDIPCONST GUID *d
|
|||
return stat;
|
||||
}
|
||||
|
||||
/* seek to the start of the stream */
|
||||
seek.QuadPart = 0;
|
||||
hr = IStream_Seek(image->stream, seek, STREAM_SEEK_SET, NULL);
|
||||
if (FAILED(hr))
|
||||
return hresult_to_status(hr);
|
||||
|
||||
/* call on the image decoder to do the real work */
|
||||
stat = codec->decode_func(image->stream, &codec->info.Clsid, frame, &new_image);
|
||||
|
||||
if (stat == Ok)
|
||||
{
|
||||
memcpy(&new_image->format, &codec->info.FormatID, sizeof(GUID));
|
||||
free_image_data(image);
|
||||
if (image->type == ImageTypeBitmap)
|
||||
*(GpBitmap *)image = *(GpBitmap *)new_image;
|
||||
else if (image->type == ImageTypeMetafile)
|
||||
*(GpMetafile *)image = *(GpMetafile *)new_image;
|
||||
new_image->type = ~0;
|
||||
GdipFree(new_image);
|
||||
return Ok;
|
||||
}
|
||||
|
||||
return stat;
|
||||
return codec->select_func(image, frame);
|
||||
}
|
||||
|
||||
GpStatus WINGDIPAPI GdipLoadImageFromStream(IStream *stream, GpImage **image)
|
||||
|
@ -3799,7 +3848,7 @@ GpStatus WINGDIPAPI GdipLoadImageFromStream(IStream *stream, GpImage **image)
|
|||
if (FAILED(hr)) return hresult_to_status(hr);
|
||||
|
||||
/* call on the image decoder to do the real work */
|
||||
stat = codec->decode_func(stream, &codec->info.Clsid, 0, image);
|
||||
stat = codec->decode_func(stream, image);
|
||||
|
||||
/* take note of the original data format */
|
||||
if (stat == Ok)
|
||||
|
@ -4212,7 +4261,8 @@ static const struct image_codec codecs[NUM_CODECS] = {
|
|||
/* SigMask */ bmp_sig_mask,
|
||||
},
|
||||
encode_image_BMP,
|
||||
decode_image_bmp
|
||||
decode_image_bmp,
|
||||
select_frame_wic
|
||||
},
|
||||
{
|
||||
{ /* JPEG */
|
||||
|
@ -4231,7 +4281,8 @@ static const struct image_codec codecs[NUM_CODECS] = {
|
|||
/* SigMask */ jpeg_sig_mask,
|
||||
},
|
||||
encode_image_jpeg,
|
||||
decode_image_jpeg
|
||||
decode_image_jpeg,
|
||||
select_frame_wic
|
||||
},
|
||||
{
|
||||
{ /* GIF */
|
||||
|
@ -4250,7 +4301,8 @@ static const struct image_codec codecs[NUM_CODECS] = {
|
|||
/* SigMask */ gif_sig_mask,
|
||||
},
|
||||
NULL,
|
||||
decode_image_gif
|
||||
decode_image_gif,
|
||||
select_frame_gif
|
||||
},
|
||||
{
|
||||
{ /* TIFF */
|
||||
|
@ -4269,7 +4321,8 @@ static const struct image_codec codecs[NUM_CODECS] = {
|
|||
/* SigMask */ tiff_sig_mask,
|
||||
},
|
||||
encode_image_tiff,
|
||||
decode_image_tiff
|
||||
decode_image_tiff,
|
||||
select_frame_wic
|
||||
},
|
||||
{
|
||||
{ /* EMF */
|
||||
|
@ -4288,7 +4341,8 @@ static const struct image_codec codecs[NUM_CODECS] = {
|
|||
/* SigMask */ emf_sig_mask,
|
||||
},
|
||||
NULL,
|
||||
decode_image_olepicture_metafile
|
||||
decode_image_olepicture_metafile,
|
||||
NULL
|
||||
},
|
||||
{
|
||||
{ /* WMF */
|
||||
|
@ -4307,7 +4361,8 @@ static const struct image_codec codecs[NUM_CODECS] = {
|
|||
/* SigMask */ wmf_sig_mask,
|
||||
},
|
||||
NULL,
|
||||
decode_image_olepicture_metafile
|
||||
decode_image_olepicture_metafile,
|
||||
NULL
|
||||
},
|
||||
{
|
||||
{ /* PNG */
|
||||
|
@ -4326,7 +4381,8 @@ static const struct image_codec codecs[NUM_CODECS] = {
|
|||
/* SigMask */ png_sig_mask,
|
||||
},
|
||||
encode_image_png,
|
||||
decode_image_png
|
||||
decode_image_png,
|
||||
select_frame_wic
|
||||
},
|
||||
{
|
||||
{ /* ICO */
|
||||
|
@ -4345,7 +4401,8 @@ static const struct image_codec codecs[NUM_CODECS] = {
|
|||
/* SigMask */ ico_sig_mask,
|
||||
},
|
||||
NULL,
|
||||
decode_image_icon
|
||||
decode_image_icon,
|
||||
select_frame_wic
|
||||
},
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue