gxps-print-converter.c 11.7 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
/* GXPSPrintConverter
 *
 * Copyright (C) 2011  Carlos Garcia Campos <carlosgc@gnome.org>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include <config.h>

#include "gxps-print-converter.h"
#include <string.h>

G_DEFINE_ABSTRACT_TYPE (GXPSPrintConverter, gxps_print_converter, GXPS_TYPE_CONVERTER)

static guint paper_width = 0;
static guint paper_height = 0;
static gboolean expand = FALSE;
static gboolean no_shrink = FALSE;
static gboolean no_center = FALSE;

static const GOptionEntry options[] =
{
        { "paper-width", '\0', G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_INT, &paper_width, "paper width, in points", "WIDTH" },
        { "paper-height", '\0', G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_INT, &paper_height, "paper height, in points", "HEIGHT" },
        { "expand", '\0', G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_NONE, &expand, "expand pages smaller than the paper size", NULL },
        { "no-shrink", '\0', G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_NONE, &no_shrink, "don't shrink pages larger than the paper size", NULL },
        { "no-center", '\0', G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_NONE, &no_center, "don't center pages smaller than the paper size", NULL },
        { NULL }
};

static gboolean
gxps_print_converter_init_with_args (GXPSConverter *converter,
                                     gint          *argc,
                                     gchar       ***argv,
                                     GList        **option_groups)
{
        GXPSPrintConverter *print_converter = GXPS_PRINT_CONVERTER (converter);
        GOptionContext     *context;
        GOptionGroup       *option_group;
        GError             *error = NULL;

        option_group = g_option_group_new ("printing", "Printing Options", "Show Printing Options", NULL, NULL);
        g_option_group_add_entries (option_group, options);

        *option_groups = g_list_prepend (*option_groups, option_group);

        if (GXPS_CONVERTER_CLASS (gxps_print_converter_parent_class)->init_with_args) {
                if (!GXPS_CONVERTER_CLASS (gxps_print_converter_parent_class)->init_with_args (converter, argc, argv, option_groups))
                        return FALSE;
        }

        context = g_option_context_new (NULL);
        g_option_context_set_ignore_unknown_options (context, TRUE);
        g_option_context_set_help_enabled (context, FALSE);
        g_option_context_add_main_entries (context, options, NULL);
        if (!g_option_context_parse (context, argc, argv, &error)) {
                g_printerr ("Error parsing arguments: %s\n", error->message);
                g_error_free (error);
                g_option_context_free (context);

                return FALSE;
        }
        g_option_context_free (context);

        print_converter->paper_width = paper_width;
        print_converter->paper_height = paper_height;

        print_converter->flags = GXPS_PRINT_CONVERTER_SHRINK | GXPS_PRINT_CONVERTER_CENTER;
        if (expand)
                print_converter->flags |= GXPS_PRINT_CONVERTER_EXPAND;
        if (no_shrink)
                print_converter->flags &= ~GXPS_PRINT_CONVERTER_SHRINK;
        if (no_center)
                print_converter->flags &= ~GXPS_PRINT_CONVERTER_CENTER;

        return TRUE;
}


static void
gxps_converter_print_converter_begin_document (GXPSConverter *converter,
                                               const gchar   *output_filename,
                                               GXPSPage      *first_page)
{
        GXPSPrintConverter *print_converter = GXPS_PRINT_CONVERTER (converter);
        gchar              *basename;
        gchar              *basename_lower;
        const gchar        *ext;

        if (output_filename) {
                print_converter->filename = g_strdup (output_filename);
                return;
        }

        basename = g_path_get_basename (converter->input_filename);
        basename_lower = g_ascii_strdown (basename, -1);
        ext = g_strrstr (basename_lower, ".xps");

        if (ext) {
                gchar *name;

                name = g_strndup (basename, strlen (basename) - strlen (ext));
                print_converter->filename = g_strdup_printf ("%s.%s", name,
                                                             gxps_converter_get_extension (converter));
                g_free (name);
        } else {
                print_converter->filename = g_strdup_printf ("%s.%s", basename,
                                                             gxps_converter_get_extension (converter));
        }

123
        g_free (basename_lower);
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
        g_free (basename);
}

static void
gxps_converter_print_get_fit_to_page_transform (GXPSPrintConverter *print_converter,
                                                gdouble             page_width,
                                                gdouble             page_height,
                                                gdouble             paper_width,
                                                gdouble             paper_height,
                                                cairo_matrix_t     *matrix)
{
        gdouble x_scale, y_scale;
        gdouble scale;

        x_scale = paper_width / page_width;
        y_scale = paper_height / page_height;
        scale = (x_scale < y_scale) ? x_scale : y_scale;

        cairo_matrix_init_identity (matrix);
        if (scale > 1.0) {
                /* Page is smaller than paper */
                if (print_converter->flags & GXPS_PRINT_CONVERTER_EXPAND) {
                        cairo_matrix_scale (matrix, scale, scale);
                } else if (print_converter->flags & GXPS_PRINT_CONVERTER_CENTER) {
                        cairo_matrix_translate (matrix,
                                                (paper_width - page_width) / 2,
                                                (paper_height - page_height) / 2);
                } else {
                        if (!print_converter->upside_down_coords) {
                                /* Move to PostScript origin */
                                cairo_matrix_translate (matrix, 0, (paper_height - page_height));
                        }
                }
        } else if (scale < 1.0) {
                /* Page is larger than paper */
                if (print_converter->flags & GXPS_PRINT_CONVERTER_SHRINK)
                        cairo_matrix_scale (matrix, scale, scale);
        }
}

static cairo_t *
gxps_converter_print_converter_begin_page (GXPSConverter *converter,
                                           GXPSPage      *page,
                                           guint          n_page)
{
        GXPSPrintConverter *print_converter = GXPS_PRINT_CONVERTER (converter);
170
        gdouble             page_width, page_height;
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
        gdouble             cropped_width, cropped_height;
        gdouble             output_width, output_height;
        cairo_matrix_t      matrix;
        cairo_t            *cr;

        g_return_val_if_fail (converter->surface != NULL, NULL);

        cairo_surface_set_fallback_resolution (converter->surface,
                                               converter->x_resolution,
                                               converter->y_resolution);
        cr = cairo_create (converter->surface);
        cairo_translate (cr, -converter->crop.x, -converter->crop.y);

        gxps_page_get_size (page, &page_width, &page_height);
        gxps_converter_get_crop_size (converter,
186
                                      page_width, page_height,
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
                                      &cropped_width, &cropped_height);
        _gxps_converter_print_get_output_size (print_converter, page,
                                               &output_width, &output_height);
        gxps_converter_print_get_fit_to_page_transform (print_converter,
                                                        cropped_width, cropped_height,
                                                        output_width, output_height,
                                                        &matrix);
        cairo_transform (cr, &matrix);
        cairo_rectangle (cr, converter->crop.x, converter->crop.y, cropped_width, cropped_height);
        cairo_clip (cr);

        return cr;
}

static void
gxps_converter_print_converter_end_page (GXPSConverter *converter)
{
        g_return_if_fail (converter->surface != NULL);

        cairo_surface_show_page (converter->surface);
}

static void
gxps_converter_print_converter_end_document (GXPSConverter *converter)
{
        GXPSPrintConverter *print_converter = GXPS_PRINT_CONVERTER (converter);
213
214
215
216
217
218
219
220
221
222
223

        if (converter->surface) {
                cairo_status_t status;

                cairo_surface_finish (converter->surface);
                status = cairo_surface_status (converter->surface);
                if (status)
                        g_printerr ("Cairo error: %s\n", cairo_status_to_string (status));
                cairo_surface_destroy (converter->surface);
                converter->surface = NULL;
        }
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267

        g_free (print_converter->filename);
        print_converter->filename = NULL;
}

static void
gxps_print_converter_finalize (GObject *object)
{
        GXPSPrintConverter *print_converter = GXPS_PRINT_CONVERTER (object);

        if (print_converter->filename) {
                g_free (print_converter->filename);
                print_converter->filename = NULL;
        }

        G_OBJECT_CLASS (gxps_print_converter_parent_class)->finalize (object);
}

static void
gxps_print_converter_init (GXPSPrintConverter *converter)
{
}

static void
gxps_print_converter_class_init (GXPSPrintConverterClass *klass)
{
        GObjectClass       *object_class = G_OBJECT_CLASS (klass);
        GXPSConverterClass *converter_class = GXPS_CONVERTER_CLASS (klass);

        object_class->finalize = gxps_print_converter_finalize;

        converter_class->init_with_args = gxps_print_converter_init_with_args;
        converter_class->begin_document = gxps_converter_print_converter_begin_document;
        converter_class->begin_page = gxps_converter_print_converter_begin_page;
        converter_class->end_page = gxps_converter_print_converter_end_page;
        converter_class->end_document = gxps_converter_print_converter_end_document;
}

void
_gxps_converter_print_get_output_size (GXPSPrintConverter *converter,
                                       GXPSPage           *page,
                                       gdouble            *output_width,
                                       gdouble            *output_height)
{
268
        gdouble page_width, page_height;
269
270
271

        gxps_page_get_size (page, &page_width, &page_height);

272
273
274
275
        /* The page width is in points, Windows expects a dpi of 96 while
         * cairo will handle the dpi in 72. We need to make the conversion
         * ourselves so we have the right output size
         */
276
277
        if (output_width) {
                *output_width = converter->paper_width == 0 ?
278
                        page_width * 72.0 / 96.0 : converter->paper_width;
279
280
281
282
        }

        if (output_height) {
                *output_height = converter->paper_height == 0 ?
283
                        page_height * 72.0 / 96.0 : converter->paper_height;
284
285
        }
}