1 /* Ghostscript widget for GTK/GNOME
3 * Copyright (C) 1998 - 2005 the Free Software Foundation
5 * Authors: Jonathan Blandford, Jaka Mocnik, Carlos Garcia Campos
7 * Based on code by: Federico Mena (Quartic), Szekeres Istvan (Pista)
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Library General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Library General Public License for more details.
19 * You should have received a copy of the GNU Library General Public
20 * License along with this library; if not, write to the
21 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 * Boston, MA 02111-1307, USA.
27 #include <glib/gstdio.h>
28 #include <glib/gi18n.h>
29 #include <gdk/gdkpixbuf.h>
33 #include "ps-document.h"
34 #include "ps-interpreter.h"
37 #include "gsdefaults.h"
38 #include "ev-file-exporter.h"
39 #include "ev-async-renderer.h"
40 #include "ev-document-thumbnails.h"
41 #include "ev-document-misc.h"
48 gboolean structured_doc;
52 /* Document Thumbnails */
53 PSInterpreter *thumbs_gs;
55 EvRenderContext *thumbs_rc;
60 gint *ps_export_pagelist;
61 gchar *ps_export_filename;
64 struct _PSDocumentClass {
65 GObjectClass parent_class;
68 static void ps_document_document_iface_init (EvDocumentIface *iface);
69 static void ps_document_file_exporter_iface_init (EvFileExporterIface *iface);
70 static void ps_async_renderer_iface_init (EvAsyncRendererIface *iface);
71 static void ps_document_document_thumbnails_iface_init (EvDocumentThumbnailsIface *iface);
73 static void ps_interpreter_page_rendered (PSInterpreter *gs,
75 PSDocument *ps_document);
77 G_DEFINE_TYPE_WITH_CODE (PSDocument, ps_document, G_TYPE_OBJECT,
79 G_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT,
80 ps_document_document_iface_init);
81 G_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_THUMBNAILS,
82 ps_document_document_thumbnails_iface_init);
83 G_IMPLEMENT_INTERFACE (EV_TYPE_FILE_EXPORTER,
84 ps_document_file_exporter_iface_init);
85 G_IMPLEMENT_INTERFACE (EV_TYPE_ASYNC_RENDERER,
86 ps_async_renderer_iface_init);
91 ps_document_init (PSDocument *ps_document)
96 ps_document_dispose (GObject *object)
98 PSDocument *ps_document = PS_DOCUMENT (object);
100 if (ps_document->gs) {
101 g_object_unref (ps_document->gs);
102 ps_document->gs = NULL;
105 if (ps_document->thumbs_gs) {
106 g_object_unref (ps_document->thumbs_gs);
107 ps_document->thumbs_gs = NULL;
110 if (ps_document->filename) {
111 g_free (ps_document->filename);
112 ps_document->filename = NULL;
115 if (ps_document->doc) {
116 psfree (ps_document->doc);
117 ps_document->doc = NULL;
120 if (ps_document->thumbnail) {
121 g_object_unref (ps_document->thumbnail);
122 ps_document->thumbnail = NULL;
125 if (ps_document->thumbs_mutex) {
126 g_mutex_free (ps_document->thumbs_mutex);
127 ps_document->thumbs_mutex = NULL;
130 if (ps_document->thumbs_cond) {
131 g_cond_free (ps_document->thumbs_cond);
132 ps_document->thumbs_cond = NULL;
135 if (ps_document->thumbs_rc) {
136 g_object_unref (ps_document->thumbs_rc);
137 ps_document->thumbs_rc = NULL;
140 G_OBJECT_CLASS (ps_document_parent_class)->dispose (object);
144 ps_document_class_init (PSDocumentClass *klass)
146 GObjectClass *object_class;
148 object_class = G_OBJECT_CLASS (klass);
150 object_class->dispose = ps_document_dispose;
153 /* EvDocumentIface */
155 document_load (PSDocument *ps_document, const gchar *fname, GError **error)
159 ps_document->filename = g_strdup (fname);
162 * We need to make sure that the file is loadable/exists!
163 * otherwise we want to exit without loading new stuff...
165 if (!g_file_test (fname, G_FILE_TEST_IS_REGULAR)) {
168 filename_dsp = g_filename_display_name (fname);
172 _("Cannot open file “%s”.\n"), /* FIXME: remove \n after freeze */
174 g_free (filename_dsp);
179 if ((fd = fopen (ps_document->filename, "r")) == NULL) {
182 filename_dsp = g_filename_display_name (fname);
186 _("Cannot open file “%s”.\n"), /* FIXME: remove \n after freeze */
188 g_free (filename_dsp);
193 /* we grab the vital statistics!!! */
194 ps_document->doc = psscan (fd, TRUE, ps_document->filename);
196 if (!ps_document->doc)
199 ps_document->structured_doc =
200 ((!ps_document->doc->epsf && ps_document->doc->numpages > 0) ||
201 (ps_document->doc->epsf && ps_document->doc->numpages > 1));
203 ps_document->gs = ps_interpreter_new (ps_document->filename,
205 g_signal_connect (G_OBJECT (ps_document->gs), "page_rendered",
206 G_CALLBACK (ps_interpreter_page_rendered),
207 (gpointer) ps_document);
213 ps_document_load (EvDocument *document,
221 filename = g_filename_from_uri (uri, NULL, error);
225 gs_path = g_find_program_in_path ("gs");
229 filename_dsp = g_filename_display_name (filename);
233 _("Failed to load document “%s”. Ghostscript interpreter was not found in path"),
235 g_free (filename_dsp);
242 result = document_load (PS_DOCUMENT (document), filename, error);
243 if (!result && !(*error)) {
246 filename_dsp = g_filename_display_name (filename);
250 _("Failed to load document “%s”"),
252 g_free (filename_dsp);
261 save_document (PSDocument *document, const char *filename)
263 gboolean result = TRUE;
264 GtkGSDocSink *sink = gtk_gs_doc_sink_new ();
268 src_file = fopen (document->filename, "r");
270 struct stat stat_rec;
272 if (stat (document->filename, &stat_rec) == 0) {
273 pscopy (src_file, sink, 0, stat_rec.st_size - 1);
279 buf = gtk_gs_doc_sink_get_buffer (sink);
284 f = fopen (filename, "w");
293 gtk_gs_doc_sink_free (sink);
300 save_page_list (PSDocument *document, int *page_list, const char *filename)
302 gboolean result = TRUE;
303 GtkGSDocSink *sink = gtk_gs_doc_sink_new ();
307 pscopydoc (sink, document->filename,
308 document->doc, page_list);
310 buf = gtk_gs_doc_sink_get_buffer (sink);
312 f = fopen (filename, "w");
321 gtk_gs_doc_sink_free (sink);
328 ps_document_save (EvDocument *document,
332 PSDocument *ps = PS_DOCUMENT (document);
336 filename = g_filename_from_uri (uri, NULL, error);
340 result = save_document (ps, filename);
348 ps_document_get_n_pages (EvDocument *document)
350 PSDocument *ps = PS_DOCUMENT (document);
352 if (!ps->filename || !ps->doc) {
356 return ps->structured_doc ? ps->doc->numpages : 1;
360 ps_document_get_page_rotation (PSDocument *ps_document,
363 gint rotation = GTK_GS_ORIENTATION_NONE;
365 g_assert (ps_document->doc != NULL);
367 if (ps_document->structured_doc) {
368 if (ps_document->doc->pages[page].orientation != GTK_GS_ORIENTATION_NONE)
369 rotation = ps_document->doc->pages[page].orientation;
371 rotation = ps_document->doc->default_page_orientation;
374 if (rotation == GTK_GS_ORIENTATION_NONE)
375 rotation = ps_document->doc->orientation;
377 if (rotation == GTK_GS_ORIENTATION_NONE)
378 rotation = GTK_GS_ORIENTATION_PORTRAIT;
384 ps_document_get_page_size (EvDocument *document,
389 PSDocument *ps_document = PS_DOCUMENT (document);
390 int urx, ury, llx, lly;
391 gdouble pwidth, pheight;
392 gdouble page_width, page_height;
395 psgetpagebox (ps_document->doc, page, &urx, &ury, &llx, &lly);
397 pwidth = (urx - llx) + 0.5;
398 pheight = (ury - lly) + 0.5;
400 rotate = ps_document_get_page_rotation (ps_document, page);
401 if (rotate == 90 || rotate == 270) {
402 page_height = pwidth;
403 page_width = pheight;
406 page_height = pheight;
414 *height = page_height;
419 ps_document_can_get_text (EvDocument *document)
424 static EvDocumentInfo *
425 ps_document_get_info (EvDocument *document)
427 EvDocumentInfo *info;
428 PSDocument *ps = PS_DOCUMENT (document);
429 int urx, ury, llx, lly;
431 info = g_new0 (EvDocumentInfo, 1);
432 info->fields_mask = EV_DOCUMENT_INFO_TITLE |
433 EV_DOCUMENT_INFO_FORMAT |
434 EV_DOCUMENT_INFO_CREATOR |
435 EV_DOCUMENT_INFO_N_PAGES |
436 EV_DOCUMENT_INFO_PAPER_SIZE;
438 info->title = g_strdup (ps->doc->title);
439 info->format = ps->doc->epsf ? g_strdup (_("Encapsulated PostScript"))
440 : g_strdup (_("PostScript"));
441 info->creator = g_strdup (ps->doc->creator);
442 info->n_pages = ev_document_get_n_pages (document);
444 psgetpagebox (PS_DOCUMENT (document)->doc, 0, &urx, &ury, &llx, &lly);
446 info->paper_width = (urx - llx) / 72.0f * 25.4f;
447 info->paper_height = (ury - lly) / 72.0f * 25.4f;
453 ps_document_document_iface_init (EvDocumentIface *iface)
455 iface->load = ps_document_load;
456 iface->save = ps_document_save;
457 iface->can_get_text = ps_document_can_get_text;
458 iface->get_n_pages = ps_document_get_n_pages;
459 iface->get_page_size = ps_document_get_page_size;
460 iface->get_info = ps_document_get_info;
463 /* EvAsyncRendererIface */
465 ps_interpreter_page_rendered (PSInterpreter *gs,
467 PSDocument *ps_document)
469 g_signal_emit_by_name (ps_document, "render_finished", pixbuf);
473 ps_async_renderer_render_pixbuf (EvAsyncRenderer *renderer,
478 PSDocument *ps_document = PS_DOCUMENT (renderer);
480 g_return_if_fail (PS_IS_INTERPRETER (ps_document->gs));
482 rotation = (rotation + ps_document_get_page_rotation (ps_document, page)) % 360;
484 ps_interpreter_render_page (ps_document->gs, page, scale, rotation);
488 ps_async_renderer_iface_init (EvAsyncRendererIface *iface)
490 iface->render_pixbuf = ps_async_renderer_render_pixbuf;
493 /* EvDocumentThumbnailsIface */
495 ps_interpreter_thumbnail_rendered (PSInterpreter *gs,
497 PSDocument *ps_document)
499 if (ps_document->thumbnail)
500 g_object_unref (ps_document->thumbnail);
501 ps_document->thumbnail = g_object_ref (pixbuf);
503 g_cond_broadcast (ps_document->thumbs_cond);
507 ps_document_render_thumbnail (PSDocument *ps_document)
509 ps_interpreter_render_page (ps_document->thumbs_gs,
510 ps_document->thumbs_rc->page,
511 ps_document->thumbs_rc->scale,
512 ps_document->thumbs_rc->rotation);
518 ps_document_thumbnails_get_thumbnail (EvDocumentThumbnails *document_thumbnails,
524 PSDocument *ps_document;
525 GdkPixbuf *pixbuf = NULL;
526 gdouble page_width, page_height;
529 ps_document = PS_DOCUMENT (document_thumbnails);
531 g_return_val_if_fail (ps_document->filename != NULL, NULL);
532 g_return_val_if_fail (ps_document->doc != NULL, NULL);
534 if (!ps_document->thumbs_gs) {
535 ps_document->thumbs_gs = ps_interpreter_new (ps_document->filename,
537 g_signal_connect (G_OBJECT (ps_document->thumbs_gs), "page_rendered",
538 G_CALLBACK (ps_interpreter_thumbnail_rendered),
539 (gpointer) ps_document);
542 if (!ps_document->thumbs_mutex)
543 ps_document->thumbs_mutex = g_mutex_new ();
544 ps_document->thumbs_cond = g_cond_new ();
546 ps_document_get_page_size (EV_DOCUMENT (ps_document), page,
547 &page_width, &page_height);
548 scale = size / page_width;
550 rotation = (rotation + ps_document_get_page_rotation (ps_document, page)) % 360;
552 if (!ps_document->thumbs_rc) {
553 ps_document->thumbs_rc = ev_render_context_new (rotation, page, scale);
555 ev_render_context_set_page (ps_document->thumbs_rc, page);
556 ev_render_context_set_scale (ps_document->thumbs_rc, scale);
557 ev_render_context_set_rotation (ps_document->thumbs_rc, rotation);
560 ev_document_doc_mutex_unlock ();
561 g_mutex_lock (ps_document->thumbs_mutex);
562 g_idle_add ((GSourceFunc)ps_document_render_thumbnail, ps_document);
563 g_cond_wait (ps_document->thumbs_cond, ps_document->thumbs_mutex);
564 g_cond_free (ps_document->thumbs_cond);
565 ps_document->thumbs_cond = NULL;
566 g_mutex_unlock (ps_document->thumbs_mutex);
567 ev_document_doc_mutex_lock ();
569 pixbuf = ps_document->thumbnail;
570 ps_document->thumbnail = NULL;
573 GdkPixbuf *border_pixbuf;
575 border_pixbuf = ev_document_misc_get_thumbnail_frame (-1, -1, rotation, pixbuf);
576 g_object_unref (pixbuf);
577 pixbuf = border_pixbuf;
584 ps_document_thumbnails_get_dimensions (EvDocumentThumbnails *document_thumbnails,
590 PSDocument *ps_document;
591 gdouble page_width, page_height;
593 ps_document = PS_DOCUMENT (document_thumbnails);
595 ps_document_get_page_size (EV_DOCUMENT (ps_document),
597 &page_width, &page_height);
599 *height = (int) (size * page_height / page_width);
603 ps_document_document_thumbnails_iface_init (EvDocumentThumbnailsIface *iface)
605 iface->get_thumbnail = ps_document_thumbnails_get_thumbnail;
606 iface->get_dimensions = ps_document_thumbnails_get_dimensions;
609 /* EvFileExporterIface */
611 ps_document_file_exporter_format_supported (EvFileExporter *exporter,
612 EvFileExporterFormat format)
614 return (format == EV_FILE_FORMAT_PS);
618 ps_document_file_exporter_begin (EvFileExporter *exporter,
619 EvFileExporterFormat format,
620 const char *filename,
627 PSDocument *document = PS_DOCUMENT (exporter);
629 if (document->structured_doc) {
630 g_free (document->ps_export_pagelist);
632 document->ps_export_pagelist = g_new0 (int, document->doc->numpages);
635 document->ps_export_filename = g_strdup (filename);
639 ps_document_file_exporter_do_page (EvFileExporter *exporter, EvRenderContext *rc)
641 PSDocument *document = PS_DOCUMENT (exporter);
643 if (document->structured_doc) {
644 document->ps_export_pagelist[rc->page] = 1;
649 ps_document_file_exporter_end (EvFileExporter *exporter)
651 PSDocument *document = PS_DOCUMENT (exporter);
653 if (!document->structured_doc) {
654 save_document (document, document->ps_export_filename);
656 save_page_list (document, document->ps_export_pagelist,
657 document->ps_export_filename);
658 g_free (document->ps_export_pagelist);
659 g_free (document->ps_export_filename);
660 document->ps_export_pagelist = NULL;
661 document->ps_export_filename = NULL;
666 ps_document_file_exporter_iface_init (EvFileExporterIface *iface)
668 iface->format_supported = ps_document_file_exporter_format_supported;
669 iface->begin = ps_document_file_exporter_begin;
670 iface->do_page = ps_document_file_exporter_do_page;
671 iface->end = ps_document_file_exporter_end;