Signed-off-by: Esme Povirk <esme(a)codeweavers.com>
---
dlls/windowscodecs/libpng.c | 55 ++++++++++++++++++++++++++
dlls/windowscodecs/pngformat.c | 42 ++++++++++++++------
dlls/windowscodecs/unix_iface.c | 50 +++++++++++++++++++++++
dlls/windowscodecs/unix_lib.c | 12 +++++-
dlls/windowscodecs/wincodecs_common.h | 5 +++
dlls/windowscodecs/wincodecs_private.h | 34 ++++++++++++++++
6 files changed, 186 insertions(+), 12 deletions(-)
diff --git a/dlls/windowscodecs/libpng.c b/dlls/windowscodecs/libpng.c
index 93ff6e056ec..fd1ee679ec3 100644
--- a/dlls/windowscodecs/libpng.c
+++ b/dlls/windowscodecs/libpng.c
@@ -611,6 +611,55 @@ HRESULT CDECL png_decoder_create(struct decoder_info *info, struct decoder **res
return S_OK;
}
+struct png_encoder
+{
+ struct encoder encoder;
+};
+
+static inline struct png_encoder *impl_from_encoder(struct encoder* iface)
+{
+ return CONTAINING_RECORD(iface, struct png_encoder, encoder);
+}
+
+static void CDECL png_encoder_destroy(struct encoder *encoder)
+{
+ struct png_encoder *This = impl_from_encoder(encoder);
+ RtlFreeHeap(GetProcessHeap(), 0, This);
+}
+
+static const struct encoder_funcs png_encoder_vtable = {
+ png_encoder_destroy
+};
+
+HRESULT CDECL png_encoder_create(struct encoder_info *info, struct encoder **result)
+{
+ struct png_encoder *This;
+
+ if (!load_libpng())
+ {
+ ERR("Failed reading PNG because unable to find %s\n",SONAME_LIBPNG);
+ return E_FAIL;
+ }
+
+ This = RtlAllocateHeap(GetProcessHeap(), 0, sizeof(*This));
+
+ if (!This)
+ {
+ return E_OUTOFMEMORY;
+ }
+
+ This->encoder.vtable = &png_encoder_vtable;
+ *result = &This->encoder;
+
+ info->container_format = GUID_ContainerFormatPng;
+ info->clsid = CLSID_WICPngEncoder;
+ info->encoder_options[0] = ENCODER_OPTION_INTERLACE;
+ info->encoder_options[1] = ENCODER_OPTION_FILTER;
+ info->encoder_options[2] = ENCODER_OPTION_END;
+
+ return S_OK;
+}
+
#else
HRESULT CDECL png_decoder_create(struct decoder_info *info, struct decoder **result)
@@ -619,4 +668,10 @@ HRESULT CDECL png_decoder_create(struct decoder_info *info, struct decoder **res
return E_FAIL;
}
+HRESULT CDECL png_encoder_create(struct encoder_info *info, struct encoder **result)
+{
+ ERR("Trying to save PNG picture, but PNG support is not compiled in.\n");
+ return E_FAIL;
+}
+
#endif
diff --git a/dlls/windowscodecs/pngformat.c b/dlls/windowscodecs/pngformat.c
index 9d24096b2cd..f0ac83dae1c 100644
--- a/dlls/windowscodecs/pngformat.c
+++ b/dlls/windowscodecs/pngformat.c
@@ -309,9 +309,6 @@ static CRITICAL_SECTION_DEBUG init_png_cs_debug =
};
static CRITICAL_SECTION init_png_cs = { &init_png_cs_debug, -1, 0, 0, 0, 0 };
-static const WCHAR wszPngInterlaceOption[] = {'I','n','t','e','r','l','a','c','e','O','p','t','i','o','n',0};
-static const WCHAR wszPngFilterOption[] = {'F','i','l','t','e','r','O','p','t','i','o','n',0};
-
static void *load_libpng(void)
{
void *result;
@@ -392,6 +389,14 @@ static void user_warning_fn(png_structp png_ptr, png_const_charp warning_message
WARN("PNG warning: %s\n", debugstr_a(warning_message));
}
+static const WCHAR wszPngInterlaceOption[] = {'I','n','t','e','r','l','a','c','e','O','p','t','i','o','n',0};
+static const WCHAR wszPngFilterOption[] = {'F','i','l','t','e','r','O','p','t','i','o','n',0};
+
+static const PROPBAG2 encoder_option_properties[ENCODER_OPTION_END] = {
+ { PROPBAG2_TYPE_DATA, VT_BOOL, 0, 0, (LPOLESTR)wszPngInterlaceOption },
+ { PROPBAG2_TYPE_DATA, VT_UI1, 0, 0, (LPOLESTR)wszPngFilterOption }
+};
+
struct png_pixelformat {
const WICPixelFormatGUID *guid;
UINT bpp;
@@ -426,6 +431,8 @@ typedef struct PngEncoder {
IStream *stream;
png_structp png_ptr;
png_infop info_ptr;
+ struct encoder *encoder;
+ struct encoder_info encoder_info;
UINT frame_count;
BOOL frame_initialized;
const struct png_pixelformat *format;
@@ -964,6 +971,7 @@ static ULONG WINAPI PngEncoder_Release(IWICBitmapEncoder *iface)
if (This->stream)
IStream_Release(This->stream);
HeapFree(GetProcessHeap(), 0, This->data);
+ encoder_destroy(This->encoder);
HeapFree(GetProcessHeap(), 0, This);
}
@@ -1045,17 +1053,19 @@ static HRESULT WINAPI PngEncoder_Initialize(IWICBitmapEncoder *iface,
static HRESULT WINAPI PngEncoder_GetContainerFormat(IWICBitmapEncoder *iface, GUID *format)
{
+ PngEncoder *This = impl_from_IWICBitmapEncoder(iface);
TRACE("(%p,%p)\n", iface, format);
if (!format)
return E_INVALIDARG;
- memcpy(format, &GUID_ContainerFormatPng, sizeof(*format));
+ memcpy(format, &This->encoder_info.container_format, sizeof(*format));
return S_OK;
}
static HRESULT WINAPI PngEncoder_GetEncoderInfo(IWICBitmapEncoder *iface, IWICBitmapEncoderInfo **info)
{
+ PngEncoder *This = impl_from_IWICBitmapEncoder(iface);
IWICComponentInfo *comp_info;
HRESULT hr;
@@ -1063,7 +1073,7 @@ static HRESULT WINAPI PngEncoder_GetEncoderInfo(IWICBitmapEncoder *iface, IWICBi
if (!info) return E_INVALIDARG;
- hr = CreateComponentInfo(&CLSID_WICPngEncoder, &comp_info);
+ hr = CreateComponentInfo(&This->encoder_info.clsid, &comp_info);
if (hr == S_OK)
{
hr = IWICComponentInfo_QueryInterface(comp_info, &IID_IWICBitmapEncoderInfo, (void **)info);
@@ -1112,11 +1122,8 @@ static HRESULT WINAPI PngEncoder_CreateNewFrame(IWICBitmapEncoder *iface,
{
PngEncoder *This = impl_from_IWICBitmapEncoder(iface);
HRESULT hr;
- static const PROPBAG2 opts[2] =
- {
- { PROPBAG2_TYPE_DATA, VT_BOOL, 0, 0, (LPOLESTR)wszPngInterlaceOption },
- { PROPBAG2_TYPE_DATA, VT_UI1, 0, 0, (LPOLESTR)wszPngFilterOption },
- };
+ DWORD opts_length;
+ PROPBAG2 opts[6];
TRACE("(%p,%p,%p)\n", iface, ppIFrameEncode, ppIEncoderOptions);
@@ -1136,7 +1143,12 @@ static HRESULT WINAPI PngEncoder_CreateNewFrame(IWICBitmapEncoder *iface,
if (ppIEncoderOptions)
{
- hr = CreatePropertyBag2(opts, ARRAY_SIZE(opts), ppIEncoderOptions);
+ for (opts_length = 0; This->encoder_info.encoder_options[opts_length] < ENCODER_OPTION_END; opts_length++)
+ {
+ opts[opts_length] = encoder_option_properties[This->encoder_info.encoder_options[opts_length]];
+ }
+
+ hr = CreatePropertyBag2(opts, opts_length, ppIEncoderOptions);
if (FAILED(hr))
{
LeaveCriticalSection(&This->lock);
@@ -1215,6 +1227,14 @@ HRESULT PngEncoder_CreateInstance(REFIID iid, void** ppv)
This = HeapAlloc(GetProcessHeap(), 0, sizeof(PngEncoder));
if (!This) return E_OUTOFMEMORY;
+ ret = get_unix_encoder(&CLSID_WICPngEncoder, &This->encoder_info, &This->encoder);
+
+ if (FAILED(ret))
+ {
+ HeapFree(GetProcessHeap(), 0, This);
+ return ret;
+ }
+
This->IWICBitmapEncoder_iface.lpVtbl = &PngEncoder_Vtbl;
This->IWICBitmapFrameEncode_iface.lpVtbl = &PngEncoder_FrameVtbl;
This->ref = 1;
diff --git a/dlls/windowscodecs/unix_iface.c b/dlls/windowscodecs/unix_iface.c
index 5ed995e7642..80769b5d560 100644
--- a/dlls/windowscodecs/unix_iface.c
+++ b/dlls/windowscodecs/unix_iface.c
@@ -143,3 +143,53 @@ HRESULT get_unix_decoder(const CLSID *decoder_clsid, struct decoder_info *info,
return hr;
}
+
+struct encoder_wrapper
+{
+ struct encoder win32_encoder;
+ struct encoder *unix_encoder;
+};
+
+static inline struct encoder_wrapper *impl_from_encoder(struct encoder* iface)
+{
+ return CONTAINING_RECORD(iface, struct encoder_wrapper, win32_encoder);
+}
+
+void CDECL encoder_wrapper_destroy(struct encoder* iface)
+{
+ struct encoder_wrapper* This = impl_from_encoder(iface);
+ unix_funcs->encoder_destroy(This->unix_encoder);
+ HeapFree(GetProcessHeap(), 0, This);
+}
+
+static const struct encoder_funcs encoder_wrapper_vtable = {
+ encoder_wrapper_destroy
+};
+
+HRESULT get_unix_encoder(const CLSID *encoder_clsid, struct encoder_info *info, struct encoder **result)
+{
+ HRESULT hr;
+ struct encoder_wrapper *wrapper;
+ struct encoder *unix_encoder;
+
+ init_unixlib();
+
+ hr = unix_funcs->encoder_create(encoder_clsid, info, &unix_encoder);
+
+ if (SUCCEEDED(hr))
+ {
+ wrapper = HeapAlloc(GetProcessHeap(), 0, sizeof(*wrapper));
+
+ if (!wrapper)
+ {
+ unix_funcs->encoder_destroy(unix_encoder);
+ return E_OUTOFMEMORY;
+ }
+
+ wrapper->win32_encoder.vtable = &encoder_wrapper_vtable;
+ wrapper->unix_encoder = unix_encoder;
+ *result = &wrapper->win32_encoder;
+ }
+
+ return hr;
+}
diff --git a/dlls/windowscodecs/unix_lib.c b/dlls/windowscodecs/unix_lib.c
index dc8549e1eb8..b0c6b37bfce 100644
--- a/dlls/windowscodecs/unix_lib.c
+++ b/dlls/windowscodecs/unix_lib.c
@@ -76,6 +76,14 @@ HRESULT CDECL decoder_create(const CLSID *decoder_clsid, struct decoder_info *in
return E_NOTIMPL;
}
+HRESULT CDECL encoder_create(const CLSID *encoder_clsid, struct encoder_info *info, struct encoder **result)
+{
+ if (IsEqualGUID(encoder_clsid, &CLSID_WICPngEncoder))
+ return png_encoder_create(info, result);
+
+ return E_NOTIMPL;
+}
+
static const struct unix_funcs unix_funcs = {
decoder_create,
decoder_initialize,
@@ -83,7 +91,9 @@ static const struct unix_funcs unix_funcs = {
decoder_copy_pixels,
decoder_get_metadata_blocks,
decoder_get_color_context,
- decoder_destroy
+ decoder_destroy,
+ encoder_create,
+ encoder_destroy
};
NTSTATUS CDECL __wine_init_unix_lib( HMODULE module, DWORD reason, const void *ptr_in, void *ptr_out )
diff --git a/dlls/windowscodecs/wincodecs_common.h b/dlls/windowscodecs/wincodecs_common.h
index b7572d69df4..303c2d9f38b 100644
--- a/dlls/windowscodecs/wincodecs_common.h
+++ b/dlls/windowscodecs/wincodecs_common.h
@@ -48,6 +48,11 @@ void CDECL decoder_destroy(struct decoder *decoder)
decoder->vtable->destroy(decoder);
}
+void CDECL encoder_destroy(struct encoder *encoder)
+{
+ encoder->vtable->destroy(encoder);
+}
+
HRESULT copy_pixels(UINT bpp, const BYTE *srcbuffer,
UINT srcwidth, UINT srcheight, INT srcstride,
const WICRect *rc, UINT dststride, UINT dstbuffersize, BYTE *dstbuffer)
diff --git a/dlls/windowscodecs/wincodecs_private.h b/dlls/windowscodecs/wincodecs_private.h
index d60b281faef..8495ea73521 100644
--- a/dlls/windowscodecs/wincodecs_private.h
+++ b/dlls/windowscodecs/wincodecs_private.h
@@ -332,10 +332,41 @@ HRESULT CDECL decoder_get_color_context(struct decoder* This, UINT frame, UINT n
BYTE **data, DWORD *datasize);
void CDECL decoder_destroy(struct decoder *This);
+struct encoder_funcs;
+
+/* sync with encoder_option_properties */
+enum encoder_option
+{
+ ENCODER_OPTION_INTERLACE,
+ ENCODER_OPTION_FILTER,
+ ENCODER_OPTION_END
+};
+
+struct encoder_info
+{
+ GUID container_format;
+ CLSID clsid;
+ DWORD encoder_options[7];
+};
+
+struct encoder
+{
+ const struct encoder_funcs *vtable;
+};
+
+struct encoder_funcs
+{
+ void (CDECL *destroy)(struct encoder* This);
+};
+
+void CDECL encoder_destroy(struct encoder* This);
+
HRESULT CDECL png_decoder_create(struct decoder_info *info, struct decoder **result);
HRESULT CDECL tiff_decoder_create(struct decoder_info *info, struct decoder **result);
HRESULT CDECL jpeg_decoder_create(struct decoder_info *info, struct decoder **result);
+HRESULT CDECL png_encoder_create(struct encoder_info *info, struct encoder **result);
+
struct unix_funcs
{
HRESULT (CDECL *decoder_create)(const CLSID *decoder_clsid, struct decoder_info *info, struct decoder **result);
@@ -348,9 +379,12 @@ struct unix_funcs
HRESULT (CDECL *decoder_get_color_context)(struct decoder* This, UINT frame, UINT num,
BYTE **data, DWORD *datasize);
void (CDECL *decoder_destroy)(struct decoder* This);
+ HRESULT (CDECL *encoder_create)(const CLSID *encoder_clsid, struct encoder_info *info, struct encoder **result);
+ void (CDECL *encoder_destroy)(struct encoder* This);
};
HRESULT get_unix_decoder(const CLSID *decoder_clsid, struct decoder_info *info, struct decoder **result);
+HRESULT get_unix_encoder(const CLSID *encoder_clsid, struct encoder_info *info, struct encoder **result);
extern HRESULT CommonDecoder_CreateInstance(struct decoder *decoder,
const struct decoder_info *decoder_info, REFIID iid, void** ppv) DECLSPEC_HIDDEN;
--
2.17.1