/* genclockimg generates a clock face PNG image */ #include #include #include #include #include #include #include #include "cairo_jpg.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; int use_jpeg; /* 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, ×tr, 0, "time to display as HH:MM", NULL}, {"jpg", 'j', POPT_ARG_NONE, &use_jpeg, 0, "Write a JPEG file", 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; use_jpeg = 0; /* 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 (use_jpeg) { img_filename_default[4] = 'j'; img_filename_default[5] = 'p'; img_filename_default[6] = 'g'; } 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, 1.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 background */ /* 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); */ /* draw clock face */ cairo_set_source_rgba (context, 1.0, 1.0, 1.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, 1.0, 1.0, 1.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 */ cairo_status_t status = CAIRO_STATUS_SUCCESS; if (use_jpeg) { status = cairo_image_surface_write_to_jpeg(surface, img_filename, 100); } else { status = cairo_surface_write_to_png(surface, img_filename); } if (status != CAIRO_STATUS_SUCCESS) { fprintf(stderr, "Error saving %s\n", img_filename); } /* cleanup */ cairo_surface_destroy(surface); poptFreeContext(options_context); return 0; }