wine-wine/dlls/windowscodecs/tests/converter.c

881 lines
31 KiB
C

/*
* Copyright 2009 Vincent Povirk
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <stdarg.h>
#include <math.h>
#define COBJMACROS
#define CONST_VTABLE
#include "windef.h"
#include "objbase.h"
#include "wincodec.h"
#include "wincodecsdk.h"
#include "wine/test.h"
typedef struct bitmap_data {
const WICPixelFormatGUID *format;
UINT bpp;
const BYTE *bits;
UINT width;
UINT height;
double xres;
double yres;
const struct bitmap_data *alt_data;
} bitmap_data;
typedef struct BitmapTestSrc {
IWICBitmapSource IWICBitmapSource_iface;
LONG ref;
const bitmap_data *data;
} BitmapTestSrc;
extern HRESULT STDMETHODCALLTYPE IWICBitmapFrameEncode_WriteSource_Proxy(IWICBitmapFrameEncode* This,
IWICBitmapSource *pIBitmapSource, WICRect *prc);
static BOOL near_equal(float a, float b)
{
return fabsf(a - b) < 0.001;
}
static inline BitmapTestSrc *impl_from_IWICBitmapSource(IWICBitmapSource *iface)
{
return CONTAINING_RECORD(iface, BitmapTestSrc, IWICBitmapSource_iface);
}
static HRESULT WINAPI BitmapTestSrc_QueryInterface(IWICBitmapSource *iface, REFIID iid,
void **ppv)
{
if (!ppv) return E_INVALIDARG;
if (IsEqualIID(&IID_IUnknown, iid) ||
IsEqualIID(&IID_IWICBitmapSource, iid))
*ppv = iface;
else
return E_NOINTERFACE;
IUnknown_AddRef((IUnknown*)*ppv);
return S_OK;
}
static ULONG WINAPI BitmapTestSrc_AddRef(IWICBitmapSource *iface)
{
BitmapTestSrc *This = impl_from_IWICBitmapSource(iface);
ULONG ref = InterlockedIncrement(&This->ref);
return ref;
}
static ULONG WINAPI BitmapTestSrc_Release(IWICBitmapSource *iface)
{
BitmapTestSrc *This = impl_from_IWICBitmapSource(iface);
ULONG ref = InterlockedDecrement(&This->ref);
return ref;
}
static HRESULT WINAPI BitmapTestSrc_GetSize(IWICBitmapSource *iface,
UINT *puiWidth, UINT *puiHeight)
{
BitmapTestSrc *This = impl_from_IWICBitmapSource(iface);
*puiWidth = This->data->width;
*puiHeight = This->data->height;
return S_OK;
}
static HRESULT WINAPI BitmapTestSrc_GetPixelFormat(IWICBitmapSource *iface,
WICPixelFormatGUID *pPixelFormat)
{
BitmapTestSrc *This = impl_from_IWICBitmapSource(iface);
memcpy(pPixelFormat, This->data->format, sizeof(GUID));
return S_OK;
}
static HRESULT WINAPI BitmapTestSrc_GetResolution(IWICBitmapSource *iface,
double *pDpiX, double *pDpiY)
{
BitmapTestSrc *This = impl_from_IWICBitmapSource(iface);
*pDpiX = This->data->xres;
*pDpiY = This->data->yres;
return S_OK;
}
static HRESULT WINAPI BitmapTestSrc_CopyPalette(IWICBitmapSource *iface,
IWICPalette *pIPalette)
{
return E_NOTIMPL;
}
static HRESULT WINAPI BitmapTestSrc_CopyPixels(IWICBitmapSource *iface,
const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer)
{
BitmapTestSrc *This = impl_from_IWICBitmapSource(iface);
UINT bytesperrow;
UINT srcstride;
UINT row_offset;
WICRect rc;
if (!prc)
{
rc.X = 0;
rc.Y = 0;
rc.Width = This->data->width;
rc.Height = This->data->height;
prc = &rc;
}
else
{
if (prc->X < 0 || prc->Y < 0 || prc->X+prc->Width > This->data->width || prc->Y+prc->Height > This->data->height)
return E_INVALIDARG;
}
bytesperrow = ((This->data->bpp * prc->Width)+7)/8;
srcstride = ((This->data->bpp * This->data->width)+7)/8;
if (cbStride < bytesperrow)
return E_INVALIDARG;
if ((cbStride * prc->Height) > cbBufferSize)
return E_INVALIDARG;
row_offset = prc->X * This->data->bpp;
if (row_offset % 8 == 0)
{
UINT row;
const BYTE *src;
BYTE *dst;
src = This->data->bits + (row_offset / 8) + prc->Y * srcstride;
dst = pbBuffer;
for (row=0; row < prc->Height; row++)
{
memcpy(dst, src, bytesperrow);
src += srcstride;
dst += cbStride;
}
return S_OK;
}
else
{
ok(0, "bitmap %p was asked to copy pixels not aligned on a byte boundary\n", iface);
return E_FAIL;
}
}
static const IWICBitmapSourceVtbl BitmapTestSrc_Vtbl = {
BitmapTestSrc_QueryInterface,
BitmapTestSrc_AddRef,
BitmapTestSrc_Release,
BitmapTestSrc_GetSize,
BitmapTestSrc_GetPixelFormat,
BitmapTestSrc_GetResolution,
BitmapTestSrc_CopyPalette,
BitmapTestSrc_CopyPixels
};
static void CreateTestBitmap(const bitmap_data *data, BitmapTestSrc **This)
{
*This = HeapAlloc(GetProcessHeap(), 0, sizeof(**This));
if (*This)
{
(*This)->IWICBitmapSource_iface.lpVtbl = &BitmapTestSrc_Vtbl;
(*This)->ref = 1;
(*This)->data = data;
}
}
static void DeleteTestBitmap(BitmapTestSrc *This)
{
ok(This->IWICBitmapSource_iface.lpVtbl == &BitmapTestSrc_Vtbl, "test bitmap %p deleted with incorrect vtable\n", This);
ok(This->ref == 1, "test bitmap %p deleted with %i references instead of 1\n", This, This->ref);
HeapFree(GetProcessHeap(), 0, This);
}
static BOOL compare_bits(const struct bitmap_data *expect, UINT buffersize, const BYTE *converted_bits)
{
BOOL equal;
if (IsEqualGUID(expect->format, &GUID_WICPixelFormat32bppBGR))
{
/* ignore the padding byte when comparing data */
UINT i;
const DWORD *a=(const DWORD*)expect->bits, *b=(const DWORD*)converted_bits;
equal=TRUE;
for (i=0; i<(buffersize/4); i++)
if ((a[i]&0xffffff) != (b[i]&0xffffff))
{
equal = FALSE;
break;
}
}
else if (IsEqualGUID(expect->format, &GUID_WICPixelFormat32bppGrayFloat))
{
UINT i;
const float *a=(const float*)expect->bits, *b=(const float*)converted_bits;
equal=TRUE;
for (i=0; i<(buffersize/4); i++)
if (!near_equal(a[i], b[i]))
{
equal = FALSE;
break;
}
}
else
equal = (memcmp(expect->bits, converted_bits, buffersize) == 0);
if (!equal && expect->alt_data)
equal = compare_bits(expect->alt_data, buffersize, converted_bits);
return equal;
}
static void compare_bitmap_data(const struct bitmap_data *expect, IWICBitmapSource *source, const char *name)
{
BYTE *converted_bits;
UINT width, height;
double xres, yres;
WICRect prc;
UINT stride, buffersize;
GUID dst_pixelformat;
HRESULT hr;
hr = IWICBitmapSource_GetSize(source, &width, &height);
ok(SUCCEEDED(hr), "GetSize(%s) failed, hr=%x\n", name, hr);
ok(width == expect->width, "expecting %u, got %u (%s)\n", expect->width, width, name);
ok(height == expect->height, "expecting %u, got %u (%s)\n", expect->height, height, name);
hr = IWICBitmapSource_GetResolution(source, &xres, &yres);
ok(SUCCEEDED(hr), "GetResolution(%s) failed, hr=%x\n", name, hr);
ok(fabs(xres - expect->xres) < 0.02, "expecting %0.2f, got %0.2f (%s)\n", expect->xres, xres, name);
ok(fabs(yres - expect->yres) < 0.02, "expecting %0.2f, got %0.2f (%s)\n", expect->yres, yres, name);
hr = IWICBitmapSource_GetPixelFormat(source, &dst_pixelformat);
ok(SUCCEEDED(hr), "GetPixelFormat(%s) failed, hr=%x\n", name, hr);
ok(IsEqualGUID(&dst_pixelformat, expect->format), "got unexpected pixel format (%s)\n", name);
prc.X = 0;
prc.Y = 0;
prc.Width = expect->width;
prc.Height = expect->height;
stride = (expect->bpp * expect->width + 7) / 8;
buffersize = stride * expect->height;
converted_bits = HeapAlloc(GetProcessHeap(), 0, buffersize);
hr = IWICBitmapSource_CopyPixels(source, &prc, stride, buffersize, converted_bits);
ok(SUCCEEDED(hr), "CopyPixels(%s) failed, hr=%x\n", name, hr);
ok(compare_bits(expect, buffersize, converted_bits), "unexpected pixel data (%s)\n", name);
/* Test with NULL rectangle - should copy the whole bitmap */
memset(converted_bits, 0xaa, buffersize);
hr = IWICBitmapSource_CopyPixels(source, NULL, stride, buffersize, converted_bits);
ok(SUCCEEDED(hr), "CopyPixels(%s,rc=NULL) failed, hr=%x\n", name, hr);
ok(compare_bits(expect, buffersize, converted_bits), "unexpected pixel data (%s)\n", name);
HeapFree(GetProcessHeap(), 0, converted_bits);
}
static const BYTE bits_24bppBGR[] = {
255,0,0, 0,255,0, 0,0,255, 0,0,0,
0,255,255, 255,0,255, 255,255,0, 255,255,255};
static const struct bitmap_data testdata_24bppBGR = {
&GUID_WICPixelFormat24bppBGR, 24, bits_24bppBGR, 4, 2, 96.0, 96.0};
static const BYTE bits_24bppRGB[] = {
0,0,255, 0,255,0, 255,0,0, 0,0,0,
255,255,0, 255,0,255, 0,255,255, 255,255,255};
static const struct bitmap_data testdata_24bppRGB = {
&GUID_WICPixelFormat24bppRGB, 24, bits_24bppRGB, 4, 2, 96.0, 96.0};
static const BYTE bits_32bppBGR[] = {
255,0,0,80, 0,255,0,80, 0,0,255,80, 0,0,0,80,
0,255,255,80, 255,0,255,80, 255,255,0,80, 255,255,255,80};
static const struct bitmap_data testdata_32bppBGR = {
&GUID_WICPixelFormat32bppBGR, 32, bits_32bppBGR, 4, 2, 96.0, 96.0};
static const BYTE bits_32bppBGRA[] = {
255,0,0,255, 0,255,0,255, 0,0,255,255, 0,0,0,255,
0,255,255,255, 255,0,255,255, 255,255,0,255, 255,255,255,255};
static const struct bitmap_data testdata_32bppBGRA = {
&GUID_WICPixelFormat32bppBGRA, 32, bits_32bppBGRA, 4, 2, 96.0, 96.0};
/* XP and 2003 use linear color conversion, later versions use sRGB gamma */
static const float bits_32bppGrayFloat_xp[] = {
0.114000f,0.587000f,0.299000f,0.000000f,
0.886000f,0.413000f,0.701000f,1.000000f};
static const struct bitmap_data testdata_32bppGrayFloat_xp = {
&GUID_WICPixelFormat32bppGrayFloat, 32, (const BYTE *)bits_32bppGrayFloat_xp, 4, 2, 96.0, 96.0};
static const float bits_32bppGrayFloat[] = {
0.072200f,0.715200f,0.212600f,0.000000f,
0.927800f,0.284800f,0.787400f,1.000000f};
static const struct bitmap_data testdata_32bppGrayFloat = {
&GUID_WICPixelFormat32bppGrayFloat, 32, (const BYTE *)bits_32bppGrayFloat, 4, 2, 96.0, 96.0, &testdata_32bppGrayFloat_xp};
static const BYTE bits_8bppGray_xp[] = {
29,150,76,0,
226,105,179,255};
static const struct bitmap_data testdata_8bppGray_xp = {
&GUID_WICPixelFormat8bppGray, 8, bits_8bppGray_xp, 4, 2, 96.0, 96.0};
static const BYTE bits_8bppGray[] = {
76,220,127,0,
247,145,230,255};
static const struct bitmap_data testdata_8bppGray = {
&GUID_WICPixelFormat8bppGray, 8, bits_8bppGray, 4, 2, 96.0, 96.0, &testdata_8bppGray_xp};
static const BYTE bits_24bppBGR_gray[] = {
76,76,76, 220,220,220, 127,127,127, 0,0,0,
247,247,247, 145,145,145, 230,230,230, 255,255,255};
static const struct bitmap_data testdata_24bppBGR_gray = {
&GUID_WICPixelFormat24bppBGR, 24, bits_24bppBGR_gray, 4, 2, 96.0, 96.0};
static void test_conversion(const struct bitmap_data *src, const struct bitmap_data *dst, const char *name, BOOL todo)
{
BitmapTestSrc *src_obj;
IWICBitmapSource *dst_bitmap;
HRESULT hr;
CreateTestBitmap(src, &src_obj);
hr = WICConvertBitmapSource(dst->format, &src_obj->IWICBitmapSource_iface, &dst_bitmap);
todo_wine_if (todo)
ok(SUCCEEDED(hr), "WICConvertBitmapSource(%s) failed, hr=%x\n", name, hr);
if (SUCCEEDED(hr))
{
compare_bitmap_data(dst, dst_bitmap, name);
IWICBitmapSource_Release(dst_bitmap);
}
DeleteTestBitmap(src_obj);
}
static void test_invalid_conversion(void)
{
BitmapTestSrc *src_obj;
IWICBitmapSource *dst_bitmap;
HRESULT hr;
CreateTestBitmap(&testdata_32bppBGRA, &src_obj);
/* convert to a non-pixel-format GUID */
hr = WICConvertBitmapSource(&GUID_VendorMicrosoft, &src_obj->IWICBitmapSource_iface, &dst_bitmap);
ok(hr == WINCODEC_ERR_COMPONENTNOTFOUND, "WICConvertBitmapSource returned %x\n", hr);
DeleteTestBitmap(src_obj);
}
static void test_default_converter(void)
{
BitmapTestSrc *src_obj;
IWICFormatConverter *converter;
BOOL can_convert = TRUE;
HRESULT hr;
CreateTestBitmap(&testdata_32bppBGRA, &src_obj);
hr = CoCreateInstance(&CLSID_WICDefaultFormatConverter, NULL, CLSCTX_INPROC_SERVER,
&IID_IWICFormatConverter, (void**)&converter);
ok(SUCCEEDED(hr), "CoCreateInstance failed, hr=%x\n", hr);
if (SUCCEEDED(hr))
{
hr = IWICFormatConverter_CanConvert(converter, &GUID_WICPixelFormat32bppBGRA,
&GUID_WICPixelFormat32bppBGR, &can_convert);
ok(SUCCEEDED(hr), "CanConvert returned %x\n", hr);
ok(can_convert, "expected TRUE, got %i\n", can_convert);
hr = IWICFormatConverter_Initialize(converter, &src_obj->IWICBitmapSource_iface,
&GUID_WICPixelFormat32bppBGR, WICBitmapDitherTypeNone, NULL, 0.0,
WICBitmapPaletteTypeCustom);
ok(SUCCEEDED(hr), "Initialize returned %x\n", hr);
if (SUCCEEDED(hr))
compare_bitmap_data(&testdata_32bppBGR, (IWICBitmapSource*)converter, "default converter");
IWICFormatConverter_Release(converter);
}
DeleteTestBitmap(src_obj);
}
typedef struct property_opt_test_data
{
LPCOLESTR name;
VARTYPE var_type;
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 },
{ wszCompressionQuality, VT_R4, VT_EMPTY },
{ 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;
for (i=0; i < all_prop_cnt; i++)
{
if (lstrcmpW(name, all_props[i].pstrName) == 0)
return i;
}
return -1;
}
static void test_specific_encoder_properties(IPropertyBag2 *options, const property_opt_test_data* data, PROPBAG2* all_props, int all_prop_cnt)
{
HRESULT hr;
int i = 0;
VARIANT pvarValue;
HRESULT phrError = S_OK;
while (data[i].name)
{
int idx = find_property_index(data[i].name, all_props, all_prop_cnt);
PROPBAG2 pb = {0};
pb.pstrName = (LPOLESTR)data[i].name;
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)
{
ok(all_props[idx].vt == data[i].var_type, "Property %s has unexpected vt type, vt=%i\n",
wine_dbgstr_w(data[i].name), all_props[idx].vt);
ok(all_props[idx].dwType == PROPBAG2_TYPE_DATA, "Property %s has unexpected dw type, vt=%i\n",
wine_dbgstr_w(data[i].name), all_props[idx].dwType);
ok(all_props[idx].cfType == 0, "Property %s has unexpected cf type, vt=%i\n",
wine_dbgstr_w(data[i].name), all_props[idx].cfType);
}
ok(SUCCEEDED(hr), "Reading property %s from bag failed, hr=%x\n",
wine_dbgstr_w(data[i].name), hr);
if (SUCCEEDED(hr))
{
/* On XP the initial type is always VT_EMPTY */
ok(V_VT(&pvarValue) == data[i].initial_var_type || V_VT(&pvarValue) == VT_EMPTY,
"Property %s has unexpected initial type, V_VT=%i\n",
wine_dbgstr_w(data[i].name), V_VT(&pvarValue));
if(V_VT(&pvarValue) == data[i].initial_var_type)
{
switch (data[i].initial_var_type)
{
case VT_BOOL:
case VT_UI1:
ok(V_UNION(&pvarValue, bVal) == data[i].i_init_val, "Property %s has an unexpected initial value, pvarValue=%i\n",
wine_dbgstr_w(data[i].name), V_UNION(&pvarValue, bVal));
break;
case VT_R4:
ok(V_UNION(&pvarValue, fltVal) == data[i].f_init_val, "Property %s has an unexpected initial value, pvarValue=%f\n",
wine_dbgstr_w(data[i].name), V_UNION(&pvarValue, fltVal));
break;
default:
break;
}
}
VariantClear(&pvarValue);
}
i++;
}
}
static void test_encoder_properties(const CLSID* clsid_encoder, IPropertyBag2 *options)
{
HRESULT hr;
ULONG cProperties = 0;
ULONG cProperties2 = 0;
PROPBAG2 all_props[64] = {{0}}; /* Should be enough for every encoder out there */
int i;
/* CountProperties */
{
hr = IPropertyBag2_CountProperties(options, &cProperties);
ok(SUCCEEDED(hr), "Reading property count, hr=%x\n", hr);
}
/* GetPropertyInfo */
{
hr = IPropertyBag2_GetPropertyInfo(options, cProperties, 1, all_props, &cProperties2);
ok(hr == WINCODEC_ERR_VALUEOUTOFRANGE, "IPropertyBag2::GetPropertyInfo - iProperty out of bounce handled wrong, hr=%x\n", hr);
hr = IPropertyBag2_GetPropertyInfo(options, 0, cProperties+1, all_props, &cProperties2);
ok(hr == WINCODEC_ERR_VALUEOUTOFRANGE, "IPropertyBag2::GetPropertyInfo - cProperty out of bounce handled wrong, hr=%x\n", hr);
if (cProperties == 0) /* GetPropertyInfo can be called for zero items on Windows 8 but not on Windows 7 (wine behaves like Win8) */
{
cProperties2 = cProperties;
hr = S_OK;
}
else
{
hr = IPropertyBag2_GetPropertyInfo(options, 0, min(64, cProperties), all_props, &cProperties2);
ok(SUCCEEDED(hr), "Reading infos from property bag failed, hr=%x\n", hr);
}
if (FAILED(hr))
return;
ok(cProperties == cProperties2, "Mismatch of property count (IPropertyBag2::CountProperties=%i, IPropertyBag2::GetPropertyInfo=%i)\n",
(int)cProperties, (int)cProperties2);
}
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++)
{
ok(all_props[i].pstrName != NULL, "Unset property name in output of IPropertyBag2::GetPropertyInfo\n");
CoTaskMemFree(all_props[i].pstrName);
}
}
struct setting {
const WCHAR *name;
PROPBAG2_TYPE type;
VARTYPE vt;
void *value;
};
#define EXPECT_REF(obj,ref) _expect_ref((IUnknown*)obj, ref, __LINE__)
static void _expect_ref(IUnknown* obj, ULONG ref, int line)
{
ULONG rc;
IUnknown_AddRef(obj);
rc = IUnknown_Release(obj);
ok_(__FILE__,line)(rc == ref, "expected refcount %d, got %d\n", ref, rc);
}
static void test_set_frame_palette(IWICBitmapFrameEncode *frameencode)
{
IWICComponentFactory *factory;
IWICPalette *palette;
HRESULT hr;
hr = CoCreateInstance(&CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER,
&IID_IWICComponentFactory, (void **)&factory);
ok(hr == S_OK, "CoCreateInstance failed, hr=%x\n", hr);
hr = IWICBitmapFrameEncode_SetPalette(frameencode, NULL);
ok(hr == E_INVALIDARG, "SetPalette failed, hr=%x\n", hr);
hr = IWICComponentFactory_CreatePalette(factory, &palette);
ok(hr == S_OK, "CreatePalette failed, hr=%x\n", hr);
hr = IWICBitmapFrameEncode_SetPalette(frameencode, palette);
todo_wine
ok(hr == WINCODEC_ERR_NOTINITIALIZED, "Unexpected hr=%x\n", hr);
hr = IWICPalette_InitializePredefined(palette, WICBitmapPaletteTypeFixedHalftone256, FALSE);
ok(hr == S_OK, "InitializePredefined failed, hr=%x\n", hr);
EXPECT_REF(palette, 1);
hr = IWICBitmapFrameEncode_SetPalette(frameencode, palette);
ok(hr == S_OK, "SetPalette failed, hr=%x\n", hr);
EXPECT_REF(palette, 1);
hr = IWICBitmapFrameEncode_SetPalette(frameencode, NULL);
ok(hr == E_INVALIDARG, "SetPalette failed, hr=%x\n", hr);
IWICPalette_Release(palette);
IWICComponentFactory_Release(factory);
}
static void test_multi_encoder(const struct bitmap_data **srcs, const CLSID* clsid_encoder,
const struct bitmap_data **dsts, const CLSID *clsid_decoder, WICRect *rc,
const struct setting *settings, const char *name)
{
HRESULT hr;
IWICBitmapEncoder *encoder;
BitmapTestSrc *src_obj;
HGLOBAL hglobal;
IStream *stream;
IWICBitmapFrameEncode *frameencode;
IPropertyBag2 *options=NULL;
IWICBitmapDecoder *decoder;
IWICBitmapFrameDecode *framedecode;
WICPixelFormatGUID pixelformat;
int i;
hr = CoCreateInstance(clsid_encoder, NULL, CLSCTX_INPROC_SERVER,
&IID_IWICBitmapEncoder, (void**)&encoder);
ok(SUCCEEDED(hr), "CoCreateInstance failed, hr=%x\n", hr);
if (SUCCEEDED(hr))
{
hglobal = GlobalAlloc(GMEM_MOVEABLE, 0);
ok(hglobal != NULL, "GlobalAlloc failed\n");
if (hglobal)
{
hr = CreateStreamOnHGlobal(hglobal, TRUE, &stream);
ok(SUCCEEDED(hr), "CreateStreamOnHGlobal failed, hr=%x\n", hr);
}
if (hglobal && SUCCEEDED(hr))
{
hr = IWICBitmapEncoder_Initialize(encoder, stream, WICBitmapEncoderNoCache);
ok(SUCCEEDED(hr), "Initialize failed, hr=%x\n", hr);
i=0;
while (SUCCEEDED(hr) && srcs[i])
{
CreateTestBitmap(srcs[i], &src_obj);
hr = IWICBitmapEncoder_CreateNewFrame(encoder, &frameencode, &options);
ok(SUCCEEDED(hr), "CreateFrame failed, hr=%x\n", hr);
if (SUCCEEDED(hr))
{
ok(options != NULL, "Encoder initialization has not created an property bag\n");
if(options)
test_encoder_properties(clsid_encoder, options);
if (settings)
{
int j;
for (j=0; settings[j].name; j++)
{
PROPBAG2 propbag;
VARIANT var;
memset(&propbag, 0, sizeof(propbag));
memset(&var, 0, sizeof(var));
propbag.pstrName = (LPOLESTR)settings[j].name;
propbag.dwType = settings[j].type;
V_VT(&var) = settings[j].vt;
V_UNKNOWN(&var) = settings[j].value;
hr = IPropertyBag2_Write(options, 1, &propbag, &var);
ok(SUCCEEDED(hr), "Writing property %s failed, hr=%x\n", wine_dbgstr_w(settings[j].name), hr);
}
}
hr = IWICBitmapFrameEncode_Initialize(frameencode, options);
ok(SUCCEEDED(hr), "Initialize failed, hr=%x\n", hr);
memcpy(&pixelformat, srcs[i]->format, sizeof(GUID));
hr = IWICBitmapFrameEncode_SetPixelFormat(frameencode, &pixelformat);
ok(SUCCEEDED(hr), "SetPixelFormat failed, hr=%x\n", hr);
ok(IsEqualGUID(&pixelformat, srcs[i]->format), "SetPixelFormat changed the format\n");
hr = IWICBitmapFrameEncode_SetSize(frameencode, srcs[i]->width, srcs[i]->height);
ok(SUCCEEDED(hr), "SetSize failed, hr=%x\n", hr);
if (IsEqualGUID(clsid_encoder, &CLSID_WICPngEncoder))
test_set_frame_palette(frameencode);
hr = IWICBitmapFrameEncode_WriteSource(frameencode, &src_obj->IWICBitmapSource_iface, rc);
if (rc && (rc->Width <= 0 || rc->Height <= 0))
{
/* WriteSource fails but WriteSource_Proxy succeeds. */
ok(hr == E_INVALIDARG, "WriteSource failed, hr=%x (%s)\n", hr, name);
hr = IWICBitmapFrameEncode_WriteSource_Proxy(frameencode, &src_obj->IWICBitmapSource_iface, rc);
}
ok(SUCCEEDED(hr), "WriteSource failed, hr=%x (%s)\n", hr, name);
hr = IWICBitmapFrameEncode_Commit(frameencode);
ok(SUCCEEDED(hr), "Commit failed, hr=%x\n", hr);
IWICBitmapFrameEncode_Release(frameencode);
IPropertyBag2_Release(options);
}
DeleteTestBitmap(src_obj);
i++;
}
if (SUCCEEDED(hr))
{
hr = IWICBitmapEncoder_Commit(encoder);
ok(SUCCEEDED(hr), "Commit failed, hr=%x\n", hr);
}
if (SUCCEEDED(hr))
{
hr = CoCreateInstance(clsid_decoder, NULL, CLSCTX_INPROC_SERVER,
&IID_IWICBitmapDecoder, (void**)&decoder);
ok(SUCCEEDED(hr), "CoCreateInstance failed, hr=%x\n", hr);
}
if (SUCCEEDED(hr))
{
hr = IWICBitmapDecoder_Initialize(decoder, stream, WICDecodeMetadataCacheOnDemand);
ok(SUCCEEDED(hr), "Initialize failed, hr=%x\n", hr);
i=0;
while (SUCCEEDED(hr) && dsts[i])
{
hr = IWICBitmapDecoder_GetFrame(decoder, i, &framedecode);
ok(SUCCEEDED(hr), "GetFrame failed, hr=%x\n", hr);
if (SUCCEEDED(hr))
{
compare_bitmap_data(dsts[i], (IWICBitmapSource*)framedecode, name);
IWICBitmapFrameDecode_Release(framedecode);
}
i++;
}
IWICBitmapDecoder_Release(decoder);
}
IStream_Release(stream);
}
IWICBitmapEncoder_Release(encoder);
}
}
static void test_encoder(const struct bitmap_data *src, const CLSID* clsid_encoder,
const struct bitmap_data *dst, const CLSID *clsid_decoder, const char *name)
{
const struct bitmap_data *srcs[2];
const struct bitmap_data *dsts[2];
srcs[0] = src;
srcs[1] = NULL;
dsts[0] = dst;
dsts[1] = NULL;
test_multi_encoder(srcs, clsid_encoder, dsts, clsid_decoder, NULL, NULL, name);
}
static void test_encoder_rects(void)
{
const struct bitmap_data *srcs[2];
const struct bitmap_data *dsts[2];
WICRect rc;
srcs[0] = &testdata_24bppBGR;
srcs[1] = NULL;
dsts[0] = &testdata_24bppBGR;
dsts[1] = NULL;
rc.X = 0;
rc.Y = 0;
rc.Width = 4;
rc.Height = 2;
test_multi_encoder(srcs, &CLSID_WICTiffEncoder, dsts, &CLSID_WICTiffDecoder, &rc, NULL, "test_encoder_rects full");
rc.Width = 0;
test_multi_encoder(srcs, &CLSID_WICTiffEncoder, dsts, &CLSID_WICTiffDecoder, &rc, NULL, "test_encoder_rects width=0");
rc.Width = -1;
test_multi_encoder(srcs, &CLSID_WICTiffEncoder, dsts, &CLSID_WICTiffDecoder, &rc, NULL, "test_encoder_rects width=-1");
rc.Width = 4;
rc.Height = 0;
test_multi_encoder(srcs, &CLSID_WICTiffEncoder, dsts, &CLSID_WICTiffDecoder, &rc, NULL, "test_encoder_rects height=0");
rc.Height = -1;
test_multi_encoder(srcs, &CLSID_WICTiffEncoder, dsts, &CLSID_WICTiffDecoder, &rc, NULL, "test_encoder_rects height=-1");
}
static const struct bitmap_data *multiple_frames[3] = {
&testdata_24bppBGR,
&testdata_24bppBGR,
NULL};
static const struct bitmap_data *single_frame[2] = {
&testdata_24bppBGR,
NULL};
static const struct setting png_interlace_settings[] = {
{wszInterlaceOption, PROPBAG2_TYPE_DATA, VT_BOOL, (void*)VARIANT_TRUE},
{NULL}
};
START_TEST(converter)
{
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
test_conversion(&testdata_32bppBGRA, &testdata_32bppBGR, "BGRA -> BGR", FALSE);
test_conversion(&testdata_32bppBGR, &testdata_32bppBGRA, "BGR -> BGRA", FALSE);
test_conversion(&testdata_32bppBGRA, &testdata_32bppBGRA, "BGRA -> BGRA", FALSE);
test_conversion(&testdata_24bppBGR, &testdata_24bppBGR, "24bppBGR -> 24bppBGR", FALSE);
test_conversion(&testdata_24bppBGR, &testdata_24bppRGB, "24bppBGR -> 24bppRGB", FALSE);
test_conversion(&testdata_24bppRGB, &testdata_24bppRGB, "24bppRGB -> 24bppRGB", FALSE);
test_conversion(&testdata_24bppRGB, &testdata_24bppBGR, "24bppRGB -> 24bppBGR", FALSE);
test_conversion(&testdata_32bppBGR, &testdata_24bppRGB, "32bppBGR -> 24bppRGB", FALSE);
test_conversion(&testdata_24bppRGB, &testdata_32bppBGR, "24bppRGB -> 32bppBGR", FALSE);
test_conversion(&testdata_32bppBGRA, &testdata_24bppRGB, "32bppBGRA -> 24bppRGB", FALSE);
test_conversion(&testdata_24bppRGB, &testdata_32bppGrayFloat, "24bppRGB -> 32bppGrayFloat", FALSE);
test_conversion(&testdata_32bppBGR, &testdata_32bppGrayFloat, "32bppBGR -> 32bppGrayFloat", FALSE);
test_conversion(&testdata_24bppBGR, &testdata_8bppGray, "24bppBGR -> 8bppGray", FALSE);
test_conversion(&testdata_32bppBGR, &testdata_8bppGray, "32bppBGR -> 8bppGray", FALSE);
test_conversion(&testdata_32bppGrayFloat, &testdata_24bppBGR_gray, "32bppGrayFloat -> 24bppBGR gray", FALSE);
test_invalid_conversion();
test_default_converter();
test_encoder(&testdata_32bppBGR, &CLSID_WICBmpEncoder,
&testdata_32bppBGR, &CLSID_WICBmpDecoder, "BMP encoder 32bppBGR");
test_encoder(&testdata_24bppBGR, &CLSID_WICPngEncoder,
&testdata_24bppBGR, &CLSID_WICPngDecoder, "PNG encoder 24bppBGR");
test_encoder(&testdata_24bppBGR, &CLSID_WICTiffEncoder,
&testdata_24bppBGR, &CLSID_WICTiffDecoder, "TIFF encoder 24bppBGR");
test_multi_encoder(multiple_frames, &CLSID_WICTiffEncoder,
multiple_frames, &CLSID_WICTiffDecoder, NULL, NULL, "TIFF encoder multi-frame");
test_encoder_rects();
test_multi_encoder(single_frame, &CLSID_WICPngEncoder,
single_frame, &CLSID_WICPngDecoder, NULL, png_interlace_settings, "PNG encoder interlaced");
CoUninitialize();
}