2019-02-16 11:18:22 +00:00
|
|
|
/*
|
2020-02-19 22:08:45 +00:00
|
|
|
Copyright 2019-2020, James R.
|
2019-02-16 11:18:22 +00:00
|
|
|
All rights reserved.
|
|
|
|
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
|
|
modification, are permitted provided that the following conditions are met:
|
|
|
|
|
|
|
|
1. Redistributions of source code must retain the above copyright notice, this
|
|
|
|
list of conditions and the following disclaimer.
|
|
|
|
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
|
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
|
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
|
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
|
|
|
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
|
|
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
|
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
|
|
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
|
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
|
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#include "apng.h"
|
|
|
|
|
2019-02-19 17:51:52 +00:00
|
|
|
#define APNG_INFO_acTL 0x20000U
|
|
|
|
|
2019-02-16 11:18:22 +00:00
|
|
|
#define APNG_WROTE_acTL 0x10000U
|
|
|
|
|
|
|
|
struct apng_info_def
|
|
|
|
{
|
|
|
|
png_uint_32 mode;
|
|
|
|
png_uint_32 valid;
|
|
|
|
|
|
|
|
png_uint_32 num_frames;
|
|
|
|
png_uint_32 num_plays;
|
|
|
|
|
|
|
|
long start_acTL;/* acTL is written here */
|
|
|
|
|
|
|
|
png_flush_ptr output_flush_fn;
|
|
|
|
apng_seek_ptr output_seek_fn;
|
|
|
|
apng_tell_ptr output_tell_fn;
|
|
|
|
|
|
|
|
apng_set_acTL_ptr set_acTL_fn;
|
|
|
|
};
|
|
|
|
|
|
|
|
/* PROTOS (FUCK COMPILER) */
|
|
|
|
void apng_seek (png_structp, apng_const_infop, size_t);
|
|
|
|
size_t apng_tell (png_structp, apng_const_infop);
|
|
|
|
#ifdef PNG_WRITE_FLUSH_SUPPORTED
|
|
|
|
void apng_flush (png_structp, apng_infop);
|
|
|
|
#ifdef PNG_STDIO_SUPPORTED
|
|
|
|
void apng_default_flush (png_structp);
|
|
|
|
#endif/* PNG_STDIO_SUPPORTED */
|
|
|
|
#endif/* PNG_WRITE_FLUSH_SUPPORTED */
|
|
|
|
#ifdef PNG_STDIO_SUPPORTED
|
|
|
|
void apng_default_seek (png_structp, size_t);
|
|
|
|
size_t apng_default_tell (png_structp);
|
|
|
|
#endif/* PNG_STDIO_SUPPORTED */
|
|
|
|
void apng_write_IEND (png_structp);
|
|
|
|
void apng_write_acTL (png_structp, png_uint_32, png_uint_32);
|
2019-02-19 17:51:52 +00:00
|
|
|
#ifndef PNG_WRITE_APNG_SUPPORTED
|
|
|
|
png_uint_32 apng_set_acTL_dummy (png_structp, png_infop,
|
|
|
|
png_uint_32, png_uint_32);
|
|
|
|
#endif/* PNG_WRITE_APNG_SUPPORTED */
|
2019-02-16 11:18:22 +00:00
|
|
|
|
|
|
|
apng_infop
|
|
|
|
apng_create_info_struct (png_structp pngp)
|
|
|
|
{
|
|
|
|
apng_infop ainfop;
|
|
|
|
(void)pngp;
|
|
|
|
if (( ainfop = calloc(sizeof (apng_info),1) ))
|
|
|
|
{
|
|
|
|
apng_set_write_fn(pngp, ainfop, 0, 0, 0, 0, 0);
|
|
|
|
apng_set_set_acTL_fn(pngp, ainfop, 0);
|
|
|
|
}
|
|
|
|
return ainfop;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
apng_destroy_info_struct (png_structp pngp, apng_infopp ainfopp)
|
|
|
|
{
|
|
|
|
(void)pngp;
|
|
|
|
if (!( pngp && ainfopp ))
|
|
|
|
return;
|
|
|
|
|
|
|
|
free((*ainfopp));
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
apng_seek (png_structp pngp, apng_const_infop ainfop, size_t l)
|
|
|
|
{
|
|
|
|
(*(ainfop->output_seek_fn))(pngp, l);
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t
|
|
|
|
apng_tell (png_structp pngp, apng_const_infop ainfop)
|
|
|
|
{
|
|
|
|
return (*(ainfop->output_tell_fn))(pngp);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef PNG_WRITE_FLUSH_SUPPORTED
|
|
|
|
void
|
|
|
|
apng_flush (png_structp pngp, apng_infop ainfop)
|
|
|
|
{
|
|
|
|
if (ainfop->output_flush_fn)
|
|
|
|
(*(ainfop->output_flush_fn))(pngp);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef PNG_STDIO_SUPPORTED
|
|
|
|
void
|
|
|
|
apng_default_flush (png_structp pngp)
|
|
|
|
{
|
|
|
|
if (!( pngp ))
|
|
|
|
return;
|
|
|
|
|
|
|
|
fflush((png_FILE_p)png_get_io_ptr);
|
|
|
|
}
|
|
|
|
#endif/* PNG_STDIO_SUPPORTED */
|
|
|
|
#endif/* PNG_WRITE_FLUSH_SUPPORTED */
|
|
|
|
|
|
|
|
#ifdef PNG_STDIO_SUPPORTED
|
|
|
|
void
|
|
|
|
apng_default_seek (png_structp pngp, size_t l)
|
|
|
|
{
|
|
|
|
if (!( pngp ))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (fseek((png_FILE_p)png_get_io_ptr(pngp), (long)l, SEEK_SET) == -1)
|
|
|
|
png_error(pngp, "Seek Error");
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t
|
|
|
|
apng_default_tell (png_structp pngp)
|
|
|
|
{
|
|
|
|
long l;
|
|
|
|
|
|
|
|
if (!( pngp ))
|
|
|
|
{
|
|
|
|
png_error(pngp, "Call to apng_default_tell with NULL pngp failed");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (( l = ftell((png_FILE_p)png_get_io_ptr(pngp)) ) == -1)
|
|
|
|
png_error(pngp, "Tell Error");
|
|
|
|
|
|
|
|
return (size_t)l;
|
|
|
|
}
|
|
|
|
#endif/* PNG_STDIO_SUPPORTED */
|
|
|
|
|
|
|
|
void
|
|
|
|
apng_set_write_fn (png_structp pngp, apng_infop ainfop, png_voidp iop,
|
2019-02-19 17:51:52 +00:00
|
|
|
png_rw_ptr write_f, png_flush_ptr flush_f,
|
2019-02-16 11:18:22 +00:00
|
|
|
apng_seek_ptr seek_f, apng_tell_ptr tell_f)
|
|
|
|
{
|
|
|
|
if (!( pngp && ainfop ))
|
|
|
|
return;
|
|
|
|
|
|
|
|
png_set_write_fn(pngp, iop, write_f, flush_f);
|
|
|
|
|
|
|
|
#ifdef PNG_WRITE_FLUSH_SUPPORTED
|
|
|
|
#ifdef PNG_STDIO_SUPPORTED
|
|
|
|
if (!flush_f)
|
|
|
|
ainfop->output_flush_fn = &apng_default_flush;
|
|
|
|
else
|
|
|
|
#endif/* PNG_STDIO_SUPPORTED */
|
|
|
|
ainfop->output_flush_fn = flush_f;
|
|
|
|
#endif/* PNG_WRITE_FLUSH_SUPPORTED */
|
|
|
|
#ifdef PNG_STDIO_SUPPORTED
|
|
|
|
if (!seek_f)
|
|
|
|
ainfop->output_seek_fn = &apng_default_seek;
|
|
|
|
else
|
|
|
|
#endif/* PNG_STDIO_SUPPORTED */
|
|
|
|
ainfop->output_seek_fn = seek_f;
|
|
|
|
#ifdef PNG_STDIO_SUPPORTED
|
|
|
|
if (!seek_f)
|
|
|
|
ainfop->output_tell_fn = apng_default_tell;
|
|
|
|
else
|
|
|
|
#endif/* PNG_STDIO_SUPPORTED */
|
|
|
|
ainfop->output_tell_fn = tell_f;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
apng_write_IEND (png_structp pngp)
|
|
|
|
{
|
|
|
|
png_byte chunkc[] = "IEND";
|
|
|
|
png_write_chunk(pngp, chunkc, 0, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
apng_write_acTL (png_structp pngp, png_uint_32 frames, png_uint_32 plays)
|
|
|
|
{
|
|
|
|
png_byte chunkc[] = "acTL";
|
|
|
|
png_byte buf[8];
|
|
|
|
png_save_uint_32(buf, frames);
|
|
|
|
png_save_uint_32(buf + 4, plays);
|
|
|
|
png_write_chunk(pngp, chunkc, buf, 8);
|
|
|
|
}
|
|
|
|
|
|
|
|
png_uint_32
|
|
|
|
apng_set_acTL (png_structp pngp, png_infop infop, apng_infop ainfop,
|
|
|
|
png_uint_32 frames, png_uint_32 plays)
|
|
|
|
{
|
|
|
|
(void)pngp;
|
|
|
|
(void)infop;
|
|
|
|
if (!( pngp && infop && ainfop ))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
ainfop->num_frames = frames;
|
|
|
|
ainfop->num_plays = plays;
|
|
|
|
|
2019-02-19 17:51:52 +00:00
|
|
|
ainfop->valid |= APNG_INFO_acTL;
|
2019-02-16 11:18:22 +00:00
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
apng_write_info_before_PLTE (png_structp pngp, png_infop infop,
|
|
|
|
apng_infop ainfop)
|
|
|
|
{
|
|
|
|
if (!( pngp && infop && ainfop ))
|
|
|
|
return;
|
|
|
|
|
|
|
|
png_write_info_before_PLTE(pngp, infop);
|
|
|
|
|
2019-02-19 17:51:52 +00:00
|
|
|
if (( ainfop->valid & APNG_INFO_acTL )&&!( ainfop->mode & APNG_WROTE_acTL ))
|
2019-02-16 11:18:22 +00:00
|
|
|
{
|
|
|
|
ainfop->start_acTL = apng_tell(pngp, ainfop);
|
|
|
|
|
|
|
|
apng_write_acTL(pngp, 0, 0);
|
|
|
|
/* modified for runtime dynamic linking */
|
|
|
|
(*(ainfop->set_acTL_fn))(pngp, infop, PNG_UINT_31_MAX, 0);
|
|
|
|
|
|
|
|
ainfop->mode |= APNG_WROTE_acTL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
apng_write_info (png_structp pngp, png_infop infop,
|
|
|
|
apng_infop ainfop)
|
|
|
|
{
|
|
|
|
apng_write_info_before_PLTE(pngp, infop, ainfop);
|
|
|
|
png_write_info(pngp, infop);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
apng_write_end (png_structp pngp, png_infop infop, apng_infop ainfop)
|
|
|
|
{
|
|
|
|
(void)infop;
|
|
|
|
apng_write_IEND(pngp);
|
|
|
|
apng_seek(pngp, ainfop, ainfop->start_acTL);
|
|
|
|
apng_write_acTL(pngp, ainfop->num_frames, ainfop->num_plays);
|
|
|
|
|
|
|
|
#ifdef PNG_WRITE_FLUSH_SUPPORTED
|
|
|
|
#ifdef PNG_WRITE_FLUSH_AFTER_IEND_SUPPORTED
|
|
|
|
apng_flush(pngp, infop);
|
|
|
|
#endif/* PNG_WRITE_FLUSH_SUPPORTED */
|
|
|
|
#endif/* PNG_WRITE_FLUSH_AFTER_IEND_SUPPORTED */
|
|
|
|
}
|
|
|
|
|
2019-02-19 17:51:52 +00:00
|
|
|
#ifndef PNG_WRITE_APNG_SUPPORTED
|
|
|
|
png_uint_32
|
|
|
|
apng_set_acTL_dummy (png_structp pngp, png_infop infop,
|
|
|
|
png_uint_32 frames, png_uint_32 plays)
|
|
|
|
{
|
|
|
|
(void)pngp;
|
|
|
|
(void)infop;
|
|
|
|
(void)frames;
|
|
|
|
(void)plays;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif/* PNG_WRITE_APNG_SUPPORTED */
|
|
|
|
|
2019-02-16 11:18:22 +00:00
|
|
|
/* Dynamic runtime linking capable! (Hopefully.) */
|
|
|
|
void
|
|
|
|
apng_set_set_acTL_fn (png_structp pngp, apng_infop ainfop,
|
|
|
|
apng_set_acTL_ptr set_acTL_f)
|
|
|
|
{
|
|
|
|
(void)pngp;
|
|
|
|
if (!ainfop->set_acTL_fn)
|
2019-02-19 17:51:52 +00:00
|
|
|
#ifndef PNG_WRITE_APNG_SUPPORTED
|
|
|
|
ainfop->set_acTL_fn = &apng_set_acTL_dummy;
|
|
|
|
#else
|
2019-02-16 11:18:22 +00:00
|
|
|
ainfop->set_acTL_fn = &png_set_acTL;
|
2019-02-19 17:51:52 +00:00
|
|
|
#endif/* PNG_WRITE_APNG_SUPPORTED */
|
2019-02-16 11:18:22 +00:00
|
|
|
else
|
|
|
|
ainfop->set_acTL_fn = set_acTL_f;
|
|
|
|
}
|