lorid

convert chordpro to pdf
git clone git://git.relim.de/lorid.git
Log | Files | Refs | README | LICENSE

commit b8ffeb167f0bb1a4efec711b3eaea904f73264de
parent 62e44e7c89b2c449ab8ce7d4b359d11a574fd83a
Author: nibo <nibo@relim.de>
Date:   Sun,  7 Jul 2024 17:40:01 +0200

A lot

Diffstat:
MMakefile | 7+++++--
Mchordpro.c | 86+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------
Mchordpro.h | 21++++++++++++++++++---
Mconfig.c | 300++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------------
Mconfig.h | 24+++++++++---------------
Afontconfig.c | 98+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Afontconfig.h | 8++++++++
Mlorid.c | 9++++++---
Mout_pdf.c | 313+++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------
Mout_pdf.h | 8+++++---
Mtodo | 1+
11 files changed, 607 insertions(+), 268 deletions(-)

diff --git a/Makefile b/Makefile @@ -1,4 +1,7 @@ all: - $(CC) -Wall -Wextra -O2 config.c chordpro.c out_pdf.c lorid.c -o lorid -lpdfio -ltoml + $(CC) -Wall -Wextra -O2 fontconfig.c config.c chordpro.c out_pdf.c lorid.c -o lorid -lpdfio -ltoml -lfontconfig debug: - $(CC) -g -Wall -Wextra config.c chordpro.c out_pdf.c lorid.c -o lorid -lpdfio -ltoml + $(CC) -g -Wall -Wextra fontconfig.c config.c chordpro.c out_pdf.c lorid.c -o lorid -I/usr/include/freetype2 -lpdfio -ltoml -lfontconfig +fontconfig: + $(CC) -g chordpro.c fontconfig.c -o fontconfig -lfontconfig +.PHONY: all debug fontconfig diff --git a/chordpro.c b/chordpro.c @@ -142,8 +142,8 @@ const char *the_font_style(enum FontStyle style) switch (style) { case FS_EMPTY: return "FS_EMPTY"; - case FS_REGULAR: - return "FS_REGULAR"; + case FS_ROMAN: + return "FS_ROMAN"; case FS_OBLIQUE: return "FS_OBLIQUE"; case FS_ITALIC: @@ -157,8 +157,8 @@ const char *the_font_weight(enum FontWeight weight) switch (weight) { case FW_EMPTY: return "FW_EMPTY"; - case FW_NORMAL: - return "FW_NORMAL"; + case FW_REGULAR: + return "FW_REGULAR"; case FW_BOLD: return "FW_BOLD"; } @@ -349,13 +349,13 @@ struct Font *cho_font_new(void) struct Font *font = malloc(sizeof(struct Font)); font->name = NULL; font->family = FF_NORMAL; - font->style = FS_REGULAR; - font->weight = FW_NORMAL; + font->style = FS_ROMAN; + font->weight = FW_REGULAR; font->size = DEFAULT_FONT_SIZE; return font; } -static struct Font *cho_font_duplicate(struct Font *font) +struct Font *cho_font_duplicate(struct Font *font) { struct Font *copy = malloc(sizeof(struct Font)); if (font->name) @@ -399,6 +399,52 @@ void cho_fonts_free(struct Font **fonts) free(fonts); } +char *cho_font_name_sanitize(const char *name) +{ + char *sanitized = NULL; + int i = 0; + int s = 0; + char c; + for (; name[i] != 0; i++) { + if (name[i] == ' ') + continue; + c = (char)tolower(name[i]); + sanitized = realloc(sanitized, (s+1) * sizeof(char)); + sanitized[s] = c; + s++; + } + sanitized = realloc(sanitized, (s+1) * sizeof(char)); + sanitized[s] = 0; + return sanitized; +} + +enum FontFamily cho_font_family_parse(const char *str) +{ + if (strcasecmp(str, "sans") == 0) { + return FF_SANS; + } else if (strcasecmp(str, "serif") == 0) { + return FF_SERIF; + } else if (strcasecmp(str, "monospace") == 0) { + return FF_MONOSPACE; + } else { + return FF_EMPTY; + } +} + +const char *cho_font_family_to_string(enum FontFamily font_family) +{ + switch (font_family) { + case FF_SANS: + return "sans"; + case FF_SERIF: + return "serif"; + case FF_MONOSPACE: + return "monospace"; + default: + return "normal"; + } +} + enum FontStyle cho_font_style_parse(const char *str) { if (strcasecmp(str, "italic") == 0) { @@ -406,9 +452,7 @@ enum FontStyle cho_font_style_parse(const char *str) } else if (strcasecmp(str, "oblique") == 0) { return FS_OBLIQUE; } else if (strcasecmp(str, "normal") == 0) { - return FS_REGULAR; - } else if (strcasecmp(str, "regular") == 0) { - return FS_REGULAR; + return FS_ROMAN; } else { return FS_EMPTY; } @@ -420,7 +464,7 @@ const char *cho_font_style_to_string(enum FontStyle style) return "italic"; if (style == FS_OBLIQUE) return "oblique"; - return "regular"; + return "normal"; } enum FontWeight cho_font_weight_parse(const char *str) @@ -428,9 +472,9 @@ enum FontWeight cho_font_weight_parse(const char *str) if (strcasecmp(str, "bold") == 0) { return FW_BOLD; } else if (strcasecmp(str, "regular") == 0) { - return FW_NORMAL; + return FW_REGULAR; } else if (strcasecmp(str, "normal") == 0) { - return FW_NORMAL; + return FW_REGULAR; } else { return FW_EMPTY; } @@ -443,12 +487,12 @@ const char *cho_font_weight_to_string(enum FontWeight weight) return "regular"; } -int cho_font_weight_to_int(enum FontWeight weight) +/* int cho_font_weight_to_int(enum FontWeight weight) { if (weight == FW_BOLD) return 200; return 80; -} +} */ struct Style *cho_style_new(void) { @@ -549,21 +593,21 @@ struct Font *cho_style_font_desc_parse(const char *str) if (stop_at == -1) stop_at = w; } else if (strcasecmp(words[w], "regular") == 0) { - font->weight = FW_NORMAL; + font->weight = FW_REGULAR; if (stop_at == -1) stop_at = w; } else if (strcasecmp(words[w], "normal") == 0) { - font->style = FS_REGULAR; + font->style = FS_ROMAN; if (stop_at == -1) stop_at = w; - } else if (strcasecmp(words[w], "sans") == 0) { + /* } else if (strcasecmp(words[w], "sans") == 0) { font->family = FF_SANS; if (stop_at == -1) stop_at = w; } else if (strcasecmp(words[w], "serif") == 0) { font->family = FF_SERIF; if (stop_at == -1) - stop_at = w; + stop_at = w; */ } else if (strcasecmp(words[w], "monospace") == 0) { font->family = FF_MONOSPACE; if (stop_at == -1) @@ -691,7 +735,7 @@ struct Style *cho_style_get(const char *tag_name, struct Attr **attrs, struct St } } else if (strcmp(attrs[a]->name, "style") == 0) { if (strcmp(attrs[a]->value, "normal") == 0) { - style->font->style = FS_REGULAR; + style->font->style = FS_ROMAN; } else if (strcmp(attrs[a]->value, "oblique") == 0) { style->font->style = FS_OBLIQUE; } else if (strcmp(attrs[a]->value, "italic") == 0) { @@ -701,7 +745,7 @@ struct Style *cho_style_get(const char *tag_name, struct Attr **attrs, struct St } } else if (strcmp(attrs[a]->name, "weight") == 0) { if (strcmp(attrs[a]->value, "normal") == 0) { - style->font->weight = FW_NORMAL; + style->font->weight = FW_REGULAR; } else if (strcmp(attrs[a]->value, "bold") == 0) { style->font->weight = FW_BOLD; } else { diff --git a/chordpro.h b/chordpro.h @@ -1,5 +1,8 @@ /* ChordPro markup language <https://chordpro.org/chordpro/chordpro_markup> */ +#ifndef _CHORDPRO_H_ +#define _CHORDPRO_H_ + #define RISE_MAX #define DEFAULT_FONT_SIZE 14.0 // Based on https://stackoverflow.com/a/417184 @@ -15,14 +18,14 @@ enum FontFamily { enum FontStyle { FS_EMPTY = -1, - FS_REGULAR, + FS_ROMAN, FS_OBLIQUE, FS_ITALIC }; enum FontWeight { FW_EMPTY = -1, - FW_NORMAL, + FW_REGULAR, FW_BOLD }; @@ -33,6 +36,7 @@ struct Font { enum FontWeight weight; double size; }; +// "Inter-monospace-regular-regular-12.0" enum LineStyle { LS_SINGLE, @@ -162,14 +166,23 @@ void cho_songs_free(struct ChoSong **song); int cho_line_item_count(struct ChoLineItem **items); int cho_chord_count(struct ChoChord **chords); struct Font *cho_style_font_desc_parse(const char *str); + struct Font *cho_font_new(void); void cho_font_free(struct Font *font); +struct Font *cho_font_duplicate(struct Font *font); void cho_fonts_free(struct Font **fonts); + +char *cho_font_name_sanitize(const char *name); + +enum FontFamily cho_font_family_parse(const char *str); +const char *cho_font_family_to_string(enum FontFamily font_family); + enum FontStyle cho_font_style_parse(const char *str); const char *cho_font_style_to_string(enum FontStyle style); + enum FontWeight cho_font_weight_parse(const char *str); const char *cho_font_weight_to_string(enum FontWeight weight); -int cho_font_weight_to_int(enum FontWeight weight); +// int cho_font_weight_to_int(enum FontWeight weight); /* Debugging */ void cho_font_print(struct Font *font); @@ -182,3 +195,5 @@ const char *the_font_style(enum FontStyle style); const char *the_font_weight(enum FontWeight weight); const char *the_rgb_color(struct RGBColor *color); const char *the_line_style(enum LineStyle style); + +#endif /* _CHORDPRO_H_ */ diff --git a/config.c b/config.c @@ -8,54 +8,65 @@ struct Config *config_load_default(void) { struct Config *config = malloc(sizeof(struct Config)); - config->title = malloc(sizeof(struct ConfigSection)); - config->title->font_name = strdup("Inter"); - config->title->font_style = FS_REGULAR; - config->title->font_weight = FW_BOLD; - config->title->font_size = 18.0; - config->text = malloc(sizeof(struct ConfigSection)); - config->text->font_name = strdup("Inter"); - config->text->font_style = FS_REGULAR; - config->text->font_weight = FW_NORMAL; - config->text->font_size = 14.0; - config->chord = malloc(sizeof(struct ConfigSection)); - config->chord->font_name = strdup("Inter"); - config->chord->font_style = FS_REGULAR; - config->chord->font_weight = FW_BOLD; - config->chord->font_size = 14.0; - config->comment = malloc(sizeof(struct ConfigSection)); - config->comment->font_name = strdup("Inter"); - config->comment->font_style = FS_REGULAR; - config->comment->font_weight = FW_NORMAL; - config->comment->font_size = 14.0; - config->comment_italic = malloc(sizeof(struct ConfigSection)); - config->comment_italic->font_name = strdup("Inter"); - config->comment_italic->font_style = FS_ITALIC; - config->comment_italic->font_weight = FW_BOLD; - config->comment_italic->font_size = 14.0; - config->comment_box = malloc(sizeof(struct ConfigSection)); - config->comment_box->font_name = strdup("Inter"); - config->comment_box->font_style = FS_REGULAR; - config->comment_box->font_weight = FW_NORMAL; - config->comment_box->font_size = 14.0; - config->tab = malloc(sizeof(struct ConfigSection)); - config->tab->font_name = strdup("Inter"); - config->tab->font_style = FS_REGULAR; - config->tab->font_weight = FW_NORMAL; - config->tab->font_size = 14.0; - config->grid = malloc(sizeof(struct ConfigSection)); - config->grid->font_name = strdup("Inter"); - config->grid->font_style = FS_REGULAR; - config->grid->font_weight = FW_BOLD; - config->grid->font_size = 14.0; + config->title_font = malloc(sizeof(struct Font)); + config->title_font->family = FF_NORMAL; + config->title_font->name = strdup("Inter"); + config->title_font->style = FS_ROMAN; + config->title_font->weight = FW_BOLD; + config->title_font->size = 18.0; + config->text_font = malloc(sizeof(struct Font)); + config->text_font->name = strdup("Inter"); + config->text_font->family = FF_NORMAL; + config->text_font->style = FS_ROMAN; + config->text_font->weight = FW_REGULAR; + config->text_font->size = 14.0; + config->chord_font = malloc(sizeof(struct Font)); + config->chord_font->name = strdup("Inter"); + config->chord_font->family = FF_NORMAL; + config->chord_font->style = FS_ROMAN; + config->chord_font->weight = FW_BOLD; + config->chord_font->size = 14.0; + config->comment_font = malloc(sizeof(struct Font)); + config->comment_font->name = strdup("Inter"); + config->comment_font->family = FF_NORMAL; + config->comment_font->style = FS_ROMAN; + config->comment_font->weight = FW_REGULAR; + config->comment_font->size = 14.0; + config->comment_italic_font = malloc(sizeof(struct Font)); + config->comment_italic_font->name = strdup("Inter"); + config->comment_italic_font->family = FF_NORMAL; + config->comment_italic_font->style = FS_ITALIC; + config->comment_italic_font->weight = FW_BOLD; + config->comment_italic_font->size = 14.0; + config->comment_box_font = malloc(sizeof(struct Font)); + config->comment_box_font->name = strdup("Inter"); + config->comment_box_font->family = FF_NORMAL; + config->comment_box_font->style = FS_ROMAN; + config->comment_box_font->weight = FW_REGULAR; + config->comment_box_font->size = 14.0; + config->tab_font = malloc(sizeof(struct Font)); + config->tab_font->name = strdup("Inter"); + config->tab_font->family = FF_NORMAL; + config->tab_font->style = FS_ROMAN; + config->tab_font->weight = FW_REGULAR; + config->tab_font->size = 14.0; + config->grid_font = malloc(sizeof(struct Font)); + config->grid_font->name = strdup("Inter"); + config->grid_font->family = FF_NORMAL; + config->grid_font->style = FS_ROMAN; + config->grid_font->weight = FW_BOLD; + config->grid_font->size = 14.0; return config; } struct Config *config_load(const char *filepath) { struct Config *config = config_load_default(); + char *home = getenv("HOME"); + char path[26+strlen(home)+1]; if (filepath == NULL) { - filepath = "~/.config/lorid/config.toml"; + sprintf(path, "%s/.config/lorid/config.toml", home); + filepath = path; } FILE *fp = fopen(filepath, "r"); if (fp == NULL) { @@ -66,7 +77,8 @@ struct Config *config_load(const char *filepath) toml_table_t *table = toml_parse_file(fp, (char *)&errbuf, sizeof(errbuf)); toml_table_t *fonts = toml_table_table(table, "fonts"); toml_table_t *section; - toml_value_t name, style, weight, size; + toml_value_t name, family, style, weight, size; + enum FontFamily font_family; enum FontStyle font_style; enum FontWeight font_weight; int unused; @@ -75,21 +87,32 @@ struct Config *config_load(const char *filepath) key_name = toml_table_key(fonts, i, &unused); section = toml_table_table(fonts, key_name); name = toml_table_string(section, "name"); + family = toml_table_string(section, "family"); style = toml_table_string(section, "style"); weight = toml_table_string(section, "weight"); size = toml_table_int(section, "size"); if (strcmp(key_name, "title") == 0) { if (name.ok) { - free(config->title->font_name); - config->title->font_name = name.u.s; + free(config->title_font->name); + config->title_font->name = name.u.s; + } + if (family.ok) { + font_family = cho_font_family_parse(family.u.s); + if (font_family == FF_EMPTY) { + fprintf(stderr, "INFO: Invalid config title section font family value.\n"); + return NULL; + } else { + config->title_font->family = font_family; + } } if (style.ok) { + printf("style here\n"); font_style = cho_font_style_parse(style.u.s); if (font_style == FS_EMPTY) { fprintf(stderr, "INFO: Invalid config title section font style value.\n"); return NULL; } else { - config->title->font_style = font_style; + config->title_font->style = font_style; } free(style.u.s); } @@ -99,206 +122,269 @@ struct Config *config_load(const char *filepath) fprintf(stderr, "INFO: Invalid config title section font weight value.\n"); return NULL; } else { - config->title->font_weight = font_weight; + config->title_font->weight = font_weight; } free(weight.u.s); } if (size.ok) - config->title->font_size = size.u.i; + config->title_font->size = size.u.i; } else if (strcmp(key_name, "text") == 0) { if (name.ok) { - free(config->text->font_name); - config->text->font_name = name.u.s; + free(config->text_font->name); + config->text_font->name = name.u.s; + } + if (family.ok) { + font_family = cho_font_family_parse(family.u.s); + if (font_family == FF_EMPTY) { + fprintf(stderr, "INFO: Invalid config text section font family value.\n"); + return NULL; + } else { + config->text_font->family = font_family; + } } if (style.ok) { font_style = cho_font_style_parse(style.u.s); if (font_style == FS_EMPTY) { - fprintf(stderr, "INFO: Invalid config title section font style value.\n"); + fprintf(stderr, "INFO: Invalid config text section font style value.\n"); return NULL; } else { - config->text->font_style = font_style; + config->text_font->style = font_style; } free(style.u.s); } if (weight.ok) { font_weight = cho_font_weight_parse(weight.u.s); if (font_weight == FW_EMPTY) { - fprintf(stderr, "INFO: Invalid config title section font weight value.\n"); + fprintf(stderr, "INFO: Invalid config text section font weight value.\n"); return NULL; } else { - config->text->font_weight = font_weight; + config->text_font->weight = font_weight; } free(weight.u.s); } if (size.ok) - config->text->font_size = size.u.i; + config->text_font->size = size.u.i; } else if (strcmp(key_name, "chord") == 0) { if (name.ok) { - free(config->chord->font_name); - config->chord->font_name = name.u.s; + free(config->chord_font->name); + config->chord_font->name = name.u.s; + } + if (family.ok) { + font_family = cho_font_family_parse(family.u.s); + if (font_family == FF_EMPTY) { + fprintf(stderr, "INFO: Invalid config chord section font family value.\n"); + return NULL; + } else { + config->chord_font->family = font_family; + } } if (style.ok) { font_style = cho_font_style_parse(style.u.s); if (font_style == FS_EMPTY) { - fprintf(stderr, "INFO: Invalid config title section font style value.\n"); + fprintf(stderr, "INFO: Invalid config chord section font style value.\n"); return NULL; } else { - config->chord->font_style = font_style; + config->chord_font->style = font_style; } free(style.u.s); } if (weight.ok) { font_weight = cho_font_weight_parse(weight.u.s); if (font_weight == FW_EMPTY) { - fprintf(stderr, "INFO: Invalid config title section font weight value.\n"); + fprintf(stderr, "INFO: Invalid config chord section font weight value.\n"); return NULL; } else { - config->chord->font_weight = font_weight; + config->chord_font->weight = font_weight; } free(weight.u.s); } if (size.ok) { - config->chord->font_size = size.u.i; + config->chord_font->size = size.u.i; } } else if (strcmp(key_name, "comment") == 0) { if (name.ok) { - free(config->comment->font_name); - config->comment->font_name = name.u.s; + free(config->comment_font->name); + config->comment_font->name = name.u.s; + } + if (family.ok) { + font_family = cho_font_family_parse(family.u.s); + if (font_family == FF_EMPTY) { + fprintf(stderr, "INFO: Invalid config comment section font family value.\n"); + return NULL; + } else { + config->comment_font->family = font_family; + } } if (style.ok) { font_style = cho_font_style_parse(style.u.s); if (font_style == FS_EMPTY) { - fprintf(stderr, "INFO: Invalid config title section font style value.\n"); + fprintf(stderr, "INFO: Invalid config comment section font style value.\n"); return NULL; } else { - config->comment->font_style = font_style; + config->comment_font->style = font_style; } free(style.u.s); } if (weight.ok) { font_weight = cho_font_weight_parse(weight.u.s); if (font_weight == FW_EMPTY) { - fprintf(stderr, "INFO: Invalid config title section font weight value.\n"); + fprintf(stderr, "INFO: Invalid config comment section font weight value.\n"); return NULL; } else { - config->comment->font_weight = font_weight; + config->comment_font->weight = font_weight; } free(weight.u.s); } if (size.ok) { - config->comment->font_size = size.u.i; + config->comment_font->size = size.u.i; } } else if (strcmp(key_name, "comment_italic") == 0) { if (name.ok) { - free(config->comment_italic->font_name); - config->comment_italic->font_name = name.u.s; + free(config->comment_italic_font->name); + config->comment_italic_font->name = name.u.s; + } + if (family.ok) { + font_family = cho_font_family_parse(family.u.s); + if (font_family == FF_EMPTY) { + fprintf(stderr, "INFO: Invalid config comment_italic section font family value.\n"); + return NULL; + } else { + config->comment_italic_font->family = font_family; + } } if (style.ok) { font_style = cho_font_style_parse(style.u.s); if (font_style == FS_EMPTY) { - fprintf(stderr, "INFO: Invalid config title section font style value.\n"); + fprintf(stderr, "INFO: Invalid config comment_italic section font style value.\n"); return NULL; } else { - config->comment_italic->font_style = font_style; + config->comment_italic_font->style = font_style; } free(style.u.s); } if (weight.ok) { font_weight = cho_font_weight_parse(weight.u.s); if (font_weight == FW_EMPTY) { - fprintf(stderr, "INFO: Invalid config title section font weight value.\n"); + fprintf(stderr, "INFO: Invalid config comment_italic section font weight value.\n"); return NULL; } else { - config->comment_italic->font_weight = font_weight; + config->comment_italic_font->weight = font_weight; } free(weight.u.s); } if (size.ok) { - config->comment_italic->font_size = size.u.i; + config->comment_italic_font->size = size.u.i; } } else if (strcmp(key_name, "comment_box") == 0) { if (name.ok) { - free(config->comment_box->font_name); - config->comment_box->font_name = name.u.s; + free(config->comment_box_font->name); + config->comment_box_font->name = name.u.s; + } + if (family.ok) { + font_family = cho_font_family_parse(family.u.s); + if (font_family == FF_EMPTY) { + fprintf(stderr, "INFO: Invalid config comment_box section font family value.\n"); + return NULL; + } else { + config->comment_box_font->family = font_family; + } } if (style.ok) { font_style = cho_font_style_parse(style.u.s); if (font_style == FS_EMPTY) { - fprintf(stderr, "INFO: Invalid config title section font style value.\n"); + fprintf(stderr, "INFO: Invalid config comment_box section font style value.\n"); return NULL; } else { - config->comment_box->font_style = font_style; + config->comment_box_font->style = font_style; } free(style.u.s); } if (weight.ok) { font_weight = cho_font_weight_parse(weight.u.s); if (font_weight == FW_EMPTY) { - fprintf(stderr, "INFO: Invalid config title section font weight value.\n"); + fprintf(stderr, "INFO: Invalid config comment_box section font weight value.\n"); return NULL; } else { - config->comment_box->font_weight = font_weight; + config->comment_box_font->weight = font_weight; } free(weight.u.s); } if (size.ok) { - config->comment_box->font_size = size.u.i; + config->comment_box_font->size = size.u.i; } } else if (strcmp(key_name, "tab") == 0) { if (name.ok) { - free(config->tab->font_name); - config->tab->font_name = name.u.s; + free(config->tab_font->name); + config->tab_font->name = name.u.s; + } + if (family.ok) { + font_family = cho_font_family_parse(family.u.s); + if (font_family == FF_EMPTY) { + fprintf(stderr, "INFO: Invalid config tab section font family value.\n"); + return NULL; + } else { + config->tab_font->family = font_family; + } } if (style.ok) { font_style = cho_font_style_parse(style.u.s); if (font_style == FS_EMPTY) { - fprintf(stderr, "INFO: Invalid config title section font style value.\n"); + fprintf(stderr, "INFO: Invalid config tab section font style value.\n"); return NULL; } else { - config->tab->font_style = font_style; + config->tab_font->style = font_style; } free(style.u.s); } if (weight.ok) { font_weight = cho_font_weight_parse(weight.u.s); if (font_weight == FW_EMPTY) { - fprintf(stderr, "INFO: Invalid config title section font weight value.\n"); + fprintf(stderr, "INFO: Invalid config tab section font weight value.\n"); return NULL; } else { - config->tab->font_weight = font_weight; + config->tab_font->weight = font_weight; } free(weight.u.s); } if (size.ok) { - config->tab->font_size = size.u.i; + config->tab_font->size = size.u.i; } } else if (strcmp(key_name, "grid") == 0) { if (name.ok) { - free(config->grid->font_name); - config->grid->font_name = name.u.s; + free(config->grid_font->name); + config->grid_font->name = name.u.s; + } + if (family.ok) { + font_family = cho_font_family_parse(family.u.s); + if (font_family == FF_EMPTY) { + fprintf(stderr, "INFO: Invalid config grid section font family value.\n"); + return NULL; + } else { + config->grid_font->family = font_family; + } } if (style.ok) { font_style = cho_font_style_parse(style.u.s); if (font_style == FS_EMPTY) { - fprintf(stderr, "INFO: Invalid config title section font style value.\n"); + fprintf(stderr, "INFO: Invalid config grid section font style value.\n"); return NULL; } else { - config->grid->font_style = font_style; + config->grid_font->style = font_style; } free(style.u.s); } if (weight.ok) { font_weight = cho_font_weight_parse(weight.u.s); if (font_weight == FW_EMPTY) { - fprintf(stderr, "INFO: Invalid config title section font weight value.\n"); + fprintf(stderr, "INFO: Invalid config grid section font weight value.\n"); return NULL; } else { - config->grid->font_weight = font_weight; + config->grid_font->weight = font_weight; } free(weight.u.s); } if (size.ok) { - config->grid->font_size = size.u.i; + config->grid_font->size = size.u.i; } } else { fprintf(stderr, "INFO: Ignoring [fonts.%s] section in config file.\n", key_name); @@ -315,21 +401,15 @@ struct Config *config_load(const char *filepath) return config; } -static void config_section_free(struct ConfigSection *section) -{ - free(section->font_name); - free(section); -} - void config_free(struct Config *config) { - config_section_free(config->title); - config_section_free(config->text); - config_section_free(config->chord); - config_section_free(config->comment); - config_section_free(config->comment_italic); - config_section_free(config->comment_box); - config_section_free(config->tab); - config_section_free(config->grid); + cho_font_free(config->title_font); + cho_font_free(config->text_font); + cho_font_free(config->chord_font); + cho_font_free(config->comment_font); + cho_font_free(config->comment_italic_font); + cho_font_free(config->comment_box_font); + cho_font_free(config->tab_font); + cho_font_free(config->grid_font); free(config); } diff --git a/config.h b/config.h @@ -1,19 +1,13 @@ -struct ConfigSection { - char *font_name; - enum FontStyle font_style; - enum FontWeight font_weight; - float font_size; -}; - struct Config { - struct ConfigSection *title; - struct ConfigSection *text; - struct ConfigSection *chord; - struct ConfigSection *comment; - struct ConfigSection *comment_italic; - struct ConfigSection *comment_box; - struct ConfigSection *tab; - struct ConfigSection *grid; + struct Font *title_font; + struct Font *text_font; + struct Font *chord_font; + struct Font *comment_font; + struct Font *comment_italic_font; + struct Font *comment_box_font; + struct Font *tab_font; + struct Font *grid_font; + // TODO: section_name_font? }; struct Config *config_load(const char *filepath); diff --git a/fontconfig.c b/fontconfig.c @@ -0,0 +1,98 @@ +#include <stdio.h> +#include <stdbool.h> +#include <stdint.h> +#include <string.h> +// #include <ft2build.h> +// #include <freetype/freetype.h> +#include <fontconfig/fontconfig.h> +#include "fontconfig.h" + +bool file_extension_is_ttc(const char *filepath) +{ + int mark = -1; + int i = 0; + while (filepath[i] != 0) { + if (filepath[i] == '.') { + mark = i; + } + i++; + } + if (strcmp(&filepath[mark+1], "ttc") == 0) + return true; + return false; +} + +char *fontconfig_fontpath_find(struct Font *font, enum FontType font_type) +{ + char *filepath = NULL; + FcObjectSet *obj = FcObjectSetBuild(FC_FAMILY, FC_SLANT, FC_WEIGHT, FC_FONTFORMAT, FC_FONT_WRAPPER, FC_FILE, NULL); + FcPattern *pattern = FcPatternCreate(); + FcValue family = { .type = FcTypeString, .u.s = (FcChar8 *)font->name }; + FcPatternAdd(pattern, FC_FAMILY, family, FcFalse); + FcValue font_wrapper = { .type = FcTypeString, .u.s = (FcChar8 *)"SFNT" }; + FcPatternAdd(pattern, FC_FONT_WRAPPER, font_wrapper, FcFalse); + /* TODO: Also handle FF_NORMAL, FF_SANS and FF_SERIF, but how? */ + if (font->family == FF_MONOSPACE) { + FcValue spacing = { .type = FcTypeInteger, .u.i = FC_MONO }; + FcPatternAdd(pattern, FC_SPACING, spacing, FcFalse); + } + FcValue type; + type.type = FcTypeString; + if (font_type == FT_OTF) + type.u.s = (FcChar8 *)"CFF"; + else + type.u.s = (FcChar8 *)"TrueType"; + FcPatternAdd(pattern, FC_FONTFORMAT, type, FcFalse); + FcValue style; + style.type = FcTypeInteger; + switch (font->style) { + case FS_ROMAN: + style.u.i = FC_SLANT_ROMAN; + break; + case FS_OBLIQUE: + style.u.i = FC_SLANT_OBLIQUE; + break; + case FS_ITALIC: + style.u.i = FC_SLANT_ITALIC; + break; + } + FcPatternAdd(pattern, FC_SLANT, style, FcFalse); + FcValue weight; + weight.type = FcTypeInteger; + switch (font->weight) { + case FW_REGULAR: + weight.u.i = FC_WEIGHT_REGULAR; + break; + case FW_BOLD: + weight.u.i = FC_WEIGHT_BOLD; + break; + } + FcPatternAdd(pattern, FC_WEIGHT, weight, FcFalse); + FcFontSet *set = FcFontList(NULL, pattern, obj); + FcChar8 *file; + for (int i=0; i<set->nfont; i++) { + if (FcPatternGetString(set->fonts[i], FC_FILE, 0, &file) == FcResultMatch) { + if (!file_extension_is_ttc((const char *)file)) { + filepath = strdup((const char *)file); + break; + } + } + } + FcObjectSetDestroy(obj); + FcPatternDestroy(pattern); + FcFontSetDestroy(set); + return filepath; +} + +/* int main(int argc, char *argv[]) +{ + struct Font font = { + .name = "LiberationMono", + .family = FF_NORMAL, + .style = FS_ITALIC, + .weight = FW_BOLD, + .size = 0.0 + }; + fontconfig_fontpath_find(&font); + return 0; +} */ diff --git a/fontconfig.h b/fontconfig.h @@ -0,0 +1,8 @@ +#include "chordpro.h" + +enum FontType { + FT_TTF, + FT_OTF +}; + +char *fontconfig_fontpath_find(struct Font *font, enum FontType font_type); diff --git a/lorid.c b/lorid.c @@ -4,12 +4,15 @@ #include <stdint.h> #include <string.h> #include <getopt.h> +#include "config.h" #include "chordpro.h" #include "out_pdf.h" -#include "config.h" int main(int argc, char *argv[]) { + char *new = cho_font_name_sanitize("Noto Sans"); + printf("new: %s\n", new); + free(new); static struct option long_options[] = { { "print-default-config", no_argument, 0, 'p' }, { "config", required_argument, 0, 'c' }, @@ -35,7 +38,6 @@ int main(int argc, char *argv[]) return 1; } free(config_filepath); - config_free(config); if (argc == optind) { fp = stdin; } else if (argc == optind+1) { @@ -53,11 +55,12 @@ int main(int argc, char *argv[]) fprintf(stderr, "cho_parse failed.\n"); return 1; } - if (!out_pdf_new(argv[1], songs)) { + if (!out_pdf_new(argv[1], songs, config)) { fprintf(stderr, "out_pdf_new failed.\n"); return 1; } cho_songs_free(songs); + config_free(config); fclose(fp); return 0; } diff --git a/out_pdf.c b/out_pdf.c @@ -4,38 +4,29 @@ #include <pdfio.h> #include <pdfio-content.h> #include "chordpro.h" +#include "config.h" #include "out_pdf.h" +#include "fontconfig.h" -static char current_font[17]; +static struct Fnt **g_fonts = NULL; + +static char current_font[200]; static double current_font_size; static double current_y = MEDIABOX_HEIGHT - 25.0; static pdfio_obj_t *current_font_obj = NULL; -static pdfio_obj_t *inter_regular; -static pdfio_obj_t *inter_bold; -static pdfio_obj_t *inter_italic; -static pdfio_obj_t *inter_bold_italic; -static pdfio_obj_t *inter_light; -static pdfio_obj_t *inter_light_italic; -static pdfio_obj_t *get_font_obj_by_name(const char *name) +static pdfio_obj_t *out_pdf_fnt_obj_get_by_name(const char *name) { - if (strcmp(name, "Inter-Regular") == 0) { - return inter_regular; - } else if (strcmp(name, "Inter-Bold") == 0) { - return inter_bold; - } else if (strcmp(name, "Inter-Italic") == 0) { - return inter_italic; - } else if (strcmp(name, "Inter-BoldItalic") == 0) { - return inter_bold_italic; - } else if (strcmp(name, "Inter-Light") == 0) { - return inter_light; - } else if (strcmp(name, "Inter-LightItalic") == 0) { - return inter_light_italic; + int i = 0; + while (g_fonts[i] != NULL) { + if (strcmp(g_fonts[i]->name, name) == 0) + return g_fonts[i]->font; + i++; } return NULL; } -char *out_pdf_concat_line_items(struct ChoLineItem **items) +static char *out_pdf_concat_line_items(struct ChoLineItem **items) { char *line = NULL; int size = 1; @@ -57,24 +48,7 @@ char *out_pdf_concat_line_items(struct ChoLineItem **items) return line; } -static bool out_pdf_font_set(pdfio_stream_t *stream, const char *name, double size) -{ - if (!pdfioContentSetTextFont(stream, name, size)) { - fprintf(stderr, "pdfioContentSetTextFont failed.\n"); - return false; - } - if (strlen(name) > 17) - return false; - pdfio_obj_t *font_obj = get_font_obj_by_name(name); - if (font_obj == NULL) - return false; - strcpy(current_font, name); - current_font_obj = font_obj; - current_font_size = size; - return true; -} - -char *string_trim(const char *text) +static char *string_trim(const char *text) { char *trimmed_text = NULL; int begin = 0; @@ -115,30 +89,7 @@ char *string_trim(const char *text) return trimmed_text; } -/* static void out_pdf_font_find(struct Font *font) -{ - FcInit(); - FcObjectSet *obj = FcObjectSetBuild(FC_FAMILY, FC_STYLE, FC_WEIGHT, FC_FILE); - FcPattern *pattern = FcPatternCreate(); - FcValue value = { .type = FcTypeString, .u.s = (unsigned char *)font->name }; - FcPatternAdd(pattern, FC_FAMILY, value, FcFalse); - FcFontSet *set = FcFontList(NULL, pattern, obj); - for (int i=0; i<set->nfont; i++) { - FcChar8 *style, *filepath; - if (FcPatternGetString(set->fonts[i], FC_STYLE, 0, &style) == FcResultMatch) { - printf("style: %s\n", style); - if (FcPatternGetString(set->fonts[i], FC_FILE, 0, &filepath) == FcResultMatch) { - printf("filepath: %s\n", filepath); - } - } - } - FcFontSetDestroy(set); - FcObjectSetDestroy(obj); - FcPatternDestroy(pattern); - FcFini(); -} */ - -static void out_pdf_font_add(struct Font *font, struct Font ***array) +/* static void out_pdf_font_add(struct Font *font, struct Font ***array) { int a = 0; if (!*array) { @@ -152,7 +103,7 @@ static void out_pdf_font_add(struct Font *font, struct Font ***array) (*array)[a] = font; (*array)[a+1] = NULL; } -} +} */ static bool out_pdf_font_add_if_not_in(struct Font *font, struct Font ***array) { @@ -224,7 +175,7 @@ static void out_pdf_add_fonts(struct Font *font, struct Font ***fonts) cho_font_free(new_font); } -static void out_pdf_fonts_add_default(struct Font ***fonts) +/* static void out_pdf_fonts_add_default(struct Font ***fonts) { struct Font *font_regular = cho_font_new(); font_regular->name = strdup("Inter"); @@ -242,12 +193,46 @@ static void out_pdf_fonts_add_default(struct Font ***fonts) font_italic_bold->style = FS_ITALIC; font_italic_bold->weight = FW_BOLD; out_pdf_font_add(font_italic_bold, fonts); -} +} */ -static struct Font **out_pdf_font_get_all(struct ChoSong **songs) +static struct Font **out_pdf_font_get_all(struct ChoSong **songs, struct Config *config) { struct Font **fonts = NULL; - out_pdf_fonts_add_default(&fonts); + struct Font *font; + // out_pdf_fonts_add_default(&fonts); + bool added = false; + font = cho_font_duplicate(config->title_font); + added = out_pdf_font_add_if_not_in(font, &fonts); + if (!added) + cho_font_free(font); + font = cho_font_duplicate(config->text_font); + added = out_pdf_font_add_if_not_in(font, &fonts); + if (!added) + cho_font_free(font); + font = cho_font_duplicate(config->chord_font); + added = out_pdf_font_add_if_not_in(font, &fonts); + if (!added) + cho_font_free(font); + font = cho_font_duplicate(config->comment_font); + added = out_pdf_font_add_if_not_in(font, &fonts); + if (!added) + cho_font_free(font); + font = cho_font_duplicate(config->comment_italic_font); + added = out_pdf_font_add_if_not_in(font, &fonts); + if (!added) + cho_font_free(font); + font = cho_font_duplicate(config->comment_box_font); + added = out_pdf_font_add_if_not_in(font, &fonts); + if (!added) + cho_font_free(font); + font = cho_font_duplicate(config->tab_font); + added = out_pdf_font_add_if_not_in(font, &fonts); + if (!added) + cho_font_free(font); + font = cho_font_duplicate(config->grid_font); + added = out_pdf_font_add_if_not_in(font, &fonts); + if (!added) + cho_font_free(font); int so = 0; int se = 0; int li = 0; @@ -280,7 +265,7 @@ static bool out_pdf_chord_show(pdfio_stream_t *stream, const char *lyrics_line, char *line = malloc((strlen(lyrics_line)+1) * sizeof(char)); strcpy(line, lyrics_line); line[chord->position] = 0; - double width = pdfioContentTextMeasure(inter_regular, line, 16); + double width = pdfioContentTextMeasure(current_font_obj, line, current_font_size); free(line); if (!pdfioContentTextBegin(stream)) { fprintf(stderr, "pdfioContentTextBegin failed.\n"); @@ -354,7 +339,7 @@ static bool out_pdf_text_show(pdfio_stream_t *stream, const char *str, enum Alig { } */ -static char *out_pdf_filename(const char *old) +static char *out_pdf_filename_create(const char *old) { char *new = NULL; int mark = -1; @@ -392,54 +377,159 @@ static char *out_pdf_filename(const char *old) return new; } -bool out_pdf_new(const char *cho_filename, struct ChoSong **songs) +static struct Fnt *out_pdf_fnt_new(void) { - char *pdf_filename = out_pdf_filename(cho_filename); - pdfio_rect_t media_box_a4 = { 0.0, 0.0, MEDIABOX_WIDTH, MEDIABOX_HEIGHT }; - pdfio_rect_t crop_box = { 36.0, 36.0, MEDIABOX_WIDTH, MEDIABOX_HEIGHT }; - pdfio_file_t *pdf = pdfioFileCreate(pdf_filename, "2.0", &media_box_a4, &crop_box, NULL, NULL); - free(pdf_filename); - pdfio_dict_t *page1_dict = pdfioDictCreate(pdf); - struct Font **fonts = out_pdf_font_get_all(songs); - int f = 0; - while (fonts[f] != NULL) { - cho_font_print(fonts[f]); - // out_pdf_font_find(fonts[f]); - f++; + struct Fnt *fnt = malloc(sizeof(struct Fnt)); + fnt->name = NULL; + fnt->font = NULL; + return fnt; +} + +static char *out_pdf_fnt_name_create(struct Font *font) +{ + char *name = cho_font_name_sanitize(font->name); + const char *family = cho_font_family_to_string(font->family); + const char *style = cho_font_style_to_string(font->style); + const char *weight = cho_font_weight_to_string(font->weight); + int n = 0; + int i = 0; + char *fnt_name = malloc((strlen(name) + strlen(family) + strlen(style) + strlen(weight) + 4) * sizeof(char)); + while (name[i] != 0) { + fnt_name[n] = name[i]; + n++; + i++; } - cho_fonts_free(fonts); - inter_regular = pdfioFileCreateFontObjFromFile(pdf, "./fonts/Inter-Regular.ttf", true); - inter_bold = pdfioFileCreateFontObjFromFile(pdf, "./fonts/Inter-Bold.ttf", true); - inter_italic = pdfioFileCreateFontObjFromFile(pdf, "./fonts/Inter-Italic.ttf", true); - inter_bold_italic = pdfioFileCreateFontObjFromFile(pdf, "./fonts/Inter-BoldItalic.ttf", true); - inter_light = pdfioFileCreateFontObjFromFile(pdf, "./fonts/Inter-Light.ttf", true); - inter_light_italic = pdfioFileCreateFontObjFromFile(pdf, "./fonts/Inter-LightItalic.ttf", true); - if (!pdfioPageDictAddFont(page1_dict, "Inter-Regular", inter_regular)) { - fprintf(stderr, "pdfioPageDictAddFont failed.\n"); - return false; + i = 0; + fnt_name[n] = '-'; + n++; + while (family[i] != 0) { + fnt_name[n] = family[i]; + n++; + i++; } - if (!pdfioPageDictAddFont(page1_dict, "Inter-Bold", inter_bold)) { - fprintf(stderr, "pdfioPageDictAddFont failed.\n"); - return false; + i = 0; + fnt_name[n] = '-'; + n++; + while (style[i] != 0) { + fnt_name[n] = style[i]; + n++; + i++; } - if (!pdfioPageDictAddFont(page1_dict, "Inter-Italic", inter_italic)) { - fprintf(stderr, "pdfioPageDictAddFont failed.\n"); - return false; + i = 0; + fnt_name[n] = '-'; + n++; + while (weight[i] != 0) { + fnt_name[n] = weight[i]; + n++; + i++; } - if (!pdfioPageDictAddFont(page1_dict, "Inter-BoldItalic", inter_bold_italic)) { - fprintf(stderr, "pdfioPageDictAddFont failed.\n"); - return false; + fnt_name[n] = 0; + free(name); + return fnt_name; +} + +static void out_pdf_fnt_free(struct Fnt *fnt) +{ + free(fnt->name); + free(fnt); +} + +static void out_pdf_fnts_free(struct Fnt **fnts) +{ + int i = 0; + while (fnts[i] != NULL) { + out_pdf_fnt_free(fnts[i]); + i++; + } + free(fnts); +} + +static void out_pdf_fnt_add(struct Fnt *fnt, struct Fnt ***array) +{ + int a = 0; + if (!*array) { + *array = realloc(*array, 2 * sizeof(struct Fnt *)); + (*array)[0] = fnt; + (*array)[1] = NULL; + } else { + while ((*array)[a] != NULL) + a++; + *array = realloc(*array, (a+2) * sizeof(struct Fnt *)); + (*array)[a] = fnt; + (*array)[a+1] = NULL; } - if (!pdfioPageDictAddFont(page1_dict, "Inter-Light", inter_light)) { - fprintf(stderr, "pdfioPageDictAddFont failed.\n"); +} + +static bool out_pdf_font_set(pdfio_stream_t *stream, struct Font *font) +{ + char *name = out_pdf_fnt_name_create(font); + if (!pdfioContentSetTextFont(stream, name, font->size)) { + fprintf(stderr, "pdfioContentSetTextFont failed.\n"); return false; } - if (!pdfioPageDictAddFont(page1_dict, "Inter-LightItalic", inter_light_italic)) { - fprintf(stderr, "pdfioPageDictAddFont failed.\n"); + pdfio_obj_t *font_obj = out_pdf_fnt_obj_get_by_name(name); + if (font_obj == NULL) return false; + strcpy(current_font, name); + current_font_obj = font_obj; + current_font_size = font->size; + free(name); + return true; +} + +bool out_pdf_new(const char *cho_filename, struct ChoSong **songs, struct Config *config) +{ + char *pdf_filename = out_pdf_filename_create(cho_filename); + printf("pdf: %s\n", pdf_filename); + pdfio_rect_t media_box_a4 = { 0.0, 0.0, MEDIABOX_WIDTH, MEDIABOX_HEIGHT }; + pdfio_rect_t crop_box = { 36.0, 36.0, MEDIABOX_WIDTH, MEDIABOX_HEIGHT }; + pdfio_file_t *pdf = pdfioFileCreate(pdf_filename, "2.0", &media_box_a4, &crop_box, NULL, NULL); + free(pdf_filename); + pdfio_dict_t *page1_dict = pdfioDictCreate(pdf); + struct Font **needed_fonts = out_pdf_font_get_all(songs, config); + struct Fnt *fnt; + int f = 0; + char *fontpath; + while (needed_fonts[f] != NULL) { + fontpath = fontconfig_fontpath_find(needed_fonts[f], FT_TTF); + if (fontpath) { + fnt = out_pdf_fnt_new(); + fnt->name = out_pdf_fnt_name_create(needed_fonts[f]); + fnt->font = pdfioFileCreateFontObjFromFile(pdf, fontpath, true); + out_pdf_fnt_add(fnt, &g_fonts); + if (!pdfioPageDictAddFont(page1_dict, fnt->name, fnt->font)) { + fprintf(stderr, "pdfioPageDictAddFont failed.\n"); + return false; + } + free(fontpath); + } else { + fontpath = fontconfig_fontpath_find(needed_fonts[f], FT_OTF); + if (fontpath) { + fnt = out_pdf_fnt_new(); + fnt->name = out_pdf_fnt_name_create(needed_fonts[f]); + fnt->font = pdfioFileCreateFontObjFromFile(pdf, fontpath, true); + out_pdf_fnt_add(fnt, &g_fonts); + if (!pdfioPageDictAddFont(page1_dict, fnt->name, fnt->font)) { + fprintf(stderr, "pdfioPageDictAddFont failed.\n"); + return false; + } + free(fontpath); + } else { + fprintf(stderr, "INFO: Didn't find font file for following font:\n"); + cho_font_print(needed_fonts[f]); + return false; + } + } + f++; + } + cho_fonts_free(needed_fonts); + f = 0; + while (g_fonts[f] != NULL) { + printf("name: %s\n", g_fonts[f]->name); + f++; } pdfio_stream_t *page1_stream = pdfioFileCreatePage(pdf, page1_dict); - if (!out_pdf_font_set(page1_stream, "Inter-Regular", 14.0)) { + if (!out_pdf_font_set(page1_stream, config->text_font)) { fprintf(stderr, "out_pdf_font_set failed.\n"); return false; } @@ -472,7 +562,7 @@ bool out_pdf_new(const char *cho_filename, struct ChoSong **songs) if (strcmp(songs[so]->metadata[m]->name, "title") == 0) { const char *title = songs[so]->metadata[m]->value; pdfioFileSetTitle(pdf, title); - if (!out_pdf_font_set(page1_stream, "Inter-Bold", 18.0)) { + if (!out_pdf_font_set(page1_stream, config->title_font)) { fprintf(stderr, "out_pdf_font_set failed.\n"); return false; } @@ -491,7 +581,7 @@ bool out_pdf_new(const char *cho_filename, struct ChoSong **songs) while (songs[so]->sections[se] != NULL) { if (songs[so]->sections[se]->name) { const char *section_name = songs[so]->sections[se]->name; - if (!out_pdf_font_set(page1_stream, "Inter-Italic", 14.0)) { + if (!out_pdf_font_set(page1_stream, config->comment_italic_font)) { fprintf(stderr, "out_pdf_font_set failed.\n"); return false; } @@ -504,7 +594,7 @@ bool out_pdf_new(const char *cho_filename, struct ChoSong **songs) chords = songs[so]->sections[se]->lines[li]->chords; int count = cho_chord_count(chords); if (count > 0) { - if (!out_pdf_font_set(page1_stream, "Inter-Bold", 15.0)) { + if (!out_pdf_font_set(page1_stream, config->chord_font)) { fprintf(stderr, "out_pdf_font_set failed.\n"); return false; } @@ -525,7 +615,7 @@ bool out_pdf_new(const char *cho_filename, struct ChoSong **songs) } char *text; int items_count = cho_line_item_count(songs[so]->sections[se]->lines[li]->lyrics); - if (!out_pdf_font_set(page1_stream, "Inter-Regular", 16.0)) { + if (!out_pdf_font_set(page1_stream, config->text_font)) { fprintf(stderr, "out_pdf_font_set failed.\n"); return false; } @@ -561,5 +651,6 @@ bool out_pdf_new(const char *cho_filename, struct ChoSong **songs) fprintf(stderr, "pdfioFileClose failed.\n"); return false; } + out_pdf_fnts_free(g_fonts); return true; } diff --git a/out_pdf.h b/out_pdf.h @@ -1,3 +1,5 @@ +#include <pdfio.h> + #define MEDIABOX_HEIGHT 842.0 #define MEDIABOX_WIDTH 595.0 #define PAGE_HEIGHT MEDIABOX_HEIGHT - 36.0 @@ -11,9 +13,9 @@ enum Alignment { CONTINUE }; -struct FontObj { +struct Fnt { char *name; - // pdfio_obj_t + pdfio_obj_t *font; }; -bool out_pdf_new(const char *cho_filename, struct ChoSong **songs); +bool out_pdf_new(const char *cho_filename, struct ChoSong **songs, struct Config *config); diff --git a/todo b/todo @@ -10,3 +10,4 @@ chordpro markup the whole chords advanced stuff transpose define chords + chord diagrams