commit 6b6cb82f00af07b909daf787245dd4cea3e76d34
parent 6904c2a57c8635c9e773fd3cd11ad8d6a84a7da9
Author: nibo <nibo@relim.de>
Date: Fri, 28 Jun 2024 18:08:44 +0200
Edit a lot
Diffstat:
| M | Makefile | | | 4 | ++-- |
| M | chordpro.c | | | 338 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------- |
| M | chordpro.h | | | 27 | +++++++++++++++++++++------ |
| A | config.c | | | 335 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | config.h | | | 20 | ++++++++++++++++++++ |
| M | lorid.c | | | 105 | +++++++++++++++++++++++++++---------------------------------------------------- |
| M | out_pdf.c | | | 288 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------- |
| M | out_pdf.h | | | 3 | ++- |
| M | todo | | | 1 | + |
9 files changed, 957 insertions(+), 164 deletions(-)
diff --git a/Makefile b/Makefile
@@ -1,4 +1,4 @@
all:
- $(CC) -Wall -Wextra -O2 chordpro.c out_pdf.c lorid.c -o lorid -lpdfio
+ $(CC) -Wall -Wextra -O2 config.c chordpro.c out_pdf.c lorid.c -o lorid -lpdfio -ltoml
debug:
- $(CC) -g -Wall -Wextra chordpro.c out_pdf.c lorid.c -o lorid -lpdfio
+ $(CC) -g -Wall -Wextra config.c chordpro.c out_pdf.c lorid.c -o lorid -lpdfio -ltoml
diff --git a/chordpro.c b/chordpro.c
@@ -31,6 +31,17 @@ static const char *preamble_directives[] = {
"new_song", "ns", NULL
};
+static const char *font_directives[] = {
+ "chordfont", "cf", "chordsize", "cs", "chordcolour",
+ "chorusfont", "chorussize", "choruscolour",
+ "gridfont", "gridsize", "gridcolour",
+ "tabfont", "tabsize", "tabcolour",
+ "textfont", "tf", "textsize", "ts", "textcolour",
+ "titlefont", "titlesize", "titlecolour"
+ /* "footerfont", "footersize", "footercolour",
+ "tocfont", "tocsize", "toccolour", */
+};
+
static const char *the_state(enum State state)
{
switch (state) {
@@ -69,6 +80,8 @@ const char *the_dtype(enum DirectiveType dtype)
return "DT_FORMATTING";
case DT_PREAMBLE:
return "DT_PREAMBLE";
+ case DT_FONT:
+ return "DT_FONT";
case DT_CUSTOM:
return "DT_CUSTOM";
}
@@ -78,6 +91,8 @@ const char *the_dtype(enum DirectiveType dtype)
const char *the_stype(enum SectionType stype)
{
switch (stype) {
+ case ST_EMPTY:
+ return "ST_EMPTY";
case ST_CHORUS:
return "ST_CHORUS";
case ST_VERSE:
@@ -108,6 +123,8 @@ const char *the_pos(enum Position pos)
const char *the_font_family(enum FontFamily font_family)
{
switch (font_family) {
+ case FF_EMPTY:
+ return "FF_EMPTY";
case FF_NORMAL:
return "FF_NORMAL";
case FF_SANS:
@@ -123,6 +140,8 @@ const char *the_font_family(enum FontFamily font_family)
const char *the_font_style(enum FontStyle style)
{
switch (style) {
+ case FS_EMPTY:
+ return "FS_EMPTY";
case FS_NORMAL:
return "FS_NORMAL";
case FS_OBLIQUE:
@@ -136,6 +155,8 @@ const char *the_font_style(enum FontStyle style)
const char *the_font_weight(enum FontWeight weight)
{
switch (weight) {
+ case FW_EMPTY:
+ return "FW_EMPTY";
case FW_NORMAL:
return "FW_NORMAL";
case FW_BOLD:
@@ -323,14 +344,88 @@ struct RGBColor *cho_color_parse(const char *str)
return color;
}
+static struct Font *cho_font_new(void)
+{
+ struct Font *font = malloc(sizeof(struct Font));
+ font->name = NULL;
+ font->family = FF_NORMAL;
+ font->style = FS_NORMAL;
+ font->weight = FW_NORMAL;
+ font->size = DEFAULT_FONT_SIZE;
+ return font;
+}
+
+static struct Font *cho_font_duplicate(struct Font *font)
+{
+ struct Font *copy = malloc(sizeof(struct Font));
+ if (font->name)
+ copy->name = strdup(font->name);
+ else
+ copy->name = NULL;
+ copy->family = font->family;
+ copy->style = font->style;
+ copy->weight = font->weight;
+ copy->size = font->size;
+ return copy;
+}
+
+void cho_font_print(struct Font *font)
+{
+ printf("---- BEGIN FONT ----\n");
+ if (font->name)
+ printf("font name: %s\n", font->name);
+ else
+ printf("font name: NULL\n");
+ printf("font family: %s\n", the_font_family(font->family));
+ printf("font style: %s\n", the_font_style(font->style));
+ printf("font weight: %s\n", the_font_weight(font->weight));
+ printf("font size: %f\n", font->size);
+ printf("---- END FONT ------\n");
+}
+
+void cho_font_free(struct Font *font)
+{
+ free(font->name);
+ free(font);
+}
+
+enum FontStyle cho_font_style_parse(const char *str)
+{
+ if (strcasecmp(str, "italic") == 0) {
+ return FS_ITALIC;
+ } else if (strcasecmp(str, "oblique") == 0) {
+ return FS_OBLIQUE;
+ } else if (strcasecmp(str, "normal") == 0) {
+ return FS_NORMAL;
+ } else if (strcasecmp(str, "regular") == 0) {
+ return FS_NORMAL;
+ } else {
+ return FS_EMPTY;
+ }
+}
+
+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;
+ } else if (strcasecmp(str, "normal") == 0) {
+ return FW_NORMAL;
+ } else {
+ return FW_EMPTY;
+ }
+}
+
struct Style *cho_style_new(void)
{
struct Style *style = malloc(sizeof(struct Style));
- style->font = NULL;
+ style->font = cho_font_new();
+ /* style->font = NULL;
style->font_family = FF_NORMAL;
style->font_size = DEFAULT_FONT_SIZE;
style->font_style = FS_NORMAL;
- style->font_weight = FW_NORMAL;
+ style->font_weight = FW_NORMAL; */
style->foreground_color = cho_rgbcolor_new(20, 20, 20);
style->background_color = cho_rgbcolor_new(255, 255, 255);
style->underline_style = LS_NONE;
@@ -348,7 +443,8 @@ struct Style *cho_style_new(void)
void cho_style_free(struct Style *style)
{
- free(style->font);
+ cho_font_free(style->font);
+ // free(style->font);
free(style->foreground_color);
free(style->background_color);
free(style->underline_color);
@@ -362,11 +458,12 @@ void cho_style_free(struct Style *style)
struct Style *cho_style_duplicate(struct Style *style)
{
struct Style *copy = malloc(sizeof(struct Style));
- copy->font = style->font ? strdup(style->font) : NULL;
+ copy->font = cho_font_duplicate(style->font);
+ /* copy->font = style->font ? strdup(style->font) : NULL;
copy->font_family = style->font_family;
copy->font_size = style->font_size;
copy->font_style = style->font_style;
- copy->font_weight = style->font_weight;
+ copy->font_weight = style->font_weight; */
copy->foreground_color = cho_rgbcolor_duplicate(style->foreground_color);
copy->background_color = cho_rgbcolor_duplicate(style->background_color);
copy->underline_style = style->underline_style;
@@ -382,11 +479,115 @@ struct Style *cho_style_duplicate(struct Style *style)
return copy;
}
+struct Font *cho_style_font_desc_parse(const char *str)
+{
+ struct Font *font = cho_font_new();
+ float size = -1.0;
+ char **words = malloc(sizeof(char *));
+ int w = 0;
+ words[w] = NULL;
+ int i = 0;
+ int k = 0;
+ while (str[i] != 0) {
+ if (str[i] == ' ') {
+ words[w] = realloc(words[w], (k+1) * sizeof(char));
+ words[w][k] = 0;
+ if (strlen(words[w]) == 0)
+ free(words[w]);
+ else
+ w++;
+ k = 0;
+ words = realloc(words, (w+1) * sizeof(char *));
+ words[w] = NULL;
+ } else {
+ words[w] = realloc(words[w], (k+1) * sizeof(char));
+ words[w][k] = str[i];
+ k++;
+ }
+ i++;
+ }
+ words[w] = realloc(words[w], (k+1) * sizeof(char));
+ words[w][k] = 0;
+ w++;
+ words = realloc(words, (w+1) * sizeof(char *));
+ words[w] = NULL;
+ w = 0;
+ int stop_at = -1;
+ while (words[w] != NULL) {
+ if (strcasecmp(words[w], "italic") == 0) {
+ font->style = FS_ITALIC;
+ if (stop_at == -1)
+ stop_at = w;
+ } else if (strcasecmp(words[w], "bold") == 0) {
+ font->weight = FW_BOLD;
+ if (stop_at == -1)
+ stop_at = w;
+ } else if (strcasecmp(words[w], "oblique") == 0) {
+ font->style = FS_OBLIQUE;
+ if (stop_at == -1)
+ stop_at = w;
+ } else if (strcasecmp(words[w], "regular") == 0) {
+ font->weight = FW_NORMAL;
+ if (stop_at == -1)
+ stop_at = w;
+ } else if (strcasecmp(words[w], "normal") == 0) {
+ font->style = FS_NORMAL;
+ if (stop_at == -1)
+ stop_at = w;
+ } 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;
+ } else if (strcasecmp(words[w], "monospace") == 0) {
+ font->family = FF_MONOSPACE;
+ if (stop_at == -1)
+ stop_at = w;
+ } else {
+ size = strtof(words[w], NULL);
+ if (size == 0.0)
+ goto SKIP;
+ font->size = size;
+ if (stop_at == -1)
+ stop_at = w;
+ }
+ SKIP:
+ w++;
+ }
+ k = 0;
+ int n = 0;
+ for (int i=0; i<stop_at; i++) {
+ while (words[i][k] != 0) {
+ font->name = realloc(font->name, (n+1) * sizeof(char));
+ font->name[n] = words[i][k];
+ n++;
+ k++;
+ }
+ font->name = realloc(font->name, (n+1) * sizeof(char));
+ font->name[n] = ' ';
+ n++;
+ k = 0;
+ }
+ n--;
+ font->name[n] = 0;
+ w = 0;
+ while (words[w] != NULL) {
+ free(words[w]);
+ w++;
+ }
+ free(words);
+ return font;
+}
+
struct Style *cho_style_get(const char *tag_name, struct Attr **attrs, struct Style *inherited_style)
{
size_t value_len, last_char;
struct RGBColor *rgb_color;
struct Style *style;
+ struct Font *font;
if (inherited_style)
style = cho_style_duplicate(inherited_style);
else
@@ -395,19 +596,27 @@ struct Style *cho_style_get(const char *tag_name, struct Attr **attrs, struct St
int a = 0;
while (attrs[a] != NULL) {
if (strcmp(attrs[a]->name, "font_desc") == 0) {
- style->font = strdup(attrs[a]->value);
+ font = cho_style_font_desc_parse(attrs[a]->value);
+ cho_font_free(style->font);
+ style->font = font;
+ /* style->font = strdup(font->name);
+ style->font_family = font->family;
+ style->font_style = font->style;
+ style->font_weight = font->weight;
+ style->font_size = font->size;
+ cho_font_free(font); */
} else if (
strcmp(attrs[a]->name, "font_family") == 0 ||
strcmp(attrs[a]->name, "face") == 0
) {
if (strcmp(attrs[a]->value, "normal") == 0) {
- style->font_family = FF_NORMAL;
+ style->font->family = FF_NORMAL;
} else if (strcmp(attrs[a]->value, "sans") == 0) {
- style->font_family = FF_SANS;
+ style->font->family = FF_SANS;
} else if (strcmp(attrs[a]->value, "serif") == 0) {
- style->font_family = FF_SERIF;
+ style->font->family = FF_SERIF;
} else if (strcmp(attrs[a]->value, "monospace") == 0) {
- style->font_family = FF_MONOSPACE;
+ style->font->family = FF_MONOSPACE;
} else {
fprintf(stderr, "INFO: Invalid value in attribute 'font_family/face'.\n");
}
@@ -419,7 +628,7 @@ struct Style *cho_style_get(const char *tag_name, struct Attr **attrs, struct St
attrs[a]->value[last_char] = 0;
int percentage = atoi(attrs[a]->value);
if (percentage != 0 && percentage <= 100) {
- style->font_size *= percentage / 100.0;
+ style->font->size *= percentage / 100.0;
} else {
fprintf(stderr, "INFO: Invalid percentage in attribute 'size'.\n");
}
@@ -429,50 +638,50 @@ struct Style *cho_style_get(const char *tag_name, struct Attr **attrs, struct St
} else if (isdigit(attrs[a]->value[0]) != 0) {
float size = strtof(attrs[a]->value, NULL);
if (size != 0.0)
- style->font_size = size;
+ style->font->size = size;
else
fprintf(stderr, "INFO: Invalid number in attribute 'size'.\n");
} else if (strcmp(attrs[a]->value, "xx-small") == 0) {
- style->font_size *= 0.8;
- style->font_size *= 0.8;
- style->font_size *= 0.8;
+ style->font->size *= 0.8;
+ style->font->size *= 0.8;
+ style->font->size *= 0.8;
} else if (strcmp(attrs[a]->value, "x-small") == 0) {
- style->font_size *= 0.8;
- style->font_size *= 0.8;
+ style->font->size *= 0.8;
+ style->font->size *= 0.8;
} else if (strcmp(attrs[a]->value, "small") == 0) {
- style->font_size *= 0.8;
+ style->font->size *= 0.8;
// } else if (strcmp(attrs[a]->value, "medium") == 0) {
} else if (strcmp(attrs[a]->value, "large") == 0) {
- style->font_size *= 1.8;
+ style->font->size *= 1.8;
} else if (strcmp(attrs[a]->value, "x-large") == 0) {
- style->font_size *= 1.8;
- style->font_size *= 1.8;
+ style->font->size *= 1.8;
+ style->font->size *= 1.8;
} else if (strcmp(attrs[a]->value, "xx-large") == 0) {
- style->font_size *= 1.8;
- style->font_size *= 1.8;
- style->font_size *= 1.8;
+ style->font->size *= 1.8;
+ style->font->size *= 1.8;
+ style->font->size *= 1.8;
} else if (strcmp(attrs[a]->value, "larger") == 0) {
- style->font_size *= 1.8;
+ style->font->size *= 1.8;
} else if (strcmp(attrs[a]->value, "smaller") == 0) {
- style->font_size *= 0.8;
+ style->font->size *= 0.8;
} else {
fprintf(stderr, "INFO: Invalid value '%s' for the attribute 'size'.\n", attrs[a]->value);
}
} else if (strcmp(attrs[a]->name, "style") == 0) {
if (strcmp(attrs[a]->value, "normal") == 0) {
- style->font_style = FS_NORMAL;
+ style->font->style = FS_NORMAL;
} else if (strcmp(attrs[a]->value, "oblique") == 0) {
- style->font_style = FS_OBLIQUE;
+ style->font->style = FS_OBLIQUE;
} else if (strcmp(attrs[a]->value, "italic") == 0) {
- style->font_style = FS_ITALIC;
+ style->font->style = FS_ITALIC;
} else {
fprintf(stderr, "INFO: Invalid value in attribute 'style'.\n");
}
} else if (strcmp(attrs[a]->name, "weight") == 0) {
if (strcmp(attrs[a]->value, "normal") == 0) {
- style->font_style = FS_NORMAL;
- } else if (strcmp(attrs[a]->value, "oblique") == 0) {
- style->font_style = FS_OBLIQUE;
+ style->font->weight = FW_NORMAL;
+ } else if (strcmp(attrs[a]->value, "bold") == 0) {
+ style->font->weight = FW_BOLD;
} else {
fprintf(stderr, "INFO: Invalid value in attribute 'weight'.\n");
}
@@ -537,7 +746,7 @@ struct Style *cho_style_get(const char *tag_name, struct Attr **attrs, struct St
attrs[a]->value[last_char] = 0;
int percentage = atoi(&attrs[a]->value[1]);
if (percentage != 0 && percentage <= 100) {
- style->rise = (style->font_size / 2) * percentage / 100.0;
+ style->rise = (style->font->size / 2) * percentage / 100.0;
} else {
fprintf(stderr, "INFO: Invalid percentage in attribute 'rise'.\n");
}
@@ -558,7 +767,7 @@ struct Style *cho_style_get(const char *tag_name, struct Attr **attrs, struct St
int percentage = atoi(attrs[a]->value);
if (percentage != 0 && percentage <= 100) {
// TODO: Test if that's right
- float more = style->font_size / 2.0 * percentage / 100.0;
+ float more = style->font->size / 2.0 * percentage / 100.0;
style->rise += more;
} else {
fprintf(stderr, "INFO: Invalid percentage in attribute 'rise'.\n");
@@ -598,25 +807,25 @@ struct Style *cho_style_get(const char *tag_name, struct Attr **attrs, struct St
a++;
}
} else if (strcmp(tag_name, "b") == 0) {
- style->font_weight = FW_BOLD;
+ style->font->weight = FW_BOLD;
} else if (strcmp(tag_name, "big") == 0) {
- style->font_size *= 0.8;
+ style->font->size *= 0.8;
} else if (strcmp(tag_name, "i") == 0) {
- style->font_style = FS_ITALIC;
+ style->font->style = FS_ITALIC;
} else if (strcmp(tag_name, "s") == 0) {
style->strikethrough = true;
} else if (strcmp(tag_name, "sub") == 0) {
- style->font_size *= 0.8;
- style->rise = (style->font_size / 2) * 0.3;
+ style->font->size *= 0.8;
+ style->rise = (style->font->size / 2) * 0.3;
} else if (strcmp(tag_name, "sup") == 0) {
- style->font_size *= 0.8;
- float thirty_percent = (style->font_size / 2) * 0.3;
+ style->font->size *= 0.8;
+ float thirty_percent = (style->font->size / 2) * 0.3;
// TODO: Is that right?
style->rise = thirty_percent - thirty_percent * 2;
} else if (strcmp(tag_name, "small") == 0) {
- style->font_size *= 0.8;
+ style->font->size *= 0.8;
} else if (strcmp(tag_name, "tt") == 0) {
- style->font_family = FF_MONOSPACE;
+ style->font->family = FF_MONOSPACE;
} else if (strcmp(tag_name, "u") == 0) {
style->underline_style = LS_SINGLE;
} else {
@@ -630,14 +839,7 @@ struct Style *cho_style_get(const char *tag_name, struct Attr **attrs, struct St
void cho_style_print(struct Style *style)
{
printf("---- BEGIN STYLE ----\n");
- if (style->font)
- printf("font: %s\n", style->font);
- else
- printf("font: NULL\n");
- printf("font_family: %s\n", the_font_family(style->font_family));
- printf("font_size: %f\n", style->font_size);
- printf("font_style: %s\n", the_font_style(style->font_style));
- printf("font_weight: %s\n", the_font_weight(style->font_weight));
+ cho_font_print(style->font);
printf("foreground_color: %s\n", the_rgb_color(style->foreground_color));
printf("background_color: %s\n", the_rgb_color(style->background_color));
printf("underline_style: %s\n", the_line_style(style->underline_style));
@@ -792,6 +994,14 @@ struct ChoChord *cho_chord_new(void)
return chord;
}
+int cho_chord_count(struct ChoChord **chords)
+{
+ int i = 0;
+ while (chords[i] != NULL)
+ i++;
+ return i;
+}
+
struct ChoLine *cho_line_new(void)
{
struct ChoLine *line = malloc(sizeof(struct ChoLine));
@@ -839,7 +1049,7 @@ int cho_line_item_count(struct ChoLineItem **items)
struct ChoSection *cho_section_new(void)
{
struct ChoSection *section = malloc(sizeof(struct ChoSection));
- section->type = -1;
+ section->type = ST_EMPTY;
section->name = NULL;
section->lines = NULL;
return section;
@@ -996,7 +1206,7 @@ struct ChoDirective *directive_parse(const char *name)
while (metadata_directives[i] != NULL) {
if (strcmp(metadata_directives[i], name) == 0) {
directive->dtype = DT_METADATA;
- directive->stype = -1;
+ directive->stype = ST_EMPTY;
directive->position = -1;
goto END;
}
@@ -1010,16 +1220,16 @@ struct ChoDirective *directive_parse(const char *name)
) {
directive->style->background_color = cho_rgbcolor_new(228, 228, 228);
directive->dtype = DT_FORMATTING;
- directive->stype = -1;
+ directive->stype = ST_EMPTY;
directive->position = -1;
goto END;
} else if (
strcmp(formatting_directives[3], name) == 0 ||
strcmp(formatting_directives[4], name) == 0
) {
- directive->style->font_style = FS_ITALIC;
+ directive->style->font->style = FS_ITALIC;
directive->dtype = DT_FORMATTING;
- directive->stype = -1;
+ directive->stype = ST_EMPTY;
directive->position = -1;
goto END;
} else if (
@@ -1028,7 +1238,7 @@ struct ChoDirective *directive_parse(const char *name)
) {
directive->style->boxed = true;
directive->dtype = DT_FORMATTING;
- directive->stype = -1;
+ directive->stype = ST_EMPTY;
directive->position = -1;
goto END;
}
@@ -1041,8 +1251,14 @@ struct ChoDirective *directive_parse(const char *name)
}
i++;
}
+ if (
+ strcmp(font_directives[0], name) == 0 ||
+ strcmp(font_directives[1], name) == 0
+ ) {
+ directive->dtype = DT_FONT;
+ }
directive->dtype = DT_CUSTOM;
- directive->stype = -1;
+ directive->stype = ST_EMPTY;
directive->position = -1;
END:
return directive;
@@ -1238,6 +1454,9 @@ struct ChoSong **cho_parse(FILE *fp)
songs[so]->sections[se]->lines = realloc(songs[so]->sections[se]->lines, (li+1) * sizeof(struct ChoLine *));
songs[so]->sections[se]->lines[li] = cho_line_new();
break;
+ case DT_FONT:
+ // Reset diretive value to default
+ break;
case DT_CUSTOM:
break;
}
@@ -1338,6 +1557,9 @@ struct ChoSong **cho_parse(FILE *fp)
case DT_PREAMBLE:
fprintf(stderr, "INFO: Preamble directive '%s' can't have a value.\n", directive_name);
break;
+ case DT_FONT:
+ // Set directive value globally
+ break;
case DT_CUSTOM:
break;
}
diff --git a/chordpro.h b/chordpro.h
@@ -6,6 +6,7 @@
#define URL_MAX_LEN 2000
enum FontFamily {
+ FF_EMPTY = -1,
FF_NORMAL,
FF_SANS,
FF_SERIF,
@@ -13,16 +14,26 @@ enum FontFamily {
};
enum FontStyle {
+ FS_EMPTY = -1,
FS_NORMAL,
FS_OBLIQUE,
FS_ITALIC
};
enum FontWeight {
+ FW_EMPTY = -1,
FW_NORMAL,
FW_BOLD
};
+struct Font {
+ char *name;
+ enum FontFamily family;
+ enum FontStyle style;
+ enum FontWeight weight;
+ double size;
+};
+
enum LineStyle {
LS_SINGLE,
LS_DOUBLE,
@@ -36,11 +47,7 @@ struct RGBColor {
};
struct Style {
- char *font; // If NULL use default font.
- enum FontFamily font_family;
- float font_size;
- enum FontStyle font_style;
- enum FontWeight font_weight;
+ struct Font *font;
struct RGBColor *foreground_color;
struct RGBColor *background_color;
enum LineStyle underline_style;
@@ -51,7 +58,7 @@ struct Style {
struct RGBColor *strikethrough_color;
bool boxed;
struct RGBColor *boxed_color;
- float rise;
+ double rise;
char *href;
};
@@ -92,10 +99,12 @@ enum DirectiveType {
DT_METADATA,
DT_FORMATTING,
DT_PREAMBLE,
+ DT_FONT,
DT_CUSTOM
};
enum SectionType {
+ ST_EMPTY = -1,
ST_NEWSONG,
ST_CHORUS,
ST_VERSE,
@@ -151,8 +160,14 @@ struct ChoSong {
struct ChoSong **cho_parse(FILE *fp);
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);
+void cho_font_free(struct Font *font);
+enum FontStyle cho_font_style_parse(const char *str);
+enum FontWeight cho_font_weight_parse(const char *str);
/* Debugging */
+void cho_font_print(struct Font *font);
void cho_style_print(struct Style *style);
const char *the_dtype(enum DirectiveType dtype);
const char *the_stype(enum SectionType stype);
diff --git a/config.c b/config.c
@@ -0,0 +1,335 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <toml.h>
+#include "chordpro.h"
+#include "config.h"
+
+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_NORMAL;
+ 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_NORMAL;
+ 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_NORMAL;
+ 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_NORMAL;
+ 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_NORMAL;
+ 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_NORMAL;
+ 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_NORMAL;
+ 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();
+ if (filepath == NULL) {
+ filepath = "~/.config/lorid/config.toml";
+ }
+ FILE *fp = fopen(filepath, "r");
+ if (fp == NULL) {
+ fprintf(stderr, "INFO: Couldn't open config file '%s'. Using default configuration.\n", filepath);
+ return config;
+ }
+ char errbuf[200];
+ 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;
+ enum FontStyle font_style;
+ enum FontWeight font_weight;
+ int unused;
+ const char *key_name;
+ for (int i=0; i<toml_table_len(fonts); i++) {
+ key_name = toml_table_key(fonts, i, &unused);
+ section = toml_table_table(fonts, key_name);
+ name = toml_table_string(section, "name");
+ 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;
+ }
+ 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");
+ return NULL;
+ } else {
+ config->title->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");
+ return NULL;
+ } else {
+ config->title->font_weight = font_weight;
+ }
+ free(weight.u.s);
+ }
+ if (size.ok)
+ 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;
+ }
+ 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");
+ return NULL;
+ } else {
+ 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");
+ return NULL;
+ } else {
+ config->text->font_weight = font_weight;
+ }
+ free(weight.u.s);
+ }
+ if (size.ok)
+ 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;
+ }
+ 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");
+ return NULL;
+ } else {
+ 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");
+ return NULL;
+ } else {
+ config->chord->font_weight = font_weight;
+ }
+ free(weight.u.s);
+ }
+ if (size.ok) {
+ 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;
+ }
+ 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");
+ return NULL;
+ } else {
+ 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");
+ return NULL;
+ } else {
+ config->comment->font_weight = font_weight;
+ }
+ free(weight.u.s);
+ }
+ if (size.ok) {
+ 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;
+ }
+ 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");
+ return NULL;
+ } else {
+ 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");
+ return NULL;
+ } else {
+ config->comment_italic->font_weight = font_weight;
+ }
+ free(weight.u.s);
+ }
+ if (size.ok) {
+ 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;
+ }
+ 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");
+ return NULL;
+ } else {
+ 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");
+ return NULL;
+ } else {
+ config->comment_box->font_weight = font_weight;
+ }
+ free(weight.u.s);
+ }
+ if (size.ok) {
+ 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;
+ }
+ 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");
+ return NULL;
+ } else {
+ 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");
+ return NULL;
+ } else {
+ config->tab->font_weight = font_weight;
+ }
+ free(weight.u.s);
+ }
+ if (size.ok) {
+ 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;
+ }
+ 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");
+ return NULL;
+ } else {
+ 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");
+ return NULL;
+ } else {
+ config->grid->font_weight = font_weight;
+ }
+ free(weight.u.s);
+ }
+ if (size.ok) {
+ config->grid->font_size = size.u.i;
+ }
+ } else {
+ fprintf(stderr, "INFO: Ignoring [fonts.%s] section in config file.\n", key_name);
+ if (name.ok)
+ free(name.u.s);
+ if (style.ok)
+ free(style.u.s);
+ if (weight.ok)
+ free(weight.u.s);
+ }
+ }
+ toml_free(table);
+ fclose(fp);
+ 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);
+ free(config);
+}
diff --git a/config.h b/config.h
@@ -0,0 +1,20 @@
+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 Config *config_load(const char *filepath);
+void config_free(struct Config *config);
diff --git a/lorid.c b/lorid.c
@@ -6,26 +6,47 @@
#include <getopt.h>
#include "chordpro.h"
#include "out_pdf.h"
-
-void print_hex(const char *str)
-{
- int i = 0;
- while (str[i] != 0) {
- printf("%02X ", str[i]);
- i++;
- }
- putchar('\n');
-}
+#include "config.h"
+#include <fontconfig/fontconfig.h>
int main(int argc, char *argv[])
{
- if (argc != 2) {
- fprintf(stderr, "Provide a file.\n");
+ static struct option long_options[] = {
+ { "print-default-config", no_argument, 0, 'p' },
+ { "config", required_argument, 0, 'c' },
+ { 0, 0, 0, 0 }
+ };
+ int o, option_index;
+ char *config_filepath = NULL;
+ FILE *fp;
+ while ((o = getopt_long(argc, argv, "pc:", long_options, &option_index)) != -1) {
+ switch(o) {
+ case 'p':
+ printf("--print-default-config\n");
+ return 0;
+ case 'c':
+ config_filepath = malloc((strlen(optarg)+1) * sizeof(char));
+ strcpy(config_filepath, optarg);
+ break;
+ }
+ }
+ struct Config *config = config_load(config_filepath);
+ if (config == NULL) {
+ fprintf(stderr, "config_load failed.\n");
return 1;
}
- FILE *fp = fopen(argv[1], "r");
- if (fp == NULL) {
- fprintf(stderr, "fopen failed.\n");
+ free(config_filepath);
+ config_free(config);
+ if (argc == optind) {
+ fp = stdin;
+ } else if (argc == optind+1) {
+ fp = fopen(argv[argc-1], "r");
+ if (fp == NULL) {
+ fprintf(stderr, "fopen failed.\n");
+ return 1;
+ }
+ } else {
+ fprintf(stderr, "Provide only one file.\n");
return 1;
}
struct ChoSong **songs = cho_parse(fp);
@@ -37,60 +58,6 @@ int main(int argc, char *argv[])
fprintf(stderr, "out_pdf_new failed.\n");
return 1;
}
- /*int m = 0;*/
- /*printf("---- BEGIN METADATA ----\n");*/
- /*while (song->metadata[m] != NULL) {*/
- /* if (song->metadata[m]->name) {*/
- /* printf("name: %s", song->metadata[m]->name);*/
- /* }*/
- /* if (song->metadata[m]->value) {*/
- /* printf(", value: %s\n", song->metadata[m]->value);*/
- /* } else {*/
- /* printf("\n");*/
- /* }*/
- /* m++;*/
- /*}*/
- /*printf("---- END METADATA ------\n");*/
- /* struct ChoChord **chords;
- enum SectionType stype;
- struct ChoLineItem *line_item;
- int s = 0;
- int li = 0;
- int c = 0;
- int ly = 0;
- struct ChoSong *song = songs[0];
- while (song->sections[s] != NULL) {
- printf("---- BEGIN SECTION ----\n");
- stype = song->sections[s]->type;
- printf("stype: %s\n", the_stype(stype));
- if (song->sections[s]->name) {
- printf("name: %s\n", song->sections[s]->name);
- }
- while (song->sections[s]->lines[li] != NULL) {
- printf("---- BEGIN LINE ----\n");
- chords = song->sections[s]->lines[li]->chords;
- while (chords[c] != NULL) {
- printf("index: %d, chord: %s | ", chords[c]->position, chords[c]->chord);
- c++;
- }
- printf("\n");
- c = 0;
- while (song->sections[s]->lines[li]->lyrics[ly] != NULL) {
- line_item = song->sections[s]->lines[li]->lyrics[ly];
- if (strlen(line_item->text) > 0) {
- printf("text: %s\n", line_item->text);
- // cho_style_print(line_item->style);
- }
- ly++;
- }
- ly = 0;
- li++;
- printf("---- END LINE ------\n");
- }
- li = 0;
- s++;
- printf("---- END SECTION ------\n");
- } */
cho_songs_free(songs);
fclose(fp);
return 0;
diff --git a/out_pdf.c b/out_pdf.c
@@ -8,7 +8,7 @@
static char current_font[17];
static double current_font_size;
-static double current_y = MEDIABOX_HEIGHT - PADDING / 2;
+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;
@@ -35,7 +35,29 @@ static pdfio_obj_t *get_font_obj_by_name(const char *name)
return NULL;
}
-static bool SetTextFont(pdfio_stream_t *stream, const char *name, double size)
+char *out_pdf_concat_line_items(struct ChoLineItem **items)
+{
+ char *line = NULL;
+ int size = 1;
+ int i = 0;
+ int k = 0;
+ int li = 0;
+ while (items[i] != NULL) {
+ size += strlen(items[i]->text);
+ line = realloc(line, size * sizeof(char));
+ while (items[i]->text[k] != 0) {
+ line[li] = items[i]->text[k];
+ li++;
+ k++;
+ }
+ k = 0;
+ i++;
+ }
+ line[li] = 0;
+ 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");
@@ -52,11 +74,190 @@ static bool SetTextFont(pdfio_stream_t *stream, const char *name, double size)
return true;
}
-static bool ShowText(pdfio_stream_t *stream, const char *str, enum Alignment align, bool linebreak)
+char *string_trim(const char *text)
+{
+ char *trimmed_text = NULL;
+ int begin = 0;
+ int end = 0;
+ int len = (int)strlen(text);
+ for (int i=0; i<len; i++) {
+ if (
+ text[i] == ' ' ||
+ text[i] == '\n' ||
+ text[i] == '\t' ||
+ text[i] == '\r'
+ )
+ begin++;
+ else
+ break;
+ }
+ for (int i=len-1; i>=0; i--) {
+ if (
+ text[i] == ' '||
+ text[i] == '\n' ||
+ text[i] == '\t' ||
+ text[i] == '\r'
+ )
+ end++;
+ else
+ break;
+ }
+ int k = 0;
+ for (int i=0; i<len; i++) {
+ if (i >= begin && i < len - end) {
+ trimmed_text = realloc(trimmed_text, (k+1) * sizeof(char));
+ trimmed_text[k] = text[i];
+ k++;
+ }
+ }
+ trimmed_text = realloc(trimmed_text, (k+1) * sizeof(char));
+ trimmed_text[k] = 0;
+ return trimmed_text;
+}
+
+static bool out_pdf_add_if_not_in(struct Font *font, struct Font ***array)
+{
+ int a = 0;
+ if (!*array) {
+ *array = realloc(*array, 2 * sizeof(struct Font *));
+ (*array)[0] = font;
+ (*array)[1] = NULL;
+ return true;
+ } else {
+ while ((*array)[a] != NULL) {
+ if (
+ strcmp((*array)[a]->name, font->name) == 0 &&
+ (*array)[a]->family == font->family &&
+ (*array)[a]->style == font->style &&
+ (*array)[a]->weight == font->weight
+ )
+ return false;
+ a++;
+ }
+ *array = realloc(*array, (a+2) * sizeof(struct Font *));
+ (*array)[a] = font;
+ (*array)[a+1] = NULL;
+ return true;
+ }
+}
+
+static void out_pdf_add_fonts(struct Font *font, struct Font ***fonts)
+{
+ bool added = false;
+ char part[100];
+ char *trimmed = NULL;
+ int i = 0;
+ int p = 0;
+ struct Font *new_font = NULL;
+ while (font->name[i] != 0) {
+ if (font->name[i] == ',') {
+ part[p] = 0;
+ trimmed = string_trim(part);
+ new_font = malloc(sizeof(struct Font));
+ new_font->name = trimmed;
+ new_font->family = font->family;
+ new_font->style = font->style;
+ new_font->weight = font->weight;
+ new_font->size = font->size;
+ added = out_pdf_add_if_not_in(new_font, fonts);
+ if (!added) {
+ cho_font_free(new_font);
+ trimmed = NULL;
+ }
+ memset(part, 0, strlen(part));
+ p = 0;
+ } else {
+ part[p] = font->name[i];
+ p++;
+ }
+ i++;
+ }
+ part[p] = 0;
+ trimmed = string_trim(part);
+ new_font = malloc(sizeof(struct Font));
+ new_font->name = trimmed;
+ new_font->family = font->family;
+ new_font->style = font->style;
+ new_font->weight = font->weight;
+ new_font->size = font->size;
+ added = out_pdf_add_if_not_in(new_font, fonts);
+ if (!added)
+ cho_font_free(new_font);
+}
+
+static void out_pdf_font_get_all(struct ChoSong **songs)
+{
+ struct Font **fonts = NULL;
+ int so = 0;
+ int se = 0;
+ int li = 0;
+ int ly = 0;
+ struct Style *style;
+ while (songs[so] != NULL) {
+ while (songs[so]->sections[se] != NULL) {
+ while (songs[so]->sections[se]->lines[li]) {
+ while (songs[so]->sections[se]->lines[li]->lyrics[ly] != NULL) {
+ style = songs[so]->sections[se]->lines[li]->lyrics[ly]->style;
+ if (style->font->name) {
+ out_pdf_add_fonts(style->font, &fonts);
+ }
+ ly++;
+ }
+ ly = 0;
+ li++;
+ }
+ li = 0;
+ se++;
+ }
+ se = 0;
+ so++;
+ }
+ int f = 0;
+ if (fonts) {
+ while (fonts[f] != NULL) {
+ // cho_font_print(fonts[f]);
+ cho_font_free(fonts[f]);
+ f++;
+ }
+ free(fonts);
+ }
+}
+
+static bool out_pdf_chord_show(pdfio_stream_t *stream, const char *lyrics_line, struct ChoChord *chord, bool linebreak)
+{
+ char *line = malloc((strlen(lyrics_line)+1) * sizeof(char));
+ strcpy(line, lyrics_line);
+ line[chord->position] = 0;
+ double width = pdfioContentTextMeasure(inter_regular, line, 16);
+ free(line);
+ if (!pdfioContentTextBegin(stream)) {
+ fprintf(stderr, "pdfioContentTextBegin failed.\n");
+ return false;
+ }
+ if (!pdfioContentTextMoveTo(stream, PADDING + width, current_y)) {
+ fprintf(stderr, "pdfioContentTextMoveTo failed.\n");
+ return false;
+ }
+ if (!pdfioContentTextShow(stream, true, chord->chord)) {
+ fprintf(stderr, "pdfioContentTextShow failed.\n");
+ return false;
+ }
+ if (!pdfioContentTextEnd(stream)) {
+ fprintf(stderr, "pdfioContentTextEnd failed.\n");
+ return false;
+ }
+ if (linebreak) {
+ current_y -= current_font_size + 2.0;
+ }
+ return true;
+}
+
+static bool out_pdf_text_show(pdfio_stream_t *stream, const char *str, enum Alignment align, bool linebreak)
{
static double x_continue = PADDING;
double x;
double width = pdfioContentTextMeasure(current_font_obj, str, current_font_size);
+ // printf("text '%s' has width: '%f'\n", str, width);
if (LINE_LEN < width)
return false;
switch (align) {
@@ -91,12 +292,16 @@ static bool ShowText(pdfio_stream_t *stream, const char *str, enum Alignment ali
return false;
}
if (linebreak) {
- current_y -= current_font_size + 5.0;
+ current_y -= current_font_size + 8.0;
x_continue = PADDING;
}
return true;
}
+/* void out_pdf_style_set(pdfio_stream_t *stream, struct Style *style)
+{
+} */
+
static char *out_pdf_filename(const char *old)
{
char *new = NULL;
@@ -142,6 +347,7 @@ bool out_pdf_new(const char *cho_filename, struct ChoSong **songs)
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);
+ out_pdf_font_get_all(songs);
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);
@@ -174,46 +380,49 @@ bool out_pdf_new(const char *cho_filename, struct ChoSong **songs)
return false;
}
pdfio_stream_t *page1_stream = pdfioFileCreatePage(pdf, page1_dict);
- if (!SetTextFont(page1_stream, "Inter-Regular", 14.0)) {
- fprintf(stderr, "SetTextFont failed.\n");
+ if (!out_pdf_font_set(page1_stream, "Inter-Regular", 14.0)) {
+ fprintf(stderr, "out_pdf_font_set failed.\n");
return false;
}
if (!pdfioContentSetFillColorRGB(page1_stream, 0.0, 0.0, 0.0)) {
fprintf(stderr, "pdfioContentSetFillColorRGB failed.\n");
return false;
}
- if (!pdfioContentSetTextCharacterSpacing(page1_stream, -0.2)) {
+ // Setting character spacing destroys pdfioContentTextMeasure() results
+ /* if (!pdfioContentSetTextCharacterSpacing(page1_stream, 1.0)) {
fprintf(stderr, "pdfioContentSetTextCharacterSpacing failed.\n");
return false;
- }
+ } */
/* if (!pdfioContentSetTextLeading(page1_stream, 1.5)) {
fprintf(stderr, "pdfioContentSetTextLeading failed.\n");
return false;
} */
- if (!pdfioContentSetLineWidth(page1_stream, LINE_LEN)) {
+ /* if (!pdfioContentSetLineWidth(page1_stream, LINE_LEN)) {
fprintf(stderr, "pdfioContentSetLineWidth failed.\n");
return false;
- }
+ } */
int so = 0;
int se = 0;
int m = 0;
int li = 0;
int ly = 0;
+ int ch = 0;
+ struct ChoChord **chords;
while (songs[so] != NULL) {
while (songs[so]->metadata[m] != NULL) {
if (strcmp(songs[so]->metadata[m]->name, "title") == 0) {
const char *title = songs[so]->metadata[m]->value;
pdfioFileSetTitle(pdf, title);
- if (!SetTextFont(page1_stream, "Inter-Bold", 18.0)) {
- fprintf(stderr, "SetTextFont failed.\n");
+ if (!out_pdf_font_set(page1_stream, "Inter-Bold", 18.0)) {
+ fprintf(stderr, "out_pdf_font_set failed.\n");
return false;
}
- if (!ShowText(page1_stream, title, CENTER, true)) {
- fprintf(stderr, "ShowText failed.\n");
+ if (!out_pdf_text_show(page1_stream, title, CENTER, true)) {
+ fprintf(stderr, "out_pdf_text_show failed.\n");
return false;
}
- if (!ShowText(page1_stream, "", CENTER, true)) {
- fprintf(stderr, "ShowText failed.\n");
+ if (!out_pdf_text_show(page1_stream, "", CENTER, true)) {
+ fprintf(stderr, "out_pdf_text_show failed.\n");
return false;
}
}
@@ -223,33 +432,56 @@ 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 (!SetTextFont(page1_stream, "Inter-Italic", 14.0)) {
- fprintf(stderr, "SetTextFont failed.\n");
+ if (!out_pdf_font_set(page1_stream, "Inter-Italic", 14.0)) {
+ fprintf(stderr, "out_pdf_font_set failed.\n");
return false;
}
- if (!ShowText(page1_stream, section_name, LEFT, true)) {
- fprintf(stderr, "ShowText failed.\n");
+ if (!out_pdf_text_show(page1_stream, section_name, LEFT, true)) {
+ fprintf(stderr, "out_pdf_text_show failed.\n");
return false;
}
}
- if (!SetTextFont(page1_stream, "Inter-Regular", 16.0)) {
- fprintf(stderr, "SetTextFont failed.\n");
- return false;
- }
while (songs[so]->sections[se]->lines[li] != NULL) {
+ 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)) {
+ fprintf(stderr, "out_pdf_font_set failed.\n");
+ return false;
+ }
+ char *lyrics_line = out_pdf_concat_line_items(songs[so]->sections[se]->lines[li]->lyrics);
+ while (ch < count - 1) {
+ if (!out_pdf_chord_show(page1_stream, lyrics_line, chords[ch], false)) {
+ fprintf(stderr, "out_pdf_chord_show failed.\n");
+ return false;
+ }
+ ch++;
+ }
+ if (!out_pdf_chord_show(page1_stream, lyrics_line, chords[ch], true)) {
+ fprintf(stderr, "out_pdf_chord_show failed.\n");
+ return false;
+ }
+ ch = 0;
+ free(lyrics_line);
+ }
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)) {
+ fprintf(stderr, "out_pdf_font_set failed.\n");
+ return false;
+ }
while (ly < items_count - 1) {
+ // out_pdf_style_set(page1_stream, songs[so]->sections[se]->lines[li]->lyrics[ly]->style);
text = songs[so]->sections[se]->lines[li]->lyrics[ly]->text;
- if (!ShowText(page1_stream, text, CONTINUE, false)) {
- fprintf(stderr, "ShowText failed.\n");
+ if (!out_pdf_text_show(page1_stream, text, CONTINUE, false)) {
+ fprintf(stderr, "out_pdf_text_show failed.\n");
return false;
}
ly++;
}
text = songs[so]->sections[se]->lines[li]->lyrics[ly]->text;
- if (!ShowText(page1_stream, text, CONTINUE, true)) {
- fprintf(stderr, "ShowText failed.\n");
+ if (!out_pdf_text_show(page1_stream, text, CONTINUE, true)) {
+ fprintf(stderr, "out_pdf_text_show failed.\n");
return false;
}
ly = 0;
diff --git a/out_pdf.h b/out_pdf.h
@@ -2,7 +2,8 @@
#define MEDIABOX_WIDTH 595.0
#define PAGE_HEIGHT MEDIABOX_HEIGHT - 36.0
#define PAGE_WIDTH MEDIABOX_WIDTH - 36.0
-#define PADDING 50.0
+// #define PADDING 50.0
+#define PADDING 80.0
#define LINE_LEN MEDIABOX_WIDTH - PADDING * 2
enum Alignment {
diff --git a/todo b/todo
@@ -2,6 +2,7 @@
decide how to implement
metadata directives
%{blabla}
+font, size, colour directives
'image' directive; decide if implement
https://chordpro.org/chordpro/directives-image/
chordpro markup