11 /* helper to write a little-endian 16-bit number portably */
12 #define write_num(fd, n) write((fd), (uint8_t []) {(n) & 0xFF, (n) >> 8}, 2)
16 struct Node
*children
[0x10];
18 typedef struct Node Node
;
21 new_node(uint16_t key
)
23 Node
*node
= calloc(1, sizeof(*node
));
32 Node
*root
= new_node(0);
33 /* Create nodes for single pixels. */
34 for (*nkeys
= 0; *nkeys
< 0x10; (*nkeys
)++)
35 root
->children
[*nkeys
] = new_node(*nkeys
);
36 *nkeys
+= 2; /* skip clear code and stop code */
47 for (i
= 0; i
< 0x10; i
++)
48 del_trie(root
->children
[i
]);
52 static void put_loop(GIF
*gif
, uint16_t loop
);
55 new_gif(const char *fname
, uint16_t w
, uint16_t h
, uint8_t *gct
, int loop
)
57 GIF
*gif
= calloc(1, sizeof(*gif
) + 2*w
*h
);
60 gif
->w
= w
; gif
->h
= h
;
61 gif
->cur
= (uint8_t *) &gif
[1];
62 gif
->old
= &gif
->cur
[w
*h
];
63 /* fill back-buffer with invalid pixels to force overwrite */
64 memset(gif
->old
, 0x10, w
*h
);
65 gif
->fd
= creat(fname
, 0666);
68 write(gif
->fd
, "GIF89a", 6);
69 write_num(gif
->fd
, w
);
70 write_num(gif
->fd
, h
);
71 write(gif
->fd
, (uint8_t []) {0xF3, 0x00, 0x00}, 3);
72 write(gif
->fd
, gct
, 0x30);
73 if (loop
>= 0 && loop
<= 0xFFFF)
74 put_loop(gif
, (uint16_t) loop
);
83 put_loop(GIF
*gif
, uint16_t loop
)
85 write(gif
->fd
, (uint8_t []) {'!', 0xFF, 0x0B}, 3);
86 write(gif
->fd
, "NETSCAPE2.0", 11);
87 write(gif
->fd
, (uint8_t []) {0x03, 0x01}, 2);
88 write_num(gif
->fd
, loop
);
89 write(gif
->fd
, "\0", 1);
92 /* Add packed key to buffer, updating offset and partial.
93 * gif->offset holds position to put next *bit*
94 * gif->partial holds bits to include in next byte */
96 put_key(GIF
*gif
, uint16_t key
, int key_size
)
98 int byte_offset
, bit_offset
, bits_to_write
;
99 byte_offset
= gif
->offset
/ 8;
100 bit_offset
= gif
->offset
% 8;
101 gif
->partial
|= ((uint32_t) key
) << bit_offset
;
102 bits_to_write
= bit_offset
+ key_size
;
103 while (bits_to_write
>= 8) {
104 gif
->buffer
[byte_offset
++] = gif
->partial
& 0xFF;
105 if (byte_offset
== 0xFF) {
106 write(gif
->fd
, "\xFF", 1);
107 write(gif
->fd
, gif
->buffer
, 0xFF);
113 gif
->offset
= (gif
->offset
+ key_size
) % (0xFF * 8);
120 byte_offset
= gif
->offset
/ 8;
122 gif
->buffer
[byte_offset
++] = gif
->partial
& 0xFF;
124 write(gif
->fd
, (uint8_t []) {byte_offset
}, 1);
125 write(gif
->fd
, gif
->buffer
, byte_offset
);
127 write(gif
->fd
, "\0", 1);
128 gif
->offset
= gif
->partial
= 0;
132 put_image(GIF
*gif
, uint16_t w
, uint16_t h
, uint16_t x
, uint16_t y
)
134 int nkeys
, key_size
, i
, j
;
135 Node
*node
, *child
, *root
;
136 uint8_t id_packed
= 0x00;
140 id_packed
|= 0x83; /* Local clut, 4 bits. */
143 root
= malloc(sizeof(*root
));
144 write(gif
->fd
, ",", 1);
145 write_num(gif
->fd
, x
);
146 write_num(gif
->fd
, y
);
147 write_num(gif
->fd
, w
);
148 write_num(gif
->fd
, h
);
149 write(gif
->fd
, &id_packed
, 1);
150 if (id_packed
& 0x80)
151 write(gif
->fd
, gif
->plt
, 3<<((id_packed
& 0x7)+1));
153 write(gif
->fd
, "\x04", 1); /* Min code size */
154 root
= node
= new_trie(&nkeys
);
156 put_key(gif
, 0x10, key_size
); /* clear code */
157 for (i
= y
; i
< y
+h
; i
++) {
158 for (j
= x
; j
< x
+w
; j
++) {
159 uint8_t pixel
= gif
->cur
[i
*gif
->w
+j
];
160 child
= node
->children
[pixel
];
164 put_key(gif
, node
->key
, key_size
);
165 if (nkeys
< 0x1000) {
166 if (nkeys
== (1 << key_size
))
168 node
->children
[pixel
] = new_node(nkeys
++);
170 put_key(gif
, 0x10, key_size
); /* clear code */
172 root
= node
= new_trie(&nkeys
);
175 node
= root
->children
[pixel
];
179 put_key(gif
, node
->key
, key_size
);
180 put_key(gif
, 0x11, key_size
); /* stop code */
186 get_bbox(GIF
*gif
, uint16_t *w
, uint16_t *h
, uint16_t *x
, uint16_t *y
)
189 int left
, right
, top
, bottom
;
190 left
= gif
->w
; right
= 0;
191 top
= gif
->h
; bottom
= 0;
193 for (i
= 0; i
< gif
->h
; i
++) {
194 for (j
= 0; j
< gif
->w
; j
++, k
++) {
195 if (gif
->cur
[k
] != gif
->old
[k
]) {
196 if (j
< left
) left
= j
;
197 if (j
> right
) right
= j
;
198 if (i
< top
) top
= i
;
199 if (i
> bottom
) bottom
= i
;
203 if (left
!= gif
->w
&& top
!= gif
->h
) {
205 *w
= right
- left
+ 1;
206 *h
= bottom
- top
+ 1;
214 set_delay(GIF
*gif
, uint16_t d
)
216 write(gif
->fd
, (uint8_t []) {'!', 0xF9, 0x04, 0x04}, 4);
217 write_num(gif
->fd
, d
);
218 write(gif
->fd
, "\0\0", 2);
222 add_frame(GIF
*gif
, uint16_t d
)
229 if (gif
->plt_dirty
) {
230 w
= gif
->w
; h
= gif
->h
; x
= y
= 0;
233 if (!get_bbox(gif
, &w
, &h
, &x
, &y
)) {
234 /* image's not changed; save one pixel just to add delay */
239 put_image(gif
, w
, h
, x
, y
);
248 write(gif
->fd
, ";", 1);