From a0d146edd7a7de6236a0d60baafeeb59f8452aae Mon Sep 17 00:00:00 2001 From: rsc Date: Tue, 12 Jul 2005 15:23:36 +0000 Subject: return of venti --- src/cmd/venti/srv/png.c | 241 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 241 insertions(+) create mode 100644 src/cmd/venti/srv/png.c (limited to 'src/cmd/venti/srv/png.c') diff --git a/src/cmd/venti/srv/png.c b/src/cmd/venti/srv/png.c new file mode 100644 index 00000000..966b7e96 --- /dev/null +++ b/src/cmd/venti/srv/png.c @@ -0,0 +1,241 @@ +#include "stdinc.h" +#include "dat.h" +#include "fns.h" + +enum +{ + IDATSIZE = 20000, + FilterNone = 0 +}; + +typedef struct ZlibR ZlibR; +typedef struct ZlibW ZlibW; + +struct ZlibR +{ + uchar *data; + int width; + int dx; + int dy; + int x; + int y; + int pixwid; +}; + +struct ZlibW +{ + Hio *io; + uchar *buf; + uchar *b; + uchar *e; +}; + +static ulong *crctab; +static uchar PNGmagic[] = { 137, 'P', 'N', 'G', '\r', '\n', 26, '\n'}; + +static void +put4(uchar *a, ulong v) +{ + a[0] = v>>24; + a[1] = v>>16; + a[2] = v>>8; + a[3] = v; +} + +static void +chunk(Hio *io, char *type, uchar *d, int n) +{ + uchar buf[4]; + ulong crc = 0; + + if(strlen(type) != 4) + return; + put4(buf, n); + hwrite(io, buf, 4); + hwrite(io, type, 4); + hwrite(io, d, n); + crc = blockcrc(crctab, crc, type, 4); + crc = blockcrc(crctab, crc, d, n); + put4(buf, crc); + hwrite(io, buf, 4); +} + +static int +zread(void *va, void *buf, int n) +{ + int a, i, pixels, pixwid; + uchar *b, *e, *img; + ZlibR *z; + + z = va; + pixwid = z->pixwid; + b = buf; + e = b+n; + while(b+pixwid <= e){ + if(z->y >= z->dy) + break; + if(z->x == 0) + *b++ = FilterNone; + pixels = (e-b)/pixwid; + if(pixels > z->dx - z->x) + pixels = z->dx - z->x; + img = z->data + z->width*z->y + pixwid*z->x; + memmove(b, img, pixwid*pixels); + if(pixwid == 4){ + /* + * Convert to non-premultiplied alpha. + */ + for(i=0; i= a) + b[0] = a; + b[0] = (b[0]*255)/a; + if(b[1] >= a) + b[1] = a; + b[1] = (b[1]*255)/a; + if(b[2] >= a) + b[2] = a; + b[2] = (b[2]*255)/a; + } + } + }else + b += pixwid*pixels; + + z->x += pixels; + if(z->x >= z->dx){ + z->x = 0; + z->y++; + } + } + return b - (uchar*)buf; +} + +static void +IDAT(ZlibW *z) +{ + chunk(z->io, "IDAT", z->buf, z->b - z->buf); + z->b = z->buf; +} + +static int +zwrite(void *va, void *buf, int n) +{ + int m; + uchar *b, *e; + ZlibW *z; + + z = va; + b = buf; + e = b+n; + + while(b < e){ + m = z->e - z->b; + if(m > e - b) + m = e - b; + memmove(z->b, b, m); + z->b += m; + b += m; + if(z->b >= z->e) + IDAT(z); + } + return n; +} + +static Memimage* +memRGBA(Memimage *i) +{ + Memimage *ni; + char buf[32]; + ulong dst; + + /* + * [A]BGR because we want R,G,B,[A] in big-endian order. Sigh. + */ + chantostr(buf, i->chan); + if(strchr(buf, 'a')) + dst = ABGR32; + else + dst = BGR24; + + if(i->chan == dst) + return i; + + qlock(&memdrawlock); + ni = allocmemimage(i->r, dst); + if(ni) + memimagedraw(ni, ni->r, i, i->r.min, nil, i->r.min, S); + qunlock(&memdrawlock); + return ni; +} + +int +writepng(Hio *io, Memimage *m) +{ + static int first = 1; + static QLock lk; + uchar buf[200], *h; + Memimage *rgb; + ZlibR zr; + ZlibW zw; + + if(first){ + qlock(&lk); + if(first){ + deflateinit(); + crctab = mkcrctab(0xedb88320); + first = 0; + } + qunlock(&lk); + } + + rgb = memRGBA(m); + if(rgb == nil) + return -1; + + hwrite(io, PNGmagic, sizeof PNGmagic); + + /* IHDR chunk */ + h = buf; + put4(h, Dx(m->r)); h += 4; + put4(h, Dy(m->r)); h += 4; + *h++ = 8; /* 8 bits per channel */ + if(rgb->chan == BGR24) + *h++ = 2; /* RGB */ + else + *h++ = 6; /* RGBA */ + *h++ = 0; /* compression - deflate */ + *h++ = 0; /* filter - none */ + *h++ = 0; /* interlace - none */ + chunk(io, "IHDR", buf, h-buf); + + /* image data */ + zr.dx = Dx(m->r); + zr.dy = Dy(m->r); + zr.width = rgb->width * sizeof(ulong); + zr.data = rgb->data->bdata; + zr.x = 0; + zr.y = 0; + zr.pixwid = chantodepth(rgb->chan)/8; + zw.io = io; + zw.buf = vtmalloc(IDATSIZE); + zw.b = zw.buf; + zw.e = zw.b + IDATSIZE; + if(deflatezlib(&zw, zwrite, &zr, zread, 6, 0) < 0){ + free(zw.buf); + return -1; + } + if(zw.b > zw.buf) + IDAT(&zw); + free(zw.buf); + chunk(io, "IEND", nil, 0); + + if(m != rgb){ + qlock(&memdrawlock); + freememimage(rgb); + qunlock(&memdrawlock); + } + return 0; +} -- cgit v1.2.3