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)
18 static uint8_t vga
[0x30] = {
39 struct Node
*children
[];
41 typedef struct Node Node
;
44 new_node(uint16_t key
, int degree
)
46 Node
*node
= calloc(1, sizeof(*node
) + degree
* sizeof(Node
*));
53 new_trie(int degree
, int *nkeys
)
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 */
64 del_trie(Node
*root
, int degree
)
68 for (int i
= 0; i
< degree
; i
++)
69 del_trie(root
->children
[i
], degree
);
73 #define write_and_store(s, dst, fd, src, n) \
77 memcpy(dst, src, n); \
82 static void put_loop(ge_GIF
*gif
, uint16_t loop
);
86 const char *fname
, uint16_t width
, uint16_t height
,
87 uint8_t *palette
, int depth
, int bgindex
, int loop
91 int store_gct
, custom_gct
;
92 int nbuffers
= bgindex
< 0 ? 2 : 1;
93 ge_GIF
*gif
= calloc(1, sizeof(*gif
) + nbuffers
*width
*height
);
96 gif
->w
= width
; gif
->h
= height
;
97 gif
->bgindex
= bgindex
;
98 gif
->frame
= (uint8_t *) &gif
[1];
99 gif
->back
= &gif
->frame
[width
*height
];
101 gif
->fd
= creat(fname
, S_IWRITE
);
103 gif
->fd
= creat(fname
, 0666);
108 setmode(gif
->fd
, O_BINARY
);
110 write(gif
->fd
, "GIF89a", 6);
111 write_num(gif
->fd
, width
);
112 write_num(gif
->fd
, height
);
113 store_gct
= custom_gct
= 0;
122 gif
->depth
= depth
> 1 ? depth
: 2;
123 write(gif
->fd
, (uint8_t []) {0xF0 | (depth
-1), (uint8_t) bgindex
, 0x00}, 3);
125 write(gif
->fd
, palette
, 3 << depth
);
126 } else if (depth
<= 4) {
127 write_and_store(store_gct
, palette
, gif
->fd
, vga
, 3 << depth
);
129 write_and_store(store_gct
, palette
, gif
->fd
, vga
, sizeof(vga
));
131 for (r
= 0; r
< 6; r
++) {
132 for (g
= 0; g
< 6; g
++) {
133 for (b
= 0; b
< 6; b
++) {
134 write_and_store(store_gct
, palette
, gif
->fd
,
135 ((uint8_t []) {r
*51, g
*51, b
*51}), 3
137 if (++i
== 1 << depth
)
142 for (i
= 1; i
<= 24; i
++) {
144 write_and_store(store_gct
, palette
, gif
->fd
,
145 ((uint8_t []) {v
, v
, v
}), 3
150 if (loop
>= 0 && loop
<= 0xFFFF)
151 put_loop(gif
, (uint16_t) loop
);
160 put_loop(ge_GIF
*gif
, uint16_t loop
)
162 write(gif
->fd
, (uint8_t []) {'!', 0xFF, 0x0B}, 3);
163 write(gif
->fd
, "NETSCAPE2.0", 11);
164 write(gif
->fd
, (uint8_t []) {0x03, 0x01}, 2);
165 write_num(gif
->fd
, loop
);
166 write(gif
->fd
, "\0", 1);
169 /* Add packed key to buffer, updating offset and partial.
170 * gif->offset holds position to put next *bit*
171 * gif->partial holds bits to include in next byte */
173 put_key(ge_GIF
*gif
, uint16_t key
, int key_size
)
175 int byte_offset
, bit_offset
, bits_to_write
;
176 byte_offset
= gif
->offset
/ 8;
177 bit_offset
= gif
->offset
% 8;
178 gif
->partial
|= ((uint32_t) key
) << bit_offset
;
179 bits_to_write
= bit_offset
+ key_size
;
180 while (bits_to_write
>= 8) {
181 gif
->buffer
[byte_offset
++] = gif
->partial
& 0xFF;
182 if (byte_offset
== 0xFF) {
183 write(gif
->fd
, "\xFF", 1);
184 write(gif
->fd
, gif
->buffer
, 0xFF);
190 gif
->offset
= (gif
->offset
+ key_size
) % (0xFF * 8);
197 byte_offset
= gif
->offset
/ 8;
199 gif
->buffer
[byte_offset
++] = gif
->partial
& 0xFF;
201 write(gif
->fd
, (uint8_t []) {byte_offset
}, 1);
202 write(gif
->fd
, gif
->buffer
, byte_offset
);
204 write(gif
->fd
, "\0", 1);
205 gif
->offset
= gif
->partial
= 0;
209 put_image(ge_GIF
*gif
, uint16_t w
, uint16_t h
, uint16_t x
, uint16_t y
)
211 int nkeys
, key_size
, i
, j
;
212 Node
*node
, *child
, *root
;
213 int degree
= 1 << gif
->depth
;
215 write(gif
->fd
, ",", 1);
216 write_num(gif
->fd
, x
);
217 write_num(gif
->fd
, y
);
218 write_num(gif
->fd
, w
);
219 write_num(gif
->fd
, h
);
220 write(gif
->fd
, (uint8_t []) {0x00, gif
->depth
}, 2);
221 root
= node
= new_trie(degree
, &nkeys
);
222 key_size
= gif
->depth
+ 1;
223 put_key(gif
, degree
, key_size
); /* clear code */
224 for (i
= y
; i
< y
+h
; i
++) {
225 for (j
= x
; j
< x
+w
; j
++) {
226 uint8_t pixel
= gif
->frame
[i
*gif
->w
+j
] & (degree
- 1);
227 child
= node
->children
[pixel
];
231 put_key(gif
, node
->key
, key_size
);
232 if (nkeys
< 0x1000) {
233 if (nkeys
== (1 << key_size
))
235 node
->children
[pixel
] = new_node(nkeys
++, degree
);
237 put_key(gif
, degree
, key_size
); /* clear code */
238 del_trie(root
, degree
);
239 root
= node
= new_trie(degree
, &nkeys
);
240 key_size
= gif
->depth
+ 1;
242 node
= root
->children
[pixel
];
246 put_key(gif
, node
->key
, key_size
);
247 put_key(gif
, degree
+ 1, key_size
); /* stop code */
249 del_trie(root
, degree
);
253 get_bbox(ge_GIF
*gif
, uint16_t *w
, uint16_t *h
, uint16_t *x
, uint16_t *y
)
256 int left
, right
, top
, bottom
;
258 left
= gif
->w
; right
= 0;
259 top
= gif
->h
; bottom
= 0;
261 for (i
= 0; i
< gif
->h
; i
++) {
262 for (j
= 0; j
< gif
->w
; j
++, k
++) {
263 back
= gif
->bgindex
>= 0 ? gif
->bgindex
: gif
->back
[k
];
264 if (gif
->frame
[k
] != back
) {
265 if (j
< left
) left
= j
;
266 if (j
> right
) right
= j
;
267 if (i
< top
) top
= i
;
268 if (i
> bottom
) bottom
= i
;
272 if (left
!= gif
->w
&& top
!= gif
->h
) {
274 *w
= right
- left
+ 1;
275 *h
= bottom
- top
+ 1;
283 add_graphics_control_extension(ge_GIF
*gif
, uint16_t d
)
285 uint8_t flags
= ((gif
->bgindex
>= 0 ? 2 : 1) << 2) + 1;
286 write(gif
->fd
, (uint8_t []) {'!', 0xF9, 0x04, flags
}, 4);
287 write_num(gif
->fd
, d
);
288 write(gif
->fd
, (uint8_t []) {(uint8_t) gif
->bgindex
, 0x00}, 2);
292 ge_add_frame(ge_GIF
*gif
, uint16_t delay
)
297 if (delay
|| (gif
->bgindex
>= 0))
298 add_graphics_control_extension(gif
, delay
);
299 if (gif
->nframes
== 0) {
303 } else if (!get_bbox(gif
, &w
, &h
, &x
, &y
)) {
304 /* image's not changed; save one pixel just to add delay */
308 put_image(gif
, w
, h
, x
, y
);
310 if (gif
->bgindex
< 0) {
312 gif
->back
= gif
->frame
;
318 ge_close_gif(ge_GIF
* gif
)
320 write(gif
->fd
, ";", 1);