[PATCH 5/5] gdiplus: Implement GdipSaveAddImage() and GdipSaveAdd().
Florian Will
florian.will at gmail.com
Mon Feb 17 04:00:47 CST 2020
Signed-off-by: Florian Will <florian.will at gmail.com>
---
dlls/gdiplus/gdiplus_private.h | 1 +
dlls/gdiplus/image.c | 67 +++++++++++++++++++++++++++++++---
dlls/gdiplus/tests/image.c | 24 ++++++------
3 files changed, 75 insertions(+), 17 deletions(-)
diff --git a/dlls/gdiplus/gdiplus_private.h b/dlls/gdiplus/gdiplus_private.h
index 36e79e29eb..12d7e32dda 100644
--- a/dlls/gdiplus/gdiplus_private.h
+++ b/dlls/gdiplus/gdiplus_private.h
@@ -347,6 +347,7 @@ struct GpAdjustableArrowCap{
struct GpImage{
IWICBitmapDecoder *decoder;
+ IWICBitmapEncoder *encoder; /* set during multi-frame save (GdipSaveAdd functions) */
ImageType type;
GUID format;
UINT flags;
diff --git a/dlls/gdiplus/image.c b/dlls/gdiplus/image.c
index 94d9344082..263b796b18 100644
--- a/dlls/gdiplus/image.c
+++ b/dlls/gdiplus/image.c
@@ -1827,6 +1827,7 @@ GpStatus WINGDIPAPI GdipCreateBitmapFromScan0(INT width, INT height, INT stride,
(*bitmap)->height = height;
(*bitmap)->format = format;
(*bitmap)->image.decoder = NULL;
+ (*bitmap)->image.encoder = NULL;
(*bitmap)->hbitmap = hbitmap;
(*bitmap)->hdc = NULL;
(*bitmap)->bits = bits;
@@ -2046,6 +2047,9 @@ static void move_bitmap(GpBitmap *dst, GpBitmap *src, BOOL clobber_palette)
if (dst->image.decoder)
IWICBitmapDecoder_Release(dst->image.decoder);
dst->image.decoder = src->image.decoder;
+ if (dst->image.encoder)
+ terminate_encoder_wic(dst->image.encoder);
+ dst->image.encoder = src->image.encoder;
dst->image.frame_count = src->image.frame_count;
dst->image.current_frame = src->image.current_frame;
dst->image.format = src->image.format;
@@ -2078,6 +2082,8 @@ static GpStatus free_image_data(GpImage *image)
}
if (image->decoder)
IWICBitmapDecoder_Release(image->decoder);
+ if (image->encoder)
+ terminate_encoder_wic(image->encoder);
heap_free(image->palette);
return Ok;
@@ -3744,6 +3750,8 @@ static GpStatus select_frame_wic(GpImage *image, UINT active_frame)
new_image->busy = image->busy;
memcpy(&new_image->format, &image->format, sizeof(GUID));
+ new_image->encoder = image->encoder;
+ image->encoder = NULL;
free_image_data(image);
if (image->type == ImageTypeBitmap)
*(GpBitmap *)image = *(GpBitmap *)new_image;
@@ -4420,6 +4428,13 @@ GpStatus WINGDIPAPI GdipSaveImageToFile(GpImage *image, GDIPCONST WCHAR* filenam
if (!image || !filename|| !clsidEncoder)
return InvalidParameter;
+ if (image->encoder)
+ {
+ /* this might release an old file stream held by the encoder so we can re-create it below */
+ terminate_encoder_wic(image->encoder);
+ image->encoder = NULL;
+ }
+
stat = GdipCreateStreamOnFile(filename, GENERIC_WRITE, &stream);
if (stat != Ok)
return GenericError;
@@ -4581,21 +4596,48 @@ 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)
{
IWICBitmapEncoder *encoder = NULL;
GpStatus status;
+ BOOL is_multi_frame = has_encoder_param_long(params, EncoderSaveFlag, EncoderValueMultiFrame);
if (image->type != ImageTypeBitmap)
return GenericError;
+ if (is_multi_frame && image->encoder != NULL)
+ terminate_encoder_wic(image->encoder);
+
status = initialize_encoder_wic(stream, container, &encoder);
if (status == Ok)
status = encode_frame_wic(encoder, image);
- if (encoder)
+ if (is_multi_frame)
+ image->encoder = encoder;
+ else if (encoder)
{
GpStatus terminate_status = terminate_encoder_wic(encoder);
if (status == Ok)
@@ -4673,8 +4715,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);
}
/*****************************************************************************
@@ -4690,8 +4731,24 @@ 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))
+ {
+ GpStatus status = terminate_encoder_wic(image->encoder);
+ image->encoder = NULL;
+ return status;
+ }
+ 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 */
--
2.20.1
More information about the wine-devel
mailing list