#include <wincodec.h>
#include <wine/test.h>
+HRESULT WINAPI WICCreateImagingFactory_Proxy(UINT, IWICImagingFactory**);
+
static const char gif_global_palette[] = {
/* LSD */'G','I','F','8','7','a',0x01,0x00,0x01,0x00,0xa1,0x02,0x00,
/* palette */0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,
0x02,0x02,0x44,0x01,0x00,0x3b
};
+/* Generated with ImageMagick:
+ * convert -delay 100 -size 2x2 xc:red \
+ * -dispose none -page +0+0 -size 2x1 xc:white \
+ * test.gif
+ */
+static const char gif_frame_sizes[] = {
+ 0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0x02, 0x00,
+ 0x02, 0x00, 0xf1, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00,
+ 0x00, 0x21, 0xf9, 0x04, 0x00, 0x64, 0x00, 0x00,
+ 0x00, 0x21, 0xff, 0x0b, 0x4e, 0x45, 0x54, 0x53,
+ 0x43, 0x41, 0x50, 0x45, 0x32, 0x2e, 0x30, 0x03,
+ 0x01, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00,
+ 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x02, 0x03,
+ 0x44, 0x34, 0x05, 0x00, 0x21, 0xf9, 0x04, 0x04,
+ 0x64, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00,
+ 0x00, 0x02, 0x00, 0x01, 0x00, 0x80, 0xff, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x02, 0x02, 0x04, 0x0a,
+ 0x00, 0x3b
+};
+
static IWICImagingFactory *factory;
-static IWICBitmapDecoder *create_decoder(const void *image_data, UINT image_size)
+static IStream *create_stream(const void *image_data, UINT image_size)
{
HGLOBAL hmem;
BYTE *data;
HRESULT hr;
- IWICBitmapDecoder *decoder = NULL;
IStream *stream;
- GUID format;
hmem = GlobalAlloc(0, image_size);
data = GlobalLock(hmem);
hr = CreateStreamOnHGlobal(hmem, TRUE, &stream);
ok(hr == S_OK, "CreateStreamOnHGlobal error %#x\n", hr);
+ return stream;
+}
+
+static IWICBitmapDecoder *create_decoder(const void *image_data, UINT image_size)
+{
+ HRESULT hr;
+ IWICBitmapDecoder *decoder;
+ IStream *stream;
+ GUID format;
+ LONG refcount;
+
+ stream = create_stream(image_data, image_size);
+ if (!stream) return NULL;
+
hr = IWICImagingFactory_CreateDecoderFromStream(factory, stream, NULL, 0, &decoder);
ok(hr == S_OK, "CreateDecoderFromStream error %#x\n", hr);
ok(IsEqualGUID(&format, &GUID_ContainerFormatGif),
"wrong container format %s\n", wine_dbgstr_guid(&format));
- IStream_Release(stream);
+ refcount = IStream_Release(stream);
+ ok(refcount > 0, "expected stream refcount > 0\n");
return decoder;
}
IWICBitmapDecoder_Release(decoder);
}
+static void test_gif_frame_sizes(void)
+{
+ static const BYTE frame0[] = {0, 1, 0xfe, 0xfe, 2, 3, 0xfe, 0xfe};
+ static const BYTE frame1[] = {0, 0, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe};
+
+ IWICBitmapDecoder *decoder;
+ IWICBitmapFrameDecode *frame;
+ UINT width, height;
+ BYTE buf[8];
+ HRESULT hr;
+
+ decoder = create_decoder(gif_frame_sizes, sizeof(gif_frame_sizes));
+ ok(decoder != 0, "Failed to load GIF image data\n");
+
+ hr = IWICBitmapDecoder_GetFrame(decoder, 0, &frame);
+ ok(hr == S_OK, "GetFrame error %#x\n", hr);
+
+ hr = IWICBitmapFrameDecode_GetSize(frame, &width, &height);
+ ok(hr == S_OK, "GetSize error %x\n", hr);
+ ok(width == 2, "width = %d\n", width);
+ ok(height == 2, "height = %d\n", height);
+
+ memset(buf, 0xfe, sizeof(buf));
+ hr = IWICBitmapFrameDecode_CopyPixels(frame, NULL, 4, sizeof(buf), buf);
+ ok(hr == S_OK, "CopyPixels error %x\n", hr);
+ ok(!memcmp(buf, frame0, sizeof(buf)), "buf = %x %x %x %x %x %x %x %x\n",
+ buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);
+
+ IWICBitmapFrameDecode_Release(frame);
+
+ hr = IWICBitmapDecoder_GetFrame(decoder, 1, &frame);
+ ok(hr == S_OK, "GetFrame error %#x\n", hr);
+
+ hr = IWICBitmapFrameDecode_GetSize(frame, &width, &height);
+ ok(hr == S_OK, "GetSize error %x\n", hr);
+ ok(width == 2, "width = %d\n", width);
+ ok(height == 1, "height = %d\n", height);
+
+ memset(buf, 0xfe, sizeof(buf));
+ hr = IWICBitmapFrameDecode_CopyPixels(frame, NULL, 4, sizeof(buf), buf);
+ ok(hr == S_OK, "CopyPixels error %x\n", hr);
+ ok(!memcmp(buf, frame1, sizeof(buf)), "buf = %x %x %x %x %x %x %x %x\n",
+ buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);
+
+ IWICBitmapFrameDecode_Release(frame);
+
+ IWICBitmapDecoder_Release(decoder);
+}
+
+static const char gif_with_trailer_1[] = {
+/* LSD */'G','I','F','8','7','a',0x01,0x00,0x01,0x00,0x80,0x00,0x00,
+/* palette */0xff,0xff,0xff,0xff,0xff,0xff,
+/* IMD */0x2c,0x00,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x00,
+/* image data */0x02,0x02,0x44,0x01,0x00,0x3b
+};
+static const char gif_with_trailer_2[] = {
+/* LSD */'G','I','F','8','7','a',0x01,0x00,0x01,0x00,0x00,0x00,0x00,
+/* IMD */0x2c,0x00,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x00,
+/* image data */0x02,0x02,0x44,0x3b
+};
+static const char gif_without_trailer_1[] = {
+/* LSD */'G','I','F','8','7','a',0x01,0x00,0x01,0x00,0x80,0x00,0x00,
+/* palette */0xff,0xff,0xff,0xff,0xff,0xff,
+/* IMD */0x2c,0x00,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x00,
+/* image data */0x02,0x02,0x44,0xde,0xad,0xbe,0xef,0xde,0xad,0xbe,0xef
+};
+
+static const char gif_without_trailer_2[] = {
+/* LSD */'G','I','F','8','7','a',0x01,0x00,0x01,0x00,0x00,0x00,0x00,
+/* IMD */0x2c,0x00,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x00,
+/* image data */0x02,0x02,0x44,0xde,0xad,0xbe,0xef,0xde,0xad,0xbe,0xef
+};
+
+static void test_truncated_gif(void)
+{
+ HRESULT hr;
+ IStream *stream;
+ IWICBitmapDecoder *decoder;
+ GUID format;
+
+ stream = create_stream(gif_with_trailer_1, sizeof(gif_with_trailer_1));
+ if (!stream) return;
+
+ hr = IWICImagingFactory_CreateDecoderFromStream(factory, stream, NULL, 0, &decoder);
+ ok(hr == S_OK, "CreateDecoderFromStream error %#x\n", hr);
+ hr = IWICBitmapDecoder_GetContainerFormat(decoder, &format);
+ ok(hr == S_OK, "GetContainerFormat error %#x\n", hr);
+ ok(IsEqualGUID(&format, &GUID_ContainerFormatGif),
+ "wrong container format %s\n", wine_dbgstr_guid(&format));
+ IWICBitmapDecoder_Release(decoder);
+ IStream_Release(stream);
+
+ stream = create_stream(gif_with_trailer_2, sizeof(gif_with_trailer_2));
+ if (!stream) return;
+ hr = IWICImagingFactory_CreateDecoderFromStream(factory, stream, NULL, 0, &decoder);
+ ok(hr == S_OK, "CreateDecoderFromStream error %#x\n", hr);
+ hr = IWICBitmapDecoder_GetContainerFormat(decoder, &format);
+ ok(hr == S_OK, "GetContainerFormat error %#x\n", hr);
+ ok(IsEqualGUID(&format, &GUID_ContainerFormatGif),
+ "wrong container format %s\n", wine_dbgstr_guid(&format));
+ IWICBitmapDecoder_Release(decoder);
+ IStream_Release(stream);
+
+ stream = create_stream(gif_without_trailer_1, sizeof(gif_without_trailer_1));
+ if (!stream) return;
+ hr = IWICImagingFactory_CreateDecoderFromStream(factory, stream, NULL, 0, &decoder);
+ ok(hr == S_OK, "CreateDecoderFromStream error %#x\n", hr);
+ hr = IWICBitmapDecoder_GetContainerFormat(decoder, &format);
+ ok(hr == S_OK, "GetContainerFormat error %#x\n", hr);
+ ok(IsEqualGUID(&format, &GUID_ContainerFormatGif),
+ "wrong container format %s\n", wine_dbgstr_guid(&format));
+ IWICBitmapDecoder_Release(decoder);
+ IStream_Release(stream);
+
+ stream = create_stream(gif_without_trailer_2, sizeof(gif_without_trailer_2));
+ if (!stream) return;
+ hr = IWICImagingFactory_CreateDecoderFromStream(factory, stream, NULL, 0, &decoder);
+ ok(hr == S_OK, "CreateDecoderFromStream error %#x\n", hr);
+ hr = IWICBitmapDecoder_GetContainerFormat(decoder, &format);
+ ok(hr == S_OK, "GetContainerFormat error %#x\n", hr);
+ ok(IsEqualGUID(&format, &GUID_ContainerFormatGif),
+ "wrong container format %s\n", wine_dbgstr_guid(&format));
+ IWICBitmapDecoder_Release(decoder);
+ IStream_Release(stream);
+}
+
START_TEST(gifformat)
{
HRESULT hr;
test_global_gif_palette();
test_global_gif_palette_2frames();
test_local_gif_palette();
+ test_gif_frame_sizes();
IWICImagingFactory_Release(factory);
CoUninitialize();
+
+ /* run the same tests with no COM initialization */
+ hr = WICCreateImagingFactory_Proxy(WINCODEC_SDK_VERSION, &factory);
+ ok(hr == S_OK, "WICCreateImagingFactory_Proxy error %#x\n", hr);
+
+ test_global_gif_palette();
+ test_global_gif_palette_2frames();
+ test_local_gif_palette();
+ test_gif_frame_sizes();
+ test_truncated_gif();
+
+ IWICImagingFactory_Release(factory);
}