commit d5287903db5d14f56f94795b8f1988014a096317
parent d9c47c88cabf983d380fdf5c2688d1687d972ed1
Author: nibo <nibo@relim.de>
Date: Sun, 19 Jan 2025 10:49:58 +0100
Add page number to pdf pages (left/center/right)
Diffstat:
5 files changed, 261 insertions(+), 40 deletions(-)
diff --git a/chordpro.h b/chordpro.h
@@ -23,6 +23,12 @@ enum TextType {
SF_LENGTH
};
+enum Alignment {
+ A_LEFT,
+ A_CENTER,
+ A_RIGHT
+};
+
#include "config.h"
@@ -35,12 +41,6 @@ enum TextType {
#define URL_MAX_LEN 2000
#define FONT_NAME_MAX 100
-enum Alignment {
- A_LEFT,
- A_CENTER,
- A_RIGHT
-};
-
enum Anchor {
AN_PAPER,
AN_PAGE,
diff --git a/config.c b/config.c
@@ -37,6 +37,10 @@ static const char *text_types[] = {
"comment_italic", "comment_box"
};
+static const char *alignments[] = {
+ "left", "center", "right"
+};
+
/* static const char *g_valid_styles[] = {
"title",
"subtitle",
@@ -387,6 +391,27 @@ config_parse_mode_to_config_string(enum ParseMode mode)
return parse_modes[mode];
}
+static enum Alignment
+config_alignment_parse(const char *str)
+{
+ if (!strcmp(str, "left")) {
+ return A_LEFT;
+ } else
+ if (!strcmp(str, "center")) {
+ return A_CENTER;
+ } else
+ if (!strcmp(str, "right")) {
+ return A_RIGHT;
+ }
+ return ENUM_UNKNOWN;
+}
+
+static const char *
+config_alignment_to_config_string(enum Alignment align)
+{
+ return alignments[align];
+}
+
static struct Config *
config_load_default(void)
{
@@ -402,6 +427,7 @@ config_load_default(void)
config->output->diagram->show = true;
config->output->diagram->instrument = INS_GUITAR;
config->output->system = NS_COMMON;
+ config->output->page_no_position = A_CENTER;
config->output->styles = emalloc(SF_LENGTH * sizeof(struct ChoStyle *));
config->output->styles[SF_EMPTY] = NULL;
@@ -472,7 +498,8 @@ config_print_default(void)
config_notes_print_as_toml(NS_ROMAN);
config_notes_print_as_toml(NS_NASHVILLE);
printf("[output]\n");
- printf("system = \"%s\"\n\n", config_naming_system_to_config_string(config->output->system));
+ printf("system = \"%s\"\n", config_naming_system_to_config_string(config->output->system));
+ printf("page_no_position = \"%s\"\n\n", config_alignment_to_config_string(config->output->page_no_position));
printf("[output.toc]\n");
printf("show = %s\n", config->output->toc->show ? "true" : "false");
printf("title = \"%s\"\n\n", config->output->toc->title);
@@ -841,6 +868,7 @@ config_load(const char *filepath)
toml_value_t value;
enum NamingSystem system;
enum Instrument instrument;
+ enum Alignment position;
struct Note **custom_notes;
chorus = toml_table_table(output, "chorus");
if (chorus) {
@@ -907,6 +935,16 @@ config_load(const char *filepath)
}
free(value.u.s);
}
+ value = toml_table_string(output, "page_no_position");
+ if (value.ok) {
+ position = config_alignment_parse(value.u.s);
+ if (position == ENUM_UNKNOWN) {
+ LOG_DEBUG("config_alignment_parse failed.");
+ return NULL;
+ }
+ config->output->page_no_position = position;
+ free(value.u.s);
+ }
toml_table_t *styles = toml_table_table(output, "styles");
if (styles) {
int i, unused;
diff --git a/config.h b/config.h
@@ -97,6 +97,7 @@ struct ConfigOutput {
struct ConfigToc *toc;
struct ConfigChordDiagram *diagram;
enum NamingSystem system;
+ enum Alignment page_no_position;
struct ChoStyle **styles;
struct Note **notes;
};
diff --git a/out_pdf.c b/out_pdf.c
@@ -20,6 +20,7 @@ static char g_current_font_name[200];
static double g_current_font_size;
static int g_current_page_index;
static pdfio_file_t *g_pdf_file = NULL;
+static struct Config *g_config = NULL;
static const char *g_base_fonts[] = {
"Courier",
@@ -1569,8 +1570,164 @@ calc_x(double width, enum Alignment align)
return MARGIN_HORIZONTAL;
}
-static void
-pdf_page_close_then_add(struct PDFContext *ctx)
+static const char *
+handle_index(int index, char a, char b, char c)
+{
+ int i = 0;
+ static char str[16];
+ memset(&str, 0, sizeof(str));
+ switch (index) {
+ case 1:
+ str[i++] = a;
+ break;
+ case 2:
+ str[i++] = a;
+ str[i++] = a;
+ break;
+ case 3:
+ str[i++] = a;
+ str[i++] = a;
+ str[i++] = a;
+ break;
+ case 4:
+ str[i++] = a;
+ str[i++] = b;
+ break;
+ case 5:
+ str[i++] = b;
+ break;
+ case 6:
+ str[i++] = b;
+ str[i++] = a;
+ break;
+ case 7:
+ str[i++] = b;
+ str[i++] = a;
+ str[i++] = a;
+ break;
+ case 8:
+ str[i++] = b;
+ str[i++] = a;
+ str[i++] = a;
+ str[i++] = a;
+ break;
+ case 9:
+ str[i++] = a;
+ str[i++] = c;
+ }
+ str[i] = 0;
+ return str;
+}
+
+static const char *
+numeral_system_western_arabic_to_roman(unsigned int n)
+{
+ if (n > 999) {
+ util_log(LOG_ERR, "Converting numbers higher than 999 is not supported.");
+ return NULL;
+ }
+ const char *str;
+ static char roman[64];
+ int k;
+ int r = 0;
+ memset(&str, 0, sizeof(str));
+ char i = 'I';
+ char v = 'V';
+ char x = 'X';
+ char l = 'L';
+ char c = 'C';
+ char d = 'D';
+ char m = 'M';
+ int index_0 = n - n / 10 * 10;
+ int index_1 = (n - n / 100 * 100 - index_0) / 10;
+ int index_2 = (n - n / 1000 * 1000 - index_0 - index_1) / 100;
+ if (index_2 > 0) {
+ str = handle_index(index_2, c, d, m);
+ for (k = 0; str[k]; k++, r++) {
+ roman[r] = str[k];
+ }
+ }
+ if (index_1 > 0) {
+ str = handle_index(index_1, x, l, c);
+ for (k = 0; str[k]; k++, r++) {
+ roman[r] = str[k];
+ }
+ }
+ if (index_0 > 0) {
+ str = handle_index(index_0, i, v, x);
+ for (k = 0; str[k]; k++, r++) {
+ roman[r] = str[k];
+ }
+ }
+ roman[r] = 0;
+ return roman;
+}
+
+static const char *
+numeral_system_number_to_str(enum NumeralSystem system, int n)
+{
+ if (system == NUS_ROMAN) {
+ const char *str = numeral_system_western_arabic_to_roman((unsigned int)n);
+ if (!str) {
+ LOG_DEBUG("numeral_system_western_arabic_to_roman failed.");
+ return NULL;
+ }
+ return str;
+ } else {
+ static char str[11+1];
+ sprintf((char *)&str, "%d", n);
+ return str;
+ }
+}
+
+static bool
+pdf_page_add_page_no(struct PDFContext *ctx, enum NumeralSystem numeral_system)
+{
+ struct PDFText ***texts;
+ struct ChoStyle *style;
+ const char *page_no;
+ double width, x;
+
+ printf("page no position %d\n", g_config->output->page_no_position);
+
+ style = cho_style_new();
+ style->font->name = strdup(DEFAULT_FONT_FAMILY);
+ texts = &ctx->content->pages[ctx->page]->texts;
+ page_no = numeral_system_number_to_str(numeral_system, ctx->page+1);
+ if (!page_no) {
+ LOG_DEBUG("numeral_system_number_to_str failed.");
+ return false;
+ }
+ width = text_width(page_no, style);
+ if (width == ERROR) {
+ LOG_DEBUG("text_width failed.");
+ return false;
+ }
+ *texts = erealloc(*texts, (ctx->text+1) * sizeof(struct PDFText *));
+ (*texts)[ctx->text] = pdf_text_new();
+ (*texts)[ctx->text]->text = strdup(page_no);
+ (*texts)[ctx->text]->style = style;
+ (*texts)[ctx->text]->x = MEDIABOX_WIDTH - MARGIN_HORIZONTAL / 2 - width;
+ (*texts)[ctx->text]->y = ctx->margin_bottom / 2;
+ (*texts)[ctx->text]->width = width;
+ switch (g_config->output->page_no_position) {
+ case A_LEFT:
+ x = MARGIN_HORIZONTAL / 2;
+ break;
+ case A_CENTER:
+ x = MARGIN_HORIZONTAL + (LINE_WIDTH - width) / 2;
+ break;
+ case A_RIGHT:
+ x = MEDIABOX_WIDTH - MARGIN_HORIZONTAL / 2 - width;
+ break;
+ }
+ (*texts)[ctx->text]->x = x;
+ ctx->text++;
+ return true;
+}
+
+static bool
+pdf_page_close_then_add(struct PDFContext *ctx, enum NumeralSystem numeral_system)
{
ctx->content->pages[ctx->page]->texts = erealloc(
ctx->content->pages[ctx->page]->texts,
@@ -1594,6 +1751,11 @@ pdf_page_close_then_add(struct PDFContext *ctx)
ctx->content->pages = erealloc(ctx->content->pages, (ctx->page+1) * sizeof(struct PDFPage *));
ctx->content->pages[ctx->page] = pdf_page_new();
ctx->y = MEDIABOX_HEIGHT - MARGIN_TOP;
+ if (!pdf_page_add_page_no(ctx, numeral_system)) {
+ LOG_DEBUG("pdf_page_add_page_no failed.");
+ return false;
+ }
+ return true;
}
static bool
@@ -1601,7 +1763,8 @@ pdf_texts_add_text(
struct PDFContext *ctx,
const char *text,
struct ChoStyle *style,
- enum Alignment align
+ enum Alignment align,
+ enum NumeralSystem numeral_system
)
{
struct PDFText ***texts;
@@ -1619,7 +1782,10 @@ pdf_texts_add_text(
char *t = (char *)&str;
while (width > LINE_WIDTH) {
if (ctx->y < ctx->margin_bottom) {
- pdf_page_close_then_add(ctx);
+ if (!pdf_page_close_then_add(ctx, numeral_system)) {
+ LOG_DEBUG("pdf_page_close_then_add failed.");
+ return false;
+ }
texts = &ctx->content->pages[ctx->page]->texts;
}
index = text_find_fitting(t, style, 0.0, LINE_WIDTH);
@@ -1679,7 +1845,10 @@ pdf_texts_add_text(
ctx->y -= 8.0 + style->font->size;
} else {
if (ctx->y < ctx->margin_bottom) {
- pdf_page_close_then_add(ctx);
+ if (!pdf_page_close_then_add(ctx, numeral_system)) {
+ LOG_DEBUG("pdf_page_close_then_add failed.");
+ return false;
+ }
texts = &ctx->content->pages[ctx->page]->texts;
}
ctx->x = calc_x(width, align);
@@ -1795,7 +1964,10 @@ pdf_texts_add_toc_entry(
line_count = 0;
while (width > max_song_title_width) {
if (ctx->y < MARGIN_BOTTOM) {
- pdf_page_close_then_add(ctx);
+ if (!pdf_page_close_then_add(ctx, NUS_ROMAN)) {
+ LOG_DEBUG("pdf_page_close_then_add failed.");
+ return false;
+ }
texts = &ctx->content->pages[ctx->page]->texts;
}
index = text_find_fitting(t, style, MARGIN_HORIZONTAL, max_song_title_width);
@@ -1823,7 +1995,10 @@ pdf_texts_add_toc_entry(
width += MARGIN_HORIZONTAL;
}
if (ctx->y < MARGIN_BOTTOM) {
- pdf_page_close_then_add(ctx);
+ if (!pdf_page_close_then_add(ctx, NUS_ROMAN)) {
+ LOG_DEBUG("pdf_page_close_then_add failed.");
+ return false;
+ }
texts = &ctx->content->pages[ctx->page]->texts;
}
end_of_title_x = width;
@@ -1875,13 +2050,10 @@ pdf_texts_add_toc_entry(
ctx->y -= 8.0 + style->font->size;
} else {
if (ctx->y < MARGIN_BOTTOM) {
- *texts = erealloc(*texts, (ctx->text+1) * sizeof(struct PDFText *));
- (*texts)[ctx->text] = NULL;
- ctx->text = 0;
- ctx->y = MEDIABOX_HEIGHT - MARGIN_TOP;
- ctx->page++;
- ctx->content->pages = erealloc(ctx->content->pages, (ctx->page+1) * sizeof(struct PDFPage *));
- ctx->content->pages[ctx->page] = pdf_page_new();
+ if (!pdf_page_close_then_add(ctx, NUS_ROMAN)) {
+ LOG_DEBUG("pdf_page_close_then_add failed.");
+ return false;
+ }
texts = &ctx->content->pages[ctx->page]->texts;
}
end_of_title_x = width;
@@ -1958,6 +2130,10 @@ pdf_toc_create(
ctx.content->pages = emalloc(sizeof(struct PDFPage *));
ctx.content->pages[ctx.page] = pdf_page_new();
texts = &ctx.content->pages[ctx.page]->texts;
+ if (!pdf_page_add_page_no(&ctx, NUS_ROMAN)) {
+ LOG_DEBUG("pdf_page_add_page_no failed.");
+ return false;
+ }
toc_style = config->output->styles[SF_TOC];
toc = pdf_content->toc;
max_song_title_width = LINE_WIDTH * 0.85;
@@ -1967,7 +2143,7 @@ pdf_toc_create(
return false;
}
title_style = config->output->styles[SF_TOC_TITLE];
- if (!pdf_texts_add_text(&ctx, config->output->toc->title, title_style, A_CENTER)) {
+ if (!pdf_texts_add_text(&ctx, config->output->toc->title, title_style, A_CENTER, NUS_ROMAN)) {
LOG_DEBUG("pdf_texts_add_text failed.");
return false;
}
@@ -2020,6 +2196,10 @@ pdf_content_create(
texts = &ctx.content->pages[ctx.page]->texts;
imgs = &ctx.content->pages[ctx.page]->images;
diagrams = &ctx.content->pages[ctx.page]->diagrams;
+ if (!pdf_page_add_page_no(&ctx, NUS_WESTERN_ARABIC)) {
+ LOG_DEBUG("pdf_page_add_page_no failed.");
+ return false;
+ }
int s;
// int the_page;
for (s = 0; songs[s]; s++) {
@@ -2059,7 +2239,7 @@ pdf_content_create(
ctx.content->toc[ctx.toc_entry]->page_index = ctx.page;
ctx.content->toc[ctx.toc_entry]->page_y = ctx.y;
ctx.toc_entry++;
- if (!pdf_texts_add_text(&ctx, (*m)->value, (*m)->style, A_CENTER)) {
+ if (!pdf_texts_add_text(&ctx, (*m)->value, (*m)->style, A_CENTER, NUS_WESTERN_ARABIC)) {
LOG_DEBUG("pdf_texts_add_text failed.");
return false;
}
@@ -2077,7 +2257,7 @@ pdf_content_create(
*/
struct ChoStyle *output_style;
output_style = config->output->styles[SF_SUBTITLE];
- if (!pdf_texts_add_text(&ctx, (*m)->value, output_style, A_CENTER)) {
+ if (!pdf_texts_add_text(&ctx, (*m)->value, output_style, A_CENTER, NUS_WESTERN_ARABIC)) {
LOG_DEBUG("pdf_texts_add_text failed.");
return false;
}
@@ -2089,7 +2269,7 @@ pdf_content_create(
ctx.y -= 30.0;
for (se = songs[s]->sections; *se; se++) {
if ((*se)->label) {
- if (!pdf_texts_add_text(&ctx, (*se)->label->text, (*se)->label->style, A_LEFT)) {
+ if (!pdf_texts_add_text(&ctx, (*se)->label->text, (*se)->label->style, A_LEFT, NUS_WESTERN_ARABIC)) {
LOG_DEBUG("pdf_texts_add_text failed.");
return false;
}
@@ -2206,7 +2386,10 @@ pdf_content_create(
*texts = erealloc(*texts, (--ctx.text) * sizeof(struct PDFText *));
}
}
- pdf_page_close_then_add(&ctx);
+ if (!pdf_page_close_then_add(&ctx, NUS_WESTERN_ARABIC)) {
+ LOG_DEBUG("pdf_page_close_then_add failed.");
+ return false;
+ }
texts = &ctx.content->pages[ctx.page]->texts;
imgs = &ctx.content->pages[ctx.page]->images;
diagrams = &ctx.content->pages[ctx.page]->diagrams;
@@ -2303,7 +2486,10 @@ pdf_content_create(
}
ctx.y -= 8.0 + ctx.biggest_font_size;
if (ctx.y < ctx.margin_bottom) {
- pdf_page_close_then_add(&ctx);
+ if (!pdf_page_close_then_add(&ctx, NUS_WESTERN_ARABIC)) {
+ LOG_DEBUG("pdf_page_close_then_add failed.");
+ return false;
+ }
texts = &ctx.content->pages[ctx.page]->texts;
imgs = &ctx.content->pages[ctx.page]->images;
diagrams = &ctx.content->pages[ctx.page]->diagrams;
@@ -2315,22 +2501,10 @@ pdf_content_create(
text_above_update_positions(left_aboves, ctx.consumed_lyrics);
}
if ((*li)->btype == BT_PAGE) {
- *texts = erealloc(*texts, (ctx.text+1) * sizeof(struct PDFText *));
- (*texts)[ctx.text] = NULL;
- *imgs = erealloc(*imgs, (ctx.image+1) * sizeof(struct PDFImage *));
- (*imgs)[ctx.image] = NULL;
- *diagrams = erealloc(*diagrams, (ctx.diagram+1) * sizeof(struct ChordDiagram *));
- (*diagrams)[ctx.diagram] = NULL;
- ctx.text = 0;
- ctx.image = 0;
- ctx.diagram = 0;
- ctx.page++;
- ctx.content->pages = erealloc(ctx.content->pages, (ctx.page+1) * sizeof(struct PDFPage *));
- ctx.content->pages[ctx.page] = pdf_page_new();
+ pdf_page_close_then_add(&ctx, NUS_WESTERN_ARABIC);
texts = &ctx.content->pages[ctx.page]->texts;
imgs = &ctx.content->pages[ctx.page]->images;
diagrams = &ctx.content->pages[ctx.page]->diagrams;
- ctx.y = MEDIABOX_HEIGHT - MARGIN_TOP;
}
}
ctx.y -= SECTION_GAP_WIDTH;
@@ -2459,6 +2633,8 @@ out_pdf_create(
pdfio_rect_t crop_box = { 0.0, 0.0, MEDIABOX_WIDTH, MEDIABOX_HEIGHT };
char *dirpath, *pdf_filepath;
+ g_config = config;
+
memset(&g_current_font_name, 0, sizeof(g_current_font_name));
memset(&g_cho_dirpath, 0, PATH_MAX);
@@ -2523,6 +2699,7 @@ out_pdf_create(
g_fonts = NULL;
g_current_font_size = 0.0;
g_current_page_index = 0;
+ g_config = NULL;
return pdf_filepath;
CLEAN:
if (unlink(pdf_filepath)) {
diff --git a/out_pdf.h b/out_pdf.h
@@ -25,6 +25,11 @@ enum FontType {
FT_OTF
};
+enum NumeralSystem {
+ NUS_WESTERN_ARABIC,
+ NUS_ROMAN
+};
+
struct CharPosition {
int line_item_index;
int text_index;