-
-
Save mmalex/908299 to your computer and use it in GitHub Desktop.
bug fix png encoder
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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) | |
// | |
// VERSION 0.02! now using zlib's crc rather than my own, and avoiding a memcpy and memory scribbler in the old one | |
// by passing the zero byte at the start of the scanline to zlib first, then the original scanline in place. WIN! | |
// | |
// more context at http://altdevblogaday.org/2011/04/06/a-smaller-jpg-encoder/. | |
// | |
// follow me on twitter @mmalex http://twitter.com/mmalex | |
// | |
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); | |
if (!zbuf) return 0; | |
z.next_out=zbuf+41; | |
for (int y=0;y<h;++y) { | |
Bytef zero=0; z.avail_in=1;z.next_in=&zero; deflate(&z,Z_NO_FLUSH); | |
z.avail_in=p;z.next_in=((Bytef*)img)+y*p; 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(crc32(0,pnghdr+12,17)); | |
memcpy(zbuf,pnghdr,41); | |
memcpy(z.next_out+4,"\x49\x45\x4e\x44\xae\x42\x60\x82",8); // footer | |
*(u32*)z.next_out =htonl(crc32(0, zbuf+41-4, len_out+4)); | |
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); | |
} |
here is a patch to my program that fixes that:
--- pngencode.c 2024-01-24 14:52:34.490371971 +0100
+++ pngencode-fixed.c 2024-01-24 14:52:54.517190368 +0100
@@ -19,7 +19,7 @@
int p = w * numchans;
z_stream z = {0};
deflateInit(&z, -1);
- uint8_t* zbuf = malloc(53 + (z.avail_out = deflateBound(&z, (1+p)*h)) + 1);
+ uint8_t* zbuf = malloc(57 + (z.avail_out = deflateBound(&z, (1+p)*h)) + 1);
if (!zbuf) return 0;
z.next_out = zbuf + 41;
@@ -39,10 +39,10 @@
*len_out>>24, *len_out>>16, *len_out>>8, *len_out, 0x49, 0x44, 0x41, 0x54};
*(unsigned int*)(pnghdr + 29) = htonl(crc32(0, pnghdr + 12, 17));
memcpy(zbuf, pnghdr, 41);
- memcpy(z.next_out + 4, "\x49\x45\x4e\x44\xae\x42\x60\x82", 8); /* footer */
+ memcpy(z.next_out + 4, "\0\0\0\0\x49\x45\x4e\x44\xae\x42\x60\x82", 12); /* footer */
*(unsigned int*)z.next_out = htonl(crc32(0, zbuf+41-4, *len_out+4));
deflateEnd(&z);
- *len_out += 53;
+ *len_out += 57;
return zbuf;
}
here is the image it produces:
compile with gcc -lz pngencode.c
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
the generated png is invalid though: