Nikolay Sivov : wincodecs: Implement FilterOption property for PNG encoder.
Alexandre Julliard
julliard at winehq.org
Mon Nov 28 15:52:47 CST 2016
Module: wine
Branch: master
Commit: 5107ef7566ea91f9319c7900addd88dd6c9a3445
URL: http://source.winehq.org/git/wine.git/?a=commit;h=5107ef7566ea91f9319c7900addd88dd6c9a3445
Author: Nikolay Sivov <nsivov at codeweavers.com>
Date: Thu Nov 24 12:23:28 2016 +0300
wincodecs: Implement FilterOption property for PNG encoder.
Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
Signed-off-by: Vincent Povirk <vincent at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>
---
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 bb2aef9..9a84162 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 7ca201a..2af9857 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 83daba8..406fe6b 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;
More information about the wine-cvs
mailing list