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