wincodecs: Implement FilterOption property for PNG encoder.

Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com>
Signed-off-by: Vincent Povirk <vincent@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
oldstable
Nikolay Sivov 2016-11-24 12:23:28 +03:00 committed by Alexandre Julliard
parent 62830143d1
commit 5107ef7566
3 changed files with 79 additions and 14 deletions

View File

@ -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);

View File

@ -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++)
{

View File

@ -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;