APNG. bug 257197. patch by Andrew Smith <asmith15@learn.senecac.on.ca>. r=biesi sr=pavlov

This commit is contained in:
pavlov%pavlov.net 2007-03-20 23:56:50 +00:00
Родитель a5665d68bc
Коммит 13c8e24bf8
24 изменённых файлов: 2511 добавлений и 143 удалений

Просмотреть файл

@ -4004,8 +4004,11 @@ fi
if test -z "$PNG_DIR" -o "$PNG_DIR" = no; then
SYSTEM_PNG=
else
_SAVE_PNG_LIBS=$PNG_LIBS
AC_CHECK_LIB(png, png_get_valid, [SYSTEM_PNG=1 PNG_LIBS="-lpng $PNG_LIBS"],
SYSTEM_PNG=, $PNG_LIBS)
AC_CHECK_LIB(png, png_get_acTl, ,
[SYSTEM_PNG= PNG_LIBS=$_SAVE_PNG_LIBS], $_SAVE_PNG_LIBS)
fi
if test "$SYSTEM_PNG" = 1; then
LIBS="$PNG_LIBS $LIBS"

Просмотреть файл

@ -51,6 +51,9 @@ PNG_tEXt;
PNG_tIME;
PNG_tRNS;
PNG_zTXt;
PNG_acTl;
PNG_fcTl;
PNG_fdAt;
#ifdef PNG_READ_SUPPORTED
/* arrays to facilitate easy interlacing - use pass (0 - 6) as index */

Просмотреть файл

@ -900,6 +900,18 @@ defined(PNG_READ_BACKGROUND_SUPPORTED)
png_fixed_point int_y_blue;
#endif
#if defined(PNG_APNG_SUPPORTED)
png_uint_32 num_frames;
png_uint_32 num_iterations;
png_uint_32 next_frame_width;
png_uint_32 next_frame_height;
png_uint_32 next_frame_x_offset;
png_uint_32 next_frame_y_offset;
png_uint_16 next_frame_delay_num;
png_uint_16 next_frame_delay_den;
png_byte next_frame_render_op;
#endif
} png_info;
typedef png_info FAR * png_infop;
@ -1001,6 +1013,8 @@ typedef png_info FAR * FAR * png_infopp;
#define PNG_INFO_sPLT 0x2000 /* ESR, 1.0.6 */
#define PNG_INFO_sCAL 0x4000 /* ESR, 1.0.6 */
#define PNG_INFO_IDAT 0x8000L /* ESR, 1.0.6 */
#define PNG_INFO_acTl 0x10000L
#define PNG_INFO_fcTl 0x20000L
/* This is used for the transformation routines, as some of them
* change these values for the row. It also should enable using
@ -1041,6 +1055,10 @@ typedef void (PNGAPI *png_progressive_info_ptr) PNGARG((png_structp, png_infop))
typedef void (PNGAPI *png_progressive_end_ptr) PNGARG((png_structp, png_infop));
typedef void (PNGAPI *png_progressive_row_ptr) PNGARG((png_structp, png_bytep,
png_uint_32, int));
#if defined(PNG_APNG_SUPPORTED)
typedef void (PNGAPI *png_progressive_frame_ptr) PNGARG((png_structp,
png_uint_32));
#endif
#endif
#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \
@ -1367,8 +1385,39 @@ struct png_struct_def
png_uint_32 user_height_max;
#endif
#if defined(PNG_APNG_SUPPORTED)
png_uint_32 apng_flags;
png_uint_32 IHDR_crc; /* read or written */
png_uint_32 PLTE_crc; /* read or written */
png_uint_32 next_seq_num; /* next fcTl/fdAt chunk sequence number */
png_uint_32 first_frame_width;
png_uint_32 first_frame_height;
#endif
#if defined(PNG_READ_APNG_SUPPORTED)
png_uint_32 num_frames_read; /* incremented after all image data of */
/* a frame is read */
#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
png_progressive_frame_ptr frame_info_fn; /* frame info read callback */
png_progressive_frame_ptr frame_end_fn; /* frame data read callback */
#endif
#endif
#if defined(PNG_WRITE_APNG_SUPPORTED)
png_uint_32 num_frames_to_write; /* copy of info_ptr->num_frames */
png_uint_32 num_frames_written;
#endif
};
/* For png_struct.apng_flags: */
#define PNG_FIRST_FRAME_HIDDEN 0x0001
/* dispose_op flags from render_op inside fcTl */
#define PNG_RENDER_OP_DISPOSE_MASK 0x07
#define PNG_RENDER_OP_DISPOSE_NONE 0x01
#define PNG_RENDER_OP_DISPOSE_BACKGROUND 0x02
#define PNG_RENDER_OP_DISPOSE_PREVIOUS 0x04
/* This triggers a compiler error in png.c, if png.c and png.h
* do not agree upon the version number.
@ -1688,6 +1737,18 @@ extern PNG_EXPORT(void,png_write_rows) PNGARG((png_structp png_ptr,
extern PNG_EXPORT(void,png_write_image) PNGARG((png_structp png_ptr,
png_bytepp image));
#if defined(PNG_WRITE_APNG_SUPPORTED)
extern PNG_EXPORT (void,png_write_frame_head) PNGARG((png_structp png_ptr,
png_infop png_info, png_bytepp row_pointers,
png_uint_32 width, png_uint_32 height,
png_uint_32 x_offset, png_uint_32 y_offset,
png_uint_16 delay_num, png_uint_16 delay_den, png_byte render_op,
png_byte first_frame_hidden));
extern PNG_EXPORT (void,png_write_frame_tail) PNGARG((png_structp png_ptr,
png_infop png_info));
#endif
/* writes the end of the PNG file. */
extern PNG_EXPORT(void,png_write_end) PNGARG((png_structp png_ptr,
png_infop info_ptr));
@ -1936,6 +1997,11 @@ extern PNG_EXPORT(void,png_set_progressive_read_fn) PNGARG((png_structp png_ptr,
png_voidp progressive_ptr,
png_progressive_info_ptr info_fn, png_progressive_row_ptr row_fn,
png_progressive_end_ptr end_fn));
#if defined(PNG_READ_APNG_SUPPORTED)
extern PNG_EXPORT(void,png_set_progressive_frame_fn) PNGARG((png_structp png_ptr,
png_progressive_frame_ptr frame_info_fn,
png_progressive_frame_ptr frame_end_fn));
#endif
/* returns the user pointer associated with the push read functions */
extern PNG_EXPORT(png_voidp,png_get_progressive_ptr)
@ -2364,6 +2430,53 @@ extern PNG_EXPORT(void,png_set_sCAL_s) PNGARG((png_structp png_ptr,
#endif
#endif /* PNG_sCAL_SUPPORTED || PNG_WRITE_sCAL_SUPPORTED */
#if defined(PNG_APNG_SUPPORTED)
extern PNG_EXPORT(png_uint_32,png_get_acTl) PNGARG((png_structp png_ptr,
png_infop info_ptr, png_uint_32 *num_frames, png_uint_32 *num_iterations));
extern PNG_EXPORT(png_uint_32,png_set_acTl) PNGARG((png_structp png_ptr,
png_infop info_ptr, png_uint_32 num_frames, png_uint_32 num_iterations));
extern PNG_EXPORT(png_uint_32,png_get_num_frames) PNGARG((png_structp png_ptr,
png_infop info_ptr));
extern PNG_EXPORT(png_uint_32,png_get_num_iterations)
PNGARG((png_structp png_ptr, png_infop info_ptr));
extern PNG_EXPORT(png_uint_32,png_get_next_frame_fcTl)
PNGARG((png_structp png_ptr, png_infop info_ptr, png_uint_32 *width,
png_uint_32 *height, png_uint_32 *x_offset, png_uint_32 *y_offset,
png_uint_16 *delay_num, png_uint_16 *delay_den, png_byte *render_op));
extern PNG_EXPORT(png_uint_32,png_set_next_frame_fcTl)
PNGARG((png_structp png_ptr, png_infop info_ptr, png_uint_32 width,
png_uint_32 height, png_uint_32 x_offset, png_uint_32 y_offset,
png_uint_16 delay_num, png_uint_16 delay_den, png_byte render_op));
extern PNG_EXPORT(void,png_ensure_fcTl_is_valid)
PNGARG((png_structp png_ptr,
png_uint_32 width, png_uint_32 height,
png_uint_32 x_offset, png_uint_32 y_offset,
png_uint_16 delay_num, png_uint_16 delay_den,
png_byte render_op));
extern PNG_EXPORT(png_uint_32,png_get_next_frame_width)
PNGARG((png_structp png_ptr, png_infop info_ptr));
extern PNG_EXPORT(png_uint_32,png_get_next_frame_height)
PNGARG((png_structp png_ptr, png_infop info_ptr));
extern PNG_EXPORT(png_uint_32,png_get_next_frame_x_offset)
PNGARG((png_structp png_ptr, png_infop info_ptr));
extern PNG_EXPORT(png_uint_32,png_get_next_frame_y_offset)
PNGARG((png_structp png_ptr, png_infop info_ptr));
extern PNG_EXPORT(png_uint_16,png_get_next_frame_delay_num)
PNGARG((png_structp png_ptr, png_infop info_ptr));
extern PNG_EXPORT(png_uint_16,png_get_next_frame_delay_den)
PNGARG((png_structp png_ptr, png_infop info_ptr));
extern PNG_EXPORT(png_byte,png_get_next_frame_render_op)
PNGARG((png_structp png_ptr, png_infop info_ptr));
extern PNG_EXPORT(png_byte,png_first_frame_is_hidden)
PNGARG((png_structp png_ptr, png_infop info_ptr));
#endif /* PNG_APNG_SUPPORTED */
#if defined(PNG_READ_APNG_SUPPORTED)
extern PNG_EXPORT(void,png_read_frame_head) PNGARG((png_structp png_ptr,
png_infop info_ptr));
#endif
#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
/* provide a list of chunks and how they are to be handled, if the built-in
handling or default unknown chunk handling is not desired. Any chunks not
@ -2667,6 +2780,8 @@ extern PNG_EXPORT(void,png_save_uint_16)
#define PNG_BACKGROUND_IS_GRAY 0x800
#define PNG_HAVE_PNG_SIGNATURE 0x1000
#define PNG_HAVE_CHUNK_AFTER_IDAT 0x2000 /* Have another chunk after IDAT */
#define PNG_HAVE_acTl 0x4000
#define PNG_HAVE_fcTl 0x8000L
/* flags for the transformations the PNG library does on the image data */
#define PNG_BGR 0x0001
@ -2810,6 +2925,9 @@ extern PNG_EXPORT(void,png_save_uint_16)
#define PNG_tIME const png_byte png_tIME[5] = {116, 73, 77, 69, '\0'}
#define PNG_tRNS const png_byte png_tRNS[5] = {116, 82, 78, 83, '\0'}
#define PNG_zTXt const png_byte png_zTXt[5] = {122, 84, 88, 116, '\0'}
#define PNG_acTl const png_byte png_acTl[5] = { 97, 99, 84, 108, '\0'}
#define PNG_fcTl const png_byte png_fcTl[5] = {102, 99, 84, 108, '\0'}
#define PNG_fdAt const png_byte png_fdAt[5] = {102, 100, 65, 116, '\0'}
#ifdef PNG_USE_GLOBAL_ARRAYS
PNG_EXPORT_VAR (const png_byte FARDATA) png_IHDR[5];
@ -2833,6 +2951,9 @@ PNG_EXPORT_VAR (const png_byte FARDATA) png_tEXt[5];
PNG_EXPORT_VAR (const png_byte FARDATA) png_tIME[5];
PNG_EXPORT_VAR (const png_byte FARDATA) png_tRNS[5];
PNG_EXPORT_VAR (const png_byte FARDATA) png_zTXt[5];
PNG_EXPORT_VAR (const png_byte FARDATA) png_acTl[5];
PNG_EXPORT_VAR (const png_byte FARDATA) png_fcTl[5];
PNG_EXPORT_VAR (const png_byte FARDATA) png_fdAt[5];
#endif /* PNG_USE_GLOBAL_ARRAYS */
#if defined(PNG_1_0_X) || defined (PNG_1_2_X)
@ -3107,6 +3228,16 @@ PNG_EXTERN void png_write_sCAL_s PNGARG((png_structp png_ptr,
#endif
#endif
#if defined(PNG_WRITE_APNG_SUPPORTED)
PNG_EXTERN void png_write_acTl PNGARG((png_structp png_ptr,
png_uint_32 num_frames, png_uint_32 num_iterations));
PNG_EXTERN void png_write_fcTl PNGARG((png_structp png_ptr,
png_uint_32 width, png_uint_32 height,
png_uint_32 x_offset, png_uint_32 y_offset,
png_uint_16 delay_num, png_uint_16 delay_den, png_byte render_op));
#endif
/* Called when finished processing a row of data */
PNG_EXTERN void png_write_finish_row PNGARG((png_structp png_ptr));
@ -3158,6 +3289,20 @@ PNG_EXTERN void png_read_start_row PNGARG((png_structp png_ptr));
PNG_EXTERN void png_read_transform_info PNGARG((png_structp png_ptr,
png_infop info_ptr));
#if defined(PNG_READ_APNG_SUPPORTED)
/* private, reset some things to become ready for reading next frame */
PNG_EXTERN void png_read_reset PNGARG((png_structp png_ptr));
PNG_EXTERN void png_read_reinit PNGARG((png_structp png_ptr,
png_infop info_ptr));
PNG_EXTERN void png_progressive_read_reset PNGARG((png_structp png_ptr));
#endif
#if defined(PNG_WRITE_APNG_SUPPORTED)
/* private, reset some things to become ready for writing next frame */
PNG_EXTERN void png_write_reset PNGARG((png_structp png_ptr));
PNG_EXTERN void png_write_reinit PNGARG((png_structp png_ptr,
png_infop info_ptr, png_uint_32 width, png_uint_32 height));
#endif
/* these are the functions that do the transformations */
#if defined(PNG_READ_FILLER_SUPPORTED)
PNG_EXTERN void png_do_read_filler PNGARG((png_row_infop row_info,
@ -3373,6 +3518,17 @@ PNG_EXTERN void png_handle_zTXt PNGARG((png_structp png_ptr, png_infop info_ptr,
png_uint_32 length));
#endif
#if defined(PNG_READ_APNG_SUPPORTED)
PNG_EXTERN void png_handle_acTl PNGARG((png_structp png_ptr, png_infop info_ptr,
png_uint_32 length));
PNG_EXTERN void png_handle_fcTl PNGARG((png_structp png_ptr, png_infop info_ptr,
png_uint_32 length));
PNG_EXTERN void png_handle_fdAt PNGARG((png_structp png_ptr, png_infop info_ptr,
png_uint_32 length));
PNG_EXTERN void png_ensure_sequence_number PNGARG((png_structp png_ptr,
png_uint_32 length));
#endif
PNG_EXTERN void png_handle_unknown PNGARG((png_structp png_ptr,
png_infop info_ptr, png_uint_32 length));

Просмотреть файл

@ -896,6 +896,10 @@
# define PNG_READ_zTXt_SUPPORTED
# define PNG_zTXt_SUPPORTED
#endif
#ifndef PNG_NO_READ_APNG
# define PNG_READ_APNG_SUPPORTED
# define PNG_APNG_SUPPORTED
#endif
#ifndef PNG_NO_READ_UNKNOWN_CHUNKS
# define PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
# ifndef PNG_UNKNOWN_CHUNKS_SUPPORTED
@ -1038,6 +1042,12 @@
# define PNG_zTXt_SUPPORTED
# endif
#endif
#ifndef PNG_NO_WRITE_APNG
# define PNG_WRITE_APNG_SUPPORTED
# ifndef PNG_APNG_SUPPORTED
# define PNG_APNG_SUPPORTED
# endif
#endif
#ifndef PNG_NO_WRITE_UNKNOWN_CHUNKS
# define PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
# ifndef PNG_UNKNOWN_CHUNKS_SUPPORTED

Просмотреть файл

@ -794,6 +794,157 @@ png_get_tRNS(png_structp png_ptr, png_infop info_ptr,
}
#endif
#if defined(PNG_APNG_SUPPORTED)
png_uint_32 PNGAPI
png_get_acTl(png_structp png_ptr, png_infop info_ptr,
png_uint_32 *num_frames, png_uint_32 *num_iterations)
{
png_debug1(1, "in %s retrieval function\n", "acTl");
if (png_ptr != NULL && info_ptr != NULL &&
(info_ptr->valid & PNG_INFO_acTl) &&
num_frames != NULL && num_iterations != NULL)
{
*num_frames = info_ptr->num_frames;
*num_iterations = info_ptr->num_iterations;
return (1);
}
return (0);
}
png_uint_32 PNGAPI
png_get_num_frames(png_structp png_ptr, png_infop info_ptr)
{
png_debug(1, "in png_get_num_frames()\n");
if (png_ptr != NULL && info_ptr != NULL)
return (info_ptr->num_frames);
return (0);
}
png_uint_32 PNGAPI
png_get_num_iterations(png_structp png_ptr, png_infop info_ptr)
{
png_debug(1, "in png_get_num_iterations()\n");
if (png_ptr != NULL && info_ptr != NULL)
return (info_ptr->num_iterations);
return (0);
}
png_uint_32 PNGAPI
png_get_next_frame_fcTl(png_structp png_ptr, png_infop info_ptr,
png_uint_32 *width, png_uint_32 *height,
png_uint_32 *x_offset, png_uint_32 *y_offset,
png_uint_16 *delay_num, png_uint_16 *delay_den,
png_byte *render_op)
{
png_debug1(1, "in %s retrieval function\n", "fcTl");
if (png_ptr != NULL && info_ptr != NULL &&
(info_ptr->valid & PNG_INFO_fcTl) &&
width != NULL && height != NULL &&
x_offset != NULL && x_offset != NULL &&
delay_num != NULL && delay_den != NULL && render_op != NULL)
{
*width = info_ptr->next_frame_width;
*height = info_ptr->next_frame_height;
*x_offset = info_ptr->next_frame_x_offset;
*y_offset = info_ptr->next_frame_y_offset;
*delay_num = info_ptr->next_frame_delay_num;
*delay_den = info_ptr->next_frame_delay_den;
*render_op = info_ptr->next_frame_render_op;
return (1);
}
return (0);
}
png_uint_32 PNGAPI
png_get_next_frame_width(png_structp png_ptr, png_infop info_ptr)
{
png_debug(1, "in png_get_next_frame_width()\n");
if (png_ptr != NULL && info_ptr != NULL)
return (info_ptr->next_frame_width);
return (0);
}
png_uint_32 PNGAPI
png_get_next_frame_height(png_structp png_ptr, png_infop info_ptr)
{
png_debug(1, "in png_get_next_frame_height()\n");
if (png_ptr != NULL && info_ptr != NULL)
return (info_ptr->next_frame_height);
return (0);
}
png_uint_32 PNGAPI
png_get_next_frame_x_offset(png_structp png_ptr, png_infop info_ptr)
{
png_debug(1, "in png_get_next_frame_x_offset()\n");
if (png_ptr != NULL && info_ptr != NULL)
return (info_ptr->next_frame_x_offset);
return (0);
}
png_uint_32 PNGAPI
png_get_next_frame_y_offset(png_structp png_ptr, png_infop info_ptr)
{
png_debug(1, "in png_get_next_frame_y_offset()\n");
if (png_ptr != NULL && info_ptr != NULL)
return (info_ptr->next_frame_y_offset);
return (0);
}
png_uint_16 PNGAPI
png_get_next_frame_delay_num(png_structp png_ptr, png_infop info_ptr)
{
png_debug(1, "in png_get_next_frame_delay_num()\n");
if (png_ptr != NULL && info_ptr != NULL)
return (info_ptr->next_frame_delay_num);
return (0);
}
png_uint_16 PNGAPI
png_get_next_frame_delay_den(png_structp png_ptr, png_infop info_ptr)
{
png_debug(1, "in png_get_next_frame_delay_den()\n");
if (png_ptr != NULL && info_ptr != NULL)
return (info_ptr->next_frame_delay_den);
return (0);
}
png_byte PNGAPI
png_get_next_frame_render_op(png_structp png_ptr, png_infop info_ptr)
{
png_debug(1, "in png_get_next_frame_render_op()\n");
if (png_ptr != NULL && info_ptr != NULL)
return (info_ptr->next_frame_render_op);
return (0);
}
png_byte PNGAPI
png_first_frame_is_hidden(png_structp png_ptr, png_infop info_ptr)
{
png_debug(1, "in png_first_frame_is_hidden()\n");
if (png_ptr != NULL && info_ptr != NULL &&
info_ptr->valid & PNG_INFO_acTl &&
!(info_ptr->valid & PNG_INFO_fcTl))
return 1;
return 0;
}
#endif /* PNG_APNG_SUPPORTED */
#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
png_uint_32 PNGAPI
png_get_unknown_chunks(png_structp png_ptr, png_infop info_ptr,

Просмотреть файл

@ -190,6 +190,11 @@ png_push_read_chunk(png_structp png_ptr, png_infop info_ptr)
#if defined(PNG_READ_zTXt_SUPPORTED)
PNG_zTXt;
#endif
#if defined(PNG_READ_APNG_SUPPORTED)
PNG_acTl;
PNG_fcTl;
PNG_fdAt;
#endif
#endif /* PNG_USE_LOCAL_ARRAYS */
/* First we make sure we have enough data for the 4 byte chunk name
* and the 4 byte chunk length before proceeding with decoding the
@ -213,7 +218,104 @@ png_push_read_chunk(png_structp png_ptr, png_infop info_ptr)
png_crc_read(png_ptr, png_ptr->chunk_name, 4);
png_ptr->mode |= PNG_HAVE_CHUNK_HEADER;
}
#if defined(PNG_READ_APNG_SUPPORTED)
if (png_ptr->num_frames_read > 0 &&
png_ptr->num_frames_read < info_ptr->num_frames)
{
if (!png_memcmp(png_ptr->chunk_name, png_IDAT, 4))
{
/* discard trailing IDATs for the first frame */
if (png_ptr->mode & PNG_HAVE_fcTl || png_ptr->num_frames_read > 1)
png_error(png_ptr, "out of place IDAT");
if (png_ptr->push_length + 4 > png_ptr->buffer_size)
{
png_push_save_buffer(png_ptr);
return;
}
png_push_crc_skip(png_ptr, png_ptr->push_length);
png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;
return;
}
else if (!png_memcmp(png_ptr->chunk_name, png_fdAt, 4))
{
if (png_ptr->buffer_size < 4)
{
png_push_save_buffer(png_ptr);
return;
}
png_ensure_sequence_number(png_ptr, 4);
if (!(png_ptr->mode & PNG_HAVE_fcTl))
{
/* discard trailing fdAts for frames other than the first */
if (png_ptr->num_frames_read < 2)
png_error(png_ptr, "out of place fdAt");
if (png_ptr->push_length + 4 > png_ptr->buffer_size)
{
png_push_save_buffer(png_ptr);
return;
}
png_push_crc_skip(png_ptr, png_ptr->push_length);
png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;
return;
}
else
{
/* frame data follows */
png_ptr->idat_size = png_ptr->push_length - 4;
png_ptr->mode |= PNG_HAVE_IDAT;
png_ptr->process_mode = PNG_READ_IDAT_MODE;
return;
}
}
else if(!png_memcmp(png_ptr->chunk_name, png_fcTl, 4))
{
if (png_ptr->push_length + 4 > png_ptr->buffer_size)
{
png_push_save_buffer(png_ptr);
return;
}
png_read_reset(png_ptr);
png_ptr->mode &= ~PNG_HAVE_fcTl;
png_handle_fcTl(png_ptr, info_ptr, png_ptr->push_length);
if (!(png_ptr->mode & PNG_HAVE_fcTl))
png_error(png_ptr, "missing required fcTl chunk");
png_read_reinit(png_ptr, info_ptr);
png_progressive_read_reset(png_ptr);
if (png_ptr->frame_info_fn != NULL)
(*(png_ptr->frame_info_fn))(png_ptr, png_ptr->num_frames_read);
png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;
return;
}
else
{
if (png_ptr->push_length + 4 > png_ptr->buffer_size)
{
png_push_save_buffer(png_ptr);
return;
}
png_warning(png_ptr, "Skipped (ignored) a chunk "
"between APNG chunks");
png_push_crc_skip(png_ptr, png_ptr->push_length);
png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;
return;
}
return;
}
#endif /* PNG_READ_APNG_SUPPORTED */
if (!png_memcmp(png_ptr->chunk_name, (png_bytep)png_IDAT, 4))
if(png_ptr->mode & PNG_AFTER_IDAT)
png_ptr->mode |= PNG_HAVE_CHUNK_AFTER_IDAT;
@ -488,6 +590,35 @@ png_push_read_chunk(png_structp png_ptr, png_infop info_ptr)
png_push_handle_iTXt(png_ptr, info_ptr, png_ptr->push_length);
}
#endif
#if defined(PNG_READ_APNG_SUPPORTED)
else if (!png_memcmp(png_ptr->chunk_name, png_acTl, 4))
{
if (png_ptr->push_length + 4 > png_ptr->buffer_size)
{
png_push_save_buffer(png_ptr);
return;
}
png_handle_acTl(png_ptr, info_ptr, png_ptr->push_length);
}
else if (!png_memcmp(png_ptr->chunk_name, png_fcTl, 4))
{
if (png_ptr->push_length + 4 > png_ptr->buffer_size)
{
png_push_save_buffer(png_ptr);
return;
}
png_handle_fcTl(png_ptr, info_ptr, png_ptr->push_length);
}
else if (!png_memcmp(png_ptr->chunk_name, png_fdAt, 4))
{
if (png_ptr->push_length + 4 > png_ptr->buffer_size)
{
png_push_save_buffer(png_ptr);
return;
}
png_handle_fdAt(png_ptr, info_ptr, png_ptr->push_length);
}
#endif /* PNG_READ_APNG_SUPPORTED */
else
{
if (png_ptr->push_length + 4 > png_ptr->buffer_size)
@ -658,12 +789,16 @@ png_push_read_IDAT(png_structp png_ptr)
{
#ifdef PNG_USE_LOCAL_ARRAYS
PNG_IDAT;
#if defined(PNG_READ_APNG_SUPPORTED)
PNG_fdAt;
PNG_IEND;
#endif
#endif
if (!(png_ptr->mode & PNG_HAVE_CHUNK_HEADER))
{
png_byte chunk_length[4];
if (png_ptr->buffer_size < 8)
if (png_ptr->buffer_size < 12)
{
png_push_save_buffer(png_ptr);
return;
@ -675,15 +810,59 @@ png_push_read_IDAT(png_structp png_ptr)
png_crc_read(png_ptr, png_ptr->chunk_name, 4);
png_ptr->mode |= PNG_HAVE_CHUNK_HEADER;
if (png_memcmp(png_ptr->chunk_name, (png_bytep)png_IDAT, 4))
#if defined(PNG_READ_APNG_SUPPORTED)
if (png_memcmp(png_ptr->chunk_name, (png_bytep)png_fdAt, 4)
&& png_ptr->num_frames_read > 0)
{
if (png_ptr->flags & PNG_FLAG_ZLIB_FINISHED)
{
png_ptr->process_mode = PNG_READ_CHUNK_MODE;
if (png_ptr->frame_end_fn != NULL)
(*(png_ptr->frame_end_fn))(png_ptr, png_ptr->num_frames_read);
png_ptr->num_frames_read++;
return;
}
else
{
if (!png_memcmp(png_ptr->chunk_name, png_IEND, 4))
png_error(png_ptr, "Not enough image data");
if (png_ptr->push_length + 4 > png_ptr->buffer_size)
{
png_push_save_buffer(png_ptr);
return;
}
png_warning(png_ptr, "Skipping (ignoring) a chunk between "
"APNG chunks");
png_crc_finish(png_ptr, png_ptr->push_length);
png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;
return;
}
}
else
#endif
if ( png_memcmp(png_ptr->chunk_name, (png_bytep)png_IDAT, 4)
&& (png_ptr->num_frames_read == 0) )
{
png_ptr->process_mode = PNG_READ_CHUNK_MODE;
if (!(png_ptr->flags & PNG_FLAG_ZLIB_FINISHED))
png_error(png_ptr, "Not enough compressed data");
#if defined(PNG_READ_APNG_SUPPORTED)
if (png_ptr->frame_end_fn != NULL)
(*(png_ptr->frame_end_fn))(png_ptr, png_ptr->num_frames_read);
png_ptr->num_frames_read++;
#endif
return;
}
png_ptr->idat_size = png_ptr->push_length;
#if defined(PNG_READ_APNG_SUPPORTED)
if(png_ptr->num_frames_read > 0)
{
png_ensure_sequence_number(png_ptr, 4);
png_ptr->idat_size -= 4;
}
#endif
}
if (png_ptr->idat_size && png_ptr->save_buffer_size)
{
@ -1570,6 +1749,17 @@ png_set_progressive_read_fn(png_structp png_ptr, png_voidp progressive_ptr,
png_set_read_fn(png_ptr, progressive_ptr, png_push_fill_buffer);
}
#if defined(PNG_READ_APNG_SUPPORTED)
void PNGAPI
png_set_progressive_frame_fn(png_structp png_ptr,
png_progressive_frame_ptr frame_info_fn,
png_progressive_frame_ptr frame_end_fn)
{
png_ptr->frame_info_fn = frame_info_fn;
png_ptr->frame_end_fn = frame_end_fn;
}
#endif
png_voidp PNGAPI
png_get_progressive_ptr(png_structp png_ptr)
{

Просмотреть файл

@ -397,6 +397,11 @@ png_read_info(png_structp png_ptr, png_infop info_ptr)
#if defined(PNG_READ_zTXt_SUPPORTED)
PNG_zTXt;
#endif
#if defined(PNG_READ_APNG_SUPPORTED)
PNG_acTl;
PNG_fcTl;
PNG_fdAt;
#endif
#endif /* PNG_USE_LOCAL_ARRAYS */
png_byte chunk_length[4];
png_uint_32 length;
@ -521,6 +526,14 @@ png_read_info(png_structp png_ptr, png_infop info_ptr)
#if defined(PNG_READ_iTXt_SUPPORTED)
else if (!png_memcmp(png_ptr->chunk_name, png_iTXt, 4))
png_handle_iTXt(png_ptr, info_ptr, length);
#endif
#if defined(PNG_READ_APNG_SUPPORTED)
else if (!png_memcmp(png_ptr->chunk_name, png_acTl, 4))
png_handle_acTl(png_ptr, info_ptr, length);
else if (!png_memcmp(png_ptr->chunk_name, png_fcTl, 4))
png_handle_fcTl(png_ptr, info_ptr, length);
else if (!png_memcmp(png_ptr->chunk_name, png_fdAt, 4))
png_handle_fdAt(png_ptr, info_ptr, length);
#endif
else
png_handle_unknown(png_ptr, info_ptr, length);
@ -528,6 +541,83 @@ png_read_info(png_structp png_ptr, png_infop info_ptr)
}
#endif /* PNG_NO_SEQUENTIAL_READ_SUPPORTED */
#if defined(PNG_READ_APNG_SUPPORTED)
void PNGAPI
png_read_frame_head(png_structp png_ptr, png_infop info_ptr)
{
png_byte have_chunk_after_DAT; /* after IDAT or after fdAt */
png_debug(0, "Reading frame head\n");
if (!(png_ptr->mode & PNG_HAVE_acTl))
png_error(png_ptr, "attempt to png_read_frame_head() but "
"no acTl present");
/* do nothing for the main IDAT */
if (png_ptr->num_frames_read == 0)
return;
png_crc_finish(png_ptr, 0); /* CRC from last IDAT or fdAt chunk */
png_read_reset(png_ptr);
png_ptr->mode &= ~PNG_HAVE_fcTl;
have_chunk_after_DAT = 0;
for (;;)
{
#ifdef PNG_USE_LOCAL_ARRAYS
PNG_IDAT;
PNG_fdAt;
PNG_fcTl;
#endif
png_byte chunk_length[4];
png_uint_32 length;
png_read_data(png_ptr, chunk_length, 4);
length = png_get_uint_31(png_ptr, chunk_length);
png_reset_crc(png_ptr);
png_crc_read(png_ptr, png_ptr->chunk_name, 4);
if (!png_memcmp(png_ptr->chunk_name, png_IDAT, 4))
{
/* discard trailing IDATs for the first frame */
if (have_chunk_after_DAT || png_ptr->num_frames_read > 1)
png_error(png_ptr, "png_read_frame_head(): out of place IDAT");
png_crc_finish(png_ptr, length);
}
else if (!png_memcmp(png_ptr->chunk_name, png_fcTl, 4))
{
png_handle_fcTl(png_ptr, info_ptr, length);
have_chunk_after_DAT = 1;
}
else if (!png_memcmp(png_ptr->chunk_name, png_fdAt, 4))
{
png_ensure_sequence_number(png_ptr, length);
/* discard trailing fdAts for frames other than the first */
if (!have_chunk_after_DAT && png_ptr->num_frames_read > 1)
png_crc_finish(png_ptr, length - 4);
else if(png_ptr->mode & PNG_HAVE_fcTl)
{
png_ptr->idat_size = length - 4;
png_ptr->mode |= PNG_HAVE_IDAT;
break;
}
else
png_error(png_ptr, "png_read_frame_head(): out of place fdAt");
}
else
{
png_warning(png_ptr, "Skipped (ignored) a chunk "
"between APNG chunks");
png_crc_finish(png_ptr, length);
}
}
}
#endif /* PNG_READ_APNG_SUPPORTED */
/* optional call to update the users info_ptr structure */
void PNGAPI
png_read_update_info(png_structp png_ptr, png_infop info_ptr)
@ -562,6 +652,10 @@ png_read_row(png_structp png_ptr, png_bytep row, png_bytep dsp_row)
{
#ifdef PNG_USE_LOCAL_ARRAYS
PNG_IDAT;
#if defined(PNG_READ_APNG_SUPPORTED)
PNG_fdAt;
PNG_IEND;
#endif
const int png_pass_dsp_mask[7] = {0xff, 0x0f, 0xff, 0x33, 0xff, 0x55, 0xff};
const int png_pass_mask[7] = {0x80, 0x08, 0x88, 0x22, 0xaa, 0x55, 0xff};
#endif
@ -689,19 +783,46 @@ png_read_row(png_structp png_ptr, png_bytep row, png_bytep dsp_row)
{
if (!(png_ptr->zstream.avail_in))
{
while (!png_ptr->idat_size)
png_uint_32 bytes_to_skip = 0;
while (!png_ptr->idat_size || bytes_to_skip != 0)
{
png_byte chunk_length[4];
png_crc_finish(png_ptr, 0);
png_crc_finish(png_ptr, bytes_to_skip);
bytes_to_skip = 0;
png_read_data(png_ptr, chunk_length, 4);
png_ptr->idat_size = png_get_uint_31(png_ptr,chunk_length);
png_reset_crc(png_ptr);
png_crc_read(png_ptr, png_ptr->chunk_name, 4);
if (png_memcmp(png_ptr->chunk_name, png_IDAT, 4))
png_error(png_ptr, "Not enough image data");
#if defined(PNG_READ_APNG_SUPPORTED)
if (png_ptr->num_frames_read == 0)
{
#endif
if (png_memcmp(png_ptr->chunk_name, png_IDAT, 4))
png_error(png_ptr, "Not enough image data");
#if defined(PNG_READ_APNG_SUPPORTED)
}
else
{
if (!png_memcmp(png_ptr->chunk_name, png_IEND, 4))
png_error(png_ptr, "Not enough image data");
if (png_memcmp(png_ptr->chunk_name, png_fdAt, 4))
{
png_warning(png_ptr, "Skipped (ignored) a chunk "
"between APNG chunks");
bytes_to_skip = png_ptr->idat_size;
continue;
}
png_ensure_sequence_number(png_ptr, png_ptr->idat_size);
png_ptr->idat_size -= 4;
}
#endif
}
png_ptr->zstream.avail_in = (uInt)png_ptr->zbuf_size;
png_ptr->zstream.next_in = png_ptr->zbuf;
@ -719,6 +840,9 @@ png_read_row(png_structp png_ptr, png_bytep row, png_bytep dsp_row)
png_error(png_ptr, "Extra compressed data");
png_ptr->mode |= PNG_AFTER_IDAT;
png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED;
#if defined(PNG_READ_APNG_SUPPORTED)
png_ptr->num_frames_read++;
#endif
break;
}
if (ret != Z_OK)
@ -970,6 +1094,11 @@ png_read_end(png_structp png_ptr, png_infop info_ptr)
#if defined(PNG_READ_zTXt_SUPPORTED)
PNG_zTXt;
#endif
#if defined(PNG_READ_APNG_SUPPORTED)
PNG_acTl;
PNG_fcTl;
PNG_fdAt;
#endif
#endif /* PNG_USE_LOCAL_ARRAYS */
png_read_data(png_ptr, chunk_length, 4);
@ -1075,6 +1204,14 @@ png_read_end(png_structp png_ptr, png_infop info_ptr)
#if defined(PNG_READ_iTXt_SUPPORTED)
else if (!png_memcmp(png_ptr->chunk_name, png_iTXt, 4))
png_handle_iTXt(png_ptr, info_ptr, length);
#endif
#if defined(PNG_READ_APNG_SUPPORTED)
else if (!png_memcmp(png_ptr->chunk_name, png_acTl, 4))
png_handle_acTl(png_ptr, info_ptr, length);
else if (!png_memcmp(png_ptr->chunk_name, png_fcTl, 4))
png_handle_fcTl(png_ptr, info_ptr, length);
else if (!png_memcmp(png_ptr->chunk_name, png_fdAt, 4))
png_handle_fdAt(png_ptr, info_ptr, length);
#endif
else
png_handle_unknown(png_ptr, info_ptr, length);

Просмотреть файл

@ -363,6 +363,12 @@ png_handle_IHDR(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
filter_type = buf[11];
interlace_type = buf[12];
#if defined(PNG_READ_APNG_SUPPORTED)
png_ptr->IHDR_crc = png_ptr->crc;
png_ptr->first_frame_width = width;
png_ptr->first_frame_height = height;
#endif
/* set internal variables */
png_ptr->width = width;
png_ptr->height = height;
@ -521,6 +527,19 @@ png_handle_PLTE(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
png_set_PLTE(png_ptr, info_ptr, palette, num);
#if defined(PNG_READ_APNG_SUPPORTED)
if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
{
if (png_ptr->mode & PNG_HAVE_acTl)
{
if (png_ptr->crc != png_ptr->PLTE_crc)
png_error(png_ptr, "PLTE checksum does not match that in acTl");
}
else
png_ptr->PLTE_crc = png_ptr->crc;
}
#endif
#if defined(PNG_READ_tRNS_SUPPORTED)
if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
{
@ -2130,6 +2149,184 @@ png_handle_iTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
}
#endif
#if defined(PNG_READ_APNG_SUPPORTED)
void /* PRIVATE */
png_handle_acTl(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
{
png_byte data[16];
png_uint_32 num_frames;
png_uint_32 num_iterations;
png_uint_32 didSet;
png_uint_32 IHDR_crc;
png_uint_32 PLTE_crc;
png_debug(1, "in png_handle_acTl\n");
if (!(png_ptr->mode & PNG_HAVE_IHDR))
{
png_error(png_ptr, "Missing IHDR before acTl");
}
else if (png_ptr->mode & PNG_HAVE_IDAT)
{
png_warning(png_ptr, "Invalid acTl after IDAT skipped");
png_crc_finish(png_ptr, length);
return;
}
else if (png_ptr->mode & PNG_HAVE_acTl)
{
png_warning(png_ptr, "Duplicate acTl skipped");
png_crc_finish(png_ptr, length);
return;
}
else if (length != 16)
{
png_warning(png_ptr, "acTl with invalid length skipped");
png_crc_finish(png_ptr, length);
return;
}
png_crc_read(png_ptr, data, 16);
png_crc_finish(png_ptr, 0);
num_frames = png_get_uint_31(png_ptr, data);
num_iterations = png_get_uint_31(png_ptr, data + 4);
IHDR_crc = png_get_uint_32(data + 8);
PLTE_crc = png_get_uint_32(data + 12);
if (IHDR_crc != png_ptr->IHDR_crc)
{
png_warning(png_ptr, "acTl with invalid IHDR checksum skipped");
return;
}
if (png_ptr->mode & PNG_HAVE_PLTE)
{
if (PLTE_crc != png_ptr->PLTE_crc)
{
png_warning(png_ptr, "acTl with invalid PLTE checksum skipped");
return;
}
}
else
png_ptr->PLTE_crc = PLTE_crc;
/* the set function will do error checking on num_frames */
didSet = png_set_acTl(png_ptr, info_ptr, num_frames, num_iterations);
if(didSet)
{
png_ptr->mode |= PNG_HAVE_acTl;
/* if there is an fcTl this flag will be unset in png_handle_fcTl() */
if (num_frames > 1)
png_ptr->apng_flags |= PNG_FIRST_FRAME_HIDDEN;
}
}
void /* PRIVATE */
png_handle_fcTl(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
{
png_byte data[21];
png_uint_32 width;
png_uint_32 height;
png_uint_32 x_offset;
png_uint_32 y_offset;
png_uint_16 delay_num;
png_uint_16 delay_den;
png_byte render_op;
png_debug(1, "in png_handle_fcTl\n");
if (!(png_ptr->mode & PNG_HAVE_IHDR))
{
png_error(png_ptr, "Missing IHDR before fcTl");
}
else if (png_ptr->mode & PNG_HAVE_IDAT)
{
/* for any frames other then the first this message may be misleading,
* but correct. PNG_HAVE_IDAT is unset before the frame head is read
* i can't think of a better message */
png_warning(png_ptr, "Invalid fcTl after IDAT skipped");
png_crc_finish(png_ptr, length);
return;
}
else if (png_ptr->mode & PNG_HAVE_fcTl)
{
png_warning(png_ptr, "Duplicate fcTl within one frame skipped");
png_crc_finish(png_ptr, length);
return;
}
else if (length != 25)
{
png_warning(png_ptr, "fcTl with invalid length skipped");
png_crc_finish(png_ptr, length);
return;
}
png_ensure_sequence_number(png_ptr, length);
png_crc_read(png_ptr, data, 21);
png_crc_finish(png_ptr, 0);
width = png_get_uint_31(png_ptr, data);
height = png_get_uint_31(png_ptr, data + 4);
x_offset = png_get_uint_31(png_ptr, data + 8);
y_offset = png_get_uint_31(png_ptr, data + 12);
delay_num = png_get_uint_16(data + 16);
delay_den = png_get_uint_16(data + 18);
render_op = data[20];
if (png_ptr->num_frames_read == 0 && (x_offset != 0 || y_offset != 0))
png_error(png_ptr, "fcTl for the first frame must have zero offset");
if (png_ptr->num_frames_read == 0 &&
(width != info_ptr->width || height != info_ptr->height))
png_error(png_ptr, "size in first frame's fcTl must match "
"the size in IHDR");
/* the set function will do more error checking */
png_set_next_frame_fcTl(png_ptr, info_ptr, width, height,
x_offset, y_offset, delay_num, delay_den,
render_op);
png_read_reinit(png_ptr, info_ptr);
png_ptr->mode |= PNG_HAVE_fcTl;
png_ptr->apng_flags &= ~PNG_FIRST_FRAME_HIDDEN;
}
void /* PRIVATE */
png_handle_fdAt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
{
png_ensure_sequence_number(png_ptr, length);
/* This function is only called from png_read_end(), png_read_info(),
* and png_push_read_chunk() which means that:
* - the user doesn't want to read this frame
* - or this is an out-of-place fdAt
* in either case it is safe to ignore the chunk with a warning */
png_warning(png_ptr, "ignoring fdAt chunk");
png_crc_finish(png_ptr, length - 4);
}
void /* PRIVATE */
png_ensure_sequence_number(png_structp png_ptr, png_uint_32 length)
{
png_byte data[4];
png_uint_32 sequence_number;
if (length < 4)
png_error(png_ptr, "invalid fcTl or fdAt chunk found");
png_crc_read(png_ptr, data, 4);
sequence_number = png_get_uint_31(png_ptr, data);
if (sequence_number != png_ptr->next_seq_num)
png_error(png_ptr, "fcTl or fdAt chunk with out-of-order sequence "
"number found");
png_ptr->next_seq_num++;
}
#endif /* PNG_READ_APNG_SUPPORTED */
/* This function is called when we haven't found a handler for a
chunk. If there isn't a problem with the chunk itself (ie bad
chunk name, CRC, or a critical chunk), the chunk is silently ignored
@ -3094,8 +3291,10 @@ defined(PNG_USER_TRANSFORM_PTR_SUPPORTED)
if (row_bytes > (png_uint_32)65536L)
png_error(png_ptr, "This image requires a row greater than 64KB");
#endif
png_ptr->big_row_buf = (png_bytep)png_malloc(png_ptr, row_bytes+64);
png_ptr->row_buf = png_ptr->big_row_buf+32;
if (png_ptr->big_row_buf == NULL)
png_ptr->big_row_buf = (png_bytep)png_malloc(png_ptr, row_bytes+64);
if (png_ptr->row_buf == NULL)
png_ptr->row_buf = png_ptr->big_row_buf+32;
#if defined(PNG_DEBUG) && defined(PNG_USE_PNGGCCRD)
png_ptr->row_buf_size = row_bytes;
#endif
@ -3120,4 +3319,82 @@ defined(PNG_USER_TRANSFORM_PTR_SUPPORTED)
png_ptr->flags |= PNG_FLAG_ROW_INIT;
}
#if defined(PNG_READ_APNG_SUPPORTED)
/* This function is to be called after the main IDAT set has been read and
* before a new IDAT is read. It resets some parts of png_ptr
* to make them usable by the read functions again */
void /* PRIVATE */
png_read_reset(png_structp png_ptr)
{
png_ptr->mode &= ~PNG_HAVE_IDAT;
png_ptr->mode &= ~PNG_AFTER_IDAT;
png_ptr->row_number = 0;
png_ptr->pass = 0;
png_ptr->flags &= ~PNG_FLAG_ROW_INIT;
}
void /* PRIVATE */
png_read_reinit(png_structp png_ptr, png_infop info_ptr)
{
png_ptr->width = info_ptr->next_frame_width;
png_ptr->height = info_ptr->next_frame_height;
png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth,png_ptr->width);
}
/* same as png_read_reset() but for the progressive reader */
void /* PRIVATE */
png_progressive_read_reset(png_structp png_ptr)
{
#ifdef PNG_USE_LOCAL_ARRAYS
/* start of interlace block */
const int FARDATA png_pass_start[] = {0, 4, 0, 2, 0, 1, 0};
/* offset to next interlace block */
const int FARDATA png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1};
/* start of interlace block in the y direction */
const int FARDATA png_pass_ystart[] = {0, 0, 4, 0, 2, 0, 1};
/* offset to next interlace block in the y direction */
const int FARDATA png_pass_yinc[] = {8, 8, 8, 4, 4, 2, 2};
#endif
png_uint_32 row_bytes;
if (png_ptr->interlaced)
{
if (!(png_ptr->transformations & PNG_INTERLACE))
png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 -
png_pass_ystart[0]) / png_pass_yinc[0];
else
png_ptr->num_rows = png_ptr->height;
png_ptr->iwidth = (png_ptr->width +
png_pass_inc[png_ptr->pass] - 1 -
png_pass_start[png_ptr->pass]) /
png_pass_inc[png_ptr->pass];
row_bytes = PNG_ROWBYTES(png_ptr->pixel_depth,png_ptr->iwidth) + 1;
png_ptr->irowbytes = (png_size_t)row_bytes;
if((png_uint_32)png_ptr->irowbytes != row_bytes)
png_error(png_ptr, "png_progressive_read_reset(): Rowbytes "
"overflow");
}
else
{
png_ptr->num_rows = png_ptr->height;
png_ptr->iwidth = png_ptr->width;
png_ptr->irowbytes = png_ptr->rowbytes + 1;
}
png_ptr->flags &= ~PNG_FLAG_ZLIB_FINISHED;
if (inflateReset(&(png_ptr->zstream)) != Z_OK)
png_error(png_ptr, "inflateReset failed");
png_ptr->zstream.avail_in = 0;
png_ptr->zstream.next_in = 0;
png_ptr->zstream.next_out = png_ptr->row_buf;
png_ptr->zstream.avail_out = (uInt)png_ptr->irowbytes;
}
#endif /* PNG_READ_APNG_SUPPORTED */
#endif /* PNG_READ_SUPPORTED */

Просмотреть файл

@ -362,6 +362,11 @@ png_set_IHDR(png_structp png_ptr, png_infop info_ptr,
info_ptr->rowbytes = (png_size_t)0;
else
info_ptr->rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth,width);
#if defined(PNG_APNG_SUPPORTED)
/* for non-animated png. this may be overritten from an acTl chunk later */
info_ptr->num_frames = 1;
#endif
}
#if defined(PNG_oFFs_SUPPORTED)
@ -993,6 +998,121 @@ png_set_sPLT(png_structp png_ptr,
}
#endif /* PNG_sPLT_SUPPORTED */
#if defined(PNG_APNG_SUPPORTED)
png_uint_32 PNGAPI
png_set_acTl(png_structp png_ptr, png_infop info_ptr,
png_uint_32 num_frames, png_uint_32 num_iterations)
{
png_debug1(1, "in %s storage function\n", "acTl");
if (png_ptr == NULL || info_ptr == NULL)
{
png_warning(png_ptr,
"Call to png_set_acTl() with NULL png_ptr "
"or info_ptr ignored");
return (0);
}
if(num_frames == 0)
{
png_warning(png_ptr,
"Ignoring attempt to set acTl with num_frames zero");
return (0);
}
if(num_frames > PNG_UINT_31_MAX)
{
png_warning(png_ptr,
"Ignoring attempt to set acTl with num_frames > 2^31-1");
return (0);
}
if(num_iterations > PNG_UINT_31_MAX)
{
png_warning(png_ptr,
"Ignoring attempt to set acTl with num_iterations "
"> 2^31-1");
return (0);
}
info_ptr->num_frames = num_frames;
info_ptr->num_iterations = num_iterations;
info_ptr->valid |= PNG_INFO_acTl;
return (1);
}
/* delay_num and delay_den can hold any values including zero */
png_uint_32 PNGAPI
png_set_next_frame_fcTl(png_structp png_ptr, png_infop info_ptr,
png_uint_32 width, png_uint_32 height,
png_uint_32 x_offset, png_uint_32 y_offset,
png_uint_16 delay_num, png_uint_16 delay_den,
png_byte render_op)
{
png_debug1(1, "in %s storage function\n", "fcTl");
if (png_ptr == NULL || info_ptr == NULL)
{
png_warning(png_ptr,
"Call to png_set_fcTl() with NULL png_ptr or info_ptr "
"ignored");
return (0);
}
png_ensure_fcTl_is_valid(png_ptr, width, height, x_offset, y_offset,
delay_num, delay_den, render_op);
info_ptr->next_frame_width = width;
info_ptr->next_frame_height = height;
info_ptr->next_frame_x_offset = x_offset;
info_ptr->next_frame_y_offset = y_offset;
info_ptr->next_frame_delay_num = delay_num;
info_ptr->next_frame_delay_den = delay_den;
info_ptr->next_frame_render_op = render_op;
info_ptr->valid |= PNG_INFO_fcTl;
return (1);
}
void /* PRIVATE */
png_ensure_fcTl_is_valid(png_structp png_ptr,
png_uint_32 width, png_uint_32 height,
png_uint_32 x_offset, png_uint_32 y_offset,
png_uint_16 delay_num, png_uint_16 delay_den,
png_byte render_op)
{
if (width > png_ptr->first_frame_width ||
height > png_ptr->first_frame_height)
png_error(png_ptr, "width and/or height for a frame greater than"
"the ones in IHDR");
if (width > PNG_UINT_31_MAX)
png_error(png_ptr, "invalid width in fcTl (> 2^31-1)");
if (height > PNG_UINT_31_MAX)
png_error(png_ptr, "invalid height in fcTl (> 2^31-1)");
if (x_offset > PNG_UINT_31_MAX)
png_error(png_ptr, "invalid x_offset in fcTl (> 2^31-1)");
if (y_offset > PNG_UINT_31_MAX)
png_error(png_ptr, "invalid y_offset in fcTl (> 2^31-1)");
if (render_op & 0xF0)
/* Bits 4 through 7 are reserved and must be set to zero (APNG spec) */
png_error(png_ptr, "invalid render_op in fcTl");
if (render_op & 0x08 && png_ptr->color_type == PNG_COLOR_TYPE_GRAY)
png_error(png_ptr, "APNG_RENDER_OP_BLEND_FLAG is not valid for "
"color type 'greyscale without alpha'");
if ((render_op & 0x08) &&
(png_ptr->color_type & PNG_COLOR_MASK_COLOR) &&
!(png_ptr->color_type & PNG_COLOR_MASK_ALPHA))
png_error(png_ptr, "APNG_RENDER_OP_BLEND_FLAG is not valid for "
"color type 'truecolor without alpha'");
if (!(render_op & PNG_RENDER_OP_DISPOSE_MASK))
png_error(png_ptr, "no DISPOSE_ flag found in fcTl");
if ( (render_op & PNG_RENDER_OP_DISPOSE_MASK) != PNG_RENDER_OP_DISPOSE_NONE &&
(render_op & PNG_RENDER_OP_DISPOSE_MASK) != PNG_RENDER_OP_DISPOSE_BACKGROUND &&
(render_op & PNG_RENDER_OP_DISPOSE_MASK) != PNG_RENDER_OP_DISPOSE_PREVIOUS)
png_error(png_ptr, "multiple DISPOSE_ flags set in fcTl");
}
#endif /* PNG_APNG_SUPPORTED */
#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
void PNGAPI
png_set_unknown_chunks(png_structp png_ptr,

Просмотреть файл

@ -261,6 +261,10 @@ png_write_info(png_structp png_ptr, png_infop info_ptr)
}
}
#endif
#if defined(PNG_WRITE_APNG_SUPPORTED)
if (info_ptr->valid & PNG_INFO_acTl)
png_write_acTl(png_ptr, info_ptr->num_frames, info_ptr->num_iterations);
#endif
#if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED)
if (info_ptr->unknown_chunks_num)
{
@ -299,6 +303,10 @@ png_write_end(png_structp png_ptr, png_infop info_ptr)
return;
if (!(png_ptr->mode & PNG_HAVE_IDAT))
png_error(png_ptr, "No IDATs written into file");
#if defined(PNG_WRITE_APNG_SUPPORTED)
if (png_ptr->num_frames_written != png_ptr->num_frames_to_write)
png_error(png_ptr, "Not enough frames written");
#endif
/* see if user wants us to write information chunks */
if (info_ptr != NULL)
@ -1510,4 +1518,38 @@ png_write_png(png_structp png_ptr, png_infop info_ptr,
/* quiet compiler warnings */ return;
}
#endif
#if defined(PNG_WRITE_APNG_SUPPORTED)
void PNGAPI
png_write_frame_head(png_structp png_ptr, png_infop info_ptr,
png_bytepp row_pointers, png_uint_32 width, png_uint_32 height,
png_uint_32 x_offset, png_uint_32 y_offset,
png_uint_16 delay_num, png_uint_16 delay_den, png_byte render_op,
png_byte first_frame_hidden)
{
png_debug(1, "in png_write_frame_head\n");
/* there is a chance this has been set after png_write_info was called,
* so it would be set but not written. is there a way to be sure? */
if (!(info_ptr->valid & PNG_INFO_acTl))
png_error(png_ptr, "png_write_frame_head(): acTl not set");
png_write_reset(png_ptr);
png_write_reinit(png_ptr, info_ptr, width, height);
if ( !(png_ptr->num_frames_written == 0 && first_frame_hidden) )
png_write_fcTl(png_ptr, width, height, x_offset, y_offset,
delay_num, delay_den, render_op);
}
void PNGAPI
png_write_frame_tail(png_structp png_ptr, png_infop png_info)
{
png_debug(1, "in png_write_frame_tail\n");
png_ptr->num_frames_written++;
}
#endif /* PNG_WRITE_APNG_SUPPORTED */
#endif /* PNG_WRITE_SUPPORTED */

Просмотреть файл

@ -491,6 +491,12 @@ png_write_IHDR(png_structp png_ptr, png_uint_32 width, png_uint_32 height,
/* write the chunk */
png_write_chunk(png_ptr, (png_bytep)png_IHDR, buf, (png_size_t)13);
#if defined(PNG_WRITE_APNG_SUPPORTED)
png_ptr->IHDR_crc = png_ptr->crc;
png_ptr->first_frame_width = width;
png_ptr->first_frame_height = height;
#endif
/* initialize zlib with PNG info */
png_ptr->zstream.zalloc = png_zalloc;
png_ptr->zstream.zfree = png_zfree;
@ -594,6 +600,13 @@ png_write_PLTE(png_structp png_ptr, png_colorp palette, png_uint_32 num_pal)
#endif
png_write_chunk_end(png_ptr);
png_ptr->mode |= PNG_HAVE_PLTE;
#if defined(PNG_WRITE_APNG_SUPPORTED)
if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
{
png_ptr->PLTE_crc = png_ptr->crc;
}
#endif
}
/* write an IDAT chunk */
@ -602,6 +615,9 @@ png_write_IDAT(png_structp png_ptr, png_bytep data, png_size_t length)
{
#ifdef PNG_USE_LOCAL_ARRAYS
PNG_IDAT;
#if defined(PNG_WRITE_APNG_SUPPORTED)
PNG_fdAt;
#endif
#endif
png_debug(1, "in png_write_IDAT\n");
@ -644,7 +660,28 @@ png_write_IDAT(png_structp png_ptr, png_bytep data, png_size_t length)
"Invalid zlib compression method or flags in IDAT");
}
png_write_chunk(png_ptr, (png_bytep)png_IDAT, data, length);
#if defined(PNG_WRITE_APNG_SUPPORTED)
if(png_ptr->num_frames_written == 0)
#endif
png_write_chunk(png_ptr, (png_bytep)png_IDAT, data, length);
#if defined(PNG_WRITE_APNG_SUPPORTED)
else
{
png_byte buf[4];
png_write_chunk_start(png_ptr, (png_bytep)png_fdAt, 4 + length);
png_save_uint_32(buf, png_ptr->next_seq_num);
png_write_chunk_data(png_ptr, buf, 4);
png_write_chunk_data(png_ptr, data, length);
png_write_chunk_end(png_ptr);
png_ptr->next_seq_num++;
}
#endif
png_ptr->mode |= PNG_HAVE_IDAT;
}
@ -1693,6 +1730,76 @@ png_write_tIME(png_structp png_ptr, png_timep mod_time)
}
#endif
#if defined(PNG_WRITE_APNG_SUPPORTED)
void /* PRIVATE */
png_write_acTl(png_structp png_ptr,
png_uint_32 num_frames, png_uint_32 num_iterations)
{
#ifdef PNG_USE_LOCAL_ARRAYS
PNG_acTl;
#endif
png_byte data[16];
png_debug(1, "in png_write_acTl\n");
if (num_frames == 0)
png_error(png_ptr, "png_write_acTl: invalid number of frames (0)");
if (num_frames > PNG_UINT_31_MAX)
png_error(png_ptr, "png_write_acTl: invalid number of frames "
"(> 2^31-1)");
if (num_iterations > PNG_UINT_31_MAX)
png_error(png_ptr, "png_write_acTl: invalid number of iterations "
"(> 2^31-1)");
png_ptr->num_frames_to_write = num_frames;
png_save_uint_32(data, num_frames);
png_save_uint_32(data + 4, num_iterations);
png_save_uint_32(data + 8, png_ptr->IHDR_crc);
png_save_uint_32(data + 12, png_ptr->PLTE_crc);
png_write_chunk(png_ptr, (png_bytep)png_acTl, data, (png_size_t)16);
}
void /* PRIVATE */
png_write_fcTl(png_structp png_ptr, png_uint_32 width, png_uint_32 height,
png_uint_32 x_offset, png_uint_32 y_offset,
png_uint_16 delay_num, png_uint_16 delay_den, png_byte render_op)
{
#ifdef PNG_USE_LOCAL_ARRAYS
PNG_fcTl;
#endif
png_byte data[25];
png_debug(1, "in png_write_fcTl\n");
if (png_ptr->num_frames_written == 0 && (x_offset != 0 || y_offset != 0))
png_error(png_ptr, "x and/or y offset for the first frame aren't 0\n");
if (png_ptr->num_frames_written == 0 &&
(width != png_ptr->first_frame_width ||
height != png_ptr->first_frame_height))
png_error(png_ptr, "width and/or height in the first frame's fcTl "
"don't match the ones in IHDR\n");
/* more error checking */
png_ensure_fcTl_is_valid(png_ptr, width, height, x_offset, y_offset,
delay_num, delay_den, render_op);
png_save_uint_32(data, png_ptr->next_seq_num);
png_save_uint_32(data + 4, width);
png_save_uint_32(data + 8, height);
png_save_uint_32(data + 12, x_offset);
png_save_uint_32(data + 16, y_offset);
png_save_uint_16(data + 20, delay_num);
png_save_uint_16(data + 22, delay_den);
data[24] = render_op;
png_write_chunk(png_ptr, (png_bytep)png_fcTl, data, (png_size_t)25);
png_ptr->next_seq_num++;
}
#endif /* PNG_WRITE_APNG_SUPPORTED */
/* initializes the row writing capability of libpng */
void /* PRIVATE */
png_write_start_row(png_structp png_ptr)
@ -1720,14 +1827,16 @@ png_write_start_row(png_structp png_ptr)
png_ptr->usr_channels*png_ptr->usr_bit_depth,png_ptr->width)+1);
/* set up row buffer */
png_ptr->row_buf = (png_bytep)png_malloc(png_ptr, (png_uint_32)buf_size);
if (png_ptr->row_buf == NULL)
png_ptr->row_buf = (png_bytep)png_malloc(png_ptr, (png_uint_32)buf_size);
png_ptr->row_buf[0] = PNG_FILTER_VALUE_NONE;
/* set up filtering buffer, if using this filter */
if (png_ptr->do_filter & PNG_FILTER_SUB)
{
png_ptr->sub_row = (png_bytep)png_malloc(png_ptr,
(png_ptr->rowbytes + 1));
if (png_ptr->sub_row == NULL)
png_ptr->sub_row = (png_bytep)png_malloc(png_ptr,
(png_ptr->rowbytes + 1));
png_ptr->sub_row[0] = PNG_FILTER_VALUE_SUB;
}
@ -1735,27 +1844,31 @@ png_write_start_row(png_structp png_ptr)
if (png_ptr->do_filter & (PNG_FILTER_AVG | PNG_FILTER_UP | PNG_FILTER_PAETH))
{
/* set up previous row buffer */
png_ptr->prev_row = (png_bytep)png_malloc(png_ptr, (png_uint_32)buf_size);
if (png_ptr->prev_row == NULL)
png_ptr->prev_row = (png_bytep)png_malloc(png_ptr, (png_uint_32)buf_size);
png_memset(png_ptr->prev_row, 0, buf_size);
if (png_ptr->do_filter & PNG_FILTER_UP)
{
png_ptr->up_row = (png_bytep )png_malloc(png_ptr,
(png_ptr->rowbytes + 1));
if (png_ptr->up_row == NULL)
png_ptr->up_row = (png_bytep )png_malloc(png_ptr,
(png_ptr->rowbytes + 1));
png_ptr->up_row[0] = PNG_FILTER_VALUE_UP;
}
if (png_ptr->do_filter & PNG_FILTER_AVG)
{
png_ptr->avg_row = (png_bytep)png_malloc(png_ptr,
(png_ptr->rowbytes + 1));
if (png_ptr->avg_row == NULL)
png_ptr->avg_row = (png_bytep)png_malloc(png_ptr,
(png_ptr->rowbytes + 1));
png_ptr->avg_row[0] = PNG_FILTER_VALUE_AVG;
}
if (png_ptr->do_filter & PNG_FILTER_PAETH)
{
png_ptr->paeth_row = (png_bytep )png_malloc(png_ptr,
(png_ptr->rowbytes + 1));
if (png_ptr->paeth_row == NULL)
png_ptr->paeth_row = (png_bytep )png_malloc(png_ptr,
(png_ptr->rowbytes + 1));
png_ptr->paeth_row[0] = PNG_FILTER_VALUE_PAETH;
}
}
@ -2747,4 +2860,39 @@ png_write_filtered_row(png_structp png_ptr, png_bytep filtered_row)
}
#endif
}
#if defined(PNG_WRITE_APNG_SUPPORTED)
void /* PRIVATE */
png_write_reset(png_structp png_ptr)
{
png_ptr->row_number = 0;
png_ptr->pass = 0;
png_ptr->mode &= ~PNG_HAVE_IDAT;
}
void /* PRIVATE */
png_write_reinit(png_structp png_ptr, png_infop info_ptr,
png_uint_32 width, png_uint_32 height)
{
if (png_ptr->num_frames_written == 0 &&
(width != png_ptr->first_frame_width ||
height != png_ptr->first_frame_height))
png_error(png_ptr, "width and/or height in the first frame's fcTl "
"don't match the ones in IHDR\n");
if (width > png_ptr->first_frame_width ||
height > png_ptr->first_frame_height)
png_error(png_ptr, "width and/or height for a frame greater than"
"the ones in IHDR");
png_set_IHDR(png_ptr, info_ptr, width, height,
info_ptr->bit_depth, info_ptr->color_type,
info_ptr->interlace_type, info_ptr->compression_type,
info_ptr->filter_type);
png_ptr->width = width;
png_ptr->height = height;
png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth, width);
png_ptr->usr_width = png_ptr->width;
}
#endif
#endif /* PNG_WRITE_SUPPORTED */

Просмотреть файл

@ -61,7 +61,6 @@
#ifdef IMG_BUILD_DECODER_gif
// gif
#include "imgContainerGIF.h"
#include "nsGIFDecoder2.h"
#endif
@ -106,7 +105,6 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(imgRequestProxy)
#ifdef IMG_BUILD_DECODER_gif
// gif
NS_GENERIC_FACTORY_CONSTRUCTOR(imgContainerGIF)
NS_GENERIC_FACTORY_CONSTRUCTOR(nsGIFDecoder2)
#endif
@ -222,10 +220,6 @@ static const nsModuleComponentInfo components[] =
#ifdef IMG_BUILD_DECODER_gif
// gif
{ "GIF image container",
NS_GIFCONTAINER_CID,
"@mozilla.org/image/container;1?type=image/gif",
imgContainerGIFConstructor, },
{ "GIF Decoder",
NS_GIFDECODER2_CID,
"@mozilla.org/image/decoder;2?type=image/gif",

Просмотреть файл

@ -634,11 +634,11 @@ PRStatus gif_write(gif_struct *gs, const PRUint8 *buf, PRUint32 len)
gs->is_transparent = PR_FALSE;
// ignoring gfx control extension
}
gs->disposal_method = (gdispose)(((*q) >> 2) & 0x7);
gs->disposal_method = ((*q) >> 2) & 0x7;
// Some specs say 3rd bit (value 4), other specs say value 3
// Let's choose 3 (the more popular)
if (gs->disposal_method == 4)
gs->disposal_method = (gdispose)3;
gs->disposal_method = 3;
gs->delay_time = GETINT16(q + 1) * 10;
GETN(1, gif_consume_block);
}

Просмотреть файл

@ -72,16 +72,6 @@ typedef enum {
gif_consume_comment
} gstate;
/* "Disposal" method indicates how the image should be handled in the
framebuffer before the subsequent image is displayed. */
typedef enum
{
DISPOSE_NOT_SPECIFIED = 0,
DISPOSE_KEEP = 1, /* Leave it in the framebuffer */
DISPOSE_OVERWRITE_BGCOLOR = 2, /* Overwrite with background color */
DISPOSE_OVERWRITE_PREVIOUS = 3 /* Save-under */
} gdispose;
/* A GIF decoder's state */
typedef struct gif_struct {
void* clientptr;
@ -115,7 +105,7 @@ typedef struct gif_struct {
PRUintn x_offset, y_offset; /* With respect to "screen" origin */
PRUintn height, width;
int tpixel; /* Index of transparent pixel */
gdispose disposal_method; /* Restore to background, leave in place, etc.*/
PRInt32 disposal_method; /* Restore to background, leave in place, etc.*/
PRUint8 *local_colormap; /* Per-image colormap */
int local_colormap_size; /* Size of local colormap array. */
PRUint32 delay_time; /* Display time, in milliseconds,

Просмотреть файл

@ -56,7 +56,10 @@ REQUIRES = xpcom \
imglib2 \
$(NULL)
CPPSRCS = GIF2.cpp nsGIFDecoder2.cpp imgContainerGIF.cpp
CPPSRCS = GIF2.cpp nsGIFDecoder2.cpp
# nsGIFDecoder2.cpp includes imgContainer.h
LOCAL_INCLUDES += -I$(topsrcdir)/modules/libpr0n/src
include $(topsrcdir)/config/rules.mk

Просмотреть файл

@ -48,6 +48,7 @@
#include "imgILoad.h"
#include "imgContainer.h"
/*******************************************************************************
* Gif decoder allocator
@ -102,7 +103,7 @@ NS_IMETHODIMP nsGIFDecoder2::Init(imgILoad *aLoad)
{
mObserver = do_QueryInterface(aLoad);
mImageContainer = do_CreateInstance("@mozilla.org/image/container;1?type=image/gif");
mImageContainer = do_CreateInstance("@mozilla.org/image/container;1");
aLoad->SetImage(mImageContainer);
if (!gGifAllocator) {
@ -257,7 +258,7 @@ NS_IMETHODIMP nsGIFDecoder2::WriteFrom(nsIInputStream *inStr, PRUint32 count, PR
//******************************************************************************
// GIF decoder callback methods. Part of pulic API for GIF2
// GIF decoder callback methods. Part of public API for GIF2
//******************************************************************************
//******************************************************************************
@ -475,7 +476,7 @@ int nsGIFDecoder2::HaveDecodedRow(
if (!cmap) { // cmap could have null value if the global color table flag is 0
for (int i = 0; i < aDuplicateCount; ++i) {
imgContainerGIF::BlackenFrame(decoder->mImageFrame, 0, aRowNumber+i, width, 1);
imgContainer::BlackenFrame(decoder->mImageFrame, 0, aRowNumber+i, width, 1);
}
} else {
PRUint8* rowBufIndex = aRowBufPtr;

Просмотреть файл

@ -42,7 +42,7 @@
#include "nsCOMPtr.h"
#include "imgIDecoder.h"
#include "imgContainerGIF.h"
#include "imgIContainer.h"
#include "imgIDecoderObserver.h"
#include "gfxIImageFrame.h"

Просмотреть файл

@ -22,6 +22,7 @@
*
* Contributor(s):
* Stuart Parmenter <stuart@mozilla.com>
* Andrew Smith
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
@ -55,9 +56,15 @@
#include "nspr.h"
#include "png.h"
// for nsPNGDecoder.apngFlags
enum {
FRAME_HIDDEN = 0x01
};
static void PNGAPI info_callback(png_structp png_ptr, png_infop info_ptr);
static void PNGAPI row_callback(png_structp png_ptr, png_bytep new_row,
png_uint_32 row_num, int pass);
static void PNGAPI frame_info_callback(png_structp png_ptr, png_uint_32 frame_num);
static void PNGAPI end_callback(png_structp png_ptr, png_infop info_ptr);
static void PNGAPI error_callback(png_structp png_ptr, png_const_charp error_msg);
static void PNGAPI warning_callback(png_structp png_ptr, png_const_charp warning_msg);
@ -70,6 +77,7 @@ NS_IMPL_ISUPPORTS1(nsPNGDecoder, imgIDecoder)
nsPNGDecoder::nsPNGDecoder() :
mPNG(nsnull), mInfo(nsnull),
apngFlags(0),
interlacebuf(nsnull), ibpr(0),
mError(PR_FALSE)
{
@ -81,6 +89,59 @@ nsPNGDecoder::~nsPNGDecoder()
nsMemory::Free(interlacebuf);
}
// CreateFrame() is used for both simple and animated images
void nsPNGDecoder::CreateFrame(png_uint_32 x_offset, png_uint_32 y_offset,
PRInt32 width, PRInt32 height, gfx_format format)
{
mFrame = do_CreateInstance("@mozilla.org/gfx/image/frame;2");
if (!mFrame)
longjmp(mPNG->jmpbuf, 5); // NS_ERROR_OUT_OF_MEMORY
nsresult rv = mFrame->Init(x_offset, y_offset, width, height, format, 24);
if (NS_FAILED(rv))
longjmp(mPNG->jmpbuf, 5); // NS_ERROR_OUT_OF_MEMORY
if (png_get_valid(mPNG, mInfo, PNG_INFO_acTl))
SetAnimFrameInfo();
mImage->AppendFrame(mFrame);
if (mObserver)
mObserver->OnStartFrame(nsnull, mFrame);
}
// set timeout and frame disposal method for the current frame
void nsPNGDecoder::SetAnimFrameInfo()
{
png_uint_16 delay_num, delay_den; /* in seconds */
png_byte render_op;
PRInt32 timeout; /* in milliseconds */
delay_num = png_get_next_frame_delay_num(mPNG, mInfo);
delay_den = png_get_next_frame_delay_den(mPNG, mInfo);
render_op = png_get_next_frame_render_op(mPNG, mInfo);
if (delay_num == 0) {
timeout = 0; // gfxImageFrame::SetTimeout() will set to a minimum
} else {
if (delay_den == 0)
delay_den = 100; // so sais the APNG spec
// Need to cast delay_num to float to have a proper division and
// the result to int to avoid compiler warning
timeout = NS_STATIC_CAST( PRInt32,
NS_STATIC_CAST(PRFloat64, delay_num) * 1000 / delay_den );
}
mFrame->SetTimeout(timeout);
if (render_op & PNG_RENDER_OP_DISPOSE_PREVIOUS)
mFrame->SetFrameDisposalMethod(imgIContainer::kDisposeRestorePrevious);
else if (render_op & PNG_RENDER_OP_DISPOSE_BACKGROUND)
mFrame->SetFrameDisposalMethod(imgIContainer::kDisposeClear);
else
mFrame->SetFrameDisposalMethod(imgIContainer::kDisposeKeep);
}
/** imgIDecoder methods **/
@ -213,20 +274,19 @@ info_callback(png_structp png_ptr, png_infop info_ptr)
int channels;
double aGamma;
png_bytep trans=NULL;
int num_trans =0;
png_bytep trans = NULL;
int num_trans = 0;
nsPNGDecoder *decoder = NS_STATIC_CAST(nsPNGDecoder*, png_get_progressive_ptr(png_ptr));
/* always decode to 24-bit RGB or 32-bit RGBA */
png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
&interlace_type, &compression_type, &filter_type);
/* limit image dimensions (bug #251381) */
#define MOZ_PNG_MAX_DIMENSION 1000000L
if (width > MOZ_PNG_MAX_DIMENSION || height > MOZ_PNG_MAX_DIMENSION) {
nsPNGDecoder *decoder = NS_STATIC_CAST(nsPNGDecoder*,
png_get_progressive_ptr(png_ptr));
if (width > MOZ_PNG_MAX_DIMENSION || height > MOZ_PNG_MAX_DIMENSION)
longjmp(decoder->mPNG->jmpbuf, 1);
}
#undef MOZ_PNG_MAX_DIMENSION
if (color_type == PNG_COLOR_TYPE_PALETTE)
@ -292,8 +352,6 @@ info_callback(png_structp png_ptr, png_infop info_ptr)
}
}
nsPNGDecoder *decoder = NS_STATIC_CAST(nsPNGDecoder*, png_get_progressive_ptr(png_ptr));
if (decoder->mObserver)
decoder->mObserver->OnStartDecode(nsnull);
@ -303,38 +361,38 @@ info_callback(png_structp png_ptr, png_infop info_ptr)
decoder->mImageLoad->SetImage(decoder->mImage);
// since the png is only 1 frame, initialize the container to the width and height of the frame
decoder->mImage->Init(width, height, decoder->mObserver);
if (decoder->mObserver)
decoder->mObserver->OnStartContainer(nsnull, decoder->mImage);
decoder->mFrame = do_CreateInstance("@mozilla.org/gfx/image/frame;2");
if (!decoder->mFrame)
longjmp(decoder->mPNG->jmpbuf, 5); // NS_ERROR_OUT_OF_MEMORY
gfx_format format;
if (channels == 3) {
format = gfxIFormats::RGB;
decoder->format = gfxIFormats::RGB;
} else if (channels > 3) {
if (alpha_bits == 8) {
decoder->mImage->GetPreferredAlphaChannelFormat(&format);
decoder->mImage->GetPreferredAlphaChannelFormat(&(decoder->format));
} else if (alpha_bits == 1) {
format = gfxIFormats::RGB_A1;
decoder->format = gfxIFormats::RGB_A1;
}
}
// then initialize the frame and append it to the container
nsresult rv = decoder->mFrame->Init(0, 0, width, height, format, 24);
if (NS_FAILED(rv))
longjmp(decoder->mPNG->jmpbuf, 5); // NS_ERROR_OUT_OF_MEMORY
decoder->mImage->AppendFrame(decoder->mFrame);
if (decoder->mObserver)
decoder->mObserver->OnStartFrame(nsnull, decoder->mFrame);
if (png_get_valid(png_ptr, info_ptr, PNG_INFO_acTl))
png_set_progressive_frame_fn(png_ptr, frame_info_callback, NULL);
if (png_first_frame_is_hidden(png_ptr, info_ptr)) {
decoder->apngFlags |= FRAME_HIDDEN;
// create a frame just to get bpr, to allocate interlacebuf
decoder->mFrame = do_CreateInstance("@mozilla.org/gfx/image/frame;2");
if (!decoder->mFrame)
longjmp(png_ptr->jmpbuf, 5); // NS_ERROR_OUT_OF_MEMORY
nsresult rv = decoder->mFrame->Init(0, 0, width, height, decoder->format, 24);
if (NS_FAILED(rv))
longjmp(png_ptr->jmpbuf, 5); // NS_ERROR_OUT_OF_MEMORY
} else {
decoder->CreateFrame(0, 0, width, height, decoder->format);
}
PRUint32 bpr;
decoder->mFrame->GetImageBytesPerRow(&bpr);
@ -346,9 +404,12 @@ info_callback(png_structp png_ptr, png_infop info_ptr)
decoder->interlacebuf = (PRUint8 *)nsMemory::Alloc(decoder->ibpr*height);
if (!decoder->interlacebuf) {
longjmp(decoder->mPNG->jmpbuf, 5); // NS_ERROR_OUT_OF_MEMORY
}
}
}
if (png_first_frame_is_hidden(png_ptr, info_ptr))
decoder->mFrame = nsnull;
return;
}
@ -384,6 +445,11 @@ row_callback(png_structp png_ptr, png_bytep new_row,
* old row and the new row.
*/
nsPNGDecoder *decoder = NS_STATIC_CAST(nsPNGDecoder*, png_get_progressive_ptr(png_ptr));
// do nothing
// is it ok that we're not telling the observer there is some data?
if (decoder->apngFlags & FRAME_HIDDEN)
return;
png_bytep line;
if (decoder->interlacebuf) {
@ -444,7 +510,32 @@ row_callback(png_structp png_ptr, png_bytep new_row,
}
}
// got the header of a new frame that's coming
void
frame_info_callback(png_structp png_ptr, png_uint_32 frame_num)
{
png_uint_32 x_offset, y_offset;
PRInt32 width, height;
nsPNGDecoder *decoder = NS_STATIC_CAST(nsPNGDecoder*, png_get_progressive_ptr(png_ptr));
// old frame is done
if (!(decoder->apngFlags & FRAME_HIDDEN)) {
PRInt32 timeout;
decoder->mFrame->GetTimeout(&timeout);
decoder->mImage->EndFrameDecode(frame_num, timeout);
decoder->mObserver->OnStopFrame(nsnull, decoder->mFrame);
}
decoder->apngFlags &= ~FRAME_HIDDEN;
x_offset = png_get_next_frame_x_offset(png_ptr, decoder->mInfo);
y_offset = png_get_next_frame_y_offset(png_ptr, decoder->mInfo);
width = png_get_next_frame_width(png_ptr, decoder->mInfo);
height = png_get_next_frame_height(png_ptr, decoder->mInfo);
decoder->CreateFrame(x_offset, y_offset, width, height, decoder->format);
}
void
end_callback(png_structp png_ptr, png_infop info_ptr)
@ -462,16 +553,29 @@ end_callback(png_structp png_ptr, png_infop info_ptr)
*/
nsPNGDecoder *decoder = NS_STATIC_CAST(nsPNGDecoder*, png_get_progressive_ptr(png_ptr));
if (png_get_valid(png_ptr, info_ptr, PNG_INFO_acTl)) {
PRInt32 num_iterations = png_get_num_iterations(png_ptr, info_ptr);
if (num_iterations <= 0) /* forever */
num_iterations = -1;
decoder->mImage->SetLoopCount(num_iterations);
}
if (!(decoder->apngFlags & FRAME_HIDDEN)) {
PRInt32 timeout;
decoder->mFrame->GetTimeout(&timeout);
decoder->mImage->EndFrameDecode(decoder->mPNG->num_frames_read, timeout);
}
decoder->mImage->DecodingComplete();
if (decoder->mObserver) {
decoder->mObserver->OnStopFrame(nsnull, decoder->mFrame);
if (!(decoder->apngFlags & FRAME_HIDDEN))
decoder->mObserver->OnStopFrame(nsnull, decoder->mFrame);
decoder->mObserver->OnStopContainer(nsnull, decoder->mImage);
decoder->mObserver->OnStopDecode(nsnull, NS_OK, nsnull);
}
// We are never going to change the data of this frame again. Let the OS
// do what it wants with this image.
decoder->mFrame->SetMutable(PR_FALSE);
}

Просмотреть файл

@ -69,6 +69,10 @@ public:
nsPNGDecoder();
virtual ~nsPNGDecoder();
void CreateFrame(png_uint_32 x_offset, png_uint_32 y_offset,
PRInt32 width, PRInt32 height, gfx_format format);
void SetAnimFrameInfo();
public:
nsCOMPtr<imgIContainer> mImage;
nsCOMPtr<gfxIImageFrame> mFrame;
@ -77,6 +81,8 @@ public:
png_structp mPNG;
png_infop mInfo;
gfx_format format;
PRUint8 apngFlags;
PRUint8 *interlacebuf;
PRUint32 ibpr;
PRPackedBool mError;

Просмотреть файл

@ -54,6 +54,19 @@ interface imgIContainerObserver;
[scriptable, uuid(1a6290e6-8285-4e10-963d-d001f8d327b8)]
interface imgIContainer : nsISupports
{
/**
* "Disposal" method indicates how the image should be handled before the
* subsequent image is displayed.
* Don't change these without looking at the implementations using them,
* struct gif_struct::disposal_method and gif_write() in particular.
*/
const long kDisposeClearAll = -1; // Clear the whole image, revealing
// what was there before the gif displayed
const long kDisposeNotSpecified = 0; // Leave frame, let new frame draw on top
const long kDisposeKeep = 1; // Leave frame, let new frame draw on top
const long kDisposeClear = 2; // Clear the frame's area, revealing bg
const long kDisposeRestorePrevious = 3; // Restore the previous (composited) frame
/**
* Create a new \a aWidth x \a aHeight sized image container.
*
@ -126,8 +139,6 @@ interface imgIContainer : nsISupports
void resetAnimation();
/* animation stuff */
/**
* number of times to loop the image.
* @note -1 means forever.

Просмотреть файл

@ -47,7 +47,7 @@ interface nsIURI;
/**
* imgIRequest interface
*
* @author Stuart Parmenter <pavlov@netscape.com>
* @author Stuart Parmenter <stuart@mozilla.com>
* @version 0.1
* @see imagelib2
*/

Просмотреть файл

@ -54,6 +54,8 @@ REQUIRES = xpcom \
necko \
nkcache \
gfx \
thebes \
cairo \
$(NULL)
CPPSRCS = \

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -38,14 +38,26 @@
*
* ***** END LICENSE BLOCK ***** */
/** @file
* This file declares the imgContainer class, which
* handles static and animated image containers.
*
* @author Stuart Parmenter <pavlov@netscape.com>
* @author Chris Saari <saari@netscape.com>
* @author Arron Mogge <paper@animecity.nu>
* @author Andrew Smith <asmith15@learn.senecac.on.ca>
*/
#ifndef __imgContainer_h__
#define __imgContainer_h__
#include "nsCOMArray.h"
#include "nsCOMPtr.h"
#include "imgIContainer.h"
#include "gfxIImageFrame.h"
#include "nsIProperties.h"
#include "nsITimer.h"
#include "nsWeakReference.h"
#define NS_IMGCONTAINER_CID \
{ /* 27f0682c-ff64-4dd2-ae7a-668e59f2fd38 */ \
@ -55,20 +67,231 @@
{0xae, 0x7a, 0x66, 0x8e, 0x59, 0xf2, 0xfd, 0x38} \
}
class imgContainer : public imgIContainer, public nsIProperties
/**
* Handles static and animated image containers.
*
*
* @par A Quick Walk Through
* The decoder initializes this class and calls AppendFrame() to add a frame.
* Once imgContainer detects more than one frame, it starts the animation
* with StartAnimation().
*
* @par
* StartAnimation() checks if animating is allowed, and creates a timer. The
* timer calls Notify when the specified frame delay time is up.
*
* @par
* Notify() moves on to the next frame, sets up the new timer delay, destroys
* the old frame, and forces a redraw via observer->FrameChanged().
*
* @par
* Each frame can have a different method of removing itself. These are
* listed as imgIContainer::cDispose... constants. Notify() calls
* DoComposite() to handle any special frame destruction.
*
* @par
* The basic path through DoComposite() is:
* 1) Calculate Area that needs updating, which is at least the area of
* aNextFrame.
* 2) Dispose of previous frame.
* 3) Draw new image onto compositingFrame.
* See comments in DoComposite() for more information and optimizations.
*
* @par
* The rest of the imgContainer specific functions are used by DoComposite to
* destroy the old frame and build the new one.
*
* @note
* <li> "Mask", "Alpha", and "Alpha Level" are interchangable phrases in
* respects to imgContainerGIF.
*
* @par
* <li> GIFs never have more than a 1 bit alpha.
* <li> APNGs may have a full alpha channel.
*
* @par
* <li> Background color specified in GIF is ignored by web browsers.
*
* @par
* <li> If Frame 3 wants to dispose by restoring previous, what it wants is to
* restore the composition up to and including Frame 2, as well as Frame 2s
* disposal. So, in the middle of DoComposite when composing Frame 3, right
* after destroying Frame 2's area, we copy compositingFrame to
* prevCompositingFrame. When DoComposite gets called to do Frame 4, we
* copy prevCompositingFrame back, and then draw Frame 4 on top.
*
* @par
* The mAnim structure has members only needed for animated images, so
* it's not allocated until the second frame is added.
*
* @note
* mAnimationMode, mLoopCount and mObserver are not in the mAnim structure
* because the first two have public setters and the observer we only get
* in Init().
*/
class imgContainer : public imgIContainer,
public nsITimerCallback,
public nsIProperties
{
public:
NS_DECL_ISUPPORTS
NS_DECL_IMGICONTAINER
NS_DECL_NSITIMERCALLBACK
NS_FORWARD_SAFE_NSIPROPERTIES(mProperties)
imgContainer();
virtual ~imgContainer();
private:
nsIntSize mSize;
nsCOMPtr<gfxIImageFrame> mFrame;
nsCOMPtr<nsIProperties> mProperties;
friend class nsGIFDecoder2;
struct Anim
{
//! Area of the first frame that needs to be redrawn on subsequent loops.
nsIntRect firstFrameRefreshArea;
// Note this doesn't hold a proper value until frame 2 finished decoding.
PRInt32 currentDecodingFrameIndex; // 0 to numFrames-1
PRInt32 currentAnimationFrameIndex; // 0 to numFrames-1
//! Track the last composited frame for Optimizations (See DoComposite code)
PRInt32 lastCompositedFrameIndex;
//! Whether we can assume there will be no more frames
//! (and thus loop the animation)
PRBool doneDecoding;
//! Are we currently animating the image?
PRBool animating;
/** For managing blending of frames
*
* Some animations will use the compositingFrame to composite images
* and just hand this back to the caller when it is time to draw the frame.
* NOTE: When clearing compositingFrame, remember to set
* lastCompositedFrameIndex to -1. Code assume that if
* lastCompositedFrameIndex >= 0 then compositingFrame exists.
*/
nsCOMPtr<gfxIImageFrame> compositingFrame;
/** the previous composited frame, for DISPOSE_RESTORE_PREVIOUS
*
* The Previous Frame (all frames composited up to the current) needs to be
* stored in cases where the image specifies it wants the last frame back
* when it's done with the current frame.
*/
nsCOMPtr<gfxIImageFrame> compositingPrevFrame;
//! Timer to animate multiframed images
nsCOMPtr<nsITimer> timer;
Anim() :
firstFrameRefreshArea(),
currentDecodingFrameIndex(0),
currentAnimationFrameIndex(0),
lastCompositedFrameIndex(-1),
doneDecoding(PR_FALSE),
animating(PR_FALSE)
{
;
}
~Anim()
{
if (timer)
timer->Cancel();
}
};
inline gfxIImageFrame* inlinedGetCurrentFrame() {
if (!mAnim)
return mFrames.SafeObjectAt(0);
if (mAnim->lastCompositedFrameIndex == mAnim->currentAnimationFrameIndex)
return mAnim->compositingFrame;
return mFrames.SafeObjectAt(mAnim->currentAnimationFrameIndex);
}
inline Anim* ensureAnimExists() {
if (!mAnim)
mAnim = new Anim();
return mAnim;
}
/** Function for doing the frame compositing of animations
*
* @param aFrameToUse Set by DoComposite
* (aNextFrame, compositingFrame, or compositingPrevFrame)
* @param aDirtyRect Area that the display will need to update
* @param aPrevFrame Last Frame seen/processed
* @param aNextFrame Frame we need to incorperate/display
* @param aNextFrameIndex Position of aNextFrame in mFrames list
*/
nsresult DoComposite(gfxIImageFrame** aFrameToUse, nsIntRect* aDirtyRect,
gfxIImageFrame* aPrevFrame,
gfxIImageFrame* aNextFrame,
PRInt32 aNextFrameIndex);
/**
* Combine aOverlayFrame's mask into aCompositingFrame's mask.
*
* This takes the mask information from the passed in aOverlayFrame and
* inserts that information into the aCompositingFrame's mask at the proper
* offsets. It does *not* rebuild the entire mask.
*
* @param aCompositingFrame Target frame
* @param aOverlayFrame This frame's mask is being copied
*/
void BuildCompositeMask(gfxIImageFrame* aCompositingFrame,
gfxIImageFrame* aOverlayFrame);
/** Sets an area of the frame's mask.
*
* @param aFrame Target Frame
* @param aVisible Turn on (PR_TRUE) or off (PR_FALSE) visibility
*
* @note Invisible area of frame's image will need to be set to 0
*/
void SetMaskVisibility(gfxIImageFrame *aFrame, PRBool aVisible);
//! @overload
void SetMaskVisibility(gfxIImageFrame *aFrame,
PRInt32 aX, PRInt32 aY,
PRInt32 aWidth, PRInt32 aHeight,
PRBool aVisible);
//! @overload
void SetMaskVisibility(gfxIImageFrame *aFrame,
nsIntRect &aRect, PRBool aVisible) {
SetMaskVisibility(aFrame, aRect.x, aRect.y,
aRect.width, aRect.height, aVisible);
}
/** Fills an area of <aFrame> with black.
*
* @param aFrame Target Frame
*
* @note Does not set the mask
*/
static void BlackenFrame(gfxIImageFrame* aFrame);
//! @overload
static void BlackenFrame(gfxIImageFrame* aFrame,
PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight);
//! @overload
static inline void BlackenFrame(gfxIImageFrame* aFrame, nsIntRect &aRect) {
BlackenFrame(aFrame, aRect.x, aRect.y, aRect.width, aRect.height);
}
//! Copy one gfxIImageFrame's image and mask into another
static PRBool CopyFrameImage(gfxIImageFrame *aSrcFrame,
gfxIImageFrame *aDstFrame);
nsIntSize mSize;
//! All the <gfxIImageFrame>s of the PNG
nsCOMArray<gfxIImageFrame> mFrames;
nsCOMPtr<nsIProperties> mProperties;
imgContainer::Anim* mAnim;
//! See imgIContainer for mode constants
PRUint16 mAnimationMode;
//! # loops remaining before animation stops (-1 no stop)
PRInt32 mLoopCount;
//! imgIContainerObserver
nsWeakPtr mObserver;
};
#endif /* __imgContainer_h__ */