imm32: Ignore some messages in ImmTranslateMessage.
[wine.git] / dlls / windowscodecs / libpng.c
blob8e876b23efe04962b87e74aea4eb0ebaf892a81c
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);
110 png_set_chunk_malloc_max(png_ptr, 0);
112 /* seek to the start of the stream */
113 hr = stream_seek(stream, 0, STREAM_SEEK_SET, NULL);
114 if (FAILED(hr))
116 goto end;
119 /* set up custom i/o handling */
120 png_set_read_fn(png_ptr, stream, user_read_data);
122 /* read the header */
123 png_read_info(png_ptr, info_ptr);
125 /* choose a pixel format */
126 color_type = png_get_color_type(png_ptr, info_ptr);
127 bit_depth = png_get_bit_depth(png_ptr, info_ptr);
129 /* PNGs with bit-depth greater than 8 are network byte order. Windows does not expect this. */
130 if (bit_depth > 8)
131 png_set_swap(png_ptr);
133 /* check for color-keyed alpha */
134 transparency = png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, &trans_values);
135 if (!transparency)
136 num_trans = 0;
138 if (transparency && (color_type == PNG_COLOR_TYPE_RGB ||
139 (color_type == PNG_COLOR_TYPE_GRAY && bit_depth == 16)))
141 /* expand to RGBA */
142 if (color_type == PNG_COLOR_TYPE_GRAY)
143 png_set_gray_to_rgb(png_ptr);
144 png_set_tRNS_to_alpha(png_ptr);
145 color_type = PNG_COLOR_TYPE_RGB_ALPHA;
148 switch (color_type)
150 case PNG_COLOR_TYPE_GRAY_ALPHA:
151 /* WIC does not support grayscale alpha formats so use RGBA */
152 png_set_gray_to_rgb(png_ptr);
153 /* fall through */
154 case PNG_COLOR_TYPE_RGB_ALPHA:
155 This->decoder_frame.bpp = bit_depth * 4;
156 switch (bit_depth)
158 case 8:
159 png_set_bgr(png_ptr);
160 This->decoder_frame.pixel_format = GUID_WICPixelFormat32bppBGRA;
161 break;
162 case 16: This->decoder_frame.pixel_format = GUID_WICPixelFormat64bppRGBA; break;
163 default:
164 ERR("invalid RGBA bit depth: %i\n", bit_depth);
165 hr = E_FAIL;
166 goto end;
168 break;
169 case PNG_COLOR_TYPE_GRAY:
170 This->decoder_frame.bpp = bit_depth;
171 if (!transparency)
173 switch (bit_depth)
175 case 1: This->decoder_frame.pixel_format = GUID_WICPixelFormatBlackWhite; break;
176 case 2: This->decoder_frame.pixel_format = GUID_WICPixelFormat2bppGray; break;
177 case 4: This->decoder_frame.pixel_format = GUID_WICPixelFormat4bppGray; break;
178 case 8: This->decoder_frame.pixel_format = GUID_WICPixelFormat8bppGray; break;
179 case 16: This->decoder_frame.pixel_format = GUID_WICPixelFormat16bppGray; break;
180 default:
181 ERR("invalid grayscale bit depth: %i\n", bit_depth);
182 hr = E_FAIL;
183 goto end;
185 break;
187 /* else fall through */
188 case PNG_COLOR_TYPE_PALETTE:
189 This->decoder_frame.bpp = bit_depth;
190 switch (bit_depth)
192 case 1: This->decoder_frame.pixel_format = GUID_WICPixelFormat1bppIndexed; break;
193 case 2: This->decoder_frame.pixel_format = GUID_WICPixelFormat2bppIndexed; break;
194 case 4: This->decoder_frame.pixel_format = GUID_WICPixelFormat4bppIndexed; break;
195 case 8: This->decoder_frame.pixel_format = GUID_WICPixelFormat8bppIndexed; break;
196 default:
197 ERR("invalid indexed color bit depth: %i\n", bit_depth);
198 hr = E_FAIL;
199 goto end;
201 break;
202 case PNG_COLOR_TYPE_RGB:
203 This->decoder_frame.bpp = bit_depth * 3;
204 switch (bit_depth)
206 case 8:
207 png_set_bgr(png_ptr);
208 This->decoder_frame.pixel_format = GUID_WICPixelFormat24bppBGR;
209 break;
210 case 16: This->decoder_frame.pixel_format = GUID_WICPixelFormat48bppRGB; break;
211 default:
212 ERR("invalid RGB color bit depth: %i\n", bit_depth);
213 hr = E_FAIL;
214 goto end;
216 break;
217 default:
218 ERR("invalid color type %i\n", color_type);
219 hr = E_FAIL;
220 goto end;
223 This->decoder_frame.width = png_get_image_width(png_ptr, info_ptr);
224 This->decoder_frame.height = png_get_image_height(png_ptr, info_ptr);
226 ret = png_get_pHYs(png_ptr, info_ptr, &xres, &yres, &unit_type);
228 if (ret && unit_type == PNG_RESOLUTION_METER)
230 This->decoder_frame.dpix = xres * 0.0254;
231 This->decoder_frame.dpiy = yres * 0.0254;
233 else
235 WARN("no pHYs block present\n");
236 This->decoder_frame.dpix = This->decoder_frame.dpiy = 96.0;
239 ret = png_get_iCCP(png_ptr, info_ptr, &cp_name, &cp_compression, &cp_profile, &cp_len);
240 if (ret)
242 This->decoder_frame.num_color_contexts = 1;
243 This->color_profile_len = cp_len;
244 This->color_profile = malloc(cp_len);
245 if (!This->color_profile)
247 hr = E_OUTOFMEMORY;
248 goto end;
250 memcpy(This->color_profile, cp_profile, cp_len);
252 else
253 This->decoder_frame.num_color_contexts = 0;
255 if (color_type == PNG_COLOR_TYPE_PALETTE)
257 ret = png_get_PLTE(png_ptr, info_ptr, &png_palette, &num_palette);
258 if (!ret)
260 ERR("paletted image with no PLTE chunk\n");
261 hr = E_FAIL;
262 goto end;
265 if (num_palette > 256)
267 ERR("palette has %i colors?!\n", num_palette);
268 hr = E_FAIL;
269 goto end;
272 This->decoder_frame.num_colors = num_palette;
273 for (i=0; i<num_palette; i++)
275 BYTE alpha = (i < num_trans) ? trans[i] : 0xff;
276 This->decoder_frame.palette[i] = (alpha << 24 |
277 png_palette[i].red << 16|
278 png_palette[i].green << 8|
279 png_palette[i].blue);
282 else if (color_type == PNG_COLOR_TYPE_GRAY && transparency && bit_depth <= 8) {
283 num_palette = 1 << bit_depth;
285 This->decoder_frame.num_colors = num_palette;
286 for (i=0; i<num_palette; i++)
288 BYTE alpha = (i == trans_values[0].gray) ? 0 : 0xff;
289 BYTE val = i * 255 / (num_palette - 1);
290 This->decoder_frame.palette[i] = (alpha << 24 | val << 16 | val << 8 | val);
293 else
295 This->decoder_frame.num_colors = 0;
298 This->stride = (This->decoder_frame.width * This->decoder_frame.bpp + 7) / 8;
299 image_size = This->stride * This->decoder_frame.height;
301 This->image_bits = malloc(image_size);
302 if (!This->image_bits)
304 hr = E_OUTOFMEMORY;
305 goto end;
308 row_pointers = malloc(sizeof(png_bytep)*This->decoder_frame.height);
309 if (!row_pointers)
311 hr = E_OUTOFMEMORY;
312 goto end;
315 for (i=0; i<This->decoder_frame.height; i++)
316 row_pointers[i] = This->image_bits + i * This->stride;
318 png_read_image(png_ptr, row_pointers);
320 free(row_pointers);
321 row_pointers = NULL;
323 /* png_read_end intentionally not called to not seek to the end of the file */
325 st->flags = WICBitmapDecoderCapabilityCanDecodeAllImages |
326 WICBitmapDecoderCapabilityCanDecodeSomeImages |
327 WICBitmapDecoderCapabilityCanEnumerateMetadata;
328 st->frame_count = 1;
330 This->stream = stream;
332 hr = S_OK;
334 end:
335 png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
336 free(row_pointers);
337 if (FAILED(hr))
339 free(This->image_bits);
340 This->image_bits = NULL;
341 free(This->color_profile);
342 This->color_profile = NULL;
344 return hr;
347 static HRESULT CDECL png_decoder_get_frame_info(struct decoder *iface, UINT frame, struct decoder_frame *info)
349 struct png_decoder *This = impl_from_decoder(iface);
350 *info = This->decoder_frame;
351 return S_OK;
354 static HRESULT CDECL png_decoder_copy_pixels(struct decoder *iface, UINT frame,
355 const WICRect *prc, UINT stride, UINT buffersize, BYTE *buffer)
357 struct png_decoder *This = impl_from_decoder(iface);
359 return copy_pixels(This->decoder_frame.bpp, This->image_bits,
360 This->decoder_frame.width, This->decoder_frame.height, This->stride,
361 prc, stride, buffersize, buffer);
364 static HRESULT CDECL png_decoder_get_metadata_blocks(struct decoder* iface,
365 UINT frame, UINT *count, struct decoder_block **blocks)
367 struct png_decoder *This = impl_from_decoder(iface);
368 HRESULT hr;
369 struct decoder_block *result = NULL;
370 ULONGLONG seek;
371 BYTE chunk_type[4];
372 ULONG chunk_size;
373 ULONGLONG chunk_start;
374 ULONG metadata_blocks_size = 0;
376 seek = 8;
377 *count = 0;
381 hr = stream_seek(This->stream, seek, STREAM_SEEK_SET, &chunk_start);
382 if (FAILED(hr)) goto end;
384 hr = read_png_chunk(This->stream, chunk_type, NULL, &chunk_size);
385 if (FAILED(hr)) goto end;
387 if (chunk_type[0] >= 'a' && chunk_type[0] <= 'z' &&
388 memcmp(chunk_type, "tRNS", 4) && memcmp(chunk_type, "pHYs", 4))
390 /* This chunk is considered metadata. */
391 if (*count == metadata_blocks_size)
393 struct decoder_block *new_metadata_blocks;
394 ULONG new_metadata_blocks_size;
396 new_metadata_blocks_size = 4 + metadata_blocks_size * 2;
397 new_metadata_blocks = RtlAllocateHeap(GetProcessHeap(), 0,
398 new_metadata_blocks_size * sizeof(*new_metadata_blocks));
400 if (!new_metadata_blocks)
402 hr = E_OUTOFMEMORY;
403 goto end;
406 memcpy(new_metadata_blocks, result,
407 *count * sizeof(*new_metadata_blocks));
409 RtlFreeHeap(GetProcessHeap(), 0, result);
410 result = new_metadata_blocks;
411 metadata_blocks_size = new_metadata_blocks_size;
414 result[*count].offset = chunk_start;
415 result[*count].length = chunk_size + 12;
416 result[*count].options = WICMetadataCreationAllowUnknown;
417 (*count)++;
420 seek = chunk_start + chunk_size + 12; /* skip data and CRC */
421 } while (memcmp(chunk_type, "IEND", 4));
423 end:
424 if (SUCCEEDED(hr))
426 *blocks = result;
428 else
430 *count = 0;
431 *blocks = NULL;
432 RtlFreeHeap(GetProcessHeap(), 0, result);
434 return hr;
437 static HRESULT CDECL png_decoder_get_color_context(struct decoder* iface, UINT frame, UINT num,
438 BYTE **data, DWORD *datasize)
440 struct png_decoder *This = impl_from_decoder(iface);
442 *data = RtlAllocateHeap(GetProcessHeap(), 0, This->color_profile_len);
443 *datasize = This->color_profile_len;
445 if (!*data)
446 return E_OUTOFMEMORY;
448 memcpy(*data, This->color_profile, This->color_profile_len);
450 return S_OK;
453 static void CDECL png_decoder_destroy(struct decoder* iface)
455 struct png_decoder *This = impl_from_decoder(iface);
457 free(This->image_bits);
458 free(This->color_profile);
459 RtlFreeHeap(GetProcessHeap(), 0, This);
462 static const struct decoder_funcs png_decoder_vtable = {
463 png_decoder_initialize,
464 png_decoder_get_frame_info,
465 png_decoder_copy_pixels,
466 png_decoder_get_metadata_blocks,
467 png_decoder_get_color_context,
468 png_decoder_destroy
471 HRESULT CDECL png_decoder_create(struct decoder_info *info, struct decoder **result)
473 struct png_decoder *This;
475 This = RtlAllocateHeap(GetProcessHeap(), 0, sizeof(*This));
477 if (!This)
479 return E_OUTOFMEMORY;
482 This->decoder.vtable = &png_decoder_vtable;
483 This->image_bits = NULL;
484 This->color_profile = NULL;
485 *result = &This->decoder;
487 info->container_format = GUID_ContainerFormatPng;
488 info->block_format = GUID_ContainerFormatPng;
489 info->clsid = CLSID_WICPngDecoder;
491 return S_OK;
494 struct png_pixelformat {
495 const WICPixelFormatGUID *guid;
496 UINT bpp;
497 int bit_depth;
498 int color_type;
499 BOOL remove_filler;
500 BOOL swap_rgb;
503 static const struct png_pixelformat formats[] = {
504 {&GUID_WICPixelFormat32bppBGRA, 32, 8, PNG_COLOR_TYPE_RGB_ALPHA, 0, 1},
505 {&GUID_WICPixelFormat24bppBGR, 24, 8, PNG_COLOR_TYPE_RGB, 0, 1},
506 {&GUID_WICPixelFormatBlackWhite, 1, 1, PNG_COLOR_TYPE_GRAY, 0, 0},
507 {&GUID_WICPixelFormat2bppGray, 2, 2, PNG_COLOR_TYPE_GRAY, 0, 0},
508 {&GUID_WICPixelFormat4bppGray, 4, 4, PNG_COLOR_TYPE_GRAY, 0, 0},
509 {&GUID_WICPixelFormat8bppGray, 8, 8, PNG_COLOR_TYPE_GRAY, 0, 0},
510 {&GUID_WICPixelFormat16bppGray, 16, 16, PNG_COLOR_TYPE_GRAY, 0, 0},
511 {&GUID_WICPixelFormat32bppBGR, 32, 8, PNG_COLOR_TYPE_RGB, 1, 1},
512 {&GUID_WICPixelFormat48bppRGB, 48, 16, PNG_COLOR_TYPE_RGB, 0, 0},
513 {&GUID_WICPixelFormat64bppRGBA, 64, 16, PNG_COLOR_TYPE_RGB_ALPHA, 0, 0},
514 {&GUID_WICPixelFormat1bppIndexed, 1, 1, PNG_COLOR_TYPE_PALETTE, 0, 0},
515 {&GUID_WICPixelFormat2bppIndexed, 2, 2, PNG_COLOR_TYPE_PALETTE, 0, 0},
516 {&GUID_WICPixelFormat4bppIndexed, 4, 4, PNG_COLOR_TYPE_PALETTE, 0, 0},
517 {&GUID_WICPixelFormat8bppIndexed, 8, 8, PNG_COLOR_TYPE_PALETTE, 0, 0},
518 {NULL},
521 struct png_encoder
523 struct encoder encoder;
524 IStream *stream;
525 png_structp png_ptr;
526 png_infop info_ptr;
527 struct encoder_frame encoder_frame;
528 const struct png_pixelformat *format;
529 BYTE *data;
530 UINT stride;
531 UINT passes;
532 UINT lines_written;
535 static inline struct png_encoder *impl_from_encoder(struct encoder* iface)
537 return CONTAINING_RECORD(iface, struct png_encoder, encoder);
540 static void user_write_data(png_structp png_ptr, png_bytep data, png_size_t length)
542 struct png_encoder *This = png_get_io_ptr(png_ptr);
543 HRESULT hr;
544 ULONG byteswritten;
546 hr = stream_write(This->stream, data, length, &byteswritten);
547 if (FAILED(hr) || byteswritten != length)
549 png_error(png_ptr, "failed writing data");
553 static void user_flush(png_structp png_ptr)
557 static HRESULT CDECL png_encoder_initialize(struct encoder *encoder, IStream *stream)
559 struct png_encoder *This = impl_from_encoder(encoder);
561 TRACE("(%p,%p)\n", encoder, stream);
563 /* initialize libpng */
564 This->png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
565 if (!This->png_ptr)
566 return E_FAIL;
568 This->info_ptr = png_create_info_struct(This->png_ptr);
569 if (!This->info_ptr)
571 png_destroy_write_struct(&This->png_ptr, NULL);
572 This->png_ptr = NULL;
573 return E_FAIL;
576 This->stream = stream;
578 /* set up setjmp/longjmp error handling */
579 if (setjmp(png_jmpbuf(This->png_ptr)))
581 png_destroy_write_struct(&This->png_ptr, &This->info_ptr);
582 This->png_ptr = NULL;
583 This->stream = NULL;
584 return E_FAIL;
587 /* set up custom i/o handling */
588 png_set_write_fn(This->png_ptr, This, user_write_data, user_flush);
590 return S_OK;
593 static HRESULT CDECL png_encoder_get_supported_format(struct encoder* iface, GUID *pixel_format, DWORD *bpp, BOOL *indexed)
595 int i;
597 for (i=0; formats[i].guid; i++)
599 if (memcmp(formats[i].guid, pixel_format, sizeof(GUID)) == 0)
600 break;
603 if (!formats[i].guid)
604 i = 0;
606 *pixel_format = *formats[i].guid;
607 *bpp = formats[i].bpp;
608 *indexed = (formats[i].color_type == PNG_COLOR_TYPE_PALETTE);
610 return S_OK;
613 static HRESULT CDECL png_encoder_create_frame(struct encoder *encoder, const struct encoder_frame *encoder_frame)
615 struct png_encoder *This = impl_from_encoder(encoder);
616 int i;
618 for (i=0; formats[i].guid; i++)
620 if (memcmp(formats[i].guid, &encoder_frame->pixel_format, sizeof(GUID)) == 0)
622 This->format = &formats[i];
623 break;
627 if (!formats[i].guid)
629 ERR("invalid pixel format %s\n", wine_dbgstr_guid(&encoder_frame->pixel_format));
630 return E_FAIL;
633 /* set up setjmp/longjmp error handling */
634 if (setjmp(png_jmpbuf(This->png_ptr)))
635 return E_FAIL;
637 This->encoder_frame = *encoder_frame;
638 This->lines_written = 0;
640 if (encoder_frame->interlace)
642 /* libpng requires us to write all data multiple times in this case. */
643 This->stride = (This->format->bpp * encoder_frame->width + 7)/8;
644 This->data = malloc(encoder_frame->height * This->stride);
645 if (!This->data)
646 return E_OUTOFMEMORY;
649 /* Tell PNG we need to byte swap if writing a >8-bpp image */
650 if (This->format->bit_depth > 8)
651 png_set_swap(This->png_ptr);
653 png_set_IHDR(This->png_ptr, This->info_ptr, encoder_frame->width, encoder_frame->height,
654 This->format->bit_depth, This->format->color_type,
655 encoder_frame->interlace ? PNG_INTERLACE_ADAM7 : PNG_INTERLACE_NONE,
656 PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
658 if (encoder_frame->dpix != 0.0 && encoder_frame->dpiy != 0.0)
660 png_set_pHYs(This->png_ptr, This->info_ptr, (encoder_frame->dpix+0.0127) / 0.0254,
661 (encoder_frame->dpiy+0.0127) / 0.0254, PNG_RESOLUTION_METER);
664 if (This->format->color_type == PNG_COLOR_TYPE_PALETTE && encoder_frame->num_colors)
666 png_color png_palette[256];
667 png_byte trans[256];
668 UINT i, num_trans = 0, colors;
670 /* Newer libpng versions don't accept larger palettes than the declared
671 * bit depth, so we need to generate the palette of the correct length.
673 colors = min(encoder_frame->num_colors, 1 << This->format->bit_depth);
675 for (i = 0; i < colors; i++)
677 png_palette[i].red = (encoder_frame->palette[i] >> 16) & 0xff;
678 png_palette[i].green = (encoder_frame->palette[i] >> 8) & 0xff;
679 png_palette[i].blue = encoder_frame->palette[i] & 0xff;
680 trans[i] = (encoder_frame->palette[i] >> 24) & 0xff;
681 if (trans[i] != 0xff)
682 num_trans = i+1;
685 png_set_PLTE(This->png_ptr, This->info_ptr, png_palette, colors);
687 if (num_trans)
688 png_set_tRNS(This->png_ptr, This->info_ptr, trans, num_trans, NULL);
691 png_write_info(This->png_ptr, This->info_ptr);
693 if (This->format->remove_filler)
694 png_set_filler(This->png_ptr, 0, PNG_FILLER_AFTER);
696 if (This->format->swap_rgb)
697 png_set_bgr(This->png_ptr);
699 if (encoder_frame->interlace)
700 This->passes = png_set_interlace_handling(This->png_ptr);
702 if (encoder_frame->filter != WICPngFilterUnspecified)
704 static const int png_filter_map[] =
706 /* WICPngFilterUnspecified */ PNG_NO_FILTERS,
707 /* WICPngFilterNone */ PNG_FILTER_NONE,
708 /* WICPngFilterSub */ PNG_FILTER_SUB,
709 /* WICPngFilterUp */ PNG_FILTER_UP,
710 /* WICPngFilterAverage */ PNG_FILTER_AVG,
711 /* WICPngFilterPaeth */ PNG_FILTER_PAETH,
712 /* WICPngFilterAdaptive */ PNG_ALL_FILTERS,
715 png_set_filter(This->png_ptr, 0, png_filter_map[encoder_frame->filter]);
718 return S_OK;
721 static HRESULT CDECL png_encoder_write_lines(struct encoder* encoder, BYTE *data, DWORD line_count, DWORD stride)
723 struct png_encoder *This = impl_from_encoder(encoder);
724 png_byte **row_pointers=NULL;
725 UINT i;
727 if (This->encoder_frame.interlace)
729 /* Just store the data so we can write it in multiple passes in Commit. */
730 for (i=0; i<line_count; i++)
731 memcpy(This->data + This->stride * (This->lines_written + i),
732 data + stride * i,
733 This->stride);
735 This->lines_written += line_count;
737 return S_OK;
740 /* set up setjmp/longjmp error handling */
741 if (setjmp(png_jmpbuf(This->png_ptr)))
743 free(row_pointers);
744 return E_FAIL;
747 row_pointers = malloc(line_count * sizeof(png_byte*));
748 if (!row_pointers)
749 return E_OUTOFMEMORY;
751 for (i=0; i<line_count; i++)
752 row_pointers[i] = data + stride * i;
754 png_write_rows(This->png_ptr, row_pointers, line_count);
755 This->lines_written += line_count;
757 free(row_pointers);
759 return S_OK;
762 static HRESULT CDECL png_encoder_commit_frame(struct encoder *encoder)
764 struct png_encoder *This = impl_from_encoder(encoder);
765 png_byte **row_pointers=NULL;
767 /* set up setjmp/longjmp error handling */
768 if (setjmp(png_jmpbuf(This->png_ptr)))
770 free(row_pointers);
771 return E_FAIL;
774 if (This->encoder_frame.interlace)
776 int i;
778 row_pointers = malloc(This->encoder_frame.height * sizeof(png_byte*));
779 if (!row_pointers)
780 return E_OUTOFMEMORY;
782 for (i=0; i<This->encoder_frame.height; i++)
783 row_pointers[i] = This->data + This->stride * i;
785 for (i=0; i<This->passes; i++)
786 png_write_rows(This->png_ptr, row_pointers, This->encoder_frame.height);
789 png_write_end(This->png_ptr, This->info_ptr);
791 free(row_pointers);
793 return S_OK;
796 static HRESULT CDECL png_encoder_commit_file(struct encoder *encoder)
798 return S_OK;
801 static void CDECL png_encoder_destroy(struct encoder *encoder)
803 struct png_encoder *This = impl_from_encoder(encoder);
804 if (This->png_ptr)
805 png_destroy_write_struct(&This->png_ptr, &This->info_ptr);
806 free(This->data);
807 RtlFreeHeap(GetProcessHeap(), 0, This);
810 static const struct encoder_funcs png_encoder_vtable = {
811 png_encoder_initialize,
812 png_encoder_get_supported_format,
813 png_encoder_create_frame,
814 png_encoder_write_lines,
815 png_encoder_commit_frame,
816 png_encoder_commit_file,
817 png_encoder_destroy
820 HRESULT CDECL png_encoder_create(struct encoder_info *info, struct encoder **result)
822 struct png_encoder *This;
824 This = RtlAllocateHeap(GetProcessHeap(), 0, sizeof(*This));
826 if (!This)
828 return E_OUTOFMEMORY;
831 This->encoder.vtable = &png_encoder_vtable;
832 This->png_ptr = NULL;
833 This->info_ptr = NULL;
834 This->data = NULL;
835 *result = &This->encoder;
837 info->flags = ENCODER_FLAGS_SUPPORTS_METADATA;
838 info->container_format = GUID_ContainerFormatPng;
839 info->clsid = CLSID_WICPngEncoder;
840 info->encoder_options[0] = ENCODER_OPTION_INTERLACE;
841 info->encoder_options[1] = ENCODER_OPTION_FILTER;
842 info->encoder_options[2] = ENCODER_OPTION_END;
844 return S_OK;