Commit 5107ef75 authored by Nikolay Sivov's avatar Nikolay Sivov Committed by Alexandre Julliard

wincodecs: Implement FilterOption property for PNG encoder.

parent 62830143
...@@ -39,8 +39,6 @@ ...@@ -39,8 +39,6 @@
WINE_DEFAULT_DEBUG_CHANNEL(wincodecs); 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) static inline ULONG read_ulong_be(BYTE* data)
{ {
return data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3]; 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); ...@@ -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); MAKE_FUNCPTR(png_set_gray_1_2_4_to_8);
#endif #endif
MAKE_FUNCPTR(png_set_filler); MAKE_FUNCPTR(png_set_filler);
MAKE_FUNCPTR(png_set_filter);
MAKE_FUNCPTR(png_set_gray_to_rgb); MAKE_FUNCPTR(png_set_gray_to_rgb);
MAKE_FUNCPTR(png_set_interlace_handling); MAKE_FUNCPTR(png_set_interlace_handling);
MAKE_FUNCPTR(png_set_IHDR); MAKE_FUNCPTR(png_set_IHDR);
...@@ -353,6 +352,9 @@ static CRITICAL_SECTION_DEBUG init_png_cs_debug = ...@@ -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 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) static void *load_libpng(void)
{ {
void *result; void *result;
...@@ -392,6 +394,7 @@ static void *load_libpng(void) ...@@ -392,6 +394,7 @@ static void *load_libpng(void)
LOAD_FUNCPTR(png_set_gray_1_2_4_to_8); LOAD_FUNCPTR(png_set_gray_1_2_4_to_8);
#endif #endif
LOAD_FUNCPTR(png_set_filler); LOAD_FUNCPTR(png_set_filler);
LOAD_FUNCPTR(png_set_filter);
LOAD_FUNCPTR(png_set_gray_to_rgb); LOAD_FUNCPTR(png_set_gray_to_rgb);
LOAD_FUNCPTR(png_set_interlace_handling); LOAD_FUNCPTR(png_set_interlace_handling);
LOAD_FUNCPTR(png_set_IHDR); LOAD_FUNCPTR(png_set_IHDR);
...@@ -1356,6 +1359,7 @@ typedef struct PngEncoder { ...@@ -1356,6 +1359,7 @@ typedef struct PngEncoder {
BOOL committed; BOOL committed;
CRITICAL_SECTION lock; CRITICAL_SECTION lock;
BOOL interlace; BOOL interlace;
WICPngFilterOption filter;
BYTE *data; BYTE *data;
UINT stride; UINT stride;
UINT passes; UINT passes;
...@@ -1410,31 +1414,44 @@ static HRESULT WINAPI PngFrameEncode_Initialize(IWICBitmapFrameEncode *iface, ...@@ -1410,31 +1414,44 @@ static HRESULT WINAPI PngFrameEncode_Initialize(IWICBitmapFrameEncode *iface,
IPropertyBag2 *pIEncoderOptions) IPropertyBag2 *pIEncoderOptions)
{ {
PngEncoder *This = impl_from_IWICBitmapFrameEncode(iface); PngEncoder *This = impl_from_IWICBitmapFrameEncode(iface);
WICPngFilterOption filter;
BOOL interlace; BOOL interlace;
PROPBAG2 opts[1]= {{0}}; PROPBAG2 opts[2]= {{0}};
VARIANT opt_values[1]; VARIANT opt_values[2];
HRESULT opt_hres[1]; HRESULT opt_hres[2];
HRESULT hr; HRESULT hr;
TRACE("(%p,%p)\n", iface, pIEncoderOptions); TRACE("(%p,%p)\n", iface, pIEncoderOptions);
opts[0].pstrName = (LPOLESTR)wszPngInterlaceOption; opts[0].pstrName = (LPOLESTR)wszPngInterlaceOption;
opts[0].vt = VT_BOOL; opts[0].vt = VT_BOOL;
opts[1].pstrName = (LPOLESTR)wszPngFilterOption;
opts[1].vt = VT_UI1;
if (pIEncoderOptions) 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)) if (FAILED(hr))
return 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 else
memset(opt_values, 0, sizeof(opt_values)); {
if (V_VT(&opt_values[0]) == VT_EMPTY)
interlace = FALSE; interlace = FALSE;
else filter = WICPngFilterUnspecified;
interlace = (V_BOOL(&opt_values[0]) != 0); }
EnterCriticalSection(&This->lock); EnterCriticalSection(&This->lock);
...@@ -1445,6 +1462,7 @@ static HRESULT WINAPI PngFrameEncode_Initialize(IWICBitmapFrameEncode *iface, ...@@ -1445,6 +1462,7 @@ static HRESULT WINAPI PngFrameEncode_Initialize(IWICBitmapFrameEncode *iface,
} }
This->interlace = interlace; This->interlace = interlace;
This->filter = filter;
This->frame_initialized = TRUE; This->frame_initialized = TRUE;
...@@ -1617,6 +1635,22 @@ static HRESULT WINAPI PngFrameEncode_WritePixels(IWICBitmapFrameEncode *iface, ...@@ -1617,6 +1635,22 @@ static HRESULT WINAPI PngFrameEncode_WritePixels(IWICBitmapFrameEncode *iface,
if (This->interlace) if (This->interlace)
This->passes = ppng_set_interlace_handling(This->png_ptr); 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; This->info_written = TRUE;
} }
...@@ -1926,7 +1960,7 @@ static HRESULT WINAPI PngEncoder_CreateNewFrame(IWICBitmapEncoder *iface, ...@@ -1926,7 +1960,7 @@ static HRESULT WINAPI PngEncoder_CreateNewFrame(IWICBitmapEncoder *iface,
{ {
PngEncoder *This = impl_from_IWICBitmapEncoder(iface); PngEncoder *This = impl_from_IWICBitmapEncoder(iface);
HRESULT hr; HRESULT hr;
PROPBAG2 opts[1]= {{0}}; PROPBAG2 opts[2]= {{0}};
TRACE("(%p,%p,%p)\n", iface, ppIFrameEncode, ppIEncoderOptions); TRACE("(%p,%p,%p)\n", iface, ppIFrameEncode, ppIEncoderOptions);
...@@ -1947,8 +1981,11 @@ static HRESULT WINAPI PngEncoder_CreateNewFrame(IWICBitmapEncoder *iface, ...@@ -1947,8 +1981,11 @@ static HRESULT WINAPI PngEncoder_CreateNewFrame(IWICBitmapEncoder *iface,
opts[0].pstrName = (LPOLESTR)wszPngInterlaceOption; opts[0].pstrName = (LPOLESTR)wszPngInterlaceOption;
opts[0].vt = VT_BOOL; opts[0].vt = VT_BOOL;
opts[0].dwType = PROPBAG2_TYPE_DATA; 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)) if (FAILED(hr))
{ {
LeaveCriticalSection(&This->lock); LeaveCriticalSection(&This->lock);
......
...@@ -418,11 +418,13 @@ typedef struct property_opt_test_data ...@@ -418,11 +418,13 @@ typedef struct property_opt_test_data
VARTYPE initial_var_type; VARTYPE initial_var_type;
int i_init_val; int i_init_val;
float f_init_val; float f_init_val;
BOOL skippable;
} property_opt_test_data; } 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 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 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 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[] = { static const struct property_opt_test_data testdata_tiff_props[] = {
{ wszTiffCompressionMethod, VT_UI1, VT_UI1, WICTiffCompressionDontCare }, { wszTiffCompressionMethod, VT_UI1, VT_UI1, WICTiffCompressionDontCare },
...@@ -430,6 +432,12 @@ static const struct property_opt_test_data testdata_tiff_props[] = { ...@@ -430,6 +432,12 @@ static const struct property_opt_test_data testdata_tiff_props[] = {
{ NULL } { 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) static int find_property_index(const WCHAR* name, PROPBAG2* all_props, int all_prop_cnt)
{ {
int i; int i;
...@@ -456,6 +464,13 @@ static void test_specific_encoder_properties(IPropertyBag2 *options, const prope ...@@ -456,6 +464,13 @@ static void test_specific_encoder_properties(IPropertyBag2 *options, const prope
hr = IPropertyBag2_Read(options, 1, &pb, NULL, &pvarValue, &phrError); 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", ok(idx >= 0, "Property %s not in output of GetPropertyInfo\n",
wine_dbgstr_w(data[i].name)); wine_dbgstr_w(data[i].name));
if (idx >= 0) if (idx >= 0)
...@@ -543,8 +558,10 @@ static void test_encoder_properties(const CLSID* clsid_encoder, IPropertyBag2 *o ...@@ -543,8 +558,10 @@ static void test_encoder_properties(const CLSID* clsid_encoder, IPropertyBag2 *o
(int)cProperties, (int)cProperties2); (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); 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++) for (i=0; i < cProperties2; i++)
{ {
......
...@@ -168,6 +168,17 @@ typedef enum WICTiffCompressionOption { ...@@ -168,6 +168,17 @@ typedef enum WICTiffCompressionOption {
WICTIFFCOMPRESSIONOPTION_FORCE_DWORD = CODEC_FORCE_DWORD WICTIFFCOMPRESSIONOPTION_FORCE_DWORD = CODEC_FORCE_DWORD
} WICTiffCompressionOption; } 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 GUID WICPixelFormatGUID;
typedef REFGUID REFWICPixelFormatGUID; typedef REFGUID REFWICPixelFormatGUID;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment