dmstyle: Rewrite style pref chunk parsing.
[wine.git] / dlls / windowscodecs / libpng.c
blob137a8e15e3311a57376398ae6839288e9a00e243
1 /*
2 * Copyright 2016 Dmitry Timoshkov
3 * Copyright 2020 Esme Povirk
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #include <stdarg.h>
21 #include <png.h>
23 #include "ntstatus.h"
24 #define WIN32_NO_STATUS
25 #include "windef.h"
26 #include "winternl.h"
27 #include "winbase.h"
28 #include "objbase.h"
30 #include "wincodecs_private.h"
32 #include "wine/debug.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
36 struct png_decoder
38 struct decoder decoder;
39 IStream *stream;
40 struct decoder_frame decoder_frame;
41 UINT stride;
42 BYTE *image_bits;
43 BYTE *color_profile;
44 DWORD color_profile_len;
47 static inline struct png_decoder *impl_from_decoder(struct decoder* iface)
49 return CONTAINING_RECORD(iface, struct png_decoder, decoder);
52 static void user_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
54 IStream *stream = png_get_io_ptr(png_ptr);
55 HRESULT hr;
56 ULONG bytesread;
58 hr = stream_read(stream, data, length, &bytesread);
59 if (FAILED(hr) || bytesread != length)
61 png_error(png_ptr, "failed reading data");
65 static HRESULT CDECL png_decoder_initialize(struct decoder *iface, IStream *stream, struct decoder_stat *st)
67 struct png_decoder *This = impl_from_decoder(iface);
68 png_structp png_ptr;
69 png_infop info_ptr;
70 HRESULT hr = E_FAIL;
71 int color_type, bit_depth;
72 png_bytep trans;
73 int num_trans;
74 png_uint_32 transparency;
75 png_color_16p trans_values;
76 png_uint_32 ret, xres, yres;
77 int unit_type;
78 png_colorp png_palette;
79 int num_palette;
80 int i;
81 UINT image_size;
82 png_bytep *row_pointers=NULL;
83 png_charp cp_name;
84 png_bytep cp_profile;
85 png_uint_32 cp_len;
86 int cp_compression;
88 png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
89 if (!png_ptr)
91 return E_FAIL;
94 info_ptr = png_create_info_struct(png_ptr);
95 if (!info_ptr)
97 png_destroy_read_struct(&png_ptr, NULL, NULL);
98 return E_FAIL;
101 /* set up setjmp/longjmp error handling */
102 if (setjmp(png_jmpbuf(png_ptr)))
104 hr = WINCODEC_ERR_UNKNOWNIMAGEFORMAT;
105 goto end;
107 png_set_crc_action(png_ptr, PNG_CRC_QUIET_USE, PNG_CRC_QUIET_USE);
108 png_set_chunk_malloc_max(png_ptr, 0);
110 /* seek to the start of the stream */
111 hr = stream_seek(stream, 0, STREAM_SEEK_SET, NULL);
112 if (FAILED(hr))
114 goto end;
117 /* set up custom i/o handling */
118 png_set_read_fn(png_ptr, stream, user_read_data);
120 /* read the header */
121 png_read_info(png_ptr, info_ptr);
123 /* choose a pixel format */
124 color_type = png_get_color_type(png_ptr, info_ptr);
125 bit_depth = png_get_bit_depth(png_ptr, info_ptr);
127 /* PNGs with bit-depth greater than 8 are network byte order. Windows does not expect this. */
128 if (bit_depth > 8)
129 png_set_swap(png_ptr);
131 /* check for color-keyed alpha */
132 transparency = png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, &trans_values);
133 if (!transparency)
134 num_trans = 0;
136 if (transparency && (color_type == PNG_COLOR_TYPE_RGB ||
137 (color_type == PNG_COLOR_TYPE_GRAY && bit_depth == 16)))
139 /* expand to RGBA */
140 if (color_type == PNG_COLOR_TYPE_GRAY)
141 png_set_gray_to_rgb(png_ptr);
142 png_set_tRNS_to_alpha(png_ptr);
143 color_type = PNG_COLOR_TYPE_RGB_ALPHA;
146 switch (color_type)
148 case PNG_COLOR_TYPE_GRAY_ALPHA:
149 /* WIC does not support grayscale alpha formats so use RGBA */
150 png_set_gray_to_rgb(png_ptr);
151 /* fall through */
152 case PNG_COLOR_TYPE_RGB_ALPHA:
153 This->decoder_frame.bpp = bit_depth * 4;
154 switch (bit_depth)
156 case 8:
157 png_set_bgr(png_ptr);
158 This->decoder_frame.pixel_format = GUID_WICPixelFormat32bppBGRA;
159 break;
160 case 16: This->decoder_frame.pixel_format = GUID_WICPixelFormat64bppRGBA; break;
161 default:
162 ERR("invalid RGBA bit depth: %i\n", bit_depth);
163 hr = E_FAIL;
164 goto end;
166 break;
167 case PNG_COLOR_TYPE_GRAY:
168 This->decoder_frame.bpp = bit_depth;
169 if (!transparency)
171 switch (bit_depth)
173 case 1: This->decoder_frame.pixel_format = GUID_WICPixelFormatBlackWhite; break;
174 case 2: This->decoder_frame.pixel_format = GUID_WICPixelFormat2bppGray; break;
175 case 4: This->decoder_frame.pixel_format = GUID_WICPixelFormat4bppGray; break;
176 case 8: This->decoder_frame.pixel_format = GUID_WICPixelFormat8bppGray; break;
177 case 16: This->decoder_frame.pixel_format = GUID_WICPixelFormat16bppGray; break;
178 default:
179 ERR("invalid grayscale bit depth: %i\n", bit_depth);
180 hr = E_FAIL;
181 goto end;
183 break;
185 /* else fall through */
186 case PNG_COLOR_TYPE_PALETTE:
187 This->decoder_frame.bpp = bit_depth;
188 switch (bit_depth)
190 case 1: This->decoder_frame.pixel_format = GUID_WICPixelFormat1bppIndexed; break;
191 case 2: This->decoder_frame.pixel_format = GUID_WICPixelFormat2bppIndexed; break;
192 case 4: This->decoder_frame.pixel_format = GUID_WICPixelFormat4bppIndexed; break;
193 case 8: This->decoder_frame.pixel_format = GUID_WICPixelFormat8bppIndexed; break;
194 default:
195 ERR("invalid indexed color bit depth: %i\n", bit_depth);
196 hr = E_FAIL;
197 goto end;
199 break;
200 case PNG_COLOR_TYPE_RGB:
201 This->decoder_frame.bpp = bit_depth * 3;
202 switch (bit_depth)
204 case 8:
205 png_set_bgr(png_ptr);
206 This->decoder_frame.pixel_format = GUID_WICPixelFormat24bppBGR;
207 break;
208 case 16: This->decoder_frame.pixel_format = GUID_WICPixelFormat48bppRGB; break;
209 default:
210 ERR("invalid RGB color bit depth: %i\n", bit_depth);
211 hr = E_FAIL;
212 goto end;
214 break;
215 default:
216 ERR("invalid color type %i\n", color_type);
217 hr = E_FAIL;
218 goto end;
221 This->decoder_frame.width = png_get_image_width(png_ptr, info_ptr);
222 This->decoder_frame.height = png_get_image_height(png_ptr, info_ptr);
224 ret = png_get_pHYs(png_ptr, info_ptr, &xres, &yres, &unit_type);
226 if (ret && unit_type == PNG_RESOLUTION_METER)
228 This->decoder_frame.dpix = xres * 0.0254;
229 This->decoder_frame.dpiy = yres * 0.0254;
231 else
233 WARN("no pHYs block present\n");
234 This->decoder_frame.dpix = This->decoder_frame.dpiy = 96.0;
237 ret = png_get_iCCP(png_ptr, info_ptr, &cp_name, &cp_compression, &cp_profile, &cp_len);
238 if (ret)
240 This->decoder_frame.num_color_contexts = 1;
241 This->color_profile_len = cp_len;
242 This->color_profile = malloc(cp_len);
243 if (!This->color_profile)
245 hr = E_OUTOFMEMORY;
246 goto end;
248 memcpy(This->color_profile, cp_profile, cp_len);
250 else
251 This->decoder_frame.num_color_contexts = 0;
253 if (color_type == PNG_COLOR_TYPE_PALETTE)
255 ret = png_get_PLTE(png_ptr, info_ptr, &png_palette, &num_palette);
256 if (!ret)
258 ERR("paletted image with no PLTE chunk\n");
259 hr = E_FAIL;
260 goto end;
263 if (num_palette > 256)
265 ERR("palette has %i colors?!\n", num_palette);
266 hr = E_FAIL;
267 goto end;
270 This->decoder_frame.num_colors = num_palette;
271 for (i=0; i<num_palette; i++)
273 BYTE alpha = (i < num_trans) ? trans[i] : 0xff;
274 This->decoder_frame.palette[i] = (alpha << 24 |
275 png_palette[i].red << 16|
276 png_palette[i].green << 8|
277 png_palette[i].blue);
280 else if (color_type == PNG_COLOR_TYPE_GRAY && transparency && bit_depth <= 8) {
281 num_palette = 1 << bit_depth;
283 This->decoder_frame.num_colors = num_palette;
284 for (i=0; i<num_palette; i++)
286 BYTE alpha = (i == trans_values[0].gray) ? 0 : 0xff;
287 BYTE val = i * 255 / (num_palette - 1);
288 This->decoder_frame.palette[i] = (alpha << 24 | val << 16 | val << 8 | val);
291 else
293 This->decoder_frame.num_colors = 0;
296 This->stride = (This->decoder_frame.width * This->decoder_frame.bpp + 7) / 8;
297 image_size = This->stride * This->decoder_frame.height;
299 This->image_bits = malloc(image_size);
300 if (!This->image_bits)
302 hr = E_OUTOFMEMORY;
303 goto end;
306 row_pointers = malloc(sizeof(png_bytep)*This->decoder_frame.height);
307 if (!row_pointers)
309 hr = E_OUTOFMEMORY;
310 goto end;
313 for (i=0; i<This->decoder_frame.height; i++)
314 row_pointers[i] = This->image_bits + i * This->stride;
316 png_read_image(png_ptr, row_pointers);
318 free(row_pointers);
319 row_pointers = NULL;
321 /* png_read_end intentionally not called to not seek to the end of the file */
323 st->flags = WICBitmapDecoderCapabilityCanDecodeAllImages |
324 WICBitmapDecoderCapabilityCanDecodeSomeImages |
325 WICBitmapDecoderCapabilityCanEnumerateMetadata;
326 st->frame_count = 1;
328 This->stream = stream;
330 hr = S_OK;
332 end:
333 png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
334 free(row_pointers);
335 if (FAILED(hr))
337 free(This->image_bits);
338 This->image_bits = NULL;
339 free(This->color_profile);
340 This->color_profile = NULL;
342 return hr;
345 static HRESULT CDECL png_decoder_get_frame_info(struct decoder *iface, UINT frame, struct decoder_frame *info)
347 struct png_decoder *This = impl_from_decoder(iface);
348 *info = This->decoder_frame;
349 return S_OK;
352 static HRESULT CDECL png_decoder_copy_pixels(struct decoder *iface, UINT frame,
353 const WICRect *prc, UINT stride, UINT buffersize, BYTE *buffer)
355 struct png_decoder *This = impl_from_decoder(iface);
357 return copy_pixels(This->decoder_frame.bpp, This->image_bits,
358 This->decoder_frame.width, This->decoder_frame.height, This->stride,
359 prc, stride, buffersize, buffer);
362 static HRESULT CDECL png_decoder_get_metadata_blocks(struct decoder* iface,
363 UINT frame, UINT *count, struct decoder_block **blocks)
365 struct png_decoder *This = impl_from_decoder(iface);
366 HRESULT hr;
367 struct decoder_block *result = NULL;
368 ULONGLONG seek;
369 BYTE chunk_type[4];
370 ULONG chunk_size;
371 ULONGLONG chunk_start;
372 ULONG metadata_blocks_size = 0;
374 seek = 8;
375 *count = 0;
379 hr = stream_seek(This->stream, seek, STREAM_SEEK_SET, &chunk_start);
380 if (FAILED(hr)) goto end;
382 hr = read_png_chunk(This->stream, chunk_type, NULL, &chunk_size);
383 if (FAILED(hr)) goto end;
385 if (chunk_type[0] >= 'a' && chunk_type[0] <= 'z' &&
386 memcmp(chunk_type, "tRNS", 4) && memcmp(chunk_type, "pHYs", 4))
388 /* This chunk is considered metadata. */
389 if (*count == metadata_blocks_size)
391 struct decoder_block *new_metadata_blocks;
392 ULONG new_metadata_blocks_size;
394 new_metadata_blocks_size = 4 + metadata_blocks_size * 2;
395 new_metadata_blocks = malloc(new_metadata_blocks_size * sizeof(*new_metadata_blocks));
397 if (!new_metadata_blocks)
399 hr = E_OUTOFMEMORY;
400 goto end;
403 memcpy(new_metadata_blocks, result,
404 *count * sizeof(*new_metadata_blocks));
406 free(result);
407 result = new_metadata_blocks;
408 metadata_blocks_size = new_metadata_blocks_size;
411 result[*count].offset = chunk_start;
412 result[*count].length = chunk_size + 12;
413 result[*count].options = WICMetadataCreationAllowUnknown;
414 (*count)++;
417 seek = chunk_start + chunk_size + 12; /* skip data and CRC */
418 } while (memcmp(chunk_type, "IEND", 4));
420 end:
421 if (SUCCEEDED(hr))
423 *blocks = result;
425 else
427 *count = 0;
428 *blocks = NULL;
429 free(result);
431 return hr;
434 static HRESULT CDECL png_decoder_get_color_context(struct decoder* iface, UINT frame, UINT num,
435 BYTE **data, DWORD *datasize)
437 struct png_decoder *This = impl_from_decoder(iface);
439 *data = malloc(This->color_profile_len);
440 *datasize = This->color_profile_len;
442 if (!*data)
443 return E_OUTOFMEMORY;
445 memcpy(*data, This->color_profile, This->color_profile_len);
447 return S_OK;
450 static void CDECL png_decoder_destroy(struct decoder* iface)
452 struct png_decoder *This = impl_from_decoder(iface);
454 free(This->image_bits);
455 free(This->color_profile);
456 free(This);
459 static const struct decoder_funcs png_decoder_vtable = {
460 png_decoder_initialize,
461 png_decoder_get_frame_info,
462 png_decoder_copy_pixels,
463 png_decoder_get_metadata_blocks,
464 png_decoder_get_color_context,
465 png_decoder_destroy
468 HRESULT CDECL png_decoder_create(struct decoder_info *info, struct decoder **result)
470 struct png_decoder *This;
472 This = malloc(sizeof(*This));
474 if (!This)
476 return E_OUTOFMEMORY;
479 This->decoder.vtable = &png_decoder_vtable;
480 This->image_bits = NULL;
481 This->color_profile = NULL;
482 *result = &This->decoder;
484 info->container_format = GUID_ContainerFormatPng;
485 info->block_format = GUID_ContainerFormatPng;
486 info->clsid = CLSID_WICPngDecoder;
488 return S_OK;
491 struct png_pixelformat {
492 const WICPixelFormatGUID *guid;
493 UINT bpp;
494 int bit_depth;
495 int color_type;
496 BOOL remove_filler;
497 BOOL swap_rgb;
500 static const struct png_pixelformat formats[] = {
501 {&GUID_WICPixelFormat32bppBGRA, 32, 8, PNG_COLOR_TYPE_RGB_ALPHA, 0, 1},
502 {&GUID_WICPixelFormat24bppBGR, 24, 8, PNG_COLOR_TYPE_RGB, 0, 1},
503 {&GUID_WICPixelFormatBlackWhite, 1, 1, PNG_COLOR_TYPE_GRAY, 0, 0},
504 {&GUID_WICPixelFormat2bppGray, 2, 2, PNG_COLOR_TYPE_GRAY, 0, 0},
505 {&GUID_WICPixelFormat4bppGray, 4, 4, PNG_COLOR_TYPE_GRAY, 0, 0},
506 {&GUID_WICPixelFormat8bppGray, 8, 8, PNG_COLOR_TYPE_GRAY, 0, 0},
507 {&GUID_WICPixelFormat16bppGray, 16, 16, PNG_COLOR_TYPE_GRAY, 0, 0},
508 {&GUID_WICPixelFormat32bppBGR, 32, 8, PNG_COLOR_TYPE_RGB, 1, 1},
509 {&GUID_WICPixelFormat48bppRGB, 48, 16, PNG_COLOR_TYPE_RGB, 0, 0},
510 {&GUID_WICPixelFormat64bppRGBA, 64, 16, PNG_COLOR_TYPE_RGB_ALPHA, 0, 0},
511 {&GUID_WICPixelFormat1bppIndexed, 1, 1, PNG_COLOR_TYPE_PALETTE, 0, 0},
512 {&GUID_WICPixelFormat2bppIndexed, 2, 2, PNG_COLOR_TYPE_PALETTE, 0, 0},
513 {&GUID_WICPixelFormat4bppIndexed, 4, 4, PNG_COLOR_TYPE_PALETTE, 0, 0},
514 {&GUID_WICPixelFormat8bppIndexed, 8, 8, PNG_COLOR_TYPE_PALETTE, 0, 0},
515 {NULL},
518 struct png_encoder
520 struct encoder encoder;
521 IStream *stream;
522 png_structp png_ptr;
523 png_infop info_ptr;
524 struct encoder_frame encoder_frame;
525 const struct png_pixelformat *format;
526 BYTE *data;
527 UINT stride;
528 UINT passes;
529 UINT lines_written;
532 static inline struct png_encoder *impl_from_encoder(struct encoder* iface)
534 return CONTAINING_RECORD(iface, struct png_encoder, encoder);
537 static void user_write_data(png_structp png_ptr, png_bytep data, png_size_t length)
539 struct png_encoder *This = png_get_io_ptr(png_ptr);
540 HRESULT hr;
541 ULONG byteswritten;
543 hr = stream_write(This->stream, data, length, &byteswritten);
544 if (FAILED(hr) || byteswritten != length)
546 png_error(png_ptr, "failed writing data");
550 static void user_flush(png_structp png_ptr)
554 static HRESULT CDECL png_encoder_initialize(struct encoder *encoder, IStream *stream)
556 struct png_encoder *This = impl_from_encoder(encoder);
558 TRACE("(%p,%p)\n", encoder, stream);
560 /* initialize libpng */
561 This->png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
562 if (!This->png_ptr)
563 return E_FAIL;
565 This->info_ptr = png_create_info_struct(This->png_ptr);
566 if (!This->info_ptr)
568 png_destroy_write_struct(&This->png_ptr, NULL);
569 This->png_ptr = NULL;
570 return E_FAIL;
573 This->stream = stream;
575 /* set up setjmp/longjmp error handling */
576 if (setjmp(png_jmpbuf(This->png_ptr)))
578 png_destroy_write_struct(&This->png_ptr, &This->info_ptr);
579 This->png_ptr = NULL;
580 This->stream = NULL;
581 return E_FAIL;
584 /* set up custom i/o handling */
585 png_set_write_fn(This->png_ptr, This, user_write_data, user_flush);
587 return S_OK;
590 static HRESULT CDECL png_encoder_get_supported_format(struct encoder* iface, GUID *pixel_format, DWORD *bpp, BOOL *indexed)
592 int i;
594 for (i=0; formats[i].guid; i++)
596 if (memcmp(formats[i].guid, pixel_format, sizeof(GUID)) == 0)
597 break;
600 if (!formats[i].guid)
601 i = 0;
603 *pixel_format = *formats[i].guid;
604 *bpp = formats[i].bpp;
605 *indexed = (formats[i].color_type == PNG_COLOR_TYPE_PALETTE);
607 return S_OK;
610 static HRESULT CDECL png_encoder_create_frame(struct encoder *encoder, const struct encoder_frame *encoder_frame)
612 struct png_encoder *This = impl_from_encoder(encoder);
613 int i;
615 for (i=0; formats[i].guid; i++)
617 if (memcmp(formats[i].guid, &encoder_frame->pixel_format, sizeof(GUID)) == 0)
619 This->format = &formats[i];
620 break;
624 if (!formats[i].guid)
626 ERR("invalid pixel format %s\n", wine_dbgstr_guid(&encoder_frame->pixel_format));
627 return E_FAIL;
630 /* set up setjmp/longjmp error handling */
631 if (setjmp(png_jmpbuf(This->png_ptr)))
632 return E_FAIL;
634 This->encoder_frame = *encoder_frame;
635 This->lines_written = 0;
637 if (encoder_frame->interlace)
639 /* libpng requires us to write all data multiple times in this case. */
640 This->stride = (This->format->bpp * encoder_frame->width + 7)/8;
641 This->data = malloc(encoder_frame->height * This->stride);
642 if (!This->data)
643 return E_OUTOFMEMORY;
646 /* Tell PNG we need to byte swap if writing a >8-bpp image */
647 if (This->format->bit_depth > 8)
648 png_set_swap(This->png_ptr);
650 png_set_IHDR(This->png_ptr, This->info_ptr, encoder_frame->width, encoder_frame->height,
651 This->format->bit_depth, This->format->color_type,
652 encoder_frame->interlace ? PNG_INTERLACE_ADAM7 : PNG_INTERLACE_NONE,
653 PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
655 if (encoder_frame->dpix != 0.0 && encoder_frame->dpiy != 0.0)
657 png_set_pHYs(This->png_ptr, This->info_ptr, (encoder_frame->dpix+0.0127) / 0.0254,
658 (encoder_frame->dpiy+0.0127) / 0.0254, PNG_RESOLUTION_METER);
661 if (This->format->color_type == PNG_COLOR_TYPE_PALETTE && encoder_frame->num_colors)
663 png_color png_palette[256];
664 png_byte trans[256];
665 UINT i, num_trans = 0, colors;
667 /* Newer libpng versions don't accept larger palettes than the declared
668 * bit depth, so we need to generate the palette of the correct length.
670 colors = min(encoder_frame->num_colors, 1 << This->format->bit_depth);
672 for (i = 0; i < colors; i++)
674 png_palette[i].red = (encoder_frame->palette[i] >> 16) & 0xff;
675 png_palette[i].green = (encoder_frame->palette[i] >> 8) & 0xff;
676 png_palette[i].blue = encoder_frame->palette[i] & 0xff;
677 trans[i] = (encoder_frame->palette[i] >> 24) & 0xff;
678 if (trans[i] != 0xff)
679 num_trans = i+1;
682 png_set_PLTE(This->png_ptr, This->info_ptr, png_palette, colors);
684 if (num_trans)
685 png_set_tRNS(This->png_ptr, This->info_ptr, trans, num_trans, NULL);
688 png_write_info(This->png_ptr, This->info_ptr);
690 if (This->format->remove_filler)
691 png_set_filler(This->png_ptr, 0, PNG_FILLER_AFTER);
693 if (This->format->swap_rgb)
694 png_set_bgr(This->png_ptr);
696 if (encoder_frame->interlace)
697 This->passes = png_set_interlace_handling(This->png_ptr);
699 if (encoder_frame->filter != WICPngFilterUnspecified)
701 static const int png_filter_map[] =
703 /* WICPngFilterUnspecified */ PNG_NO_FILTERS,
704 /* WICPngFilterNone */ PNG_FILTER_NONE,
705 /* WICPngFilterSub */ PNG_FILTER_SUB,
706 /* WICPngFilterUp */ PNG_FILTER_UP,
707 /* WICPngFilterAverage */ PNG_FILTER_AVG,
708 /* WICPngFilterPaeth */ PNG_FILTER_PAETH,
709 /* WICPngFilterAdaptive */ PNG_ALL_FILTERS,
712 png_set_filter(This->png_ptr, 0, png_filter_map[encoder_frame->filter]);
715 return S_OK;
718 static HRESULT CDECL png_encoder_write_lines(struct encoder* encoder, BYTE *data, DWORD line_count, DWORD stride)
720 struct png_encoder *This = impl_from_encoder(encoder);
721 png_byte **row_pointers=NULL;
722 UINT i;
724 if (This->encoder_frame.interlace)
726 /* Just store the data so we can write it in multiple passes in Commit. */
727 for (i=0; i<line_count; i++)
728 memcpy(This->data + This->stride * (This->lines_written + i),
729 data + stride * i,
730 This->stride);
732 This->lines_written += line_count;
734 return S_OK;
737 /* set up setjmp/longjmp error handling */
738 if (setjmp(png_jmpbuf(This->png_ptr)))
740 free(row_pointers);
741 return E_FAIL;
744 row_pointers = malloc(line_count * sizeof(png_byte*));
745 if (!row_pointers)
746 return E_OUTOFMEMORY;
748 for (i=0; i<line_count; i++)
749 row_pointers[i] = data + stride * i;
751 png_write_rows(This->png_ptr, row_pointers, line_count);
752 This->lines_written += line_count;
754 free(row_pointers);
756 return S_OK;
759 static HRESULT CDECL png_encoder_commit_frame(struct encoder *encoder)
761 struct png_encoder *This = impl_from_encoder(encoder);
762 png_byte **row_pointers=NULL;
764 /* set up setjmp/longjmp error handling */
765 if (setjmp(png_jmpbuf(This->png_ptr)))
767 free(row_pointers);
768 return E_FAIL;
771 if (This->encoder_frame.interlace)
773 int i;
775 row_pointers = malloc(This->encoder_frame.height * sizeof(png_byte*));
776 if (!row_pointers)
777 return E_OUTOFMEMORY;
779 for (i=0; i<This->encoder_frame.height; i++)
780 row_pointers[i] = This->data + This->stride * i;
782 for (i=0; i<This->passes; i++)
783 png_write_rows(This->png_ptr, row_pointers, This->encoder_frame.height);
786 png_write_end(This->png_ptr, This->info_ptr);
788 free(row_pointers);
790 return S_OK;
793 static HRESULT CDECL png_encoder_commit_file(struct encoder *encoder)
795 return S_OK;
798 static void CDECL png_encoder_destroy(struct encoder *encoder)
800 struct png_encoder *This = impl_from_encoder(encoder);
801 if (This->png_ptr)
802 png_destroy_write_struct(&This->png_ptr, &This->info_ptr);
803 free(This->data);
804 free(This);
807 static const struct encoder_funcs png_encoder_vtable = {
808 png_encoder_initialize,
809 png_encoder_get_supported_format,
810 png_encoder_create_frame,
811 png_encoder_write_lines,
812 png_encoder_commit_frame,
813 png_encoder_commit_file,
814 png_encoder_destroy
817 HRESULT CDECL png_encoder_create(struct encoder_info *info, struct encoder **result)
819 struct png_encoder *This;
821 This = malloc(sizeof(*This));
823 if (!This)
825 return E_OUTOFMEMORY;
828 This->encoder.vtable = &png_encoder_vtable;
829 This->png_ptr = NULL;
830 This->info_ptr = NULL;
831 This->data = NULL;
832 *result = &This->encoder;
834 info->flags = ENCODER_FLAGS_SUPPORTS_METADATA;
835 info->container_format = GUID_ContainerFormatPng;
836 info->clsid = CLSID_WICPngEncoder;
837 info->encoder_options[0] = ENCODER_OPTION_INTERLACE;
838 info->encoder_options[1] = ENCODER_OPTION_FILTER;
839 info->encoder_options[2] = ENCODER_OPTION_END;
841 return S_OK;