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