//calp: printable calendar generator #include #include #include #include #include #include #include #include "draw.h" #include "date.h" #include "color.h" #include "image.h" // Metric #define A4_WIDTH 210 #define A4_HEIGHT 297 #define US_LETTER_WIDTH 216 #define US_LETTER_HEIGHT 279 // Font Settings #define FONT_FAMILY "Sans" #define FONT_SIZE_NORMAL 10 #define FONT_SIZE_LARGE 40 int main (void) { // Definitions // ----------- double width = A4_WIDTH; double height = A4_HEIGHT; const int row_count = 6; const int column_count = 7; // Convert to inches, then 1 unit = 1/72th inch width = (width / 25.4) * 72.0; height = (height / 25.4) * 72.0; //extern char *months[]; int num_of_months = 12; char *months[num_of_months]; extern int days_in_month[12]; //const nl_item nl_abmons[12] = {ABMON_1, ABMON_2, ABMON_3, ABMON_4, // ABMON_5, ABMON_6, ABMON_7, ABMON_8, // ABMON_9, ABMON_10, ABMON_11, ABMON_12}; const nl_item nl_months[12] = {MON_1, MON_2, MON_3, MON_4, MON_5, MON_6, MON_7, MON_8, MON_9, MON_10, MON_11, MON_12}; int i; setlocale(LC_ALL, ""); for (i = 0; i < 12; i++) { months[i] = nl_langinfo(nl_months[i]); } // Create dimensions struct to hold measurements struct dimensions dim; // Create dimensions struct to hold information about a // month struct month_info month; // Leap year adjustment: increment February day count by one if // it is a leap year. const int year = 2026; if (isleap(year)) { days_in_month[1]++; } int verbose_output = 0; // TBD: Add ability to choose filename // Defaults to the year being generated char filename[20]; snprintf(filename, sizeof(filename), "%d.pdf", year); // Initialization // -------------- // Calculates measurements, stores them in dimensions struct. See "draw.h" calculate_dimensions(width, height, &dim); struct extents paper_extents = { .width = width, .height = height }; const double margin = 0.05 * paper_extents.width; struct extents day_extents = { .width = paper_extents.width / 10.0, .height = paper_extents.width / 10.0 }; struct extents month_extents = { .x = (paper_extents.width - (day_extents.width * column_count)) / 2.0, .y = paper_extents.height - margin - (day_extents.height * row_count), .width = day_extents.width * column_count, .height = day_extents.height * row_count, }; printf("%f\n", month_extents.x); if (!CAIRO_HAS_PDF_SURFACE) { printf("Error: PDF backend not available.\n"); return 1; } cairo_surface_t *surface = cairo_pdf_surface_create(filename, paper_extents.width, paper_extents.height); cairo_t *paper = cairo_create(surface); // Sub-surface for rendering content in day boxes cairo_surface_t *day = cairo_surface_create_similar(surface, CAIRO_CONTENT_COLOR_ALPHA, day_extents.width, day_extents.height); // cd = context day cairo_t *cd = cairo_create(day); // Fill background with white color set_color(paper, WHITE); fill_bg(paper); // Construction // ------------ // Month generation loop for (int i = 0; i < num_of_months; i++) { // Initialize month struct month.first_day = day_of_week(1, i + 1, year); month.num_of_days = days_in_month[i]; month.month_position = i; month.minimum_rows = calculate_minimum_rows(&month); dim.header_width = dim.paper_width - (dim.margin * 2.0); dim.header_height = dim.paper_height - (dim.margin * 3.0) - (month.minimum_rows * dim.day_height); cairo_surface_t *header = cairo_surface_create_similar(surface, CAIRO_CONTENT_COLOR_ALPHA, dim.header_width, dim.header_height); cairo_t *ch = cairo_create(header); set_color(ch, BLACK); draw_month_title(ch, &dim, "Sans", 40, months[i]); char path[20]; snprintf(path, 20, "assets/%d.png", i + 1); if (verbose_output) { printf("Drawing month \'%s\'\n", months[i]); } draw_month_art(paper, &dim, path); cairo_set_source_surface(paper, header, dim.margin, dim.margin); cairo_paint(paper); draw_month(paper, cd, day, &month, &dim); draw_month_grid(paper, &month, &month_extents, &day_extents); // Go to the next page in pdf cairo_show_page(paper); cairo_destroy(ch); cairo_surface_destroy(header); } if (verbose_output) { printf("Finished generating \'%s\'.\n", filename); } // Clean up // -------- cairo_destroy(paper); cairo_surface_destroy(surface); cairo_destroy(cd); cairo_surface_destroy(day); return 0; }