Blob


1 #include "stdinc.h"
2 #include "dat.h"
3 #include "fns.h"
5 enum
6 {
7 IDATSIZE = 20000,
8 FilterNone = 0
9 };
11 typedef struct ZlibR ZlibR;
12 typedef struct ZlibW ZlibW;
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 };
25 struct ZlibW
26 {
27 Hio *io;
28 uchar *buf;
29 uchar *b;
30 uchar *e;
31 };
33 static u32int *crctab;
34 static uchar PNGmagic[] = { 137, 'P', 'N', 'G', '\r', '\n', 26, '\n'};
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 }
45 static void
46 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 int
64 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;
102 }else
103 b += pixwid*pixels;
105 z->x += pixels;
106 if(z->x >= z->dx){
107 z->x = 0;
108 z->y++;
111 return b - (uchar*)buf;
114 static void
115 IDAT(ZlibW *z)
117 chunk(z->io, "IDAT", z->buf, z->b - z->buf);
118 z->b = z->buf;
121 static int
122 zwrite(void *va, void *buf, int n)
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);
142 return n;
145 static Memimage*
146 memRGBA(Memimage *i)
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 else
159 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;
172 int
173 writepng(Hio *io, Memimage *m)
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;
189 qunlock(&lk);
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 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);
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;
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);
238 return 0;