Signed-off-by: Florian Will florian.will@gmail.com --- v2: Use the new terminate_encoder_wic() function signature from patch 1/5 (which simplifies things). Changes related to the GpImage "encoder" field dropped from this patch because they have been moved to patch 1. --- dlls/gdiplus/image.c | 54 ++++++++++++++++++++++++++++++++------ dlls/gdiplus/tests/image.c | 24 ++++++++--------- 2 files changed, 58 insertions(+), 20 deletions(-)
diff --git a/dlls/gdiplus/image.c b/dlls/gdiplus/image.c index 94c03ede19..28ccc78400 100644 --- a/dlls/gdiplus/image.c +++ b/dlls/gdiplus/image.c @@ -4426,6 +4426,9 @@ GpStatus WINGDIPAPI GdipSaveImageToFile(GpImage *image, GDIPCONST WCHAR* filenam if (!image || !filename|| !clsidEncoder) return InvalidParameter;
+ /* this might release an old file stream held by the encoder so we can re-create it below */ + terminate_encoder_wic(image); + stat = GdipCreateStreamOnFile(filename, GENERIC_WRITE, &stream); if (stat != Ok) return GenericError; @@ -4598,6 +4601,27 @@ static GpStatus encode_frame_wic(IWICBitmapEncoder *encoder, GpImage *image) return hresult_to_status(hr); }
+static BOOL has_encoder_param_long(GDIPCONST EncoderParameters *params, GUID param_guid, ULONG val) +{ + if (!params) + return FALSE; + + for (int param_idx = 0; param_idx < params->Count; param_idx++) + { + EncoderParameter param = params->Parameter[param_idx]; + if (param.Type == EncoderParameterValueTypeLong && IsEqualCLSID(¶m.Guid, ¶m_guid)) + { + ULONG *value_array = (ULONG*) param.Value; + for (int value_idx = 0; value_idx < param.NumberOfValues; value_idx++) + { + if (value_array[value_idx] == val) + return TRUE; + } + } + } + return FALSE; +} + static GpStatus encode_image_wic(GpImage *image, IStream *stream, REFGUID container, GDIPCONST EncoderParameters *params) { @@ -4611,10 +4635,13 @@ static GpStatus encode_image_wic(GpImage *image, IStream *stream, if (status == Ok) status = encode_frame_wic(image->encoder, image);
- /* always try to terminate, but if something already failed earlier, keep the old status. */ - terminate_status = terminate_encoder_wic(image); - if (status == Ok) - status = terminate_status; + if (!has_encoder_param_long(params, EncoderSaveFlag, EncoderValueMultiFrame)) + { + /* always try to terminate, but if something already failed earlier, keep the old status. */ + terminate_status = terminate_encoder_wic(image); + if (status == Ok) + status = terminate_status; + }
return status; } @@ -4687,8 +4714,7 @@ GpStatus WINGDIPAPI GdipSaveImageToStream(GpImage *image, IStream* stream, */ GpStatus WINGDIPAPI GdipSaveAdd(GpImage *image, GDIPCONST EncoderParameters *params) { - FIXME("(%p,%p): stub\n", image, params); - return NotImplemented; + return GdipSaveAddImage(image, image, params); }
/***************************************************************************** @@ -4704,8 +4730,20 @@ GpStatus WINGDIPAPI GdipSaveAdd(GpImage *image, GDIPCONST EncoderParameters *par GpStatus WINGDIPAPI GdipSaveAddImage(GpImage *image, GpImage *additional_image, GDIPCONST EncoderParameters *params) { - FIXME("(%p,%p,%p): stub\n", image, additional_image, params); - return NotImplemented; + TRACE("%p, %p, %p\n", image, additional_image, params); + + if (!image || !additional_image || !params) + return InvalidParameter; + + if (!image->encoder) + return Win32Error; + + if (has_encoder_param_long(params, EncoderSaveFlag, EncoderValueFlush)) + return terminate_encoder_wic(image); + else if (has_encoder_param_long(params, EncoderSaveFlag, EncoderValueFrameDimensionPage)) + return encode_frame_wic(image->encoder, additional_image); + else + return InvalidParameter; }
/***************************************************************************** diff --git a/dlls/gdiplus/tests/image.c b/dlls/gdiplus/tests/image.c index 01d79f08c4..bbb9365edb 100644 --- a/dlls/gdiplus/tests/image.c +++ b/dlls/gdiplus/tests/image.c @@ -552,41 +552,41 @@ static void test_SavingMultiPageTiff(void)
/* invalid params: NULL */ stat = GdipSaveAdd(0, ¶ms); - todo_wine expect(InvalidParameter, stat); + expect(InvalidParameter, stat); stat = GdipSaveAdd((GpImage*)bm1, 0); - todo_wine expect(InvalidParameter, stat); + expect(InvalidParameter, stat);
stat = GdipSaveAddImage((GpImage*)bm1, (GpImage*)bm2, 0); - todo_wine expect(InvalidParameter, stat); + expect(InvalidParameter, stat); stat = GdipSaveAddImage((GpImage*)bm1, 0, ¶ms); - todo_wine expect(InvalidParameter, stat); + expect(InvalidParameter, stat); stat = GdipSaveAddImage(0, (GpImage*)bm2, ¶ms); - todo_wine expect(InvalidParameter, stat); + expect(InvalidParameter, stat);
/* win32 error: SaveAdd() can only be called after Save() with the MultiFrame param */ stat = GdipSaveAdd((GpImage*)bm1, ¶ms); - todo_wine expect(Win32Error, stat); + expect(Win32Error, stat); stat = GdipSaveAddImage((GpImage*)bm1, (GpImage*)bm2, ¶ms); - todo_wine expect(Win32Error, stat); + expect(Win32Error, stat);
stat = GdipSaveImageToFile((GpImage*)bm1, filename1, &tiff_clsid, 0); /* param not set! */ expect(Ok, stat); if (stat != Ok) goto cleanup;
stat = GdipSaveAdd((GpImage*)bm1, ¶ms); - todo_wine expect(Win32Error, stat); + expect(Win32Error, stat); stat = GdipSaveAddImage((GpImage*)bm1, (GpImage*)bm2, ¶ms); - todo_wine expect(Win32Error, stat); + expect(Win32Error, stat);
/* win32 error: can't flush before starting the encoding process */ paramValue = EncoderValueFlush; stat = GdipSaveAdd((GpImage*)bm1, ¶ms); - todo_wine expect(Win32Error, stat); + expect(Win32Error, stat);
/* win32 error: can't start encoding process through SaveAdd(), only Save() */ paramValue = EncoderValueMultiFrame; stat = GdipSaveAdd((GpImage*)bm1, ¶ms); - todo_wine expect(Win32Error, stat); + expect(Win32Error, stat);
/* start encoding process: add first frame (bm1) */ paramValue = EncoderValueMultiFrame; @@ -600,7 +600,7 @@ static void test_SavingMultiPageTiff(void) /* add second frame (bm2) */ paramValue = EncoderValueFrameDimensionPage; stat = GdipSaveAddImage((GpImage*)bm1, (GpImage*)bm2, ¶ms); - todo_wine expect(Ok, stat); + expect(Ok, stat); if (stat != Ok) goto cleanup;
/* finish encoding process */