Blame


1 cbeb0b26 2006-04-01 devnull /* based on PNG 1.2 specification, July 1999 (see also rfc2083) */
2 cbeb0b26 2006-04-01 devnull /* Alpha is not supported yet because of lack of industry acceptance and */
3 cbeb0b26 2006-04-01 devnull /* because Plan9 Image uses premultiplied alpha, so png can't be lossless. */
4 cbeb0b26 2006-04-01 devnull /* Only 24bit color supported, because 8bit may as well use GIF. */
5 28994509 2004-04-21 devnull
6 28994509 2004-04-21 devnull #include <u.h>
7 28994509 2004-04-21 devnull #include <libc.h>
8 28994509 2004-04-21 devnull #include <draw.h>
9 28994509 2004-04-21 devnull #include <memdraw.h>
10 28994509 2004-04-21 devnull #include <ctype.h>
11 28994509 2004-04-21 devnull #include <bio.h>
12 28994509 2004-04-21 devnull #include <flate.h>
13 28994509 2004-04-21 devnull #include "imagefile.h"
14 28994509 2004-04-21 devnull
15 28994509 2004-04-21 devnull enum{ IDATSIZE = 20000,
16 cbeb0b26 2006-04-01 devnull FilterNone = 0
17 28994509 2004-04-21 devnull };
18 28994509 2004-04-21 devnull
19 28994509 2004-04-21 devnull typedef struct ZlibR{
20 28994509 2004-04-21 devnull uchar *data;
21 28994509 2004-04-21 devnull int width;
22 28994509 2004-04-21 devnull int nrow, ncol;
23 cbeb0b26 2006-04-01 devnull int row, col; /* next pixel to send */
24 0cbccd3a 2005-02-15 devnull int pixwid;
25 28994509 2004-04-21 devnull } ZlibR;
26 28994509 2004-04-21 devnull
27 28994509 2004-04-21 devnull typedef struct ZlibW{
28 28994509 2004-04-21 devnull Biobuf *bo;
29 28994509 2004-04-21 devnull uchar *buf;
30 cbeb0b26 2006-04-01 devnull uchar *b; /* next place to write */
31 cbeb0b26 2006-04-01 devnull uchar *e; /* past end of buf */
32 28994509 2004-04-21 devnull } ZlibW;
33 28994509 2004-04-21 devnull
34 9a054520 2010-02-08 rsc static uint32 *crctab;
35 28994509 2004-04-21 devnull static uchar PNGmagic[] = {137,80,78,71,13,10,26,10};
36 28994509 2004-04-21 devnull
37 28994509 2004-04-21 devnull static void
38 9a054520 2010-02-08 rsc put4(uchar *a, uint32 v)
39 28994509 2004-04-21 devnull {
40 28994509 2004-04-21 devnull a[0] = v>>24;
41 28994509 2004-04-21 devnull a[1] = v>>16;
42 28994509 2004-04-21 devnull a[2] = v>>8;
43 28994509 2004-04-21 devnull a[3] = v;
44 28994509 2004-04-21 devnull }
45 28994509 2004-04-21 devnull
46 28994509 2004-04-21 devnull static void
47 28994509 2004-04-21 devnull chunk(Biobuf *bo, char *type, uchar *d, int n)
48 28994509 2004-04-21 devnull {
49 28994509 2004-04-21 devnull uchar buf[4];
50 9a054520 2010-02-08 rsc uint32 crc = 0;
51 28994509 2004-04-21 devnull
52 28994509 2004-04-21 devnull if(strlen(type) != 4)
53 28994509 2004-04-21 devnull return;
54 28994509 2004-04-21 devnull put4(buf, n);
55 28994509 2004-04-21 devnull Bwrite(bo, buf, 4);
56 28994509 2004-04-21 devnull Bwrite(bo, type, 4);
57 28994509 2004-04-21 devnull Bwrite(bo, d, n);
58 28994509 2004-04-21 devnull crc = blockcrc(crctab, crc, type, 4);
59 28994509 2004-04-21 devnull crc = blockcrc(crctab, crc, d, n);
60 28994509 2004-04-21 devnull put4(buf, crc);
61 28994509 2004-04-21 devnull Bwrite(bo, buf, 4);
62 28994509 2004-04-21 devnull }
63 28994509 2004-04-21 devnull
64 28994509 2004-04-21 devnull static int
65 28994509 2004-04-21 devnull zread(void *va, void *buf, int n)
66 28994509 2004-04-21 devnull {
67 28994509 2004-04-21 devnull ZlibR *z = va;
68 28994509 2004-04-21 devnull int nrow = z->nrow;
69 28994509 2004-04-21 devnull int ncol = z->ncol;
70 28994509 2004-04-21 devnull uchar *b = buf, *e = b+n, *img;
71 cbeb0b26 2006-04-01 devnull int pixels; /* number of pixels in row that can be sent now */
72 0cbccd3a 2005-02-15 devnull int i, a, pixwid;
73 fa325e9b 2020-01-10 cross
74 0cbccd3a 2005-02-15 devnull pixwid = z->pixwid;
75 cbeb0b26 2006-04-01 devnull while(b+pixwid <= e){ /* loop over image rows */
76 28994509 2004-04-21 devnull if(z->row >= nrow)
77 28994509 2004-04-21 devnull break;
78 28994509 2004-04-21 devnull if(z->col==0)
79 28994509 2004-04-21 devnull *b++ = FilterNone;
80 0cbccd3a 2005-02-15 devnull pixels = (e-b)/pixwid;
81 28994509 2004-04-21 devnull if(pixels > ncol - z->col)
82 28994509 2004-04-21 devnull pixels = ncol - z->col;
83 0cbccd3a 2005-02-15 devnull img = z->data + z->width * z->row + pixwid * z->col;
84 28994509 2004-04-21 devnull
85 0cbccd3a 2005-02-15 devnull memmove(b, img, pixwid*pixels);
86 0cbccd3a 2005-02-15 devnull if(pixwid == 4){
87 0cbccd3a 2005-02-15 devnull /*
88 0cbccd3a 2005-02-15 devnull * Convert to non-premultiplied alpha.
89 0cbccd3a 2005-02-15 devnull */
90 0cbccd3a 2005-02-15 devnull for(i=0; i<pixels; i++, b+=4){
91 0cbccd3a 2005-02-15 devnull a = b[3];
92 0cbccd3a 2005-02-15 devnull if(a == 255 || a == 0)
93 0cbccd3a 2005-02-15 devnull ;
94 0cbccd3a 2005-02-15 devnull else{
95 0cbccd3a 2005-02-15 devnull if(b[0] >= a)
96 0cbccd3a 2005-02-15 devnull b[0] = a;
97 0cbccd3a 2005-02-15 devnull b[0] = (b[0]*255)/a;
98 0cbccd3a 2005-02-15 devnull if(b[1] >= a)
99 0cbccd3a 2005-02-15 devnull b[1] = a;
100 0cbccd3a 2005-02-15 devnull b[1] = (b[1]*255)/a;
101 0cbccd3a 2005-02-15 devnull if(b[2] >= a)
102 0cbccd3a 2005-02-15 devnull b[2] = a;
103 0cbccd3a 2005-02-15 devnull b[2] = (b[2]*255)/a;
104 0cbccd3a 2005-02-15 devnull }
105 0cbccd3a 2005-02-15 devnull }
106 fa325e9b 2020-01-10 cross }else
107 0cbccd3a 2005-02-15 devnull b += pixwid*pixels;
108 28994509 2004-04-21 devnull
109 28994509 2004-04-21 devnull z->col += pixels;
110 28994509 2004-04-21 devnull if(z->col >= ncol){
111 28994509 2004-04-21 devnull z->col = 0;
112 28994509 2004-04-21 devnull z->row++;
113 28994509 2004-04-21 devnull }
114 28994509 2004-04-21 devnull }
115 28994509 2004-04-21 devnull return b - (uchar*)buf;
116 28994509 2004-04-21 devnull }
117 28994509 2004-04-21 devnull
118 28994509 2004-04-21 devnull static void
119 28994509 2004-04-21 devnull IDAT(ZlibW *z)
120 28994509 2004-04-21 devnull {
121 28994509 2004-04-21 devnull chunk(z->bo, "IDAT", z->buf, z->b - z->buf);
122 28994509 2004-04-21 devnull z->b = z->buf;
123 28994509 2004-04-21 devnull }
124 28994509 2004-04-21 devnull
125 28994509 2004-04-21 devnull static int
126 28994509 2004-04-21 devnull zwrite(void *va, void *buf, int n)
127 28994509 2004-04-21 devnull {
128 28994509 2004-04-21 devnull ZlibW *z = va;
129 28994509 2004-04-21 devnull uchar *b = buf, *e = b+n;
130 28994509 2004-04-21 devnull int m;
131 28994509 2004-04-21 devnull
132 cbeb0b26 2006-04-01 devnull while(b < e){ /* loop over IDAT chunks */
133 28994509 2004-04-21 devnull m = z->e - z->b;
134 28994509 2004-04-21 devnull if(m > e - b)
135 28994509 2004-04-21 devnull m = e - b;
136 28994509 2004-04-21 devnull memmove(z->b, b, m);
137 28994509 2004-04-21 devnull z->b += m;
138 28994509 2004-04-21 devnull b += m;
139 28994509 2004-04-21 devnull if(z->b >= z->e)
140 28994509 2004-04-21 devnull IDAT(z);
141 28994509 2004-04-21 devnull }
142 28994509 2004-04-21 devnull return n;
143 28994509 2004-04-21 devnull }
144 28994509 2004-04-21 devnull
145 28994509 2004-04-21 devnull static Memimage*
146 0cbccd3a 2005-02-15 devnull memRGBA(Memimage *i)
147 28994509 2004-04-21 devnull {
148 28994509 2004-04-21 devnull Memimage *ni;
149 0cbccd3a 2005-02-15 devnull char buf[32];
150 0cbccd3a 2005-02-15 devnull ulong dst;
151 fa325e9b 2020-01-10 cross
152 9fe5a621 2005-01-30 devnull /*
153 0cbccd3a 2005-02-15 devnull * [A]BGR because we want R,G,B,[A] in big-endian order. Sigh.
154 9fe5a621 2005-01-30 devnull */
155 0cbccd3a 2005-02-15 devnull chantostr(buf, i->chan);
156 0cbccd3a 2005-02-15 devnull if(strchr(buf, 'a'))
157 0cbccd3a 2005-02-15 devnull dst = ABGR32;
158 0cbccd3a 2005-02-15 devnull else
159 0cbccd3a 2005-02-15 devnull dst = BGR24;
160 fa325e9b 2020-01-10 cross
161 0cbccd3a 2005-02-15 devnull if(i->chan == dst)
162 28994509 2004-04-21 devnull return i;
163 28994509 2004-04-21 devnull
164 0cbccd3a 2005-02-15 devnull ni = allocmemimage(i->r, dst);
165 28994509 2004-04-21 devnull if(ni == nil)
166 28994509 2004-04-21 devnull return ni;
167 28994509 2004-04-21 devnull memimagedraw(ni, ni->r, i, i->r.min, nil, i->r.min, S);
168 28994509 2004-04-21 devnull return ni;
169 28994509 2004-04-21 devnull }
170 28994509 2004-04-21 devnull
171 28994509 2004-04-21 devnull char*
172 28994509 2004-04-21 devnull memwritepng(Biobuf *bo, Memimage *r, ImageInfo *II)
173 28994509 2004-04-21 devnull {
174 28994509 2004-04-21 devnull uchar buf[200], *h;
175 28994509 2004-04-21 devnull ulong vgamma;
176 28994509 2004-04-21 devnull int err, n;
177 28994509 2004-04-21 devnull ZlibR zr;
178 28994509 2004-04-21 devnull ZlibW zw;
179 28994509 2004-04-21 devnull int nrow = r->r.max.y - r->r.min.y;
180 28994509 2004-04-21 devnull int ncol = r->r.max.x - r->r.min.x;
181 28994509 2004-04-21 devnull Tm *tm;
182 28994509 2004-04-21 devnull Memimage *rgb;
183 28994509 2004-04-21 devnull
184 0cbccd3a 2005-02-15 devnull rgb = memRGBA(r);
185 28994509 2004-04-21 devnull if(rgb == nil)
186 28994509 2004-04-21 devnull return "allocmemimage nil";
187 28994509 2004-04-21 devnull crctab = mkcrctab(0xedb88320);
188 28994509 2004-04-21 devnull if(crctab == nil)
189 28994509 2004-04-21 devnull sysfatal("mkcrctab error");
190 28994509 2004-04-21 devnull deflateinit();
191 28994509 2004-04-21 devnull
192 28994509 2004-04-21 devnull Bwrite(bo, PNGmagic, sizeof PNGmagic);
193 cbeb0b26 2006-04-01 devnull /* IHDR chunk */
194 28994509 2004-04-21 devnull h = buf;
195 28994509 2004-04-21 devnull put4(h, ncol); h += 4;
196 28994509 2004-04-21 devnull put4(h, nrow); h += 4;
197 cbeb0b26 2006-04-01 devnull *h++ = 8; /* bit depth = 24 bit per pixel */
198 cbeb0b26 2006-04-01 devnull *h++ = rgb->chan==BGR24 ? 2 : 6; /* color type = rgb */
199 cbeb0b26 2006-04-01 devnull *h++ = 0; /* compression method = deflate */
200 cbeb0b26 2006-04-01 devnull *h++ = 0; /* filter method */
201 cbeb0b26 2006-04-01 devnull *h++ = 0; /* interlace method = no interlace */
202 28994509 2004-04-21 devnull chunk(bo, "IHDR", buf, h-buf);
203 28994509 2004-04-21 devnull
204 28994509 2004-04-21 devnull tm = gmtime(time(0));
205 28994509 2004-04-21 devnull h = buf;
206 28994509 2004-04-21 devnull *h++ = (tm->year + 1900)>>8;
207 28994509 2004-04-21 devnull *h++ = (tm->year + 1900)&0xff;
208 28994509 2004-04-21 devnull *h++ = tm->mon + 1;
209 28994509 2004-04-21 devnull *h++ = tm->mday;
210 28994509 2004-04-21 devnull *h++ = tm->hour;
211 28994509 2004-04-21 devnull *h++ = tm->min;
212 28994509 2004-04-21 devnull *h++ = tm->sec;
213 28994509 2004-04-21 devnull chunk(bo, "tIME", buf, h-buf);
214 fa325e9b 2020-01-10 cross
215 28994509 2004-04-21 devnull if(II->fields_set & II_GAMMA){
216 28994509 2004-04-21 devnull vgamma = II->gamma*100000;
217 28994509 2004-04-21 devnull put4(buf, vgamma);
218 28994509 2004-04-21 devnull chunk(bo, "gAMA", buf, 4);
219 28994509 2004-04-21 devnull }
220 28994509 2004-04-21 devnull
221 28994509 2004-04-21 devnull if(II->fields_set & II_COMMENT){
222 28994509 2004-04-21 devnull strncpy((char*)buf, "Comment", sizeof buf);
223 cbeb0b26 2006-04-01 devnull n = strlen((char*)buf)+1; /* leave null between Comment and text */
224 28994509 2004-04-21 devnull strncpy((char*)(buf+n), II->comment, sizeof buf - n);
225 28994509 2004-04-21 devnull chunk(bo, "tEXt", buf, n+strlen((char*)buf+n));
226 28994509 2004-04-21 devnull }
227 28994509 2004-04-21 devnull
228 cbeb0b26 2006-04-01 devnull /* image chunks */
229 28994509 2004-04-21 devnull zr.nrow = nrow;
230 28994509 2004-04-21 devnull zr.ncol = ncol;
231 77929f82 2010-09-03 rsc zr.width = rgb->width * sizeof(uint32);
232 28994509 2004-04-21 devnull zr.data = rgb->data->bdata;
233 28994509 2004-04-21 devnull zr.row = zr.col = 0;
234 0cbccd3a 2005-02-15 devnull zr.pixwid = chantodepth(rgb->chan)/8;
235 28994509 2004-04-21 devnull zw.bo = bo;
236 28994509 2004-04-21 devnull zw.buf = malloc(IDATSIZE);
237 28994509 2004-04-21 devnull zw.b = zw.buf;
238 28994509 2004-04-21 devnull zw.e = zw.b + IDATSIZE;
239 28994509 2004-04-21 devnull err = deflatezlib(&zw, zwrite, &zr, zread, 6, 0);
240 28994509 2004-04-21 devnull if(zw.b > zw.buf)
241 28994509 2004-04-21 devnull IDAT(&zw);
242 28994509 2004-04-21 devnull free(zw.buf);
243 28994509 2004-04-21 devnull if(err)
244 28994509 2004-04-21 devnull sysfatal("deflatezlib %s\n", flateerr(err));
245 28994509 2004-04-21 devnull chunk(bo, "IEND", nil, 0);
246 28994509 2004-04-21 devnull
247 28994509 2004-04-21 devnull if(r != rgb)
248 28994509 2004-04-21 devnull freememimage(rgb);
249 28994509 2004-04-21 devnull return nil;
250 28994509 2004-04-21 devnull }