Blame


1 28994509 2004-04-21 devnull // based on PNG 1.2 specification, July 1999 (see also rfc2083)
2 28994509 2004-04-21 devnull // Alpha is not supported yet because of lack of industry acceptance and
3 28994509 2004-04-21 devnull // because Plan9 Image uses premultiplied alpha, so png can't be lossless.
4 28994509 2004-04-21 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 28994509 2004-04-21 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 28994509 2004-04-21 devnull int row, col; // next pixel to send
24 28994509 2004-04-21 devnull } ZlibR;
25 28994509 2004-04-21 devnull
26 28994509 2004-04-21 devnull typedef struct ZlibW{
27 28994509 2004-04-21 devnull Biobuf *bo;
28 28994509 2004-04-21 devnull uchar *buf;
29 28994509 2004-04-21 devnull uchar *b; // next place to write
30 28994509 2004-04-21 devnull uchar *e; // past end of buf
31 28994509 2004-04-21 devnull } ZlibW;
32 28994509 2004-04-21 devnull
33 28994509 2004-04-21 devnull static ulong *crctab;
34 28994509 2004-04-21 devnull static uchar PNGmagic[] = {137,80,78,71,13,10,26,10};
35 28994509 2004-04-21 devnull
36 28994509 2004-04-21 devnull static void
37 28994509 2004-04-21 devnull put4(uchar *a, ulong v)
38 28994509 2004-04-21 devnull {
39 28994509 2004-04-21 devnull a[0] = v>>24;
40 28994509 2004-04-21 devnull a[1] = v>>16;
41 28994509 2004-04-21 devnull a[2] = v>>8;
42 28994509 2004-04-21 devnull a[3] = v;
43 28994509 2004-04-21 devnull }
44 28994509 2004-04-21 devnull
45 28994509 2004-04-21 devnull static void
46 28994509 2004-04-21 devnull chunk(Biobuf *bo, char *type, uchar *d, int n)
47 28994509 2004-04-21 devnull {
48 28994509 2004-04-21 devnull uchar buf[4];
49 28994509 2004-04-21 devnull ulong crc = 0;
50 28994509 2004-04-21 devnull
51 28994509 2004-04-21 devnull if(strlen(type) != 4)
52 28994509 2004-04-21 devnull return;
53 28994509 2004-04-21 devnull put4(buf, n);
54 28994509 2004-04-21 devnull Bwrite(bo, buf, 4);
55 28994509 2004-04-21 devnull Bwrite(bo, type, 4);
56 28994509 2004-04-21 devnull Bwrite(bo, d, n);
57 28994509 2004-04-21 devnull crc = blockcrc(crctab, crc, type, 4);
58 28994509 2004-04-21 devnull crc = blockcrc(crctab, crc, d, n);
59 28994509 2004-04-21 devnull put4(buf, crc);
60 28994509 2004-04-21 devnull Bwrite(bo, buf, 4);
61 28994509 2004-04-21 devnull }
62 28994509 2004-04-21 devnull
63 28994509 2004-04-21 devnull static int
64 28994509 2004-04-21 devnull zread(void *va, void *buf, int n)
65 28994509 2004-04-21 devnull {
66 28994509 2004-04-21 devnull ZlibR *z = va;
67 28994509 2004-04-21 devnull int nrow = z->nrow;
68 28994509 2004-04-21 devnull int ncol = z->ncol;
69 28994509 2004-04-21 devnull uchar *b = buf, *e = b+n, *img;
70 28994509 2004-04-21 devnull int i, pixels; // number of pixels in row that can be sent now
71 28994509 2004-04-21 devnull
72 28994509 2004-04-21 devnull while(b+3 <= e){ // loop over image rows
73 28994509 2004-04-21 devnull if(z->row >= nrow)
74 28994509 2004-04-21 devnull break;
75 28994509 2004-04-21 devnull if(z->col==0)
76 28994509 2004-04-21 devnull *b++ = FilterNone;
77 28994509 2004-04-21 devnull pixels = (e-b)/3;
78 28994509 2004-04-21 devnull if(pixels > ncol - z->col)
79 28994509 2004-04-21 devnull pixels = ncol - z->col;
80 28994509 2004-04-21 devnull img = z->data + z->width * z->row + 3 * z->col;
81 28994509 2004-04-21 devnull
82 28994509 2004-04-21 devnull // Plan 9 image format is BGR?!!!
83 28994509 2004-04-21 devnull // memmove(b, img, 3*pixels);
84 28994509 2004-04-21 devnull // b += 3*pixels;
85 28994509 2004-04-21 devnull for(i=0; i<pixels; i++, img += 3){
86 28994509 2004-04-21 devnull *b++ = img[2];
87 28994509 2004-04-21 devnull *b++ = img[1];
88 28994509 2004-04-21 devnull *b++ = img[0];
89 28994509 2004-04-21 devnull }
90 28994509 2004-04-21 devnull
91 28994509 2004-04-21 devnull z->col += pixels;
92 28994509 2004-04-21 devnull if(z->col >= ncol){
93 28994509 2004-04-21 devnull z->col = 0;
94 28994509 2004-04-21 devnull z->row++;
95 28994509 2004-04-21 devnull }
96 28994509 2004-04-21 devnull }
97 28994509 2004-04-21 devnull return b - (uchar*)buf;
98 28994509 2004-04-21 devnull }
99 28994509 2004-04-21 devnull
100 28994509 2004-04-21 devnull static void
101 28994509 2004-04-21 devnull IDAT(ZlibW *z)
102 28994509 2004-04-21 devnull {
103 28994509 2004-04-21 devnull chunk(z->bo, "IDAT", z->buf, z->b - z->buf);
104 28994509 2004-04-21 devnull z->b = z->buf;
105 28994509 2004-04-21 devnull }
106 28994509 2004-04-21 devnull
107 28994509 2004-04-21 devnull static int
108 28994509 2004-04-21 devnull zwrite(void *va, void *buf, int n)
109 28994509 2004-04-21 devnull {
110 28994509 2004-04-21 devnull ZlibW *z = va;
111 28994509 2004-04-21 devnull uchar *b = buf, *e = b+n;
112 28994509 2004-04-21 devnull int m;
113 28994509 2004-04-21 devnull
114 28994509 2004-04-21 devnull while(b < e){ // loop over IDAT chunks
115 28994509 2004-04-21 devnull m = z->e - z->b;
116 28994509 2004-04-21 devnull if(m > e - b)
117 28994509 2004-04-21 devnull m = e - b;
118 28994509 2004-04-21 devnull memmove(z->b, b, m);
119 28994509 2004-04-21 devnull z->b += m;
120 28994509 2004-04-21 devnull b += m;
121 28994509 2004-04-21 devnull if(z->b >= z->e)
122 28994509 2004-04-21 devnull IDAT(z);
123 28994509 2004-04-21 devnull }
124 28994509 2004-04-21 devnull return n;
125 28994509 2004-04-21 devnull }
126 28994509 2004-04-21 devnull
127 28994509 2004-04-21 devnull static Memimage*
128 28994509 2004-04-21 devnull memRGB(Memimage *i)
129 28994509 2004-04-21 devnull {
130 28994509 2004-04-21 devnull Memimage *ni;
131 28994509 2004-04-21 devnull
132 28994509 2004-04-21 devnull if(i->chan == RGB24)
133 28994509 2004-04-21 devnull return i;
134 28994509 2004-04-21 devnull
135 28994509 2004-04-21 devnull ni = allocmemimage(i->r, RGB24);
136 28994509 2004-04-21 devnull if(ni == nil)
137 28994509 2004-04-21 devnull return ni;
138 28994509 2004-04-21 devnull memimagedraw(ni, ni->r, i, i->r.min, nil, i->r.min, S);
139 28994509 2004-04-21 devnull return ni;
140 28994509 2004-04-21 devnull }
141 28994509 2004-04-21 devnull
142 28994509 2004-04-21 devnull char*
143 28994509 2004-04-21 devnull memwritepng(Biobuf *bo, Memimage *r, ImageInfo *II)
144 28994509 2004-04-21 devnull {
145 28994509 2004-04-21 devnull uchar buf[200], *h;
146 28994509 2004-04-21 devnull ulong vgamma;
147 28994509 2004-04-21 devnull int err, n;
148 28994509 2004-04-21 devnull ZlibR zr;
149 28994509 2004-04-21 devnull ZlibW zw;
150 28994509 2004-04-21 devnull int nrow = r->r.max.y - r->r.min.y;
151 28994509 2004-04-21 devnull int ncol = r->r.max.x - r->r.min.x;
152 28994509 2004-04-21 devnull Tm *tm;
153 28994509 2004-04-21 devnull Memimage *rgb;
154 28994509 2004-04-21 devnull
155 28994509 2004-04-21 devnull rgb = memRGB(r);
156 28994509 2004-04-21 devnull if(rgb == nil)
157 28994509 2004-04-21 devnull return "allocmemimage nil";
158 28994509 2004-04-21 devnull crctab = mkcrctab(0xedb88320);
159 28994509 2004-04-21 devnull if(crctab == nil)
160 28994509 2004-04-21 devnull sysfatal("mkcrctab error");
161 28994509 2004-04-21 devnull deflateinit();
162 28994509 2004-04-21 devnull
163 28994509 2004-04-21 devnull Bwrite(bo, PNGmagic, sizeof PNGmagic);
164 28994509 2004-04-21 devnull // IHDR chunk
165 28994509 2004-04-21 devnull h = buf;
166 28994509 2004-04-21 devnull put4(h, ncol); h += 4;
167 28994509 2004-04-21 devnull put4(h, nrow); h += 4;
168 28994509 2004-04-21 devnull *h++ = 8; // bit depth = 24 bit per pixel
169 28994509 2004-04-21 devnull *h++ = 2; // color type = rgb
170 28994509 2004-04-21 devnull *h++ = 0; // compression method = deflate
171 28994509 2004-04-21 devnull *h++ = 0; // filter method
172 28994509 2004-04-21 devnull *h++ = 0; // interlace method = no interlace
173 28994509 2004-04-21 devnull chunk(bo, "IHDR", buf, h-buf);
174 28994509 2004-04-21 devnull
175 28994509 2004-04-21 devnull tm = gmtime(time(0));
176 28994509 2004-04-21 devnull h = buf;
177 28994509 2004-04-21 devnull *h++ = (tm->year + 1900)>>8;
178 28994509 2004-04-21 devnull *h++ = (tm->year + 1900)&0xff;
179 28994509 2004-04-21 devnull *h++ = tm->mon + 1;
180 28994509 2004-04-21 devnull *h++ = tm->mday;
181 28994509 2004-04-21 devnull *h++ = tm->hour;
182 28994509 2004-04-21 devnull *h++ = tm->min;
183 28994509 2004-04-21 devnull *h++ = tm->sec;
184 28994509 2004-04-21 devnull chunk(bo, "tIME", buf, h-buf);
185 28994509 2004-04-21 devnull
186 28994509 2004-04-21 devnull if(II->fields_set & II_GAMMA){
187 28994509 2004-04-21 devnull vgamma = II->gamma*100000;
188 28994509 2004-04-21 devnull put4(buf, vgamma);
189 28994509 2004-04-21 devnull chunk(bo, "gAMA", buf, 4);
190 28994509 2004-04-21 devnull }
191 28994509 2004-04-21 devnull
192 28994509 2004-04-21 devnull if(II->fields_set & II_COMMENT){
193 28994509 2004-04-21 devnull strncpy((char*)buf, "Comment", sizeof buf);
194 28994509 2004-04-21 devnull n = strlen((char*)buf)+1; // leave null between Comment and text
195 28994509 2004-04-21 devnull strncpy((char*)(buf+n), II->comment, sizeof buf - n);
196 28994509 2004-04-21 devnull chunk(bo, "tEXt", buf, n+strlen((char*)buf+n));
197 28994509 2004-04-21 devnull }
198 28994509 2004-04-21 devnull
199 28994509 2004-04-21 devnull // image chunks
200 28994509 2004-04-21 devnull zr.nrow = nrow;
201 28994509 2004-04-21 devnull zr.ncol = ncol;
202 28994509 2004-04-21 devnull zr.width = rgb->width * sizeof(ulong);
203 28994509 2004-04-21 devnull zr.data = rgb->data->bdata;
204 28994509 2004-04-21 devnull zr.row = zr.col = 0;
205 28994509 2004-04-21 devnull zw.bo = bo;
206 28994509 2004-04-21 devnull zw.buf = malloc(IDATSIZE);
207 28994509 2004-04-21 devnull zw.b = zw.buf;
208 28994509 2004-04-21 devnull zw.e = zw.b + IDATSIZE;
209 28994509 2004-04-21 devnull err = deflatezlib(&zw, zwrite, &zr, zread, 6, 0);
210 28994509 2004-04-21 devnull if(zw.b > zw.buf)
211 28994509 2004-04-21 devnull IDAT(&zw);
212 28994509 2004-04-21 devnull free(zw.buf);
213 28994509 2004-04-21 devnull if(err)
214 28994509 2004-04-21 devnull sysfatal("deflatezlib %s\n", flateerr(err));
215 28994509 2004-04-21 devnull chunk(bo, "IEND", nil, 0);
216 28994509 2004-04-21 devnull
217 28994509 2004-04-21 devnull if(r != rgb)
218 28994509 2004-04-21 devnull freememimage(rgb);
219 28994509 2004-04-21 devnull return nil;
220 28994509 2004-04-21 devnull }