commit 8a62c19c899c643177e0d2448e9e457858457417
parent 9e08b6cb16c8a7d76cdacae1bab328df2cd0e091
Author: nibo <nibo@relim.de>
Date: Tue, 15 Oct 2024 14:26:22 +0200
Start with image assets
Diffstat:
| M | chordpro.c | | | 154 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------- |
| M | chordpro.h | | | 1 | + |
| M | util.c | | | 16 | ++++++++++++++++ |
| M | util.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);