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