summaryrefslogtreecommitdiff
path: root/genclockimg.c
blob: e85a4ee692c2faca2f5ec0ef04b4b1851971bf9a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
/*
	genclockimg
	generates a clock face PNG image
*/
#include <cairo.h>
#include <popt.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>

#include <math.h>

int main (int argc, const char **argv)
{

	/* configuration options */
	int img_width;
	int img_height;
	char *img_filename;
	char img_filename_default[] = "out.png\0";
	char *timestr;
	
	/* timestamp represeting what time to draw */
	time_t clock_timestamp;
	struct tm *clock_localtime;
	int h;
	int m;

	/* cairo surface and context */
	cairo_surface_t *surface;
	cairo_t *context;
	
	/* popt options table */
	struct poptOption options_table[] = {
		{"out", 'o', POPT_ARG_STRING, &img_filename, 0, "output filename",  NULL },
		{"width", 'w', POPT_ARG_INT, &img_width, 0, "output image width", NULL },
		{"height", 'h', POPT_ARG_INT, &img_height, 0, "output image height", NULL },
		{"hours", '\0', POPT_ARG_INT, &h, 0, "hour to display", NULL },
		{"minutes", '\0', POPT_ARG_INT, &m, 0, "minutes to display", NULL },
		{"time", 't', POPT_ARG_STRING, &timestr, 0, "time to display as HH:MM", NULL},
		POPT_AUTOHELP
		{NULL, '\0', 0, NULL, 0, NULL, NULL}
	};
	/* popt context */
	poptContext options_context;
		
	/* default filename is out.png */
	img_filename = NULL;
	
	timestr = NULL;
	
	/* default image size is 128x128 */
	img_width = 128;
	img_height = 128;

	/* default timestamp is current localtime */
	clock_timestamp = time(NULL);
	clock_localtime = localtime(&clock_timestamp);
	h = clock_localtime->tm_hour % 12;
	m = clock_localtime->tm_min;
	
	/* parse command line options */
	options_context = poptGetContext(NULL, argc, argv, options_table, 0);

	int result;
	while ((result = poptGetNextOpt(options_context)) > 0 ) {		
	}
	if (result < -1) {
      /* an error occurred during option processing */
      fprintf(stderr, "%s: %s\n", poptBadOption(options_context, POPT_BADOPTION_NOALIAS), poptStrerror(result));
      exit(1);
	}
	
	if (img_filename == NULL) {
		img_filename = img_filename_default;
	}
	
	if (timestr != NULL ) {
		/* note: clock_localtime is already initialized here */
		strptime(timestr, "%H:%M", clock_localtime);
		h = clock_localtime->tm_hour % 12;
		m = clock_localtime->tm_min;
	}
	
	/* keep hours and minutes into range */
	h %= 12;
	m %= 60;	
	
	/* create the cairo drawing context and an RGBA drawing surface */	
	surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, img_width, img_height);
	context = cairo_create(surface);	

	/* draw image */
	cairo_set_source_rgba(context, 0.0, 0.0, 0.0, 0.0);
	cairo_rectangle(context, 0, 0, img_width, img_height);
	cairo_fill(context);
	
	int x1 = img_width / 2 -1;
	int y1 = img_height / 2 -1;

	float r;
	if (img_width < img_height) {
		r = img_width / 2;
	} else {
		r = img_height /2;
	}
	float angle = 2.0f * M_PI / 12.0f;
	
	/* draw clock face */
	cairo_set_source_rgba (context, 1.0, 1.0, 1.0, 1.0);
	cairo_arc(context, x1, y1, r-4, 0, 2 * M_PI);
	cairo_fill(context);
	
	cairo_set_source_rgba (context, 0.0, 0.0, 0.0, 1.0);
	cairo_set_line_width (context, 1);	
	cairo_arc(context, x1, y1, r-4, 0, 2 * M_PI);
	cairo_stroke(context);

	/* draw markers */
	cairo_set_source_rgba (context, 0.0, 0.0, 0.0, 1.0);
	cairo_set_line_width (context, 2);	
	for (int h = 0; h < 12; h++) {
		cairo_move_to(context, x1 + (r - 10) * cosf(angle * h), y1 + (r - 10) * sinf(angle * h));
		cairo_line_to(context, x1 + (r - 4) * cosf(angle * h), y1 + (r - 4)* sinf(angle * h));
	}
	cairo_stroke(context);
	
	/* draw handles */
	cairo_set_line_width (context, 4);
	
	/* hours handle */
	cairo_move_to(context, x1, y1);
	cairo_line_to(context, x1 + (r/2 - 4) * sinf(angle * h + angle / 60 * m), y1 - (r/2 - 4) * cosf(angle * h + angle / 60 * m));
	
	/* minutes handle */
	cairo_move_to(context, x1, y1);
	cairo_line_to(context, x1 + (r - 10) * sinf(M_PI / 30.0f * m ), y1 - (r - 10) * cosf(M_PI / 30.0f * m));
	cairo_stroke(context);
	
	
	/* write image file */
	if (cairo_surface_write_to_png(surface, img_filename) != CAIRO_STATUS_SUCCESS) {
		fprintf(stderr, "Error saving %s\n", img_filename);
	}

	/* cleanup */
	cairo_surface_destroy(surface);
	poptFreeContext(options_context);
	
	return 0;
}