lorid

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

commit f3ae24795f381aee6019836576f797b34befc3f7
parent f7126d012b878b189d3e5512e8bb9817e21209d4
Author: nibo <nibo@relim.de>
Date:   Fri, 29 Nov 2024 13:59:45 +0100

WIP: chord diagrams

Diffstat:
MMakefile | 4+---
Achord_diagram.c | 490+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Achord_diagram.h | 35+++++++++++++++++++++++++++++++++++
Mconfig.c | 37++++++++++++++++++++++++++++++++++++-
Mconfig.h | 12++++++++++++
Mfontconfig.c | 25+++++++++++++++++++++++++
Mfontconfig.h | 1+
Mlorid.c | 5-----
Amisc/ChordProSymbols.ttf | 0
Mout_pdf.c | 93+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------
10 files changed, 687 insertions(+), 15 deletions(-)

diff --git a/Makefile b/Makefile @@ -3,7 +3,7 @@ PREFIX = /usr/local MANPREFIX = ${PREFIX}/share/man CFLAGS = -pedantic -Wall -Wextra -DVERSION=\"${VERSION}\" LDFLAGS = -lpdfio -ltoml -lfontconfig -SRC = util.c fontconfig.c config.c chordpro.c out_pdf.c lorid.c +SRC = util.c fontconfig.c config.c chordpro.c chord_diagram.c out_pdf.c lorid.c COLOR = 0 @@ -17,8 +17,6 @@ clean: rm liblorid.so* fontconfig: $(CC) -g chordpro.c fontconfig.c -o fontconfig -lfontconfig -parser: - $(CC) ${CFLAGS} -g util.c config.c chordpro.c lorid.c -o parser -ltoml lib: $(CC) -fpic -c util.c fontconfig.c config.c chordpro.c out_pdf.c $(CC) -shared *.o ${LDFLAGS} -o liblorid.so.${VERSION} diff --git a/chord_diagram.c b/chord_diagram.c @@ -0,0 +1,490 @@ +#include <string.h> +#include <stdint.h> +#include <pdfio.h> +#include <pdfio-content.h> +#include "util.h" +#include "chord_diagram.h" + +static bool +text_show( + pdfio_stream_t *stream, + const char *text, + double x, + double y +) +{ + if (!pdfioContentSetTextRenderingMode(stream, PDFIO_TEXTRENDERING_FILL)) { + fprintf(stderr, "pdfioContentSetTextRenderingMode failed.\n"); + return false; + } + if (!pdfioContentTextBegin(stream)) { + fprintf(stderr, "pdfioContentTextBegin failed.\n"); + return false; + } + if (!pdfioContentTextMoveTo(stream, x, y)) { + fprintf(stderr, "pdfioContentTextMoveTo failed.\n"); + return false; + } + if (!pdfioContentTextShow(stream, true, text)) { + fprintf(stderr, "pdfioContentTextShow failed.\n"); + return false; + } + if (!pdfioContentTextEnd(stream)) { + fprintf(stderr, "pdfioContentTextEnd failed.\n"); + return false; + } + return true; +} + +static bool +draw_rectangle( + pdfio_stream_t *stream, + double x, + double y, + double width, + double height, + enum TextRendering type +) +{ + if (!pdfioContentSetFillColorRGB(stream, 0.0, 0.0, 0.0)) { + fprintf(stderr, "pdfioContentSetFillColorRGB failed.\n"); + return false; + } + if (!pdfioContentSetStrokeColorRGB(stream, 0.0, 0.0, 0.0)) { + fprintf(stderr, "pdfioContentSetStrokeColorRGB failed.\n"); + return false; + } + if (!pdfioContentPathRect(stream, x, y, width, height)) { + fprintf(stderr, "pdfioContentPathRect failed.\n"); + return false; + } + switch (type) { + case FILL_AND_STROKE: + if (!pdfioContentFillAndStroke(stream, true)) { + fprintf(stderr, "pdfioContentFillAndStroke failed.\n"); + return false; + } + break; + case FILL: + if (!pdfioContentFill(stream, true)) { + fprintf(stderr, "pdfioContentFill failed.\n"); + return false; + } + break; + case STROKE: + if (!pdfioContentStroke(stream)) { + fprintf(stderr, "pdfioContentStroke failed.\n"); + return false; + } + break; + } + return true; +} + +static bool +draw_line( + pdfio_stream_t *stream, + double x, + double y, + double width, + enum Direction direction +) +{ + if (!pdfioContentPathMoveTo(stream, x, y)) { + fprintf(stderr, "pdfioContentPathMoveTo failed.\n"); + return false; + } + if (direction == HORIZONTAL) { + if (!pdfioContentPathLineTo(stream, x+width, y)) { + fprintf(stderr, "pdfioContentPathLineTo failed.\n"); + return false; + } + } else { + if (!pdfioContentPathLineTo(stream, x, y+width)) { + fprintf(stderr, "pdfioContentPathLineTo failed.\n"); + return false; + } + } + if (!pdfioContentSetStrokeColorRGB(stream, 0.0, 0.0, 0.0)) { + fprintf(stderr, "pdfioContentSetStrokeColorRGB failed.\n"); + return false; + } + if (!pdfioContentStroke(stream)) { + fprintf(stderr, "pdfioContentFill failed.\n"); + return false; + } + return true; +} + +static bool +draw_bezier_oval_quarter( + pdfio_stream_t *stream, + double center_x, + double center_y, + double size_x, + double size_y +) +{ + if (!pdfioContentPathMoveTo(stream, center_x - size_x, center_y)) { + fprintf(stderr, "pdfioContentPathMoveTo failed.\n"); + return false; + } + if (!pdfioContentPathCurve( + stream, + center_x - size_x, + center_y - 0.552 * size_y, + center_x - 0.552 * size_x, + center_y - size_y, + center_x, + center_y - size_y + )) { + fprintf(stderr, "pdfioContentPathCurve failed.\n"); + return false; + } + return true; +} + +static bool +draw_bezier_oval( + pdfio_stream_t *stream, + double center_x, + double center_y, + double size_x, + double size_y +) +{ + if (!pdfioContentSetStrokeColorRGB(stream, 0.0, 0.0, 0.0)) { + fprintf(stderr, "pdfioContentSetStrokeColorRGB failed.\n"); + return false; + } + if (!draw_bezier_oval_quarter(stream, center_x, center_y, -size_x, size_y)) { + fprintf(stderr, "draw_bezier_oval_quarter failed."); + return false; + } + if (!draw_bezier_oval_quarter(stream, center_x, center_y, size_x, size_y)) { + fprintf(stderr, "draw_bezier_oval_quarter failed."); + return false; + } + if (!draw_bezier_oval_quarter(stream, center_x, center_y, size_x, -size_y)) { + fprintf(stderr, "draw_bezier_oval_quarter failed."); + return false; + } + if (!draw_bezier_oval_quarter(stream, center_x, center_y, -size_x, -size_y)) { + fprintf(stderr, "draw_bezier_oval_quarter failed."); + return false; + } + if (!pdfioContentStroke(stream)) { + fprintf(stderr, "pdfioContentStroke failed.\n"); + return false; + } + return true; +} + +static bool +draw_bezier_circle( + pdfio_stream_t *stream, + double center_x, + double center_y, + double size +) +{ + if (!pdfioContentSetLineWidth(stream, size * 0.4)) { + fprintf(stderr, "pdfioContentSetLineWidth failed.\n"); + return false; + } + if (!draw_bezier_oval(stream, center_x, center_y, size, size)) { + fprintf(stderr, "draw_bezier_oval failed."); + return false; + } + return true; +} + +static bool +draw_x(pdfio_stream_t *stream, double x, double y, double size) +{ + if (!pdfioContentSetLineWidth(stream, size * 0.4)) { + fprintf(stderr, "pdfioContentSetLineWidth failed.\n"); + return false; + } + if (!pdfioContentSetStrokeColorRGB(stream, 0.0, 0.0, 0.0)) { + fprintf(stderr, "pdfioContentSetStrokeColorRGB failed.\n"); + return false; + } + if (!pdfioContentPathMoveTo(stream, x - size, y - size)) { + fprintf(stderr, "pdfioContentPathMoveTo failed.\n"); + return false; + } + if (!pdfioContentPathLineTo(stream, x + size, y + size)) { + fprintf(stderr, "pdfioContentPathLineTo failed.\n"); + return false; + } + if (!pdfioContentStroke(stream)) { + fprintf(stderr, "pdfioContentFill failed.\n"); + return false; + } + if (!pdfioContentPathMoveTo(stream, x - size, y + size)) { + fprintf(stderr, "pdfioContentPathMoveTo failed.\n"); + return false; + } + if (!pdfioContentPathLineTo(stream, x + size, y - size)) { + fprintf(stderr, "pdfioContentPathLineTo failed.\n"); + return false; + } + if (!pdfioContentStroke(stream)) { + fprintf(stderr, "pdfioContentFill failed.\n"); + return false; + } + return true; +} + +static bool +is_valid_circle_char(char c) +{ + if (c >= '/' && c <= '9') { + return true; + } + if (c >= 'A' && c <= 'Z') { + return true; + } + return false; +} + +static bool +draw_circle_with_char_inside( + pdfio_stream_t *stream, + double x, + double y, + double field_width, + char c +) +{ + if (!is_valid_circle_char(c)) { + fprintf(stderr, "is_valid_circle_char failed.\n"); + return false; + } + char str[2]; + str[0] = c; + str[1] = 0; + if (!pdfioContentSetTextFont(stream, "chord-diagram-symbols", field_width)) { + fprintf(stderr, "pdfioContentSetTextFont failed.\n"); + return false; + } + /* INFO: Needs to be the color of the page background. This cannot be set at the moment. It will always be white. */ + if (!pdfioContentSetFillColorRGB(stream, 1.0, 1.0, 1.0)) { + fprintf(stderr, "pdfioContentSetFillColorRGB failed.\n"); + return false; + } + if (!text_show(stream, "/", x-field_width/2, y-field_width/2.8)) { + fprintf(stderr, "text_show failed."); + return false; + } + if (!pdfioContentSetFillColorRGB(stream, 0.0, 0.0, 0.0)) { + fprintf(stderr, "pdfioContentSetFillColorRGB failed.\n"); + return false; + } + if (!text_show(stream, (char *)&str, x-field_width/2, y-field_width/2.8)) { + fprintf(stderr, "text_show failed."); + return false; + } + return true; +} + +static struct StringDiagram * +string_diagram_new(void) +{ + struct StringDiagram *d = emalloc(sizeof(struct StringDiagram)); + d->name = NULL; + d->base_fret = -2; + memset(d->frets, -2, sizeof(d->frets)); + memset(d->fingers, -2, sizeof(d->fingers)); + return d; +} + +static int +string_diagram_string_count(struct StringDiagram *d) +{ + int i = 0; + while (d->frets[i] != -2 && i < 12) { + i++; + } + return i; +} + +static void +string_diagram_free(struct StringDiagram *d) +{ + free(d->name); + free(d); +} + +static bool +string_diagram_is_valid(struct StringDiagram *d) +{ + int i; + size_t fret_count, finger_count; + if (d->base_fret < 1 || d->base_fret > 99) { + return false; + } + i = 0; + while (d->frets[i] != -2 && i < 12) { + i++; + } + fret_count = i; + i = 0; + while (d->fingers[i] != -2 && i < 12) { + i++; + } + finger_count = i; + if (finger_count > 0 && fret_count != finger_count) { + return false; + } + return true; +} + +static char +finger_to_char(int8_t finger) +{ + switch (finger) { + case 1: + return '1'; + case 2: + return '2'; + case 3: + return '3'; + case 4: + return '4'; + default: + return '/'; + } +} + +static bool +draw_string_chord_diagram( + pdfio_stream_t *stream, + struct StringDiagram *diagram, + double x, + double y, + double width +) +{ + int i; + int instrument_string_count = string_diagram_string_count(diagram); + double field_width = width / (instrument_string_count - 1); + double height = field_width * 4; + double vertical_lines_height = height + field_width / 2; + if (!pdfioContentSetLineWidth(stream, field_width * 0.09)) { + fprintf(stderr, "pdfioContentSetLineWidth failed.\n"); + return false; + } + if (!draw_rectangle(stream, x, y, width, height, STROKE)) { + fprintf(stderr, "draw_rectangle failed.\n"); + return false; + } + // from bottom to top draw horizontal lines + for (i = 0; i<4; i++) { + if (!draw_line(stream, x, y+field_width * (i+1), width, HORIZONTAL)) { + fprintf(stderr, "draw_line failed.\n"); + return false; + } + } + // from left to right draw vertical lines + for (i = 0; i<instrument_string_count; i++) { + if (!draw_line(stream, x+field_width*i, y, vertical_lines_height, VERTICAL)) { + fprintf(stderr, "draw_line failed.\n"); + return false; + } + } + if (diagram->base_fret == 1) { + if (!draw_rectangle(stream, x, y+height, width, field_width/2, FILL_AND_STROKE)) { + fprintf(stderr, "draw_rectangle failed.\n"); + return false; + } + } else { + double base_pos_x; + char base_position[5]; + base_position[4] = 0; + sprintf((char *)&base_position, "%d", diagram->base_fret); + if (diagram->base_fret > 9) { + base_pos_x = x - field_width - field_width / 2; + } else { + base_pos_x = x - field_width; + } + if (!pdfioContentSetTextFont(stream, "chord-diagram-regular-font", field_width*1.15)) { + fprintf(stderr, "pdfioContentSetTextFont failed.\n"); + return false; + } + if (!text_show(stream, base_position, base_pos_x, y+field_width*3+field_width*0.1)) { + fprintf(stderr, "text_show failed.\n"); + return false; + } + } + double y_above_diagram; + int8_t fret, finger; + for (i = 0; i<instrument_string_count; i++) { + y_above_diagram = y + height + field_width / 2 + field_width / 2.5; + fret = diagram->frets[i]; + finger = diagram->fingers[i]; + if (fret == -1) { + if (!draw_x(stream, x+(i*field_width), y_above_diagram, field_width / 4)) { + fprintf(stderr, "draw_x failed.\n"); + return false; + } + } else + if (fret == 0) { + if (!draw_bezier_circle(stream, x+(i*field_width), y_above_diagram, field_width / 4)) { + fprintf(stderr, "draw_circle_with_char_inside failed.\n"); + return false; + } + } else + if (fret < 5) { + if (!draw_circle_with_char_inside(stream, + x + i * field_width, + y + field_width/2 + field_width * (4 - fret), + field_width, + finger_to_char(finger) + )) { + fprintf(stderr, "draw_circle_with_char_inside failed.\n"); + return false; + } + } + } + return true; +} + +static void +keyboard_diagram_free(struct KeyboardDiagram *d) +{ + free(d->name); + free(d); +} + +void +chord_diagram_free(struct ChordDiagram *d) +{ + if (d->is_string_instrument) { + string_diagram_free(d->u.sd); + } else { + keyboard_diagram_free(d->u.kd); + } + free(d); +} + +bool +chord_diagram_draw( + pdfio_stream_t *stream, + struct ChordDiagram *diagram, + double x, + double y, + double width +) +{ + if (diagram->is_string_instrument) { + if (!draw_string_chord_diagram(stream, diagram->u.sd, x, y, width)) { + LOG_DEBUG("draw_string_chord_diagram failed."); + return false; + } + } else { + util_log(LOG_TODO, "draw_keyboard_chord_diagram()"); + } + return true; +} diff --git a/chord_diagram.h b/chord_diagram.h @@ -0,0 +1,35 @@ +#include <pdfio.h> + +enum TextRendering { + FILL, + STROKE, + FILL_AND_STROKE +}; + +enum Direction { + HORIZONTAL, + VERTICAL +}; + +struct StringDiagram { + char *name; + int8_t base_fret; + int8_t frets[12]; + int8_t fingers[12]; +}; + +struct KeyboardDiagram { + char *name; + int8_t keys[24]; +}; + +struct ChordDiagram { + bool is_string_instrument; + union { + struct StringDiagram *sd; + struct KeyboardDiagram *kd; + } u; +}; + +void chord_diagram_free(struct ChordDiagram *d); +bool chord_diagram_draw(pdfio_stream_t *stream, struct ChordDiagram *diagram, double x, double y, double width); diff --git a/config.c b/config.c @@ -5,6 +5,7 @@ #include "chordpro.h" #include "config.h" #include "util.h" +#include "chord_diagram.h" static char *naming_systems[] = { "common", @@ -159,6 +160,18 @@ config_naming_system_to_config_string(enum NamingSystem system) return naming_systems[system]; } +static enum Instrument +config_instrument_parse(const char *str) +{ + if (!strcmp(str, "string")) { + return INS_STRING; + } else + if (!strcmp(str, "keyboard")) { + return INS_KEYBOARD; + } + return INS_UNKNOWN; +} + static struct Note * config_note_new(void) { @@ -314,6 +327,9 @@ config_load_default(void) config->output->chorus = emalloc(sizeof(struct ConfigChorus)); config->output->chorus->label = strdup("Chorus"); config->output->chorus->quote = false; + config->output->diagram = emalloc(sizeof(struct ChordDiagram)); + config->output->diagram->show = true; + config->output->diagram->instrument = INS_STRING; config->output->system = NS_COMMON; config->output->styles = emalloc(12 * sizeof(struct OutputStyle *)); config->output->styles[0] = config_output_style_new("title"); @@ -601,9 +617,10 @@ config_load(const char *filepath) } toml_table_t *output = toml_table_table(table, "output"); if (output) { - toml_table_t *notes, *chorus; + toml_table_t *notes, *chorus, *diagram; toml_value_t value; enum NamingSystem system; + enum Instrument instrument; struct Note **custom_notes; chorus = toml_table_table(output, "chorus"); if (chorus) { @@ -617,6 +634,23 @@ config_load(const char *filepath) config->output->chorus->quote = value.u.b; } } + diagram = toml_table_table(output, "chord_diagram"); + if (diagram) { + value = toml_table_bool(diagram, "show"); + if (value.ok) { + config->output->diagram->show = value.u.b; + } + value = toml_table_string(diagram, "instrument"); + if (value.ok) { + instrument = config_instrument_parse(value.u.s); + if (instrument == INS_UNKNOWN) { + util_log(LOG_ERR, "Unknown instrument '%s' in [output.chord_diagram].", value.u.s); + return NULL; + } + config->output->diagram->instrument = instrument; + free(value.u.s); + } + } value = toml_table_string(output, "system"); if (value.ok) { system = config_naming_system_parse(value.u.s); @@ -729,6 +763,7 @@ config_free(struct Config *config) config->output->notes++; } free(start_notes); + free(config->output->diagram); free(config->output); free(config->parser->chords); start_notes = config->parser->notes; diff --git a/config.h b/config.h @@ -33,6 +33,12 @@ enum NoteType { NT_FLAT }; +enum Instrument { + INS_STRING, + INS_KEYBOARD, + INS_UNKNOWN +}; + struct ConfigChords { enum NamingSystem system; enum ParseMode mode; @@ -48,8 +54,14 @@ struct ConfigParser { struct Note **notes; }; +struct ConfigChordDiagram { + bool show; + enum Instrument instrument; +}; + struct ConfigOutput { struct ConfigChorus *chorus; + struct ConfigChordDiagram *diagram; enum NamingSystem system; struct OutputStyle **styles; struct Note **notes; diff --git a/fontconfig.c b/fontconfig.c @@ -23,6 +23,31 @@ file_extension_is_ttc(const char *filepath) } char * +fontconfig_fontpath_find_regular_font(void) +{ + char *filepath = NULL; + FcChar8 *file; + FcResult result; + FcPattern *match; + FcPattern *pattern = FcPatternCreate(); + FcConfigSubstitute(NULL, pattern, FcMatchPattern); + FcDefaultSubstitute(pattern); + FcValue weight; + weight.type = FcTypeInteger; + weight.u.i = FC_WEIGHT_REGULAR; + FcPatternAdd(pattern, FC_WEIGHT, weight, FcFalse); + match = FcFontMatch(NULL, pattern, &result); + if (match && result == FcResultMatch) { + if (FcPatternGetString(match, FC_FILE, 0, &file) == FcResultMatch) { + filepath = strdup((const char *)file); + } + } + FcPatternDestroy(pattern); + FcPatternDestroy(match); + return filepath; +} + +char * fontconfig_fontpath_find(struct Font *font, enum FontType font_type) { char *filepath = NULL; diff --git a/fontconfig.h b/fontconfig.h @@ -5,4 +5,5 @@ enum FontType { FT_OTF }; +char *fontconfig_fontpath_find_regular_font(void); char *fontconfig_fontpath_find(struct Font *font, enum FontType font_type); diff --git a/lorid.c b/lorid.c @@ -70,11 +70,6 @@ main(int argc, char *argv[]) LOG_DEBUG("cho_songs_parse failed."); return 1; } - struct ChoMetadata **m = songs[0]->metadata; - while (*m) { - printf("'%s' = '%s'\n", (*m)->name, (*m)->value); - m++; - } char *pdf_filename = out_pdf_create(argc == optind+1 ? argv[argc-1] : NULL, output ? output : NULL, songs, config); if (!pdf_filename) { LOG_DEBUG("out_pdf_new failed."); diff --git a/misc/ChordProSymbols.ttf b/misc/ChordProSymbols.ttf Binary files differ. diff --git a/out_pdf.c b/out_pdf.c @@ -791,6 +791,59 @@ out_pdf_load_images(struct Obj ***images, pdfio_file_t *file, struct ChoSong **s return true; } +static bool +out_pdf_load_chord_diagram_fonts(void) +{ + struct Obj *fnt; + char *regular_font_filepath = fontconfig_fontpath_find_regular_font(); + if (!regular_font_filepath) { + LOG_DEBUG("fontconfig_fontpath_find_regular_font failed."); + return false; + } + fnt = obj_new(); + fnt->name = strdup("chord-diagram-regular-font"); + fnt->value = pdfioFileCreateFontObjFromFile(g_pdf_file, regular_font_filepath, true); + free(regular_font_filepath); + objs_add_obj(&g_fonts, fnt); + fnt = obj_new(); + fnt->name = strdup("chord-diagram-symbols"); + fnt->value = pdfioFileCreateFontObjFromFile(g_pdf_file, "./misc/ChordProSymbols.ttf", true); + objs_add_obj(&g_fonts, fnt); + return true; +} + +static bool +out_pdf_get_chords(struct ChoSong **songs, char ***chords) +{ + struct ChoSong **s = songs; + struct ChoSection **se; + struct ChoLine **li; + struct ChoLineItemAbove **above; + char *name; + while (*s) { + se = (*s)->sections; + while (*se) { + li = (*se)->lines; + while (*li) { + above = (*li)->text_above; + while (*above) { + if ((*above)->is_chord) { + name = cho_chord_name_generate((*above)->u.chord); + printf("chord '%s'\n", name); + // TODO: Add name to chords + free(name); + } + above++; + } + li++; + } + se++; + } + s++; + } + return true; +} + static double line_width_until_text_above( struct ChoLineItem **items, @@ -1394,7 +1447,12 @@ pdf_content_create( struct PDFText ***texts; struct PDFImage ***imgs; struct PDFContext ctx; - double width, height; + double width, height, margin_bottom; + if (config->output->diagram->show) { + margin_bottom = 150.0; + } else { + margin_bottom = MARGIN_BOTTOM; + } ctx.x = MARGIN_HORIZONTAL; ctx.y = MEDIABOX_HEIGHT - MARGIN_TOP; ctx.text = 0; @@ -1542,7 +1600,7 @@ pdf_content_create( ctx.y -= height; } } - if (ctx.y < MARGIN_BOTTOM) { + if (ctx.y < margin_bottom) { /* INFO: chords/annotations and their corresponding lyrics won't be splitted */ struct PDFText **tmp = NULL; int tm = 0; @@ -1636,7 +1694,7 @@ pdf_content_create( left_items++; } ctx.y -= 8.0 + ctx.biggest_font_size; - if (ctx.y < MARGIN_BOTTOM) { + if (ctx.y < margin_bottom) { *texts = erealloc(*texts, (ctx.text+1) * sizeof(struct PDFText *)); (*texts)[ctx.text] = NULL; *imgs = erealloc(*imgs, (ctx.image+1) * sizeof(struct PDFImage *)); @@ -1705,8 +1763,9 @@ pdf_content_free(struct PDFContent *content) } static bool -pdf_content_render(struct PDFContent *content, pdfio_file_t *file) +pdf_content_render(struct PDFContent *content, pdfio_file_t *file, struct Config *config) { + int page = 1; struct PDFPage **pages; struct PDFText **texts; struct PDFImage **imgs; @@ -1743,17 +1802,30 @@ pdf_content_render(struct PDFContent *content, pdfio_file_t *file) } imgs++; } + // TODO: Add chord diagrams to first page + /* if (page == 1) { + if (!chord_diagram_draw(stream, diagram, x, y, width)) { + LOG_DEBUG("chord_diagram_draw failed."); + return false; + } + } */ if (!pdfioStreamClose(stream)) { LOG_DEBUG("pdfioStreamClose failed."); return false; } pages++; + page++; } return true; } char * -out_pdf_create(const char *cho_filepath, const char *output_folder_or_file, struct ChoSong **songs, struct Config *config) +out_pdf_create( + const char *cho_filepath, + const char *output_folder_or_file, + struct ChoSong **songs, + struct Config *config +) { memset(&g_current_font_name, 0, sizeof(g_current_font_name)); memset(&g_cho_dirpath, 0, PATH_MAX); @@ -1802,16 +1874,25 @@ out_pdf_create(const char *cho_filepath, const char *output_folder_or_file, stru f++; } cho_fonts_free(needed_fonts); + if (!out_pdf_load_chord_diagram_fonts()) { + LOG_DEBUG("out_pdf_load_chord_diagram_fonts failed."); + return NULL; + } if (!out_pdf_load_images(&img_objs, g_pdf_file, songs)) { LOG_DEBUG("out_pdf_load_images failed."); return NULL; } + char **chords = NULL; + if (!out_pdf_get_chords(songs, &chords)) { + LOG_DEBUG("out_pdf_get_chords failed."); + return NULL; + } struct PDFContent *pdf_content; if (!pdf_content_create(&pdf_content, songs, config, img_objs)) { LOG_DEBUG("pdf_content_create failed."); return NULL; } - if (!pdf_content_render(pdf_content, g_pdf_file)) { + if (!pdf_content_render(pdf_content, g_pdf_file, config)) { LOG_DEBUG("pdf_content_render failed."); return NULL; }