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 != 0 && a != 255){91 if(b[0] >= a)92 b[0] = a;93 b[0] = (b[0]*255)/a;94 if(b[1] >= a)95 b[1] = a;96 b[1] = (b[1]*255)/a;97 if(b[2] >= a)98 b[2] = a;99 b[2] = (b[2]*255)/a;100 }101 }102 }else103 b += pixwid*pixels;105 z->x += pixels;106 if(z->x >= z->dx){107 z->x = 0;108 z->y++;109 }110 }111 return b - (uchar*)buf;112 }114 static void115 IDAT(ZlibW *z)116 {117 chunk(z->io, "IDAT", z->buf, z->b - z->buf);118 z->b = z->buf;119 }121 static int122 zwrite(void *va, void *buf, int n)123 {124 int m;125 uchar *b, *e;126 ZlibW *z;128 z = va;129 b = buf;130 e = b+n;132 while(b < e){133 m = z->e - z->b;134 if(m > e - b)135 m = e - b;136 memmove(z->b, b, m);137 z->b += m;138 b += m;139 if(z->b >= z->e)140 IDAT(z);141 }142 return n;143 }145 static Memimage*146 memRGBA(Memimage *i)147 {148 Memimage *ni;149 char buf[32];150 ulong dst;152 /*153 * [A]BGR because we want R,G,B,[A] in big-endian order. Sigh.154 */155 chantostr(buf, i->chan);156 if(strchr(buf, 'a'))157 dst = ABGR32;158 else159 dst = BGR24;161 if(i->chan == dst)162 return i;164 qlock(&memdrawlock);165 ni = allocmemimage(i->r, dst);166 if(ni)167 memimagedraw(ni, ni->r, i, i->r.min, nil, i->r.min, S);168 qunlock(&memdrawlock);169 return ni;170 }172 int173 writepng(Hio *io, Memimage *m)174 {175 static int first = 1;176 static QLock lk;177 uchar buf[200], *h;178 Memimage *rgb;179 ZlibR zr;180 ZlibW zw;182 if(first){183 qlock(&lk);184 if(first){185 deflateinit();186 crctab = mkcrctab(0xedb88320);187 first = 0;188 }189 qunlock(&lk);190 }192 rgb = memRGBA(m);193 if(rgb == nil)194 return -1;196 hwrite(io, PNGmagic, sizeof PNGmagic);198 /* IHDR chunk */199 h = buf;200 put4(h, Dx(m->r)); h += 4;201 put4(h, Dy(m->r)); h += 4;202 *h++ = 8; /* 8 bits per channel */203 if(rgb->chan == BGR24)204 *h++ = 2; /* RGB */205 else206 *h++ = 6; /* RGBA */207 *h++ = 0; /* compression - deflate */208 *h++ = 0; /* filter - none */209 *h++ = 0; /* interlace - none */210 chunk(io, "IHDR", buf, h-buf);212 /* image data */213 zr.dx = Dx(m->r);214 zr.dy = Dy(m->r);215 zr.width = rgb->width * sizeof(ulong);216 zr.data = rgb->data->bdata;217 zr.x = 0;218 zr.y = 0;219 zr.pixwid = chantodepth(rgb->chan)/8;220 zw.io = io;221 zw.buf = vtmalloc(IDATSIZE);222 zw.b = zw.buf;223 zw.e = zw.b + IDATSIZE;224 if(deflatezlib(&zw, zwrite, &zr, zread, 6, 0) < 0){225 free(zw.buf);226 return -1;227 }228 if(zw.b > zw.buf)229 IDAT(&zw);230 free(zw.buf);231 chunk(io, "IEND", nil, 0);233 if(m != rgb){234 qlock(&memdrawlock);235 freememimage(rgb);236 qunlock(&memdrawlock);237 }238 return 0;239 }