plan9port

[fork] Plan 9 from user space
git clone git://src.adamsgaard.dk/plan9port # fast
git clone https://src.adamsgaard.dk/plan9port.git # slow
Log | Files | Refs | README | LICENSE Back to index

png.c (3726B)


      1 #include "stdinc.h"
      2 #include "dat.h"
      3 #include "fns.h"
      4 
      5 enum
      6 {
      7 	IDATSIZE	= 20000,
      8 	FilterNone = 0
      9 };
     10 
     11 typedef struct ZlibR ZlibR;
     12 typedef struct ZlibW ZlibW;
     13 
     14 struct ZlibR
     15 {
     16 	uchar *data;
     17 	int width;
     18 	int dx;
     19 	int dy;
     20 	int x;
     21 	int y;
     22 	int pixwid;
     23 };
     24 
     25 struct ZlibW
     26 {
     27 	Hio *io;
     28 	uchar *buf;
     29 	uchar *b;
     30 	uchar *e;
     31 };
     32 
     33 static u32int *crctab;
     34 static uchar PNGmagic[] = { 137, 'P', 'N', 'G', '\r', '\n', 26, '\n'};
     35 
     36 static void
     37 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 }
     44 
     45 static void
     46 chunk(Hio *io, char *type, uchar *d, int n)
     47 {
     48 	uchar buf[4];
     49 	ulong crc = 0;
     50 
     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 }
     62 
     63 static int
     64 zread(void *va, void *buf, int n)
     65 {
     66 	int a, i, pixels, pixwid;
     67 	uchar *b, *e, *img;
     68 	ZlibR *z;
     69 
     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 		}else
    103 			b += pixwid*pixels;
    104 
    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 }
    113 
    114 static void
    115 IDAT(ZlibW *z)
    116 {
    117 	chunk(z->io, "IDAT", z->buf, z->b - z->buf);
    118 	z->b = z->buf;
    119 }
    120 
    121 static int
    122 zwrite(void *va, void *buf, int n)
    123 {
    124 	int m;
    125 	uchar *b, *e;
    126 	ZlibW *z;
    127 
    128 	z = va;
    129 	b = buf;
    130 	e = b+n;
    131 
    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 }
    144 
    145 static Memimage*
    146 memRGBA(Memimage *i)
    147 {
    148 	Memimage *ni;
    149 	char buf[32];
    150 	ulong dst;
    151 
    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 	else
    159 		dst = BGR24;
    160 
    161 	if(i->chan == dst)
    162 		return i;
    163 
    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 }
    171 
    172 int
    173 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;
    181 
    182 	if(first){
    183 		qlock(&lk);
    184 		if(first){
    185 			deflateinit();
    186 			crctab = mkcrctab(0xedb88320);
    187 			first = 0;
    188 		}
    189 		qunlock(&lk);
    190 	}
    191 
    192 	rgb = memRGBA(m);
    193 	if(rgb == nil)
    194 		return -1;
    195 
    196 	hwrite(io, PNGmagic, sizeof PNGmagic);
    197 
    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 	else
    206 		*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);
    211 
    212 	/* image data */
    213 	zr.dx = Dx(m->r);
    214 	zr.dy = Dy(m->r);
    215 	zr.width = rgb->width * sizeof(u32int);
    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);
    232 
    233 	if(m != rgb){
    234 		qlock(&memdrawlock);
    235 		freememimage(rgb);
    236 		qunlock(&memdrawlock);
    237 	}
    238 	return 0;
    239 }