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
24 #define WIN32_NO_STATUS
30 #include "wincodecs_private.h"
32 #include "wine/debug.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs
);
38 struct decoder decoder
;
40 struct decoder_frame decoder_frame
;
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
);
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
);
71 int color_type
, bit_depth
;
74 png_uint_32 transparency
;
75 png_color_16p trans_values
;
76 png_uint_32 ret
, xres
, yres
;
78 png_colorp png_palette
;
82 png_bytep
*row_pointers
=NULL
;
88 png_ptr
= png_create_read_struct(PNG_LIBPNG_VER_STRING
, NULL
, NULL
, NULL
);
94 info_ptr
= png_create_info_struct(png_ptr
);
97 png_destroy_read_struct(&png_ptr
, NULL
, NULL
);
101 /* set up setjmp/longjmp error handling */
102 if (setjmp(png_jmpbuf(png_ptr
)))
104 hr
= WINCODEC_ERR_UNKNOWNIMAGEFORMAT
;
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
);
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. */
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
);
136 if (transparency
&& (color_type
== PNG_COLOR_TYPE_RGB
||
137 (color_type
== PNG_COLOR_TYPE_GRAY
&& bit_depth
== 16)))
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
;
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
);
152 case PNG_COLOR_TYPE_RGB_ALPHA
:
153 This
->decoder_frame
.bpp
= bit_depth
* 4;
157 png_set_bgr(png_ptr
);
158 This
->decoder_frame
.pixel_format
= GUID_WICPixelFormat32bppBGRA
;
160 case 16: This
->decoder_frame
.pixel_format
= GUID_WICPixelFormat64bppRGBA
; break;
162 ERR("invalid RGBA bit depth: %i\n", bit_depth
);
167 case PNG_COLOR_TYPE_GRAY
:
168 This
->decoder_frame
.bpp
= 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;
179 ERR("invalid grayscale bit depth: %i\n", bit_depth
);
185 /* else fall through */
186 case PNG_COLOR_TYPE_PALETTE
:
187 This
->decoder_frame
.bpp
= 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;
195 ERR("invalid indexed color bit depth: %i\n", bit_depth
);
200 case PNG_COLOR_TYPE_RGB
:
201 This
->decoder_frame
.bpp
= bit_depth
* 3;
205 png_set_bgr(png_ptr
);
206 This
->decoder_frame
.pixel_format
= GUID_WICPixelFormat24bppBGR
;
208 case 16: This
->decoder_frame
.pixel_format
= GUID_WICPixelFormat48bppRGB
; break;
210 ERR("invalid RGB color bit depth: %i\n", bit_depth
);
216 ERR("invalid color type %i\n", color_type
);
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;
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
);
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
)
248 memcpy(This
->color_profile
, cp_profile
, cp_len
);
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
);
258 ERR("paletted image with no PLTE chunk\n");
263 if (num_palette
> 256)
265 ERR("palette has %i colors?!\n", num_palette
);
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
);
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
)
306 row_pointers
= malloc(sizeof(png_bytep
)*This
->decoder_frame
.height
);
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
);
321 /* png_read_end intentionally not called to not seek to the end of the file */
323 st
->flags
= WICBitmapDecoderCapabilityCanDecodeAllImages
|
324 WICBitmapDecoderCapabilityCanDecodeSomeImages
|
325 WICBitmapDecoderCapabilityCanEnumerateMetadata
;
328 This
->stream
= stream
;
333 png_destroy_read_struct(&png_ptr
, &info_ptr
, NULL
);
337 free(This
->image_bits
);
338 This
->image_bits
= NULL
;
339 free(This
->color_profile
);
340 This
->color_profile
= NULL
;
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
;
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
);
367 struct decoder_block
*result
= NULL
;
371 ULONGLONG chunk_start
;
372 ULONG metadata_blocks_size
= 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
)
403 memcpy(new_metadata_blocks
, result
,
404 *count
* sizeof(*new_metadata_blocks
));
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
;
417 seek
= chunk_start
+ chunk_size
+ 12; /* skip data and CRC */
418 } while (memcmp(chunk_type
, "IEND", 4));
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
;
443 return E_OUTOFMEMORY
;
445 memcpy(*data
, This
->color_profile
, This
->color_profile_len
);
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
);
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
,
468 HRESULT CDECL
png_decoder_create(struct decoder_info
*info
, struct decoder
**result
)
470 struct png_decoder
*This
;
472 This
= malloc(sizeof(*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
;
491 struct png_pixelformat
{
492 const WICPixelFormatGUID
*guid
;
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},
520 struct encoder encoder
;
524 struct encoder_frame encoder_frame
;
525 const struct png_pixelformat
*format
;
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
);
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
);
565 This
->info_ptr
= png_create_info_struct(This
->png_ptr
);
568 png_destroy_write_struct(&This
->png_ptr
, NULL
);
569 This
->png_ptr
= NULL
;
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
;
584 /* set up custom i/o handling */
585 png_set_write_fn(This
->png_ptr
, This
, user_write_data
, user_flush
);
590 static HRESULT CDECL
png_encoder_get_supported_format(struct encoder
* iface
, GUID
*pixel_format
, DWORD
*bpp
, BOOL
*indexed
)
594 for (i
=0; formats
[i
].guid
; i
++)
596 if (memcmp(formats
[i
].guid
, pixel_format
, sizeof(GUID
)) == 0)
600 if (!formats
[i
].guid
)
603 *pixel_format
= *formats
[i
].guid
;
604 *bpp
= formats
[i
].bpp
;
605 *indexed
= (formats
[i
].color_type
== PNG_COLOR_TYPE_PALETTE
);
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
);
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
];
624 if (!formats
[i
].guid
)
626 ERR("invalid pixel format %s\n", wine_dbgstr_guid(&encoder_frame
->pixel_format
));
630 /* set up setjmp/longjmp error handling */
631 if (setjmp(png_jmpbuf(This
->png_ptr
)))
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
);
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];
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)
682 png_set_PLTE(This
->png_ptr
, This
->info_ptr
, png_palette
, colors
);
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
]);
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
;
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
),
732 This
->lines_written
+= line_count
;
737 /* set up setjmp/longjmp error handling */
738 if (setjmp(png_jmpbuf(This
->png_ptr
)))
744 row_pointers
= malloc(line_count
* sizeof(png_byte
*));
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
;
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
)))
771 if (This
->encoder_frame
.interlace
)
775 row_pointers
= malloc(This
->encoder_frame
.height
* sizeof(png_byte
*));
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
);
793 static HRESULT CDECL
png_encoder_commit_file(struct encoder
*encoder
)
798 static void CDECL
png_encoder_destroy(struct encoder
*encoder
)
800 struct png_encoder
*This
= impl_from_encoder(encoder
);
802 png_destroy_write_struct(&This
->png_ptr
, &This
->info_ptr
);
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
,
817 HRESULT CDECL
png_encoder_create(struct encoder_info
*info
, struct encoder
**result
)
819 struct png_encoder
*This
;
821 This
= malloc(sizeof(*This
));
825 return E_OUTOFMEMORY
;
828 This
->encoder
.vtable
= &png_encoder_vtable
;
829 This
->png_ptr
= NULL
;
830 This
->info_ptr
= 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
;