19890ff83SToomas Soome /*
29890ff83SToomas Soome * pnglite.c - pnglite library
39890ff83SToomas Soome * For conditions of distribution and use, see copyright notice in pnglite.h
49890ff83SToomas Soome */
59890ff83SToomas Soome
69890ff83SToomas Soome #ifdef _STANDALONE
79890ff83SToomas Soome #include <sys/cdefs.h>
89890ff83SToomas Soome #include <stand.h>
99890ff83SToomas Soome #else
109890ff83SToomas Soome #include <stdio.h>
119890ff83SToomas Soome #include <stdlib.h>
129890ff83SToomas Soome #include <sys/types.h>
139890ff83SToomas Soome #include <sys/stat.h>
149890ff83SToomas Soome #include <fcntl.h>
159890ff83SToomas Soome #endif
169890ff83SToomas Soome #include <zlib.h>
179890ff83SToomas Soome #include "pnglite.h"
189890ff83SToomas Soome
199890ff83SToomas Soome #ifndef abs
209890ff83SToomas Soome #define abs(x) ((x) < 0? -(x):(x))
219890ff83SToomas Soome #endif
229890ff83SToomas Soome
239890ff83SToomas Soome #define PNG_32b(b, s) ((uint32_t)(b) << (s))
249890ff83SToomas Soome #define PNG_U32(b1, b2, b3, b4) \
259890ff83SToomas Soome (PNG_32b(b1, 24) | PNG_32b(b2, 16) | PNG_32b(b3, 8) | PNG_32b(b4, 0))
269890ff83SToomas Soome
279890ff83SToomas Soome #define png_IDAT PNG_U32(73, 68, 65, 84)
289890ff83SToomas Soome #define png_IEND PNG_U32(73, 69, 78, 68)
299890ff83SToomas Soome
309890ff83SToomas Soome static ssize_t
file_read(png_t * png,void * out,size_t size,size_t numel)319890ff83SToomas Soome file_read(png_t *png, void *out, size_t size, size_t numel)
329890ff83SToomas Soome {
339890ff83SToomas Soome ssize_t result;
349890ff83SToomas Soome off_t offset = (off_t)(size * numel);
359890ff83SToomas Soome
369890ff83SToomas Soome if (offset < 0)
379890ff83SToomas Soome return (PNG_FILE_ERROR);
389890ff83SToomas Soome
399890ff83SToomas Soome if (!out) {
409890ff83SToomas Soome result = lseek(png->fd, offset, SEEK_CUR);
419890ff83SToomas Soome } else {
429890ff83SToomas Soome result = read(png->fd, out, size * numel);
439890ff83SToomas Soome }
449890ff83SToomas Soome
459890ff83SToomas Soome return (result);
469890ff83SToomas Soome }
479890ff83SToomas Soome
489890ff83SToomas Soome static int
file_read_ul(png_t * png,unsigned * out)499890ff83SToomas Soome file_read_ul(png_t *png, unsigned *out)
509890ff83SToomas Soome {
519890ff83SToomas Soome uint8_t buf[4];
529890ff83SToomas Soome
539890ff83SToomas Soome if (file_read(png, buf, 1, 4) != 4)
549890ff83SToomas Soome return (PNG_FILE_ERROR);
559890ff83SToomas Soome
569890ff83SToomas Soome *out = (buf[0]<<24) | (buf[1]<<16) | (buf[2]<<8) | buf[3];
579890ff83SToomas Soome
589890ff83SToomas Soome return (PNG_NO_ERROR);
599890ff83SToomas Soome }
609890ff83SToomas Soome
619890ff83SToomas Soome static unsigned
get_ul(uint8_t * buf)629890ff83SToomas Soome get_ul(uint8_t *buf)
639890ff83SToomas Soome {
649890ff83SToomas Soome unsigned result;
659890ff83SToomas Soome uint8_t foo[4];
669890ff83SToomas Soome
679890ff83SToomas Soome memcpy(foo, buf, 4);
689890ff83SToomas Soome
699890ff83SToomas Soome result = (foo[0]<<24) | (foo[1]<<16) | (foo[2]<<8) | foo[3];
709890ff83SToomas Soome
719890ff83SToomas Soome return (result);
729890ff83SToomas Soome }
739890ff83SToomas Soome
749890ff83SToomas Soome static int
png_get_bpp(png_t * png)759890ff83SToomas Soome png_get_bpp(png_t *png)
769890ff83SToomas Soome {
779890ff83SToomas Soome int bpp;
789890ff83SToomas Soome
799890ff83SToomas Soome switch (png->color_type) {
809890ff83SToomas Soome case PNG_GREYSCALE:
819890ff83SToomas Soome bpp = 1; break;
829890ff83SToomas Soome case PNG_TRUECOLOR:
839890ff83SToomas Soome bpp = 3; break;
849890ff83SToomas Soome case PNG_INDEXED:
859890ff83SToomas Soome bpp = 1; break;
869890ff83SToomas Soome case PNG_GREYSCALE_ALPHA:
879890ff83SToomas Soome bpp = 2; break;
889890ff83SToomas Soome case PNG_TRUECOLOR_ALPHA:
899890ff83SToomas Soome bpp = 4; break;
909890ff83SToomas Soome default:
919890ff83SToomas Soome return (PNG_FILE_ERROR);
929890ff83SToomas Soome }
939890ff83SToomas Soome
949890ff83SToomas Soome bpp *= png->depth / 8;
959890ff83SToomas Soome
969890ff83SToomas Soome return (bpp);
979890ff83SToomas Soome }
989890ff83SToomas Soome
999890ff83SToomas Soome static int
png_read_ihdr(png_t * png)1009890ff83SToomas Soome png_read_ihdr(png_t *png)
1019890ff83SToomas Soome {
102*f7e4f33fSToomas Soome unsigned length = 0;
1039890ff83SToomas Soome unsigned orig_crc;
1049890ff83SToomas Soome unsigned calc_crc;
1059890ff83SToomas Soome uint8_t ihdr[13+4]; /* length should be 13, make room for type (IHDR) */
1069890ff83SToomas Soome
107*f7e4f33fSToomas Soome if (file_read_ul(png, &length) != PNG_NO_ERROR)
108*f7e4f33fSToomas Soome return (PNG_FILE_ERROR);
1099890ff83SToomas Soome
1109890ff83SToomas Soome if (length != 13)
1119890ff83SToomas Soome return (PNG_CRC_ERROR);
1129890ff83SToomas Soome
1139890ff83SToomas Soome if (file_read(png, ihdr, 1, 13+4) != 13+4)
1149890ff83SToomas Soome return (PNG_EOF_ERROR);
1159890ff83SToomas Soome
116*f7e4f33fSToomas Soome if (file_read_ul(png, &orig_crc) != PNG_NO_ERROR)
117*f7e4f33fSToomas Soome return (PNG_FILE_ERROR);
1189890ff83SToomas Soome
1199890ff83SToomas Soome calc_crc = crc32(0L, Z_NULL, 0);
1209890ff83SToomas Soome calc_crc = crc32(calc_crc, ihdr, 13+4);
1219890ff83SToomas Soome
1229890ff83SToomas Soome if (orig_crc != calc_crc) {
1239890ff83SToomas Soome return (PNG_CRC_ERROR);
1249890ff83SToomas Soome }
1259890ff83SToomas Soome
1269890ff83SToomas Soome png->width = get_ul(ihdr+4);
1279890ff83SToomas Soome png->height = get_ul(ihdr+8);
1289890ff83SToomas Soome png->depth = ihdr[12];
1299890ff83SToomas Soome png->color_type = ihdr[13];
1309890ff83SToomas Soome png->compression_method = ihdr[14];
1319890ff83SToomas Soome png->filter_method = ihdr[15];
1329890ff83SToomas Soome png->interlace_method = ihdr[16];
1339890ff83SToomas Soome
1349890ff83SToomas Soome if (png->color_type == PNG_INDEXED)
1359890ff83SToomas Soome return (PNG_NOT_SUPPORTED);
1369890ff83SToomas Soome
1379890ff83SToomas Soome if (png->depth != 8 && png->depth != 16)
1389890ff83SToomas Soome return (PNG_NOT_SUPPORTED);
1399890ff83SToomas Soome
1409890ff83SToomas Soome if (png->interlace_method)
1419890ff83SToomas Soome return (PNG_NOT_SUPPORTED);
1429890ff83SToomas Soome
1439890ff83SToomas Soome return (PNG_NO_ERROR);
1449890ff83SToomas Soome }
1459890ff83SToomas Soome
1469890ff83SToomas Soome void
png_print_info(png_t * png)1479890ff83SToomas Soome png_print_info(png_t *png)
1489890ff83SToomas Soome {
1499890ff83SToomas Soome printf("PNG INFO:\n");
1509890ff83SToomas Soome printf("\twidth:\t\t%d\n", png->width);
1519890ff83SToomas Soome printf("\theight:\t\t%d\n", png->height);
1529890ff83SToomas Soome printf("\tdepth:\t\t%d\n", png->depth);
1539890ff83SToomas Soome printf("\tcolor:\t\t");
1549890ff83SToomas Soome
1559890ff83SToomas Soome switch (png->color_type) {
1569890ff83SToomas Soome case PNG_GREYSCALE:
1579890ff83SToomas Soome printf("greyscale\n"); break;
1589890ff83SToomas Soome case PNG_TRUECOLOR:
1599890ff83SToomas Soome printf("truecolor\n"); break;
1609890ff83SToomas Soome case PNG_INDEXED:
1619890ff83SToomas Soome printf("palette\n"); break;
1629890ff83SToomas Soome case PNG_GREYSCALE_ALPHA:
1639890ff83SToomas Soome printf("greyscale with alpha\n"); break;
1649890ff83SToomas Soome case PNG_TRUECOLOR_ALPHA:
1659890ff83SToomas Soome printf("truecolor with alpha\n"); break;
1669890ff83SToomas Soome default:
1679890ff83SToomas Soome printf("unknown, this is not good\n"); break;
1689890ff83SToomas Soome }
1699890ff83SToomas Soome
1709890ff83SToomas Soome printf("\tcompression:\t%s\n",
1719890ff83SToomas Soome png->compression_method?
1729890ff83SToomas Soome "unknown, this is not good":"inflate/deflate");
1739890ff83SToomas Soome printf("\tfilter:\t\t%s\n",
1749890ff83SToomas Soome png->filter_method? "unknown, this is not good":"adaptive");
1759890ff83SToomas Soome printf("\tinterlace:\t%s\n",
1769890ff83SToomas Soome png->interlace_method? "interlace":"no interlace");
1779890ff83SToomas Soome }
1789890ff83SToomas Soome
1799890ff83SToomas Soome int
png_open(png_t * png,const char * filename)1809890ff83SToomas Soome png_open(png_t *png, const char *filename)
1819890ff83SToomas Soome {
1829890ff83SToomas Soome char header[8];
1839890ff83SToomas Soome int result;
1849890ff83SToomas Soome
1859890ff83SToomas Soome png->image = NULL;
1869890ff83SToomas Soome png->fd = open(filename, O_RDONLY);
1879890ff83SToomas Soome if (png->fd == -1)
1889890ff83SToomas Soome return (PNG_FILE_ERROR);
1899890ff83SToomas Soome
1909890ff83SToomas Soome if (file_read(png, header, 1, 8) != 8) {
1919890ff83SToomas Soome result = PNG_EOF_ERROR;
1929890ff83SToomas Soome goto done;
1939890ff83SToomas Soome }
1949890ff83SToomas Soome
1959890ff83SToomas Soome if (memcmp(header, "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A", 8) != 0) {
1969890ff83SToomas Soome result = PNG_HEADER_ERROR;
1979890ff83SToomas Soome goto done;
1989890ff83SToomas Soome }
1999890ff83SToomas Soome
2009890ff83SToomas Soome result = png_read_ihdr(png);
2019890ff83SToomas Soome if (result == PNG_NO_ERROR) {
2029890ff83SToomas Soome result = png_get_bpp(png);
2039890ff83SToomas Soome if (result > 0) {
2049890ff83SToomas Soome png->bpp = (uint8_t)result;
2059890ff83SToomas Soome result = PNG_NO_ERROR;
2069890ff83SToomas Soome }
2079890ff83SToomas Soome }
2089890ff83SToomas Soome
2099890ff83SToomas Soome done:
2109890ff83SToomas Soome if (result == PNG_NO_ERROR) {
2119890ff83SToomas Soome uint64_t size = png->width * png->height * png->bpp;
2129890ff83SToomas Soome
2139890ff83SToomas Soome if (size < UINT_MAX)
2149890ff83SToomas Soome png->image = malloc(size);
2159890ff83SToomas Soome if (png->image == NULL)
2169890ff83SToomas Soome result = PNG_MEMORY_ERROR;
2179890ff83SToomas Soome }
2189890ff83SToomas Soome
2199890ff83SToomas Soome if (result == PNG_NO_ERROR)
2209890ff83SToomas Soome result = png_get_data(png, png->image);
2219890ff83SToomas Soome
2229890ff83SToomas Soome if (result != PNG_NO_ERROR) {
2239890ff83SToomas Soome free(png->image);
224*f7e4f33fSToomas Soome (void) close(png->fd);
2259890ff83SToomas Soome png->fd = -1;
2269890ff83SToomas Soome return (result);
2279890ff83SToomas Soome }
2289890ff83SToomas Soome
2299890ff83SToomas Soome return (result);
2309890ff83SToomas Soome }
2319890ff83SToomas Soome
2329890ff83SToomas Soome int
png_close(png_t * png)2339890ff83SToomas Soome png_close(png_t *png)
2349890ff83SToomas Soome {
235*f7e4f33fSToomas Soome (void) close(png->fd);
2369890ff83SToomas Soome png->fd = -1;
2379890ff83SToomas Soome free(png->image);
2389890ff83SToomas Soome png->image = NULL;
2399890ff83SToomas Soome
2409890ff83SToomas Soome return (PNG_NO_ERROR);
2419890ff83SToomas Soome }
2429890ff83SToomas Soome
2439890ff83SToomas Soome static int
png_init_inflate(png_t * png)2449890ff83SToomas Soome png_init_inflate(png_t *png)
2459890ff83SToomas Soome {
2469890ff83SToomas Soome z_stream *stream;
2479890ff83SToomas Soome png->zs = calloc(1, sizeof (z_stream));
2489890ff83SToomas Soome
2499890ff83SToomas Soome stream = png->zs;
2509890ff83SToomas Soome
2519890ff83SToomas Soome if (!stream)
2529890ff83SToomas Soome return (PNG_MEMORY_ERROR);
2539890ff83SToomas Soome
2549890ff83SToomas Soome if (inflateInit(stream) != Z_OK) {
2559890ff83SToomas Soome free(png->zs);
2569890ff83SToomas Soome png->zs = NULL;
2579890ff83SToomas Soome return (PNG_ZLIB_ERROR);
2589890ff83SToomas Soome }
2599890ff83SToomas Soome
2609890ff83SToomas Soome stream->next_out = png->png_data;
2619890ff83SToomas Soome stream->avail_out = png->png_datalen;
2629890ff83SToomas Soome
2639890ff83SToomas Soome return (PNG_NO_ERROR);
2649890ff83SToomas Soome }
2659890ff83SToomas Soome
2669890ff83SToomas Soome static int
png_end_inflate(png_t * png)2679890ff83SToomas Soome png_end_inflate(png_t *png)
2689890ff83SToomas Soome {
2699890ff83SToomas Soome z_stream *stream = png->zs;
2709890ff83SToomas Soome int rc = PNG_NO_ERROR;
2719890ff83SToomas Soome
2729890ff83SToomas Soome if (!stream)
2739890ff83SToomas Soome return (PNG_MEMORY_ERROR);
2749890ff83SToomas Soome
2759890ff83SToomas Soome if (inflateEnd(stream) != Z_OK) {
2769890ff83SToomas Soome printf("ZLIB says: %s\n", stream->msg);
2779890ff83SToomas Soome rc = PNG_ZLIB_ERROR;
2789890ff83SToomas Soome }
2799890ff83SToomas Soome
2809890ff83SToomas Soome free(png->zs);
2819890ff83SToomas Soome png->zs = NULL;
2829890ff83SToomas Soome
2839890ff83SToomas Soome return (rc);
2849890ff83SToomas Soome }
2859890ff83SToomas Soome
2869890ff83SToomas Soome static int
png_inflate(png_t * png,uint8_t * data,int len)2879890ff83SToomas Soome png_inflate(png_t *png, uint8_t *data, int len)
2889890ff83SToomas Soome {
2899890ff83SToomas Soome int result;
2909890ff83SToomas Soome z_stream *stream = png->zs;
2919890ff83SToomas Soome
2929890ff83SToomas Soome if (!stream)
2939890ff83SToomas Soome return (PNG_MEMORY_ERROR);
2949890ff83SToomas Soome
2959890ff83SToomas Soome stream->next_in = data;
2969890ff83SToomas Soome stream->avail_in = len;
2979890ff83SToomas Soome
2989890ff83SToomas Soome result = inflate(stream, Z_SYNC_FLUSH);
2999890ff83SToomas Soome
3009890ff83SToomas Soome if (result != Z_STREAM_END && result != Z_OK) {
3019890ff83SToomas Soome printf("%s\n", stream->msg);
3029890ff83SToomas Soome return (PNG_ZLIB_ERROR);
3039890ff83SToomas Soome }
3049890ff83SToomas Soome
3059890ff83SToomas Soome if (stream->avail_in != 0)
3069890ff83SToomas Soome return (PNG_ZLIB_ERROR);
3079890ff83SToomas Soome
3089890ff83SToomas Soome return (PNG_NO_ERROR);
3099890ff83SToomas Soome }
3109890ff83SToomas Soome
3119890ff83SToomas Soome static int
png_read_idat(png_t * png,unsigned length)3129890ff83SToomas Soome png_read_idat(png_t *png, unsigned length)
3139890ff83SToomas Soome {
3149890ff83SToomas Soome unsigned orig_crc;
3159890ff83SToomas Soome unsigned calc_crc;
3169890ff83SToomas Soome ssize_t len = length;
3179890ff83SToomas Soome
3189890ff83SToomas Soome if (!png->readbuf || png->readbuflen < length) {
3199890ff83SToomas Soome png->readbuf = realloc(png->readbuf, length);
3209890ff83SToomas Soome png->readbuflen = length;
3219890ff83SToomas Soome }
3229890ff83SToomas Soome
3239890ff83SToomas Soome if (!png->readbuf)
3249890ff83SToomas Soome return (PNG_MEMORY_ERROR);
3259890ff83SToomas Soome
3269890ff83SToomas Soome if (file_read(png, png->readbuf, 1, length) != len)
3279890ff83SToomas Soome return (PNG_FILE_ERROR);
3289890ff83SToomas Soome
3299890ff83SToomas Soome calc_crc = crc32(0L, Z_NULL, 0);
3309890ff83SToomas Soome calc_crc = crc32(calc_crc, (uint8_t *)"IDAT", 4);
3319890ff83SToomas Soome calc_crc = crc32(calc_crc, (uint8_t *)png->readbuf, length);
3329890ff83SToomas Soome
333*f7e4f33fSToomas Soome if (file_read_ul(png, &orig_crc) != PNG_NO_ERROR)
334*f7e4f33fSToomas Soome return (PNG_FILE_ERROR);
3359890ff83SToomas Soome
3369890ff83SToomas Soome if (orig_crc != calc_crc)
3379890ff83SToomas Soome return (PNG_CRC_ERROR);
3389890ff83SToomas Soome
3399890ff83SToomas Soome return (png_inflate(png, png->readbuf, length));
3409890ff83SToomas Soome }
3419890ff83SToomas Soome
3429890ff83SToomas Soome static int
png_process_chunk(png_t * png)3439890ff83SToomas Soome png_process_chunk(png_t *png)
3449890ff83SToomas Soome {
3459890ff83SToomas Soome int result = PNG_NO_ERROR;
3469890ff83SToomas Soome unsigned type;
3479890ff83SToomas Soome unsigned length;
3489890ff83SToomas Soome
349*f7e4f33fSToomas Soome if (file_read_ul(png, &length) != PNG_NO_ERROR)
350*f7e4f33fSToomas Soome return (PNG_FILE_ERROR);
3519890ff83SToomas Soome
352*f7e4f33fSToomas Soome if (file_read_ul(png, &type) != PNG_NO_ERROR)
3539890ff83SToomas Soome return (PNG_FILE_ERROR);
3549890ff83SToomas Soome
3559890ff83SToomas Soome /*
3569890ff83SToomas Soome * if we found an idat, all other idats should be followed with no
3579890ff83SToomas Soome * other chunks in between
3589890ff83SToomas Soome */
3599890ff83SToomas Soome if (type == png_IDAT) {
3609890ff83SToomas Soome if (!png->png_data) { /* first IDAT */
3619890ff83SToomas Soome png->png_datalen = png->width * png->height *
3629890ff83SToomas Soome png->bpp + png->height;
3639890ff83SToomas Soome png->png_data = malloc(png->png_datalen);
3649890ff83SToomas Soome }
3659890ff83SToomas Soome
3669890ff83SToomas Soome if (!png->png_data)
3679890ff83SToomas Soome return (PNG_MEMORY_ERROR);
3689890ff83SToomas Soome
3699890ff83SToomas Soome if (!png->zs) {
3709890ff83SToomas Soome result = png_init_inflate(png);
3719890ff83SToomas Soome if (result != PNG_NO_ERROR)
3729890ff83SToomas Soome return (result);
3739890ff83SToomas Soome }
3749890ff83SToomas Soome
3759890ff83SToomas Soome return (png_read_idat(png, length));
3769890ff83SToomas Soome } else if (type == png_IEND)
3779890ff83SToomas Soome return (PNG_DONE);
3789890ff83SToomas Soome else
379*f7e4f33fSToomas Soome (void) file_read(png, 0, 1, length + 4); /* unknown chunk */
3809890ff83SToomas Soome
3819890ff83SToomas Soome return (result);
3829890ff83SToomas Soome }
3839890ff83SToomas Soome
3849890ff83SToomas Soome static void
png_filter_sub(unsigned stride,uint8_t * in,uint8_t * out,unsigned len)3859890ff83SToomas Soome png_filter_sub(unsigned stride, uint8_t *in, uint8_t *out, unsigned len)
3869890ff83SToomas Soome {
3879890ff83SToomas Soome unsigned i;
3889890ff83SToomas Soome uint8_t a = 0;
3899890ff83SToomas Soome
3909890ff83SToomas Soome for (i = 0; i < len; i++) {
3919890ff83SToomas Soome if (i >= stride)
3929890ff83SToomas Soome a = out[i - stride];
3939890ff83SToomas Soome
3949890ff83SToomas Soome out[i] = in[i] + a;
3959890ff83SToomas Soome }
3969890ff83SToomas Soome }
3979890ff83SToomas Soome
3989890ff83SToomas Soome static void
png_filter_up(unsigned stride __unused,uint8_t * in,uint8_t * out,uint8_t * prev_line,unsigned len)3999890ff83SToomas Soome png_filter_up(unsigned stride __unused, uint8_t *in, uint8_t *out,
4009890ff83SToomas Soome uint8_t *prev_line, unsigned len)
4019890ff83SToomas Soome {
4029890ff83SToomas Soome unsigned i;
4039890ff83SToomas Soome
4049890ff83SToomas Soome if (prev_line) {
4059890ff83SToomas Soome for (i = 0; i < len; i++)
4069890ff83SToomas Soome out[i] = in[i] + prev_line[i];
4079890ff83SToomas Soome } else
4089890ff83SToomas Soome memcpy(out, in, len);
4099890ff83SToomas Soome }
4109890ff83SToomas Soome
4119890ff83SToomas Soome static void
png_filter_average(unsigned stride,uint8_t * in,uint8_t * out,uint8_t * prev_line,unsigned len)4129890ff83SToomas Soome png_filter_average(unsigned stride, uint8_t *in, uint8_t *out,
4139890ff83SToomas Soome uint8_t *prev_line, unsigned len)
4149890ff83SToomas Soome {
4159890ff83SToomas Soome unsigned int i;
4169890ff83SToomas Soome uint8_t a = 0;
4179890ff83SToomas Soome uint8_t b = 0;
4189890ff83SToomas Soome unsigned int sum = 0;
4199890ff83SToomas Soome
4209890ff83SToomas Soome for (i = 0; i < len; i++) {
4219890ff83SToomas Soome if (prev_line)
4229890ff83SToomas Soome b = prev_line[i];
4239890ff83SToomas Soome
4249890ff83SToomas Soome if (i >= stride)
4259890ff83SToomas Soome a = out[i - stride];
4269890ff83SToomas Soome
4279890ff83SToomas Soome sum = a;
4289890ff83SToomas Soome sum += b;
4299890ff83SToomas Soome
4309890ff83SToomas Soome out[i] = in[i] + sum/2;
4319890ff83SToomas Soome }
4329890ff83SToomas Soome }
4339890ff83SToomas Soome
4349890ff83SToomas Soome static uint8_t
png_paeth(uint8_t a,uint8_t b,uint8_t c)4359890ff83SToomas Soome png_paeth(uint8_t a, uint8_t b, uint8_t c)
4369890ff83SToomas Soome {
4379890ff83SToomas Soome int p = (int)a + b - c;
4389890ff83SToomas Soome int pa = abs(p - a);
4399890ff83SToomas Soome int pb = abs(p - b);
4409890ff83SToomas Soome int pc = abs(p - c);
4419890ff83SToomas Soome
4429890ff83SToomas Soome int pr;
4439890ff83SToomas Soome
4449890ff83SToomas Soome if (pa <= pb && pa <= pc)
4459890ff83SToomas Soome pr = a;
4469890ff83SToomas Soome else if (pb <= pc)
4479890ff83SToomas Soome pr = b;
4489890ff83SToomas Soome else
4499890ff83SToomas Soome pr = c;
4509890ff83SToomas Soome
4519890ff83SToomas Soome return (pr);
4529890ff83SToomas Soome }
4539890ff83SToomas Soome
4549890ff83SToomas Soome static void
png_filter_paeth(unsigned stride,uint8_t * in,uint8_t * out,uint8_t * prev_line,unsigned len)4559890ff83SToomas Soome png_filter_paeth(unsigned stride, uint8_t *in, uint8_t *out, uint8_t *prev_line,
4569890ff83SToomas Soome unsigned len)
4579890ff83SToomas Soome {
4589890ff83SToomas Soome unsigned i;
4599890ff83SToomas Soome uint8_t a;
4609890ff83SToomas Soome uint8_t b;
4619890ff83SToomas Soome uint8_t c;
4629890ff83SToomas Soome
4639890ff83SToomas Soome for (i = 0; i < len; i++) {
4649890ff83SToomas Soome if (prev_line && i >= stride) {
4659890ff83SToomas Soome a = out[i - stride];
4669890ff83SToomas Soome b = prev_line[i];
4679890ff83SToomas Soome c = prev_line[i - stride];
4689890ff83SToomas Soome } else {
4699890ff83SToomas Soome if (prev_line)
4709890ff83SToomas Soome b = prev_line[i];
4719890ff83SToomas Soome else
4729890ff83SToomas Soome b = 0;
4739890ff83SToomas Soome
4749890ff83SToomas Soome if (i >= stride)
4759890ff83SToomas Soome a = out[i - stride];
4769890ff83SToomas Soome else
4779890ff83SToomas Soome a = 0;
4789890ff83SToomas Soome
4799890ff83SToomas Soome c = 0;
4809890ff83SToomas Soome }
4819890ff83SToomas Soome
4829890ff83SToomas Soome out[i] = in[i] + png_paeth(a, b, c);
4839890ff83SToomas Soome }
4849890ff83SToomas Soome }
4859890ff83SToomas Soome
4869890ff83SToomas Soome static int
png_unfilter(png_t * png,uint8_t * data)4879890ff83SToomas Soome png_unfilter(png_t *png, uint8_t *data)
4889890ff83SToomas Soome {
4899890ff83SToomas Soome unsigned i;
4909890ff83SToomas Soome unsigned pos = 0;
4919890ff83SToomas Soome unsigned outpos = 0;
4929890ff83SToomas Soome uint8_t *filtered = png->png_data;
4939890ff83SToomas Soome unsigned stride = png->bpp;
4949890ff83SToomas Soome
4959890ff83SToomas Soome while (pos < png->png_datalen) {
4969890ff83SToomas Soome uint8_t filter = filtered[pos];
4979890ff83SToomas Soome
4989890ff83SToomas Soome pos++;
4999890ff83SToomas Soome
5009890ff83SToomas Soome if (png->depth == 16) {
5019890ff83SToomas Soome for (i = 0; i < png->width * stride; i += 2) {
5029890ff83SToomas Soome *(short *)(filtered+pos+i) =
5039890ff83SToomas Soome (filtered[pos+i] << 8) | filtered[pos+i+1];
5049890ff83SToomas Soome }
5059890ff83SToomas Soome }
5069890ff83SToomas Soome
5079890ff83SToomas Soome switch (filter) {
5089890ff83SToomas Soome case 0: /* none */
5099890ff83SToomas Soome memcpy(data+outpos, filtered+pos, png->width * stride);
5109890ff83SToomas Soome break;
5119890ff83SToomas Soome case 1: /* sub */
5129890ff83SToomas Soome png_filter_sub(stride, filtered+pos, data+outpos,
5139890ff83SToomas Soome png->width * stride);
5149890ff83SToomas Soome break;
5159890ff83SToomas Soome case 2: /* up */
5169890ff83SToomas Soome if (outpos) {
5179890ff83SToomas Soome png_filter_up(stride, filtered+pos, data+outpos,
5189890ff83SToomas Soome data + outpos - (png->width*stride),
5199890ff83SToomas Soome png->width*stride);
5209890ff83SToomas Soome } else {
5219890ff83SToomas Soome png_filter_up(stride, filtered+pos, data+outpos,
5229890ff83SToomas Soome 0, png->width*stride);
5239890ff83SToomas Soome }
5249890ff83SToomas Soome break;
5259890ff83SToomas Soome case 3: /* average */
5269890ff83SToomas Soome if (outpos) {
5279890ff83SToomas Soome png_filter_average(stride, filtered+pos,
5289890ff83SToomas Soome data+outpos,
5299890ff83SToomas Soome data + outpos - (png->width*stride),
5309890ff83SToomas Soome png->width*stride);
5319890ff83SToomas Soome } else {
5329890ff83SToomas Soome png_filter_average(stride, filtered+pos,
5339890ff83SToomas Soome data+outpos, 0, png->width*stride);
5349890ff83SToomas Soome }
5359890ff83SToomas Soome break;
5369890ff83SToomas Soome case 4: /* paeth */
5379890ff83SToomas Soome if (outpos) {
5389890ff83SToomas Soome png_filter_paeth(stride, filtered+pos,
5399890ff83SToomas Soome data+outpos,
5409890ff83SToomas Soome data + outpos - (png->width*stride),
5419890ff83SToomas Soome png->width*stride);
5429890ff83SToomas Soome } else {
5439890ff83SToomas Soome png_filter_paeth(stride, filtered+pos,
5449890ff83SToomas Soome data+outpos, 0, png->width*stride);
5459890ff83SToomas Soome }
5469890ff83SToomas Soome break;
5479890ff83SToomas Soome default:
5489890ff83SToomas Soome return (PNG_UNKNOWN_FILTER);
5499890ff83SToomas Soome }
5509890ff83SToomas Soome
5519890ff83SToomas Soome outpos += png->width * stride;
5529890ff83SToomas Soome pos += png->width * stride;
5539890ff83SToomas Soome }
5549890ff83SToomas Soome
5559890ff83SToomas Soome return (PNG_NO_ERROR);
5569890ff83SToomas Soome }
5579890ff83SToomas Soome
5589890ff83SToomas Soome int
png_get_data(png_t * png,uint8_t * data)5599890ff83SToomas Soome png_get_data(png_t *png, uint8_t *data)
5609890ff83SToomas Soome {
5619890ff83SToomas Soome int result = PNG_NO_ERROR;
5629890ff83SToomas Soome
5639890ff83SToomas Soome png->zs = NULL;
5649890ff83SToomas Soome png->png_datalen = 0;
5659890ff83SToomas Soome png->png_data = NULL;
5669890ff83SToomas Soome png->readbuf = NULL;
5679890ff83SToomas Soome png->readbuflen = 0;
5689890ff83SToomas Soome
5699890ff83SToomas Soome while (result == PNG_NO_ERROR)
5709890ff83SToomas Soome result = png_process_chunk(png);
5719890ff83SToomas Soome
5729890ff83SToomas Soome if (png->readbuf) {
5739890ff83SToomas Soome free(png->readbuf);
5749890ff83SToomas Soome png->readbuflen = 0;
5759890ff83SToomas Soome }
5769890ff83SToomas Soome if (png->zs)
577*f7e4f33fSToomas Soome (void) png_end_inflate(png);
5789890ff83SToomas Soome
5799890ff83SToomas Soome if (result != PNG_DONE) {
5809890ff83SToomas Soome free(png->png_data);
5819890ff83SToomas Soome return (result);
5829890ff83SToomas Soome }
5839890ff83SToomas Soome
5849890ff83SToomas Soome result = png_unfilter(png, data);
5859890ff83SToomas Soome
5869890ff83SToomas Soome free(png->png_data);
5879890ff83SToomas Soome
5889890ff83SToomas Soome return (result);
5899890ff83SToomas Soome }
5909890ff83SToomas Soome
5919890ff83SToomas Soome char *
png_error_string(int error)5929890ff83SToomas Soome png_error_string(int error)
5939890ff83SToomas Soome {
5949890ff83SToomas Soome switch (error) {
5959890ff83SToomas Soome case PNG_NO_ERROR:
5969890ff83SToomas Soome return ("No error");
5979890ff83SToomas Soome case PNG_FILE_ERROR:
5989890ff83SToomas Soome return ("Unknown file error.");
5999890ff83SToomas Soome case PNG_HEADER_ERROR:
6009890ff83SToomas Soome return ("No PNG header found. Are you sure this is a PNG?");
6019890ff83SToomas Soome case PNG_IO_ERROR:
6029890ff83SToomas Soome return ("Failure while reading file.");
6039890ff83SToomas Soome case PNG_EOF_ERROR:
6049890ff83SToomas Soome return ("Reached end of file.");
6059890ff83SToomas Soome case PNG_CRC_ERROR:
6069890ff83SToomas Soome return ("CRC or chunk length error.");
6079890ff83SToomas Soome case PNG_MEMORY_ERROR:
6089890ff83SToomas Soome return ("Could not allocate memory.");
6099890ff83SToomas Soome case PNG_ZLIB_ERROR:
6109890ff83SToomas Soome return ("zlib reported an error.");
6119890ff83SToomas Soome case PNG_UNKNOWN_FILTER:
6129890ff83SToomas Soome return ("Unknown filter method used in scanline.");
6139890ff83SToomas Soome case PNG_DONE:
6149890ff83SToomas Soome return ("PNG done");
6159890ff83SToomas Soome case PNG_NOT_SUPPORTED:
6169890ff83SToomas Soome return ("The PNG is unsupported by pnglite, too bad for you!");
6179890ff83SToomas Soome case PNG_WRONG_ARGUMENTS:
6189890ff83SToomas Soome return ("Wrong combination of arguments passed to png_open. "
6199890ff83SToomas Soome "You must use either a read_function or supply a file "
6209890ff83SToomas Soome "pointer to use.");
6219890ff83SToomas Soome default:
6229890ff83SToomas Soome return ("Unknown error.");
6239890ff83SToomas Soome };
6249890ff83SToomas Soome }
625