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;