commit e69184c0f06e72039dd8a3ca32b0e105479d3019
parent 7df72cd690fff63c07b79ac54852b4b6802c2528
Author: nibo <nibo@relim.de>
Date: Tue, 24 Dec 2024 18:06:38 +0100
Finish toc
Diffstat:
| M | out_pdf.c | | | 192 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------- |
1 file changed, 156 insertions(+), 36 deletions(-)
diff --git a/out_pdf.c b/out_pdf.c
@@ -18,6 +18,7 @@ static char g_cho_dirpath[PATH_MAX];
static char g_current_font_name[200];
static double g_current_font_size;
static pdfio_obj_t *g_current_font_obj = NULL;
+static int g_current_page_index;
static pdfio_file_t *g_pdf_file = NULL;
pdfio_obj_t *
@@ -291,8 +292,13 @@ out_pdf_fnt_name_create(struct Font *font)
static bool
out_pdf_font_set(pdfio_stream_t *stream, struct Font *font)
{
+ static int page_index = 0;
char *name = out_pdf_fnt_name_create(font);
- if (!strcmp(name, g_current_font_name) && font->size == g_current_font_size) {
+ if (
+ !strcmp(name, g_current_font_name) &&
+ font->size == g_current_font_size &&
+ g_current_page_index == page_index
+ ) {
free(name);
return true;
}
@@ -308,6 +314,7 @@ out_pdf_font_set(pdfio_stream_t *stream, struct Font *font)
strcpy(g_current_font_name, name);
g_current_font_obj = font_obj;
g_current_font_size = font->size;
+ page_index = g_current_page_index;
free(name);
return true;
}
@@ -514,16 +521,20 @@ static bool
annot_page_link_add(
struct PDFContext *ctx,
struct TocEntry *entry,
+ int toc_page_count,
+ int line_count,
double font_size
)
{
+ int page_index;
pdfio_rect_t rect;
pdfio_dict_t *annot;
pdfio_array_t *destination;
rect.x1 = MARGIN_HORIZONTAL;
rect.x2 = MARGIN_HORIZONTAL + LINE_WIDTH;
rect.y1 = ctx->y - 2.0;
- rect.y2 = ctx->y + font_size * 0.8;
+ rect.y2 = ctx->y + (8.0 + font_size) * line_count - font_size * 0.8;
+ page_index = entry->page_index + toc_page_count;
annot = pdfioDictCreate(g_pdf_file);
if (!pdfioDictSetName(annot, "Subtype", "Link")) {
LOG_DEBUG("pdfioDictSetName failed.");
@@ -534,15 +545,20 @@ annot_page_link_add(
return false;
}
destination = pdfioArrayCreate(g_pdf_file);
- printf("page index '%d'\n", entry->page_index);
- if (!pdfioArrayAppendNumber(destination, entry->page_index)) {
+ if (!pdfioArrayAppendNumber(destination, page_index)) {
LOG_DEBUG("pdfioArrayAppendNumber failed.");
return false;
}
- if (!pdfioArrayAppendName(destination, "Fit")) {
+ if (!pdfioArrayAppendName(destination, "FitH")) {
LOG_DEBUG("pdfioArrayAppendName failed.");
return false;
}
+ // TODO: Is this constant '30.0' correct with different font sizes, etc. ?
+ // clicking the annotation should show the song including the song title at the top
+ if (!pdfioArrayAppendNumber(destination, entry->page_y + 30.0)) {
+ LOG_DEBUG("pdfioArrayAppendNumber failed.");
+ return false;
+ }
if (!pdfioDictSetArray(annot, "Dest", destination)) {
LOG_DEBUG("pdfioDictSetArray failed.");
return false;
@@ -1339,6 +1355,7 @@ text_above_update_positions(struct ChoLineItemAbove **aboves, size_t consumed_ly
}
}
+// TODO: This function doesn't create a new page if needed
static bool
pdf_texts_add_lyrics(
struct ChoLineItem *item,
@@ -1447,6 +1464,7 @@ calc_x(double width, enum Alignment align)
return MARGIN_HORIZONTAL;
}
+// TODO: This function doesn't create a new page if needed
static bool
pdf_texts_add_text(
struct PDFContext *ctx,
@@ -1542,17 +1560,78 @@ pdf_texts_add_text(
return true;
}
+// TODO: This function doesn't create a new page if needed
+static int
+pdf_toc_page_count(
+ struct TocEntry **entries,
+ struct ChoStyle *style,
+ double max_title_width
+)
+{
+ int text = 0;
+ int page = 0;
+ double x = MARGIN_HORIZONTAL;
+ double y = MEDIABOX_HEIGHT - MARGIN_TOP;
+ double width;
+ struct TocEntry **toc;
+ toc = entries;
+ while (*toc) {
+ if (y < MARGIN_BOTTOM) {
+ text = 0;
+ y = MEDIABOX_HEIGHT - MARGIN_TOP;
+ page++;
+ }
+ int index;
+ char tmp[strlen((*toc)->title)+1];
+ strcpy((char *)&tmp, (*toc)->title);
+ width = text_width((*toc)->title, style);
+ if (width == ERROR) {
+ LOG_DEBUG("text_width failed.");
+ return -1;
+ }
+ width += MARGIN_HORIZONTAL;
+ if (width > max_title_width) {
+ char *t = (char *)&tmp;
+ while (width > max_title_width) {
+ index = text_find_fitting(t, style, MARGIN_HORIZONTAL, max_title_width);
+ if (index == EMPTY_INT) {
+ LOG_DEBUG("text_find_fitting failed.");
+ return -1;
+ }
+ t[index] = 0;
+ y -= 8.0 + style->font->size;
+ t += index + 1;
+ width = text_width(t, style);
+ if (width == ERROR) {
+ LOG_DEBUG("text_width failed.");
+ return -1;
+ }
+ }
+ y -= 8.0 + style->font->size;
+ } else {
+ y -= 8.0 + style->font->size;
+ }
+ toc++;
+ }
+ return page + 1;
+}
+
+// TODO: This function doesn't create a new page if needed
static bool
pdf_texts_add_toc_entry(
struct PDFContext *ctx,
struct TocEntry *entry,
struct ChoStyle *style,
- double max_title_width
+ double max_title_width,
+ int toc_page_count
)
{
- double width;
- int index;
+ struct PDFText ***texts;
+ texts = &ctx->content->pages[ctx->page]->texts;
+ double width, page_no_x;
+ int index, line_count;
char tmp[strlen(entry->title)+1];
+ char page_no[5+1];
strcpy((char *)&tmp, entry->title);
width = text_width(entry->title, style);
if (width == ERROR) {
@@ -1562,6 +1641,7 @@ pdf_texts_add_toc_entry(
width += MARGIN_HORIZONTAL;
if (width > max_title_width) {
char *t = (char *)&tmp;
+ line_count = 0;
while (width > max_title_width) {
index = text_find_fitting(t, style, MARGIN_HORIZONTAL, max_title_width);
if (index == EMPTY_INT) {
@@ -1569,7 +1649,15 @@ pdf_texts_add_toc_entry(
return false;
}
t[index] = 0;
- printf("part '%s'\n", t);
+ *texts = erealloc(*texts, (ctx->text+1) * sizeof(struct PDFText *));
+ (*texts)[ctx->text] = pdf_text_new();
+ (*texts)[ctx->text]->text = strdup(t);
+ (*texts)[ctx->text]->style = cho_style_copy(style);
+ (*texts)[ctx->text]->x = MARGIN_HORIZONTAL;
+ (*texts)[ctx->text]->y = ctx->y;
+ ctx->text++;
+ ctx->y -= 8.0 + style->font->size;
+ line_count++;
t += index + 1;
width = text_width(t, style);
if (width == ERROR) {
@@ -1577,9 +1665,54 @@ pdf_texts_add_toc_entry(
return false;
}
}
- printf("last part '%s'\n", t);
+ *texts = erealloc(*texts, (ctx->text+1) * sizeof(struct PDFText *));
+ (*texts)[ctx->text] = pdf_text_new();
+ (*texts)[ctx->text]->text = strdup(t);
+ (*texts)[ctx->text]->style = cho_style_copy(style);
+ (*texts)[ctx->text]->x = MARGIN_HORIZONTAL;
+ (*texts)[ctx->text]->y = ctx->y;
+ ctx->text++;
+ sprintf((char *)&page_no, "%d", entry->page_index+1);
+ width = text_width(page_no, style);
+
+ page_no_x = MEDIABOX_WIDTH - MARGIN_HORIZONTAL - width;
+ *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 = cho_style_copy(style);
+ (*texts)[ctx->text]->x = page_no_x;
+ (*texts)[ctx->text]->y = ctx->y;
+ line_count++;
+ if (!annot_page_link_add(ctx, entry, toc_page_count, line_count, style->font->size)) {
+ LOG_DEBUG("annot_page_link_add");
+ return false;
+ }
+ ctx->text++;
+ ctx->y -= 8.0 + style->font->size;
} else {
- printf("title '%s'\n", entry->title);
+ *texts = erealloc(*texts, (ctx->text+1) * sizeof(struct PDFText *));
+ (*texts)[ctx->text] = pdf_text_new();
+ (*texts)[ctx->text]->text = strdup(entry->title);
+ (*texts)[ctx->text]->style = cho_style_copy(style);
+ (*texts)[ctx->text]->x = MARGIN_HORIZONTAL;
+ (*texts)[ctx->text]->y = ctx->y;
+ ctx->text++;
+ sprintf((char *)&page_no, "%d", entry->page_index+1);
+ width = text_width(page_no, style);
+
+ page_no_x = MEDIABOX_WIDTH - MARGIN_HORIZONTAL - width;
+ *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 = cho_style_copy(style);
+ (*texts)[ctx->text]->x = page_no_x;
+ (*texts)[ctx->text]->y = ctx->y;
+ if (!annot_page_link_add(ctx, entry, toc_page_count, 1, style->font->size)) {
+ LOG_DEBUG("annot_page_link_add");
+ return false;
+ }
+ ctx->text++;
+ ctx->y -= 8.0 + style->font->size;
}
return true;
}
@@ -1593,6 +1726,7 @@ pdf_toc_create(
)
{
double width, space_for_dots, max_title_width;
+ int toc_page_count;
struct PDFContext ctx;
struct PDFText ***texts;
ctx.text = 0;
@@ -1606,10 +1740,14 @@ pdf_toc_create(
struct OutputStyle *toc_style = config_output_style_get(config->output->styles, "toc");
struct TocEntry **toc;
toc = pdf_content->toc;
- max_title_width = LINE_WIDTH * 0.85 + MARGIN_HORIZONTAL;
- // TODO: First find out how many pages the toc will have
+ max_title_width = LINE_WIDTH * 0.85;
+ toc_page_count = pdf_toc_page_count(toc, toc_style->style, max_title_width);
+ if (toc_page_count == -1) {
+ LOG_DEBUG("pdf_toc_page_count failed.");
+ return false;
+ }
while (*toc) {
- if (!pdf_texts_add_toc_entry(&ctx, *toc, toc_style->style, max_title_width)) {
+ if (!pdf_texts_add_toc_entry(&ctx, *toc, toc_style->style, max_title_width, toc_page_count)) {
LOG_DEBUG("pdf_texts_add_toc_entry failed.");
return false;
}
@@ -1623,29 +1761,9 @@ pdf_toc_create(
ctx.content->pages[ctx.page] = pdf_page_new();
texts = &ctx.content->pages[ctx.page]->texts;
}
- // pdf_text_count_vertical_space((*toc)->title, toc_style->style);
- /* if (!annot_page_link_add(&ctx, *toc, toc_style->style->font->size)) {
- LOG_DEBUG("annot_page_link_add");
- return false;
- } */
// TODO: create (multi)line with title, dots and the page number
- space_for_dots = LINE_WIDTH;
- char page_no[5+1];
- sprintf((char *)&page_no, "%d", (*toc)->page_index+1);
- width = text_width(page_no, toc_style->style);
-
- double most_right_x = MEDIABOX_WIDTH - MARGIN_HORIZONTAL;
- double page_no_x = most_right_x - width;
- *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 = cho_style_copy(toc_style->style);
- (*texts)[ctx.text]->x = page_no_x;
- (*texts)[ctx.text]->y = ctx.y;
- ctx.text++;
- ctx.y -= 8.0 + toc_style->style->font->size;
-
- /* space_for_dots -= width;
+ /* space_for_dots = LINE_WIDTH;
+ space_for_dots -= width;
width = text_width((*toc)->title, toc_style->style);
space_for_dots -= width;
printf("width for dots '%.1f'\n", space_for_dots);
@@ -2042,6 +2160,7 @@ pdf_toc_render(struct PDFContent *content, pdfio_file_t *file)
pages = content->pages;
int p;
for (p = 0; pages[p]; p++) {
+ g_current_page_index = p;
texts = pages[p]->texts;
stream = out_pdf_page_create(file, NULL, pages[p]->annots);
while (*texts) {
@@ -2069,6 +2188,7 @@ pdf_content_render(struct PDFContent *content, pdfio_file_t *file)
pdfio_stream_t *stream;
pages = content->pages;
for (p = 0; pages[p]; p++) {
+ g_current_page_index = p;
texts = pages[p]->texts;
imgs = pages[p]->images;
stream = out_pdf_page_create(file, imgs, pages[p]->annots);