windowscodecs: Fix interlaced PNG writing.
This commit is contained in:
parent
1211ffd76e
commit
e2d6b28a1b
|
@ -185,6 +185,7 @@ MAKE_FUNCPTR(png_set_gray_1_2_4_to_8);
|
|||
#endif
|
||||
MAKE_FUNCPTR(png_set_filler);
|
||||
MAKE_FUNCPTR(png_set_gray_to_rgb);
|
||||
MAKE_FUNCPTR(png_set_interlace_handling);
|
||||
MAKE_FUNCPTR(png_set_IHDR);
|
||||
MAKE_FUNCPTR(png_set_pHYs);
|
||||
MAKE_FUNCPTR(png_set_read_fn);
|
||||
|
@ -234,6 +235,7 @@ static void *load_libpng(void)
|
|||
#endif
|
||||
LOAD_FUNCPTR(png_set_filler);
|
||||
LOAD_FUNCPTR(png_set_gray_to_rgb);
|
||||
LOAD_FUNCPTR(png_set_interlace_handling);
|
||||
LOAD_FUNCPTR(png_set_IHDR);
|
||||
LOAD_FUNCPTR(png_set_pHYs);
|
||||
LOAD_FUNCPTR(png_set_read_fn);
|
||||
|
@ -1063,6 +1065,9 @@ typedef struct PngEncoder {
|
|||
BOOL committed;
|
||||
CRITICAL_SECTION lock;
|
||||
BOOL interlace;
|
||||
BYTE *data;
|
||||
UINT stride;
|
||||
UINT passes;
|
||||
} PngEncoder;
|
||||
|
||||
static inline PngEncoder *impl_from_IWICBitmapEncoder(IWICBitmapEncoder *iface)
|
||||
|
@ -1287,6 +1292,18 @@ static HRESULT WINAPI PngFrameEncode_WritePixels(IWICBitmapFrameEncode *iface,
|
|||
|
||||
if (!This->info_written)
|
||||
{
|
||||
if (This->interlace)
|
||||
{
|
||||
/* libpng requires us to write all data multiple times in this case. */
|
||||
This->stride = (This->format->bpp * This->width + 7)/8;
|
||||
This->data = HeapAlloc(GetProcessHeap(), 0, This->height * This->stride);
|
||||
if (!This->data)
|
||||
{
|
||||
LeaveCriticalSection(&This->lock);
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
ppng_set_IHDR(This->png_ptr, This->info_ptr, This->width, This->height,
|
||||
This->format->bit_depth, This->format->color_type,
|
||||
This->interlace ? PNG_INTERLACE_ADAM7 : PNG_INTERLACE_NONE,
|
||||
|
@ -1306,9 +1323,26 @@ static HRESULT WINAPI PngFrameEncode_WritePixels(IWICBitmapFrameEncode *iface,
|
|||
if (This->format->swap_rgb)
|
||||
ppng_set_bgr(This->png_ptr);
|
||||
|
||||
if (This->interlace)
|
||||
This->passes = ppng_set_interlace_handling(This->png_ptr);
|
||||
|
||||
This->info_written = TRUE;
|
||||
}
|
||||
|
||||
if (This->interlace)
|
||||
{
|
||||
/* Just store the data so we can write it in multiple passes in Commit. */
|
||||
for (i=0; i<lineCount; i++)
|
||||
memcpy(This->data + This->stride * (This->lines_written + i),
|
||||
pbPixels + cbStride * i,
|
||||
This->stride);
|
||||
|
||||
This->lines_written += lineCount;
|
||||
|
||||
LeaveCriticalSection(&This->lock);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
row_pointers = HeapAlloc(GetProcessHeap(), 0, lineCount * sizeof(png_byte*));
|
||||
if (!row_pointers)
|
||||
{
|
||||
|
@ -1355,6 +1389,7 @@ static HRESULT WINAPI PngFrameEncode_WriteSource(IWICBitmapFrameEncode *iface,
|
|||
static HRESULT WINAPI PngFrameEncode_Commit(IWICBitmapFrameEncode *iface)
|
||||
{
|
||||
PngEncoder *This = impl_from_IWICBitmapFrameEncode(iface);
|
||||
png_byte **row_pointers=NULL;
|
||||
jmp_buf jmpbuf;
|
||||
TRACE("(%p)\n", iface);
|
||||
|
||||
|
@ -1370,14 +1405,35 @@ static HRESULT WINAPI PngFrameEncode_Commit(IWICBitmapFrameEncode *iface)
|
|||
if (setjmp(jmpbuf))
|
||||
{
|
||||
LeaveCriticalSection(&This->lock);
|
||||
HeapFree(GetProcessHeap(), 0, row_pointers);
|
||||
return E_FAIL;
|
||||
}
|
||||
ppng_set_error_fn(This->png_ptr, jmpbuf, user_error_fn, user_warning_fn);
|
||||
|
||||
if (This->interlace)
|
||||
{
|
||||
int i;
|
||||
|
||||
row_pointers = HeapAlloc(GetProcessHeap(), 0, This->height * sizeof(png_byte*));
|
||||
if (!row_pointers)
|
||||
{
|
||||
LeaveCriticalSection(&This->lock);
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
for (i=0; i<This->height; i++)
|
||||
row_pointers[i] = This->data + This->stride * i;
|
||||
|
||||
for (i=0; i<This->passes; i++)
|
||||
ppng_write_rows(This->png_ptr, row_pointers, This->height);
|
||||
}
|
||||
|
||||
ppng_write_end(This->png_ptr, This->info_ptr);
|
||||
|
||||
This->frame_committed = TRUE;
|
||||
|
||||
HeapFree(GetProcessHeap(), 0, row_pointers);
|
||||
|
||||
LeaveCriticalSection(&This->lock);
|
||||
|
||||
return S_OK;
|
||||
|
@ -1455,6 +1511,7 @@ static ULONG WINAPI PngEncoder_Release(IWICBitmapEncoder *iface)
|
|||
ppng_destroy_write_struct(&This->png_ptr, &This->info_ptr);
|
||||
if (This->stream)
|
||||
IStream_Release(This->stream);
|
||||
HeapFree(GetProcessHeap(), 0, This->data);
|
||||
HeapFree(GetProcessHeap(), 0, This);
|
||||
}
|
||||
|
||||
|
@ -1695,6 +1752,7 @@ HRESULT PngEncoder_CreateInstance(REFIID iid, void** ppv)
|
|||
This->lines_written = 0;
|
||||
This->frame_committed = FALSE;
|
||||
This->committed = FALSE;
|
||||
This->data = NULL;
|
||||
InitializeCriticalSection(&This->lock);
|
||||
This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": PngEncoder.lock");
|
||||
|
||||
|
|
|
@ -378,6 +378,7 @@ typedef struct 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 struct property_opt_test_data testdata_tiff_props[] = {
|
||||
{ wszTiffCompressionMethod, VT_UI1, VT_UI1, WICTiffCompressionDontCare },
|
||||
|
@ -508,8 +509,16 @@ static void test_encoder_properties(const CLSID* clsid_encoder, IPropertyBag2 *o
|
|||
}
|
||||
}
|
||||
|
||||
struct setting {
|
||||
const WCHAR *name;
|
||||
PROPBAG2_TYPE type;
|
||||
VARTYPE vt;
|
||||
void *value;
|
||||
};
|
||||
|
||||
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 char *name)
|
||||
const struct bitmap_data **dsts, const CLSID *clsid_decoder, WICRect *rc,
|
||||
const struct setting *settings, const char *name)
|
||||
{
|
||||
HRESULT hr;
|
||||
IWICBitmapEncoder *encoder;
|
||||
|
@ -554,6 +563,26 @@ static void test_multi_encoder(const struct bitmap_data **srcs, const CLSID* cls
|
|||
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);
|
||||
|
||||
|
@ -641,7 +670,7 @@ static void test_encoder(const struct bitmap_data *src, const CLSID* clsid_encod
|
|||
dsts[0] = dst;
|
||||
dsts[1] = NULL;
|
||||
|
||||
test_multi_encoder(srcs, clsid_encoder, dsts, clsid_decoder, NULL, name);
|
||||
test_multi_encoder(srcs, clsid_encoder, dsts, clsid_decoder, NULL, NULL, name);
|
||||
}
|
||||
|
||||
static void test_encoder_rects(void)
|
||||
|
@ -660,20 +689,20 @@ static void test_encoder_rects(void)
|
|||
rc.Width = 4;
|
||||
rc.Height = 2;
|
||||
|
||||
test_multi_encoder(srcs, &CLSID_WICTiffEncoder, dsts, &CLSID_WICTiffDecoder, &rc, "test_encoder_rects full");
|
||||
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, "test_encoder_rects 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, "test_encoder_rects 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, "test_encoder_rects 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, "test_encoder_rects 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] = {
|
||||
|
@ -681,6 +710,15 @@ static const struct bitmap_data *multiple_frames[3] = {
|
|||
&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);
|
||||
|
@ -711,9 +749,12 @@ START_TEST(converter)
|
|||
&testdata_24bppBGR, &CLSID_WICTiffDecoder, "TIFF encoder 24bppBGR");
|
||||
|
||||
test_multi_encoder(multiple_frames, &CLSID_WICTiffEncoder,
|
||||
multiple_frames, &CLSID_WICTiffDecoder, NULL, "TIFF encoder multi-frame");
|
||||
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();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue