dinput: Implement SetProperty DIPROP_APPDATA using enum_objects.
[wine.git] / dlls / windowscodecs / libpng.c
blob27a735550f3fca0252ca825d16622363892bf8a5
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 #define NONAMELESSUNION
25 #include "ntstatus.h"
26 #define WIN32_NO_STATUS
27 #include "windef.h"
28 #include "winternl.h"
29 #include "winbase.h"
30 #include "objbase.h"
32 #include "wincodecs_private.h"
34 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
38 struct png_decoder
40 struct decoder decoder;
41 IStream *stream;
42 struct decoder_frame decoder_frame;
43 UINT stride;
44 BYTE *image_bits;
45 BYTE *color_profile;
46 DWORD color_profile_len;
49 static inline struct png_decoder *impl_from_decoder(struct decoder* iface)
51 return CONTAINING_RECORD(iface, struct png_decoder, decoder);
54 static void user_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
56 IStream *stream = png_get_io_ptr(png_ptr);
57 HRESULT hr;
58 ULONG bytesread;
60 hr = stream_read(stream, data, length, &bytesread);
61 if (FAILED(hr) || bytesread != length)
63 png_error(png_ptr, "failed reading data");
67 static HRESULT CDECL png_decoder_initialize(struct decoder *iface, IStream *stream, struct decoder_stat *st)
69 struct png_decoder *This = impl_from_decoder(iface);
70 png_structp png_ptr;
71 png_infop info_ptr;
72 HRESULT hr = E_FAIL;
73 int color_type, bit_depth;
74 png_bytep trans;
75 int num_trans;
76 png_uint_32 transparency;
77 png_color_16p trans_values;
78 png_uint_32 ret, xres, yres;
79 int unit_type;
80 png_colorp png_palette;
81 int num_palette;
82 int i;
83 UINT image_size;
84 png_bytep *row_pointers=NULL;
85 png_charp cp_name;
86 png_bytep cp_profile;
87 png_uint_32 cp_len;
88 int cp_compression;
90 png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
91 if (!png_ptr)
93 return E_FAIL;
96 info_ptr = png_create_info_struct(png_ptr);
97 if (!info_ptr)
99 png_destroy_read_struct(&png_ptr, NULL, NULL);
100 return E_FAIL;
103 /* set up setjmp/longjmp error handling */
104 if (setjmp(png_jmpbuf(png_ptr)))
106 hr = WINCODEC_ERR_UNKNOWNIMAGEFORMAT;
107 goto end;
109 png_set_crc_action(png_ptr, PNG_CRC_QUIET_USE, PNG_CRC_QUIET_USE);
111 /* seek to the start of the stream */
112 hr = stream_seek(stream, 0, STREAM_SEEK_SET, NULL);
113 if (FAILED(hr))
115 goto end;
118 /* set up custom i/o handling */
119 png_set_read_fn(png_ptr, stream, user_read_data);
121 /* read the header */
122 png_read_info(png_ptr, info_ptr);
124 /* choose a pixel format */
125 color_type = png_get_color_type(png_ptr, info_ptr);
126 bit_depth = png_get_bit_depth(png_ptr, info_ptr);
128 /* PNGs with bit-depth greater than 8 are network byte order. Windows does not expect this. */
129 if (bit_depth > 8)
130 png_set_swap(png_ptr);
132 /* check for color-keyed alpha */
133 transparency = png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, &trans_values);
134 if (!transparency)
135 num_trans = 0;
137 if (transparency && (color_type == PNG_COLOR_TYPE_RGB ||
138 (color_type == PNG_COLOR_TYPE_GRAY && bit_depth == 16)))
140 /* expand to RGBA */
141 if (color_type == PNG_COLOR_TYPE_GRAY)
142 png_set_gray_to_rgb(png_ptr);
143 png_set_tRNS_to_alpha(png_ptr);
144 color_type = PNG_COLOR_TYPE_RGB_ALPHA;
147 switch (color_type)
149 case PNG_COLOR_TYPE_GRAY_ALPHA:
150 /* WIC does not support grayscale alpha formats so use RGBA */
151 png_set_gray_to_rgb(png_ptr);
152 /* fall through */
153 case PNG_COLOR_TYPE_RGB_ALPHA:
154 This->decoder_frame.bpp = bit_depth * 4;
155 switch (bit_depth)
157 case 8:
158 png_set_bgr(png_ptr);
159 This->decoder_frame.pixel_format = GUID_WICPixelFormat32bppBGRA;
160 break;
161 case 16: This->decoder_frame.pixel_format = GUID_WICPixelFormat64bppRGBA; break;
162 default:
163 ERR("invalid RGBA bit depth: %i\n", bit_depth);
164 hr = E_FAIL;
165 goto end;
167 break;
168 case PNG_COLOR_TYPE_GRAY:
169 This->decoder_frame.bpp = bit_depth;
170 if (!transparency)
172 switch (bit_depth)
174 case 1: This->decoder_frame.pixel_format = GUID_WICPixelFormatBlackWhite; break;
175 case 2: This->decoder_frame.pixel_format = GUID_WICPixelFormat2bppGray; break;
176 case 4: This->decoder_frame.pixel_format = GUID_WICPixelFormat4bppGray; break;
177 case 8: This->decoder_frame.pixel_format = GUID_WICPixelFormat8bppGray; break;
178 case 16: This->decoder_frame.pixel_format = GUID_WICPixelFormat16bppGray; break;
179 default:
180 ERR("invalid grayscale bit depth: %i\n", bit_depth);
181 hr = E_FAIL;
182 goto end;
184 break;
186 /* else fall through */
187 case PNG_COLOR_TYPE_PALETTE:
188 This->decoder_frame.bpp = bit_depth;
189 switch (bit_depth)
191 case 1: This->decoder_frame.pixel_format = GUID_WICPixelFormat1bppIndexed; break;
192 case 2: This->decoder_frame.pixel_format = GUID_WICPixelFormat2bppIndexed; break;
193 case 4: This->decoder_frame.pixel_format = GUID_WICPixelFormat4bppIndexed; break;
194 case 8: This->decoder_frame.pixel_format = GUID_WICPixelFormat8bppIndexed; break;
195 default:
196 ERR("invalid indexed color bit depth: %i\n", bit_depth);
197 hr = E_FAIL;
198 goto end;
200 break;
201 case PNG_COLOR_TYPE_RGB:
202 This->decoder_frame.bpp = bit_depth * 3;
203 switch (bit_depth)
205 case 8:
206 png_set_bgr(png_ptr);
207 This->decoder_frame.pixel_format = GUID_WICPixelFormat24bppBGR;
208 break;
209 case 16: This->decoder_frame.pixel_format = GUID_WICPixelFormat48bppRGB; break;
210 default:
211 ERR("invalid RGB color bit depth: %i\n", bit_depth);
212 hr = E_FAIL;
213 goto end;
215 break;
216 default:
217 ERR("invalid color type %i\n", color_type);
218 hr = E_FAIL;
219 goto end;
222 This->decoder_frame.width = png_get_image_width(png_ptr, info_ptr);
223 This->decoder_frame.height = png_get_image_height(png_ptr, info_ptr);
225 ret = png_get_pHYs(png_ptr, info_ptr, &xres, &yres, &unit_type);
227 if (ret && unit_type == PNG_RESOLUTION_METER)
229 This->decoder_frame.dpix = xres * 0.0254;
230 This->decoder_frame.dpiy = yres * 0.0254;
232 else
234 WARN("no pHYs block present\n");
235 This->decoder_frame.dpix = This->decoder_frame.dpiy = 96.0;
238 ret = png_get_iCCP(png_ptr, info_ptr, &cp_name, &cp_compression, &cp_profile, &cp_len);
239 if (ret)
241 This->decoder_frame.num_color_contexts = 1;
242 This->color_profile_len = cp_len;
243 This->color_profile = malloc(cp_len);
244 if (!This->color_profile)
246 hr = E_OUTOFMEMORY;
247 goto end;
249 memcpy(This->color_profile, cp_profile, cp_len);
251 else
252 This->decoder_frame.num_color_contexts = 0;
254 if (color_type == PNG_COLOR_TYPE_PALETTE)
256 ret = png_get_PLTE(png_ptr, info_ptr, &png_palette, &num_palette);
257 if (!ret)
259 ERR("paletted image with no PLTE chunk\n");
260 hr = E_FAIL;
261 goto end;
264 if (num_palette > 256)
266 ERR("palette has %i colors?!\n", num_palette);
267 hr = E_FAIL;
268 goto end;
271 This->decoder_frame.num_colors = num_palette;
272 for (i=0; i<num_palette; i++)
274 BYTE alpha = (i < num_trans) ? trans[i] : 0xff;
275 This->decoder_frame.palette[i] = (alpha << 24 |
276 png_palette[i].red << 16|
277 png_palette[i].green << 8|
278 png_palette[i].blue);
281 else if (color_type == PNG_COLOR_TYPE_GRAY && transparency && bit_depth <= 8) {
282 num_palette = 1 << bit_depth;
284 This->decoder_frame.num_colors = num_palette;
285 for (i=0; i<num_palette; i++)
287 BYTE alpha = (i == trans_values[0].gray) ? 0 : 0xff;
288 BYTE val = i * 255 / (num_palette - 1);
289 This->decoder_frame.palette[i] = (alpha << 24 | val << 16 | val << 8 | val);
292 else
294 This->decoder_frame.num_colors = 0;
297 This->stride = (This->decoder_frame.width * This->decoder_frame.bpp + 7) / 8;
298 image_size = This->stride * This->decoder_frame.height;
300 This->image_bits = malloc(image_size);
301 if (!This->image_bits)
303 hr = E_OUTOFMEMORY;
304 goto end;
307 row_pointers = malloc(sizeof(png_bytep)*This->decoder_frame.height);
308 if (!row_pointers)
310 hr = E_OUTOFMEMORY;
311 goto end;
314 for (i=0; i<This->decoder_frame.height; i++)
315 row_pointers[i] = This->image_bits + i * This->stride;
317 png_read_image(png_ptr, row_pointers);
319 free(row_pointers);
320 row_pointers = NULL;
322 /* png_read_end intentionally not called to not seek to the end of the file */
324 st->flags = WICBitmapDecoderCapabilityCanDecodeAllImages |
325 WICBitmapDecoderCapabilityCanDecodeSomeImages |
326 WICBitmapDecoderCapabilityCanEnumerateMetadata;
327 st->frame_count = 1;
329 This->stream = stream;
331 hr = S_OK;
333 end:
334 png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
335 free(row_pointers);
336 if (FAILED(hr))
338 free(This->image_bits);
339 This->image_bits = NULL;
340 free(This->color_profile);
341 This->color_profile = NULL;
343 return hr;
346 static HRESULT CDECL png_decoder_get_frame_info(struct decoder *iface, UINT frame, struct decoder_frame *info)
348 struct png_decoder *This = impl_from_decoder(iface);
349 *info = This->decoder_frame;
350 return S_OK;
353 static HRESULT CDECL png_decoder_copy_pixels(struct decoder *iface, UINT frame,
354 const WICRect *prc, UINT stride, UINT buffersize, BYTE *buffer)
356 struct png_decoder *This = impl_from_decoder(iface);
358 return copy_pixels(This->decoder_frame.bpp, This->image_bits,
359 This->decoder_frame.width, This->decoder_frame.height, This->stride,
360 prc, stride, buffersize, buffer);
363 static HRESULT CDECL png_decoder_get_metadata_blocks(struct decoder* iface,
364 UINT frame, UINT *count, struct decoder_block **blocks)
366 struct png_decoder *This = impl_from_decoder(iface);
367 HRESULT hr;
368 struct decoder_block *result = NULL;
369 ULONGLONG seek;
370 BYTE chunk_type[4];
371 ULONG chunk_size;
372 ULONGLONG chunk_start;
373 ULONG metadata_blocks_size = 0;
375 seek = 8;
376 *count = 0;
380 hr = stream_seek(This->stream, seek, STREAM_SEEK_SET, &chunk_start);
381 if (FAILED(hr)) goto end;
383 hr = read_png_chunk(This->stream, chunk_type, NULL, &chunk_size);
384 if (FAILED(hr)) goto end;
386 if (chunk_type[0] >= 'a' && chunk_type[0] <= 'z' &&
387 memcmp(chunk_type, "tRNS", 4) && memcmp(chunk_type, "pHYs", 4))
389 /* This chunk is considered metadata. */
390 if (*count == metadata_blocks_size)
392 struct decoder_block *new_metadata_blocks;
393 ULONG new_metadata_blocks_size;
395 new_metadata_blocks_size = 4 + metadata_blocks_size * 2;
396 new_metadata_blocks = RtlAllocateHeap(GetProcessHeap(), 0,
397 new_metadata_blocks_size * sizeof(*new_metadata_blocks));
399 if (!new_metadata_blocks)
401 hr = E_OUTOFMEMORY;
402 goto end;
405 memcpy(new_metadata_blocks, result,
406 *count * sizeof(*new_metadata_blocks));
408 RtlFreeHeap(GetProcessHeap(), 0, result);
409 result = new_metadata_blocks;
410 metadata_blocks_size = new_metadata_blocks_size;
413 result[*count].offset = chunk_start;
414 result[*count].length = chunk_size + 12;
415 result[*count].options = WICMetadataCreationAllowUnknown;
416 (*count)++;
419 seek = chunk_start + chunk_size + 12; /* skip data and CRC */
420 } while (memcmp(chunk_type, "IEND", 4));
422 end:
423 if (SUCCEEDED(hr))
425 *blocks = result;
427 else
429 *count = 0;
430 *blocks = NULL;
431 RtlFreeHeap(GetProcessHeap(), 0, result);
433 return hr;
436 static HRESULT CDECL png_decoder_get_color_context(struct decoder* iface, UINT frame, UINT num,
437 BYTE **data, DWORD *datasize)
439 struct png_decoder *This = impl_from_decoder(iface);
441 *data = RtlAllocateHeap(GetProcessHeap(), 0, This->color_profile_len);
442 *datasize = This->color_profile_len;
444 if (!*data)
445 return E_OUTOFMEMORY;
447 memcpy(*data, This->color_profile, This->color_profile_len);
449 return S_OK;
452 static void CDECL png_decoder_destroy(struct decoder* iface)
454 struct png_decoder *This = impl_from_decoder(iface);
456 free(This->image_bits);
457 free(This->color_profile);
458 RtlFreeHeap(GetProcessHeap(), 0, This);
461 static const struct decoder_funcs png_decoder_vtable = {
462 png_decoder_initialize,
463 png_decoder_get_frame_info,
464 png_decoder_copy_pixels,
465 png_decoder_get_metadata_blocks,
466 png_decoder_get_color_context,
467 png_decoder_destroy
470 HRESULT CDECL png_decoder_create(struct decoder_info *info, struct decoder **result)
472 struct png_decoder *This;
474 This = RtlAllocateHeap(GetProcessHeap(), 0, sizeof(*This));
476 if (!This)
478 return E_OUTOFMEMORY;
481 This->decoder.vtable = &png_decoder_vtable;
482 This->image_bits = NULL;
483 This->color_profile = NULL;
484 *result = &This->decoder;
486 info->container_format = GUID_ContainerFormatPng;
487 info->block_format = GUID_ContainerFormatPng;
488 info->clsid = CLSID_WICPngDecoder;
490 return S_OK;
493 struct png_pixelformat {
494 const WICPixelFormatGUID *guid;
495 UINT bpp;
496 int bit_depth;
497 int color_type;
498 BOOL remove_filler;
499 BOOL swap_rgb;
502 static const struct png_pixelformat formats[] = {
503 {&GUID_WICPixelFormat32bppBGRA, 32, 8, PNG_COLOR_TYPE_RGB_ALPHA, 0, 1},
504 {&GUID_WICPixelFormat24bppBGR, 24, 8, PNG_COLOR_TYPE_RGB, 0, 1},
505 {&GUID_WICPixelFormatBlackWhite, 1, 1, PNG_COLOR_TYPE_GRAY, 0, 0},
506 {&GUID_WICPixelFormat2bppGray, 2, 2, PNG_COLOR_TYPE_GRAY, 0, 0},
507 {&GUID_WICPixelFormat4bppGray, 4, 4, PNG_COLOR_TYPE_GRAY, 0, 0},
508 {&GUID_WICPixelFormat8bppGray, 8, 8, PNG_COLOR_TYPE_GRAY, 0, 0},
509 {&GUID_WICPixelFormat16bppGray, 16, 16, PNG_COLOR_TYPE_GRAY, 0, 0},
510 {&GUID_WICPixelFormat32bppBGR, 32, 8, PNG_COLOR_TYPE_RGB, 1, 1},
511 {&GUID_WICPixelFormat48bppRGB, 48, 16, PNG_COLOR_TYPE_RGB, 0, 0},
512 {&GUID_WICPixelFormat64bppRGBA, 64, 16, PNG_COLOR_TYPE_RGB_ALPHA, 0, 0},
513 {&GUID_WICPixelFormat1bppIndexed, 1, 1, PNG_COLOR_TYPE_PALETTE, 0, 0},
514 {&GUID_WICPixelFormat2bppIndexed, 2, 2, PNG_COLOR_TYPE_PALETTE, 0, 0},
515 {&GUID_WICPixelFormat4bppIndexed, 4, 4, PNG_COLOR_TYPE_PALETTE, 0, 0},
516 {&GUID_WICPixelFormat8bppIndexed, 8, 8, PNG_COLOR_TYPE_PALETTE, 0, 0},
517 {NULL},
520 struct png_encoder
522 struct encoder encoder;
523 IStream *stream;
524 png_structp png_ptr;
525 png_infop info_ptr;
526 struct encoder_frame encoder_frame;
527 const struct png_pixelformat *format;
528 BYTE *data;
529 UINT stride;
530 UINT passes;
531 UINT lines_written;
534 static inline struct png_encoder *impl_from_encoder(struct encoder* iface)
536 return CONTAINING_RECORD(iface, struct png_encoder, encoder);
539 static void user_write_data(png_structp png_ptr, png_bytep data, png_size_t length)
541 struct png_encoder *This = png_get_io_ptr(png_ptr);
542 HRESULT hr;
543 ULONG byteswritten;
545 hr = stream_write(This->stream, data, length, &byteswritten);
546 if (FAILED(hr) || byteswritten != length)
548 png_error(png_ptr, "failed writing data");
552 static void user_flush(png_structp png_ptr)
556 static HRESULT CDECL png_encoder_initialize(struct encoder *encoder, IStream *stream)
558 struct png_encoder *This = impl_from_encoder(encoder);
560 TRACE("(%p,%p)\n", encoder, stream);
562 /* initialize libpng */
563 This->png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
564 if (!This->png_ptr)
565 return E_FAIL;
567 This->info_ptr = png_create_info_struct(This->png_ptr);
568 if (!This->info_ptr)
570 png_destroy_write_struct(&This->png_ptr, NULL);
571 This->png_ptr = NULL;
572 return E_FAIL;
575 This->stream = stream;
577 /* set up setjmp/longjmp error handling */
578 if (setjmp(png_jmpbuf(This->png_ptr)))
580 png_destroy_write_struct(&This->png_ptr, &This->info_ptr);
581 This->png_ptr = NULL;
582 This->stream = NULL;
583 return E_FAIL;
586 /* set up custom i/o handling */
587 png_set_write_fn(This->png_ptr, This, user_write_data, user_flush);
589 return S_OK;
592 static HRESULT CDECL png_encoder_get_supported_format(struct encoder* iface, GUID *pixel_format, DWORD *bpp, BOOL *indexed)
594 int i;
596 for (i=0; formats[i].guid; i++)
598 if (memcmp(formats[i].guid, pixel_format, sizeof(GUID)) == 0)
599 break;
602 if (!formats[i].guid)
603 i = 0;
605 *pixel_format = *formats[i].guid;
606 *bpp = formats[i].bpp;
607 *indexed = (formats[i].color_type == PNG_COLOR_TYPE_PALETTE);
609 return S_OK;
612 static HRESULT CDECL png_encoder_create_frame(struct encoder *encoder, const struct encoder_frame *encoder_frame)
614 struct png_encoder *This = impl_from_encoder(encoder);
615 int i;
617 for (i=0; formats[i].guid; i++)
619 if (memcmp(formats[i].guid, &encoder_frame->pixel_format, sizeof(GUID)) == 0)
621 This->format = &formats[i];
622 break;
626 if (!formats[i].guid)
628 ERR("invalid pixel format %s\n", wine_dbgstr_guid(&encoder_frame->pixel_format));
629 return E_FAIL;
632 /* set up setjmp/longjmp error handling */
633 if (setjmp(png_jmpbuf(This->png_ptr)))
634 return E_FAIL;
636 This->encoder_frame = *encoder_frame;
637 This->lines_written = 0;
639 if (encoder_frame->interlace)
641 /* libpng requires us to write all data multiple times in this case. */
642 This->stride = (This->format->bpp * encoder_frame->width + 7)/8;
643 This->data = malloc(encoder_frame->height * This->stride);
644 if (!This->data)
645 return E_OUTOFMEMORY;
648 /* Tell PNG we need to byte swap if writing a >8-bpp image */
649 if (This->format->bit_depth > 8)
650 png_set_swap(This->png_ptr);
652 png_set_IHDR(This->png_ptr, This->info_ptr, encoder_frame->width, encoder_frame->height,
653 This->format->bit_depth, This->format->color_type,
654 encoder_frame->interlace ? PNG_INTERLACE_ADAM7 : PNG_INTERLACE_NONE,
655 PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
657 if (encoder_frame->dpix != 0.0 && encoder_frame->dpiy != 0.0)
659 png_set_pHYs(This->png_ptr, This->info_ptr, (encoder_frame->dpix+0.0127) / 0.0254,
660 (encoder_frame->dpiy+0.0127) / 0.0254, PNG_RESOLUTION_METER);
663 if (This->format->color_type == PNG_COLOR_TYPE_PALETTE && encoder_frame->num_colors)
665 png_color png_palette[256];
666 png_byte trans[256];
667 UINT i, num_trans = 0, colors;
669 /* Newer libpng versions don't accept larger palettes than the declared
670 * bit depth, so we need to generate the palette of the correct length.
672 colors = min(encoder_frame->num_colors, 1 << This->format->bit_depth);
674 for (i = 0; i < colors; i++)
676 png_palette[i].red = (encoder_frame->palette[i] >> 16) & 0xff;
677 png_palette[i].green = (encoder_frame->palette[i] >> 8) & 0xff;
678 png_palette[i].blue = encoder_frame->palette[i] & 0xff;
679 trans[i] = (encoder_frame->palette[i] >> 24) & 0xff;
680 if (trans[i] != 0xff)
681 num_trans = i+1;
684 png_set_PLTE(This->png_ptr, This->info_ptr, png_palette, colors);
686 if (num_trans)
687 png_set_tRNS(This->png_ptr, This->info_ptr, trans, num_trans, NULL);
690 png_write_info(This->png_ptr, This->info_ptr);
692 if (This->format->remove_filler)
693 png_set_filler(This->png_ptr, 0, PNG_FILLER_AFTER);
695 if (This->format->swap_rgb)
696 png_set_bgr(This->png_ptr);
698 if (encoder_frame->interlace)
699 This->passes = png_set_interlace_handling(This->png_ptr);
701 if (encoder_frame->filter != WICPngFilterUnspecified)
703 static const int png_filter_map[] =
705 /* WICPngFilterUnspecified */ PNG_NO_FILTERS,
706 /* WICPngFilterNone */ PNG_FILTER_NONE,
707 /* WICPngFilterSub */ PNG_FILTER_SUB,
708 /* WICPngFilterUp */ PNG_FILTER_UP,
709 /* WICPngFilterAverage */ PNG_FILTER_AVG,
710 /* WICPngFilterPaeth */ PNG_FILTER_PAETH,
711 /* WICPngFilterAdaptive */ PNG_ALL_FILTERS,
714 png_set_filter(This->png_ptr, 0, png_filter_map[encoder_frame->filter]);
717 return S_OK;
720 static HRESULT CDECL png_encoder_write_lines(struct encoder* encoder, BYTE *data, DWORD line_count, DWORD stride)
722 struct png_encoder *This = impl_from_encoder(encoder);
723 png_byte **row_pointers=NULL;
724 UINT i;
726 if (This->encoder_frame.interlace)
728 /* Just store the data so we can write it in multiple passes in Commit. */
729 for (i=0; i<line_count; i++)
730 memcpy(This->data + This->stride * (This->lines_written + i),
731 data + stride * i,
732 This->stride);
734 This->lines_written += line_count;
736 return S_OK;
739 /* set up setjmp/longjmp error handling */
740 if (setjmp(png_jmpbuf(This->png_ptr)))
742 free(row_pointers);
743 return E_FAIL;
746 row_pointers = malloc(line_count * sizeof(png_byte*));
747 if (!row_pointers)
748 return E_OUTOFMEMORY;
750 for (i=0; i<line_count; i++)
751 row_pointers[i] = data + stride * i;
753 png_write_rows(This->png_ptr, row_pointers, line_count);
754 This->lines_written += line_count;
756 free(row_pointers);
758 return S_OK;
761 static HRESULT CDECL png_encoder_commit_frame(struct encoder *encoder)
763 struct png_encoder *This = impl_from_encoder(encoder);
764 png_byte **row_pointers=NULL;
766 /* set up setjmp/longjmp error handling */
767 if (setjmp(png_jmpbuf(This->png_ptr)))
769 free(row_pointers);
770 return E_FAIL;
773 if (This->encoder_frame.interlace)
775 int i;
777 row_pointers = malloc(This->encoder_frame.height * sizeof(png_byte*));
778 if (!row_pointers)
779 return E_OUTOFMEMORY;
781 for (i=0; i<This->encoder_frame.height; i++)
782 row_pointers[i] = This->data + This->stride * i;
784 for (i=0; i<This->passes; i++)
785 png_write_rows(This->png_ptr, row_pointers, This->encoder_frame.height);
788 png_write_end(This->png_ptr, This->info_ptr);
790 free(row_pointers);
792 return S_OK;
795 static HRESULT CDECL png_encoder_commit_file(struct encoder *encoder)
797 return S_OK;
800 static void CDECL png_encoder_destroy(struct encoder *encoder)
802 struct png_encoder *This = impl_from_encoder(encoder);
803 if (This->png_ptr)
804 png_destroy_write_struct(&This->png_ptr, &This->info_ptr);
805 free(This->data);
806 RtlFreeHeap(GetProcessHeap(), 0, This);
809 static const struct encoder_funcs png_encoder_vtable = {
810 png_encoder_initialize,
811 png_encoder_get_supported_format,
812 png_encoder_create_frame,
813 png_encoder_write_lines,
814 png_encoder_commit_frame,
815 png_encoder_commit_file,
816 png_encoder_destroy
819 HRESULT CDECL png_encoder_create(struct encoder_info *info, struct encoder **result)
821 struct png_encoder *This;
823 This = RtlAllocateHeap(GetProcessHeap(), 0, sizeof(*This));
825 if (!This)
827 return E_OUTOFMEMORY;
830 This->encoder.vtable = &png_encoder_vtable;
831 This->png_ptr = NULL;
832 This->info_ptr = NULL;
833 This->data = NULL;
834 *result = &This->encoder;
836 info->flags = ENCODER_FLAGS_SUPPORTS_METADATA;
837 info->container_format = GUID_ContainerFormatPng;
838 info->clsid = CLSID_WICPngEncoder;
839 info->encoder_options[0] = ENCODER_OPTION_INTERLACE;
840 info->encoder_options[1] = ENCODER_OPTION_FILTER;
841 info->encoder_options[2] = ENCODER_OPTION_END;
843 return S_OK;