]> git.sur5r.net Git - iec16022/blob - image.c
Imported Upstream version 0.1
[iec16022] / image.c
1 /** 
2  *
3  * Image handling tools, (c) AJK 2001-2005
4  *
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.
9  *
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.
14  *
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
18  *
19  */ 
20
21
22 #include <stdio.h>
23 #include <malloc.h>
24 #include <string.h>
25 #include <ctype.h>
26 #include "image.h"
27
28 #define INTERLACE
29 #define CLEAR
30 #define USEZLIB
31
32 #ifdef USEZLIB
33 #include <zlib.h>
34 #endif
35
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,      //
133 };
134
135 const char smallc[] = " 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-+&()/[];%";
136 unsigned char const small[] = {
137    0x00, 0x00, 0x00,            //
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,            //%
184 };
185
186 Image *
187 ImageNew (int w, int h, int c)
188 {                               // create a new blank image
189    Image *i;
190    if (!w || !h)
191       return 0;
192    i = malloc (sizeof (*i));
193    if (!i)
194       return 0;
195    memset (i, 0, sizeof (*i));
196    i->W = w;
197    i->L = w + 1;
198    i->H = h;
199    i->C = c;
200    i->Image = malloc ((w + 1) * h);
201    if (!i->Image)
202    {
203       free (i);
204       return 0;
205    }
206    memset (i->Image, 0, (w + 1) * h);
207    if (c)
208    {
209       i->Colour = malloc (sizeof (Colour) * c);
210       if (!i->Colour)
211       {
212          free (i->Image);
213          free (i);
214          return 0;
215       }
216       memset (i->Colour, 0, sizeof (Colour) * c);
217    }
218    return i;
219 }
220
221 void
222 ImageFree (Image * i)
223 {                               // free an image
224    if (i)
225    {
226       if (i->Image)
227          free (i->Image);
228       if (i->Colour)
229          free (i->Colour);
230       free (i);
231    }
232 }
233
234 #define MAXLZW  4096
235 typedef short LZW[256];
236 typedef LZW LZWTree[MAXLZW];
237 typedef struct strPrivate
238 {
239    int cols;                    // number of colours, power of 2
240    unsigned char colbits;       // number of bits for colours
241    int fh;                      // file handle
242    int lzwnext;                 // next code
243    int lzwlast;                 // last code in current bit size
244    int lzwbits;                 // current bit size
245    LZWTree lzw;                 // encode tree
246    unsigned char block[256];    // block so far, with count at start
247    int blockv;                  // pending value
248    int blockb;                  // bits used in pending value
249    short lzwcode;               // which code we are on now
250 }
251 Private;
252
253 static
254 LZWFlush (Private * p)
255 {                               // flush this block
256    write (p->fh, p->block, *p->block + 1);
257    *p->block = 0;
258 }
259
260 static
261 LZWOut (Private * p, short v)
262 {                               // output a value
263    p->blockv |= (v << p->blockb);
264    p->blockb += p->lzwbits;
265    while (p->blockb >= 8)
266    {
267       p->block[++*p->block] = p->blockv;        // last partial byte
268       p->blockv >>= 8;
269       p->blockb -= 8;
270       if (*p->block == 255)
271          LZWFlush (p);
272    }
273 }
274
275 static
276 LZWClear (Private * p)
277 {
278    int c;
279    p->lzwbits = p->colbits + 1;
280    p->lzwnext = p->cols + 2;
281    p->lzwlast = (1 << p->lzwbits) - 1;
282    p->lzwcode = p->cols;        // starting point
283    for (c = 0; c < p->cols; c++)
284    {
285       p->lzw[p->cols][c] = c;   // links to literal entries
286       memset (&p->lzw[c], -1, p->cols * 2);     // links from literals, dead ends initially
287    }
288 }
289
290 static
291 ImageStart (Private * p)
292 {
293    unsigned char b = p->colbits;
294    write (p->fh, &b, 1);
295    *p->block = 0;
296    p->blockb = 0;
297    p->blockv = 0;
298    LZWClear (p);
299    LZWOut (p, p->cols);         // clear code
300 }
301
302 static
303 ImageEnd (Private * p)
304 {
305    LZWOut (p, p->lzwcode);      // last prefix
306    LZWOut (p, p->cols + 1);     // end code
307    if (p->blockb)
308       p->block[++*p->block] = p->blockv;        // last partial byte
309    LZWFlush (p);
310 }
311
312 static
313 ImageOut (Private * p, unsigned char c)
314 {
315    short next = p->lzw[p->lzwcode][c];
316    if (next == -1)
317    {                            // dead end
318       LZWOut (p, p->lzwcode);   // prefix
319 #ifdef CLEAR
320       if (p->lzwnext + 1 == MAXLZW)
321       {
322          LZWOut (p, p->cols);   // clear code
323          LZWClear (p);
324       } else
325 #endif
326       if (p->lzwnext < MAXLZW)
327       {
328          memset (p->lzw[p->lzwnext], -1, p->cols * 2);  // init dead ends
329          p->lzw[p->lzwcode][c] = p->lzwnext;
330          if (p->lzwnext > p->lzwlast)
331          {                      // bigger code
332             p->lzwbits++;
333             p->lzwlast = (1 << p->lzwbits) - 1;
334          }
335          p->lzwnext++;
336       }
337       p->lzwcode = c;
338    } else
339       p->lzwcode = next;        // not a dead end
340 }
341
342 // write GIF image
343 void
344 ImageWriteGif (Image * i, int fh, int back, int trans, char *comment)
345 {
346    struct strPrivate p;
347    p.fh = fh;
348    for (p.colbits = 2, p.cols = 4; p.cols < i->C; p.cols *= 2, p.colbits++);    // count colours, min 4
349    {                            // headers
350       char buf[1500];
351       int n = 0;
352       strcpy (buf, "GIF87a");
353 #ifndef INTERLACE
354       if (comment || trans >= 0)
355 #endif
356          buf[4] = '9';          // needs gif89 format
357       n = 6;
358       buf[n++] = (i->W & 255);
359       buf[n++] = (i->W >> 8);
360       buf[n++] = (i->H & 255);
361       buf[n++] = (i->H >> 8);
362       buf[n++] = (i->Colour ? 0x80 : 0) + 0x70 + (p.colbits - 1);
363       buf[n++] = back;          // background
364       buf[n++] = 0;             // aspect
365       if (i->Colour)
366       {
367          int c;
368          for (c = 0; c < p.cols; c++)
369          {
370             if (c < i->C)
371             {
372                buf[n++] = (i->Colour[c] >> 16 & 255);
373                buf[n++] = (i->Colour[c] >> 8 & 255);
374                buf[n++] = (i->Colour[c] & 255);
375             } else
376             {                   // extra, unused, colour
377                buf[n++] = 0;
378                buf[n++] = 0;
379                buf[n++] = 0;
380             }
381          }
382       }
383       // comment
384       if (comment && strlen (comment) < 256)
385       {                         // comment
386          buf[n++] = 0x21;       //extension
387          buf[n++] = 0xFE;       //comment
388          buf[n++] = strlen (comment);
389          strcpy (buf + n, comment);
390          n += buf[n - 1];
391          buf[n++] = 0;          // end of block
392       }
393       if (trans >= 0)
394       {                         // transparrent
395          buf[n++] = 0x21;       // extension
396          buf[n++] = 0xF9;       // graphic control
397          buf[n++] = 4;          // len
398          buf[n++] = 1;          // transparrent
399          buf[n++] = 0;          // delay
400          buf[n++] = 0;
401          buf[n++] = trans;
402          buf[n++] = 0;          // terminator
403       }
404       // image
405       buf[n++] = 0x2C;
406       buf[n++] = 0;             // offset X
407       buf[n++] = 0;
408       buf[n++] = 0;             // offset Y
409       buf[n++] = 0;
410       buf[n++] = (i->W & 255);
411       buf[n++] = (i->W >> 8);
412       buf[n++] = (i->H & 255);
413       buf[n++] = (i->H >> 8);
414 #ifdef INTERLACE
415       buf[n++] = 0x40;          // interlaced, no local colour table
416 #else
417       buf[n++] = 0x00;          // non interlaced, no local colour table
418 #endif
419       write (fh, buf, n);
420    }
421    // image data
422    {
423       unsigned char *b;
424       int x,
425         y;
426       ImageStart (&p);
427 #ifdef INTERLACE
428       for (y = 0; y < i->H; y += 8)
429          for (b = &ImagePixel (i, 0, y), x = 0; x < i->W; x++)
430             ImageOut (&p, *b++);
431       for (y = 4; y < i->H; y += 8)
432          for (b = &ImagePixel (i, 0, y), x = 0; x < i->W; x++)
433             ImageOut (&p, *b++);
434       for (y = 2; y < i->H; y += 4)
435          for (b = &ImagePixel (i, 0, y), x = 0; x < i->W; x++)
436             ImageOut (&p, *b++);
437       for (y = 1; y < i->H; y += 2)
438          for (b = &ImagePixel (i, 0, y), x = 0; x < i->W; x++)
439             ImageOut (&p, *b++);
440 #else
441       for (y = 0; y < i->H; y++)
442          for (b = &ImagePixel (i, 0, y), x = 0; x < i->W; x++)
443             ImageOut (&p, *b++);
444 #endif
445       ImageEnd (&p);
446    }
447    write (fh, "\0", 1);         // end of image data
448    write (fh, "\x3B", 1);       // trailer
449 }
450
451 void
452 ImageText (Image * i, int x, int y, int col, char *text)
453 {                               // writes 8x8 text
454    if (i && text)
455       while (*text)
456       {
457          if (*text >= ' ' && *text)
458          {
459             int r;
460             unsigned const char *b = bbc + (*text - ' ') * 8;
461             for (r = 0; r < 8; r++)
462             {
463                unsigned char v = *b++;
464                unsigned char *p = &ImagePixel (i, x, y + r);
465                unsigned char m;
466                for (m = 0x80; m; m >>= 1, p++)
467                   if (v & m)
468                      *p = col;
469             }
470          }
471          x += 8;
472          text++;
473       }
474 }
475
476 void
477 ImageSmall (Image * i, int x, int y, int col, char *text)
478 {                               // writes 4x6 digits
479    if (i && text)
480       while (*text)
481       {
482          char *p = strchr (smallc, toupper (*text));
483          if (p)
484          {
485             int r;
486             char m = 1;
487             unsigned const char *b = small + (p - smallc) * 3;
488             for (r = 0; r < 5; r++)
489             {
490                int c;
491                for (c = 0; c < 3; c++)
492                   if (b[c] & m)
493                      ImagePixel (i, x + c, y + r) = col;
494                m <<= 1;
495             }
496             x += 4;
497          } else if (*text == '.')
498          {
499             ImagePixel (i, x, y + 4) = col;
500             x += 2;
501          } else if (*text == ':')
502          {
503             ImagePixel (i, x, y + 1) = col;
504             ImagePixel (i, x, y + 3) = col;
505             x += 2;
506          }
507          text++;
508       }
509 }
510
511 void
512 ImageRect (Image * i, int x, int y, int w, int h, int c)
513 {                               // fill a box
514    if (i && w && h)
515    {
516       while (h--)
517       {
518          unsigned char *p = &ImagePixel (i, x, y);
519          int n = w;
520          while (n--)
521             *p++ = c;
522          y++;
523       }
524    }
525 }
526
527 // PNG code
528
529       /* Table of CRCs of all 8-bit messages. */
530 static unsigned int crc_table[256];
531
532       /* Make the table for a fast CRC. */
533 void
534 make_crc_table (void)
535 {
536    unsigned int c;
537    int n,
538      k;
539    for (n = 0; n < 256; n++)
540    {
541       c = (unsigned int) n;
542       for (k = 0; k < 8; k++)
543       {
544          if (c & 1)
545             c = 0xedb88320L ^ (c >> 1);
546          else
547             c = c >> 1;
548       }
549       crc_table[n] = c;
550    }
551 }
552
553       /* Update a running CRC with the bytes buf[0..len-1]--the CRC
554          should be initialized to all 1's, and the transmitted value
555          is the 1's complement of the final running CRC (see the
556          crc() routine below)). */
557
558 unsigned int
559 update_crc (unsigned int crc, unsigned char *buf, int len)
560 {
561    unsigned int c = crc;
562    int n;
563
564    for (n = 0; n < len; n++)
565       c = crc_table[(c ^ buf[n]) & 0xff] ^ (c >> 8);
566
567    return c;
568 }
569
570       /* Return the CRC of the bytes buf[0..len-1]. */
571 unsigned int
572 crc (unsigned char *buf, int len)
573 {
574    return update_crc (0xffffffffL, buf, len) ^ 0xffffffffL;
575 }
576
577 unsigned int
578 writecrc (int fh, char *ptr, int len, unsigned int c)
579 {
580    write (fh, ptr, len);
581    while (len--)
582       c = crc_table[(c ^ *ptr++) & 0xff] ^ (c >> 8);
583    return c;
584 }
585
586 void
587 writechunk (int fh, char *typ, void *ptr, int len)
588 {
589    unsigned int v = htonl (len),
590       crc;
591    write (fh, &v, 4);
592    crc = writecrc (fh, typ, 4, ~0);
593    if (len)
594       crc = writecrc (fh, ptr, len, crc);
595    v = htonl (~crc);
596    write (fh, &v, 4);
597 }
598
599 #ifndef USEZLIB
600 unsigned int
601 adlersum (unsigned char *p, int l, unsigned int adler)
602 {
603    unsigned int s1 = (adler & 65535),
604       s2 = (adler >> 16);
605    while (l--)
606    {
607       s1 += *p++;
608       s2 += s1;
609    }
610    s1 %= 65521;                 // can be delayed due to sensible "l" values...
611    s2 %= 65521;
612    return (s2 << 16) + s1;
613 }
614 #endif
615
616 // write PNG image
617 void
618 ImageWritePNG (Image * i, int fh, int back, int trans, char *comment)
619 {
620    make_crc_table ();
621    write (fh, "\211PNG\r\n\032\n", 8);  // PNG header
622    {                            // IHDR
623       struct
624       {
625          unsigned int width;
626          unsigned int height;
627          unsigned char depth;
628          unsigned char colour;
629          unsigned char compress;
630          unsigned char filter;
631          unsigned char interlace;
632       }
633       ihdr =
634       {
635       0, 0, 8, 3, 0, 0};
636       ihdr.width = htonl (i->W);
637       ihdr.height = htonl (i->H);
638       writechunk (fh, "IHDR", &ihdr, 13);
639    }
640    {                            // PLTE
641       unsigned int v = htonl (i->C * 3),
642          crc,
643          n;
644       write (fh, &v, 4);
645       crc = writecrc (fh, "PLTE", 4, ~0);
646       for (n = 0; n < i->C; n++)
647       {
648          v = htonl (i->Colour[n] << 8);
649          crc = writecrc (fh, (void *) &v, 3, crc);
650       }
651       v = htonl (~crc);
652       write (fh, &v, 4);
653    }
654    if (back >= 0)
655    {                            // bKGD
656       unsigned char b = back;
657       writechunk (fh, "bKGD", &b, 1);
658    }
659    if (*comment)
660    {                            // tEXt
661       char c[] = "Comment";
662       unsigned int v = htonl (strlen (c) + strlen (comment) + 1),
663          crc;
664       write (fh, &v, 4);
665       crc = writecrc (fh, "tEXt", 4, ~0);
666       crc = writecrc (fh, c, strlen (c) + 1, crc);
667       crc = writecrc (fh, comment, strlen (comment), crc);
668       v = htonl (~crc);
669       write (fh, &v, 4);
670    }
671    {                            // tRNS
672       unsigned char alpha[256];
673       int n;
674       for (n = 0; n < i->C; n++)
675          alpha[n] = 255 - (i->Colour[n] >> 24); // 4th palette byte treated as 0=opaque, 255-transparrent
676       if (trans >= 0 && trans < i->C)
677          alpha[trans] = 0;      // manual set of specific transparrent colour
678       writechunk (fh, "tRNS", alpha, i->C);
679    }
680 #ifndef USEZLIB
681    {                            // IDAT
682       unsigned int v = htonl (i->H * (i->L + 5) + 6),
683          crc,
684          adler = 1,
685          n;
686       unsigned char *p = i->Image;
687       write (fh, &v, 4);
688       crc = writecrc (fh, "IDAT", 4, ~0);
689       crc = writecrc (fh, "\170\001", 2, crc);  // zlib header for deflate
690       n = i->H;
691       while (n--)
692       {
693          unsigned char h[5];
694          h[0] = (n ? 0 : 1);    // last chunk in deflate, un compressed
695          h[1] = (i->L & 255);   // Len, LSB first as per deflate spec
696          h[2] = (i->L / 256);
697          h[3] = ~(i->L & 255);  // Inverse of Len
698          h[4] = ~(i->L / 256);
699          *p = 0;                // filter 0 (NONE)
700          crc = writecrc (fh, h, 5, crc);
701          crc = writecrc (fh, p, i->L, crc);
702          adler = adlersum (p, i->L, adler);
703          p += i->L;
704       }
705       v = htonl (adler);
706       crc = writecrc (fh, (void *) &v, 4, crc);
707       v = htonl (~crc);
708       write (fh, &v, 4);
709    }
710 #else
711    {                            // IDAT
712       unsigned char *temp;
713       unsigned long n;
714       for (n = 0; n < i->H; n++)
715          i->Image[n * i->L] = 0;        // filter 0
716       n = i->H * i->L * 1001 / 1000 + 12;
717       temp = malloc (n);
718       if (compress2 (temp, &n, i->Image, i->L * i->H, 9) != Z_OK)
719          fprintf (stderr, "Deflate error\n");
720       else
721          writechunk (fh, "IDAT", temp, n);
722       free (temp);
723    }
724 #endif
725    writechunk (fh, "IEND", 0, 0);       // IEND
726 }