~centralelyon2010/inkscape/imagelinks2

« back to all changes in this revision

Viewing changes to src/extension/internal/ps.cpp

  • Committer: Ted Gould
  • Date: 2008-11-21 05:24:08 UTC
  • Revision ID: ted@canonical.com-20081121052408-tilucis2pjrrpzxx
MergeĀ fromĀ fe-moved

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#define __SP_PS_C__
2
 
 
3
 
/** \file
4
 
 * PostScript printing.
5
 
 */
6
 
/*
7
 
 * Authors:
8
 
 *   Lauris Kaplinski <lauris@kaplinski.com>
9
 
 *   bulia byak <buliabyak@users.sf.net>
10
 
 *
11
 
 * Basic printing code, EXCEPT image and
12
 
 * ascii85 filter is in public domain
13
 
 *
14
 
 * Image printing and Ascii85 filter:
15
 
 *
16
 
 * Copyright (C) 2006 Johan Engelen
17
 
 * Copyright (C) 1997-98 Peter Kirchgessner
18
 
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
19
 
 * George White <aa056@chebucto.ns.ca>
20
 
 * Austin Donnelly <austin@gimp.org>
21
 
 *
22
 
 * Licensed under GNU GPL
23
 
 */
24
 
 
25
 
/* Plain Print */
26
 
 
27
 
#ifdef HAVE_CONFIG_H
28
 
# include "config.h"
29
 
#endif
30
 
 
31
 
#include <signal.h>
32
 
#include <errno.h>
33
 
 
34
 
#include <libnr/nr-matrix-fns.h>
35
 
 
36
 
#include <glib/gmem.h>
37
 
#include <glib/gstrfuncs.h>
38
 
#include <gtk/gtkstock.h>
39
 
#include <gtk/gtkvbox.h>
40
 
#include <gtk/gtkframe.h>
41
 
#include <gtk/gtkradiobutton.h>
42
 
#include <gtk/gtkcombo.h>
43
 
#include <gtk/gtklabel.h>
44
 
#include <gtk/gtkentry.h>
45
 
#include <gtk/gtktooltips.h>
46
 
 
47
 
#include <glibmm/i18n.h>
48
 
#include "display/nr-arena-item.h"
49
 
#include "display/canvas-bpath.h"
50
 
#include "sp-item.h"
51
 
#include "style.h"
52
 
#include "sp-linear-gradient.h"
53
 
#include "sp-radial-gradient.h"
54
 
 
55
 
#include "libnrtype/font-instance.h"
56
 
#include "libnrtype/font-style-to-pos.h"
57
 
 
58
 
#include <unit-constants.h>
59
 
 
60
 
#include "ps.h"
61
 
#include "extension/system.h"
62
 
#include "extension/print.h"
63
 
 
64
 
#include "io/sys.h"
65
 
 
66
 
#include <ft2build.h>
67
 
#include FT_FREETYPE_H
68
 
#include FT_XFREE86_H
69
 
#include <pango/pangoft2.h>
70
 
#include <string>
71
 
#include <iostream>
72
 
#include <fstream>
73
 
#include <cstring>
74
 
#include <cstdio>
75
 
#include <cstdlib>
76
 
#include <cmath>
77
 
 
78
 
#include <2geom/sbasis-to-bezier.h>
79
 
#include <2geom/bezier-curve.h>
80
 
#include <2geom/hvlinesegment.h>
81
 
#include "helper/geom-curves.h"
82
 
 
83
 
/*
84
 
using std::atof;
85
 
using std::ceil;
86
 
using std::fclose;
87
 
using std::ferror;
88
 
using std::fflush;
89
 
using std::fgetc;
90
 
using std::fprintf;  --> this line will result  'std::libintl_fprintf' has not been declared
91
 
using std::fputc;
92
 
using std::fseek;
93
 
using std::ifstream;
94
 
using std::ios;
95
 
using std::memset;
96
 
using std::strchr;
97
 
using std::strcmp;
98
 
using std::strerror;
99
 
using std::tmpfile;
100
 
*/
101
 
using namespace std;
102
 
 
103
 
namespace Inkscape {
104
 
namespace Extension {
105
 
namespace Internal {
106
 
 
107
 
PrintPS::PrintPS() :
108
 
    _stream(NULL),
109
 
    _dpi(72),
110
 
    _bitmap(false)
111
 
{
112
 
    //map font types
113
 
    _fontTypesMap["Type 1"] = FONT_TYPE1;
114
 
    _fontTypesMap["TrueType"] = FONT_TRUETYPE;
115
 
    //TODO: support other font types (cf. embed_font())
116
 
}
117
 
 
118
 
PrintPS::~PrintPS(void)
119
 
{
120
 
    /* fixme: should really use pclose for popen'd streams */
121
 
    if (_stream) fclose(_stream);
122
 
    if(_begin_stream) fclose(_begin_stream);
123
 
    if(_fonts) g_tree_destroy(_fonts);
124
 
 
125
 
    /* restore default signal handling for SIGPIPE */
126
 
#if !defined(_WIN32) && !defined(__WIN32__)
127
 
    (void) signal(SIGPIPE, SIG_DFL);
128
 
#endif
129
 
 
130
 
    return;
131
 
}
132
 
 
133
 
unsigned int
134
 
PrintPS::setup(Inkscape::Extension::Print * mod)
135
 
{
136
 
    static gchar const *const pdr[] = {"72", "75", "100", "144", "150", "200", "300", "360", "600", "1200", "2400", NULL};
137
 
 
138
 
#ifdef TED
139
 
    Inkscape::XML::Node *repr = ((SPModule *) mod)->repr;
140
 
#endif
141
 
 
142
 
    unsigned int ret = FALSE;
143
 
    gchar const *destination = mod->get_param_string("destination");
144
 
 
145
 
    /* Create dialog */
146
 
    GtkTooltips *tt = gtk_tooltips_new();
147
 
    g_object_ref((GObject *) tt);
148
 
    gtk_object_sink((GtkObject *) tt);
149
 
 
150
 
    GtkWidget *dlg = gtk_dialog_new_with_buttons(
151
 
            destination ?  _("Print Configuration") : _("Print Destination"),
152
 
//            SP_DT_WIDGET(SP_ACTIVE_DESKTOP)->window,
153
 
            NULL,
154
 
            (GtkDialogFlags) (GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR | GTK_DIALOG_DESTROY_WITH_PARENT),
155
 
            GTK_STOCK_CANCEL,
156
 
            GTK_RESPONSE_CANCEL,
157
 
            destination ? GTK_STOCK_GO_FORWARD : GTK_STOCK_PRINT,
158
 
            GTK_RESPONSE_OK,
159
 
            NULL);
160
 
 
161
 
    gtk_dialog_set_default_response(GTK_DIALOG(dlg), GTK_RESPONSE_OK);
162
 
 
163
 
    GtkWidget *vbox = GTK_DIALOG(dlg)->vbox;
164
 
    gtk_container_set_border_width(GTK_CONTAINER(vbox), 4);
165
 
    /* Print properties frame */
166
 
    GtkWidget *f = gtk_frame_new(_("Print properties"));
167
 
    gtk_box_pack_start(GTK_BOX(vbox), f, FALSE, FALSE, 4);
168
 
    GtkWidget *vb = gtk_vbox_new(FALSE, 4);
169
 
    gtk_container_add(GTK_CONTAINER(f), vb);
170
 
    gtk_container_set_border_width(GTK_CONTAINER(vb), 4);
171
 
    /* Print type */
172
 
    bool const p2bm = mod->get_param_bool("bitmap");
173
 
    GtkWidget *rb = gtk_radio_button_new_with_label(NULL, _("Print using PostScript operators"));
174
 
    gtk_tooltips_set_tip((GtkTooltips *) tt, rb,
175
 
                         _("Use PostScript vector operators. The resulting image is usually smaller "
176
 
                           "in file size and can be arbitrarily scaled, but alpha transparency "
177
 
                           "and patterns will be lost."), NULL);
178
 
    if (!p2bm) gtk_toggle_button_set_active((GtkToggleButton *) rb, TRUE);
179
 
    gtk_box_pack_start(GTK_BOX(vb), rb, FALSE, FALSE, 0);
180
 
    rb = gtk_radio_button_new_with_label(gtk_radio_button_get_group((GtkRadioButton *) rb), _("Print as bitmap"));
181
 
    gtk_tooltips_set_tip((GtkTooltips *) tt, rb,
182
 
                         _("Print everything as bitmap. The resulting image is usually larger "
183
 
                           "in file size and cannot be arbitrarily scaled without quality loss, "
184
 
                           "but all objects will be rendered exactly as displayed."), NULL);
185
 
    if (p2bm) gtk_toggle_button_set_active((GtkToggleButton *) rb, TRUE);
186
 
    gtk_box_pack_start(GTK_BOX(vb), rb, FALSE, FALSE, 0);
187
 
    /* Resolution */
188
 
    GtkWidget *hb = gtk_hbox_new(FALSE, 4);
189
 
    gtk_box_pack_start(GTK_BOX(vb), hb, FALSE, FALSE, 0);
190
 
    GtkWidget *combo = gtk_combo_new();
191
 
    gtk_combo_set_value_in_list(GTK_COMBO(combo), FALSE, FALSE);
192
 
    gtk_combo_set_use_arrows(GTK_COMBO(combo), TRUE);
193
 
    gtk_combo_set_use_arrows_always(GTK_COMBO(combo), TRUE);
194
 
    gtk_widget_set_size_request(combo, 64, -1);
195
 
    gtk_tooltips_set_tip((GtkTooltips *) tt, GTK_COMBO(combo)->entry,
196
 
                         _("Preferred resolution (dots per inch) of bitmap"), NULL);
197
 
    /* Setup strings */
198
 
    GList *sl = NULL;
199
 
    for (unsigned i = 0; pdr[i] != NULL; i++) {
200
 
        sl = g_list_prepend(sl, (gpointer) pdr[i]);
201
 
    }
202
 
    sl = g_list_reverse(sl);
203
 
    gtk_combo_set_popdown_strings(GTK_COMBO(combo), sl);
204
 
    g_list_free(sl);
205
 
    if (1) {
206
 
        gchar const *val = mod->get_param_string("resolution");
207
 
        gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), val);
208
 
    }
209
 
    gtk_box_pack_end(GTK_BOX(hb), combo, FALSE, FALSE, 0);
210
 
    GtkWidget *l = gtk_label_new(_("Resolution:"));
211
 
    gtk_box_pack_end(GTK_BOX(hb), l, FALSE, FALSE, 0);
212
 
 
213
 
    GtkWidget *e = NULL;
214
 
    /* if the destination isn't already set, we must prompt for it */
215
 
    if (!destination) {
216
 
        /* Print destination frame */
217
 
        f = gtk_frame_new(_("Print destination"));
218
 
        gtk_box_pack_start(GTK_BOX(vbox), f, FALSE, FALSE, 4);
219
 
        vb = gtk_vbox_new(FALSE, 4);
220
 
        gtk_container_add(GTK_CONTAINER(f), vb);
221
 
        gtk_container_set_border_width(GTK_CONTAINER(vb), 4);
222
 
 
223
 
        l = gtk_label_new(_("Printer name (as given by lpstat -p);\n"
224
 
                            "leave empty to use the system default printer.\n"
225
 
                            "Use '> filename' to print to file.\n"
226
 
                        "Use '| prog arg...' to pipe to a program."));
227
 
        gtk_box_pack_start(GTK_BOX(vb), l, FALSE, FALSE, 0);
228
 
 
229
 
        e = gtk_entry_new();
230
 
        gtk_entry_set_text(GTK_ENTRY(e), ( destination != NULL
231
 
                                           ? destination
232
 
                                           : "" ));
233
 
        gtk_box_pack_start(GTK_BOX(vb), e, FALSE, FALSE, 0);
234
 
 
235
 
        // pressing enter in the destination field is the same as clicking Print:
236
 
        gtk_entry_set_activates_default(GTK_ENTRY(e), TRUE);
237
 
    }
238
 
 
239
 
    gtk_widget_show_all(vbox);
240
 
 
241
 
    int const response = gtk_dialog_run(GTK_DIALOG(dlg));
242
 
 
243
 
    g_object_unref((GObject *) tt);
244
 
 
245
 
    if (response == GTK_RESPONSE_OK) {
246
 
        gchar const *fn;
247
 
        char const *sstr;
248
 
 
249
 
        _bitmap = gtk_toggle_button_get_active((GtkToggleButton *) rb);
250
 
        sstr = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(combo)->entry));
251
 
        _dpi = (unsigned int) MAX((int)(atof(sstr)), 1);
252
 
 
253
 
        /* if the destination was prompted for, record the new value */
254
 
        if (e) {
255
 
            /* Arrgh, have to do something */
256
 
            fn = gtk_entry_get_text(GTK_ENTRY(e));
257
 
            /* skip leading whitespace, bug #1068483 */
258
 
            while (fn && *fn==' ') { fn++; }
259
 
            /* g_print("Printing to %s\n", fn); */
260
 
 
261
 
            mod->set_param_string("destination", (gchar *)fn);
262
 
        }
263
 
        mod->set_param_bool("bitmap", _bitmap);
264
 
        mod->set_param_string("resolution", (gchar *)sstr);
265
 
        ret = TRUE;
266
 
    }
267
 
 
268
 
    gtk_widget_destroy(dlg);
269
 
 
270
 
    return ret;
271
 
}
272
 
 
273
 
unsigned int
274
 
PrintPS::begin(Inkscape::Extension::Print *mod, SPDocument *doc)
275
 
{
276
 
    gboolean epsexport = false;
277
 
 
278
 
 
279
 
    _latin1_encoded_fonts.clear();
280
 
    _newlatin1font_proc_defined = false;
281
 
 
282
 
    FILE *osf = NULL;
283
 
    FILE *osp = NULL;
284
 
    FILE *osf_tmp = NULL;
285
 
 
286
 
    gsize bytesRead = 0;
287
 
    gsize bytesWritten = 0;
288
 
    GError *error = NULL;
289
 
    //check whether fonts have to be embedded in the (EPS only) output
290
 
    bool font_embedded = mod->fontEmbedded();
291
 
    gchar const *utf8_fn = mod->get_param_string("destination");
292
 
    gchar *local_fn = g_filename_from_utf8( utf8_fn,
293
 
                                            -1,  &bytesRead,  &bytesWritten, &error);
294
 
    gchar const *fn = local_fn;
295
 
 
296
 
    /* TODO: Replace the below fprintf's with something that does the right thing whether in
297
 
     * gui or batch mode (e.g. --print=blah).  Consider throwing an exception: currently one of
298
 
     * the callers (sp_print_document_to_file, "ret = mod->begin(doc)") wrongly ignores the
299
 
     * return code.
300
 
     */
301
 
    if (fn != NULL) {
302
 
        if (*fn == '|') {
303
 
            fn += 1;
304
 
            while (g_ascii_isspace(*fn)) fn += 1;
305
 
#ifndef WIN32
306
 
            osp = popen(fn, "w");
307
 
#else
308
 
            osp = _popen(fn, "w");
309
 
#endif
310
 
            if (!osp) {
311
 
                fprintf(stderr, "inkscape: popen(%s): %s\n",
312
 
                        fn, strerror(errno));
313
 
                return 0;
314
 
            }
315
 
            _stream = _begin_stream = osp;
316
 
        } else if (*fn == '>') {
317
 
            fn += 1;
318
 
            epsexport = g_str_has_suffix(fn,".eps");
319
 
            while (isspace(*fn)) fn += 1;
320
 
            Inkscape::IO::dump_fopen_call(fn, "K");
321
 
            osf = Inkscape::IO::fopen_utf8name(fn, "w+");
322
 
            if (!osf) {
323
 
                fprintf(stderr, "inkscape: fopen(%s): %s\n",
324
 
                        fn, strerror(errno));
325
 
                return 0;
326
 
            }
327
 
            _begin_stream = osf;
328
 
             /* if font embedding is requested for EPS export...
329
 
             * TODO:could be extended to PS export if texttopath=FALSE possible
330
 
             */
331
 
             if(font_embedded && epsexport)
332
 
             {
333
 
               /**
334
 
               * Create temporary file where to print the main "script" part of the EPS document.
335
 
               * Use an extra stream (_begin_stream) to print the prolog and document setup sections.
336
 
               * Thus, once all the (main) script part printed, all the fonts used are known and can be embedded
337
 
               * just after the prolog section, in a Begin(End)Setup section (document setup),
338
 
               * one Begin(End)Resource (DSC comment) section for each font embedded.
339
 
               * Then, append the final script part from the temporary file (_stream in this case).
340
 
               * Reference: Adobe Technical note 5001, "PostScript Document Struturing Conventions Specifications"
341
 
               * page 19
342
 
               */
343
 
               osf_tmp = tmpfile();
344
 
               if(!osf_tmp)
345
 
               {
346
 
                 g_warning("Could not create a temporary file for font embedding. Font embedding canceled.");
347
 
                 mod->set_param_bool("fontEmbedded", false);
348
 
                 font_embedded = false;
349
 
                 _stream = osf;
350
 
               } else _stream = osf_tmp;
351
 
             } else _stream = osf;
352
 
        } else {
353
 
            /* put cwd stuff in here */
354
 
            gchar *qn = ( *fn
355
 
                          ? g_strdup_printf("lpr -P %s", fn)  /* FIXME: quote fn */
356
 
                          : g_strdup("lpr") );
357
 
#ifndef WIN32
358
 
            osp = popen(qn, "w");
359
 
#else
360
 
            osp = _popen(qn, "w");
361
 
#endif
362
 
            if (!osp) {
363
 
                fprintf(stderr, "inkscape: popen(%s): %s\n",
364
 
                        qn, strerror(errno));
365
 
                return 0;
366
 
            }
367
 
            g_free(qn);
368
 
            _stream = _begin_stream = osp;
369
 
        }
370
 
    }
371
 
 
372
 
    g_free(local_fn);
373
 
 
374
 
    if (_stream) {
375
 
        /* fixme: this is kinda icky */
376
 
#if !defined(_WIN32) && !defined(__WIN32__)
377
 
        (void) signal(SIGPIPE, SIG_IGN);
378
 
#endif
379
 
    }
380
 
 
381
 
    int const res = fprintf(_begin_stream, ( epsexport
382
 
                                       ? "%%!PS-Adobe-3.0 EPSF-3.0\n"
383
 
                                       : "%%!PS-Adobe-3.0\n" ));
384
 
    /* flush this to test output stream as early as possible */
385
 
    if (fflush(_begin_stream)) {
386
 
        /*g_print("caught error in sp_module_print_plain_begin\n");*/
387
 
        if (ferror(_begin_stream)) {
388
 
            g_print("Error %d on output stream: %s\n", errno,
389
 
                    g_strerror(errno));
390
 
        }
391
 
        g_print("Printing failed\n");
392
 
        /* fixme: should use pclose() for pipes */
393
 
        fclose(_begin_stream);
394
 
        _begin_stream = NULL;
395
 
        fflush(stdout);
396
 
        return 0;
397
 
    }
398
 
    //TODO: do this same test on _stream
399
 
 
400
 
    // width and height in pt
401
 
    _width = sp_document_width(doc) * PT_PER_PX;
402
 
    _height = sp_document_height(doc) * PT_PER_PX;
403
 
 
404
 
    NRRect d;
405
 
    bool   pageBoundingBox;
406
 
    bool   pageLandscape;
407
 
    pageBoundingBox = mod->get_param_bool("pageBoundingBox");
408
 
    // printf("Page Bounding Box: %s\n", pageBoundingBox ? "TRUE" : "FALSE");
409
 
    if (pageBoundingBox) {
410
 
        d.x0 = d.y0 = 0;
411
 
        d.x1 = ceil(_width);
412
 
        d.y1 = ceil(_height);
413
 
    } else {
414
 
        SPItem* doc_item = SP_ITEM(sp_document_root(doc));
415
 
        sp_item_invoke_bbox(doc_item, &d, sp_item_i2r_affine(doc_item), TRUE);
416
 
        // convert from px to pt
417
 
        d.x0 *= PT_PER_PX;
418
 
        d.x1 *= PT_PER_PX;
419
 
        d.y0 *= PT_PER_PX;
420
 
        d.y1 *= PT_PER_PX;
421
 
    }
422
 
 
423
 
    Inkscape::SVGOStringStream os;
424
 
    if (res >= 0) {
425
 
 
426
 
        os << "%%Creator: " << PACKAGE_STRING << "\n";
427
 
        // This will become problematic if inkscape gains the
428
 
        // ability to handle multi paged documents. If this is
429
 
        // the case the %%Orientation: comments should be
430
 
        // renamed to %%PageOrientation: and moved to the
431
 
        // respective pages.
432
 
        os << "%%Pages: 1\n";
433
 
 
434
 
        // 2004 Dec 10, BFC:
435
 
        // The point of the following code is (1) to do the thing that's expected by users
436
 
        // who have done File>New>A4_landscape or ...letter_landscape (i.e., rotate
437
 
        // the output), while (2) not messing up users who simply want their output wider
438
 
        // than it is tall (e.g., small figures for inclusion in LaTeX).
439
 
        // The original patch by WQ only had the w>h condition.
440
 
        {
441
 
             double w = (d.x1 - d.x0); // width and height of bounding box, in pt
442
 
             double h = (d.y1 - d.y0);
443
 
             pageLandscape = (
444
 
                 (w > 0. && h > 0.) // empty documents fail this sanity check, have w<0, h<0
445
 
                 && (w > h)   // implies, but does not prove, the user wanted landscape
446
 
                 && (w > 600) // approximate maximum printable width of an A4
447
 
                 && (!epsexport) // eps should always be portrait
448
 
             )
449
 
             ? true : false;
450
 
        }
451
 
 
452
 
        if (pageLandscape) {
453
 
            os << "%%Orientation: Landscape\n";
454
 
            os << "%%BoundingBox: " << (int) (_height - d.y1) << " "
455
 
               << (int) d.x0 << " "
456
 
               << (int) ceil(_height - d.y0) << " "
457
 
               << (int) ceil(d.x1) << "\n";
458
 
            // According to Mike Sweet (the author of CUPS)
459
 
            // HiResBoundingBox is only appropriate
460
 
            // for EPS files. This means that we should
461
 
            // distinguish if we export to ps or eps here.
462
 
            // FIXME: I couldn't find HiResBoundingBox in the PS
463
 
            // reference manual, so I guess we should skip
464
 
            // it.
465
 
            os << "%%HiResBoundingBox: " << (_height - d.y1) << " "
466
 
               << d.x0 << " "
467
 
               << (_height - d.y0) << " "
468
 
               << d.x1 << "\n";
469
 
            if (!epsexport) {
470
 
                os << "%%DocumentMedia: plain "
471
 
                   << (int) ceil(_height) << " "
472
 
                   << (int) ceil(_width) << " "
473
 
                   << "0 () ()\n";
474
 
            }
475
 
        } else {
476
 
            os << "%%Orientation: Portrait\n";
477
 
            os << "%%BoundingBox: " << (int) d.x0 << " "
478
 
               << (int) d.y0 << " "
479
 
               << (int) ceil(d.x1) << " "
480
 
               << (int) ceil(d.y1) << "\n";
481
 
            os << "%%HiResBoundingBox: " << d.x0 << " "
482
 
               << d.y0 << " "
483
 
               << d.x1 << " "
484
 
               << d.y1 << "\n";
485
 
            if (!epsexport) {
486
 
                                os << "%%DocumentMedia: plain "
487
 
                                   << (int) ceil(_width) << " "
488
 
                  << (int) ceil(_height) << " "
489
 
                  << "0 () ()\n";
490
 
                        }
491
 
        }
492
 
 
493
 
        os << "%%EndComments\n";
494
 
         /* If font embedding requested, begin document setup section where to include font resources */
495
 
         if(font_embedded) os << "%%BeginSetup\n";/* Resume it later with Begin(End)Resource sections for font embedding. So, for now, we are done with the prolog/setup part. */
496
 
         gint ret = fprintf(_begin_stream, "%s", os.str().c_str());
497
 
         if(ret < 0) return ret;
498
 
 
499
 
         /* Main Script part (after document setup) begins */
500
 
         /* Empty os from all previous printing */
501
 
         std::string clrstr = "";
502
 
         os.str(clrstr);
503
 
        // This will become problematic if we print multi paged documents:
504
 
        os << "%%Page: 1 1\n";
505
 
 
506
 
        if (pageLandscape) {
507
 
            os << "90 rotate\n";
508
 
            if (_bitmap) {
509
 
                os << "0 " << (int) -ceil(_height) << " translate\n";
510
 
            }
511
 
        } else {
512
 
            if (!_bitmap) {
513
 
                os << "0 " << (int) ceil(_height) << " translate\n";
514
 
            }
515
 
        }
516
 
 
517
 
        if (!_bitmap) {
518
 
            os << PT_PER_PX << " " << -PT_PER_PX << " scale\n";
519
 
            // from now on we can output px, but they will be treated as pt
520
 
        }
521
 
 
522
 
        /* As a new PS document is created, _fontlist has to be reinitialized (unref fonts from possible former PS docs) */
523
 
        _fonts = g_tree_new_full((GCompareDataFunc)strcmp, NULL, (GDestroyNotify)g_free, (GDestroyNotify)g_free);
524
 
    }
525
 
 
526
 
    os << "0 0 0 setrgbcolor\n"
527
 
       << "[] 0 setdash\n"
528
 
       << "1 setlinewidth\n"
529
 
       << "0 setlinejoin\n"
530
 
       << "0 setlinecap\n";
531
 
 
532
 
    /* FIXME: This function is declared to return unsigned, whereas fprintf returns a signed int *
533
 
     * that can be zero if the first fprintf failed (os is empty) or "negative" (i.e. very positive
534
 
     * in unsigned int interpretation) if the first fprintf failed but this one succeeds, or
535
 
     * positive if both succeed. */
536
 
    return fprintf(_stream, "%s", os.str().c_str());
537
 
}
538
 
 
539
 
unsigned int
540
 
PrintPS::finish(Inkscape::Extension::Print *mod)
541
 
{
542
 
    if (!_stream) return 0;
543
 
 
544
 
    if (_bitmap) {
545
 
        double const dots_per_pt = _dpi / PT_PER_IN;
546
 
 
547
 
        double const x0 = 0.0;
548
 
        double const y0 = 0.0;
549
 
        double const x1 = x0 + _width;
550
 
        double const y1 = y0 + _height;
551
 
 
552
 
        /* Bitmap width/height in bitmap dots. */
553
 
        int const width = (int) (_width * dots_per_pt + 0.5);
554
 
        int const height = (int) (_height * dots_per_pt + 0.5);
555
 
 
556
 
        Geom::Matrix affine;
557
 
        affine[0] = width / ((x1 - x0) * PX_PER_PT);
558
 
        affine[1] = 0.0;
559
 
        affine[2] = 0.0;
560
 
        affine[3] = height / ((y1 - y0) * PX_PER_PT);
561
 
        affine[4] = -affine[0] * x0;
562
 
        affine[5] = -affine[3] * y0;
563
 
 
564
 
        nr_arena_item_set_transform(mod->root, &affine);
565
 
 
566
 
        guchar *const px = g_new(guchar, 4 * width * 64);
567
 
 
568
 
        for (int y = 0; y < height; y += 64) {
569
 
            /* Set area of interest. */
570
 
            NRRectL bbox;
571
 
            bbox.x0 = 0;
572
 
            bbox.y0 = y;
573
 
            bbox.x1 = width;
574
 
            bbox.y1 = MIN(height, y + 64);
575
 
 
576
 
            /* Update to renderable state. */
577
 
            NRGC gc(NULL);
578
 
            gc.transform.setIdentity();
579
 
            nr_arena_item_invoke_update(mod->root, &bbox, &gc, NR_ARENA_ITEM_STATE_ALL, NR_ARENA_ITEM_STATE_NONE);
580
 
            /* Render */
581
 
            /* This should take guchar* instead of unsigned char*) */
582
 
            NRPixBlock pb;
583
 
            nr_pixblock_setup_extern(&pb, NR_PIXBLOCK_MODE_R8G8B8A8N,
584
 
                                     bbox.x0, bbox.y0, bbox.x1, bbox.y1,
585
 
                                     (guchar*)px, 4 * width, FALSE, FALSE);
586
 
            memset(px, 0xff, 4 * width * 64);
587
 
            nr_arena_item_invoke_render(NULL, mod->root, &bbox, &pb, 0);
588
 
            /* Blitter goes here */
589
 
            Geom::Matrix imgt;
590
 
            imgt[0] = (bbox.x1 - bbox.x0) / dots_per_pt;
591
 
            imgt[1] = 0.0;
592
 
            imgt[2] = 0.0;
593
 
            imgt[3] = (bbox.y1 - bbox.y0) / dots_per_pt;
594
 
            imgt[4] = 0.0;
595
 
            imgt[5] = _height - y / dots_per_pt - (bbox.y1 - bbox.y0) / dots_per_pt;
596
 
 
597
 
            print_image(_stream, px, bbox.x1 - bbox.x0, bbox.y1 - bbox.y0, 4 * width, &imgt);
598
 
        }
599
 
 
600
 
        g_free(px);
601
 
    }
602
 
 
603
 
    fprintf(_stream, "showpage\n");
604
 
    int const res = fprintf(_stream, "%%%%EOF\n");
605
 
 
606
 
    /* Flush stream to be sure. */
607
 
    (void) fflush(_stream);
608
 
 
609
 
    char c;
610
 
    /* If font embedding... */
611
 
    if(mod->get_param_bool("fontEmbedded"))
612
 
    {
613
 
        /* Close the document setup section that had been started (because all the needed resources are supposed to be included now) */
614
 
       /*res = */fprintf(_begin_stream, "%s", "%%EndSetup\n");
615
 
       /* If font embedding requested, the following PS script part was printed to a different file from the prolog/setup, so script part (current _stream) needs to be copied to prolog/setup file to get the complete (E)PS document */
616
 
       if(fseek(_stream, 0, SEEK_SET) == 0)
617
 
       {
618
 
           while((c = fgetc(_stream))!=EOF) fputc(c, _begin_stream);
619
 
       }
620
 
       fclose(_stream);
621
 
       _stream = _begin_stream;
622
 
    }
623
 
 
624
 
    /* fixme: should really use pclose for popen'd streams */
625
 
    fclose(_stream);
626
 
    _stream = NULL;
627
 
 
628
 
    _latin1_encoded_fonts.clear();
629
 
 
630
 
    g_tree_destroy(_fonts);
631
 
 
632
 
    return res;
633
 
}
634
 
 
635
 
unsigned int
636
 
PrintPS::bind(Inkscape::Extension::Print */*mod*/, Geom::Matrix const *transform, float /*opacity*/)
637
 
{
638
 
    if (!_stream) return 0;  // XXX: fixme, returning -1 as unsigned.
639
 
    if (_bitmap) return 0;
640
 
 
641
 
    Inkscape::SVGOStringStream os;
642
 
    os << "gsave [" << (*transform)[0] << " "
643
 
       << (*transform)[1] << " "
644
 
       << (*transform)[2] << " "
645
 
       << (*transform)[3] << " "
646
 
       << (*transform)[4] << " "
647
 
       << (*transform)[5] << "] concat\n";
648
 
 
649
 
    return fprintf(_stream, "%s", os.str().c_str());
650
 
}
651
 
 
652
 
unsigned int
653
 
PrintPS::release(Inkscape::Extension::Print */*mod*/)
654
 
{
655
 
    if (!_stream) return 0; // XXX: fixme, returning -1 as unsigned.
656
 
    if (_bitmap) return 0;
657
 
 
658
 
    return fprintf(_stream, "grestore\n");
659
 
}
660
 
 
661
 
unsigned int
662
 
PrintPS::comment(Inkscape::Extension::Print */*mod*/, char const *comment)
663
 
{
664
 
    if (!_stream) return 0; // XXX: fixme, returning -1 as unsigned.
665
 
    if (_bitmap) return 0;
666
 
 
667
 
    return fprintf(_stream, "%%! %s\n",comment);
668
 
}
669
 
 
670
 
void
671
 
PrintPS::print_fill_style(SVGOStringStream &os, SPStyle const *const style, NRRect const *pbox)
672
 
{
673
 
    g_return_if_fail( style->fill.isColor()
674
 
                      || ( style->fill.isPaintserver()
675
 
                           && SP_IS_GRADIENT(SP_STYLE_FILL_SERVER(style)) ) );
676
 
 
677
 
    if (style->fill.isColor()) {
678
 
        float rgb[3];
679
 
        sp_color_get_rgb_floatv(&style->fill.value.color, rgb);
680
 
 
681
 
        os << rgb[0] << " " << rgb[1] << " " << rgb[2] << " setrgbcolor\n";
682
 
 
683
 
    } else {
684
 
        g_assert( style->fill.isPaintserver()
685
 
                  && SP_IS_GRADIENT(SP_STYLE_FILL_SERVER(style)) );
686
 
 
687
 
        if (SP_IS_LINEARGRADIENT(SP_STYLE_FILL_SERVER(style))) {
688
 
 
689
 
            SPLinearGradient *lg = SP_LINEARGRADIENT(SP_STYLE_FILL_SERVER(style));
690
 
            Geom::Point p1 (lg->x1.computed, lg->y1.computed);
691
 
            Geom::Point p2 (lg->x2.computed, lg->y2.computed);
692
 
            if (pbox && SP_GRADIENT(lg)->units == SP_GRADIENT_UNITS_OBJECTBOUNDINGBOX) {
693
 
                // convert to userspace
694
 
                Geom::Matrix bbox2user(pbox->x1 - pbox->x0, 0, 0, pbox->y1 - pbox->y0, pbox->x0, pbox->y0);
695
 
                p1 *= bbox2user;
696
 
                p2 *= bbox2user;
697
 
            }
698
 
 
699
 
            os << "<<\n/ShadingType 2\n/ColorSpace /DeviceRGB\n";
700
 
            os << "/Coords [" << p1[Geom::X] << " " << p1[Geom::Y] << " " << p2[Geom::X] << " " << p2[Geom::Y] <<"]\n";
701
 
            os << "/Extend [true true]\n";
702
 
            os << "/Domain [0 1]\n";
703
 
            os << "/Function <<\n/FunctionType 3\n/Functions\n[\n";
704
 
 
705
 
            sp_gradient_ensure_vector(SP_GRADIENT(lg)); // when exporting from commandline, vector is not built
706
 
            for (unsigned i = 0; i + 1 < lg->vector.stops.size(); i++) {
707
 
                float rgb[3];
708
 
                sp_color_get_rgb_floatv(&lg->vector.stops[i].color, rgb);
709
 
                os << "<<\n/FunctionType 2\n/Domain [0 1]\n";
710
 
                os << "/C0 [" << rgb[0] << " " << rgb[1] << " " << rgb[2] << "]\n";
711
 
                sp_color_get_rgb_floatv(&lg->vector.stops[i+1].color, rgb);
712
 
                os << "/C1 [" << rgb[0] << " " << rgb[1] << " " << rgb[2] << "]\n";
713
 
                os << "/N 1\n>>\n";
714
 
            }
715
 
            os << "]\n/Domain [0 1]\n";
716
 
            os << "/Bounds [ ";
717
 
            for (unsigned i = 0; i + 2 < lg->vector.stops.size(); i++) {
718
 
                os << lg->vector.stops[i+1].offset <<" ";
719
 
            }
720
 
            os << "]\n";
721
 
            os << "/Encode [ ";
722
 
            for (unsigned i = 0; i + 1 < lg->vector.stops.size(); i++) {
723
 
                os << "0 1 ";
724
 
            }
725
 
            os << "]\n";
726
 
            os << ">>\n>>\n";
727
 
 
728
 
        } else if (SP_IS_RADIALGRADIENT(SP_STYLE_FILL_SERVER(style))) {
729
 
 
730
 
            SPRadialGradient *rg = SP_RADIALGRADIENT(SP_STYLE_FILL_SERVER(style));
731
 
            Geom::Point c(rg->cx.computed, rg->cy.computed);
732
 
            Geom::Point f(rg->fx.computed, rg->fy.computed);
733
 
            double r = rg->r.computed;
734
 
            if (pbox && SP_GRADIENT(rg)->units == SP_GRADIENT_UNITS_OBJECTBOUNDINGBOX) {
735
 
                // convert to userspace
736
 
                Geom::Matrix const bbox2user(pbox->x1 - pbox->x0, 0,
737
 
                                           0, pbox->y1 - pbox->y0,
738
 
                                           pbox->x0, pbox->y0);
739
 
                c *= bbox2user;
740
 
                f *= bbox2user;
741
 
                r *= bbox2user.descrim();
742
 
            }
743
 
 
744
 
            os << "<<\n/ShadingType 3\n/ColorSpace /DeviceRGB\n";
745
 
            os << "/Coords ["<< f[Geom::X] <<" "<< f[Geom::Y] <<" 0 "<< c[Geom::X] <<" "<< c[Geom::Y] <<" "<< r <<"]\n";
746
 
            os << "/Extend [true true]\n";
747
 
            os << "/Domain [0 1]\n";
748
 
            os << "/Function <<\n/FunctionType 3\n/Functions\n[\n";
749
 
 
750
 
            sp_gradient_ensure_vector(SP_GRADIENT(rg)); // when exporting from commandline, vector is not built
751
 
            for (unsigned i = 0; i + 1 < rg->vector.stops.size(); i++) {
752
 
                float rgb[3];
753
 
                sp_color_get_rgb_floatv(&rg->vector.stops[i].color, rgb);
754
 
                os << "<<\n/FunctionType 2\n/Domain [0 1]\n";
755
 
                os << "/C0 [" << rgb[0] << " " << rgb[1] << " " << rgb[2] << "]\n";
756
 
                sp_color_get_rgb_floatv(&rg->vector.stops[i+1].color, rgb);
757
 
                os << "/C1 [" << rgb[0] << " " << rgb[1] << " " << rgb[2] << "]\n";
758
 
                os << "/N 1\n>>\n";
759
 
            }
760
 
            os << "]\n/Domain [0 1]\n";
761
 
            os << "/Bounds [ ";
762
 
            for (unsigned i = 0; i + 2 < rg->vector.stops.size(); i++) {
763
 
                os << rg->vector.stops[i+1].offset << " ";
764
 
            }
765
 
            os << "]\n";
766
 
            os << "/Encode [ ";
767
 
            for (unsigned i = 0; i + 1 < rg->vector.stops.size(); i++) {
768
 
                os << "0 1 ";
769
 
            }
770
 
            os << "]\n";
771
 
            os << ">>\n>>\n";
772
 
        }
773
 
    }
774
 
}
775
 
 
776
 
void
777
 
PrintPS::print_stroke_style(SVGOStringStream &os, SPStyle const *style)
778
 
{
779
 
    float rgb[3];
780
 
    sp_color_get_rgb_floatv(&style->stroke.value.color, rgb);
781
 
 
782
 
    os << rgb[0] << " " << rgb[1] << " " << rgb[2] << " setrgbcolor\n";
783
 
 
784
 
    // There are rare cases in which for a solid line stroke_dasharray_set is true. To avoid
785
 
    // invalid PS-lines such as "[0.0000000 0.0000000] 0.0000000 setdash", which should be "[] 0 setdash",
786
 
    // we first check if all components of stroke_dash.dash are 0.
787
 
    bool LineSolid = true;
788
 
    if (style->stroke_dash.n_dash   &&
789
 
        style->stroke_dash.dash       )
790
 
    {
791
 
        int i = 0;
792
 
        while (LineSolid && (i < style->stroke_dash.n_dash)) {
793
 
                if (style->stroke_dash.dash[i] > 0.00000001)
794
 
                    LineSolid = false;
795
 
                i++;
796
 
        }
797
 
        if (!LineSolid) {
798
 
            os << "[";
799
 
            for (i = 0; i < style->stroke_dash.n_dash; i++) {
800
 
                if (i > 0) {
801
 
                    os << " ";
802
 
                }
803
 
                os << style->stroke_dash.dash[i];
804
 
            }
805
 
            os << "] " << style->stroke_dash.offset << " setdash\n";
806
 
        } else {
807
 
            os << "[] 0 setdash\n";
808
 
        }
809
 
    } else {
810
 
        os << "[] 0 setdash\n";
811
 
    }
812
 
 
813
 
    os << style->stroke_width.computed << " setlinewidth\n";
814
 
    os << style->stroke_linejoin.computed << " setlinejoin\n";
815
 
    os << style->stroke_linecap.computed << " setlinecap\n";
816
 
}
817
 
 
818
 
 
819
 
unsigned int
820
 
PrintPS::fill(Inkscape::Extension::Print *mod, Geom::PathVector const &pathv, Geom::Matrix const *ctm, SPStyle const *const style,
821
 
              NRRect const *pbox, NRRect const *dbox, NRRect const *bbox)
822
 
{
823
 
    if (!_stream) return 0; // XXX: fixme, returning -1 as unsigned.
824
 
    if (_bitmap) return 0;
825
 
 
826
 
    if ( style->fill.isColor()
827
 
         || ( style->fill.isPaintserver()
828
 
              && SP_IS_GRADIENT(SP_STYLE_FILL_SERVER(style)) ) )
829
 
    {
830
 
        Inkscape::SVGOStringStream os;
831
 
 
832
 
        os << "gsave\n";
833
 
 
834
 
        print_fill_style(os, style, pbox);
835
 
 
836
 
        print_pathvector(os, pathv);
837
 
 
838
 
        if (style->fill_rule.computed == SP_WIND_RULE_EVENODD) {
839
 
            if (style->fill.isColor()) {
840
 
                os << "eofill\n";
841
 
            } else {
842
 
                g_assert( style->fill.isPaintserver()
843
 
                          && SP_IS_GRADIENT(SP_STYLE_FILL_SERVER(style)) );
844
 
                SPGradient const *g = SP_GRADIENT(SP_STYLE_FILL_SERVER(style));
845
 
                os << "eoclip\n";
846
 
                if (g->gradientTransform_set) {
847
 
                    os << "gsave [" << g->gradientTransform[0] << " " << g->gradientTransform[1]
848
 
                        << " " << g->gradientTransform[2] << " " << g->gradientTransform[3]
849
 
                        << " " << g->gradientTransform[4] << " " << g->gradientTransform[5] << "] concat\n";
850
 
                }
851
 
                os << "shfill\n";
852
 
                if (g->gradientTransform_set) {
853
 
                    os << "grestore\n";
854
 
                }
855
 
            }
856
 
        } else {
857
 
            if (style->fill.isColor()) {
858
 
                os << "fill\n";
859
 
            } else {
860
 
                g_assert( style->fill.isPaintserver()
861
 
                          && SP_IS_GRADIENT(SP_STYLE_FILL_SERVER(style)) );
862
 
                SPGradient const *g = SP_GRADIENT(SP_STYLE_FILL_SERVER(style));
863
 
                os << "clip\n";
864
 
                if (g->gradientTransform_set) {
865
 
                    os << "gsave [" << g->gradientTransform[0] << " " << g->gradientTransform[1]
866
 
                        << " " << g->gradientTransform[2] << " " << g->gradientTransform[3]
867
 
                        << " " << g->gradientTransform[4] << " " << g->gradientTransform[5] << "] concat\n";
868
 
                }
869
 
                os << "shfill\n";
870
 
                if (g->gradientTransform_set) {
871
 
                    os << "grestore\n";
872
 
                }
873
 
            }
874
 
        }
875
 
 
876
 
        os << "grestore\n";
877
 
 
878
 
        fprintf(_stream, "%s", os.str().c_str());
879
 
    }
880
 
 
881
 
    return 0;
882
 
}
883
 
 
884
 
 
885
 
unsigned int
886
 
PrintPS::stroke(Inkscape::Extension::Print *mod, Geom::PathVector const &pathv, Geom::Matrix const *ctm, SPStyle const *style,
887
 
                NRRect const *pbox, NRRect const *dbox, NRRect const *bbox)
888
 
{
889
 
    if (!_stream) return 0; // XXX: fixme, returning -1 as unsigned.
890
 
    if (_bitmap) return 0;
891
 
 
892
 
    if (style->stroke.isColor()) {
893
 
        Inkscape::SVGOStringStream os;
894
 
 
895
 
        print_stroke_style(os, style);
896
 
 
897
 
        print_pathvector(os, pathv);
898
 
 
899
 
        os << "stroke\n";
900
 
 
901
 
        fprintf(_stream, "%s", os.str().c_str());
902
 
    }
903
 
 
904
 
    return 0;
905
 
}
906
 
 
907
 
unsigned int
908
 
PrintPS::image(Inkscape::Extension::Print *mod, guchar *px, unsigned int w, unsigned int h, unsigned int rs,
909
 
               Geom::Matrix const *transform, SPStyle const *style)
910
 
{
911
 
    if (!_stream) return 0; // XXX: fixme, returning -1 as unsigned.
912
 
    if (_bitmap) return 0;
913
 
 
914
 
    return print_image(_stream, px, w, h, rs, transform);
915
 
}
916
 
 
917
 
/* PSFontName is now useless (cf. text() method code) */
918
 
char const *
919
 
PrintPS::PSFontName(SPStyle const *style)
920
 
{
921
 
    font_instance *tf = font_factory::Default()->FaceFromStyle(style);
922
 
 
923
 
    char const *n;
924
 
    char name_buf[256];
925
 
 
926
 
    // PS does not like spaces in fontnames, replace them with the usual dashes.
927
 
 
928
 
    if (tf) {
929
 
        tf->PSName(name_buf, sizeof(name_buf));
930
 
        n = g_strdelimit(name_buf, " ", '-');
931
 
        tf->Unref();
932
 
    } else {
933
 
        // this system does not have this font, so just use the name from SVG in the hope that PS interpreter will make sense of it
934
 
        bool i = (style->font_style.value == SP_CSS_FONT_STYLE_ITALIC);
935
 
        bool o = (style->font_style.value == SP_CSS_FONT_STYLE_OBLIQUE);
936
 
        bool b = (style->font_weight.value == SP_CSS_FONT_WEIGHT_BOLD) ||
937
 
            (style->font_weight.value >= SP_CSS_FONT_WEIGHT_500 && style->font_weight.value <= SP_CSS_FONT_WEIGHT_900);
938
 
 
939
 
        n = g_strdup_printf("%s%s%s%s",
940
 
                            g_strdelimit(style->text->font_family.value, " ", '-'), 
941
 
                            (b || i || o) ? "-" : "",
942
 
                            (b) ? "Bold" : "",
943
 
                            (i) ? "Italic" : ((o) ? "Oblique" : "") );
944
 
    }
945
 
 
946
 
    return g_strdup(n);
947
 
}
948
 
 
949
 
//LSB = Least Significant Byte
950
 
//converts 4-byte array to "LSB first" to "LSB last"
951
 
/**
952
 
* (Used by PrintPS::embed_t1 (from libgnomeprint/gnome-font-face.c),
953
 
* to get the length of data segment (bytes 3-6 in IBM PC (PostScript) font file format.
954
 
* Reference: Adobe technical note 5040, "Supporting Downloadable PostScript
955
 
* Language Fonts", page 9)
956
 
*/
957
 
 
958
 
#define INT32_LSB_2_5(q) ((q)[2] + ((q)[3] << 8) + ((q)[4] << 16) + ((q)[5] << 24))
959
 
 
960
 
/**
961
 
* \brief For "Type 1" font only, print font data in output stream, to embed font data in PS output.
962
 
* \param os Stream of output.
963
 
* \param font Font whose data to embed.
964
 
* \return FALSE if font embedding canceled (due to error or not supported font type), TRUE otherwise
965
 
* TODO: enable font embedding for True Type
966
 
*/
967
 
//adapted more/less from libgnomeprint/gnome_font_face_ps_embed_t1()
968
 
bool
969
 
PrintPS::embed_t1 (SVGOStringStream &os, font_instance* font)
970
 
{
971
 
        //check font type
972
 
        FT_Face font_face = pango_ft2_font_get_face(font->pFont);
973
 
        const FT_String* font_type = FT_Get_X11_Font_Format(font_face);
974
 
        g_return_val_if_fail (_fontTypesMap[font_type] == FONT_TYPE1, false);
975
 
        //get font filename, stream to font file and size
976
 
        FT_Stream font_stream = font_face->stream;
977
 
        const char* font_filename = (char*) font_stream->pathname.pointer;
978
 
        unsigned long font_stream_size = font_stream->size;
979
 
        //first detect if font file is in IBM PC format
980
 
        /**
981
 
        * if first byte is 0x80, font file is pfb, do the same as a pfb to pfa converter
982
 
        * Reference: Adobe technical note 5040, "Supporting Downloadable PostScript
983
 
        * Language Fonts", page 9
984
 
        * else: include all the ASCII data in the font pfa file
985
 
        **/
986
 
        char* buf = new char[7];
987
 
        unsigned char* buffer = new unsigned char[7];//for the 6 header bytes (data segment length is unknown at this point) and final '\0'
988
 
        std::string ascii_data;//for data segment "type 1" in IBM PC Format
989
 
        //read the 6 header bytes
990
 
        //for debug: g_warning("Reading from font file %s...", font_filename);
991
 
        font_stream->close(font_stream);
992
 
        ifstream font_file (font_filename, ios::in|ios::binary);
993
 
        if (!font_file.is_open()) {
994
 
                g_warning ("file %s: line %d: Cannot open font file %s", __FILE__, __LINE__, font_filename);
995
 
                return false;
996
 
        }
997
 
        font_file.read(buf, 6);
998
 
        buffer = (unsigned char*) buf;
999
 
 
1000
 
        //If font file is pfb, do the same as pfb to pfa converter
1001
 
        //check byte 1
1002
 
        if (buffer[0] == 0x80) {
1003
 
                const char hextab[17] = "0123456789abcdef";
1004
 
                unsigned long offset = 0;
1005
 
 
1006
 
                while (offset < font_stream_size) {
1007
 
                        gint length, i;
1008
 
                        if (buffer[0] != 0x80) {
1009
 
                                g_warning ("file %s: line %d: Corrupt %s", __FILE__, __LINE__, font_filename);
1010
 
                                //TODO: print some default font data anyway like libgnomeprint/gnome_font_face_ps_embed_empty
1011
 
                                return false;
1012
 
                        }
1013
 
                        switch (buffer[1]) {
1014
 
                        case 1:
1015
 
                                //get data segment length from bytes 3-6
1016
 
                                //(Note: byte 1 is first byte in comments to match Adobe technical note 5040, but index 0 in code)
1017
 
                                length = INT32_LSB_2_5 (buffer);
1018
 
                                offset += 6;
1019
 
                                //resize the buffer to fit the data segment length
1020
 
                                delete [] buf;
1021
 
                                buf = new char[length + 1];
1022
 
                                buffer = new unsigned char[length + 1];
1023
 
                                //read and print all the data segment length
1024
 
                                font_file.read(buf, length);
1025
 
                                buffer = (unsigned char*) buf;
1026
 
                                /**
1027
 
                                * Assigning a part from the buffer of length "length" ensures
1028
 
                                * that no incorrect extra character will be printed and make the PS output invalid
1029
 
                                * That was the case with the code:
1030
 
                                * os << buffer;
1031
 
                                * (A substring method could have been used as well.)
1032
 
                                */
1033
 
                                ascii_data.assign(buf, 0, length);
1034
 
                                os << ascii_data;
1035
 
                                offset += length;
1036
 
                                //read next 6 header bytes
1037
 
                                font_file.read(buf, 6);
1038
 
                                break;
1039
 
                        case 2:
1040
 
                                length = INT32_LSB_2_5 (buffer);
1041
 
                                offset += 6;
1042
 
                                //resize the buffer to fit the data segment length
1043
 
                                delete [] buf;
1044
 
                                buf = new char[length + 1];
1045
 
                                buffer = new unsigned char[length + 1];
1046
 
                                //read and print all the data segment length
1047
 
                                font_file.read(buf, length);
1048
 
                                buffer = (unsigned char*) buf;
1049
 
                                for (i = 0; i < length; i++) {
1050
 
                                        os << hextab[buffer[i] >> 4];
1051
 
                                        os << hextab[buffer[i] & 15];
1052
 
                                        offset += 1;
1053
 
                                        if ((i & 31) == 31 || i == length - 1)
1054
 
                                                os << "\n";
1055
 
                                }
1056
 
                                //read next 6 header bytes
1057
 
                                font_file.read(buf, 6);
1058
 
                                break;
1059
 
                        case 3:
1060
 
                                /* Finished */
1061
 
                                os << "\n";
1062
 
                                offset = font_stream_size;
1063
 
                                break;
1064
 
                        default:
1065
 
                                os << "%%%ERROR: Font file corrupted at byte " << offset << "\n";
1066
 
                                //TODO: print some default font data anyway like libgnomeprint/gnome_font_face_ps_embed_empty
1067
 
                                return false;
1068
 
                        }
1069
 
                }
1070
 
        }
1071
 
        //else: font file is pfa, include all directly
1072
 
        else {
1073
 
                //font is not in IBM PC format, all the file content can be directly printed
1074
 
                //resize buffer
1075
 
                delete [] buf;
1076
 
                buf = new char[font_stream_size + 1];
1077
 
                delete [] buffer;
1078
 
                font_file.seekg (0, ios::beg);
1079
 
                font_file.read(buf, font_stream_size);
1080
 
                /**
1081
 
                 * Assigning a part from the buffer of length "length" ensures
1082
 
                 * that no incorrect extra character will be printed and make the PS output invalid
1083
 
                 * That was the case with the code:
1084
 
                 * os << buffer;
1085
 
                 * (A substring method could have been used as well.)
1086
 
                 */
1087
 
                ascii_data.assign(buf, 0, font_stream_size);
1088
 
                os << ascii_data;
1089
 
        }
1090
 
        font_file.close();
1091
 
        delete [] buf;
1092
 
        buf = NULL;
1093
 
        buffer = NULL;// Clear buffer to prevent using invalid memory reference.
1094
 
 
1095
 
        char font_psname[256];
1096
 
        font->PSName(font_psname, sizeof(font_psname));
1097
 
        FT_Long font_num_glyphs = font_face->num_glyphs;
1098
 
        if (font_num_glyphs < 256) {
1099
 
                gint glyph;
1100
 
                /* 8-bit vector */
1101
 
                os << "(" << font_psname << ") cvn findfont dup length dict begin\n";
1102
 
                os << "{1 index /FID ne {def} {pop pop} ifelse} forall\n";
1103
 
                os << "/Encoding [\n";
1104
 
                for (glyph = 0; glyph < 256; glyph++) {
1105
 
                        guint g;
1106
 
                        gchar c[256];
1107
 
                        FT_Error status;
1108
 
                        g = (glyph < font_num_glyphs) ? glyph : 0;
1109
 
                        status = FT_Get_Glyph_Name (font_face, g, c, 256);
1110
 
 
1111
 
                        if (status != FT_Err_Ok) {
1112
 
                                g_warning ("file %s: line %d: Glyph %d has no name in %s", __FILE__, __LINE__, g, font_filename);
1113
 
                                g_snprintf (c, 256, ".notdef");
1114
 
                        }
1115
 
 
1116
 
                        os << "/" << c << ( ((glyph & 0xf) == 0xf)?"\n":" " );
1117
 
                }
1118
 
                os << "] def currentdict end\n";
1119
 
                //TODO: manage several font instances for same ps name like in libgnomeprint/gnome_print_ps2_set_font_real()
1120
 
                //gf_pso_sprintf (pso, "(%s) cvn exch definefont pop\n", pso->encodedname);
1121
 
                os << "(" << font_psname << ") cvn exch definefont pop\n";
1122
 
        } else {
1123
 
                gint nfonts, i, j;
1124
 
                /* 16-bit vector */
1125
 
                nfonts = (font_num_glyphs + 255) >> 8;
1126
 
 
1127
 
                os << "32 dict begin\n";
1128
 
                /* Common entries */
1129
 
                os << "/FontType 0 def\n";
1130
 
                os << "/FontMatrix [1 0 0 1 0 0] def\n";
1131
 
                os << "/FontName (" << font_psname << "-Glyph-Composite) cvn def\n";
1132
 
                os << "/LanguageLevel 2 def\n";
1133
 
 
1134
 
                /* Type 0 entries */
1135
 
                os << "/FMapType 2 def\n";
1136
 
 
1137
 
                /* Bitch 'o' bitches */
1138
 
                os << "/FDepVector [\n";
1139
 
 
1140
 
                for (i = 0; i < nfonts; i++) {
1141
 
                        os << "(" << font_psname << ") cvn findfont dup length dict begin\n";
1142
 
                        os << "{1 index /FID ne {def} {pop pop} ifelse} forall\n";
1143
 
                        os << "/Encoding [\n";
1144
 
                        for (j = 0; j < 256; j++) {
1145
 
                                gint glyph;
1146
 
                                gchar c[256];
1147
 
                                FT_Error status;
1148
 
                                glyph = 256 * i + j;
1149
 
                                if (glyph >= font_num_glyphs)
1150
 
                                        glyph = 0;
1151
 
                                status = FT_Get_Glyph_Name (font_face, glyph, c, 256);
1152
 
                                if (status != FT_Err_Ok) {
1153
 
                                        g_warning ("file %s: line %d: Glyph %d has no name in %s", __FILE__, __LINE__, glyph, font_filename);
1154
 
                                        g_snprintf (c, 256, ".notdef");
1155
 
                                }
1156
 
                                os << "/" << c << ( ((j & 0xf) == 0xf)?"\n":" " );
1157
 
                        }
1158
 
                        os << "] def\n";
1159
 
                        os << "currentdict end (" << font_psname << "-Glyph-Page-";
1160
 
                        os << std::dec << i;
1161
 
                        os << ") cvn exch definefont\n";
1162
 
                }
1163
 
                os << "] def\n";
1164
 
                os << "/Encoding [\n";
1165
 
                for (i = 0; i < 256; i++) {
1166
 
                        gint fn;
1167
 
                        fn = (i < nfonts) ? i : 0;
1168
 
                        os << std::dec << fn;
1169
 
                        os << ( ((i & 0xf) == 0xf) ? "\n" : " " );
1170
 
                }
1171
 
                os << "] def\n";
1172
 
                os << "currentdict end\n";
1173
 
                //TODO: manage several font instances for same ps name like in libgnomeprint/gnome_print_ps2_set_font_real()
1174
 
                //gf_pso_sprintf (pso, "(%s) cvn exch definefont pop\n", pso->encodedname);
1175
 
                os << "(" << font_psname << ") cvn exch definefont pop\n";
1176
 
        }
1177
 
        //font embedding completed
1178
 
        return true;
1179
 
}
1180
 
 
1181
 
 
1182
 
 
1183
 
/**
1184
 
* \brief Print font data in output stream, to embed font data in PS output.
1185
 
* \param os Stream of output.
1186
 
* \param font Font whose data to embed.
1187
 
* \return FALSE if font embedding canceled (due to error or not supported font type), TRUE otherwise
1188
 
*/
1189
 
//adapted from libgnomeprint/gnome_font_face_ps_embed()
1190
 
bool PrintPS::embed_font(SVGOStringStream &os, font_instance* font)
1191
 
{
1192
 
  //Hinted at by a comment in libgnomeprint/fcpattern_to_gp_font_entry()
1193
 
  //Determining the font type in the "Pango way"
1194
 
  FT_Face font_face = pango_ft2_font_get_face(font->pFont);
1195
 
  const FT_String* font_type = FT_Get_X11_Font_Format(font_face);
1196
 
 
1197
 
  /**
1198
 
  * Possible values of "font_type": Type 1, TrueType, etc.
1199
 
  * Embedding available only for Type 1 fonts so far.
1200
 
  */
1201
 
  //TODO: provide support for other font types (TrueType is a priority)
1202
 
  switch(_fontTypesMap[font_type])
1203
 
  {
1204
 
    case FONT_TYPE1:
1205
 
      return embed_t1 (os, font);
1206
 
    //TODO: implement TT font embedding
1207
 
    /*case FONT_TRUETYPE:
1208
 
      embed_tt (os, font);
1209
 
      break;*/
1210
 
    default:
1211
 
      g_warning("Unknown (not supported) font type for embedding: %s", font_type);
1212
 
      //TODO: embed something like in libgnomeprint/gnome_font_face_ps_embed_empty();
1213
 
      return false;
1214
 
  }
1215
 
}
1216
 
 
1217
 
 
1218
 
/**
1219
 
* \brief Converts UTF-8 string to sequence of glyph numbers for PostScript string (cf. "show" commands.).
1220
 
* \param os Stream of output.
1221
 
* \param font Font used for unicode->glyph mapping.
1222
 
* \param unistring UTF-8 encoded string to convert.
1223
 
*/
1224
 
void PrintPS::print_glyphlist(SVGOStringStream &os, font_instance* font, Glib::ustring unistring)
1225
 
{
1226
 
  //iterate through unicode chars in unistring
1227
 
  Glib::ustring::iterator unistring_iter;
1228
 
  gunichar unichar;
1229
 
  gint glyph_index, glyph_page;
1230
 
  
1231
 
  FT_Face font_face = pango_ft2_font_get_face(font->pFont);
1232
 
  FT_Long font_num_glyphs = font_face->num_glyphs;
1233
 
  //whether font has more than one glyph pages (16-bit encoding)
1234
 
  bool two_bytes_encoded = (font_num_glyphs > 255);
1235
 
 
1236
 
  for (unistring_iter = unistring.begin();   unistring_iter!=unistring.end();  unistring_iter++)
1237
 
  {
1238
 
    //get unicode char
1239
 
    unichar = *unistring_iter;
1240
 
    //get matching glyph index in current font for unicode char
1241
 
    //default glyph index is 0 for undefined font character (glyph unavailable)
1242
 
    //TODO: if glyph unavailable for current font, use a default font among the most Unicode-compliant - e.g. Bitstream Cyberbit - I guess
1243
 
    glyph_index = font->MapUnicodeChar(unichar);
1244
 
    //if more than one glyph pages for current font (16-bit encoding),
1245
 
    if(two_bytes_encoded)
1246
 
    {
1247
 
      //add glyph page before glyph index.
1248
 
      glyph_page = (glyph_index >> 8) & 0xff;
1249
 
      os << "\\";
1250
 
      //convert in octal code before printing
1251
 
      os << std::oct << glyph_page;
1252
 
    }
1253
 
    //(If one page - 8-bit encoding -, nothing to add.)
1254
 
    //TODO: explain the following line inspired from libgnomeprint/gnome_print_ps2_glyphlist()
1255
 
    glyph_index = glyph_index & 0xff;
1256
 
    //TODO: mark glyph as used for current font, if Inkscape has to embed minimal font data in PS
1257
 
    os << "\\";
1258
 
    //convert in octal code before printing
1259
 
    os << std::oct << glyph_index;
1260
 
  }
1261
 
}
1262
 
 
1263
 
unsigned int
1264
 
PrintPS::text(Inkscape::Extension::Print *mod, char const *text, Geom::Point p,
1265
 
              SPStyle const *const style)
1266
 
{
1267
 
    if (!_stream) return 0; // XXX: fixme, returning -1 as unsigned.
1268
 
    if (_bitmap) return 0;
1269
 
 
1270
 
    //check whether fonts have to be embedded in the PS output
1271
 
    //if not, use the former way of Inkscape to print text
1272
 
    gboolean font_embedded = mod->fontEmbedded();
1273
 
 
1274
 
    Inkscape::SVGOStringStream os;
1275
 
    //find font
1276
 
    /**
1277
 
    * A font_instance object is necessary for the next steps,
1278
 
    * that's why using PSFontName() method just to get the PS fontname
1279
 
    * is not enough and not appropriate
1280
 
    */
1281
 
    font_instance *tf = font_factory::Default()->FaceFromStyle(style);
1282
 
    
1283
 
    const gchar *fn = NULL;
1284
 
    char name_buf[256];
1285
 
 
1286
 
    //check whether font was found
1287
 
    /**
1288
 
    * This check is not strictly reliable
1289
 
    * since Inkscape returns a default font if font not found.
1290
 
    * This is just to be consistent with the method PSFontName().
1291
 
    */
1292
 
    if (tf) {
1293
 
        //get font PS name
1294
 
        tf->PSName(name_buf, sizeof(name_buf));
1295
 
        fn = name_buf;
1296
 
    } else {
1297
 
        // this system does not have this font, so cancel font embedding...
1298
 
        font_embedded = FALSE;
1299
 
        //this case seems to never happen since Inkscape uses a default font instead (like BitstreamVeraSans on Windows)
1300
 
        g_warning("Font %s not found.", fn);
1301
 
        //...and just use the name from SVG in the hope that PS interpreter will make sense of it
1302
 
        bool i = (style->font_style.value == SP_CSS_FONT_STYLE_ITALIC);
1303
 
        bool o = (style->font_style.value == SP_CSS_FONT_STYLE_OBLIQUE);
1304
 
        bool b = (style->font_weight.value == SP_CSS_FONT_WEIGHT_BOLD) ||
1305
 
            (style->font_weight.value >= SP_CSS_FONT_WEIGHT_500 && style->font_weight.value <= SP_CSS_FONT_WEIGHT_900);
1306
 
 
1307
 
        fn = g_strdup_printf("%s%s%s%s",
1308
 
                            g_strdelimit(style->text->font_family.value, " ", '-'),
1309
 
                            (b || i || o) ? "-" : "",
1310
 
                            (b) ? "Bold" : "",
1311
 
                            (i) ? "Italic" : ((o) ? "Oblique" : "") );
1312
 
    }
1313
 
 
1314
 
    /**
1315
 
    * If font embedding is requested, tempt to embed the font the first time it is used, once and for all.
1316
 
    * There is no selection of the glyph descriptions to embed, based on the characters used effectively in the document.
1317
 
    * (TODO?)
1318
 
    * Else, back to the former way of printing.
1319
 
    */
1320
 
    gpointer  is_embedded;
1321
 
    //if not first time the font is used and if font embedding requested, check whether the font has been embedded (successfully the first time).
1322
 
    if(g_tree_lookup_extended(_fonts, fn, NULL, &is_embedded)) font_embedded = font_embedded && (strcmp((char *)is_embedded, "TRUE") == 0);
1323
 
    else
1324
 
    {
1325
 
      //first time the font is used
1326
 
      if(font_embedded)
1327
 
      {
1328
 
        //embed font in PS output
1329
 
        //adapted from libgnomeprint/gnome_print_ps2_close()
1330
 
        os << "%%BeginResource: font " << fn << "\n";
1331
 
        font_embedded = embed_font(os, tf);
1332
 
        os << "%%EndResource: font " << fn << "\n";
1333
 
        if(!font_embedded) g_warning("Font embedding canceled for font: %s", fn);
1334
 
        else fprintf(_begin_stream, "%s", os.str().c_str());
1335
 
        //empty os before resume printing to the script stream
1336
 
        std::string clrstr = "";
1337
 
        os.str(clrstr);
1338
 
 
1339
 
      }
1340
 
      //add to the list
1341
 
      g_tree_insert(_fonts, g_strdup(fn), g_strdup((font_embedded)?"TRUE":"FALSE"));
1342
 
    }
1343
 
    
1344
 
    Glib::ustring s;
1345
 
    // Escape chars
1346
 
    Inkscape::SVGOStringStream escaped_text;
1347
 
    //if font embedding, all characters will be converted to glyph indices (cf. PrintPS::print_glyphlist()),
1348
 
    //so no need to escape characters
1349
 
    //else back to the old way, i.e. escape chars: '\',')','(' and UTF-8 ones
1350
 
    if(font_embedded) s = text;
1351
 
    else {
1352
 
        escaped_text << std::oct;
1353
 
        for (gchar const *p_text = text ; *p_text ; p_text = g_utf8_next_char(p_text)) {
1354
 
                gunichar const c = g_utf8_get_char(p_text);
1355
 
                if (c == '\\' || c == ')' || c == '(')
1356
 
                escaped_text << '\\' << static_cast<char>(c);
1357
 
                else if (c >= 0x80)
1358
 
                escaped_text << '\\' << c;
1359
 
                else
1360
 
                escaped_text << static_cast<char>(c);
1361
 
        }
1362
 
    }
1363
 
 
1364
 
    os << "gsave\n";
1365
 
 
1366
 
    // set font
1367
 
    if(font_embedded) os << "/" << fn << " findfont\n";
1368
 
    else {
1369
 
        if (_latin1_encoded_fonts.find(fn) == _latin1_encoded_fonts.end()) {
1370
 
                if (!_newlatin1font_proc_defined) {
1371
 
                // input: newfontname, existingfontname
1372
 
                // output: new font object, also defined to newfontname
1373
 
                os << "/newlatin1font "         // name of the proc
1374
 
                        "{findfont dup length dict copy "     // load the font and create a copy of it
1375
 
                        "dup /Encoding ISOLatin1Encoding put "     // change the encoding in the copy
1376
 
                        "definefont} def\n";      // create the new font and leave it on the stack, define the proc
1377
 
                _newlatin1font_proc_defined = true;
1378
 
                }
1379
 
                if(strchr(fn, ' ') == NULL)
1380
 
                        os << "/" << fn << "-ISOLatin1 /" << fn << " newlatin1font\n";
1381
 
                else
1382
 
                        os << "(/" << fn << "-ISOLatin1) (/" << fn << ") newlatin1font\n";
1383
 
                _latin1_encoded_fonts.insert(fn);
1384
 
        } else
1385
 
                if(strchr(fn, ' ') == NULL)
1386
 
                        os << "/" << fn << "-ISOLatin1 findfont\n";
1387
 
                else
1388
 
                        os << "(/" << fn << "-ISOLatin1) findfont\n";
1389
 
    }
1390
 
    os << style->font_size.computed << " scalefont\n";
1391
 
    os << "setfont\n";
1392
 
   //The commented line beneath causes Inkscape to crash under Linux but not under Windows
1393
 
    //g_free((void*) fn);
1394
 
 
1395
 
    if ( style->fill.isColor()
1396
 
         || ( style->fill.isPaintserver()
1397
 
              && SP_IS_GRADIENT(SP_STYLE_FILL_SERVER(style)) ) )
1398
 
    {
1399
 
        // set fill style
1400
 
        print_fill_style(os, style, NULL);
1401
 
        // FIXME: we don't know the pbox of text, so have to pass NULL. This means gradients with
1402
 
        // bbox units won't work with text. However userspace gradients don't work with text either
1403
 
        // (text is black) for some reason.
1404
 
 
1405
 
        os << "newpath\n";
1406
 
        os << p[Geom::X] << " " << p[Geom::Y] << " moveto\n";
1407
 
        os << "(";
1408
 
        if(font_embedded) print_glyphlist(os, tf, s);
1409
 
        else os << escaped_text.str();
1410
 
        os << ") show\n";
1411
 
    }
1412
 
 
1413
 
    if (style->stroke.isColor()) {
1414
 
 
1415
 
        // set stroke style
1416
 
        print_stroke_style(os, style);
1417
 
 
1418
 
        // paint stroke
1419
 
        os << "newpath\n";
1420
 
        os << p[Geom::X] << " " << p[Geom::Y] << " moveto\n";
1421
 
        os << "(";
1422
 
        if(font_embedded) print_glyphlist(os, tf, s);
1423
 
        else os << escaped_text.str();
1424
 
        os << ") false charpath stroke\n";
1425
 
    }
1426
 
 
1427
 
    if(tf) tf->Unref();
1428
 
 
1429
 
    os << "grestore\n";
1430
 
 
1431
 
    fprintf(_stream, "%s", os.str().c_str());
1432
 
 
1433
 
    return 0;
1434
 
}
1435
 
 
1436
 
 
1437
 
 
1438
 
/* PostScript helpers */
1439
 
 
1440
 
void
1441
 
PrintPS::print_pathvector(SVGOStringStream &os, Geom::PathVector const &pathv)
1442
 
{
1443
 
    if (pathv.empty())
1444
 
        return;
1445
 
 
1446
 
    os << "newpath\n";
1447
 
 
1448
 
    for(Geom::PathVector::const_iterator it = pathv.begin(); it != pathv.end(); ++it) {
1449
 
 
1450
 
        os << it->initialPoint()[Geom::X] << " " << it->initialPoint()[Geom::Y] << " moveto\n";
1451
 
 
1452
 
        for(Geom::Path::const_iterator cit = it->begin(); cit != it->end_open(); ++cit) {
1453
 
            print_2geomcurve(os, *cit);
1454
 
        }
1455
 
 
1456
 
        if (it->closed()) {
1457
 
            os << "closepath\n";
1458
 
        }
1459
 
 
1460
 
    }
1461
 
}
1462
 
 
1463
 
void
1464
 
PrintPS::print_2geomcurve(SVGOStringStream &os, Geom::Curve const & c )
1465
 
{
1466
 
    using Geom::X;
1467
 
    using Geom::Y;
1468
 
 
1469
 
    if( is_straight_curve(c) )
1470
 
    {
1471
 
        os << c.finalPoint()[X] << " " << c.finalPoint()[Y] << " lineto\n";
1472
 
    }
1473
 
    else if(Geom::CubicBezier const *cubic_bezier = dynamic_cast<Geom::CubicBezier const*>(&c)) {
1474
 
        std::vector<Geom::Point> points = cubic_bezier->points();
1475
 
        os << points[1][X] << " " << points[1][Y] << " "
1476
 
           << points[2][X] << " " << points[2][Y] << " "
1477
 
           << points[3][X] << " " << points[3][Y] << " curveto\n";
1478
 
    }
1479
 
    else {
1480
 
        //this case handles sbasis as well as all other curve types
1481
 
        Geom::Path sbasis_path = Geom::cubicbezierpath_from_sbasis(c.toSBasis(), 0.1);
1482
 
 
1483
 
        for(Geom::Path::iterator iter = sbasis_path.begin(); iter != sbasis_path.end(); ++iter) {
1484
 
            print_2geomcurve(os, *iter);
1485
 
        }
1486
 
    }
1487
 
}
1488
 
 
1489
 
 
1490
 
/* The following code is licensed under GNU GPL.
1491
 
** The packbits, ascii85 and imaging printing code
1492
 
** is from the gimp's postscript.c.
1493
 
*/
1494
 
 
1495
 
/**
1496
 
* \param nin Number of bytes of source data.
1497
 
* \param src Source data.
1498
 
* \param nout Number of output bytes.
1499
 
* \param dst Buffer for output.
1500
 
*/
1501
 
void
1502
 
PrintPS::compress_packbits(int nin,
1503
 
                           guchar *src,
1504
 
                           int *nout,
1505
 
                           guchar *dst)
1506
 
 
1507
 
{
1508
 
    register guchar c;
1509
 
    int nrepeat, nliteral;
1510
 
    guchar *run_start;
1511
 
    guchar *start_dst = dst;
1512
 
    guchar *last_literal = NULL;
1513
 
 
1514
 
    for (;;) {
1515
 
        if (nin <= 0) break;
1516
 
 
1517
 
        run_start = src;
1518
 
        c = *run_start;
1519
 
 
1520
 
        /* Search repeat bytes */
1521
 
        if ((nin > 1) && (c == src[1])) {
1522
 
            nrepeat = 1;
1523
 
            nin -= 2;
1524
 
            src += 2;
1525
 
            while ((nin > 0) && (c == *src)) {
1526
 
                nrepeat++;
1527
 
                src++;
1528
 
                nin--;
1529
 
                if (nrepeat == 127) break; /* Maximum repeat */
1530
 
            }
1531
 
 
1532
 
            /* Add two-byte repeat to last literal run ? */
1533
 
            if ( (nrepeat == 1)
1534
 
                 && (last_literal != NULL) && (((*last_literal)+1)+2 <= 128) )
1535
 
            {
1536
 
                *last_literal += 2;
1537
 
                *(dst++) = c;
1538
 
                *(dst++) = c;
1539
 
                continue;
1540
 
            }
1541
 
 
1542
 
            /* Add repeat run */
1543
 
            *(dst++) = (guchar)((-nrepeat) & 0xff);
1544
 
            *(dst++) = c;
1545
 
            last_literal = NULL;
1546
 
            continue;
1547
 
        }
1548
 
        /* Search literal bytes */
1549
 
        nliteral = 1;
1550
 
        nin--;
1551
 
        src++;
1552
 
 
1553
 
        for (;;) {
1554
 
            if (nin <= 0) break;
1555
 
 
1556
 
            if ((nin >= 2) && (src[0] == src[1])) /* A two byte repeat ? */
1557
 
                break;
1558
 
 
1559
 
            nliteral++;
1560
 
            nin--;
1561
 
            src++;
1562
 
            if (nliteral == 128) break; /* Maximum literal run */
1563
 
        }
1564
 
 
1565
 
        /* Could be added to last literal run ? */
1566
 
        if ((last_literal != NULL) && (((*last_literal)+1)+nliteral <= 128)) {
1567
 
            *last_literal += nliteral;
1568
 
        } else {
1569
 
            last_literal = dst;
1570
 
            *(dst++) = (guchar)(nliteral-1);
1571
 
        }
1572
 
        while (nliteral-- > 0) *(dst++) = *(run_start++);
1573
 
    }
1574
 
    *nout = dst - start_dst;
1575
 
}
1576
 
 
1577
 
void
1578
 
PrintPS::ascii85_init(void)
1579
 
{
1580
 
    ascii85_len = 0;
1581
 
    ascii85_linewidth = 0;
1582
 
}
1583
 
 
1584
 
void
1585
 
PrintPS::ascii85_flush(SVGOStringStream &os)
1586
 
{
1587
 
    char c[5];
1588
 
    bool const zero_case = (ascii85_buf == 0);
1589
 
    static int const max_linewidth = 75;
1590
 
 
1591
 
    for (int i = 4; i >= 0; i--) {
1592
 
        c[i] = (ascii85_buf % 85) + '!';
1593
 
        ascii85_buf /= 85;
1594
 
    }
1595
 
    /* check for special case: "!!!!!" becomes "z", but only if not
1596
 
     * at end of data. */
1597
 
    if (zero_case && (ascii85_len == 4)) {
1598
 
        if (ascii85_linewidth >= max_linewidth) {
1599
 
            os << '\n';
1600
 
            ascii85_linewidth = 0;
1601
 
        }
1602
 
        os << 'z';
1603
 
        ascii85_linewidth++;
1604
 
    } else {
1605
 
        for (int i = 0; i < ascii85_len+1; i++) {
1606
 
            if ((ascii85_linewidth >= max_linewidth) && (c[i] != '%')) {
1607
 
                os << '\n';
1608
 
                ascii85_linewidth = 0;
1609
 
            }
1610
 
            os << c[i];
1611
 
            ascii85_linewidth++;
1612
 
        }
1613
 
    }
1614
 
 
1615
 
    ascii85_len = 0;
1616
 
    ascii85_buf = 0;
1617
 
}
1618
 
 
1619
 
inline void
1620
 
PrintPS::ascii85_out(guchar byte, SVGOStringStream &os)
1621
 
{
1622
 
    if (ascii85_len == 4)
1623
 
        ascii85_flush(os);
1624
 
 
1625
 
    ascii85_buf <<= 8;
1626
 
    ascii85_buf |= byte;
1627
 
    ascii85_len++;
1628
 
}
1629
 
 
1630
 
void
1631
 
PrintPS::ascii85_nout(int n, guchar *uptr, SVGOStringStream &os)
1632
 
{
1633
 
    while (n-- > 0) {
1634
 
        ascii85_out(*uptr, os);
1635
 
        uptr++;
1636
 
    }
1637
 
}
1638
 
 
1639
 
void
1640
 
PrintPS::ascii85_done(SVGOStringStream &os)
1641
 
{
1642
 
    if (ascii85_len) {
1643
 
        /* zero any unfilled buffer portion, then flush */
1644
 
        ascii85_buf <<= (8 * (4-ascii85_len));
1645
 
        ascii85_flush(os);
1646
 
    }
1647
 
 
1648
 
    os << "~>\n";
1649
 
}
1650
 
 
1651
 
unsigned int
1652
 
PrintPS::print_image(FILE *ofp, guchar *px, unsigned int width, unsigned int height, unsigned int rs,
1653
 
                     Geom::Matrix const *transform)
1654
 
{
1655
 
    Inkscape::SVGOStringStream os;
1656
 
 
1657
 
    os << "gsave\n";
1658
 
 
1659
 
    os << "[" << (*transform)[0] << " "
1660
 
       << (*transform)[1] << " "
1661
 
       << (*transform)[2] << " "
1662
 
       << (*transform)[3] << " "
1663
 
       << (*transform)[4] << " "
1664
 
       << (*transform)[5] << "] concat\n";
1665
 
 
1666
 
    /* Write read image procedure */
1667
 
    os << "<<\n";
1668
 
    os << "  /ImageType 3\n";
1669
 
    os << "  /InterleaveType 1\n";
1670
 
 
1671
 
    os << "  /MaskDict\n";
1672
 
    os << "  <<\n";
1673
 
    os << "    /ImageType 1\n";
1674
 
    os << "    /Width " << width << "\n";
1675
 
    os << "    /Height " << height << "\n";
1676
 
    os << "    /ImageMatrix "
1677
 
       << "[" << width << " "
1678
 
       << 0 << " "
1679
 
       << 0 << " "
1680
 
       << -((long) height) << " "
1681
 
       << 0 << " "
1682
 
       << height << "]\n";
1683
 
    os << "    /BitsPerComponent 8\n";
1684
 
    os << "    /Decode [1 0]\n";
1685
 
    os << "  >>\n";
1686
 
 
1687
 
    os << "  /DataDict\n";
1688
 
    os << "  <<\n";
1689
 
    os << "    /ImageType 1\n";
1690
 
    os << "    /Width " << width << "\n";
1691
 
    os << "    /Height " << height << "\n";
1692
 
    os << "    /ImageMatrix "
1693
 
       << "[" << width << " "
1694
 
       << 0 << " "
1695
 
       << 0 << " "
1696
 
       << -((long )height) << " "
1697
 
       << 0 << " "
1698
 
       << height << "]\n";
1699
 
    os << "    /DataSource currentfile /ASCII85Decode filter\n";
1700
 
    os << "    /BitsPerComponent 8\n";
1701
 
    os << "    /Decode [0 1 0 1 0 1]\n";
1702
 
    os << "  >>\n";
1703
 
 
1704
 
    os << ">>\n";
1705
 
 
1706
 
    /* Allocate buffer for packbits data. Worst case: Less than 1% increase */
1707
 
    guchar *const packb = (guchar *)g_malloc((4*width * 105)/100+2);
1708
 
    guchar *const plane = (guchar *)g_malloc(4*width);
1709
 
 
1710
 
    os << "image\n";
1711
 
 
1712
 
    ascii85_init();
1713
 
    
1714
 
    for (unsigned i = 0; i < height; i++) {
1715
 
        guchar const *const src = px + i * rs;
1716
 
 
1717
 
        guchar const *src_ptr = src;
1718
 
        guchar *plane_ptr = plane;
1719
 
        for (unsigned j = 0; j < width; j++) {
1720
 
            *(plane_ptr++) = *(src_ptr+3);
1721
 
            *(plane_ptr++) = *(src_ptr+0);
1722
 
            *(plane_ptr++) = *(src_ptr+1);
1723
 
            *(plane_ptr++) = *(src_ptr+2);
1724
 
            src_ptr += 4;
1725
 
        }
1726
 
        
1727
 
        ascii85_nout(4*width, plane, os);
1728
 
    }
1729
 
    ascii85_done(os);
1730
 
 
1731
 
    g_free(packb);
1732
 
    g_free(plane);
1733
 
 
1734
 
    os << "grestore\n";
1735
 
 
1736
 
    fprintf(ofp, "%s", os.str().c_str());
1737
 
 
1738
 
    return 0;
1739
 
}
1740
 
 
1741
 
bool
1742
 
PrintPS::textToPath(Inkscape::Extension::Print * ext)
1743
 
{
1744
 
    return ext->get_param_bool("textToPath");
1745
 
}
1746
 
 
1747
 
/**
1748
 
* \brief Get "fontEmbedded" param
1749
 
* \retval TRUE Fonts have to be embedded in the output so that the user might not need to install fonts to have the interpreter read the document correctly
1750
 
* \retval FALSE No font embedding
1751
 
*
1752
 
* Only available for Adobe Type 1 fonts in EPS output till now
1753
 
*/
1754
 
bool
1755
 
PrintPS::fontEmbedded(Inkscape::Extension::Print * ext)
1756
 
{
1757
 
    return ext->get_param_bool("fontEmbedded");
1758
 
}
1759
 
 
1760
 
#include "clear-n_.h"
1761
 
 
1762
 
void
1763
 
PrintPS::init(void)
1764
 
{
1765
 
    /* SVG in */
1766
 
    (void) Inkscape::Extension::build_from_mem(
1767
 
        "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
1768
 
        "<name>" N_("Postscript Print") "</name>\n"
1769
 
        "<id>" SP_MODULE_KEY_PRINT_PS "</id>\n"
1770
 
        "<param name=\"bitmap\" type=\"boolean\">false</param>\n"
1771
 
        "<param name=\"resolution\" type=\"string\">72</param>\n"
1772
 
        "<param name=\"destination\" type=\"string\">| lp</param>\n"
1773
 
        "<param name=\"pageBoundingBox\" type=\"boolean\">true</param>\n"
1774
 
        "<param name=\"textToPath\" type=\"boolean\">true</param>\n"
1775
 
        "<param name=\"fontEmbedded\" type=\"boolean\">false</param>\n"
1776
 
        "<print/>\n"
1777
 
        "</inkscape-extension>", new PrintPS());
1778
 
}
1779
 
 
1780
 
 
1781
 
}  /* namespace Internal */
1782
 
}  /* namespace Extension */
1783
 
}  /* namespace Inkscape */
1784
 
 
1785
 
/* End of GNU GPL code */
1786
 
 
1787
 
 
1788
 
/*
1789
 
  Local Variables:
1790
 
  mode:c++
1791
 
  c-file-style:"stroustrup"
1792
 
  c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1793
 
  indent-tabs-mode:nil
1794
 
  fill-column:99
1795
 
  End:
1796
 
*/
1797
 
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :