commit 4b82b459c5024c4456fd2cb1ae15ce6362176f26
parent 725cd889f39811bd1de31e4428134145da1b5290
Author: nibo <nibo@relim.de>
Date: Sun, 5 Jan 2025 17:39:25 +0100
Improve font handling
Using base fonts doesn't look great at the
moment.
Diffstat:
| M | README | | | 14 | ++++++++++++++ |
| M | out_pdf.c | | | 353 | +++++++++++++++++++++++++++++++++++++++++++++---------------------------------- |
2 files changed, 215 insertions(+), 152 deletions(-)
diff --git a/README b/README
@@ -26,3 +26,17 @@ care of that anyway.
There is one more case where memory leaks are tolerated. The library
fontconfig produces memory leaks according to valgrind. Fixing these
memory leaks is out of the scope of this project.
+
+## font handling
+
+If you specify a font somewhere and that font can't be found on your
+system lorid will show an error and terminate instead of finding
+an alternate font.
+
+#### cho_style_font_desc_parse()
+
+This function implements part of the Pango Markup described at
+'https://docs.gtk.org/Pango/type_func.FontDescription.from_string.html'.
+
+The website states: "FAMILY-LIST is a comma-separated list of families optionally terminated by a comma".
+My function cho_style_font_desc_parse() allows only one family name.
diff --git a/out_pdf.c b/out_pdf.c
@@ -20,6 +20,83 @@ static pdfio_obj_t *g_current_font_obj = NULL;
static int g_current_page_index;
static pdfio_file_t *g_pdf_file = NULL;
+static const char *g_base_fonts[] = {
+ "Courier",
+ "Courier-Bold",
+ "Courier-BoldItalic",
+ "Courier-Italic",
+ "Helvetica",
+ "Helvetica-Bold",
+ "Helvetica-BoldOblique",
+ "Helvetica-Oblique",
+ "Symbol",
+ "Times-Bold",
+ "Times-BoldItalic",
+ "Times-Italic",
+ "Times-Roman",
+ "ZapfDingbats"
+};
+
+static struct Obj *
+obj_new(void)
+{
+ struct Obj *obj = emalloc(sizeof(struct Obj));
+ obj->name = NULL;
+ obj->value = NULL;
+ return obj;
+}
+
+static void
+obj_free(struct Obj *obj)
+{
+ free(obj->name);
+ free(obj);
+}
+
+static void
+objs_free(struct Obj **objs)
+{
+ if (!objs) {
+ return;
+ }
+ struct Obj **start = objs;
+ for (; *objs; objs++) {
+ obj_free(*objs);
+ }
+ free(start);
+}
+
+static pdfio_obj_t *
+objs_get_obj(struct Obj **objs, const char *name)
+{
+ if (!objs) {
+ return NULL;
+ }
+ struct Obj **o;
+ for (o = objs; *o; o++) {
+ if (!strcmp((*o)->name, name)) {
+ return (*o)->value;
+ }
+ }
+ return NULL;
+}
+
+static void
+objs_add_obj(struct Obj ***array, struct Obj *obj)
+{
+ if (!*array) {
+ *array = erealloc(*array, 2 * sizeof(struct Obj *));
+ (*array)[0] = obj;
+ (*array)[1] = NULL;
+ } else {
+ int a;
+ for (a = 0; (*array)[a]; a++);
+ *array = erealloc(*array, (a+2) * sizeof(struct Obj *));
+ (*array)[a] = obj;
+ (*array)[a+1] = NULL;
+ }
+}
+
pdfio_obj_t *
out_pdf_fnt_obj_get_by_name(const char *name)
{
@@ -93,50 +170,6 @@ fonts_add_if_not_in(struct Font ***array, struct Font *font)
}
}
-static void
-fonts_add(struct Font ***fonts, struct Font *font)
-{
- bool added = false;
- char part[100];
- char *trimmed = NULL;
- int p = 0;
- int i;
- struct Font *new_font = NULL;
- for (i = 0; font->name[i]; i++) {
- if (font->name[i] == ',') {
- part[p] = 0;
- trimmed = str_trim(part);
- new_font = emalloc(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 = fonts_add_if_not_in(fonts, new_font);
- if (!added) {
- cho_font_free(new_font);
- trimmed = NULL;
- }
- memset(part, 0, strlen(part));
- p = 0;
- } else {
- part[p] = font->name[i];
- p++;
- }
- }
- part[p] = 0;
- trimmed = str_trim(part);
- new_font = emalloc(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 = fonts_add_if_not_in(fonts, new_font);
- if (!added)
- cho_font_free(new_font);
-}
-
static struct Font **
fonts_get_all(struct ChoSong **songs, struct Config *config)
{
@@ -167,14 +200,22 @@ fonts_get_all(struct ChoSong **songs, struct Config *config)
style = (*above)->u.annot->style;
}
if (style->font->name) {
- fonts_add(&fonts, style->font);
+ font = cho_font_copy(style->font);
+ added = fonts_add_if_not_in(&fonts, font);
+ if (!added) {
+ cho_font_free(font);
+ }
}
}
for (it = (*li)->items; *it; it++) {
if ((*it)->is_text) {
style = (*it)->u.text->style;
if (style->font->name) {
- fonts_add(&fonts, style->font);
+ font = cho_font_copy(style->font);
+ added = fonts_add_if_not_in(&fonts, font);
+ if (!added) {
+ cho_font_free(font);
+ }
}
}
}
@@ -253,6 +294,115 @@ fontpath_find(struct Font *font, enum FontType font_type)
return filepath;
}
+static bool
+pdf_load_chord_diagram_fonts(void)
+{
+ struct Obj *fnt;
+ fnt = obj_new();
+ fnt->name = strdup("chord-diagram-regular-font");
+ fnt->value = pdfioFileCreateFontObjFromBase(g_pdf_file, "Helvetica");
+ objs_add_obj(&g_fonts, fnt);
+ fnt = obj_new();
+ fnt->name = strdup("chord-diagram-symbols");
+ fnt->value = pdfioFileCreateFontObjFromFile(g_pdf_file, SYMBOLS_FILEPATH, true);
+ objs_add_obj(&g_fonts, fnt);
+ return true;
+}
+
+static const char *
+is_base_font(struct Font *font)
+{
+ int i;
+ for (i = 0; i<14; i++) {
+ if (!strcmp(font->name, g_base_fonts[i])) {
+ return g_base_fonts[i];
+ }
+ }
+ return NULL;
+}
+
+static bool
+font_name_is_path(const char *name)
+{
+ if (strchr(name, '/')) {
+ return true;
+ }
+ if (file_extension_equals(name, "ttf") || file_extension_equals(name, "otf")) {
+ return true;
+ }
+ return false;
+}
+
+static bool
+pdf_load_fonts(struct Font **needed_fonts, struct Config *config)
+{
+ char *fontpath;
+ const char *name;
+ struct Font **f;
+ struct Obj *fnt;
+ for (f = needed_fonts; *f; f++) {
+ if (font_name_is_path((*f)->name)) {
+ fnt = obj_new();
+ fnt->name = fnt_name_create(*f);
+ fnt->value = pdfioFileCreateFontObjFromFile(g_pdf_file, (*f)->name, true);
+ if (!fnt->value) {
+ LOG_DEBUG("pdfioFileCreateFontObjFromFile failed.");
+ return false;
+ }
+ objs_add_obj(&g_fonts, fnt);
+ } else
+ if ((name = is_base_font(*f))) {
+ fnt = obj_new();
+ fnt->name = fnt_name_create(*f);
+ fnt->value = pdfioFileCreateFontObjFromBase(g_pdf_file, name);
+ if (!fnt->value) {
+ LOG_DEBUG("pdfioFileCreateFontObjFromBase failed.");
+ return false;
+ }
+ objs_add_obj(&g_fonts, fnt);
+ } else {
+ fontpath = fontpath_find(*f, FT_TTF);
+ if (fontpath) {
+ util_log(LOG_INFO, "Loading font from '%s'.", fontpath);
+ fnt = obj_new();
+ fnt->name = fnt_name_create(*f);
+ fnt->value = pdfioFileCreateFontObjFromFile(g_pdf_file, fontpath, true);
+ if (!fnt->value) {
+ LOG_DEBUG("pdfioFileCreateFontObjFromFile failed.");
+ return false;
+ }
+ objs_add_obj(&g_fonts, fnt);
+ free(fontpath);
+ } else {
+ fontpath = fontpath_find(*f, FT_OTF);
+ if (fontpath) {
+ util_log(LOG_INFO, "Loading font from '%s'.", fontpath);
+ fnt = obj_new();
+ fnt->name = fnt_name_create(*f);
+ fnt->value = pdfioFileCreateFontObjFromFile(g_pdf_file, fontpath, true);
+ if (!fnt->value) {
+ LOG_DEBUG("pdfioFileCreateFontObjFromFile failed.");
+ return false;
+ }
+ objs_add_obj(&g_fonts, fnt);
+ free(fontpath);
+ } else {
+ util_log(LOG_ERR, "Didn't find font file for following font:");
+ cho_font_print(*f);
+ return false;
+ }
+ }
+ }
+ }
+ if (config->output->diagram->show) {
+ if (!pdf_load_chord_diagram_fonts()) {
+ LOG_DEBUG("pdf_load_chord_diagram_fonts failed.");
+ return false;
+ }
+ }
+ return true;
+}
+
static char *
pdf_filename_generate_from_songs(struct ChoSong **songs)
{
@@ -714,66 +864,6 @@ pdf_page_create(pdfio_file_t *pdf, struct PDFImage **imgs, pdfio_array_t *annots
return page_stream;
}
-static struct Obj *
-obj_new(void)
-{
- struct Obj *obj = emalloc(sizeof(struct Obj));
- obj->name = NULL;
- obj->value = NULL;
- return obj;
-}
-
-static void
-obj_free(struct Obj *obj)
-{
- free(obj->name);
- free(obj);
-}
-
-static void
-objs_free(struct Obj **objs)
-{
- if (!objs) {
- return;
- }
- struct Obj **start = objs;
- for (; *objs; objs++) {
- obj_free(*objs);
- }
- free(start);
-}
-
-static pdfio_obj_t *
-objs_get_obj(struct Obj **objs, const char *name)
-{
- if (!objs) {
- return NULL;
- }
- struct Obj **o;
- for (o = objs; *o; o++) {
- if (!strcmp((*o)->name, name)) {
- return (*o)->value;
- }
- }
- return NULL;
-}
-
-static void
-objs_add_obj(struct Obj ***array, struct Obj *obj)
-{
- if (!*array) {
- *array = erealloc(*array, 2 * sizeof(struct Obj *));
- (*array)[0] = obj;
- (*array)[1] = NULL;
- } else {
- int a;
- for (a = 0; (*array)[a]; a++);
- *array = erealloc(*array, (a+2) * sizeof(struct Obj *));
- (*array)[a] = obj;
- (*array)[a+1] = NULL;
- }
-}
-
static double
image_width(struct ChoImage *image, pdfio_obj_t *obj)
{
@@ -872,6 +962,7 @@ pdf_load_images(struct Obj ***images, pdfio_file_t *file, struct ChoSong **songs
} else {
image_filepath = (char *)&filepath;
}
+ util_log(LOG_INFO, "Loading image from '%s'.", image_filepath);
(*images)[i]->value = pdfioFileCreateImageObjFromFile(file, image_filepath, true);
if (!(*images)[i]->value) {
LOG_DEBUG("pdfioFileCreateImageObjFromFile failed.");
@@ -890,21 +981,6 @@ pdf_load_images(struct Obj ***images, pdfio_file_t *file, struct ChoSong **songs
}
static bool
-pdf_load_chord_diagram_fonts(void)
-{
- struct Obj *fnt;
- fnt = obj_new();
- fnt->name = strdup("chord-diagram-regular-font");
- fnt->value = pdfioFileCreateFontObjFromBase(g_pdf_file, "Helvetica");
- objs_add_obj(&g_fonts, fnt);
- fnt = obj_new();
- fnt->name = strdup("chord-diagram-symbols");
- fnt->value = pdfioFileCreateFontObjFromFile(g_pdf_file, SYMBOLS_FILEPATH, true);
- objs_add_obj(&g_fonts, fnt);
- return true;
-}
-
-static bool
pdf_get_chords(struct ChoSong *song, struct ChoChord ***chords)
{
struct ChoSection **se;
@@ -2288,12 +2364,11 @@ out_pdf_create(
{
struct Font **needed_fonts;
struct Obj **img_objs = NULL;
- struct Obj *fnt;
struct PDFContent *pdf_content = NULL;
struct PDFContent *toc_content = NULL;
pdfio_rect_t media_box_a4 = { 0.0, 0.0, MEDIABOX_WIDTH, MEDIABOX_HEIGHT };
pdfio_rect_t crop_box = { 0.0, 0.0, MEDIABOX_WIDTH, MEDIABOX_HEIGHT };
- char *dirpath, *fontpath, *pdf_filepath;
+ char *dirpath, *pdf_filepath;
memset(&g_current_font_name, 0, sizeof(g_current_font_name));
memset(&g_cho_dirpath, 0, PATH_MAX);
@@ -2319,38 +2394,12 @@ out_pdf_create(
LOG_DEBUG("pdf_set_title failed.");
goto CLEAN;
}
- int f;
needed_fonts = fonts_get_all(songs, config);
- for (f = 0; needed_fonts[f]; f++) {
- fontpath = fontpath_find(needed_fonts[f], FT_TTF);
- if (fontpath) {
- fnt = obj_new();
- fnt->name = fnt_name_create(needed_fonts[f]);
- fnt->value = pdfioFileCreateFontObjFromFile(g_pdf_file, fontpath, true);
- objs_add_obj(&g_fonts, fnt);
- free(fontpath);
- } else {
- fontpath = fontpath_find(needed_fonts[f], FT_OTF);
- if (fontpath) {
- fnt = obj_new();
- fnt->name = fnt_name_create(needed_fonts[f]);
- fnt->value = pdfioFileCreateFontObjFromFile(g_pdf_file, fontpath, true);
- objs_add_obj(&g_fonts, fnt);
- free(fontpath);
- } else {
- util_log(LOG_ERR, "Didn't find font file for following font:");
- cho_font_print(needed_fonts[f]);
- goto CLEAN;
- }
- }
+ if (!pdf_load_fonts(needed_fonts, config)) {
+ LOG_DEBUG("pdf_load_fonts failed.");
+ goto CLEAN;
}
cho_fonts_free(needed_fonts);
- if (config->output->diagram->show) {
- if (!pdf_load_chord_diagram_fonts()) {
- LOG_DEBUG("pdf_load_chord_diagram_fonts failed.");
- goto CLEAN;
- }
- }
if (!pdf_load_images(&img_objs, g_pdf_file, songs)) {
LOG_DEBUG("pdf_load_images failed.");
goto CLEAN;