1 /*
2  * File: abc_img.c
3  * Part of the ABClock package
4  * (c) Peter Kleiweg
5  *
6  * 2002/05/31: version 1.0b
7  * 2000/08/15: version 1.0
8  * 2000/08/06: version 0.9
9  * 2000/08/04: version 0.1
10  *
11  * This is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as
13  * published by the Free Software Foundation; either version 2,
14  * or (at your option) any later version.
15  *
16  */
17 
18 #define my_VERSION "1.0b"
19 
20 #ifdef __WIN32__
21 #  define my_PATH_SEP '\\'
22 #else
23 #  define my_PATH_SEP '/'
24 #endif
25 
26 #ifdef __MSDOS__
27 #  ifndef __COMPACT__
28 #    error Memory model COMPACT required
29 #  endif  /* __COMPACT__  */
30 #  include <dir.h>
31 #  include <fcntl.h>
32 #  include <io.h>
33 #endif
34 #ifdef __WIN32__
35 #   include <fcntl.h>
36 #endif
37 #include <errno.h>
38 #include <math.h>
39 #include <stdarg.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <time.h>
44 
45 #include "abclib.h"
46 
47 #ifdef __WIN32__
48 unsigned int
49     _CRT_fmode = _O_BINARY;
50 #endif
51 
52 typedef enum { FALSE = 0, TRUE } BOOL;
53 
54 typedef enum { XBM, XPM, PBM, PPM, BMP, BMPWIN } IMAGETYPE;
55 
56 IMAGETYPE
57 #if defined(__MSDOS__) || defined(__WIN32__)
58     imagetype = BMP;
59 #   define my_NL "\r\n"
60 #else
61     imagetype = PPM;
62 #   define my_NL "\n"
63 #endif
64 
65 unsigned char
66     **map;
67 
68 char
69     *filename = NULL,
70     **arg_v,
71     *programname,
72     *no_mem_buffer,
73     out_of_memory [] = "Out of memory";
74 
75 int
76     color [5][3] = {
77 	{ 255, 255, 255 },    /* background       */
78 	{ 255, 255, 255 },    /* inside of square */
79 	{   0,   0,   0 },    /* square border    */
80 	{   0,   0,   0 },    /* hours            */
81 	{   0,   0,   0 }     /* minutes          */
82     },
83     xsize = 80,
84     ysize = 80,
85     xmapsize,
86     border = -1,
87     indexcolor,
88     arg_c;
89 
90 BOOL
91     verbose = TRUE;
92 
93 FILE
94     *fp;
95 
96 void
97     setup_clock (void),
98     write_xbm (void),
99     write_xpm (void),
100     write_pbm (void),
101     write_ppm (void),
102     write_bmp (BOOL win),
103     *s_malloc (size_t size),
104     get_programname (char const *argv0),
105     process_args (void),
106     testcolor (int i, char const *s),
107     testsize (int size, char const *s),
108     errit (char const *format, ...),
109     syntax (void);
110 char
111     *get_arg (void);
112 
main(int argc,char * argv[])113 int main (int argc, char *argv [])
114 {
115     time_t
116 	tp;
117     struct tm
118 	*tm;
119 
120     no_mem_buffer = (char *) malloc (1024);
121 
122     get_programname (argv [0]);
123 
124     arg_c = argc;
125     arg_v = argv;
126     process_args ();
127 
128     setup_clock ();
129 
130     switch (arg_c) {
131 	case 1:
132 	    time (&tp);
133 	    tm = localtime (&tp);
134 	    ABC_Make (tm->tm_hour, tm->tm_min, tm->tm_sec, xsize, ysize, border);
135 	    break;
136 	case 4:
137 	    ABC_Make (
138                 ((unsigned) atoi (arg_v [1])) % 24,
139 		((unsigned) atoi (arg_v [2])) % 60,
140 		((unsigned) atoi (arg_v [3])) % 60,
141 		xsize, ysize, border
142 		);
143 	    break;
144 	default:
145 	    syntax ();
146     }
147 
148     if (filename) {
149 #ifdef __MSDOS__
150 	fp = fopen (filename, "wb");
151 #else
152 	fp = fopen (filename, "w");
153 #endif
154 	if (! fp)
155 	    errit ("Creating file \"%s\": %s", filename, strerror (errno));
156 	if (verbose)
157 	    fprintf (stderr, "Writing to file \"%s\"" my_NL, filename);
158     } else {
159 	fp = stdout;
160 #ifdef __MSDOS__
161 	setmode (fileno (stdout), O_BINARY);
162 #endif
163     }
164 
165     switch (imagetype) {
166 	case XBM:
167 	    write_xbm ();
168 	    break;
169 	case XPM:
170 	    write_xpm ();
171 	    break;
172 	case PBM:
173 	    write_pbm ();
174 	    break;
175 	case PPM:
176 	    write_ppm ();
177 	    break;
178 	case BMP:
179 	    write_bmp (FALSE);
180 	    break;
181 	case BMPWIN:
182 	    write_bmp (TRUE);
183 	    break;
184     }
185 
186     if (fp != stdout)
187 	fclose (fp);
188 
189     return 0;
190 }
191 
write_xbm()192 void write_xbm ()
193 {
194     int
195 	byte,
196 	x,
197 	y,
198 	n;
199 
200     if (verbose)
201 	fprintf (stderr, "Writing XBM" my_NL);
202 
203     fprintf (
204 	fp,
205         "#define ABClock_width %i\n"
206         "#define ABClock_height %i\n"
207         "static char ABClock_bits[] = {\n",
208 	xsize,
209         ysize
210     );
211 
212     n = 0;
213     for (y = ysize - 1; y >= 0; y--)
214         for (x = 0; x < xmapsize; x += 8) {
215 	    byte = (map [x    ][y] > 1 ?   1 : 0) +
216 		   (map [x + 1][y] > 1 ?   2 : 0) +
217 		   (map [x + 2][y] > 1 ?   4 : 0) +
218 		   (map [x + 3][y] > 1 ?   8 : 0) +
219 		   (map [x + 4][y] > 1 ?  16 : 0) +
220 		   (map [x + 5][y] > 1 ?  32 : 0) +
221 		   (map [x + 6][y] > 1 ?  64 : 0) +
222 		   (map [x + 7][y] > 1 ? 128 : 0);
223 	    fprintf (
224 		fp,
225 	        "0x%02x%s%s",
226 		byte,
227 		(y == 0 && x == xmapsize - 8) ? "};" : ",",
228 		(++n % 15) ? "" : "\n"
229 	    );
230 	}
231     if (n % 15)
232 	fprintf (fp, "\n");
233 }
234 
write_xpm()235 void write_xpm ()
236 {
237     int
238 	x,
239 	y;
240     char
241         c [] = ".,#@%";
242 
243     if (verbose)
244 	fprintf (stderr, "Writing XPM" my_NL);
245 
246     fprintf (
247 	fp,
248         "/* XPM */\n"
249 	"static char *ABClock[] = {\n"
250 	"/* width height num_colors chars_per_pixel */\n"
251 	"\"    %i    %i        5            1\",\n"
252 	"/* colors */\n"
253 	"\"%c c #%02x%02x%02x\",\n"
254 	"\"%c c #%02x%02x%02x\",\n"
255 	"\"%c c #%02x%02x%02x\",\n"
256 	"\"%c c #%02x%02x%02x\",\n"
257 	"\"%c c #%02x%02x%02x\",\n"
258 	"/* pixels */\n",
259 	xsize,
260 	ysize,
261 	c [0], color [0][0], color [0][1], color [0][2],
262 	c [1], color [1][0], color [1][1], color [1][2],
263 	c [2], color [2][0], color [2][1], color [2][2],
264 	c [3], color [3][0], color [3][1], color [3][2],
265 	c [4], color [4][0], color [4][1], color [4][2]
266     );
267 
268     for (y = ysize - 1; y >= 0; y--) {
269 	fprintf (fp, "\"");
270 	for (x = 0; x < xsize; x++)
271 	    fprintf (fp, "%c", c [map [x][y]]);
272         fprintf (fp, y ? "\",\n" : "\"\n");
273     }
274 
275     fprintf (fp, "};\n");
276 }
277 
write_pbm()278 void write_pbm ()
279 {
280     int
281 	x,
282 	y;
283 
284     if (verbose)
285 	fprintf (stderr, "Writing PBM" my_NL);
286 
287     fprintf (
288 	fp,
289         "P4\n"
290         "%i %i\n",
291 	xsize,
292         ysize
293     );
294 
295     for (y = ysize - 1; y >= 0; y--)
296         for (x = 0; x < xmapsize; x += 8)
297 	    fputc ((map [x + 7][y] > 1 ?   1 : 0) +
298 		   (map [x + 6][y] > 1 ?   2 : 0) +
299 		   (map [x + 5][y] > 1 ?   4 : 0) +
300 		   (map [x + 4][y] > 1 ?   8 : 0) +
301 		   (map [x + 3][y] > 1 ?  16 : 0) +
302 		   (map [x + 2][y] > 1 ?  32 : 0) +
303 		   (map [x + 1][y] > 1 ?  64 : 0) +
304 		   (map [x    ][y] > 1 ? 128 : 0),
305 		   fp);
306 }
307 
write_ppm()308 void write_ppm ()
309 {
310     int
311 	x,
312 	y;
313 
314     if (verbose)
315 	fprintf (stderr, "Writing PPM" my_NL);
316 
317     fprintf (
318         fp,
319 	"P6\n"
320 	"%i %i\n"
321 	"255\n",
322 	xsize,
323 	ysize
324     );
325 
326     for (y = ysize - 1; y >= 0; y--)
327         for (x = 0; x < xsize; x++)
328 	    fprintf (
329 	        fp,
330 		"%c%c%c",
331 		(unsigned char) color [map [x][y]][0],
332 		(unsigned char) color [map [x][y]][1],
333 		(unsigned char) color [map [x][y]][2]
334             );
335 }
336 
write_bmp(BOOL win)337 void write_bmp (BOOL win)
338 {
339     unsigned long
340 	ul;
341     unsigned short
342 	us;
343     unsigned char
344         uc;
345     int
346 	bitsperline,
347 	i,
348 	x,
349 	y;
350 
351     if (verbose)
352 	fprintf (stderr, "Writing BMP%s" my_NL, win ? " Windows" : "");
353 
354     /* file header */
355 
356     bitsperline = xsize * 4;
357 
358     if ((bitsperline % 32) != 0)
359 	bitsperline += (32 - (bitsperline % 32));
360 
361     fwrite ("BM", 1, 2, fp);
362 
363     ul = 14 + (win ? 40 : 12) + 16 * (win ? 4 : 3) + ysize * (bitsperline >> 3);
364     fwrite (&ul, 4, 1, fp);
365 
366     us = 0;
367     fwrite (&us, 2, 1, fp);
368     fwrite (&us, 2, 1, fp);
369 
370     ul = 14 + (win ? 40 : 12) + 16 * (win ? 4 : 3);
371     fwrite (&ul, 4, 1, fp);
372 
373     /* info header */
374 
375     if (win) {
376 	ul = 40;
377 	fwrite (&ul, 4, 1, fp);
378 	ul = xsize;
379 	fwrite (&ul, 4, 1, fp);
380 	ul = ysize;
381 	fwrite (&ul, 4, 1, fp);
382 	us = 1;
383 	fwrite (&us, 2, 1, fp);
384 	us = 4;
385 	fwrite (&us, 2, 1, fp);
386 	ul = 0;
387 	fwrite (&ul, 4, 1, fp);
388 	fwrite (&ul, 4, 1, fp);
389 	fwrite (&ul, 4, 1, fp);
390 	fwrite (&ul, 4, 1, fp);
391 	fwrite (&ul, 4, 1, fp);
392 	fwrite (&ul, 4, 1, fp);
393     } else {
394 	ul = 12;
395 	fwrite (&ul, 4, 1, fp);
396 	us = xsize;
397 	fwrite (&us, 2, 1, fp);
398 	us = ysize;
399 	fwrite (&us, 2, 1, fp);
400 	us = 1;
401 	fwrite (&us, 2, 1, fp);
402 	us = 4;
403 	fwrite (&us, 2, 1, fp);
404     }
405 
406     /* rgb table, reverse from other bitmaps colors */
407 
408     uc = 0;
409     for (i = 0; i < 5; i++) {
410         fwrite (&(color [i][2]), 1, 1, fp);
411         fwrite (&(color [i][1]), 1, 1, fp);
412         fwrite (&(color [i][0]), 1, 1, fp);
413         if (win)
414 	    fwrite (&uc, 1, 1, fp);
415     }
416     for (; i < 16; i++) {
417         fwrite (&uc, 1, 1, fp);
418         fwrite (&uc, 1, 1, fp);
419         fwrite (&uc, 1, 1, fp);
420 	if (win)
421 	    fwrite (&uc, 1, 1, fp);
422     }
423 
424     /* image data */
425 
426     for (y = 0; y < ysize; y++)
427 	for (x = 0; x < xmapsize; x += 2) {
428 	    us = 16 * ((unsigned char) map [x][y]) + (unsigned char) map [x + 1][y];
429 	    fwrite (&us, 1, 1, fp);
430 	}
431 
432 }
433 
setup_clock()434 void setup_clock ()
435 {
436     int
437 	x,
438 	y;
439 
440     xmapsize = (xsize % 8) ? (xsize - (xsize % 8) + 8) : xsize;
441 
442     map = (unsigned char **) s_malloc (xmapsize * sizeof (unsigned char *));
443     for (x = 0; x < xmapsize; x++)
444 	map [x] = (unsigned char *) s_malloc (ysize * sizeof (unsigned char));
445     for (x = xsize; x < xmapsize; x++)
446 	for (y = 0; y < ysize; y++)
447 	    map [x][y] = 0;
448 }
449 
ABC_SetColor(int color)450 void ABC_SetColor (int color)
451 {
452     indexcolor = color;
453 }
454 
ABC_Rect(int x1,int y1,int x2,int y2)455 void ABC_Rect (int x1, int y1, int x2, int y2)
456 {
457     int
458         x,
459 	y;
460 
461     if (x1 > x2 || y1 > y2)
462 	return;
463 
464     for (x = x1; x <= x2; x++)
465 	for (y = y1; y <= y2; y++)
466 	    map [x][y] = indexcolor;
467 }
468 
testcolor(int i,char const * s)469 void  testcolor (int i, char const *s)
470 {
471     if (color [i][0] < 0 || color [i][0] > 255 ||
472         color [i][1] < 0 || color [i][1] > 255 ||
473         color [i][2] < 0 || color [i][2] > 255)
474             errit ("Invalid color for -%s", s);
475 }
476 
testsize(int size,char const * s)477 void testsize (int size, char const *s)
478 {
479     if (size < ABC_MINSIZE || size > 1000)
480         errit ("%s out of range, must be in [%i, 600]", s, (int) ABC_MINSIZE);
481 }
482 
process_args()483 void process_args ()
484 {
485     if (arg_c < 2)
486 	syntax ();
487 
488     if (arg_v [1][0] == '-' && arg_v [1][1] != '\0')
489 	syntax ();
490 
491     if (strcmp (arg_v [1], "-"))
492 	filename = arg_v [1];
493 
494     arg_v++;
495     arg_c--;
496 
497     while (arg_c > 1 && arg_v [1][0] == '-') {
498 	if (! strcmp (arg_v [1], "-border")) {
499 	    border = atoi (get_arg ());
500 	    if (border < 0 || border > 200)
501 		errit ("Value for -border out of range");
502 	} else if (! strcmp (arg_v [1], "-width")) {
503 	    xsize = atoi (get_arg ());
504 	    testsize (xsize, "width");
505 	} else if (! strcmp (arg_v [1], "-height")) {
506 	    ysize = atoi (get_arg ());
507 	    testsize (ysize, "height");
508 	} else if (! strcmp (arg_v [1], "-xbm"))
509 	    imagetype = XBM;
510 	else if (! strcmp (arg_v [1], "-xpm"))
511 	    imagetype = XPM;
512 	else if (! strcmp (arg_v [1], "-pbm"))
513 	    imagetype = PBM;
514 	else if (! strcmp (arg_v [1], "-ppm"))
515 	    imagetype = PPM;
516 	else if (! strcmp (arg_v [1], "-bmp"))
517 	    imagetype = BMP;
518 	else if (! strcmp (arg_v [1], "-bmpwin"))
519 	    imagetype = BMPWIN;
520 	else if (! strcmp (arg_v [1], "-bg")) {
521 	    color [0][0] = atoi (get_arg ());
522 	    color [0][1] = atoi (get_arg ());
523 	    color [0][2] = atoi (get_arg ());
524 	    testcolor (0, "bg");
525 	} else if (! strcmp (arg_v [1], "-ic")) {
526 	    color [1][0] = atoi (get_arg ());
527 	    color [1][1] = atoi (get_arg ());
528 	    color [1][2] = atoi (get_arg ());
529 	    testcolor (1, "ic");
530 	} else if (! strcmp (arg_v [1], "-sc")) {
531 	    color [2][0] = atoi (get_arg ());
532 	    color [2][1] = atoi (get_arg ());
533 	    color [2][2] = atoi (get_arg ());
534 	    testcolor (2, "sc");
535 	} else if (! strcmp (arg_v [1], "-hc")) {
536 	    color [3][0] = atoi (get_arg ());
537 	    color [3][1] = atoi (get_arg ());
538 	    color [3][2] = atoi (get_arg ());
539 	    testcolor (3, "hc");
540 	} else if (! strcmp (arg_v [1], "-mc")) {
541 	    color [4][0] = atoi (get_arg ());
542 	    color [4][1] = atoi (get_arg ());
543 	    color [4][2] = atoi (get_arg ());
544 	    testcolor (4, "mc");
545 	} else if (! strcmp (arg_v [1], "-q"))
546 	    verbose = FALSE;
547         else
548 	    syntax ();
549 	arg_c--;
550 	arg_v++;
551     }
552 }
553 
get_arg()554 char *get_arg ()
555 {
556     if (arg_c == 2)
557         errit ("Missing argument for '%s'", arg_v [1]);
558 
559     arg_v++;
560     arg_c--;
561     return arg_v [1];
562 }
563 
s_malloc(size_t size)564 void *s_malloc (size_t size)
565 {
566     void
567 	*p;
568 
569     p = malloc (size);
570     if (! p) {
571         free (no_mem_buffer);
572 	errit (out_of_memory);
573     }
574     return p;
575 }
576 
errit(char const * format,...)577 void errit (char const *format, ...)
578 {
579     va_list
580 	list;
581 
582     fprintf (stderr, my_NL "Error %s: ", programname);
583 
584     va_start (list, format);
585     vfprintf (stderr, format, list);
586 
587     fprintf (stderr, my_NL my_NL);
588 
589     exit (1);
590 }
591 
get_programname(char const * argv0)592 void get_programname (char const *argv0)
593 {
594 #ifdef __MSDOS__
595     char
596         name [MAXFILE];
597     fnsplit (argv0, NULL, NULL, name, NULL);
598     programname = strdup (name);
599 #else
600     char
601         *p;
602     p = strrchr (argv0, my_PATH_SEP);
603     if (p)
604         programname = strdup (p + 1);
605     else
606         programname = strdup (argv0);
607 #endif
608 }
609 
syntax()610 void syntax ()
611 {
612     fprintf (
613 	stderr,
614 	my_NL
615 	"Analogue Bitmap Clock -- version " my_VERSION my_NL
616 	"create image file" my_NL
617 	"(c) Peter Kleiweg 2000, 2002" my_NL
618         my_NL
619         "Usage: %s <filename> [options] [<hour> <minute> <second>]" my_NL
620         my_NL
621 	"<filename> : use - for stdout" my_NL
622         my_NL
623 	"If no time is specified, the current time will be used" my_NL
624 	my_NL
625         "options:" my_NL
626 	"-border <int> : border width" my_NL
627 	"-width <int> : width" my_NL
628 	"-height <int> : height" my_NL
629         "-xbm : create XBM image file" my_NL
630         "-xpm : create XPM image file" my_NL
631         "-pbm : create PBM image file" my_NL
632         "-ppm : create PPM image file" my_NL
633         "-bmp : create BMP image file" my_NL
634         "-bmpwin : create BMP Windows image file" my_NL
635         "-bg <red> <green <blue> : set background colour" my_NL
636         "-hc <red> <green <blue> : set colour for hours" my_NL
637         "-mc <red> <green <blue> : set colour for minutes" my_NL
638         "-sc <red> <green <blue> : set border colour for square" my_NL
639         "-ic <red> <green <blue> : set inside colour for square" my_NL
640 	"-q : quiet" my_NL
641         "<red>, <green>, <blue> must be 0 - 255" my_NL
642         my_NL,
643 	programname
644     );
645     exit (1);
646 }
647