lorid

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

commit 8a62c19c899c643177e0d2448e9e457858457417
parent 9e08b6cb16c8a7d76cdacae1bab328df2cd0e091
Author: nibo <nibo@relim.de>
Date:   Tue, 15 Oct 2024 14:26:22 +0200

Start with image assets

Diffstat:
Mchordpro.c | 154++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------
Mchordpro.h | 1+
Mutil.c | 16++++++++++++++++
Mutil.h | 9+++++++++
4 files changed, 164 insertions(+), 16 deletions(-)

diff --git a/chordpro.c b/chordpro.c @@ -181,10 +181,26 @@ static const char *g_chordpro_filepath = NULL; static int *g_transpose_history = NULL; static int *g_transpose = NULL; static size_t g_line_number = 1; +struct ChoImage **g_image_assets = NULL; +static int g_ia = 0; #ifdef DEBUG -static char *chord_qualifier_enums[] = { +static const char *alignment_enums[] = { + "A_LEFT", + "A_CENTER", + "A_RIGHT" +}; + +static const char *anchor_enums[] = { + "AN_PAPER", + "AN_PAGE", + "AN_COLUMN", + "AN_LINE", + "AN_FLOAT" +}; + +static const char *chord_qualifier_enums[] = { "CQ_EMPTY", "CQ_MIN", "CQ_MAJ", @@ -192,7 +208,7 @@ static char *chord_qualifier_enums[] = { "CQ_DIM" }; -const char *directive_type_enums[] = { +static const char *directive_type_enums[] = { "DT_EMPTY", "DT_ENVIRONMENT", "DT_METADATA", @@ -205,7 +221,7 @@ const char *directive_type_enums[] = { "DT_CUSTOM" }; -const char *section_type_enums[] = { +static const char *section_type_enums[] = { "ST_EMPTY", "ST_NEWSONG", "ST_CHORUS", @@ -216,13 +232,13 @@ const char *section_type_enums[] = { "ST_CUSTOM" }; -const char *position_enums[] = { +static const char *position_enums[] = { "POS_EMPTY", "POS_START", "POS_END" }; -const char *song_fragment_type_enums[] = { +static const char *song_fragment_type_enums[] = { "SF_EMPTY", "SF_CHORD", "SF_ANNOT", @@ -237,7 +253,7 @@ const char *song_fragment_type_enums[] = { "SF_LABEL" }; -const char *style_property_type_enums[] = { +static const char *style_property_type_enums[] = { "SPT_EMPTY", "SPT_FONT", "SPT_SIZE", @@ -1980,6 +1996,7 @@ void cho_songs_free(struct ChoSong **songs) static struct ChoImage *cho_image_new(void) { struct ChoImage *image = malloc(sizeof(struct ChoImage)); + image->is_asset = false; image->id = NULL; image->src = NULL; image->width = NULL; @@ -2025,10 +2042,83 @@ static void cho_image_free(struct ChoImage *image) free(image); } +static struct ChoImage * +cho_image_find_asset(const char *id) +{ + int i; + for (i = 0; i<g_ia; i++) { + if (!strcmp(g_image_assets[i]->id, id)) { + return g_image_assets[i]; + } + } + return NULL; +} + +#ifdef DEBUG +static void +cho_debug_image_print(struct ChoImage *image) +{ + printf("---- BEGIN IMAGE ----\n"); + printf("is_asset: %d\n", image->is_asset); + if (image->id) { + printf("id: %s\n", image->id); + } else { + printf("id: NULL\n"); + } + if (image->src) { + printf("src: %s\n", image->src); + } else { + printf("src: NULL\n"); + } + if (image->width) { + printf("width: %s\n", double_or_percent_to_string(image->width)); + } else { + printf("width: NULL\n"); + } + if (image->height) { + printf("height: %s\n", double_or_percent_to_string(image->height)); + } else { + printf("height: NULL\n"); + } + if (image->scale) { + printf("scale: %s\n", double_or_percent_to_string(image->scale)); + } else { + printf("scale: NULL\n"); + } + printf("align: %s\n", alignment_enums[image->align]); + printf("border: %.1f\n", image->border); + if (image->spread_space) { + printf("spread_space: %s\n", double_or_percent_to_string(image->spread_space)); + } else { + printf("spread_space: NULL\n"); + } + if (image->href) { + printf("href: %s\n", image->href); + } else { + printf("href: NULL\n"); + } + if (image->x) { + printf("x: %s\n", double_or_percent_to_string(image->x)); + } else { + printf("x: NULL\n"); + } + if (image->y) { + printf("y: %s\n", double_or_percent_to_string(image->y)); + } else { + printf("y: NULL\n"); + } + printf("anchor: %s\n", anchor_enums[image->anchor]); + printf("dx: %.1f\n", image->dx); + printf("dy: %.1f\n", image->dy); + printf("w: %.1f\n", image->w); + printf("h: %.1f\n", image->h); + printf("---- END IMAGE ------\n"); +} +#endif /* DEBUG */ + static bool cho_image_option_parse(struct ChoImage *image, const char *name, const char *value) { char *endptr; - // size_t value_len = strlen(value); if (!strcmp(name, "id")) { image->id = strdup(value); } else @@ -2127,6 +2217,7 @@ static bool cho_image_option_parse(struct ChoImage *image, const char *name, con static struct ChoImage *cho_image_directive_parse(const char *str) { struct ChoImage *image = cho_image_new(); + struct ChoImage *asset; char c; enum OptionState state = OS_NAME; enum AttrValueSyntax avs = AVS_NO; @@ -2136,6 +2227,7 @@ static struct ChoImage *cho_image_directive_parse(const char *str) int v = 0; memset(name, 0, sizeof(name)); memset(value, 0, sizeof(value)); + int option_count = 0; int i; for (i = 0; str[i] != 0; i++) { c = str[i]; @@ -2152,8 +2244,6 @@ static struct ChoImage *cho_image_directive_parse(const char *str) } if (c == '=') { name[n] = 0; - // memset(name, 0, n); - // n = 0; state = OS_VALUE; break; } @@ -2191,11 +2281,11 @@ static struct ChoImage *cho_image_directive_parse(const char *str) (avs == AVS_UNQUOTED && (c == ' ' || c == '\t')) ) { value[v] = 0; - printf("'%s' -> '%s'\n", name, value); if (!cho_image_option_parse(image, name, value)) { LOG_DEBUG("cho_image_option_check failed."); return NULL; } + option_count++; memset(name, 0, n); memset(value, 0, v); n = 0; @@ -2211,11 +2301,26 @@ static struct ChoImage *cho_image_directive_parse(const char *str) } if (avs == AVS_UNQUOTED) { value[v] = 0; - printf("'%s' -> '%s'\n", name, value); if (!cho_image_option_parse(image, name, value)) { LOG_DEBUG("cho_image_option_check failed."); return NULL; } + option_count++; + } + if (image->id) { + if (image->src) { + if (option_count > 2) { + cho_log(LOG_ERR, "Defining an image asset disallows any options other than 'id' and 'src'."); + return NULL; + } + image->is_asset = true; + } else { + asset = cho_image_find_asset(image->id); + if (!asset) { + cho_log(LOG_ERR, "There is no image asset with the id '%s'.", image->id); + return NULL; + } + } } return image; } @@ -2920,12 +3025,25 @@ struct ChoSong **cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct te += strlen(trimmed_directive_value); break; case DT_IMAGE: - image = cho_image_directive_parse(directive_value); - if (!image) { - LOG_DEBUG("cho_image_directive_parse failed."); - return NULL; + if (strstr(directive_value, "=")) { + image = cho_image_directive_parse(directive_value); + if (!image) { + LOG_DEBUG("cho_image_directive_parse failed."); + return NULL; + } + } else { + image = cho_image_new(); + image->src = str_remove_leading_whitespace(directive_value); } - cho_image_free(image); + if (image->is_asset) { + g_image_assets = realloc(g_image_assets, (g_ia+1) * sizeof(struct ChoImage *)); + g_image_assets[g_ia] = image; + g_ia++; + } else { + cho_image_free(image); + } + // cho_debug_image_print(image); + // cho_image_free(image); break; case DT_PREAMBLE: cho_log(LOG_ERR, "Preamble directive '%s' can't have a value.", directive_name); @@ -3376,6 +3494,10 @@ struct ChoSong **cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct songs = realloc(songs, (so+1) * sizeof(struct ChoSong *)); songs[so] = NULL; free(g_transpose_history); + for (e = 0; e<g_ia; e++) { + cho_image_free(g_image_assets[e]); + } + free(g_image_assets); bool exist_title = false; for (so = 0; songs[so]; so++) { for (m = 0; songs[so]->metadata[m]; m++) { diff --git a/chordpro.h b/chordpro.h @@ -139,6 +139,7 @@ enum OptionState { }; struct ChoImage { + bool is_asset; char *id; char *src; struct DoubleOrPercent *width; diff --git a/util.c b/util.c @@ -265,6 +265,22 @@ char *filepath_dirname(const char *path) return dirname; } +const char * +double_or_percent_to_string(struct DoubleOrPercent *dop) +{ + static char str[8+1]; + if (dop->is_percent) { + sprintf((char *)&str, "%d%%", dop->u.p); + } else { + if (dop->u.d > 999999) { + sprintf((char *)&str, ">999.999"); + } else { + sprintf((char *)&str, "%.1f", dop->u.d); + } + } + return str; +} + struct DoubleOrPercent * double_or_percent_create(const char *str) { diff --git a/util.h b/util.h @@ -17,6 +17,14 @@ enum FileType { F_OTHER }; +/* + INFO: Typically I would directly calculate the percent + and store it as a double but I can't do that here because + the percent refers to something in the pdf that will be + generated. At parsing stage there is no information about + the pdf. +*/ + struct DoubleOrPercent { bool is_percent; union { @@ -40,4 +48,5 @@ char *filepath_add_ending_slash_if_missing(const char *path); char *filepath_basename(const char *path); char *filepath_dirname(const char *path); +const char *double_or_percent_to_string(struct DoubleOrPercent *dop); struct DoubleOrPercent *double_or_percent_create(const char *str);