From 5107ef7566ea91f9319c7900addd88dd6c9a3445 Mon Sep 17 00:00:00 2001 From: Nikolay Sivov Date: Thu, 24 Nov 2016 12:23:28 +0300 Subject: [PATCH] wincodecs: Implement FilterOption property for PNG encoder. Signed-off-by: Nikolay Sivov Signed-off-by: Vincent Povirk Signed-off-by: Alexandre Julliard --- dlls/windowscodecs/pngformat.c | 63 ++++++++++++++++++++++------ dlls/windowscodecs/tests/converter.c | 19 ++++++++- include/wincodec.idl | 11 +++++ 3 files changed, 79 insertions(+), 14 deletions(-) diff --git a/dlls/windowscodecs/pngformat.c b/dlls/windowscodecs/pngformat.c index bb2aef9f9de..9a841626ab9 100644 --- a/dlls/windowscodecs/pngformat.c +++ b/dlls/windowscodecs/pngformat.c @@ -39,8 +39,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(wincodecs); -static const WCHAR wszPngInterlaceOption[] = {'I','n','t','e','r','l','a','c','e','O','p','t','i','o','n',0}; - static inline ULONG read_ulong_be(BYTE* data) { return data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3]; @@ -327,6 +325,7 @@ MAKE_FUNCPTR(png_set_expand_gray_1_2_4_to_8); MAKE_FUNCPTR(png_set_gray_1_2_4_to_8); #endif MAKE_FUNCPTR(png_set_filler); +MAKE_FUNCPTR(png_set_filter); MAKE_FUNCPTR(png_set_gray_to_rgb); MAKE_FUNCPTR(png_set_interlace_handling); MAKE_FUNCPTR(png_set_IHDR); @@ -353,6 +352,9 @@ 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 +394,7 @@ static void *load_libpng(void) LOAD_FUNCPTR(png_set_gray_1_2_4_to_8); #endif LOAD_FUNCPTR(png_set_filler); + LOAD_FUNCPTR(png_set_filter); LOAD_FUNCPTR(png_set_gray_to_rgb); LOAD_FUNCPTR(png_set_interlace_handling); LOAD_FUNCPTR(png_set_IHDR); @@ -1356,6 +1359,7 @@ typedef struct PngEncoder { BOOL committed; CRITICAL_SECTION lock; BOOL interlace; + WICPngFilterOption filter; BYTE *data; UINT stride; UINT passes; @@ -1410,31 +1414,44 @@ static HRESULT WINAPI PngFrameEncode_Initialize(IWICBitmapFrameEncode *iface, IPropertyBag2 *pIEncoderOptions) { PngEncoder *This = impl_from_IWICBitmapFrameEncode(iface); + WICPngFilterOption filter; BOOL interlace; - PROPBAG2 opts[1]= {{0}}; - VARIANT opt_values[1]; - HRESULT opt_hres[1]; + PROPBAG2 opts[2]= {{0}}; + VARIANT opt_values[2]; + HRESULT opt_hres[2]; HRESULT hr; TRACE("(%p,%p)\n", iface, pIEncoderOptions); opts[0].pstrName = (LPOLESTR)wszPngInterlaceOption; opts[0].vt = VT_BOOL; + opts[1].pstrName = (LPOLESTR)wszPngFilterOption; + opts[1].vt = VT_UI1; if (pIEncoderOptions) { - hr = IPropertyBag2_Read(pIEncoderOptions, 1, opts, NULL, opt_values, opt_hres); + hr = IPropertyBag2_Read(pIEncoderOptions, sizeof(opts)/sizeof(opts[0]), opts, NULL, opt_values, opt_hres); if (FAILED(hr)) return hr; + + if (V_VT(&opt_values[0]) == VT_EMPTY) + interlace = FALSE; + else + interlace = (V_BOOL(&opt_values[0]) != 0); + + filter = V_UI1(&opt_values[1]); + if (filter > WICPngFilterAdaptive) + { + WARN("Unrecognized filter option value %u.\n", filter); + filter = WICPngFilterUnspecified; + } } else - memset(opt_values, 0, sizeof(opt_values)); - - if (V_VT(&opt_values[0]) == VT_EMPTY) + { interlace = FALSE; - else - interlace = (V_BOOL(&opt_values[0]) != 0); + filter = WICPngFilterUnspecified; + } EnterCriticalSection(&This->lock); @@ -1445,6 +1462,7 @@ static HRESULT WINAPI PngFrameEncode_Initialize(IWICBitmapFrameEncode *iface, } This->interlace = interlace; + This->filter = filter; This->frame_initialized = TRUE; @@ -1617,6 +1635,22 @@ static HRESULT WINAPI PngFrameEncode_WritePixels(IWICBitmapFrameEncode *iface, if (This->interlace) This->passes = ppng_set_interlace_handling(This->png_ptr); + if (This->filter != WICPngFilterUnspecified) + { + static const int png_filter_map[] = + { + /* WICPngFilterUnspecified */ PNG_NO_FILTERS, + /* WICPngFilterNone */ PNG_FILTER_NONE, + /* WICPngFilterSub */ PNG_FILTER_SUB, + /* WICPngFilterUp */ PNG_FILTER_UP, + /* WICPngFilterAverage */ PNG_FILTER_AVG, + /* WICPngFilterPaeth */ PNG_FILTER_PAETH, + /* WICPngFilterAdaptive */ PNG_ALL_FILTERS, + }; + + ppng_set_filter(This->png_ptr, 0, png_filter_map[This->filter]); + } + This->info_written = TRUE; } @@ -1926,7 +1960,7 @@ static HRESULT WINAPI PngEncoder_CreateNewFrame(IWICBitmapEncoder *iface, { PngEncoder *This = impl_from_IWICBitmapEncoder(iface); HRESULT hr; - PROPBAG2 opts[1]= {{0}}; + PROPBAG2 opts[2]= {{0}}; TRACE("(%p,%p,%p)\n", iface, ppIFrameEncode, ppIEncoderOptions); @@ -1947,8 +1981,11 @@ static HRESULT WINAPI PngEncoder_CreateNewFrame(IWICBitmapEncoder *iface, opts[0].pstrName = (LPOLESTR)wszPngInterlaceOption; opts[0].vt = VT_BOOL; opts[0].dwType = PROPBAG2_TYPE_DATA; + opts[1].pstrName = (LPOLESTR)wszPngFilterOption; + opts[1].vt = VT_UI1; + opts[1].dwType = PROPBAG2_TYPE_DATA; - hr = CreatePropertyBag2(opts, 1, ppIEncoderOptions); + hr = CreatePropertyBag2(opts, sizeof(opts)/sizeof(opts[0]), ppIEncoderOptions); if (FAILED(hr)) { LeaveCriticalSection(&This->lock); diff --git a/dlls/windowscodecs/tests/converter.c b/dlls/windowscodecs/tests/converter.c index 7ca201a2697..2af985785cf 100644 --- a/dlls/windowscodecs/tests/converter.c +++ b/dlls/windowscodecs/tests/converter.c @@ -418,11 +418,13 @@ typedef struct property_opt_test_data VARTYPE initial_var_type; int i_init_val; float f_init_val; + BOOL skippable; } property_opt_test_data; static const WCHAR wszTiffCompressionMethod[] = {'T','i','f','f','C','o','m','p','r','e','s','s','i','o','n','M','e','t','h','o','d',0}; static const WCHAR wszCompressionQuality[] = {'C','o','m','p','r','e','s','s','i','o','n','Q','u','a','l','i','t','y',0}; static const WCHAR wszInterlaceOption[] = {'I','n','t','e','r','l','a','c','e','O','p','t','i','o','n',0}; +static const WCHAR wszFilterOption[] = {'F','i','l','t','e','r','O','p','t','i','o','n',0}; static const struct property_opt_test_data testdata_tiff_props[] = { { wszTiffCompressionMethod, VT_UI1, VT_UI1, WICTiffCompressionDontCare }, @@ -430,6 +432,12 @@ static const struct property_opt_test_data testdata_tiff_props[] = { { NULL } }; +static const struct property_opt_test_data testdata_png_props[] = { + { wszInterlaceOption, VT_BOOL, VT_BOOL, 0 }, + { wszFilterOption, VT_UI1, VT_UI1, WICPngFilterUnspecified, 0.0f, TRUE /* not supported on XP/2k3 */}, + { NULL } +}; + static int find_property_index(const WCHAR* name, PROPBAG2* all_props, int all_prop_cnt) { int i; @@ -456,6 +464,13 @@ static void test_specific_encoder_properties(IPropertyBag2 *options, const prope hr = IPropertyBag2_Read(options, 1, &pb, NULL, &pvarValue, &phrError); + if (data[i].skippable && idx == -1) + { + win_skip("Property %s is not supported on this machine.\n", wine_dbgstr_w(data[i].name)); + i++; + continue; + } + ok(idx >= 0, "Property %s not in output of GetPropertyInfo\n", wine_dbgstr_w(data[i].name)); if (idx >= 0) @@ -543,8 +558,10 @@ static void test_encoder_properties(const CLSID* clsid_encoder, IPropertyBag2 *o (int)cProperties, (int)cProperties2); } - if (clsid_encoder == &CLSID_WICTiffEncoder) + if (IsEqualCLSID(clsid_encoder, &CLSID_WICTiffEncoder)) test_specific_encoder_properties(options, testdata_tiff_props, all_props, cProperties2); + else if (IsEqualCLSID(clsid_encoder, &CLSID_WICPngEncoder)) + test_specific_encoder_properties(options, testdata_png_props, all_props, cProperties2); for (i=0; i < cProperties2; i++) { diff --git a/include/wincodec.idl b/include/wincodec.idl index 83daba8d253..406fe6b4113 100644 --- a/include/wincodec.idl +++ b/include/wincodec.idl @@ -168,6 +168,17 @@ typedef enum WICTiffCompressionOption { WICTIFFCOMPRESSIONOPTION_FORCE_DWORD = CODEC_FORCE_DWORD } WICTiffCompressionOption; +typedef enum WICPngFilterOption { + WICPngFilterUnspecified = 0, + WICPngFilterNone = 1, + WICPngFilterSub = 2, + WICPngFilterUp = 3, + WICPngFilterAverage = 4, + WICPngFilterPaeth = 5, + WICPngFilterAdaptive = 6, + WICPNFFILTEROPTION_FORCE_DWORD = CODEC_FORCE_DWORD +} WICPngFilterOption; + typedef GUID WICPixelFormatGUID; typedef REFGUID REFWICPixelFormatGUID;