1 #include "gifenc.h"
2 
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <sys/types.h>
7 #include <sys/stat.h>
8 #include <fcntl.h>
9 #ifdef _WIN32
10 #include <io.h>
11 #else
12 #include <unistd.h>
13 #endif
14 
15 /* helper to write a little-endian 16-bit number portably */
16 #define write_num(fd, n) write((fd), (uint8_t []) {(n) & 0xFF, (n) >> 8}, 2)
17 
18 static uint8_t vga[0x30] = {
19     0x00, 0x00, 0x00,
20     0xAA, 0x00, 0x00,
21     0x00, 0xAA, 0x00,
22     0xAA, 0x55, 0x00,
23     0x00, 0x00, 0xAA,
24     0xAA, 0x00, 0xAA,
25     0x00, 0xAA, 0xAA,
26     0xAA, 0xAA, 0xAA,
27     0x55, 0x55, 0x55,
28     0xFF, 0x55, 0x55,
29     0x55, 0xFF, 0x55,
30     0xFF, 0xFF, 0x55,
31     0x55, 0x55, 0xFF,
32     0xFF, 0x55, 0xFF,
33     0x55, 0xFF, 0xFF,
34     0xFF, 0xFF, 0xFF,
35 };
36 
37 struct Node {
38     uint16_t key;
39     struct Node *children[];
40 };
41 typedef struct Node Node;
42 
43 static Node *
new_node(uint16_t key,int degree)44 new_node(uint16_t key, int degree)
45 {
46     Node *node = calloc(1, sizeof(*node) + degree * sizeof(Node *));
47     if (node)
48         node->key = key;
49     return node;
50 }
51 
52 static Node *
new_trie(int degree,int * nkeys)53 new_trie(int degree, int *nkeys)
54 {
55     Node *root = new_node(0, degree);
56     /* Create nodes for single pixels. */
57     for (*nkeys = 0; *nkeys < degree; (*nkeys)++)
58         root->children[*nkeys] = new_node(*nkeys, degree);
59     *nkeys += 2; /* skip clear code and stop code */
60     return root;
61 }
62 
63 static void
del_trie(Node * root,int degree)64 del_trie(Node *root, int degree)
65 {
66   int i;
67     if (!root)
68         return;
69     for (i = 0; i < degree; i++)
70         del_trie(root->children[i], degree);
71     free(root);
72 }
73 
74 static void put_loop(ge_GIF *gif, uint16_t loop);
75 
76 ge_GIF *
ge_new_gif(const char * fname,uint16_t width,uint16_t height,uint8_t * palette,int depth,int loop)77 ge_new_gif(
78     const char *fname, uint16_t width, uint16_t height,
79     uint8_t *palette, int depth, int loop
80 )
81 {
82     int i, r, g, b, v;
83     ge_GIF *gif = calloc(1, sizeof(*gif) + 2*width*height);
84     if (!gif)
85         goto no_gif;
86     gif->w = width; gif->h = height;
87     gif->depth = depth > 1 ? depth : 2;
88     gif->frame = (uint8_t *) &gif[1];
89     gif->back = &gif->frame[width*height];
90     gif->fd = creat(fname, 0666);
91     if (gif->fd == -1)
92         goto no_fd;
93 #ifdef _WIN32
94     setmode(gif->fd, O_BINARY);
95 #endif
96     write(gif->fd, "GIF89a", 6);
97     write_num(gif->fd, width);
98     write_num(gif->fd, height);
99     write(gif->fd, (uint8_t []) {0xF0 | (depth-1), 0x00, 0x00}, 3);
100     if (palette) {
101         write(gif->fd, palette, 3 << depth);
102     } else if (depth <= 4) {
103         write(gif->fd, vga, 3 << depth);
104     } else {
105         write(gif->fd, vga, sizeof(vga));
106         i = 0x10;
107         for (r = 0; r < 6; r++) {
108             for (g = 0; g < 6; g++) {
109                 for (b = 0; b < 6; b++) {
110                     write(gif->fd, (uint8_t []) {r*51, g*51, b*51}, 3);
111                     if (++i == 1 << depth)
112                         goto done_gct;
113                 }
114             }
115         }
116         for (i = 1; i <= 24; i++) {
117             v = i * 0xFF / 25;
118             write(gif->fd, (uint8_t []) {v, v, v}, 3);
119         }
120     }
121 done_gct:
122     if (loop >= 0 && loop <= 0xFFFF)
123         put_loop(gif, (uint16_t) loop);
124     return gif;
125 no_fd:
126     free(gif);
127 no_gif:
128     return NULL;
129 }
130 
131 static void
put_loop(ge_GIF * gif,uint16_t loop)132 put_loop(ge_GIF *gif, uint16_t loop)
133 {
134     write(gif->fd, (uint8_t []) {'!', 0xFF, 0x0B}, 3);
135     write(gif->fd, "NETSCAPE2.0", 11);
136     write(gif->fd, (uint8_t []) {0x03, 0x01}, 2);
137     write_num(gif->fd, loop);
138     write(gif->fd, "\0", 1);
139 }
140 
141 /* Add packed key to buffer, updating offset and partial.
142  *   gif->offset holds position to put next *bit*
143  *   gif->partial holds bits to include in next byte */
144 static void
put_key(ge_GIF * gif,uint16_t key,int key_size)145 put_key(ge_GIF *gif, uint16_t key, int key_size)
146 {
147     int byte_offset, bit_offset, bits_to_write;
148     byte_offset = gif->offset / 8;
149     bit_offset = gif->offset % 8;
150     gif->partial |= ((uint32_t) key) << bit_offset;
151     bits_to_write = bit_offset + key_size;
152     while (bits_to_write >= 8) {
153         gif->buffer[byte_offset++] = gif->partial & 0xFF;
154         if (byte_offset == 0xFF) {
155             write(gif->fd, "\xFF", 1);
156             write(gif->fd, gif->buffer, 0xFF);
157             byte_offset = 0;
158         }
159         gif->partial >>= 8;
160         bits_to_write -= 8;
161     }
162     gif->offset = (gif->offset + key_size) % (0xFF * 8);
163 }
164 
165 static void
end_key(ge_GIF * gif)166 end_key(ge_GIF *gif)
167 {
168     int byte_offset;
169     byte_offset = gif->offset / 8;
170     if (gif->offset % 8)
171         gif->buffer[byte_offset++] = gif->partial & 0xFF;
172     write(gif->fd, (uint8_t []) {byte_offset}, 1);
173     write(gif->fd, gif->buffer, byte_offset);
174     write(gif->fd, "\0", 1);
175     gif->offset = gif->partial = 0;
176 }
177 
178 static void
put_image(ge_GIF * gif,uint16_t w,uint16_t h,uint16_t x,uint16_t y)179 put_image(ge_GIF *gif, uint16_t w, uint16_t h, uint16_t x, uint16_t y)
180 {
181     int nkeys, key_size, i, j;
182     Node *node, *child, *root;
183     int degree = 1 << gif->depth;
184 
185     write(gif->fd, ",", 1);
186     write_num(gif->fd, x);
187     write_num(gif->fd, y);
188     write_num(gif->fd, w);
189     write_num(gif->fd, h);
190     write(gif->fd, (uint8_t []) {0x00, gif->depth}, 2);
191     root = node = new_trie(degree, &nkeys);
192     key_size = gif->depth + 1;
193     put_key(gif, degree, key_size); /* clear code */
194     for (i = y; i < y+h; i++) {
195         for (j = x; j < x+w; j++) {
196             uint8_t pixel = gif->frame[i*gif->w+j] & (degree - 1);
197             child = node->children[pixel];
198             if (child) {
199                 node = child;
200             } else {
201                 put_key(gif, node->key, key_size);
202                 if (nkeys < 0x1000) {
203                     if (nkeys == (1 << key_size))
204                         key_size++;
205                     node->children[pixel] = new_node(nkeys++, degree);
206                 } else {
207                     put_key(gif, degree, key_size); /* clear code */
208                     del_trie(root, degree);
209                     root = node = new_trie(degree, &nkeys);
210                     key_size = gif->depth + 1;
211                 }
212                 node = root->children[pixel];
213             }
214         }
215     }
216     put_key(gif, node->key, key_size);
217     put_key(gif, degree + 1, key_size); /* stop code */
218     end_key(gif);
219     del_trie(root, degree);
220 }
221 
222 static int
get_bbox(ge_GIF * gif,uint16_t * w,uint16_t * h,uint16_t * x,uint16_t * y)223 get_bbox(ge_GIF *gif, uint16_t *w, uint16_t *h, uint16_t *x, uint16_t *y)
224 {
225     int i, j, k;
226     int left, right, top, bottom;
227     left = gif->w; right = 0;
228     top = gif->h; bottom = 0;
229     k = 0;
230     for (i = 0; i < gif->h; i++) {
231         for (j = 0; j < gif->w; j++, k++) {
232             if (gif->frame[k] != gif->back[k]) {
233                 if (j < left)   left    = j;
234                 if (j > right)  right   = j;
235                 if (i < top)    top     = i;
236                 if (i > bottom) bottom  = i;
237             }
238         }
239     }
240     if (left != gif->w && top != gif->h) {
241         *x = left; *y = top;
242         *w = right - left + 1;
243         *h = bottom - top + 1;
244         return 1;
245     } else {
246         return 0;
247     }
248 }
249 
250 /* (From the docs)
251  * The `delay` parameter  specifies how long the frame will  be shown, in hundreths
252  * of a second. For example, `delay` ==  100 means "show this frame for one second"
253  * and `delay` == 25  means "show this frame for a quarter of  a second". Note that
254  * short delays may not be supported by  some GIF viewers: it's recommended to keep
255  * a minimum of `delay` == 6. If `delay` == 0, no delay information  will be stored
256  * for the frame. This can be used when creating still (single-frame) GIF images.
257  */
258 static void
set_delay(ge_GIF * gif,uint16_t d)259 set_delay(ge_GIF *gif, uint16_t d)
260 {
261     write(gif->fd, (uint8_t []) {'!', 0xF9, 0x04, 0x04}, 4);
262     write_num(gif->fd, d);
263     write(gif->fd, "\0\0", 2);
264 }
265 
266 void
ge_add_frame(ge_GIF * gif,uint16_t delay)267 ge_add_frame(ge_GIF *gif, uint16_t delay)
268 {
269     uint16_t w, h, x, y;
270     uint8_t *tmp;
271 
272     if (delay)
273         set_delay(gif, delay);
274     if (gif->nframes == 0) {
275         w = gif->w;
276         h = gif->h;
277         x = y = 0;
278     } else if (!get_bbox(gif, &w, &h, &x, &y)) {
279         /* image's not changed; save one pixel just to add delay */
280         w = h = 1;
281         x = y = 0;
282     }
283     put_image(gif, w, h, x, y);
284     gif->nframes++;
285     tmp = gif->back;
286     gif->back = gif->frame;
287     gif->frame = tmp;
288 }
289 
290 void
ge_close_gif(ge_GIF * gif)291 ge_close_gif(ge_GIF* gif)
292 {
293     write(gif->fd, ";", 1);
294     close(gif->fd);
295     free(gif);
296 }
297