Blame


1 28994509 2004-04-21 devnull #include <u.h>
2 28994509 2004-04-21 devnull #include <libc.h>
3 28994509 2004-04-21 devnull #include <draw.h>
4 28994509 2004-04-21 devnull #include <memdraw.h>
5 28994509 2004-04-21 devnull #include <bio.h>
6 28994509 2004-04-21 devnull #include "imagefile.h"
7 28994509 2004-04-21 devnull
8 28994509 2004-04-21 devnull enum
9 28994509 2004-04-21 devnull {
10 28994509 2004-04-21 devnull Nhash = 4001,
11 cbeb0b26 2006-04-01 devnull Nbuf = 300
12 28994509 2004-04-21 devnull };
13 28994509 2004-04-21 devnull
14 28994509 2004-04-21 devnull typedef struct Entry Entry;
15 28994509 2004-04-21 devnull typedef struct IO IO;
16 28994509 2004-04-21 devnull
17 28994509 2004-04-21 devnull
18 28994509 2004-04-21 devnull struct Entry
19 28994509 2004-04-21 devnull {
20 28994509 2004-04-21 devnull int index;
21 28994509 2004-04-21 devnull int prefix;
22 28994509 2004-04-21 devnull int exten;
23 28994509 2004-04-21 devnull Entry *next;
24 28994509 2004-04-21 devnull };
25 28994509 2004-04-21 devnull
26 28994509 2004-04-21 devnull struct IO
27 28994509 2004-04-21 devnull {
28 28994509 2004-04-21 devnull Biobuf *fd;
29 28994509 2004-04-21 devnull uchar buf[Nbuf];
30 28994509 2004-04-21 devnull int i;
31 28994509 2004-04-21 devnull int nbits; /* bits in right side of shift register */
32 28994509 2004-04-21 devnull int sreg; /* shift register */
33 28994509 2004-04-21 devnull };
34 28994509 2004-04-21 devnull
35 28994509 2004-04-21 devnull static Rectangle mainrect;
36 28994509 2004-04-21 devnull static Entry tbl[4096];
37 28994509 2004-04-21 devnull static uchar *colormap[5]; /* one for each ldepth: GREY1 GREY2 GREY4 CMAP8=rgbv plus GREY8 */
38 28994509 2004-04-21 devnull #define GREYMAP 4
39 28994509 2004-04-21 devnull static int colormapsize[] = { 2, 4, 16, 256, 256 }; /* 2 for zero is an odd property of GIF */
40 28994509 2004-04-21 devnull
41 28994509 2004-04-21 devnull static void writeheader(Biobuf*, Rectangle, int, ulong, int);
42 28994509 2004-04-21 devnull static void writedescriptor(Biobuf*, Rectangle);
43 28994509 2004-04-21 devnull static char* writedata(Biobuf*, Image*, Memimage*);
44 28994509 2004-04-21 devnull static void writecomment(Biobuf *fd, char*);
45 28994509 2004-04-21 devnull static void writegraphiccontrol(Biobuf *fd, int, int);
46 28994509 2004-04-21 devnull static void* gifmalloc(ulong);
47 28994509 2004-04-21 devnull static void encode(Biobuf*, Rectangle, int, uchar*, uint);
48 28994509 2004-04-21 devnull
49 28994509 2004-04-21 devnull static
50 28994509 2004-04-21 devnull char*
51 28994509 2004-04-21 devnull startgif0(Biobuf *fd, ulong chan, Rectangle r, int depth, int loopcount)
52 28994509 2004-04-21 devnull {
53 28994509 2004-04-21 devnull int i;
54 28994509 2004-04-21 devnull
55 840bb968 2004-04-25 devnull for(i=0; i<nelem(tbl); i++){
56 840bb968 2004-04-25 devnull tbl[i].index = i;
57 840bb968 2004-04-25 devnull tbl[i].prefix = -1;
58 840bb968 2004-04-25 devnull tbl[i].exten = i;
59 840bb968 2004-04-25 devnull }
60 28994509 2004-04-21 devnull
61 28994509 2004-04-21 devnull switch(chan){
62 28994509 2004-04-21 devnull case GREY1:
63 28994509 2004-04-21 devnull case GREY2:
64 28994509 2004-04-21 devnull case GREY4:
65 28994509 2004-04-21 devnull case CMAP8:
66 28994509 2004-04-21 devnull case GREY8:
67 28994509 2004-04-21 devnull break;
68 28994509 2004-04-21 devnull default:
69 28994509 2004-04-21 devnull return "WriteGIF: can't handle channel type";
70 28994509 2004-04-21 devnull }
71 28994509 2004-04-21 devnull
72 28994509 2004-04-21 devnull mainrect = r;
73 28994509 2004-04-21 devnull writeheader(fd, r, depth, chan, loopcount);
74 28994509 2004-04-21 devnull return nil;
75 28994509 2004-04-21 devnull }
76 28994509 2004-04-21 devnull
77 28994509 2004-04-21 devnull char*
78 28994509 2004-04-21 devnull startgif(Biobuf *fd, Image *image, int loopcount)
79 28994509 2004-04-21 devnull {
80 28994509 2004-04-21 devnull return startgif0(fd, image->chan, image->r, image->depth, loopcount);
81 28994509 2004-04-21 devnull }
82 28994509 2004-04-21 devnull
83 28994509 2004-04-21 devnull char*
84 28994509 2004-04-21 devnull memstartgif(Biobuf *fd, Memimage *memimage, int loopcount)
85 28994509 2004-04-21 devnull {
86 28994509 2004-04-21 devnull return startgif0(fd, memimage->chan, memimage->r, memimage->depth, loopcount);
87 28994509 2004-04-21 devnull }
88 28994509 2004-04-21 devnull
89 28994509 2004-04-21 devnull static
90 28994509 2004-04-21 devnull char*
91 28994509 2004-04-21 devnull writegif0(Biobuf *fd, Image *image, Memimage *memimage, ulong chan, Rectangle r, char *comment, int dt, int trans)
92 28994509 2004-04-21 devnull {
93 28994509 2004-04-21 devnull char *err;
94 28994509 2004-04-21 devnull
95 28994509 2004-04-21 devnull switch(chan){
96 28994509 2004-04-21 devnull case GREY1:
97 28994509 2004-04-21 devnull case GREY2:
98 28994509 2004-04-21 devnull case GREY4:
99 28994509 2004-04-21 devnull case CMAP8:
100 28994509 2004-04-21 devnull case GREY8:
101 28994509 2004-04-21 devnull break;
102 28994509 2004-04-21 devnull default:
103 28994509 2004-04-21 devnull return "WriteGIF: can't handle channel type";
104 28994509 2004-04-21 devnull }
105 28994509 2004-04-21 devnull
106 28994509 2004-04-21 devnull writecomment(fd, comment);
107 28994509 2004-04-21 devnull writegraphiccontrol(fd, dt, trans);
108 28994509 2004-04-21 devnull writedescriptor(fd, r);
109 28994509 2004-04-21 devnull
110 28994509 2004-04-21 devnull err = writedata(fd, image, memimage);
111 28994509 2004-04-21 devnull if(err != nil)
112 28994509 2004-04-21 devnull return err;
113 28994509 2004-04-21 devnull
114 28994509 2004-04-21 devnull return nil;
115 28994509 2004-04-21 devnull }
116 28994509 2004-04-21 devnull
117 28994509 2004-04-21 devnull char*
118 28994509 2004-04-21 devnull writegif(Biobuf *fd, Image *image, char *comment, int dt, int trans)
119 28994509 2004-04-21 devnull {
120 28994509 2004-04-21 devnull return writegif0(fd, image, nil, image->chan, image->r, comment, dt, trans);
121 28994509 2004-04-21 devnull }
122 28994509 2004-04-21 devnull
123 28994509 2004-04-21 devnull char*
124 28994509 2004-04-21 devnull memwritegif(Biobuf *fd, Memimage *memimage, char *comment, int dt, int trans)
125 28994509 2004-04-21 devnull {
126 28994509 2004-04-21 devnull return writegif0(fd, nil, memimage, memimage->chan, memimage->r, comment, dt, trans);
127 28994509 2004-04-21 devnull }
128 28994509 2004-04-21 devnull
129 28994509 2004-04-21 devnull /*
130 28994509 2004-04-21 devnull * Write little-endian 16-bit integer
131 28994509 2004-04-21 devnull */
132 28994509 2004-04-21 devnull static
133 28994509 2004-04-21 devnull void
134 28994509 2004-04-21 devnull put2(Biobuf *fd, int i)
135 28994509 2004-04-21 devnull {
136 28994509 2004-04-21 devnull Bputc(fd, i);
137 28994509 2004-04-21 devnull Bputc(fd, i>>8);
138 28994509 2004-04-21 devnull }
139 28994509 2004-04-21 devnull
140 28994509 2004-04-21 devnull /*
141 28994509 2004-04-21 devnull * Get color map for all ldepths, in format suitable for writing out
142 28994509 2004-04-21 devnull */
143 28994509 2004-04-21 devnull static
144 28994509 2004-04-21 devnull void
145 28994509 2004-04-21 devnull getcolormap(void)
146 28994509 2004-04-21 devnull {
147 28994509 2004-04-21 devnull int i, col;
148 28994509 2004-04-21 devnull ulong rgb;
149 28994509 2004-04-21 devnull uchar *c;
150 28994509 2004-04-21 devnull
151 28994509 2004-04-21 devnull if(colormap[0] != nil)
152 28994509 2004-04-21 devnull return;
153 28994509 2004-04-21 devnull for(i=0; i<nelem(colormap); i++)
154 28994509 2004-04-21 devnull colormap[i] = gifmalloc(3* colormapsize[i]);
155 28994509 2004-04-21 devnull c = colormap[GREYMAP]; /* GREY8 */
156 28994509 2004-04-21 devnull for(i=0; i<256; i++){
157 28994509 2004-04-21 devnull c[3*i+0] = i; /* red */
158 28994509 2004-04-21 devnull c[3*i+1] = i; /* green */
159 28994509 2004-04-21 devnull c[3*i+2] = i; /* blue */
160 28994509 2004-04-21 devnull }
161 28994509 2004-04-21 devnull c = colormap[3]; /* RGBV */
162 28994509 2004-04-21 devnull for(i=0; i<256; i++){
163 28994509 2004-04-21 devnull rgb = cmap2rgb(i);
164 28994509 2004-04-21 devnull c[3*i+0] = (rgb>>16) & 0xFF; /* red */
165 28994509 2004-04-21 devnull c[3*i+1] = (rgb>> 8) & 0xFF; /* green */
166 28994509 2004-04-21 devnull c[3*i+2] = (rgb>> 0) & 0xFF; /* blue */
167 28994509 2004-04-21 devnull }
168 28994509 2004-04-21 devnull c = colormap[2]; /* GREY4 */
169 28994509 2004-04-21 devnull for(i=0; i<16; i++){
170 28994509 2004-04-21 devnull col = (i<<4)|i;
171 28994509 2004-04-21 devnull rgb = cmap2rgb(col);
172 28994509 2004-04-21 devnull c[3*i+0] = (rgb>>16) & 0xFF; /* red */
173 28994509 2004-04-21 devnull c[3*i+1] = (rgb>> 8) & 0xFF; /* green */
174 28994509 2004-04-21 devnull c[3*i+2] = (rgb>> 0) & 0xFF; /* blue */
175 28994509 2004-04-21 devnull }
176 28994509 2004-04-21 devnull c = colormap[1]; /* GREY2 */
177 28994509 2004-04-21 devnull for(i=0; i<4; i++){
178 28994509 2004-04-21 devnull col = (i<<6)|(i<<4)|(i<<2)|i;
179 28994509 2004-04-21 devnull rgb = cmap2rgb(col);
180 28994509 2004-04-21 devnull c[3*i+0] = (rgb>>16) & 0xFF; /* red */
181 28994509 2004-04-21 devnull c[3*i+1] = (rgb>> 8) & 0xFF; /* green */
182 28994509 2004-04-21 devnull c[3*i+2] = (rgb>> 0) & 0xFF; /* blue */
183 28994509 2004-04-21 devnull }
184 28994509 2004-04-21 devnull c = colormap[0]; /* GREY1 */
185 28994509 2004-04-21 devnull for(i=0; i<2; i++){
186 28994509 2004-04-21 devnull if(i == 0)
187 28994509 2004-04-21 devnull col = 0;
188 28994509 2004-04-21 devnull else
189 28994509 2004-04-21 devnull col = 0xFF;
190 28994509 2004-04-21 devnull rgb = cmap2rgb(col);
191 28994509 2004-04-21 devnull c[3*i+0] = (rgb>>16) & 0xFF; /* red */
192 28994509 2004-04-21 devnull c[3*i+1] = (rgb>> 8) & 0xFF; /* green */
193 28994509 2004-04-21 devnull c[3*i+2] = (rgb>> 0) & 0xFF; /* blue */
194 28994509 2004-04-21 devnull }
195 28994509 2004-04-21 devnull }
196 28994509 2004-04-21 devnull
197 28994509 2004-04-21 devnull /*
198 28994509 2004-04-21 devnull * Write header, logical screen descriptor, and color map
199 28994509 2004-04-21 devnull */
200 28994509 2004-04-21 devnull static
201 28994509 2004-04-21 devnull void
202 28994509 2004-04-21 devnull writeheader(Biobuf *fd, Rectangle r, int depth, ulong chan, int loopcount)
203 28994509 2004-04-21 devnull {
204 28994509 2004-04-21 devnull /* Header */
205 28994509 2004-04-21 devnull Bprint(fd, "%s", "GIF89a");
206 28994509 2004-04-21 devnull
207 28994509 2004-04-21 devnull /* Logical Screen Descriptor */
208 28994509 2004-04-21 devnull put2(fd, Dx(r));
209 28994509 2004-04-21 devnull put2(fd, Dy(r));
210 28994509 2004-04-21 devnull
211 28994509 2004-04-21 devnull /* Color table present, 4 bits per color (for RGBV best case), size of color map */
212 28994509 2004-04-21 devnull Bputc(fd, (1<<7)|(3<<4)|(depth-1)); /* not right for GREY8, but GIF doesn't let us specify enough bits */
213 28994509 2004-04-21 devnull Bputc(fd, 0xFF); /* white background (doesn't matter anyway) */
214 28994509 2004-04-21 devnull Bputc(fd, 0); /* pixel aspect ratio - unused */
215 28994509 2004-04-21 devnull
216 28994509 2004-04-21 devnull /* Global Color Table */
217 28994509 2004-04-21 devnull getcolormap();
218 28994509 2004-04-21 devnull if(chan == GREY8)
219 28994509 2004-04-21 devnull depth = GREYMAP;
220 28994509 2004-04-21 devnull else
221 28994509 2004-04-21 devnull depth = drawlog2[depth];
222 28994509 2004-04-21 devnull Bwrite(fd, colormap[depth], 3*colormapsize[depth]);
223 28994509 2004-04-21 devnull
224 28994509 2004-04-21 devnull if(loopcount >= 0){ /* hard-to-discover way to force cycled animation */
225 28994509 2004-04-21 devnull /* Application Extension with (1 loopcountlo loopcounthi) as data */
226 28994509 2004-04-21 devnull Bputc(fd, 0x21);
227 28994509 2004-04-21 devnull Bputc(fd, 0xFF);
228 28994509 2004-04-21 devnull Bputc(fd, 11);
229 28994509 2004-04-21 devnull Bwrite(fd, "NETSCAPE2.0", 11);
230 28994509 2004-04-21 devnull Bputc(fd, 3);
231 28994509 2004-04-21 devnull Bputc(fd, 1);
232 28994509 2004-04-21 devnull put2(fd, loopcount);
233 28994509 2004-04-21 devnull Bputc(fd, 0);
234 28994509 2004-04-21 devnull }
235 28994509 2004-04-21 devnull }
236 28994509 2004-04-21 devnull
237 28994509 2004-04-21 devnull /*
238 28994509 2004-04-21 devnull * Write optional comment block
239 28994509 2004-04-21 devnull */
240 28994509 2004-04-21 devnull static
241 28994509 2004-04-21 devnull void
242 28994509 2004-04-21 devnull writecomment(Biobuf *fd, char *comment)
243 28994509 2004-04-21 devnull {
244 28994509 2004-04-21 devnull int n;
245 28994509 2004-04-21 devnull
246 28994509 2004-04-21 devnull if(comment==nil || comment[0]=='\0')
247 28994509 2004-04-21 devnull return;
248 28994509 2004-04-21 devnull
249 28994509 2004-04-21 devnull /* Comment extension and label */
250 28994509 2004-04-21 devnull Bputc(fd, 0x21);
251 28994509 2004-04-21 devnull Bputc(fd, 0xFE);
252 28994509 2004-04-21 devnull
253 28994509 2004-04-21 devnull /* Comment data */
254 28994509 2004-04-21 devnull n = strlen(comment);
255 28994509 2004-04-21 devnull if(n > 255)
256 28994509 2004-04-21 devnull n = 255;
257 28994509 2004-04-21 devnull Bputc(fd, n);
258 28994509 2004-04-21 devnull Bwrite(fd, comment, n);
259 28994509 2004-04-21 devnull
260 28994509 2004-04-21 devnull /* Block terminator */
261 28994509 2004-04-21 devnull Bputc(fd, 0x00);
262 28994509 2004-04-21 devnull }
263 28994509 2004-04-21 devnull
264 28994509 2004-04-21 devnull /*
265 28994509 2004-04-21 devnull * Write optional control block (sets Delay Time)
266 28994509 2004-04-21 devnull */
267 28994509 2004-04-21 devnull static
268 28994509 2004-04-21 devnull void
269 28994509 2004-04-21 devnull writegraphiccontrol(Biobuf *fd, int dt, int trans)
270 28994509 2004-04-21 devnull {
271 28994509 2004-04-21 devnull if(dt < 0 && trans < 0)
272 28994509 2004-04-21 devnull return;
273 28994509 2004-04-21 devnull
274 28994509 2004-04-21 devnull /* Comment extension and label and block size*/
275 28994509 2004-04-21 devnull Bputc(fd, 0x21);
276 28994509 2004-04-21 devnull Bputc(fd, 0xF9);
277 28994509 2004-04-21 devnull Bputc(fd, 0x04);
278 28994509 2004-04-21 devnull
279 28994509 2004-04-21 devnull /* Disposal method and other flags (none) */
280 28994509 2004-04-21 devnull if(trans >= 0)
281 28994509 2004-04-21 devnull Bputc(fd, 0x01);
282 28994509 2004-04-21 devnull else
283 28994509 2004-04-21 devnull Bputc(fd, 0x00);
284 28994509 2004-04-21 devnull
285 28994509 2004-04-21 devnull /* Delay time, in centisec (argument is millisec for sanity) */
286 28994509 2004-04-21 devnull if(dt < 0)
287 28994509 2004-04-21 devnull dt = 0;
288 28994509 2004-04-21 devnull else if(dt < 10)
289 28994509 2004-04-21 devnull dt = 1;
290 28994509 2004-04-21 devnull else
291 28994509 2004-04-21 devnull dt = (dt+5)/10;
292 28994509 2004-04-21 devnull put2(fd, dt);
293 28994509 2004-04-21 devnull
294 28994509 2004-04-21 devnull /* Transparency index */
295 28994509 2004-04-21 devnull if(trans < 0)
296 28994509 2004-04-21 devnull trans = 0;
297 28994509 2004-04-21 devnull Bputc(fd, trans);
298 28994509 2004-04-21 devnull
299 28994509 2004-04-21 devnull /* Block terminator */
300 28994509 2004-04-21 devnull Bputc(fd, 0x00);
301 28994509 2004-04-21 devnull }
302 28994509 2004-04-21 devnull
303 28994509 2004-04-21 devnull /*
304 28994509 2004-04-21 devnull * Write image descriptor
305 28994509 2004-04-21 devnull */
306 28994509 2004-04-21 devnull static
307 28994509 2004-04-21 devnull void
308 28994509 2004-04-21 devnull writedescriptor(Biobuf *fd, Rectangle r)
309 28994509 2004-04-21 devnull {
310 28994509 2004-04-21 devnull /* Image Separator */
311 28994509 2004-04-21 devnull Bputc(fd, 0x2C);
312 28994509 2004-04-21 devnull
313 28994509 2004-04-21 devnull /* Left, top, width, height */
314 28994509 2004-04-21 devnull put2(fd, r.min.x-mainrect.min.x);
315 28994509 2004-04-21 devnull put2(fd, r.min.y-mainrect.min.y);
316 28994509 2004-04-21 devnull put2(fd, Dx(r));
317 28994509 2004-04-21 devnull put2(fd, Dy(r));
318 28994509 2004-04-21 devnull /* no special processing */
319 28994509 2004-04-21 devnull Bputc(fd, 0);
320 28994509 2004-04-21 devnull }
321 28994509 2004-04-21 devnull
322 28994509 2004-04-21 devnull /*
323 28994509 2004-04-21 devnull * Write data
324 28994509 2004-04-21 devnull */
325 28994509 2004-04-21 devnull static
326 28994509 2004-04-21 devnull char*
327 28994509 2004-04-21 devnull writedata(Biobuf *fd, Image *image, Memimage *memimage)
328 28994509 2004-04-21 devnull {
329 28994509 2004-04-21 devnull char *err;
330 28994509 2004-04-21 devnull uchar *data;
331 28994509 2004-04-21 devnull int ndata, depth;
332 28994509 2004-04-21 devnull Rectangle r;
333 28994509 2004-04-21 devnull
334 28994509 2004-04-21 devnull if(memimage != nil){
335 28994509 2004-04-21 devnull r = memimage->r;
336 28994509 2004-04-21 devnull depth = memimage->depth;
337 28994509 2004-04-21 devnull }else{
338 28994509 2004-04-21 devnull r = image->r;
339 28994509 2004-04-21 devnull depth = image->depth;
340 28994509 2004-04-21 devnull }
341 28994509 2004-04-21 devnull
342 28994509 2004-04-21 devnull /* LZW Minimum code size */
343 28994509 2004-04-21 devnull if(depth == 1)
344 28994509 2004-04-21 devnull Bputc(fd, 2);
345 28994509 2004-04-21 devnull else
346 28994509 2004-04-21 devnull Bputc(fd, depth);
347 28994509 2004-04-21 devnull
348 28994509 2004-04-21 devnull /*
349 28994509 2004-04-21 devnull * Read image data into memory
350 28994509 2004-04-21 devnull * potentially one extra byte on each end of each scan line
351 28994509 2004-04-21 devnull */
352 28994509 2004-04-21 devnull ndata = Dy(r)*(2+(Dx(r)>>(3-drawlog2[depth])));
353 28994509 2004-04-21 devnull data = gifmalloc(ndata);
354 28994509 2004-04-21 devnull if(memimage != nil)
355 28994509 2004-04-21 devnull ndata = unloadmemimage(memimage, r, data, ndata);
356 28994509 2004-04-21 devnull else
357 28994509 2004-04-21 devnull ndata = unloadimage(image, r, data, ndata);
358 28994509 2004-04-21 devnull if(ndata < 0){
359 28994509 2004-04-21 devnull err = gifmalloc(ERRMAX);
360 28994509 2004-04-21 devnull snprint(err, ERRMAX, "WriteGIF: %r");
361 28994509 2004-04-21 devnull free(data);
362 28994509 2004-04-21 devnull return err;
363 28994509 2004-04-21 devnull }
364 28994509 2004-04-21 devnull
365 28994509 2004-04-21 devnull /* Encode and emit the data */
366 28994509 2004-04-21 devnull encode(fd, r, depth, data, ndata);
367 28994509 2004-04-21 devnull free(data);
368 28994509 2004-04-21 devnull
369 28994509 2004-04-21 devnull /* Block Terminator */
370 28994509 2004-04-21 devnull Bputc(fd, 0);
371 28994509 2004-04-21 devnull return nil;
372 28994509 2004-04-21 devnull }
373 28994509 2004-04-21 devnull
374 28994509 2004-04-21 devnull /*
375 28994509 2004-04-21 devnull * Write trailer
376 28994509 2004-04-21 devnull */
377 28994509 2004-04-21 devnull void
378 28994509 2004-04-21 devnull endgif(Biobuf *fd)
379 28994509 2004-04-21 devnull {
380 28994509 2004-04-21 devnull Bputc(fd, 0x3B);
381 28994509 2004-04-21 devnull Bflush(fd);
382 28994509 2004-04-21 devnull }
383 28994509 2004-04-21 devnull
384 28994509 2004-04-21 devnull void
385 28994509 2004-04-21 devnull memendgif(Biobuf *fd)
386 28994509 2004-04-21 devnull {
387 28994509 2004-04-21 devnull endgif(fd);
388 28994509 2004-04-21 devnull }
389 28994509 2004-04-21 devnull
390 28994509 2004-04-21 devnull /*
391 28994509 2004-04-21 devnull * Put n bits of c into output at io.buf[i];
392 28994509 2004-04-21 devnull */
393 28994509 2004-04-21 devnull static
394 28994509 2004-04-21 devnull void
395 28994509 2004-04-21 devnull output(IO *io, int c, int n)
396 28994509 2004-04-21 devnull {
397 28994509 2004-04-21 devnull if(c < 0){
398 28994509 2004-04-21 devnull if(io->nbits != 0)
399 28994509 2004-04-21 devnull io->buf[io->i++] = io->sreg;
400 28994509 2004-04-21 devnull Bputc(io->fd, io->i);
401 28994509 2004-04-21 devnull Bwrite(io->fd, io->buf, io->i);
402 28994509 2004-04-21 devnull io->nbits = 0;
403 28994509 2004-04-21 devnull return;
404 28994509 2004-04-21 devnull }
405 28994509 2004-04-21 devnull
406 28994509 2004-04-21 devnull if(io->nbits+n >= 31){
407 28994509 2004-04-21 devnull fprint(2, "panic: WriteGIF sr overflow\n");
408 28994509 2004-04-21 devnull exits("WriteGIF panic");
409 28994509 2004-04-21 devnull }
410 28994509 2004-04-21 devnull io->sreg |= c<<io->nbits;
411 28994509 2004-04-21 devnull io->nbits += n;
412 28994509 2004-04-21 devnull
413 28994509 2004-04-21 devnull while(io->nbits >= 8){
414 28994509 2004-04-21 devnull io->buf[io->i++] = io->sreg;
415 28994509 2004-04-21 devnull io->sreg >>= 8;
416 28994509 2004-04-21 devnull io->nbits -= 8;
417 28994509 2004-04-21 devnull }
418 28994509 2004-04-21 devnull
419 28994509 2004-04-21 devnull if(io->i >= 255){
420 28994509 2004-04-21 devnull Bputc(io->fd, 255);
421 28994509 2004-04-21 devnull Bwrite(io->fd, io->buf, 255);
422 28994509 2004-04-21 devnull memmove(io->buf, io->buf+255, io->i-255);
423 28994509 2004-04-21 devnull io->i -= 255;
424 28994509 2004-04-21 devnull }
425 28994509 2004-04-21 devnull }
426 28994509 2004-04-21 devnull
427 28994509 2004-04-21 devnull /*
428 28994509 2004-04-21 devnull * LZW encoder
429 28994509 2004-04-21 devnull */
430 28994509 2004-04-21 devnull static
431 28994509 2004-04-21 devnull void
432 28994509 2004-04-21 devnull encode(Biobuf *fd, Rectangle r, int depth, uchar *data, uint ndata)
433 28994509 2004-04-21 devnull {
434 28994509 2004-04-21 devnull int i, c, h, csize, prefix, first, sreg, nbits, bitsperpixel;
435 28994509 2004-04-21 devnull int CTM, EOD, codesize, ld0, datai, x, ld, pm;
436 28994509 2004-04-21 devnull int nentry, maxentry, early;
437 28994509 2004-04-21 devnull Entry *e, *oe;
438 28994509 2004-04-21 devnull IO *io;
439 28994509 2004-04-21 devnull Entry **hash;
440 28994509 2004-04-21 devnull
441 28994509 2004-04-21 devnull first = 1;
442 28994509 2004-04-21 devnull ld = drawlog2[depth];
443 28994509 2004-04-21 devnull /* ldepth 0 must generate codesize 2 with values 0 and 1 (see the spec.) */
444 28994509 2004-04-21 devnull ld0 = ld;
445 28994509 2004-04-21 devnull if(ld0 == 0)
446 28994509 2004-04-21 devnull ld0 = 1;
447 28994509 2004-04-21 devnull codesize = (1<<ld0);
448 28994509 2004-04-21 devnull CTM = 1<<codesize;
449 28994509 2004-04-21 devnull EOD = CTM+1;
450 28994509 2004-04-21 devnull
451 28994509 2004-04-21 devnull io = gifmalloc(sizeof(IO));
452 28994509 2004-04-21 devnull io->fd = fd;
453 28994509 2004-04-21 devnull sreg = 0;
454 28994509 2004-04-21 devnull nbits = 0;
455 28994509 2004-04-21 devnull bitsperpixel = 1<<ld;
456 28994509 2004-04-21 devnull pm = (1<<bitsperpixel)-1;
457 28994509 2004-04-21 devnull
458 28994509 2004-04-21 devnull datai = 0;
459 28994509 2004-04-21 devnull x = r.min.x;
460 28994509 2004-04-21 devnull hash = gifmalloc(Nhash*sizeof(Entry*));
461 28994509 2004-04-21 devnull
462 28994509 2004-04-21 devnull Init:
463 28994509 2004-04-21 devnull memset(hash, 0, Nhash*sizeof(Entry*));
464 28994509 2004-04-21 devnull csize = codesize+1;
465 28994509 2004-04-21 devnull nentry = EOD+1;
466 28994509 2004-04-21 devnull maxentry = (1<<csize);
467 28994509 2004-04-21 devnull for(i = 0; i<nentry; i++){
468 28994509 2004-04-21 devnull e = &tbl[i];
469 28994509 2004-04-21 devnull h = (e->prefix<<24) | (e->exten<<8);
470 28994509 2004-04-21 devnull h %= Nhash;
471 28994509 2004-04-21 devnull if(h < 0)
472 28994509 2004-04-21 devnull h += Nhash;
473 28994509 2004-04-21 devnull e->next = hash[h];
474 28994509 2004-04-21 devnull hash[h] = e;
475 28994509 2004-04-21 devnull }
476 28994509 2004-04-21 devnull prefix = -1;
477 28994509 2004-04-21 devnull if(first)
478 28994509 2004-04-21 devnull output(io, CTM, csize);
479 28994509 2004-04-21 devnull first = 0;
480 28994509 2004-04-21 devnull
481 28994509 2004-04-21 devnull /*
482 28994509 2004-04-21 devnull * Scan over pixels. Because of partially filled bytes on ends of scan lines,
483 28994509 2004-04-21 devnull * which must be ignored in the data stream passed to GIF, this is more
484 28994509 2004-04-21 devnull * complex than we'd like.
485 28994509 2004-04-21 devnull */
486 28994509 2004-04-21 devnull Next:
487 28994509 2004-04-21 devnull for(;;){
488 28994509 2004-04-21 devnull if(ld != 3){
489 28994509 2004-04-21 devnull /* beginning of scan line is difficult; prime the shift register */
490 28994509 2004-04-21 devnull if(x == r.min.x){
491 28994509 2004-04-21 devnull if(datai == ndata)
492 28994509 2004-04-21 devnull break;
493 28994509 2004-04-21 devnull sreg = data[datai++];
494 28994509 2004-04-21 devnull nbits = 8-((x&(7>>ld))<<ld);
495 28994509 2004-04-21 devnull }
496 28994509 2004-04-21 devnull x++;
497 28994509 2004-04-21 devnull if(x == r.max.x)
498 28994509 2004-04-21 devnull x = r.min.x;
499 28994509 2004-04-21 devnull }
500 28994509 2004-04-21 devnull if(nbits == 0){
501 28994509 2004-04-21 devnull if(datai == ndata)
502 28994509 2004-04-21 devnull break;
503 28994509 2004-04-21 devnull sreg = data[datai++];
504 28994509 2004-04-21 devnull nbits = 8;
505 28994509 2004-04-21 devnull }
506 28994509 2004-04-21 devnull nbits -= bitsperpixel;
507 28994509 2004-04-21 devnull c = sreg>>nbits & pm;
508 28994509 2004-04-21 devnull h = prefix<<24 | c<<8;
509 28994509 2004-04-21 devnull h %= Nhash;
510 28994509 2004-04-21 devnull if(h < 0)
511 28994509 2004-04-21 devnull h += Nhash;
512 28994509 2004-04-21 devnull oe = nil;
513 28994509 2004-04-21 devnull for(e = hash[h]; e!=nil; e=e->next){
514 28994509 2004-04-21 devnull if(e->prefix == prefix && e->exten == c){
515 28994509 2004-04-21 devnull if(oe != nil){
516 28994509 2004-04-21 devnull oe->next = e->next;
517 28994509 2004-04-21 devnull e->next = hash[h];
518 28994509 2004-04-21 devnull hash[h] = e;
519 28994509 2004-04-21 devnull }
520 28994509 2004-04-21 devnull prefix = e->index;
521 28994509 2004-04-21 devnull goto Next;
522 28994509 2004-04-21 devnull }
523 28994509 2004-04-21 devnull oe = e;
524 28994509 2004-04-21 devnull }
525 28994509 2004-04-21 devnull
526 28994509 2004-04-21 devnull output(io, prefix, csize);
527 28994509 2004-04-21 devnull early = 0; /* peculiar tiff feature here for reference */
528 28994509 2004-04-21 devnull if(nentry == maxentry-early){
529 28994509 2004-04-21 devnull if(csize == 12){
530 28994509 2004-04-21 devnull nbits += bitsperpixel; /* unget pixel */
531 28994509 2004-04-21 devnull x--;
532 28994509 2004-04-21 devnull if(ld != 3 && x == r.min.x)
533 28994509 2004-04-21 devnull datai--;
534 28994509 2004-04-21 devnull output(io, CTM, csize);
535 28994509 2004-04-21 devnull goto Init;
536 28994509 2004-04-21 devnull }
537 28994509 2004-04-21 devnull csize++;
538 28994509 2004-04-21 devnull maxentry = (1<<csize);
539 28994509 2004-04-21 devnull }
540 28994509 2004-04-21 devnull
541 28994509 2004-04-21 devnull e = &tbl[nentry];
542 28994509 2004-04-21 devnull e->prefix = prefix;
543 28994509 2004-04-21 devnull e->exten = c;
544 28994509 2004-04-21 devnull e->next = hash[h];
545 28994509 2004-04-21 devnull hash[h] = e;
546 28994509 2004-04-21 devnull
547 28994509 2004-04-21 devnull prefix = c;
548 28994509 2004-04-21 devnull nentry++;
549 28994509 2004-04-21 devnull }
550 28994509 2004-04-21 devnull
551 28994509 2004-04-21 devnull output(io, prefix, csize);
552 28994509 2004-04-21 devnull output(io, EOD, csize);
553 28994509 2004-04-21 devnull output(io, -1, csize);
554 28994509 2004-04-21 devnull free(io);
555 28994509 2004-04-21 devnull free(hash);
556 28994509 2004-04-21 devnull }
557 28994509 2004-04-21 devnull
558 28994509 2004-04-21 devnull static
559 28994509 2004-04-21 devnull void*
560 28994509 2004-04-21 devnull gifmalloc(ulong sz)
561 28994509 2004-04-21 devnull {
562 28994509 2004-04-21 devnull void *v;
563 28994509 2004-04-21 devnull v = malloc(sz);
564 28994509 2004-04-21 devnull if(v == nil) {
565 28994509 2004-04-21 devnull fprint(2, "WriteGIF: out of memory allocating %ld\n", sz);
566 28994509 2004-04-21 devnull abort();
567 28994509 2004-04-21 devnull exits("mem");
568 28994509 2004-04-21 devnull }
569 28994509 2004-04-21 devnull memset(v, 0, sz);
570 28994509 2004-04-21 devnull return v;
571 28994509 2004-04-21 devnull }