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
23 #define NONAMELESSUNION
26 #define WIN32_NO_STATUS
32 #include "wincodecs_private.h"
34 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs
);
40 struct decoder decoder
;
42 struct decoder_frame decoder_frame
;
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
);
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
);
73 int color_type
, bit_depth
;
76 png_uint_32 transparency
;
77 png_color_16p trans_values
;
78 png_uint_32 ret
, xres
, yres
;
80 png_colorp png_palette
;
84 png_bytep
*row_pointers
=NULL
;
90 png_ptr
= png_create_read_struct(PNG_LIBPNG_VER_STRING
, NULL
, NULL
, NULL
);
96 info_ptr
= png_create_info_struct(png_ptr
);
99 png_destroy_read_struct(&png_ptr
, NULL
, NULL
);
103 /* set up setjmp/longjmp error handling */
104 if (setjmp(png_jmpbuf(png_ptr
)))
106 hr
= WINCODEC_ERR_UNKNOWNIMAGEFORMAT
;
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
);
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. */
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
);
138 if (transparency
&& (color_type
== PNG_COLOR_TYPE_RGB
||
139 (color_type
== PNG_COLOR_TYPE_GRAY
&& bit_depth
== 16)))
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
;
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
);
154 case PNG_COLOR_TYPE_RGB_ALPHA
:
155 This
->decoder_frame
.bpp
= bit_depth
* 4;
159 png_set_bgr(png_ptr
);
160 This
->decoder_frame
.pixel_format
= GUID_WICPixelFormat32bppBGRA
;
162 case 16: This
->decoder_frame
.pixel_format
= GUID_WICPixelFormat64bppRGBA
; break;
164 ERR("invalid RGBA bit depth: %i\n", bit_depth
);
169 case PNG_COLOR_TYPE_GRAY
:
170 This
->decoder_frame
.bpp
= 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;
181 ERR("invalid grayscale bit depth: %i\n", bit_depth
);
187 /* else fall through */
188 case PNG_COLOR_TYPE_PALETTE
:
189 This
->decoder_frame
.bpp
= 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;
197 ERR("invalid indexed color bit depth: %i\n", bit_depth
);
202 case PNG_COLOR_TYPE_RGB
:
203 This
->decoder_frame
.bpp
= bit_depth
* 3;
207 png_set_bgr(png_ptr
);
208 This
->decoder_frame
.pixel_format
= GUID_WICPixelFormat24bppBGR
;
210 case 16: This
->decoder_frame
.pixel_format
= GUID_WICPixelFormat48bppRGB
; break;
212 ERR("invalid RGB color bit depth: %i\n", bit_depth
);
218 ERR("invalid color type %i\n", color_type
);
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;
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
);
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
)
250 memcpy(This
->color_profile
, cp_profile
, cp_len
);
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
);
260 ERR("paletted image with no PLTE chunk\n");
265 if (num_palette
> 256)
267 ERR("palette has %i colors?!\n", num_palette
);
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
);
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
)
308 row_pointers
= malloc(sizeof(png_bytep
)*This
->decoder_frame
.height
);
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
);
323 /* png_read_end intentionally not called to not seek to the end of the file */
325 st
->flags
= WICBitmapDecoderCapabilityCanDecodeAllImages
|
326 WICBitmapDecoderCapabilityCanDecodeSomeImages
|
327 WICBitmapDecoderCapabilityCanEnumerateMetadata
;
330 This
->stream
= stream
;
335 png_destroy_read_struct(&png_ptr
, &info_ptr
, NULL
);
339 free(This
->image_bits
);
340 This
->image_bits
= NULL
;
341 free(This
->color_profile
);
342 This
->color_profile
= NULL
;
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
;
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
);
369 struct decoder_block
*result
= NULL
;
373 ULONGLONG chunk_start
;
374 ULONG metadata_blocks_size
= 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
)
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
;
420 seek
= chunk_start
+ chunk_size
+ 12; /* skip data and CRC */
421 } while (memcmp(chunk_type
, "IEND", 4));
432 RtlFreeHeap(GetProcessHeap(), 0, result
);
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
;
446 return E_OUTOFMEMORY
;
448 memcpy(*data
, This
->color_profile
, This
->color_profile_len
);
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
,
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
));
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
;
494 struct png_pixelformat
{
495 const WICPixelFormatGUID
*guid
;
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},
523 struct encoder encoder
;
527 struct encoder_frame encoder_frame
;
528 const struct png_pixelformat
*format
;
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
);
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
);
568 This
->info_ptr
= png_create_info_struct(This
->png_ptr
);
571 png_destroy_write_struct(&This
->png_ptr
, NULL
);
572 This
->png_ptr
= NULL
;
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
;
587 /* set up custom i/o handling */
588 png_set_write_fn(This
->png_ptr
, This
, user_write_data
, user_flush
);
593 static HRESULT CDECL
png_encoder_get_supported_format(struct encoder
* iface
, GUID
*pixel_format
, DWORD
*bpp
, BOOL
*indexed
)
597 for (i
=0; formats
[i
].guid
; i
++)
599 if (memcmp(formats
[i
].guid
, pixel_format
, sizeof(GUID
)) == 0)
603 if (!formats
[i
].guid
)
606 *pixel_format
= *formats
[i
].guid
;
607 *bpp
= formats
[i
].bpp
;
608 *indexed
= (formats
[i
].color_type
== PNG_COLOR_TYPE_PALETTE
);
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
);
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
];
627 if (!formats
[i
].guid
)
629 ERR("invalid pixel format %s\n", wine_dbgstr_guid(&encoder_frame
->pixel_format
));
633 /* set up setjmp/longjmp error handling */
634 if (setjmp(png_jmpbuf(This
->png_ptr
)))
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
);
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];
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)
685 png_set_PLTE(This
->png_ptr
, This
->info_ptr
, png_palette
, colors
);
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
]);
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
;
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
),
735 This
->lines_written
+= line_count
;
740 /* set up setjmp/longjmp error handling */
741 if (setjmp(png_jmpbuf(This
->png_ptr
)))
747 row_pointers
= malloc(line_count
* sizeof(png_byte
*));
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
;
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
)))
774 if (This
->encoder_frame
.interlace
)
778 row_pointers
= malloc(This
->encoder_frame
.height
* sizeof(png_byte
*));
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
);
796 static HRESULT CDECL
png_encoder_commit_file(struct encoder
*encoder
)
801 static void CDECL
png_encoder_destroy(struct encoder
*encoder
)
803 struct png_encoder
*This
= impl_from_encoder(encoder
);
805 png_destroy_write_struct(&This
->png_ptr
, &This
->info_ptr
);
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
,
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
));
828 return E_OUTOFMEMORY
;
831 This
->encoder
.vtable
= &png_encoder_vtable
;
832 This
->png_ptr
= NULL
;
833 This
->info_ptr
= 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
;