3 * Image handling tools, (c) AJK 2001-2005
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
36 unsigned char const bbc[] = {
37 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
38 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x00, // !
39 0x6C, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00, // "
40 0x36, 0x36, 0x7F, 0x36, 0x7F, 0x36, 0x36, 0x00, // #
41 0x0C, 0x3F, 0x68, 0x3E, 0x0B, 0x7E, 0x18, 0x00, // $
42 0x60, 0x66, 0x0C, 0x18, 0x30, 0x66, 0x06, 0x00, // %
43 0x38, 0x6C, 0x6C, 0x38, 0x6D, 0x66, 0x3B, 0x00, // &
44 0x0C, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, // '
45 0x0C, 0x18, 0x30, 0x30, 0x30, 0x18, 0x0C, 0x00, // (
46 0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x18, 0x30, 0x00, // )
47 0x00, 0x18, 0x7E, 0x3C, 0x7E, 0x18, 0x00, 0x00, // *
48 0x00, 0x18, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x00, // +
49 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, // ,
50 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00, // -
51 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, // .
52 0x00, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x00, 0x00, // /
53 0x18, 0x24, 0x66, 0x66, 0x66, 0x24, 0x18, 0x00, // 0 (non crossed)
54 0x18, 0x38, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x00, // 1
55 0x3C, 0x66, 0x06, 0x0C, 0x18, 0x30, 0x7E, 0x00, // 2
56 0x3C, 0x66, 0x06, 0x1C, 0x06, 0x66, 0x3C, 0x00, // 3
57 0x0C, 0x1C, 0x3C, 0x6C, 0x7E, 0x0C, 0x0C, 0x00, // 4
58 0x7E, 0x60, 0x7C, 0x06, 0x06, 0x66, 0x3C, 0x00, // 5
59 0x1C, 0x30, 0x60, 0x7C, 0x66, 0x66, 0x3C, 0x00, // 6
60 0x7E, 0x06, 0x0C, 0x18, 0x30, 0x30, 0x30, 0x00, // 7
61 0x3C, 0x66, 0x66, 0x3C, 0x66, 0x66, 0x3C, 0x00, // 8
62 0x3C, 0x66, 0x66, 0x3E, 0x06, 0x0C, 0x38, 0x00, // 9
63 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, // :
64 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x30, // ;
65 0x0C, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0C, 0x00, // <
66 0x00, 0x00, 0x7E, 0x00, 0x7E, 0x00, 0x00, 0x00, // =
67 0x30, 0x18, 0x0C, 0x06, 0x0C, 0x18, 0x30, 0x00, // >
68 0x3C, 0x66, 0x0C, 0x18, 0x18, 0x00, 0x18, 0x00, // ?
69 0x3C, 0x66, 0x6E, 0x6A, 0x6E, 0x60, 0x3C, 0x00, // @
70 0x3C, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x66, 0x00, // A
71 0x7C, 0x66, 0x66, 0x7C, 0x66, 0x66, 0x7C, 0x00, // B
72 0x3C, 0x66, 0x60, 0x60, 0x60, 0x66, 0x3C, 0x00, // C
73 0x78, 0x6C, 0x66, 0x66, 0x66, 0x6C, 0x78, 0x00, // D
74 0x7E, 0x60, 0x60, 0x7C, 0x60, 0x60, 0x7E, 0x00, // E
75 0x7E, 0x60, 0x60, 0x7C, 0x60, 0x60, 0x60, 0x00, // F
76 0x3C, 0x66, 0x60, 0x6E, 0x66, 0x66, 0x3C, 0x00, // G
77 0x66, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x66, 0x00, // H
78 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x00, // I
79 0x3E, 0x0C, 0x0C, 0x0C, 0x0C, 0x6C, 0x38, 0x00, // J
80 0x66, 0x6C, 0x78, 0x70, 0x78, 0x6C, 0x66, 0x00, // K
81 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x7E, 0x00, // L
82 0x63, 0x77, 0x7F, 0x6B, 0x6B, 0x63, 0x63, 0x00, // M
83 0x66, 0x66, 0x76, 0x7E, 0x6E, 0x66, 0x66, 0x00, // N
84 0x3C, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00, // O
85 0x7C, 0x66, 0x66, 0x7C, 0x60, 0x60, 0x60, 0x00, // P
86 0x3C, 0x66, 0x66, 0x66, 0x6A, 0x6C, 0x36, 0x00, // Q
87 0x7C, 0x66, 0x66, 0x7C, 0x6C, 0x66, 0x66, 0x00, // R
88 0x3C, 0x66, 0x60, 0x3C, 0x06, 0x66, 0x3C, 0x00, // S
89 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, // T
90 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00, // U
91 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x00, // V
92 0x63, 0x63, 0x6B, 0x6B, 0x7F, 0x77, 0x63, 0x00, // W
93 0x66, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x66, 0x00, // X
94 0x66, 0x66, 0x66, 0x3C, 0x18, 0x18, 0x18, 0x00, // Y
95 0x7E, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x7E, 0x00, // Z
96 0x7C, 0x60, 0x60, 0x60, 0x60, 0x60, 0x7C, 0x00, // [
97 0x00, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x00, 0x00, //
98 0x3E, 0x06, 0x06, 0x06, 0x06, 0x06, 0x3E, 0x00, // ]
99 0x18, 0x3C, 0x66, 0x42, 0x00, 0x00, 0x00, 0x00, // ^
100 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, // _
101 0x1C, 0x36, 0x30, 0x7C, 0x30, 0x30, 0x7E, 0x00, // `
102 0x00, 0x00, 0x3C, 0x06, 0x3E, 0x66, 0x3E, 0x00, // a
103 0x60, 0x60, 0x7C, 0x66, 0x66, 0x66, 0x7C, 0x00, // b
104 0x00, 0x00, 0x3C, 0x66, 0x60, 0x66, 0x3C, 0x00, // c
105 0x06, 0x06, 0x3E, 0x66, 0x66, 0x66, 0x3E, 0x00, // d
106 0x00, 0x00, 0x3C, 0x66, 0x7E, 0x60, 0x3C, 0x00, // e
107 0x1C, 0x30, 0x30, 0x7C, 0x30, 0x30, 0x30, 0x00, // f
108 0x00, 0x00, 0x3E, 0x66, 0x66, 0x3E, 0x06, 0x3C, // g
109 0x60, 0x60, 0x7C, 0x66, 0x66, 0x66, 0x66, 0x00, // h
110 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x3C, 0x00, // i
111 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x70, // j
112 0x60, 0x60, 0x66, 0x6C, 0x78, 0x6C, 0x66, 0x00, // k
113 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, // l
114 0x00, 0x00, 0x36, 0x7F, 0x6B, 0x6B, 0x63, 0x00, // m
115 0x00, 0x00, 0x7C, 0x66, 0x66, 0x66, 0x66, 0x00, // n
116 0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x00, // o
117 0x00, 0x00, 0x7C, 0x66, 0x66, 0x7C, 0x60, 0x60, // p
118 0x00, 0x00, 0x3E, 0x66, 0x66, 0x3E, 0x06, 0x07, // q
119 0x00, 0x00, 0x6C, 0x76, 0x60, 0x60, 0x60, 0x00, // r
120 0x00, 0x00, 0x3E, 0x60, 0x3C, 0x06, 0x7C, 0x00, // s
121 0x30, 0x30, 0x7C, 0x30, 0x30, 0x30, 0x1C, 0x00, // t
122 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3E, 0x00, // u
123 0x00, 0x00, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x00, // v
124 0x00, 0x00, 0x63, 0x6B, 0x6B, 0x7F, 0x36, 0x00, // w
125 0x00, 0x00, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x00, // x
126 0x00, 0x00, 0x66, 0x66, 0x66, 0x3E, 0x06, 0x3C, // y
127 0x00, 0x00, 0x7E, 0x0C, 0x18, 0x30, 0x7E, 0x00, // z
128 0x0C, 0x18, 0x18, 0x70, 0x18, 0x18, 0x0C, 0x00, // {
129 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00, // |
130 0x30, 0x18, 0x18, 0x0E, 0x18, 0x18, 0x30, 0x00, // }
131 0x31, 0x6B, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, // ~
132 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, //
135 const char smallc[] = " 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-+&()/[];%";
136 unsigned char const small[] = {
138 0x1F, 0x11, 0x1F, //0
139 0x11, 0x1F, 0x10, //1
140 0x1D, 0x15, 0x17, //2
141 0x11, 0x15, 0x1F, //3
142 0x07, 0x04, 0x1F, //4
143 0x17, 0x15, 0x1D, //5
144 0x1F, 0x15, 0x1D, //6
145 0x01, 0x01, 0x1F, //7
146 0x1F, 0x15, 0x1F, //8
147 0x17, 0x15, 0x1F, //9
148 0x1E, 0x05, 0x1E, //A
149 0x1F, 0x15, 0x0A, //B
150 0x0E, 0x11, 0x11, //C
151 0x1F, 0x11, 0x0E, //D
152 0x1F, 0x15, 0x11, //E
153 0x1F, 0x05, 0x01, //F
154 0x0E, 0x11, 0x19, //G
155 0x1F, 0x04, 0x1F, //H
156 0x11, 0x1F, 0x11, //I
157 0x11, 0x0F, 0x01, //J
158 0x1F, 0x04, 0x1B, //K
159 0x1F, 0x10, 0x10, //L
160 0x1F, 0x03, 0x1F, //M
161 0x1F, 0x01, 0x1F, //N
162 0x0E, 0x11, 0x0E, //O
163 0x1F, 0x05, 0x02, //P
164 0x0E, 0x19, 0x1E, //Q
165 0x1F, 0x05, 0x1A, //R
166 0x12, 0x15, 0x09, //S
167 0x01, 0x1F, 0x01, //T
168 0x1F, 0x10, 0x1F, //U
169 0x0F, 0x10, 0x0F, //V
170 0x1F, 0x18, 0x1F, //W
171 0x1B, 0x04, 0x1B, //X
172 0x03, 0x1C, 0x03, //Y
173 0x19, 0x15, 0x13, //Z
174 0x04, 0x04, 0x04, //-
175 0x04, 0x0E, 0x04, //+
176 0x04, 0x0E, 0x04, //& (+)
177 0x00, 0x0E, 0x11, //(
178 0x11, 0x0E, 0x00, //)
179 0x08, 0x04, 0x02, ///
180 0x00, 0x1F, 0x11, //[
181 0x11, 0x1F, 0x00, //]
182 0x10, 0x0A, 0x00, //;
183 0x09, 0x04, 0x12, //%
186 Image * ImageNew (int w, int h, int c)
187 { // create a new blank image
191 i = malloc (sizeof (*i));
194 memset (i, 0, sizeof (*i));
199 i->Image = malloc ((w + 1) * h);
205 memset (i->Image, 0, (w + 1) * h);
208 i->Colour = malloc (sizeof (Colour) * c);
215 memset (i->Colour, 0, sizeof (Colour) * c);
220 void ImageFree (Image * i)
233 typedef short LZW[256];
234 typedef LZW LZWTree[MAXLZW];
235 typedef struct strPrivate
237 int cols; // number of colours, power of 2
238 unsigned char colbits; // number of bits for colours
239 int fh; // file handle
240 int lzwnext; // next code
241 int lzwlast; // last code in current bit size
242 int lzwbits; // current bit size
243 LZWTree lzw; // encode tree
244 unsigned char block[256]; // block so far, with count at start
245 int blockv; // pending value
246 int blockb; // bits used in pending value
247 short lzwcode; // which code we are on now
251 static LZWFlush (Private * p)
252 { // flush this block
253 write (p->fh, p->block, *p->block + 1);
257 static LZWOut (Private * p, short v)
259 p->blockv |= (v << p->blockb);
260 p->blockb += p->lzwbits;
261 while (p->blockb >= 8)
263 p->block[++*p->block] = p->blockv; // last partial byte
266 if (*p->block == 255)
271 static LZWClear (Private * p)
274 p->lzwbits = p->colbits + 1;
275 p->lzwnext = p->cols + 2;
276 p->lzwlast = (1 << p->lzwbits) - 1;
277 p->lzwcode = p->cols; // starting point
278 for (c = 0; c < p->cols; c++)
280 p->lzw[p->cols][c] = c; // links to literal entries
281 // links from literals, dead ends initially
282 memset (&p->lzw[c], -1, p->cols * 2);
286 static ImageStart (Private * p)
288 unsigned char b = p->colbits;
289 write (p->fh, &b, 1);
294 LZWOut (p, p->cols); // clear code
297 static ImageEnd (Private * p)
299 LZWOut (p, p->lzwcode); // last prefix
300 LZWOut (p, p->cols + 1); // end code
302 p->block[++*p->block] = p->blockv; // last partial byte
306 static ImageOut (Private * p, unsigned char c)
308 short next = p->lzw[p->lzwcode][c];
311 LZWOut (p, p->lzwcode); // prefix
313 if (p->lzwnext + 1 == MAXLZW)
315 LZWOut (p, p->cols); // clear code
319 if (p->lzwnext < MAXLZW)
321 memset (p->lzw[p->lzwnext], -1, p->cols * 2); // init dead ends
322 p->lzw[p->lzwcode][c] = p->lzwnext;
323 if (p->lzwnext > p->lzwlast)
326 p->lzwlast = (1 << p->lzwbits) - 1;
332 p->lzwcode = next; // not a dead end
336 void ImageWriteGif (Image * i, int fh, int back, int trans, char *comment)
340 // count colours, min 4
341 for (p.colbits = 2, p.cols = 4; p.cols < i->C; p.cols *= 2, p.colbits++);
345 strcpy (buf, "GIF87a");
347 if (comment || trans >= 0)
349 buf[4] = '9'; // needs gif89 format
351 buf[n++] = (i->W & 255);
352 buf[n++] = (i->W >> 8);
353 buf[n++] = (i->H & 255);
354 buf[n++] = (i->H >> 8);
355 buf[n++] = (i->Colour ? 0x80 : 0) + 0x70 + (p.colbits - 1);
356 buf[n++] = back; // background
357 buf[n++] = 0; // aspect
361 for (c = 0; c < p.cols; c++)
365 buf[n++] = (i->Colour[c] >> 16 & 255);
366 buf[n++] = (i->Colour[c] >> 8 & 255);
367 buf[n++] = (i->Colour[c] & 255);
369 { // extra, unused, colour
377 if (comment && strlen (comment) < 256)
379 buf[n++] = 0x21; //extension
380 buf[n++] = 0xFE; //comment
381 buf[n++] = strlen (comment);
382 strcpy (buf + n, comment);
384 buf[n++] = 0; // end of block
388 buf[n++] = 0x21; // extension
389 buf[n++] = 0xF9; // graphic control
391 buf[n++] = 1; // transparrent
392 buf[n++] = 0; // delay
395 buf[n++] = 0; // terminator
399 buf[n++] = 0; // offset X
401 buf[n++] = 0; // offset Y
403 buf[n++] = (i->W & 255);
404 buf[n++] = (i->W >> 8);
405 buf[n++] = (i->H & 255);
406 buf[n++] = (i->H >> 8);
408 buf[n++] = 0x40; // interlaced, no local colour table
410 buf[n++] = 0x00; // non interlaced, no local colour table
421 for (y = 0; y < i->H; y += 8)
422 for (b = &ImagePixel (i, 0, y), x = 0; x < i->W; x++)
424 for (y = 4; y < i->H; y += 8)
425 for (b = &ImagePixel (i, 0, y), x = 0; x < i->W; x++)
427 for (y = 2; y < i->H; y += 4)
428 for (b = &ImagePixel (i, 0, y), x = 0; x < i->W; x++)
430 for (y = 1; y < i->H; y += 2)
431 for (b = &ImagePixel (i, 0, y), x = 0; x < i->W; x++)
434 for (y = 0; y < i->H; y++)
435 for (b = &ImagePixel (i, 0, y), x = 0; x < i->W; x++)
440 write (fh, "\0", 1); // end of image data
441 write (fh, "\x3B", 1); // trailer
444 void ImageText (Image * i, int x, int y, int col, char *text)
449 if (*text >= ' ' && *text)
452 unsigned const char *b = bbc + (*text - ' ') * 8;
453 for (r = 0; r < 8; r++)
455 unsigned char v = *b++;
456 unsigned char *p = &ImagePixel (i, x, y + r);
458 for (m = 0x80; m; m >>= 1, p++)
468 void ImageSmall (Image * i, int x, int y, int col, char *text)
469 { // writes 4x6 digits
473 char *p = strchr (smallc, toupper (*text));
478 unsigned const char *b = small + (p - smallc) * 3;
479 for (r = 0; r < 5; r++)
482 for (c = 0; c < 3; c++)
484 ImagePixel (i, x + c, y + r) = col;
488 } else if (*text == '.')
490 ImagePixel (i, x, y + 4) = col;
492 } else if (*text == ':')
494 ImagePixel (i, x, y + 1) = col;
495 ImagePixel (i, x, y + 3) = col;
502 void ImageRect (Image * i, int x, int y, int w, int h, int c)
508 unsigned char *p = &ImagePixel (i, x, y);
519 /* Table of CRCs of all 8-bit messages. */
520 static unsigned int crc_table[256];
522 /* Make the table for a fast CRC. */
523 void make_crc_table (void)
528 for (n = 0; n < 256; n++)
530 c = (unsigned int) n;
531 for (k = 0; k < 8; k++)
534 c = 0xedb88320L ^ (c >> 1);
542 /* Update a running CRC with the bytes buf[0..len-1]--the CRC
543 should be initialized to all 1's, and the transmitted value
544 is the 1's complement of the final running CRC (see the
545 crc() routine below)). */
547 unsigned int update_crc (unsigned int crc, unsigned char *buf, int len)
549 unsigned int c = crc;
552 for (n = 0; n < len; n++)
553 c = crc_table[(c ^ buf[n]) & 0xff] ^ (c >> 8);
558 /* Return the CRC of the bytes buf[0..len-1]. */
559 unsigned int crc (unsigned char *buf, int len)
561 return update_crc (0xffffffffL, buf, len) ^ 0xffffffffL;
564 unsigned int writecrc (int fh, char *ptr, int len, unsigned int c)
566 write (fh, ptr, len);
568 c = crc_table[(c ^ *ptr++) & 0xff] ^ (c >> 8);
572 void writechunk (int fh, char *typ, void *ptr, int len)
574 unsigned int v = htonl (len),
577 crc = writecrc (fh, typ, 4, ~0);
579 crc = writecrc (fh, ptr, len, crc);
585 unsigned int adlersum (unsigned char *p, int l, unsigned int adler)
587 unsigned int s1 = (adler & 65535),
594 s1 %= 65521; // can be delayed due to sensible "l" values...
596 return (s2 << 16) + s1;
601 void ImageWritePNG (Image * i, int fh, int back, int trans, char *comment)
604 write (fh, "\211PNG\r\n\032\n", 8); // PNG header
611 unsigned char colour;
612 unsigned char compress;
613 unsigned char filter;
614 unsigned char interlace;
619 ihdr.width = htonl (i->W);
620 ihdr.height = htonl (i->H);
621 writechunk (fh, "IHDR", &ihdr, 13);
624 unsigned int v = htonl (i->C * 3),
628 crc = writecrc (fh, "PLTE", 4, ~0);
629 for (n = 0; n < i->C; n++)
631 v = htonl (i->Colour[n] << 8);
632 crc = writecrc (fh, (void *) &v, 3, crc);
639 unsigned char b = back;
640 writechunk (fh, "bKGD", &b, 1);
644 char c[] = "Comment";
645 unsigned int v = htonl (strlen (c) + strlen (comment) + 1),
648 crc = writecrc (fh, "tEXt", 4, ~0);
649 crc = writecrc (fh, c, strlen (c) + 1, crc);
650 crc = writecrc (fh, comment, strlen (comment), crc);
655 unsigned char alpha[256];
657 for (n = 0; n < i->C; n++)
658 // 4th palette byte treated as 0=opaque, 255-transparren
659 alpha[n] = 255 - (i->Colour[n] >> 24);
660 if (trans >= 0 && trans < i->C)
661 // manual set of specific transparrent colour
663 writechunk (fh, "tRNS", alpha, i->C);
667 unsigned int v = htonl (i->H * (i->L + 5) + 6),
671 unsigned char *p = i->Image;
673 crc = writecrc (fh, "IDAT", 4, ~0);
674 crc = writecrc (fh, "\170\001", 2, crc); // zlib header for deflate
679 h[0] = (n ? 0 : 1); // last chunk in deflate, un compressed
680 h[1] = (i->L & 255); // Len, LSB first as per deflate spec
682 h[3] = ~(i->L & 255); // Inverse of Len
683 h[4] = ~(i->L / 256);
684 *p = 0; // filter 0 (NONE)
685 crc = writecrc (fh, h, 5, crc);
686 crc = writecrc (fh, p, i->L, crc);
687 adler = adlersum (p, i->L, adler);
691 crc = writecrc (fh, (void *) &v, 4, crc);
699 for (n = 0; n < i->H; n++)
700 i->Image[n * i->L] = 0; // filter 0
701 n = i->H * i->L * 1001 / 1000 + 12;
703 if (compress2 (temp, &n, i->Image, i->L * i->H, 9) != Z_OK)
704 fprintf (stderr, "Deflate error\n");
706 writechunk (fh, "IDAT", temp, n);
710 writechunk (fh, "IEND", 0, 0); // IEND