diff --git a/src/libpaps.c b/src/libpaps.c index b6363a7..1b80257 100644 --- a/src/libpaps.c +++ b/src/libpaps.c @@ -55,6 +55,9 @@ typedef struct { double last_pos_x; double scale_x; double scale_y; + double width; + double height; + double cpi; } paps_private_t; @@ -88,6 +91,26 @@ paps_t *paps_new() } void +paps_set_paper_size(paps_t *paps_, + gdouble width, + gdouble height) +{ + paps_private_t *paps = (paps_private_t *)paps_; + + paps->width = width; + paps->height = height; +} + +void +paps_set_cpi(paps_t *paps_, + gdouble cpi) +{ + paps_private_t *paps = (paps_private_t *)paps_; + + paps->cpi = cpi; +} + +void paps_set_scale(paps_t *paps_, gdouble scale_x, gdouble scale_y) @@ -401,7 +424,7 @@ static void draw_contour(paps_private_t *paps, FT_Face ft_face = pango_ft2_font_get_face(font); int num_glyphs = glyphs->num_glyphs; int glyph_idx; - + for (glyph_idx=0; glyph_idxglyphs[glyph_idx].geometry; @@ -410,7 +433,11 @@ static void draw_contour(paps_private_t *paps, glyph_pos_x = x_pos + 1.0*geometry.x_offset * scale; glyph_pos_y = line_start_pos_y - 1.0*geometry.y_offset * scale; - x_pos += geometry.width * scale * paps->scale_x; + if (paps->cpi > 0.0L) { + x_pos += (1 / paps->cpi * 72.0); + } else { + x_pos += geometry.width * scale * paps->scale_x; + } if (glyphs->glyphs[glyph_idx].glyph == PANGO_GLYPH_EMPTY) continue; diff --git a/src/libpaps.h b/src/libpaps.h index 0b74321..cbb4042 100644 --- a/src/libpaps.h +++ b/src/libpaps.h @@ -53,10 +53,16 @@ void paps_free(paps_t *paps); * @param scale_y y-coordinate scale * */ -void -paps_set_scale(paps_t *paps, - gdouble scale_x, - gdouble scale_y); +void paps_set_scale(paps_t *paps, + gdouble scale_x, + gdouble scale_y); + +void paps_set_paper_size(paps_t *paps_, + gdouble width, + gdouble height); + +void paps_set_cpi(paps_t *paps_, + gdouble cpi); /** * libpaps may currently be used only with a PangoContext that it diff --git a/src/paps.c b/src/paps.c index 334d547..72dbaad 100644 --- a/src/paps.c +++ b/src/paps.c @@ -33,6 +33,8 @@ #include #include #include +#include +#include #define BUFSIZE 1024 #define DEFAULT_FONT_FAMILY "Monospace" @@ -594,6 +596,8 @@ int main(int argc, char *argv[]) page_layout.owner = page_owner; page_layout.cups_mode = cups_mode; + paps_set_paper_size(paps, page_width, page_height); + /* calculate x-coordinate scale */ if (page_layout.cpi > 0.0L) { @@ -606,7 +610,7 @@ int main(int argc, char *argv[]) w = pango_font_metrics_get_approximate_digit_width (metrics); if (w > max_width) max_width = w; - page_layout.scale_x = 1 / page_layout.cpi * 72.0 * PANGO_SCALE / max_width; + page_layout.scale_x = 1 / page_layout.cpi * 72.0 * (gdouble)PANGO_SCALE / (gdouble)max_width; pango_font_metrics_unref (metrics); g_object_unref (G_OBJECT (fontmap)); @@ -614,6 +618,8 @@ int main(int argc, char *argv[]) // update the font size to that width pango_font_description_set_size (font_description, font_size * page_layout.scale_x); pango_context_set_font_description (pango_context, font_description); + + paps_set_cpi(paps, page_layout.cpi); } page_layout.scale_x = page_layout.scale_y = 1.0; @@ -727,119 +733,6 @@ read_file (FILE *file, return text; } -#if 0 -/* Take a UTF8 string and break it into paragraphs on \n characters. - * - * Sorry. I couldn't figure out what this version was supposed to do - * - */ -static GList * -split_text_into_paragraphs (PangoContext *pango_context, - page_layout_t *page_layout, - int paint_width, /* In pixels */ - char *text) -{ - char *p = text; - char *next; - gunichar wc; - GList *result = NULL; - char *last_para = text; - - while (p != NULL && *p) - { - wc = g_utf8_get_char (p); - next = g_utf8_next_char (p); - if (wc == (gunichar)-1) - { - fprintf (stderr, "%s: Invalid character in input\n", g_get_prgname ()); - wc = 0; - } - if (!*p || !wc || wc == '\n' || wc == '\f') - { - Paragraph *para = g_new (Paragraph, 1); - para->text = last_para; - para->length = p - last_para; - para->layout = pango_layout_new (pango_context); - - if (cpi > 0.0L && page_layout->do_wordwrap) - { - PangoRectangle ink_rect, logical_rect; - wchar_t *wtext, *wnewtext; - gchar *newtext; - size_t i, len, wwidth = 0, n; - - wtext = g_utf8_to_ucs4 (para->text, para->length, NULL, NULL, NULL); - if (wtext == NULL) - { - fprintf (stderr, "Failed to convert UTF-8 to UCS-4.\n"); - exit(1); - } - - len = g_utf8_strlen (para->text, para->length); - /* the amount of characters to be able to put on the line against CPI */ - n = page_layout->column_width / 72.0 * cpi; - if (len > n) - { - wnewtext = g_new (wchar_t, wcslen (wtext) + 1); - if (wnewtext == NULL) - { - fprintf (stderr, "Failed to allocate a memory.\n"); - g_free (wtext); - exit(1); - } - for (i = 0; i < len; i++) - { - wwidth += wcwidth (wtext[i]); - if (wwidth > n) - break; - wnewtext[i] = wtext[i]; - } - wnewtext[i] = 0L; - - newtext = g_ucs4_to_utf8 ((const gunichar *)wnewtext, i, NULL, NULL, NULL); - if (newtext == NULL) - { - fprintf (stderr, "Failed to convert UCS-4 to UTF-8.\n"); - exit(1); - } - - pango_layout_set_text (para->layout, newtext, -1); - pango_layout_get_extents (para->layout, &ink_rect, &logical_rect); - /* update paint_width to wrap_against CPI */ - paint_width = logical_rect.width / PANGO_SCALE; - g_free (newtext); - g_free (wnewtext); - } - g_free (wtext); - } - pango_layout_set_text (para->layout, para->text, para->length); - pango_layout_set_justify (para->layout, page_layout->do_justify); - pango_layout_set_alignment (para->layout, - page_layout->pango_dir == PANGO_DIRECTION_LTR - ? PANGO_ALIGN_LEFT : PANGO_ALIGN_RIGHT); - pango_layout_set_width (para->layout, paint_width * PANGO_SCALE); - if (page_layout->do_wordwrap) - pango_layout_set_wrap (para->layout, PANGO_WRAP_WORD_CHAR); - para->height = 0; - - if (wc == '\f') - para->formfeed = 1; - else - para->formfeed = 0; - - last_para = next; - - result = g_list_prepend (result, para); - } - if (!wc) /* incomplete character at end */ - break; - p = next; - } - - return g_list_reverse (result); -} -#endif - /* Take a UTF8 string and break it into paragraphs on \n characters */ static GList * @@ -905,18 +798,85 @@ split_text_into_paragraphs (PangoContext *pango_context, para->text = last_para; para->length = p - last_para; para->layout = pango_layout_new (pango_context); - // pango_layout_set_font_description (para->layout, font_description); - pango_layout_set_text (para->layout, para->text, para->length); + + if (page_layout->cpi > 0.0L && page_layout->do_wordwrap) { + /* figuring out the correct width from the pango_font_metrics_get_approximate_width() + * is really hard and pango_layout_set_wrap() doesn't work properly then. + * Those are not reliable to render the characters exactly according to the given CPI. + * So Re-calculate the width to wrap up to be comfortable with CPI. + */ + wchar_t *wtext = NULL, *wnewtext = NULL; + gchar *newtext = NULL; + gsize len, col, i, wwidth = 0; + PangoRectangle ink_rect, logical_rect; + + wtext = (wchar_t *)g_utf8_to_ucs4(para->text, para->length, NULL, NULL, NULL); + if (wtext == NULL) { + fprintf(stderr, "%s: Unable to convert UTF-8 to UCS-4.\n", g_get_prgname()); + fail: + g_free(wtext); + g_free(wnewtext); + g_free(newtext); + if (page_layout->cups_mode) { + /* try to continue parsing text */ + p = next; + continue; + } else { + exit(1); + } + } + len = g_utf8_strlen(para->text, para->length); + /* the amount of characters that can be put on the line against CPI */ + col = page_layout->column_width / 72.0 * page_layout->cpi; + if (len > col) { + /* need to wrap up them */ + wnewtext = g_new(wchar_t, wcslen(wtext) + 1); + if (wnewtext == NULL) { + fprintf(stderr, "%s: Unable to allocate the memory.\n", g_get_prgname()); + goto fail; + } + for (i = 0; i < len; i++) { + wwidth += wcwidth(wtext[i]); + if (wwidth > col) + break; + wnewtext[i] = wtext[i]; + } + wnewtext[i] = 0L; + + newtext = g_ucs4_to_utf8((const gunichar *)wnewtext, i, NULL, NULL, NULL); + if (newtext == NULL) { + fprintf(stderr, "%s: Unable to convert UCS-4 to UTF-8.\n", g_get_prgname()); + goto fail; + } + pango_layout_set_text(para->layout, newtext, -1); + pango_layout_get_extents(para->layout, &ink_rect, &logical_rect); + paint_width = logical_rect.width / PANGO_SCALE; + g_free(wnewtext); + g_free(newtext); + + para->length = i; + next = g_utf8_offset_to_pointer(para->text, para->length); + wc = g_utf8_prev_char(next); + } else { + pango_layout_set_text(para->layout, para->text, para->length); + } + g_free(wtext); + + pango_layout_set_width(para->layout, -1); + } else { + pango_layout_set_text (para->layout, para->text, para->length); + if (page_layout->do_wordwrap) { + pango_layout_set_wrap (para->layout, PANGO_WRAP_WORD_CHAR); + pango_layout_set_width (para->layout, paint_width * PANGO_SCALE); + } else { + pango_layout_set_width (para->layout, -1); + } + } + pango_layout_set_justify (para->layout, page_layout->do_justify); pango_layout_set_alignment (para->layout, page_layout->pango_dir == PANGO_DIRECTION_LTR ? PANGO_ALIGN_LEFT : PANGO_ALIGN_RIGHT); - if (page_layout->do_wordwrap) { - pango_layout_set_wrap (para->layout, PANGO_WRAP_WORD_CHAR); - pango_layout_set_width (para->layout, paint_width * PANGO_SCALE); - } else { - pango_layout_set_width (para->layout, -1); - } para->height = 0;