Blob
1 #include "stdinc.h"2 #include "dat.h"3 #include "fns.h"5 enum6 {7 IDATSIZE = 20000,8 FilterNone = 09 };11 typedef struct ZlibR ZlibR;12 typedef struct ZlibW ZlibW;14 struct ZlibR15 {16 uchar *data;17 int width;18 int dx;19 int dy;20 int x;21 int y;22 int pixwid;23 };25 struct ZlibW26 {27 Hio *io;28 uchar *buf;29 uchar *b;30 uchar *e;31 };33 static ulong *crctab;34 static uchar PNGmagic[] = { 137, 'P', 'N', 'G', '\r', '\n', 26, '\n'};36 static void37 put4(uchar *a, ulong v)38 {39 a[0] = v>>24;40 a[1] = v>>16;41 a[2] = v>>8;42 a[3] = v;43 }45 static void46 chunk(Hio *io, char *type, uchar *d, int n)47 {48 uchar buf[4];49 ulong crc = 0;51 if(strlen(type) != 4)52 return;53 put4(buf, n);54 hwrite(io, buf, 4);55 hwrite(io, type, 4);56 hwrite(io, d, n);57 crc = blockcrc(crctab, crc, type, 4);58 crc = blockcrc(crctab, crc, d, n);59 put4(buf, crc);60 hwrite(io, buf, 4);61 }63 static int64 zread(void *va, void *buf, int n)65 {66 int a, i, pixels, pixwid;67 uchar *b, *e, *img;68 ZlibR *z;70 z = va;71 pixwid = z->pixwid;72 b = buf;73 e = b+n;74 while(b+pixwid <= e){75 if(z->y >= z->dy)76 break;77 if(z->x == 0)78 *b++ = FilterNone;79 pixels = (e-b)/pixwid;80 if(pixels > z->dx - z->x)81 pixels = z->dx - z->x;82 img = z->data + z->width*z->y + pixwid*z->x;83 memmove(b, img, pixwid*pixels);84 if(pixwid == 4){85 /*86 * Convert to non-premultiplied alpha.87 */88 for(i=0; i<pixels; i++, b+=4){89 a = b[3];90 if(a == 255 || a == 0)91 ;92 else{93 if(b[0] >= a)94 b[0] = a;95 b[0] = (b[0]*255)/a;96 if(b[1] >= a)97 b[1] = a;98 b[1] = (b[1]*255)/a;99 if(b[2] >= a)100 b[2] = a;101 b[2] = (b[2]*255)/a;102 }103 }104 }else105 b += pixwid*pixels;107 z->x += pixels;108 if(z->x >= z->dx){109 z->x = 0;110 z->y++;111 }112 }113 return b - (uchar*)buf;114 }116 static void117 IDAT(ZlibW *z)118 {119 chunk(z->io, "IDAT", z->buf, z->b - z->buf);120 z->b = z->buf;121 }123 static int124 zwrite(void *va, void *buf, int n)125 {126 int m;127 uchar *b, *e;128 ZlibW *z;130 z = va;131 b = buf;132 e = b+n;134 while(b < e){135 m = z->e - z->b;136 if(m > e - b)137 m = e - b;138 memmove(z->b, b, m);139 z->b += m;140 b += m;141 if(z->b >= z->e)142 IDAT(z);143 }144 return n;145 }147 static Memimage*148 memRGBA(Memimage *i)149 {150 Memimage *ni;151 char buf[32];152 ulong dst;154 /*155 * [A]BGR because we want R,G,B,[A] in big-endian order. Sigh.156 */157 chantostr(buf, i->chan);158 if(strchr(buf, 'a'))159 dst = ABGR32;160 else161 dst = BGR24;163 if(i->chan == dst)164 return i;166 qlock(&memdrawlock);167 ni = allocmemimage(i->r, dst);168 if(ni)169 memimagedraw(ni, ni->r, i, i->r.min, nil, i->r.min, S);170 qunlock(&memdrawlock);171 return ni;172 }174 int175 writepng(Hio *io, Memimage *m)176 {177 static int first = 1;178 static QLock lk;179 uchar buf[200], *h;180 Memimage *rgb;181 ZlibR zr;182 ZlibW zw;184 if(first){185 qlock(&lk);186 if(first){187 deflateinit();188 crctab = mkcrctab(0xedb88320);189 first = 0;190 }191 qunlock(&lk);192 }194 rgb = memRGBA(m);195 if(rgb == nil)196 return -1;198 hwrite(io, PNGmagic, sizeof PNGmagic);200 /* IHDR chunk */201 h = buf;202 put4(h, Dx(m->r)); h += 4;203 put4(h, Dy(m->r)); h += 4;204 *h++ = 8; /* 8 bits per channel */205 if(rgb->chan == BGR24)206 *h++ = 2; /* RGB */207 else208 *h++ = 6; /* RGBA */209 *h++ = 0; /* compression - deflate */210 *h++ = 0; /* filter - none */211 *h++ = 0; /* interlace - none */212 chunk(io, "IHDR", buf, h-buf);214 /* image data */215 zr.dx = Dx(m->r);216 zr.dy = Dy(m->r);217 zr.width = rgb->width * sizeof(ulong);218 zr.data = rgb->data->bdata;219 zr.x = 0;220 zr.y = 0;221 zr.pixwid = chantodepth(rgb->chan)/8;222 zw.io = io;223 zw.buf = vtmalloc(IDATSIZE);224 zw.b = zw.buf;225 zw.e = zw.b + IDATSIZE;226 if(deflatezlib(&zw, zwrite, &zr, zread, 6, 0) < 0){227 free(zw.buf);228 return -1;229 }230 if(zw.b > zw.buf)231 IDAT(&zw);232 free(zw.buf);233 chunk(io, "IEND", nil, 0);235 if(m != rgb){236 qlock(&memdrawlock);237 freememimage(rgb);238 qunlock(&memdrawlock);239 }240 return 0;241 }