summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStijn Buys <ingar@telenet.be>2022-05-25 18:26:40 +0200
committerStijn Buys <ingar@telenet.be>2022-05-25 18:26:40 +0200
commit763efda3098f8098b18ce37f29e67f6485f0836f (patch)
treef3a123083eaf2096f6af9370a0b76f31f0b79949
Initial commit
-rw-r--r--Makefile15
-rw-r--r--genclockimg.c152
2 files changed, 167 insertions, 0 deletions
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..3ec2468
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,15 @@
+
+CFLAGS = -I/usr/include/cairo -D_XOPEN_SOURCE -g
+LDDFLAGS = -lcairo -lpopt -lm
+
+SRC = genclockimg.o
+TARGET = genclockimg
+
+$(TARGET): $(SRC)
+ gcc $(SRC) -o $(TARGET) $(LDDFLAGS)
+
+all:
+
+clean:
+ rm *.o $(TARGET)
+
diff --git a/genclockimg.c b/genclockimg.c
new file mode 100644
index 0000000..e85a4ee
--- /dev/null
+++ b/genclockimg.c
@@ -0,0 +1,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;
+}