I just read the png spec, and came up with this as a minimal, zlib based png encoding of a truecolour image with 1-4 channels
// by alex evans, 2011. released into the public domain. | |
// based on a first ever reading of the png spec, it occurs to me that a minimal png encoder should be quite simple. | |
// this is a first stab - may be buggy! the only external dependency is zlib and some basic typedefs (u32, u8) | |
// | |
// more context at http://altdevblogaday.org/2011/04/06/a-smaller-jpg-encoder/. | |
// | |
// follow me on twitter @mmalex http://twitter.com/mmalex | |
// | |
u32 crc_table[256]={0}; | |
void make_crc_table(void) | |
{ | |
for (int n = 0; n < 256; n++) { | |
u32 c = n; | |
for (int k = 0; k < 8; k++) if (c & 1) c = 0xedb88320L ^ (c >> 1); else c = c >> 1; | |
crc_table[n] = c; | |
} | |
} | |
u32 update_crc(u32 c, unsigned char *buf, int len) | |
{ | |
if (!crc_table[0]) make_crc_table(); | |
for (int n = 0; n < len; n++) c = crc_table[(c ^ buf[n]) & 0xff] ^ (c >> 8); | |
return c; | |
} | |
u8* CompressPNG(void *img, int w, int h, int numchans, u32 &len_out) | |
{ int p=w*numchans; | |
z_stream z={0}; deflateInit(&z,-1); | |
u8 *zbuf=(u8*)malloc(53+(z.avail_out=deflateBound(&z,(1+p)*h))+1); | |
u8 *scanline=zbuf+53+z.avail_out; | |
z.next_out=zbuf+41; | |
for (int y=0;y<h;++y) | |
{ | |
u8 *dst=scanline; *dst++ = 0; | |
u8 *src=((u8*)img)+y*p; | |
for (int x=0;x<p;++x) *dst++ = *src++; | |
z.avail_in=1+p; z.next_in=scanline; | |
int err = deflate(&z,(y==h-1) ? Z_FINISH : Z_NO_FLUSH); | |
} | |
len_out=z.next_out-zbuf-41; | |
u8 pnghdr[41]={0x89,0x50,0x4e,0x47,0x0d,0x0a,0x1a,0x0a,0x00,0x00,0x00,0x0d,0x49,0x48,0x44,0x52, | |
0,0,w>>8,w,0,0,h>>8,h,8,"\0\0\04\02\06"[numchans],0,0,0,0,0,0,0, | |
len_out>>24,len_out>>16,len_out>>8,len_out,0x49,0x44,0x41,0x54}; | |
*(u32*)(pnghdr+29)=htonl(update_crc(0xffffffffL,pnghdr+12,17)^0xffffffffL); | |
memcpy(zbuf,pnghdr,41); // header | |
memcpy(z.next_out+4,"\x49\x45\x4e\x44\xae\x42\x60\x82",8); // footer | |
*(u32*)z.next_out =htonl(update_crc(0xffffffffL, zbuf+41-4, len_out+4)^0xffffffffL); | |
deflateEnd(&z); | |
len_out+=53; | |
return zbuf; | |
} | |
void PNGTest() | |
{ | |
u32 img[200][320]; | |
for (int y=0;y<200;++y) for (int x=0;x<320;++x) img[y][x]=x+(y<<8)+0xff000000; | |
u32 blen; u8*zbuf = CompressPNG(img,16,16,4,blen); | |
FILE *f=fopen("test.png","wb"); | |
fwrite(zbuf,1,blen,f); | |
fclose(f); | |
free(zbuf); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment