//calp: printable calendar generator #include #include #include #include #include #include #include #include "draw.h" #include "date.h" #include "color.h" #include "image.h" // Font Settings #define FONT_FAMILY "Sans" #define FONT_SIZE_NORMAL 10 #define FONT_SIZE_LARGE 40 int main (void) { // Definitions // ----------- double paper_width = A4_WIDTH; double paper_height = A4_HEIGHT; // Convert to inches, then 1 unit = 1/72th inch paper_width = (paper_width / 25.4) * 72.0; paper_height = (paper_height / 25.4) * 72.0; int num_of_months = 12; char *months[num_of_months]; extern int days_in_month[12]; char *week_names[7]; //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 locale_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}; const nl_item locale_days[7] = {ABDAY_1, ABDAY_2, ABDAY_3, ABDAY_4, ABDAY_5, ABDAY_6, ABDAY_7}; setlocale(LC_ALL, ""); for (int i = 0; i < 12; i++) { months[i] = nl_langinfo(locale_months[i]); } for (int i = 0; i < 7; i++) { week_names[i] = nl_langinfo(locale_days[i]); printf("%s\n", week_names[i]); } // Create dimensions struct to hold measurements struct dimensions dim; const int row_count = 6; const int column_count = 7; // Create dimensions struct to hold information about a // month struct month_info month = { .row_count = row_count, .column_count = column_count }; // 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]++; } // 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(paper_width, paper_height, &dim); // Height and width of the paper // .x and .y are empty struct extents paper_extents = { .width = paper_width, .height = paper_height }; const double margin = 0.05 * paper_extents.width; struct alignment page_layout = { .margin = margin }; // Width and Height of the boxes are set // No position data is set until later. struct extents day_extents = { .width = paper_extents.width / 10.0, .height = paper_extents.width / 10.0 }; //struct extents week_name_extents = { // .width = day_extents.width //}; // Position and dimensions of the month "grid" 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, }; // Position and width of the header // Height is set dynamically, based on the size of // the month grid struct extents header_extents = { .x = margin, .y = margin, .width = paper_extents.width - (margin * 2.0), }; // Program fails if the PDF backend isn't available if (!CAIRO_HAS_PDF_SURFACE) { printf("Error: PDF backend not available.\n"); return 1; } // Main surface and context are created 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); double month_header_spacing = margin * 3.0; header_extents.height = paper_extents.height - month_header_spacing - ((month.minimum_rows + 1) * day_extents.height); // Create another surface and context for working with the // header cairo_surface_t *header = cairo_surface_create_similar( surface, CAIRO_CONTENT_COLOR_ALPHA, header_extents.width, header_extents.height ); cairo_t *ch = cairo_create(header); set_color(ch, BLUE); fill_bg(ch); set_color(ch, BLACK); draw_month_title(ch, &header_extents, &page_layout, FONT_FAMILY, FONT_SIZE_LARGE, months[i]); // Draw the header cairo_set_source_surface(paper, header, header_extents.x, header_extents.y); cairo_paint(paper); draw_month_dates(paper, cd, day, &month, &month_extents, &day_extents); 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); } // Clean up // -------- cairo_destroy(paper); cairo_surface_destroy(surface); cairo_destroy(cd); cairo_surface_destroy(day); return 0; }