"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "src/paps.c" between
paps-0.6.8.tar.gz and paps-0.7.1.tar.gz

About: is a text to postscript converter through pango.

paps.c  (paps-0.6.8):paps.c  (paps-0.7.1)
skipping to change at line 25 skipping to change at line 25
* *
* You should have received a copy of the GNU Library General Public * You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the * License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA. * Boston, MA 02111-1307, USA.
* *
*/ */
#include <pango/pango.h> #include <pango/pango.h>
#include <pango/pangoft2.h> #include <pango/pangoft2.h>
#include "libpaps.h" #include <pango/pangocairo.h>
#include <cairo/cairo.h>
#include <cairo/cairo-ps.h>
#include <cairo/cairo-pdf.h>
#include <cairo/cairo-svg.h>
#include <errno.h> #include <errno.h>
#include <langinfo.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <time.h> #include <time.h>
#include <locale.h> #include <locale.h>
#include <math.h>
#include <wchar.h>
#include <libgen.h>
#include <config.h>
#if ENABLE_NLS
#include <libintl.h>
#define _(str) gettext(str)
#ifdef gettext_noop
#define N_(str) gettext_noop(str)
#else
#define N_(str) (str)
#endif
#else /* NLS is disabled */
#define _(str) (str)
#define N_(str) (str)
#endif
#define BUFSIZE 1024 #define BUFSIZE 1024
#define DEFAULT_FONT_FAMILY "Monospace" #define DEFAULT_FONT_FAMILY "Monospace"
#define DEFAULT_FONT_SIZE "12" #define DEFAULT_FONT_SIZE "12"
#define HEADER_FONT_FAMILY "Monospace Bold" #define HEADER_FONT_FAMILY "Monospace Bold"
#define HEADER_FONT_SCALE "12" #define HEADER_FONT_SCALE "12"
#define MAKE_FONT_NAME(f,s) f " " s #define MAKE_FONT_NAME(f,s) f " " s
/*
* Cairo sets limit on the comment line for cairo_ps_surface_dsc_comment() to
* 255 characters, including the initial percent characters.
*/
#define CAIRO_COMMENT_MAX 255
#define MARGIN_LEFT 36
#define MARGIN_RIGHT 36
#define MARGIN_TOP 36
#define MARGIN_BOTTOM 36
typedef enum { typedef enum {
PAPER_TYPE_A4 = 0, PAPER_TYPE_A4 = 0,
PAPER_TYPE_US_LETTER = 1, PAPER_TYPE_US_LETTER = 1,
PAPER_TYPE_US_LEGAL = 2 PAPER_TYPE_US_LEGAL = 2,
PAPER_TYPE_A3 = 3
} paper_type_t ; } paper_type_t ;
typedef enum {
FORMAT_POSTSCRIPT = 0,
FORMAT_PDF = 1,
FORMAT_SVG = 2
} output_format_t ;
typedef struct { typedef struct {
double width; double width;
double height; double height;
} paper_size_t; } paper_size_t;
const paper_size_t paper_sizes[] = { static const paper_size_t paper_sizes[] = {
{ 595.28, 841.89}, /* A4 */ { 595.28, 841.89}, /* A4 */
{ 612, 792}, /* US letter */ { 612, 792}, /* US letter */
{ 612, 1008} /* US legal */ { 612, 1008}, /* US legal */
{ 842, 1190} /* A3 */
}; };
typedef struct { typedef struct {
double pt_to_pixel;
double pixel_to_pt;
int column_width; int column_width;
int column_height; int column_height;
int num_columns; int num_columns;
int gutter_width; /* These are all in postscript points=1/72 inch... */ int gutter_width; /* These are all in postscript points=1/72 inch... */
int top_margin; int top_margin;
int bottom_margin; int bottom_margin;
int left_margin; int left_margin;
int right_margin; int right_margin;
int page_width; double page_width;
int page_height; double page_height;
int header_ypos; int header_ypos;
int header_sep; int header_sep;
int header_height; int header_height;
int footer_height; int footer_height;
gdouble scale_x; gdouble scale_x;
gdouble scale_y; gdouble scale_y;
gboolean do_draw_header; gboolean do_draw_header;
gboolean do_draw_footer; gboolean do_draw_footer;
gboolean do_duplex; gboolean do_duplex;
gboolean do_tumble; gboolean do_tumble;
gboolean do_landscape; gboolean do_landscape;
gboolean do_justify; gboolean do_justify;
gboolean do_separation_line; gboolean do_separation_line;
gboolean do_draw_contour; gboolean do_draw_contour;
gboolean do_wordwrap; gboolean do_show_wrap;
gboolean do_use_markup; gboolean do_use_markup;
gboolean do_stretch_chars; gboolean do_stretch_chars;
PangoDirection pango_dir; PangoDirection pango_dir;
gchar *filename; const gchar *title;
gchar *header_font_desc; const gchar *header_font_desc;
gint lpi; gdouble lpi;
gint cpi; gdouble cpi;
} page_layout_t; } page_layout_t;
typedef struct { typedef struct {
char *text;
int length;
} para_t;
typedef struct {
PangoLayoutLine *pango_line; PangoLayoutLine *pango_line;
PangoRectangle logical_rect; PangoRectangle logical_rect;
PangoRectangle ink_rect; PangoRectangle ink_rect;
int formfeed; int formfeed;
gboolean wrapped; // Whether the paragraph was character wrapped
} LineLink; } LineLink;
typedef struct _Paragraph Paragraph; typedef struct _Paragraph Paragraph;
/* Structure representing a paragraph /* Structure representing a paragraph
*/ */
struct _Paragraph { struct _Paragraph {
char *text; const char *text;
int length; int length;
int height; /* Height, in pixels */ int height; /* Height, in pixels */
int formfeed; int formfeed;
gboolean wrapped;
gboolean clipped; // Whether the line was clipped. Used for CPI.
PangoLayout *layout; PangoLayout *layout;
}; };
/* Information passed in user data when drawing outlines */ /* Information passed in user data when drawing outlines */
GList *split_paragraphs_into_lines (page_layout_t *page_layout, static GList *split_paragraphs_into_lines (page_layout_t *page_layout,
GList *paragraphs); GList *paragraphs);
static char *read_file (FILE *file, static char *read_file (FILE *file,
GIConv handle); gchar *encoding);
static GList *split_text_into_paragraphs (PangoContext *pango_context, static GList *split_text_into_paragraphs (cairo_t *cr,
PangoContext *pango_context,
page_layout_t *page_layout, page_layout_t *page_layout,
int paint_width, int paint_width,
char *text); const char *text);
static int output_pages (FILE *OUT, static int output_pages (cairo_surface_t * surface,
cairo_t *cr,
GList *pango_lines, GList *pango_lines,
page_layout_t *page_layout, page_layout_t *page_layout,
gboolean need_header, gboolean need_header,
PangoContext *pango_context); PangoContext *pango_context);
static void print_postscript_header (FILE *OUT, static void eject_column (cairo_t *cr,
const char *title,
page_layout_t *page_layout);
static void print_postscript_trailer (FILE *OUT,
int num_pages);
static void eject_column (FILE *OUT,
page_layout_t *page_layout, page_layout_t *page_layout,
int column_idx); int column_idx);
static void eject_page (FILE *OUT); static void eject_page (cairo_t *cr);
static void start_page (FILE *OUT, static void start_page (cairo_surface_t *surface,
int page_idx); cairo_t *cr,
static void draw_line_to_page (FILE *OUT, page_layout_t *page_layout);
static void draw_line_to_page (cairo_t *cr,
int column_idx, int column_idx,
int column_pos, int column_pos,
page_layout_t *page_layout, page_layout_t *page_layout,
PangoLayoutLine *line); PangoLayoutLine *line,
static int draw_page_header_line_to_page(FILE *OUT, gboolean draw_wrap_character
);
static int draw_page_header_line_to_page(cairo_t *cr,
gboolean is_footer, gboolean is_footer,
page_layout_t *page_layout, page_layout_t *page_layout,
PangoContext *ctx, PangoContext *ctx,
int page); int page);
static void postscript_dsc_comments (cairo_surface_t *surface,
page_layout_t *page_layout);
// Fonts are three character symbols in an alphabet composing of FILE *output_fh;
// the following characters: static paper_type_t paper_type = PAPER_TYPE_A4;
// static gboolean output_format_set = FALSE;
// First character: a-zA-Z@_.,!-~`'" static output_format_t output_format = FORMAT_POSTSCRIPT;
// Rest of chars: like first + 0-9 static PangoGravity gravity = PANGO_GRAVITY_AUTO;
// static PangoGravityHint gravity_hint = PANGO_GRAVITY_HINT_NATURAL;
// Care is taken that no keywords are overwritten, e.g. def, end. static PangoWrapMode opt_wrap = PANGO_WRAP_WORD_CHAR;
GString *ps_font_def_string = NULL; static cairo_font_face_t *paps_glyph_face = NULL; /* Special face for paps chara
GString *ps_pages_string = NULL; cters, e.g. newline */
int last_char_idx = 0; static double glyph_font_size = -1;
double last_pos_y = -1;
double last_pos_x = -1; /* Render function for paps glyphs */
paps_t *paps; static cairo_status_t
paper_type_t paper_type = PAPER_TYPE_A4; paps_render_glyph(cairo_scaled_font_t *scaled_font G_GNUC_UNUSED,
unsigned long glyph,
cairo_t *cr,
cairo_text_extents_t *extents)
{
char ch = (unsigned char)glyph;
#define CASE(s) if (strcmp(S_, s) == 0) if (ch == 'R' || ch == 'L')
{
// A newline sign that I created with MetaPost
cairo_save(cr);
cairo_scale(cr,0.005,-0.005); // TBD - figure out the scaling.
if (ch == 'L')
{
cairo_scale(cr,-1,1);
// cairo_translate(cr,-120,0); // Keep glyph protruding to the right.
}
cairo_translate(cr, 20,-50);
cairo_move_to(cr, 0, 175);
cairo_curve_to(cr, 25.69278, 175, 53.912, 177.59557, 71.25053, 158.75053);
cairo_curve_to(cr, 103.52599, 123.67075, 64.54437, 77.19373, 34.99985, 34.99
985);
cairo_set_line_width(cr, 25);
cairo_stroke(cr);
cairo_move_to(cr,0,0);
cairo_line_to(cr,75,0);
cairo_line_to(cr,0,75);
cairo_close_path(cr);
cairo_fill(cr);
cairo_restore(cr);
}
return CAIRO_STATUS_SUCCESS;
}
static gboolean static gboolean
_paps_arg_paper_cb(const char *option_name, _paps_arg_paper_cb(const char *option_name,
const char *value, const char *value,
gpointer data) gpointer data)
{ {
gboolean retval = TRUE; gboolean retval = TRUE;
if (value && *value) if (value && *value)
{ {
if (g_ascii_strcasecmp(value, "legal") == 0) if (g_ascii_strcasecmp(value, "legal") == 0)
paper_type = PAPER_TYPE_US_LEGAL; paper_type = PAPER_TYPE_US_LEGAL;
else if (g_ascii_strcasecmp(value, "letter") == 0) else if (g_ascii_strcasecmp(value, "letter") == 0)
paper_type = PAPER_TYPE_US_LETTER; paper_type = PAPER_TYPE_US_LETTER;
else if (g_ascii_strcasecmp(value, "a4") == 0) else if (g_ascii_strcasecmp(value, "a4") == 0)
paper_type = PAPER_TYPE_A4; paper_type = PAPER_TYPE_A4;
else if (g_ascii_strcasecmp(value, "a3") == 0)
paper_type = PAPER_TYPE_A3;
else { else {
retval = FALSE; retval = FALSE;
fprintf(stderr, "Unknown page size name: %s.\n", value); fprintf(stderr, _("Unknown page size name: %s.\n"), value);
} }
} }
else else
{ {
fprintf(stderr, "You must specify page size.\n"); fprintf(stderr, _("You must specify page size.\n"));
retval = FALSE;
}
return retval;
}
static gboolean
parse_enum (GType type,
int *value,
const char *name,
const char *arg,
gpointer data G_GNUC_UNUSED,
GError **error)
{
char *possible_values = NULL;
gboolean ret;
ret = pango_parse_enum (type,
arg,
value,
FALSE,
&possible_values);
if (!ret && error)
{
g_set_error(error,
G_OPTION_ERROR,
G_OPTION_ERROR_BAD_VALUE,
_("Argument for %1$s must be one of %2$s"),
name,
possible_values);
}
g_free (possible_values);
return ret;
}
static gboolean
parse_wrap (const char *name,
const char *arg,
gpointer data,
GError **error)
{
return (parse_enum (PANGO_TYPE_WRAP_MODE, (int*)(void*)&opt_wrap,
name, arg, data, error));
}
static gboolean
parse_gravity_hint (const char *name,
const char *arg,
gpointer data,
GError **error)
{
return (parse_enum (PANGO_TYPE_GRAVITY_HINT, (int*)(void*)&gravity_hint,
name, arg, data, error));
}
static gboolean
parse_gravity (const char *name,
const char *arg,
gpointer data,
GError **error)
{
return (parse_enum (PANGO_TYPE_GRAVITY, (int*)(void*)&gravity,
name, arg, data, error));
}
static gboolean
_paps_arg_format_cb(const char *option_name,
const char *value,
gpointer data)
{
gboolean retval = TRUE;
if (value && *value)
{
output_format_set = TRUE;
if (g_ascii_strcasecmp(value, "pdf") == 0)
output_format = FORMAT_PDF;
else if (g_ascii_strcasecmp(value, "ps") == 0
|| g_ascii_strcasecmp(value, "postscript") == 0)
output_format = FORMAT_POSTSCRIPT;
else if (g_ascii_strcasecmp(value, "svg") == 0)
output_format = FORMAT_SVG;
else {
retval = FALSE;
fprintf(stderr, _("Unknown output format: %s.\n"), value);
}
}
else
{
fprintf(stderr, _("You must specify a output format.\n"));
retval = FALSE; retval = FALSE;
} }
return retval; return retval;
} }
static gboolean static gboolean
_paps_arg_lpi_cb(const gchar *option_name, _paps_arg_lpi_cb(const gchar *option_name,
const gchar *value, const gchar *value,
gpointer data) gpointer data)
{ {
gboolean retval = TRUE; gboolean retval = TRUE;
gchar *p = NULL; gchar *p = NULL;
page_layout_t *page_layout = (page_layout_t*)data; page_layout_t *page_layout = (page_layout_t*)data;
if (value && *value) if (value && *value)
{ {
errno = 0; errno = 0;
page_layout->lpi = g_strtod(value, &p); page_layout->lpi = g_strtod(value, &p);
if ((p && *p) || errno == ERANGE) if ((p && *p) || errno == ERANGE)
{ {
fprintf(stderr, "given LPI value was invalid.\n"); fprintf(stderr, _("Given LPI value was invalid.\n"));
retval = FALSE; retval = FALSE;
} }
} }
else else
{ {
fprintf(stderr, "You must specify the amount of lines per inch.\n"); fprintf(stderr, _("You must specify the amount of lines per inch.\n"));
retval = FALSE; retval = FALSE;
} }
return retval; return retval;
} }
static gboolean static gboolean
_paps_arg_cpi_cb(const gchar *option_name, _paps_arg_cpi_cb(const gchar *option_name,
const gchar *value, const gchar *value,
gpointer data) gpointer data)
{ {
gboolean retval = TRUE; gboolean retval = TRUE;
gchar *p = NULL; gchar *p = NULL;
page_layout_t *page_layout = (page_layout_t*)data; page_layout_t *page_layout = (page_layout_t*)data;
if (value && *value) if (value && *value)
{ {
errno = 0; errno = 0;
page_layout->cpi = g_strtod(value, &p); page_layout->cpi = g_strtod(value, &p);
if ((p && *p) || errno == ERANGE) if ((p && *p) || errno == ERANGE)
{ {
fprintf(stderr, "given CPI value was invalid.\n"); fprintf(stderr, _("Given CPI value was invalid.\n"));
retval = FALSE; retval = FALSE;
} }
} }
else else
{ {
fprintf(stderr, "You must specify the amount of characters per inch.\n"); fprintf(stderr, _("You must specify the amount of characters per inch.\n") );
retval = FALSE; retval = FALSE;
} }
return retval; return retval;
} }
static PangoLanguage * /*
get_language(void) * Return codeset name of the environment's locale. Use UTF8 by default
*/
static char*
get_encoding()
{ {
PangoLanguage *retval; static char *encoding = NULL;
gchar *lang = g_strdup (setlocale (LC_CTYPE, NULL));
gchar *p;
p = strchr (lang, '.');
if (p)
*p = 0;
p = strchr (lang, '@');
if (p)
*p = 0;
retval = pango_language_from_string (lang); if (encoding == NULL)
g_free (lang); encoding = nl_langinfo(CODESET);
return retval; return encoding;
}
static cairo_status_t paps_cairo_write_func(void *closure G_GNUC_UNUSED,
const unsigned char *data,
unsigned int length)
{
fwrite(data,length,1,output_fh);
return CAIRO_STATUS_SUCCESS;
} }
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
gboolean do_landscape = FALSE, do_rtl = FALSE, do_justify = FALSE, do_draw_hea der = FALSE; gboolean do_landscape = FALSE, do_rtl = FALSE, do_justify = FALSE, do_draw_hea der = FALSE, do_draw_footer=FALSE;
gboolean do_stretch_chars = FALSE; gboolean do_stretch_chars = FALSE;
gboolean do_use_markup = FALSE; gboolean do_use_markup = FALSE;
gboolean do_wordwrap = TRUE; // What should be default? gboolean do_show_wrap = FALSE; /* Whether to show wrap characters */
int num_columns = 1; int num_columns = 1;
int top_margin = 36, bottom_margin = 36, right_margin = 36, left_margin = 36; int top_margin = MARGIN_TOP, bottom_margin = MARGIN_BOTTOM,
gchar *font = MAKE_FONT_NAME (DEFAULT_FONT_FAMILY, DEFAULT_FONT_SIZE), *encodi right_margin = MARGIN_RIGHT, left_margin = MARGIN_LEFT;
ng = NULL;
gboolean do_fatal_warnings = FALSE;
const gchar *font = MAKE_FONT_NAME (DEFAULT_FONT_FAMILY, DEFAULT_FONT_SIZE);
gchar *encoding = NULL;
gchar *output = NULL;
gchar *htitle = NULL;
page_layout_t page_layout; page_layout_t page_layout;
GOptionContext *ctxt = g_option_context_new("[text file]"); GOptionContext *ctxt = g_option_context_new("[text file]");
GOptionEntry entries[] = { GOptionEntry entries[] = {
{"landscape", 0, 0, G_OPTION_ARG_NONE, &do_landscape, "Landscape output. (De {"landscape", 0, 0, G_OPTION_ARG_NONE, &do_landscape,
fault: portrait)", NULL}, N_("Landscape output. (Default: portrait)"), NULL},
{"stretch-chars", 0, 0, G_OPTION_ARG_NONE, &do_stretch_chars, "Whether to st {"columns", 0, 0, G_OPTION_ARG_INT, &num_columns,
retch characters in y-direction to fill lines. (Default: no)", NULL}, N_("Number of columns output. (Default: 1)"), "NUM"},
{"markup", 0, 0, G_OPTION_ARG_NONE, &do_use_markup, "Should the text be cons {"font", 0, 0, G_OPTION_ARG_STRING, &font,
idered pango markup? (Default: no)", NULL}, N_("Set font. (Default: Monospace 12)"), "DESC"},
{"columns", 0, 0, G_OPTION_ARG_INT, &num_columns, "Number of columns output. {"output", 'o', 0, G_OPTION_ARG_STRING, &output,
(Default: 1)", "NUM"}, N_("Output file. (Default: stdout)"), "DESC"},
{"font", 0, 0, G_OPTION_ARG_STRING, &font, "Set the font description. (Defau {"rtl", 0, 0, G_OPTION_ARG_NONE, &do_rtl,
lt: Monospace 12)", "DESC"}, N_("Do right-to-left text layout."), NULL},
{"rtl", 0, 0, G_OPTION_ARG_NONE, &do_rtl, "Do rtl layout.", NULL}, {"justify", 0, 0, G_OPTION_ARG_NONE, &do_justify,
N_("Justify the layout."), NULL},
{"wrap", 0, 0, G_OPTION_ARG_CALLBACK, &parse_wrap,
N_("Text wrapping mode [word, char, word-char]. (Default: word-char)"), "WR
AP"},
{"show-wrap", 0, 0, G_OPTION_ARG_NONE, &do_show_wrap,
N_("Show characters for wrapping."), NULL},
{"paper", 0, 0, G_OPTION_ARG_CALLBACK, _paps_arg_paper_cb, {"paper", 0, 0, G_OPTION_ARG_CALLBACK, _paps_arg_paper_cb,
"Choose paper size. Known paper sizes are legal,\n" N_("Set paper size [legal, letter, a3, a4]. (Default: a4)"), "PAPER"},
" letter, a4. (Default: a4)", "PAPER"}, {"gravity", 0, 0, G_OPTION_ARG_CALLBACK, &parse_gravity,
{"bottom-margin", 0, 0, G_OPTION_ARG_INT, &bottom_margin, "Set bottom margin N_("Base glyph rotation [south, west, north, east, auto]. (Defaut: auto)"),
in postscript point units (1/72inch). (Default: 36)", "NUM"}, "GRAVITY"},
{"top-margin", 0, 0, G_OPTION_ARG_INT, &top_margin, "Set top margin. (Defaul {"gravity-hint", 0, 0, G_OPTION_ARG_CALLBACK, &parse_gravity_hint,
t: 36)", "NUM"}, N_("Base glyph orientation [natural, strong, line]. (Default: natural)"), "
{"right-margin", 0, 0, G_OPTION_ARG_INT, &right_margin, "Set right margin. ( HINT"},
Default: 36)", "NUM"}, {"format", 0, 0, G_OPTION_ARG_CALLBACK, _paps_arg_format_cb,
{"left-margin", 0, 0, G_OPTION_ARG_INT, &left_margin, "Set left margin. (Def N_("Set output format [pdf, svg, ps]. (Default: ps)"), "FORMAT"},
ault: 36)", "NUM"}, {"bottom-margin", 0, 0, G_OPTION_ARG_INT, &bottom_margin,
{"header", 0, 0, G_OPTION_ARG_NONE, &do_draw_header, "Draw page header for e N_("Set bottom margin in postscript point units (1/72 inch). (Default: 36)"
ach page.", NULL}, ), "NUM"},
{"encoding", 0, 0, G_OPTION_ARG_STRING, &encoding, "Assume the documentation {"top-margin", 0, 0, G_OPTION_ARG_INT, &top_margin,
encoding.", "ENCODING"}, N_("Set top margin. (Default: 36)"), "NUM"},
{"lpi", 0, 0, G_OPTION_ARG_CALLBACK, _paps_arg_lpi_cb, "Set the amount of li {"right-margin", 0, 0, G_OPTION_ARG_INT, &right_margin,
nes per inch.", "REAL"}, N_("Set right margin. (Default: 36)"), "NUM"},
{"cpi", 0, 0, G_OPTION_ARG_CALLBACK, _paps_arg_cpi_cb, "Set the amount of ch {"left-margin", 0, 0, G_OPTION_ARG_INT, &left_margin,
aracters per inch.", "REAL"}, N_("Set left margin. (Default: 36)"), "NUM"},
{"header", 0, 0, G_OPTION_ARG_NONE, &do_draw_header,
N_("Draw page header for each page."), NULL},
{"footer", 0, 0, G_OPTION_ARG_NONE, &do_draw_footer,
"Draw page footer for each page.", NULL},
{"title", 0, 0, G_OPTION_ARG_STRING, &htitle,
N_("Title string for page header (Default: filename/stdin)."), "TITLE"},
{"markup", 0, 0, G_OPTION_ARG_NONE, &do_use_markup,
N_("Interpret input text as pango markup."), NULL},
{"encoding", 0, 0, G_OPTION_ARG_STRING, &encoding,
N_("Assume encoding of input text. (Default: UTF-8)"), "ENCODING"},
{"lpi", 0, 0, G_OPTION_ARG_CALLBACK, _paps_arg_lpi_cb,
N_("Set the amount of lines per inch."), "REAL"},
{"cpi", 0, 0, G_OPTION_ARG_CALLBACK, _paps_arg_cpi_cb,
N_("Set the amount of characters per inch."), "REAL"},
/*
* not fixed for cairo backend: disable
*
{"stretch-chars", 0, 0, G_OPTION_ARG_NONE, &do_stretch_chars,
N_("Stretch characters in y-direction to fill lines."), NULL},
*/
{"g-fatal-warnings", 0, 0, G_OPTION_ARG_NONE, &do_fatal_warnings,
N_("Make all glib warnings fatal."), "REAL"},
{NULL} {NULL}
}; };
GError *error = NULL; GError *error = NULL;
FILE *IN, *OUT = NULL; FILE *IN = NULL;
GList *paragraphs; GList *paragraphs;
GList *pango_lines; GList *pango_lines;
PangoContext *pango_context; PangoContext *pango_context;
PangoFontDescription *font_description; PangoFontDescription *font_description;
PangoDirection pango_dir = PANGO_DIRECTION_LTR; PangoDirection pango_dir = PANGO_DIRECTION_LTR;
PangoFontMap *fontmap; PangoFontMap *fontmap;
PangoFontset *fontset; PangoFontset *fontset;
PangoFontMetrics *metrics; PangoFontMetrics *metrics;
int num_pages = 1;
int gutter_width = 40; int gutter_width = 40;
int total_gutter_width; int total_gutter_width;
int page_width = paper_sizes[0].width; double page_width = paper_sizes[0].width;
int page_height = paper_sizes[0].height; double page_height = paper_sizes[0].height;
int do_tumble = -1; /* -1 means not initialized */ int do_tumble = -1; /* -1 means not initialized */
int do_duplex = -1; int do_duplex = -1;
gchar *paps_header = NULL; const gchar *header_font_desc = MAKE_FONT_NAME (HEADER_FONT_FAMILY, HEADER_FON
gchar *header_font_desc = MAKE_FONT_NAME (HEADER_FONT_FAMILY, HEADER_FONT_SCAL T_SCALE);
E); const gchar *filename_in;
gchar *filename_in, *title, *text; gchar *text;
int header_sep = 20; int header_sep = 20;
int max_width = 0, w; int max_width = 0, w;
GIConv cvh = NULL;
GOptionGroup *options; GOptionGroup *options;
cairo_t *cr;
/* Prerequisite when using glib. */ cairo_surface_t *surface = NULL;
g_type_init(); double surface_page_width = 0, surface_page_height = 0;
/* Set locale from environment */
(void) setlocale(LC_ALL, "");
/* Setup i18n */
textdomain(GETTEXT_PACKAGE);
bindtextdomain(GETTEXT_PACKAGE, DATADIR "/locale");
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
/* Setup the paps glyph face */
paps_glyph_face = cairo_user_font_face_create();
cairo_user_font_face_set_render_glyph_func(paps_glyph_face, paps_render_glyph)
;
/* Init page_layout_t parameters set by the option parsing */ /* Init page_layout_t parameters set by the option parsing */
page_layout.cpi = page_layout.lpi = 0; page_layout.cpi = page_layout.lpi = 0;
options = g_option_group_new("main","","",&page_layout, NULL); options = g_option_group_new("main","","",&page_layout, NULL);
g_option_group_add_entries(options, entries); g_option_group_add_entries(options, entries);
g_option_group_set_translation_domain(options, GETTEXT_PACKAGE);
g_option_context_set_main_group(ctxt, options); g_option_context_set_main_group(ctxt, options);
#if 0 #if 0
g_option_context_add_main_entries(ctxt, entries, NULL); g_option_context_add_main_entries(ctxt, entries, NULL);
#endif #endif
/* Parse command line */ /* Parse command line */
if (!g_option_context_parse(ctxt, &argc, &argv, &error)) if (!g_option_context_parse(ctxt, &argc, &argv, &error))
{ {
fprintf(stderr, "Command line error: %s\n", error->message); fprintf(stderr, _("Command line error: %s\n"), error->message);
exit(1); exit(1);
} }
if (do_fatal_warnings)
g_log_set_always_fatal(G_LOG_LEVEL_MASK);
if (do_rtl) if (do_rtl)
pango_dir = PANGO_DIRECTION_RTL; pango_dir = PANGO_DIRECTION_RTL;
if (argc > 1) if (argc > 1)
{ {
filename_in = argv[1]; filename_in = argv[1];
IN = fopen(filename_in, "rb"); IN = fopen(filename_in, "r");
if (!IN) if (!IN)
{ {
fprintf(stderr, "Failed to open %s!\n", filename_in); fprintf(stderr, _("Failed to open %s!\n"), filename_in);
exit(-1); exit(1);
} }
} }
else else
{ {
filename_in = "stdin"; filename_in = "stdin";
IN = stdin; IN = stdin;
} }
title = filename_in;
paps = paps_new(); // For now always write to stdout
pango_context = paps_get_pango_context (paps); if (output == NULL)
output_fh = stdout;
else
{
output_fh = fopen(output,"wb");
if (!output_fh)
{
fprintf(stderr, _("Failed to open %s for writing!\n"), output);
exit(1);
}
}
/* Page layout */
page_width = paper_sizes[(int)paper_type].width;
page_height = paper_sizes[(int)paper_type].height;
/* Deduce output format from file name if not explicitely set */
if (!output_format_set && output != NULL)
{
if (g_str_has_suffix(output, ".svg") || g_str_has_suffix(output, ".SVG"))
output_format = FORMAT_SVG;
else if (g_str_has_suffix(output, ".pdf") || g_str_has_suffix(output, ".PD
F"))
output_format = FORMAT_PDF;
/* Otherwise keep postscript default */
}
/* Swap width and height for landscape except for postscript */
surface_page_width = page_width;
surface_page_height = page_height;
if (output_format != FORMAT_POSTSCRIPT && do_landscape)
{
surface_page_width = page_height;
surface_page_height = page_width;
}
if (output_format == FORMAT_POSTSCRIPT)
surface = cairo_ps_surface_create_for_stream(&paps_cairo_write_func,
NULL,
surface_page_width,
surface_page_height);
else if (output_format == FORMAT_PDF)
surface = cairo_pdf_surface_create_for_stream(&paps_cairo_write_func,
NULL,
surface_page_width,
surface_page_height);
else
surface = cairo_svg_surface_create_for_stream(&paps_cairo_write_func,
NULL,
surface_page_width,
surface_page_height);
cr = cairo_create(surface);
pango_context = pango_cairo_create_context(cr);
pango_cairo_context_set_resolution(pango_context, 72.0); /* Native postscript
resolution */
/* Setup pango */ /* Setup pango */
pango_context_set_language (pango_context, get_language ());
pango_context_set_base_dir (pango_context, pango_dir); pango_context_set_base_dir (pango_context, pango_dir);
pango_context_set_language (pango_context, pango_language_get_default ());
pango_context_set_base_gravity (pango_context, gravity);
pango_context_set_gravity_hint (pango_context, gravity_hint);
/* create the font description */ /* create the font description */
font_description = pango_font_description_from_string (font); font_description = pango_font_description_from_string (font);
if ((pango_font_description_get_set_fields (font_description) & PANGO_FONT_MAS K_FAMILY) == 0) if ((pango_font_description_get_set_fields (font_description) & PANGO_FONT_MAS K_FAMILY) == 0)
pango_font_description_set_family (font_description, DEFAULT_FONT_FAMILY); pango_font_description_set_family (font_description, DEFAULT_FONT_FAMILY);
if ((pango_font_description_get_set_fields (font_description) & PANGO_FONT_MAS K_SIZE) == 0) if ((pango_font_description_get_set_fields (font_description) & PANGO_FONT_MAS K_SIZE) == 0)
pango_font_description_set_size (font_description, atoi(DEFAULT_FONT_SIZE) * PANGO_SCALE); pango_font_description_set_size (font_description, atoi(DEFAULT_FONT_SIZE) * PANGO_SCALE);
// Keep the font size for the wrap character.
glyph_font_size = pango_font_description_get_size(font_description) / PANGO_SC
ALE;
pango_context_set_font_description (pango_context, font_description); pango_context_set_font_description (pango_context, font_description);
/* Page layout */ if (num_columns <= 0) {
page_width = paper_sizes[(int)paper_type].width; fprintf(stderr, _("%s: Invalid input: --columns=%d, using default.\n"), g_ge
page_height = paper_sizes[(int)paper_type].height; t_prgname (), num_columns);
num_columns = 1;
}
if (num_columns == 1) if (num_columns == 1)
total_gutter_width = 0; total_gutter_width = 0;
else else
total_gutter_width = gutter_width * (num_columns - 1); total_gutter_width = gutter_width * (num_columns - 1);
if (do_landscape) if (do_landscape)
{ {
int tmp; double tmp;
tmp = page_width; tmp = page_width;
page_width = page_height; page_width = page_height;
page_height = tmp; page_height = tmp;
if (do_tumble < 0) if (do_tumble < 0)
do_tumble = TRUE; do_tumble = TRUE;
if (do_duplex < 0) if (do_duplex < 0)
do_duplex = TRUE; do_duplex = TRUE;
} }
else else
{ {
skipping to change at line 427 skipping to change at line 709
page_layout.page_height = page_height; page_layout.page_height = page_height;
page_layout.num_columns = num_columns; page_layout.num_columns = num_columns;
page_layout.left_margin = left_margin; page_layout.left_margin = left_margin;
page_layout.right_margin = right_margin; page_layout.right_margin = right_margin;
page_layout.gutter_width = gutter_width; page_layout.gutter_width = gutter_width;
page_layout.top_margin = top_margin; page_layout.top_margin = top_margin;
page_layout.bottom_margin = bottom_margin; page_layout.bottom_margin = bottom_margin;
page_layout.header_ypos = page_layout.top_margin; page_layout.header_ypos = page_layout.top_margin;
page_layout.header_height = 0; page_layout.header_height = 0;
page_layout.footer_height = 0; page_layout.footer_height = 0;
page_layout.do_wordwrap = do_wordwrap; page_layout.do_show_wrap = do_show_wrap;
page_layout.scale_x = 1.0L; page_layout.scale_x = 1.0L;
page_layout.scale_y = 1.0L; page_layout.scale_y = 1.0L;
if (do_draw_header) if (do_draw_header)
page_layout.header_sep = header_sep; page_layout.header_sep = 0; // header_sep;
else else
page_layout.header_sep = 0; page_layout.header_sep = 0;
page_layout.column_height = page_height page_layout.column_height = (int)page_height
- page_layout.top_margin - page_layout.top_margin
- page_layout.header_sep - page_layout.header_sep
- page_layout.bottom_margin; - page_layout.bottom_margin;
page_layout.column_width = (page_layout.page_width page_layout.column_width = ((int)page_layout.page_width
- page_layout.left_margin - page_layout.right_margin - page_layout.left_margin - page_layout.right_margin
- total_gutter_width) / page_layout.num_columns; - total_gutter_width) / page_layout.num_columns;
page_layout.pt_to_pixel = paps_postscript_points_to_pango(1)/PANGO_SCALE;
page_layout.pixel_to_pt = 1.0/page_layout.pt_to_pixel;
page_layout.do_separation_line = TRUE; page_layout.do_separation_line = TRUE;
page_layout.do_landscape = do_landscape; page_layout.do_landscape = do_landscape;
page_layout.do_justify = do_justify; page_layout.do_justify = do_justify;
page_layout.do_stretch_chars = do_stretch_chars; page_layout.do_stretch_chars = do_stretch_chars;
page_layout.do_use_markup = do_use_markup; page_layout.do_use_markup = do_use_markup;
page_layout.do_tumble = do_tumble; page_layout.do_tumble = do_tumble;
page_layout.do_duplex = do_duplex; page_layout.do_duplex = do_duplex;
page_layout.pango_dir = pango_dir; page_layout.pango_dir = pango_dir;
page_layout.filename = filename_in; if (htitle)
page_layout.title = htitle;
else
page_layout.title = basename((char *)filename_in);
page_layout.header_font_desc = header_font_desc; page_layout.header_font_desc = header_font_desc;
/* calculate x-coordinate scale */ /* calculate x-coordinate scale */
if (page_layout.cpi > 0.0L) if (page_layout.cpi > 0.0L)
{ {
double scale; gint font_size;
fontmap = pango_ft2_font_map_new (); fontmap = pango_ft2_font_map_new ();
fontset = pango_font_map_load_fontset (fontmap, pango_context, font_descri ption, get_language ()); fontset = pango_font_map_load_fontset (fontmap, pango_context, font_descri ption, pango_language_get_default());
metrics = pango_fontset_get_metrics (fontset); metrics = pango_fontset_get_metrics (fontset);
max_width = pango_font_metrics_get_approximate_char_width (metrics); max_width = pango_font_metrics_get_approximate_char_width (metrics);
w = pango_font_metrics_get_approximate_digit_width (metrics); w = pango_font_metrics_get_approximate_digit_width (metrics);
if (w > max_width) if (w > max_width)
max_width = w; 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); pango_font_metrics_unref (metrics);
g_object_unref (G_OBJECT (fontmap)); g_object_unref (G_OBJECT (fontmap));
// Now figure out how to scale the font to get that size font_size = pango_font_description_get_size (font_description);
scale = 1 / page_layout.cpi * 72.0 * PANGO_SCALE / max_width;
// update the font size to that width // update the font size to that width
pango_font_description_set_size (font_description, (int)(atoi(DEFAULT_FONT pango_font_description_set_size (font_description, (int)(font_size * page_
_SIZE) * PANGO_SCALE * scale)); layout.scale_x));
glyph_font_size = font_size * page_layout.scale_x / PANGO_SCALE;
pango_context_set_font_description (pango_context, font_description); pango_context_set_font_description (pango_context, font_description);
} }
page_layout.scale_x = page_layout.scale_y = 1.0; page_layout.scale_x = page_layout.scale_y = 1.0;
if (encoding != NULL) if (encoding == NULL)
{ encoding = get_encoding();
cvh = g_iconv_open ("UTF-8", encoding);
if (cvh == NULL)
{
fprintf(stderr, "%s: Invalid encoding: %s\n", g_get_prgname (), encodi
ng);
exit(-1);
}
}
text = read_file(IN, cvh); text = read_file(IN, encoding);
if (encoding != NULL && cvh != NULL) if (output_format == FORMAT_POSTSCRIPT)
g_iconv_close(cvh); postscript_dsc_comments(surface, &page_layout);
paragraphs = split_text_into_paragraphs(pango_context, paragraphs = split_text_into_paragraphs(cr,
pango_context,
&page_layout, &page_layout,
page_layout.column_width * page_layout .pt_to_pixel, page_layout.column_width,
text); text);
pango_lines = split_paragraphs_into_lines(&page_layout, paragraphs); pango_lines = split_paragraphs_into_lines(&page_layout, paragraphs);
if (OUT == NULL) cairo_scale(cr, page_layout.scale_x, page_layout.scale_y);
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("");
num_pages = output_pages(OUT, pango_lines, &page_layout, do_draw_header, pango
_context);
paps_header = paps_get_postscript_header_strdup(paps);
fprintf(OUT, "%s", paps_header);
g_free(paps_header);
fprintf(OUT, "%%%%EndPrologue\n"); output_pages(surface, cr, pango_lines, &page_layout, do_draw_header, pango_con
fprintf(OUT, "%s", ps_pages_string->str); text);
print_postscript_trailer(OUT, num_pages);
// Cleanup cairo_destroy (cr);
g_string_free(ps_pages_string, TRUE); cairo_surface_finish (surface);
cairo_surface_destroy(surface);
g_option_context_free(ctxt); g_option_context_free(ctxt);
return 0; return 0;
} }
/* Read an entire file into a string /* Read an entire file into a string
*/ */
static char * static char *
read_file (FILE *file, read_file (FILE *file,
GIConv handle) gchar *encoding)
{ {
GString *inbuf; GString *inbuf;
char *text; char *text;
char buffer[BUFSIZE]; char buffer[BUFSIZE];
GIConv cvh = NULL;
gsize inc_seq_bytes = 0;
if (encoding != NULL)
{
cvh = g_iconv_open ("UTF-8", encoding);
if (cvh == (GIConv)-1)
{
fprintf(stderr, _("%s: Invalid encoding: %s\n"), g_get_prgname (), enc
oding);
exit(1);
}
}
inbuf = g_string_new (NULL); inbuf = g_string_new (NULL);
while (1) while (1)
{ {
char *ib, *ob, obuffer[BUFSIZE * 6], *bp = fgets (buffer, BUFSIZE-1, file) char *ib, *ob, obuffer[BUFSIZE * 6], *bp;
; gsize iblen, ibleft, oblen;
gsize iblen, oblen;
bp = fgets (buffer+inc_seq_bytes, BUFSIZE-inc_seq_bytes-1, file);
if (inc_seq_bytes)
inc_seq_bytes = 0;
if (ferror (file)) if (ferror (file))
{ {
fprintf(stderr, "%s: Error reading file.\n", g_get_prgname ()); fprintf(stderr, _("%s: Error reading file.\n"), g_get_prgname ());
g_string_free (inbuf, TRUE); g_string_free (inbuf, TRUE);
return NULL; exit(1);
} }
else if (bp == NULL) else if (bp == NULL)
break; break;
if (handle != NULL) if (cvh != NULL)
{ {
ib = bp; ib = buffer;
iblen = strlen (ib); iblen = strlen (ib);
ob = bp = obuffer; ob = bp = obuffer;
oblen = BUFSIZE * 6 - 1; oblen = BUFSIZE * 6 - 1;
if (g_iconv (handle, &ib, &iblen, &ob, &oblen) == -1) if (g_iconv (cvh, &ib, &iblen, &ob, &oblen) == (gsize)-1)
{ {
fprintf (stderr, "%s: Error while converting strings.\n", g_get_pr /*
gname ()); * EINVAL - incomplete sequence at the end of the buffer. Move the
return NULL; * incomplete sequence bytes to the beginning of the buffer for
} * the next round of conversion.
*/
if (errno == EINVAL)
{
inc_seq_bytes = iblen;
memmove (buffer, ib, inc_seq_bytes);
}
else
{
fprintf (stderr, _("%1$s: Error while converting input from '%
2$s' to UTF-8.\n"),
g_get_prgname(), encoding);
exit(1);
}
}
obuffer[BUFSIZE * 6 - 1 - oblen] = 0; obuffer[BUFSIZE * 6 - 1 - oblen] = 0;
} }
g_string_append (inbuf, bp); g_string_append (inbuf, bp);
} }
fclose (file); fclose (file);
/* Add a trailing new line if it is missing */ /* Add a trailing new line if it is missing */
if (inbuf->str[inbuf->len-1] != '\n') if (inbuf->len && inbuf->str[inbuf->len-1] != '\n')
g_string_append(inbuf, "\n"); g_string_append(inbuf, "\n");
text = inbuf->str; text = inbuf->str;
g_string_free (inbuf, FALSE); g_string_free (inbuf, FALSE);
return text; if (encoding != NULL && cvh != NULL)
} g_iconv_close(cvh);
#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");
return NULL;
}
len = g_utf8_strlen (para->text, para->length);
/* the amount of characters to be able to put on the line against C
PI */
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_rec
t);
/* 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); return text;
} }
#endif
/* Take a UTF8 string and break it into paragraphs on \n characters /* Take a UTF8 string and break it into paragraphs on \n characters
*/ */
static GList * static GList *
split_text_into_paragraphs (PangoContext *pango_context, split_text_into_paragraphs (cairo_t *cr,
PangoContext *pango_context,
page_layout_t *page_layout, page_layout_t *page_layout,
int paint_width, /* In pixels */ int paint_width, /* In pixels */
char *text) const char *text)
{ {
char *p = text; const char *p = text;
char *next; char *next;
gunichar wc; gunichar wc;
GList *result = NULL; GList *result = NULL;
char *last_para = text; const char *last_para = text;
/* If we are using markup we treat the entire text as a single paragraph. /* If we are using markup we treat the entire text as a single paragraph.
* I tested it and found that this is much slower than the split and * I tested it and found that this is much slower than the split and
* assign method used below. Otherwise we might as well use this single * assign method used below. Otherwise we might as well use this single
* chunk method always. * chunk method always.
*/ */
if (page_layout->do_use_markup) if (page_layout->do_use_markup)
{ {
Paragraph *para = g_new (Paragraph, 1); Paragraph *para = g_new (Paragraph, 1);
para->wrapped = FALSE; /* No wrapped chars for markups */
para->clipped = FALSE;
para->text = text; para->text = text;
para->length = strlen(text); para->length = strlen(text);
para->layout = pango_layout_new (pango_context); para->layout = pango_layout_new (pango_context);
// pango_layout_set_font_description (para->layout, font_descript ion);
pango_layout_set_markup (para->layout, para->text, para->length); pango_layout_set_markup (para->layout, para->text, para->length);
pango_layout_set_justify (para->layout, page_layout->do_justify); pango_layout_set_justify (para->layout, page_layout->do_justify);
pango_layout_set_alignment (para->layout, pango_layout_set_alignment (para->layout,
page_layout->pango_dir == PANGO_DIRECTION_LTR page_layout->pango_dir == PANGO_DIRECTION_LTR
? PANGO_ALIGN_LEFT : PANGO_ALIGN_RIGHT); ? PANGO_ALIGN_LEFT : PANGO_ALIGN_RIGHT);
pango_layout_set_wrap (para->layout, PANGO_WRAP_WORD_CHAR);
pango_layout_set_width (para->layout, paint_width * PANGO_SCALE); pango_layout_set_width (para->layout, paint_width * PANGO_SCALE);
pango_layout_set_wrap (para->layout, opt_wrap);
para->height = 0; para->height = 0;
result = g_list_prepend (result, para); result = g_list_prepend (result, para);
} }
else else
{ {
while (p != NULL && *p) while (p != NULL && *p)
{ {
wc = g_utf8_get_char (p); wc = g_utf8_get_char (p);
next = g_utf8_next_char (p); next = g_utf8_next_char (p);
if (wc == (gunichar)-1) if (wc == (gunichar)-1)
{ {
fprintf (stderr, "%s: Invalid character in input\n", g_get_prgname ()); fprintf (stderr, _("%s: Invalid character in input\n"), g_get_prgn ame ());
wc = 0; wc = 0;
} }
if (!*p || !wc || wc == '\n' || wc == '\f') if (!*p || !wc || wc == '\r' || wc == '\n' || wc == '\f')
{ {
Paragraph *para = g_new (Paragraph, 1); Paragraph *para = g_new (Paragraph, 1);
para->wrapped = FALSE;
para->clipped = FALSE;
para->text = last_para; para->text = last_para;
para->length = p - last_para; para->length = p - last_para;
/* handle dos line breaks */
if (wc == '\r' && *next == '\n')
next = g_utf8_next_char(next);
para->layout = pango_layout_new (pango_context); para->layout = pango_layout_new (pango_context);
// pango_layout_set_font_description (para->layout, font_ if (page_layout->cpi > 0.0L)
description); {
pango_layout_set_text (para->layout, para->text, para->length); /* figuring out the correct width from the pango_font_metrics_
get_approximate_width()
* is really hard and pango_layout_set_wrap() doesn't work pro
perly then.
* Those are not reliable to render the characters exactly acc
ording 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, N
ULL, 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);
exit (1);
}
len = g_utf8_strlen (para->text, para->length);
/* the amount of characters that can be put on the line agains
t CPI */
col = (int)(page_layout->column_width / 72.0 * page_layout->cp
i);
if (len > col)
{
/* need to wrap them up */
wnewtext = g_new (wchar_t, wcslen (wtext) + 1);
para->clipped = TRUE;
if (wnewtext == NULL)
{
fprintf (stderr, _("%s: Unable to allocate the memory.
\n"), g_get_prgname ());
goto fail;
}
for (i = 0; i < len; i++)
{
gssize w = wcwidth (wtext[i]);
if (w >= 0)
wwidth += w;
if (wwidth > col)
break;
wnewtext[i] = wtext[i];
}
wnewtext[i] = 0L;
newtext = g_ucs4_to_utf8 ((const gunichar *)wnewtext, i, N
ULL, 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, &logica
l_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_get_char (g_utf8_prev_char (next));
}
else
{
pango_layout_set_text (para->layout, para->text, para->len
gth);
}
g_free (wtext);
pango_layout_set_width (para->layout, -1);
}
else
{
pango_layout_set_text (para->layout, para->text, para->length)
;
pango_layout_set_width (para->layout, paint_width * PANGO_SCAL
E);
pango_layout_set_wrap (para->layout, opt_wrap);
if (opt_wrap == PANGO_WRAP_CHAR)
para->wrapped = TRUE;
/* Should we support truncation as well? */
}
pango_layout_set_justify (para->layout, page_layout->do_justify); pango_layout_set_justify (para->layout, page_layout->do_justify);
pango_layout_set_alignment (para->layout, pango_layout_set_alignment (para->layout,
page_layout->pango_dir == PANGO_DIRECT ION_LTR page_layout->pango_dir == PANGO_DIRECT ION_LTR
? PANGO_ALIGN_LEFT : PANGO_ALIGN_RIGHT ); ? PANGO_ALIGN_LEFT : PANGO_ALIGN_RIGHT );
pango_layout_set_wrap (para->layout, PANGO_WRAP_WORD_CHAR);
pango_layout_set_width (para->layout, paint_width * PANGO_SCALE);
para->height = 0; para->height = 0;
last_para = next; last_para = next;
if (wc == '\f') if (wc == '\f')
para->formfeed = 1; para->formfeed = 1;
else else
para->formfeed = 0; para->formfeed = 0;
result = g_list_prepend (result, para); result = g_list_prepend (result, para);
skipping to change at line 781 skipping to change at line 1054
} }
} }
return g_list_reverse (result); return g_list_reverse (result);
} }
/* Split a list of paragraphs into a list of lines. /* Split a list of paragraphs into a list of lines.
*/ */
GList * GList *
split_paragraphs_into_lines(page_layout_t *page_layout, split_paragraphs_into_lines(page_layout_t *page_layout,
GList *paragraphs) GList *paragraphs)
{ {
GList *line_list = NULL; GList *line_list = NULL;
int max_height = 0; int max_height = 0;
/* Read the file */ /* Read the file */
/* Now split all the pagraphs into lines */ /* Now split all the pagraphs into lines */
GList *par_list; GList *par_list;
par_list = paragraphs; par_list = paragraphs;
while(par_list) while(par_list)
skipping to change at line 805 skipping to change at line 1078
Paragraph *para = par_list->data; Paragraph *para = par_list->data;
para_num_lines = pango_layout_get_line_count(para->layout); para_num_lines = pango_layout_get_line_count(para->layout);
for (i=0; i<para_num_lines; i++) for (i=0; i<para_num_lines; i++)
{ {
PangoRectangle logical_rect, ink_rect; PangoRectangle logical_rect, ink_rect;
line_link = g_new(LineLink, 1); line_link = g_new(LineLink, 1);
line_link->formfeed = 0; line_link->formfeed = 0;
line_link->wrapped = (para->wrapped && i < para_num_lines - 1) || (par a->clipped);
line_link->pango_line = pango_layout_get_line(para->layout, i); line_link->pango_line = pango_layout_get_line(para->layout, i);
pango_layout_line_get_extents(line_link->pango_line, pango_layout_line_get_extents(line_link->pango_line,
&ink_rect, &logical_rect); &ink_rect, &logical_rect);
line_link->logical_rect = logical_rect; line_link->logical_rect = logical_rect;
if (para->formfeed && i == (para_num_lines - 1)) if (para->formfeed && i == (para_num_lines - 1))
line_link->formfeed = 1; line_link->formfeed = 1;
line_link->ink_rect = ink_rect; line_link->ink_rect = ink_rect;
line_list = g_list_prepend(line_list, line_link); line_list = g_list_prepend(line_list, line_link);
if (logical_rect.height > max_height) if (logical_rect.height > max_height)
max_height = logical_rect.height; max_height = logical_rect.height;
} }
par_list = par_list->next; par_list = par_list->next;
} }
/*
* not fixed for cairo backend: disable
*
if (page_layout->do_stretch_chars && page_layout->lpi > 0.0L) if (page_layout->do_stretch_chars && page_layout->lpi > 0.0L)
page_layout->scale_y = 1.0 / page_layout->lpi * 72.0 * page_layout->pt_to_ page_layout->scale_y = 1.0 / page_layout->lpi * 72.0 * PANGO_SCALE / max_h
pixel * PANGO_SCALE / max_height; eight;
*/
return g_list_reverse(line_list); return g_list_reverse(line_list);
} }
/*
* Define PostScript document header information.
*/
void
postscript_dsc_comments(cairo_surface_t *surface, page_layout_t *pl)
{
char buf[CAIRO_COMMENT_MAX];
int x, y;
/*
* Title
*/
snprintf(buf, CAIRO_COMMENT_MAX, "%%%%Title: %s", pl->title);
cairo_ps_surface_dsc_comment (surface, buf);
/*
* Orientation
*/
if (pl->do_landscape)
{
cairo_ps_surface_dsc_comment (surface, "%%Orientation: Landscape");
x = (int)pl->page_height;
y = (int)pl->page_width;
}
else
{
cairo_ps_surface_dsc_comment (surface, "%%Orientation: Portrait");
x = (int)pl->page_width;
y = (int)pl->page_height;
}
/*
* Redefine BoundingBox to cover the whole paper. Cairo creates the entry
* based on the text only. This may affect further processing, such as with
* convert(1).
*/
snprintf(buf, CAIRO_COMMENT_MAX, "%%%%BoundingBox: 0 0 %d %d", x, y);
cairo_ps_surface_dsc_comment (surface, buf);
/*
* Duplex
*/
if (pl->do_duplex)
{
cairo_ps_surface_dsc_comment(surface, "%%Requirements: duplex");
cairo_ps_surface_dsc_begin_setup(surface);
if (pl->do_tumble)
cairo_ps_surface_dsc_comment(surface, "%%IncludeFeature: *Duplex DuplexT
umble");
else
cairo_ps_surface_dsc_comment(surface, "%%IncludeFeature: *Duplex DuplexN
oTumble");
}
}
int int
output_pages(FILE *OUT, output_pages(cairo_surface_t *surface,
cairo_t *cr,
GList *pango_lines, GList *pango_lines,
page_layout_t *page_layout, page_layout_t *page_layout,
gboolean need_header, gboolean need_header,
PangoContext *pango_context) PangoContext *pango_context)
{ {
int column_idx = 0; int column_idx = 0;
int column_y_pos = 0; int column_y_pos = 0;
int page_idx = 1; int page_idx = 1;
int pango_column_height = page_layout->column_height * page_layout->pt_to_pixe int pango_column_height = page_layout->column_height * PANGO_SCALE;
l * PANGO_SCALE; int height = 0;
LineLink *prev_line_link = NULL; LineLink *prev_line_link = NULL;
start_page(OUT, page_idx); start_page(surface, cr, page_layout);
if (need_header) if (need_header)
draw_page_header_line_to_page(OUT, FALSE, page_layout, pango_context, page_i dx); draw_page_header_line_to_page(cr, TRUE, page_layout, pango_context, page_idx );
while(pango_lines) while(pango_lines)
{ {
LineLink *line_link = pango_lines->data; LineLink *line_link = pango_lines->data;
PangoLayoutLine *line = line_link->pango_line; PangoLayoutLine *line = line_link->pango_line;
gboolean draw_wrap_character = page_layout->do_show_wrap && line_link->wra pped;
/* Check if we need to move to next column */ /* Check if we need to move to next column */
if ((column_y_pos + line_link->logical_rect.height if ((column_y_pos + line_link->logical_rect.height
>= pango_column_height) || >= pango_column_height) ||
(prev_line_link && prev_line_link->formfeed)) (prev_line_link && prev_line_link->formfeed))
{ {
column_idx++; column_idx++;
column_y_pos = 0; column_y_pos = 0;
if (column_idx == page_layout->num_columns) if (column_idx == page_layout->num_columns)
{ {
column_idx = 0; column_idx = 0;
eject_page(OUT); eject_page(cr);
page_idx++; page_idx++;
start_page(OUT, page_idx); start_page(surface, cr, page_layout);
if (need_header) if (need_header)
draw_page_header_line_to_page(OUT, FALSE, page_layout, pango_con text, page_idx); draw_page_header_line_to_page(cr, TRUE, page_layout, pango_conte xt, page_idx);
} }
else else
{ {
eject_column(OUT, eject_column(cr,
page_layout, page_layout,
column_idx column_idx
); );
} }
} }
draw_line_to_page(OUT,
column_idx,
column_y_pos+line_link->logical_rect.height,
page_layout,
line);
if (page_layout->lpi > 0.0L) if (page_layout->lpi > 0.0L)
column_y_pos += (int)(1.0 / page_layout->lpi * 72.0 * page_layout->pt_to _pixel * PANGO_SCALE); height = (int)(1.0 / page_layout->lpi * 72.0 * PANGO_SCALE);
else else
column_y_pos += line_link->logical_rect.height; height = line_link->logical_rect.height;
draw_line_to_page(cr,
column_idx,
column_y_pos+height,
page_layout,
line,
draw_wrap_character);
column_y_pos += height;
pango_lines = pango_lines->next; pango_lines = pango_lines->next;
prev_line_link = line_link; prev_line_link = line_link;
} }
eject_page(OUT); eject_page(cr);
return page_idx; return page_idx;
} }
void print_postscript_header(FILE *OUT, void eject_column(cairo_t *cr,
const char *title,
page_layout_t *page_layout)
{
const char *bool_name[2] = { "false", "true" };
const char *orientation_names[2] = { "Portrait", "Landscape" };
int bodytop = page_layout->header_ypos + page_layout->header_sep;
int orientation = page_layout->page_width > page_layout->page_height;
int bb_page_width = page_layout->page_width;
int bb_page_height = page_layout->page_height;
/* Keep bounding box non-rotated to make ggv happy */
if (orientation)
{
int tmp = bb_page_width;
bb_page_width = bb_page_height;
bb_page_height = tmp;
}
fprintf(OUT,
"%%!PS-Adobe-3.0\n"
"%%%%Title: %s\n"
"%%%%Creator: paps version 0.6.7 by Dov Grobgeld\n"
"%%%%Pages: (atend)\n"
"%%%%BoundingBox: 0 0 %d %d\n"
"%%%%BeginProlog\n"
"%%%%Orientation: %s\n"
"/papsdict 1 dict def\n"
"papsdict begin\n"
"\n"
"/inch {72 mul} bind def\n"
"/mm {1 inch 25.4 div mul} bind def\n"
"\n"
"%% override setpagedevice if it is not defined\n"
"/setpagedevice where {\n"
" pop %% get rid of its dictionary\n"
" /setpagesize { \n"
" 3 dict begin\n"
" /pageheight exch def \n"
" /pagewidth exch def\n"
" /orientation 0 def\n"
" %% Exchange pagewidth and pageheight so that pagewidth is bi
gger\n"
" pagewidth pageheight gt { \n"
" pagewidth\n"
" /pagewidth pageheight def\n"
" /pageheight exch def\n"
" /orientation 3 def\n"
" } if\n"
" 2 dict\n"
" dup /PageSize [pagewidth pageheight] put\n"
" dup /Orientation orientation put\n"
" setpagedevice \n"
" end\n"
" } def\n"
"}\n"
"{\n"
" /setpagesize { pop pop } def\n"
"} ifelse\n"
"/duplex {\n"
" statusdict /setduplexmode known \n"
" { statusdict begin setduplexmode end } {pop} ifelse\n"
"} def\n"
"/tumble {\n"
" statusdict /settumble known\n"
" { statusdict begin settumble end } {pop} ifelse\n"
"} def\n"
"%% Turn the page around\n"
"/turnpage {\n"
" 90 rotate\n"
" 0 pageheight neg translate\n"
"} def\n",
title,
bb_page_width,
bb_page_height,
orientation_names[orientation]
);
fprintf(OUT,
"%% User settings\n"
"/pagewidth %d def\n"
"/pageheight %d def\n"
"pagewidth pageheight setpagesize\n"
"/column_width %d def\n"
"/bodyheight %d def\n"
"/lmarg %d def\n"
"/ytop %d def\n"
"/do_separation_line %s def\n"
"/do_landscape %s def\n"
"/do_tumble %s def\n"
"/do_duplex %s def\n",
page_layout->page_width,
page_layout->page_height,
page_layout->column_width,
page_layout->column_height,
page_layout->left_margin,
page_layout->page_height - bodytop,
bool_name[page_layout->do_separation_line>0],
bool_name[page_layout->do_landscape>0],
bool_name[page_layout->do_tumble>0],
bool_name[page_layout->do_duplex>0]
);
fprintf(OUT,
"%% Procedures to translate position to first and second column\n"
"/lw 20 def %% whatever\n"
"/setnumcolumns {\n"
" /numcolumns exch def\n"
" /firstcolumn { /xpos lmarg def /ypos ytop def} def\n"
" /nextcolumn { \n"
" do_separation_line {\n"
" xpos column_width add gutter_width 2 div add %% x start\n"
" ytop lw add moveto %% y start\n"
" 0 bodyheight lw add neg rlineto 0 setlinewidth stroke\n"
" } if\n"
" /xpos xpos column_width add gutter_width add def \n"
" /ypos ytop def\n"
" } def\n"
"} def\n"
"\n"
);
fprintf(OUT,
"%d setnumcolumns\n",
page_layout->num_columns);
fprintf(OUT,
"/showline {\n"
" /y exch def\n"
" /s exch def\n"
" xpos y moveto \n"
" column_width 0 rlineto stroke\n"
" xpos y moveto /Helvetica findfont 20 scalefont setfont s show\n"
"} def\n"
);
// The following definitions polute the global namespace. All such
// definitions should start with paps_
fprintf(OUT,
"/paps_bop { %% Beginning of page definitions\n"
" papsdict begin\n"
" gsave\n"
" do_landscape {turnpage} if \n"
" %% ps2pdf gets wrong orientation without this!\n"
" /Helvetica findfont setfont 100 100 moveto ( ) show\n"
" firstcolumn\n"
" end\n"
"} def\n"
"\n"
"/paps_eop { %% End of page cleanups\n"
" grestore \n"
"} def\n");
}
void print_postscript_trailer(FILE *OUT,
int num_pages)
{
fprintf(OUT,
"%%%%Pages: %d\n"
"%%%%Trailer\n"
"%%%%EOF\n",
num_pages
);
}
void eject_column(FILE *OUT,
page_layout_t *page_layout, page_layout_t *page_layout,
int column_idx) int column_idx)
{ {
double x_pos, y_top, y_bot, total_gutter; double x_pos, y_top, y_bot, total_gutter;
#if 0 #if 0
fprintf(stderr, "do_separation_line column_idx = %d %d\n", page_layout->do_sep aration_line, column_idx); fprintf(stderr, "do_separation_line column_idx = %d %d\n", page_layout->do_sep aration_line, column_idx);
#endif #endif
if (!page_layout->do_separation_line) if (!page_layout->do_separation_line)
return; return;
skipping to change at line 1084 skipping to change at line 1252
if (column_idx == 1) if (column_idx == 1)
total_gutter = 1.0 * page_layout->gutter_width /2; total_gutter = 1.0 * page_layout->gutter_width /2;
else else
total_gutter = (column_idx - 0.5) * page_layout->gutter_width; total_gutter = (column_idx - 0.5) * page_layout->gutter_width;
x_pos = page_layout->left_margin x_pos = page_layout->left_margin
+ page_layout->column_width * column_idx + page_layout->column_width * column_idx
+ total_gutter; + total_gutter;
y_top = page_layout->page_height - page_layout->top_margin - page_layout->head y_top = page_layout->top_margin + page_layout->header_height + page_layout->he
er_height - page_layout->header_sep / 2; ader_sep / 2;
y_bot = page_layout->bottom_margin - page_layout->footer_height; y_bot = page_layout->page_height - page_layout->bottom_margin - page_layout->f
ooter_height;
g_string_append_printf(ps_pages_string, cairo_move_to(cr,x_pos, y_top);
"%f %f moveto %f %f lineto 0 setlinewidth stroke\n", cairo_line_to(cr,x_pos, y_bot);
x_pos, y_top, cairo_set_line_width(cr, 0.1);
x_pos, y_bot); cairo_stroke(cr);
} }
void eject_page(FILE *OUT) void eject_page(cairo_t *cr)
{ {
g_string_append_printf(ps_pages_string, cairo_show_page(cr);
"paps_eop\n"
"showpage\n");
} }
void start_page(FILE *OUT, void start_page(cairo_surface_t *surface,
int page_idx) cairo_t *cr,
page_layout_t *page_layout)
{ {
g_string_append_printf(ps_pages_string, cairo_identity_matrix(cr);
"%%%%Page: %d %d\n"
"paps_bop\n", if (output_format == FORMAT_POSTSCRIPT)
page_idx, page_idx); cairo_ps_surface_dsc_begin_page_setup (surface);
if (page_layout->do_landscape)
{
if (output_format == FORMAT_POSTSCRIPT)
{
cairo_ps_surface_dsc_comment (surface, "%%PageOrientation: Landscape")
;
cairo_translate(cr, 0, page_layout->page_width);
cairo_rotate(cr, 3*M_PI/2);
}
}
else
{
if (output_format == FORMAT_POSTSCRIPT)
cairo_ps_surface_dsc_comment (surface, "%%PageOrientation: Portrait");
}
} }
void void
draw_line_to_page(FILE *OUT, draw_line_to_page(cairo_t *cr,
int column_idx, int column_idx,
int column_pos, int column_pos,
page_layout_t *page_layout, page_layout_t *page_layout,
PangoLayoutLine *line) PangoLayoutLine *line,
gboolean draw_wrap_character)
{ {
/* Assume square aspect ratio for now */ /* Assume square aspect ratio for now */
double y_pos = page_layout->page_height double y_pos = page_layout->top_margin
- page_layout->top_margin + page_layout->header_sep
- page_layout->header_sep + column_pos / PANGO_SCALE;
- column_pos / PANGO_SCALE * page_layout->pixel_to_pt;
double x_pos = page_layout->left_margin double x_pos = page_layout->left_margin
+ column_idx * (page_layout->column_width + column_idx * (page_layout->column_width
+ page_layout->gutter_width); + page_layout->gutter_width);
gchar *ps_layout;
PangoRectangle ink_rect, logical_rect; PangoRectangle ink_rect, logical_rect;
/* Do RTL column layout for RTL direction */ /* Do RTL column layout for RTL direction */
if (page_layout->pango_dir == PANGO_DIRECTION_RTL) if (page_layout->pango_dir == PANGO_DIRECTION_RTL)
{ {
x_pos = page_layout->left_margin x_pos = page_layout->left_margin
+ (page_layout->num_columns-1-column_idx) + (page_layout->num_columns-1-column_idx)
* (page_layout->column_width + page_layout->gutter_width); * (page_layout->column_width + page_layout->gutter_width);
} }
pango_layout_line_get_extents(line, pango_layout_line_get_extents(line,
&ink_rect, &ink_rect,
&logical_rect); &logical_rect);
if (page_layout->pango_dir == PANGO_DIRECTION_RTL) { if (page_layout->pango_dir == PANGO_DIRECTION_RTL) {
x_pos += page_layout->column_width - logical_rect.width / (page_layout->p x_pos += page_layout->column_width - logical_rect.width / PANGO_SCALE;
t_to_pixel * PANGO_SCALE); }
cairo_move_to(cr, x_pos, y_pos);
pango_cairo_show_layout_line(cr, line);
if (draw_wrap_character)
{
cairo_set_font_face(cr, paps_glyph_face);
cairo_set_font_size(cr, glyph_font_size);
if (page_layout->pango_dir == PANGO_DIRECTION_LTR)
{
cairo_move_to(cr, x_pos + page_layout->column_width, y_pos);
cairo_show_text(cr, "R");
}
else
{
double left_margin = page_layout->left_margin
+ (page_layout->num_columns-1-column_idx)
* (page_layout->column_width + page_layout->gutter_width);
cairo_move_to(cr, left_margin, y_pos);
cairo_show_text(cr, "L");
}
}
}
/*
* Provide date string from current locale converted to UTF-8.
*/
char *
get_date(char *date, int maxlen)
{
time_t t;
GIConv cvh = NULL;
GString *inbuf;
char *ib, *ob, obuffer[BUFSIZE * 6], *bp;
gsize iblen, oblen;
static char *date_utf8 = NULL;
if (date_utf8 == NULL) {
t = time(NULL);
strftime(date, maxlen, "%c", localtime(&t));
cvh = g_iconv_open("UTF-8", get_encoding());
if (cvh == (GIConv)-1) {
fprintf(stderr, _("%s: Invalid encoding: %s\n"), g_get_prgname(), get_enco
ding());
exit(1);
}
inbuf = g_string_new(NULL);
ib = bp = date;
iblen = strlen(ib);
ob = bp = obuffer;
oblen = BUFSIZE * 6 - 1;
if (g_iconv(cvh, &ib, &iblen, &ob, &oblen) == (gsize)-1) {
fprintf(stderr, _("%1$s: Error while converting date string from '%2$s' to
UTF-8.\n"),
g_get_prgname(), get_encoding());
/* Return the unconverted string. */
g_string_free(inbuf, FALSE);
g_iconv_close(cvh);
return date;
}
obuffer[BUFSIZE * 6 - 1 - oblen] = 0;
g_string_append(inbuf, bp);
date_utf8 = inbuf->str;
g_string_free(inbuf, FALSE);
g_iconv_close(cvh);
} }
paps_set_scale(paps, page_layout->scale_x, page_layout->scale_y); return date_utf8;
ps_layout = paps_layout_line_to_postscript_strdup(paps,
x_pos, y_pos,
line);
g_string_append(ps_pages_string,
ps_layout);
g_free(ps_layout);
} }
int int
draw_page_header_line_to_page(FILE *OUT, draw_page_header_line_to_page(cairo_t *cr,
gboolean is_footer, gboolean is_footer,
page_layout_t *page_layout, page_layout_t *page_layout,
PangoContext *ctx, PangoContext *ctx,
int page) int page)
{ {
PangoLayout *layout = pango_layout_new(ctx); PangoLayout *layout = pango_layout_new(ctx);
PangoLayoutLine *line; PangoLayoutLine *line;
PangoRectangle ink_rect, logical_rect; PangoRectangle ink_rect, logical_rect, pagenum_rect;
/* Assume square aspect ratio for now */ /* Assume square aspect ratio for now */
double x_pos, y_pos; double x_pos, y_pos;
gchar *ps_layout, *header, date[256]; gchar *header, date[256];
time_t t;
struct tm tm;
int height; int height;
gdouble line_pos; gdouble line_pos;
t = time(NULL); /* Reset gravity?? */
tm = *localtime(&t); #if 0
strftime(date, 255, "%c", &tm);
header = g_strdup_printf("<span font_desc=\"%s\">%s</span>\n" header = g_strdup_printf("<span font_desc=\"%s\">%s</span>\n"
"<span font_desc=\"%s\">%s</span>\n" "<span font_desc=\"%s\">%s</span>\n"
"<span font_desc=\"%s\">Page %d</span>", "<span font_desc=\"%s\">%d</span>",
page_layout->header_font_desc,
page_layout->title,
page_layout->header_font_desc, page_layout->header_font_desc,
date, get_date(date, 255),
page_layout->header_font_desc, page_layout->header_font_desc,
page_layout->filename, page);
#endif
header = g_strdup_printf("<span font_desc=\"%s\">%d</span>\n",
page_layout->header_font_desc, page_layout->header_font_desc,
page); page);
pango_layout_set_markup(layout, header, -1); pango_layout_set_markup(layout, header, -1);
g_free(header); g_free(header);
/* output a left edge of header/footer */ /* output a left edge of header/footer */
line = pango_layout_get_line(layout, 0); line = pango_layout_get_line(layout, 0);
pango_layout_line_get_extents(line, pango_layout_line_get_extents(line,
&ink_rect, &ink_rect,
&logical_rect); &logical_rect);
x_pos = page_layout->left_margin; x_pos = page_layout->left_margin + (page_layout->page_width-page_layout->left_
height = logical_rect.height / PANGO_SCALE * page_layout->pixel_to_pt/3.0; margin-page_layout->right_margin)*0.5 - 0.5*logical_rect.width/PANGO_SCALE;
height = logical_rect.height / PANGO_SCALE /3.0;
/* The header is placed right after the margin */ /* The header is placed right after the margin */
if (is_footer) if (is_footer)
{ {
y_pos = page_layout->bottom_margin; y_pos = page_layout->page_height - page_layout->bottom_margin*0.5;
page_layout->footer_height = height; page_layout->footer_height = height;
} }
else else
{ {
y_pos = page_layout->page_height - page_layout->top_margin - height; y_pos = page_layout->top_margin + height;
page_layout->header_height = height; page_layout->header_height = height;
} }
paps_set_scale(paps, page_layout->scale_x, page_layout->scale_y);
ps_layout = paps_layout_line_to_postscript_strdup(paps,
x_pos, y_pos,
line);
g_string_append(ps_pages_string,
ps_layout);
g_free(ps_layout);
/* output a center of header/footer */ cairo_move_to(cr, x_pos,y_pos);
line = pango_layout_get_line(layout, 1); pango_cairo_show_layout_line(cr,line);
/* output a right edge of header/footer */
line = pango_layout_get_line(layout, 2);
pango_layout_line_get_extents(line, pango_layout_line_get_extents(line,
&ink_rect, &ink_rect,
&logical_rect); &logical_rect);
x_pos = (page_layout->page_width - (logical_rect.width / PANGO_SCALE * page_la pagenum_rect = logical_rect;
yout->pixel_to_pt)) / 2; x_pos = page_layout->page_width - page_layout->right_margin - (logical_rect.wi
paps_set_scale(paps, page_layout->scale_x, page_layout->scale_y); dth / PANGO_SCALE );
ps_layout = paps_layout_line_to_postscript_strdup(paps, cairo_move_to(cr, x_pos,y_pos);
x_pos, y_pos, pango_cairo_show_layout_line(cr,line);
line);
g_string_append(ps_pages_string,
ps_layout);
g_free(ps_layout);
/* output a right edge of header/footer */ /* output a "center" of header/footer */
line = pango_layout_get_line(layout, 2); line = pango_layout_get_line(layout, 1);
pango_layout_line_get_extents(line, pango_layout_line_get_extents(line,
&ink_rect, &ink_rect,
&logical_rect); &logical_rect);
x_pos = page_layout->page_width - page_layout->right_margin - (logical_rect.wi x_pos = page_layout->page_width - page_layout->right_margin -
dth / PANGO_SCALE * page_layout->pixel_to_pt); ((logical_rect.width + pagenum_rect.width) / PANGO_SCALE + page_layout->gu
paps_set_scale(paps, page_layout->scale_x, page_layout->scale_y); tter_width);
ps_layout = paps_layout_line_to_postscript_strdup(paps, cairo_move_to(cr, x_pos,y_pos);
x_pos, y_pos, pango_cairo_show_layout_line(cr,line);
line);
g_string_append(ps_pages_string,
ps_layout);
g_free(ps_layout);
g_object_unref(layout); g_object_unref(layout);
/* header separator */ /* header separator */
line_pos = page_layout->page_height - page_layout->top_margin - page_layout->h #if 0
eader_height - page_layout->header_sep / 2; line_pos = page_layout->top_margin + page_layout->header_height + page_layout-
g_string_append_printf(ps_pages_string, >header_sep / 2;
"%d %f moveto %d %f lineto 0 setlinewidth stroke\n", cairo_move_to(cr, page_layout->left_margin, line_pos);
page_layout->left_margin, line_pos, cairo_line_to(cr,page_layout->page_width - page_layout->right_margin, line_pos
page_layout->page_width - page_layout->right_margin, li );
ne_pos); cairo_set_line_width(cr,0.1); // TBD
cairo_stroke(cr);
#endif
return logical_rect.height; return logical_rect.height;
} }
 End of changes. 159 change blocks. 
617 lines changed or deleted 863 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)