aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/venti/srv/png.c
diff options
context:
space:
mode:
authorrsc <devnull@localhost>2005-07-12 15:23:36 +0000
committerrsc <devnull@localhost>2005-07-12 15:23:36 +0000
commita0d146edd7a7de6236a0d60baafeeb59f8452aae (patch)
treeb55baa526d9f5adfc73246e6ee2fadf455e0b7a2 /src/cmd/venti/srv/png.c
parent88bb285e3d87ec2508840af33f7e0af53ec3c13c (diff)
downloadplan9port-a0d146edd7a7de6236a0d60baafeeb59f8452aae.tar.gz
plan9port-a0d146edd7a7de6236a0d60baafeeb59f8452aae.tar.bz2
plan9port-a0d146edd7a7de6236a0d60baafeeb59f8452aae.zip
return of venti
Diffstat (limited to 'src/cmd/venti/srv/png.c')
-rw-r--r--src/cmd/venti/srv/png.c241
1 files changed, 241 insertions, 0 deletions
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<pixels; i++, b+=4){
+ a = b[3];
+ if(a == 255 || a == 0)
+ ;
+ else{
+ if(b[0] >= 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;
+}