diff -ruN paps-0.6.6.orig/src/libpaps.c paps-0.6.6/src/libpaps.c --- paps-0.6.6.orig/src/libpaps.c 2006-04-27 04:09:03.000000000 +0900 +++ paps-0.6.6/src/libpaps.c 2006-07-17 13:33:13.000000000 +0900 @@ -52,16 +52,20 @@ int last_char_idx; double last_pos_y; double last_pos_x; + double scale_x; + double scale_y; } paps_private_t; // Forward declarations -static void add_postscript_prologue(GString *ps_string); +static void add_postscript_prologue(paps_private_t *paps); static gchar *get_next_char_id_strdup(paps_private_t *paps); static void add_line_to_postscript(paps_private_t *paps, GString *line_str, double x_pos, double y_pos, + double scale_x, + double scale_y, PangoLayoutLine *line); paps_t *paps_new() @@ -76,12 +80,27 @@ paps->last_pos_x = -1e67; paps->last_pos_y = -1e67; paps->last_char_idx = 0; + paps->scale_x = 1.0; + paps->scale_y = 1.0; - add_postscript_prologue(paps->header); + add_postscript_prologue(paps); return paps; } +void +paps_set_scale(paps_t *paps_, + gdouble scale_x, + gdouble scale_y) +{ + paps_private_t *paps = (paps_private_t *)paps_; + + paps->scale_x = scale_x; + paps->scale_y = scale_y; + g_string_erase(paps->header, 0, -1); + add_postscript_prologue(paps); +} + PangoContext *paps_get_pango_context() { return pango_ft2_get_context (PAPS_DPI, PAPS_DPI); @@ -124,14 +143,18 @@ GString *line_str, PangoLayoutLine *pango_line, double line_start_pos_x, - double line_start_pos_y + double line_start_pos_y, + double scale_x, + double scale_y ); void draw_bezier_outline(paps_private_t *paps, GString *layout_str, FT_Face face, PangoGlyphInfo *glyph_info, double pos_x, - double pos_y + double pos_y, + double scale_x, + double scale_y ); /* Countour traveling functions */ static int paps_ps_move_to( FT_Vector* to, @@ -166,6 +189,8 @@ gchar *paps_layout_to_postscript_strdup(paps_t *paps_, double pos_x, double pos_y, + double scale_x, + double scale_y, PangoLayout *layout) { paps_private_t *paps = (paps_private_t*)paps_; @@ -189,6 +214,8 @@ layout_str, pos_x, pos_y, + scale_x, + scale_y, pango_line); pos_y -= logical_rect.height * scale; @@ -203,6 +230,8 @@ gchar *paps_layout_line_to_postscript_strdup(paps_t *paps_, double pos_x, double pos_y, + double scale_x, + double scale_y, PangoLayoutLine *layout_line) { paps_private_t *paps = (paps_private_t*)paps_; @@ -213,6 +242,8 @@ layout_str, pos_x, pos_y, + scale_x, + scale_y, layout_line); ret_str = layout_str->str; @@ -221,9 +252,10 @@ return ret_str; } -void add_postscript_prologue(GString *ps_string) +static void +add_postscript_prologue(paps_private_t *paps) { - g_string_append_printf(ps_string, + g_string_append_printf(paps->header, "%%%%BeginProlog\n" "/papsdict 1 dict def\n" "papsdict begin\n" @@ -231,7 +263,7 @@ ); /* Outline support */ - g_string_append_printf(ps_string, + g_string_append_printf(paps->header, "/conicto {\n" " /to_y exch def\n" " /to_x exch def\n" @@ -249,7 +281,7 @@ "/start_ol { gsave } bind def\n" "/end_ol { closepath fill grestore } bind def\n" /* Specify both x and y. */ - "/draw_char { fontdict begin gsave %f dup scale last_x last_y translate load exec end grestore} def\n" + "/draw_char { fontdict begin gsave %f dup scale last_x last_y translate %f %f scale load exec end grestore} def\n" "/goto_xy { fontdict begin /last_y exch def /last_x exch def end } def\n" "/goto_x { fontdict begin /last_x exch def end } def\n" "/fwd_x { fontdict begin /last_x exch last_x add def end } def\n" @@ -261,14 +293,15 @@ // The scaling is a combination of the scaling due // to the dpi and the difference in the coordinate // systems of postscript and freetype2. - 1.0 / PAPS_DPI + 1.0 / PAPS_DPI, + paps->scale_x, paps->scale_y ); // The following is a dispatcher for an encoded string that contains // a packed version of the pango layout data. Currently it just executes // the symbols corresponding to the encoded characters, but in the future // it will also contain some meta data, e.g. the size of the layout. - g_string_append_printf(ps_string, + g_string_append_printf(paps->header, "/paps_exec {\n" " 1 dict begin\n" " /ps exch def\n" @@ -320,7 +353,7 @@ ); /* Open up dictionaries */ - g_string_append(ps_string, + g_string_append(paps->header, "/fontdict 1 dict def\n" "papsdict begin fontdict begin\n"); } @@ -331,6 +364,8 @@ GString *line_str, double x_pos, double y_pos, + double scale_x, + double scale_y, PangoLayoutLine *line) { PangoRectangle ink_rect, logical_rect; @@ -349,7 +384,7 @@ } #endif - draw_contour(paps, line_str, line, x_pos, y_pos); + draw_contour(paps, line_str, line, x_pos, y_pos, scale_x, scale_y); } /* draw_contour() draws all of the contours that make up a line. @@ -359,7 +394,9 @@ GString *layout_str, PangoLayoutLine *pango_line, double line_start_pos_x, - double line_start_pos_y + double line_start_pos_y, + double scale_x, + double scale_y ) { GSList *runs_list; @@ -389,7 +426,7 @@ 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; + x_pos += geometry.width * scale * scale_x; if (glyphs->glyphs[glyph_idx].glyph == PANGO_GLYPH_EMPTY) continue; @@ -399,7 +436,9 @@ ft_face, &glyphs->glyphs[glyph_idx], glyph_pos_x, - glyph_pos_y + glyph_pos_y, + scale_x, + scale_y ); } @@ -415,13 +454,15 @@ FT_Face face, PangoGlyphInfo *glyph_info, double pos_x, - double pos_y + double pos_y, + double scale_x, + double scale_y ) { static gchar glyph_hash_string[100]; double scale = 72.0 / PANGO_SCALE / PAPS_DPI; double epsilon = 1e-2; - double glyph_width = glyph_info->geometry.width * scale; + double glyph_width = glyph_info->geometry.width * scale * scale_x; gchar *id = NULL; /* Output outline */ @@ -480,7 +521,7 @@ g_string_append_printf(glyph_def_string, "%.0f fwd_x\n" "end_ol\n", - glyph_info->geometry.width * scale * PAPS_DPI + glyph_info->geometry.width * scale * scale_x * PAPS_DPI ); // TBD - Check if the glyph_def_string is empty. If so, set the diff -ruN paps-0.6.6.orig/src/libpaps.h paps-0.6.6/src/libpaps.h --- paps-0.6.6.orig/src/libpaps.h 2005-12-21 04:35:39.000000000 +0900 +++ paps-0.6.6/src/libpaps.h 2006-07-17 13:27:59.000000000 +0900 @@ -40,6 +40,19 @@ */ void paps_free(paps_t *paps); +/** + * Set the scales for characters. + * + * @param paps Paps object + * @param scale_x x-coordinate scale + * @param scale_y y-coordinate scale + * + */ +void +paps_set_scale(paps_t *paps, + gdouble scale_x, + gdouble scale_y); + /** * libpaps may currently be used only with a PangoContext that it * is creating. The context returned may of course be changed though @@ -78,6 +91,8 @@ gchar *paps_layout_to_postscript_strdup(paps_t *paps, double pos_x, double pos_y, + double scale_x, + double scale_y, PangoLayout *layout); /** * Create postscript related to a single PangoLayout line at position @@ -95,6 +110,8 @@ gchar *paps_layout_line_to_postscript_strdup(paps_t *paps_, double pos_x, double pos_y, + double scale_x, + double scale_y, PangoLayoutLine *layout_line); /** diff -ruN paps-0.6.6.orig/src/paps.c paps-0.6.6/src/paps.c --- paps-0.6.6.orig/src/paps.c 2006-07-17 13:27:27.000000000 +0900 +++ paps-0.6.6/src/paps.c 2006-07-17 13:27:59.000000000 +0900 @@ -22,6 +22,7 @@ #include +#include #include "libpaps.h" #include #include @@ -29,6 +30,7 @@ #include #include #include +#include #define BUFSIZE 1024 #define DEFAULT_FONT_FAMILY "Monospace" @@ -71,6 +73,8 @@ int header_sep; int header_height; int footer_height; + gdouble scale_x; + gdouble scale_y; gboolean do_draw_header; gboolean do_draw_footer; gboolean do_duplex; @@ -110,7 +114,8 @@ }; /* Information passed in user data when drawing outlines */ -GList *split_paragraphs_into_lines (GList *paragraphs); +GList *split_paragraphs_into_lines (page_layout_t *page_layout, + GList *paragraphs); static char *read_file (FILE *file, GIConv handle); static GList *split_text_into_paragraphs (PangoContext *pango_context, @@ -136,6 +141,8 @@ static void draw_line_to_page (FILE *OUT, int column_idx, int column_pos, + gdouble scale_x, + gdouble scale_y, page_layout_t *page_layout, PangoLayoutLine *line); static int draw_page_header_line_to_page(FILE *OUT, @@ -158,6 +165,7 @@ double last_pos_x = -1; paps_t *paps; paper_type_t paper_type = PAPER_TYPE_A4; +gdouble lpi = 0.0L, cpi = 0.0L; #define CASE(s) if (strcmp(S_, s) == 0) @@ -190,6 +198,60 @@ return retval; } +static gboolean +_paps_arg_lpi_cb(const gchar *option_name, + const gchar *value, + gpointer data) +{ + gboolean retval = TRUE; + gchar *p = NULL; + + if (value && *value) + { + errno = 0; + lpi = g_strtod(value, &p); + if ((p && *p) || errno == ERANGE) + { + fprintf(stderr, "given LPI value was invalid.\n"); + retval = FALSE; + } + } + else + { + fprintf(stderr, "You must specify the amount of lines per inch.\n"); + retval = FALSE; + } + + return retval; +} + +static gboolean +_paps_arg_cpi_cb(const gchar *option_name, + const gchar *value, + gpointer data) +{ + gboolean retval = TRUE; + gchar *p = NULL; + + if (value && *value) + { + errno = 0; + cpi = g_strtod(value, &p); + if ((p && *p) || errno == ERANGE) + { + fprintf(stderr, "given CPI value was invalid.\n"); + retval = FALSE; + } + } + else + { + fprintf(stderr, "You must specify the amount of characters per inch.\n"); + retval = FALSE; + } + + return retval; +} + static PangoLanguage * get_language(void) { @@ -233,6 +295,8 @@ {"left-margin", 0, 0, G_OPTION_ARG_INT, &left_margin, "Set left margin. (Default: 36)", "NUM"}, {"header", 0, 0, G_OPTION_ARG_NONE, &do_draw_header, "Draw page header for each page.", NULL}, {"encoding", 0, 0, G_OPTION_ARG_STRING, &encoding, "Assume the documentation encoding.", "ENCODING"}, + {"lpi", 0, 0, G_OPTION_ARG_CALLBACK, _paps_arg_lpi_cb, "Set the amount of lines per inch.", "REAL"}, + {"cpi", 0, 0, G_OPTION_ARG_CALLBACK, _paps_arg_cpi_cb, "Set the amount of characters per inch.", "REAL"}, {NULL} }; GError *error = NULL; @@ -243,6 +307,9 @@ PangoContext *pango_context; PangoFontDescription *font_description; PangoDirection pango_dir = PANGO_DIRECTION_LTR; + PangoFontMap *fontmap; + PangoFontset *fontset; + PangoFontMetrics *metrics; int num_pages = 1; int gutter_width = 40; int total_gutter_width; @@ -254,6 +321,7 @@ gchar *header_font_desc = MAKE_FONT_NAME (HEADER_FONT_FAMILY, HEADER_FONT_SCALE); gchar *filename_in, *title, *text; int header_sep = 20; + int max_width = 0, w; GIConv cvh = NULL; /* Prerequisite when using glib. */ @@ -343,6 +411,8 @@ page_layout.header_height = 0; page_layout.footer_height = 0; page_layout.do_wordwrap = do_wordwrap; + page_layout.scale_x = 1.0L; + page_layout.scale_y = 1.0L; if (do_draw_header) page_layout.header_sep = header_sep; else @@ -365,7 +435,22 @@ page_layout.pango_dir = pango_dir; page_layout.filename = filename_in; page_layout.header_font_desc = header_font_desc; - + + /* calculate x-coordinate scale */ + if (cpi > 0.0L) + { + fontmap = pango_ft2_font_map_new (); + fontset = pango_font_map_load_fontset (fontmap, pango_context, font_description, get_language ()); + metrics = pango_fontset_get_metrics (fontset); + max_width = pango_font_metrics_get_approximate_char_width (metrics); + w = pango_font_metrics_get_approximate_digit_width (metrics); + if (w > max_width) + max_width = w; + page_layout.scale_x = 1 / cpi * 72.0 * PANGO_SCALE / max_width; + pango_font_metrics_unref (metrics); + g_object_unref (G_OBJECT (fontmap)); + } + if (encoding != NULL) { cvh = g_iconv_open ("UTF-8", encoding); @@ -385,11 +470,12 @@ &page_layout, page_layout.column_width * page_layout.pt_to_pixel, text); - pango_lines = split_paragraphs_into_lines(paragraphs); + pango_lines = split_paragraphs_into_lines(&page_layout, paragraphs); if (OUT == NULL) OUT = stdout; + paps_set_scale(paps, page_layout.scale_x, page_layout.scale_y); print_postscript_header(OUT, title, &page_layout); ps_pages_string = g_string_new(""); @@ -493,6 +579,58 @@ 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 = (wchar_t *)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"); + return NULL; + } + + len = wcswidth (wtext); + /* 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); + return NULL; + } + 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"); + return NULL; + } + + 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, @@ -523,9 +661,11 @@ /* Split a list of paragraphs into a list of lines. */ GList * -split_paragraphs_into_lines(GList *paragraphs) +split_paragraphs_into_lines(page_layout_t *page_layout, + GList *paragraphs) { GList *line_list = NULL; + int max_height = 0; /* Read the file */ /* Now split all the pagraphs into lines */ @@ -554,10 +694,14 @@ line_link->formfeed = 1; line_link->ink_rect = ink_rect; line_list = g_list_prepend(line_list, line_link); + if (logical_rect.height > max_height) + max_height = logical_rect.height; } par_list = par_list->next; } + if (lpi > 0.0L) + page_layout->scale_y = 1 / lpi * 72.0 * page_layout->pt_to_pixel * PANGO_SCALE / max_height; return g_list_reverse(line_list); @@ -612,9 +756,14 @@ draw_line_to_page(OUT, column_idx, column_y_pos+line_link->logical_rect.height, + page_layout->scale_x, page_layout->scale_y, page_layout, line); - column_y_pos += line_link->logical_rect.height; + + if (lpi > 0.0L) + column_y_pos += (1 / lpi * 72.0 * page_layout->pt_to_pixel * PANGO_SCALE); + else + column_y_pos += line_link->logical_rect.height; pango_lines = pango_lines->next; } @@ -840,6 +989,8 @@ draw_line_to_page(FILE *OUT, int column_idx, int column_pos, + gdouble scale_x, + gdouble scale_y, page_layout_t *page_layout, PangoLayoutLine *line) { @@ -874,6 +1025,7 @@ ps_layout = paps_layout_line_to_postscript_strdup(paps, x_pos, y_pos, + scale_x, scale_y, line); g_string_append(ps_pages_string, @@ -935,6 +1087,7 @@ } ps_layout = paps_layout_line_to_postscript_strdup(paps, x_pos, y_pos, + page_layout->scale_x, page_layout->scale_y, line); g_string_append(ps_pages_string, ps_layout); @@ -948,6 +1101,7 @@ x_pos = (page_layout->page_width - (logical_rect.width / PANGO_SCALE * page_layout->pixel_to_pt)) / 2; ps_layout = paps_layout_line_to_postscript_strdup(paps, x_pos, y_pos, + page_layout->scale_x, page_layout->scale_y, line); g_string_append(ps_pages_string, ps_layout); @@ -961,6 +1115,7 @@ x_pos = page_layout->page_width - page_layout->right_margin - (logical_rect.width / PANGO_SCALE * page_layout->pixel_to_pt); ps_layout = paps_layout_line_to_postscript_strdup(paps, x_pos, y_pos, + page_layout->scale_x, page_layout->scale_y, line); g_string_append(ps_pages_string, ps_layout); @@ -977,4 +1132,3 @@ return logical_rect.height; } - diff -ruN paps-0.6.6.orig/src/test_libpaps.c paps-0.6.6/src/test_libpaps.c --- paps-0.6.6.orig/src/test_libpaps.c 2005-12-21 04:35:39.000000000 +0900 +++ paps-0.6.6/src/test_libpaps.c 2006-07-17 13:27:59.000000000 +0900 @@ -83,6 +83,7 @@ ps_layout = paps_layout_to_postscript_strdup(paps, 0, 0, + 1.0, 1.0, layout); g_string_append_printf(ps_text, "gsave\n" @@ -110,6 +111,7 @@ ); ps_layout = paps_layout_to_postscript_strdup(paps, 0, 0, + 1.0, 1.0, layout); g_string_append_printf(ps_text, "gsave\n"