X-Git-Url: https://www.fi.muni.cz/~kas/git//home/kas/public_html/git/?a=blobdiff_plain;f=ps%2Fps-document.c;h=a794e9956340dd0172a8e5689a454a4ea095b806;hb=0c5e5eb759113c47b0e3973f5ac11a9d04d3a7f4;hp=4b2d4c43e36d23ef37e2466e49f3c8f39f028c9d;hpb=e8096c18ba580156072e8c84103bee6f6d3f0bfc;p=evince.git diff --git a/ps/ps-document.c b/ps/ps-document.c index 4b2d4c43..a794e995 100644 --- a/ps/ps-document.c +++ b/ps/ps-document.c @@ -46,6 +46,7 @@ #include "ps-document.h" #include "ev-debug.h" #include "gsdefaults.h" +#include "ev-ps-exporter.h" #ifdef HAVE_LOCALE_H # include @@ -67,11 +68,6 @@ GCond* pixbuf_cond = NULL; GMutex* pixbuf_mutex = NULL; GdkPixbuf *current_pixbuf = NULL; -enum { - PROP_0, - PROP_TITLE -}; - /* structure to describe section of file to send to ghostscript */ struct record_list { FILE *fp; @@ -82,6 +78,12 @@ struct record_list { struct record_list *next; }; +typedef struct { + int page; + double scale; + PSDocument *document; +} PSRenderJob; + static gboolean broken_pipe = FALSE; /* Forward declarations */ @@ -95,6 +97,7 @@ static void input(gpointer data, gint source, GdkInputCondition condition); static void stop_interpreter(PSDocument * gs); static gint start_interpreter(PSDocument * gs); static void ps_document_document_iface_init (EvDocumentIface *iface); +static void ps_document_ps_exporter_iface_init (EvPSExporterIface *iface); static gboolean ps_document_widget_event (GtkWidget *widget, GdkEvent *event, gpointer data); static GObjectClass *parent_class = NULL; @@ -106,11 +109,8 @@ ps_document_init (PSDocument *gs) { gs->bpixmap = NULL; - gs->current_page = 0; gs->interpreter_pid = -1; - gs->width = -1; - gs->height = -1; gs->busy = FALSE; gs->gs_filename = 0; gs->gs_filename_unc = 0; @@ -137,49 +137,15 @@ ps_document_init (PSDocument *gs) gs->bytes_left = 0; gs->buffer_bytes_left = 0; - gs->zoom_factor = 1.0; - gs->gs_status = _("No document loaded."); + gs->ps_export_pagelist = NULL; + gs->ps_export_filename = NULL; + pixbuf_cond = g_cond_new (); pixbuf_mutex = g_mutex_new (); } -static void -ps_document_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - switch (prop_id) - - { - case PROP_TITLE: - /* read only */ - break; - } -} - -static void -ps_document_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - PSDocument *ps = PS_DOCUMENT (object); - - switch (prop_id) - { - case PROP_TITLE: - if (ps->doc) { - g_value_set_string (value, ps->doc->title); - } else { - g_value_set_string (value, NULL); - } - break; - } -} - static void ps_document_class_init(PSDocumentClass *klass) { @@ -190,15 +156,11 @@ ps_document_class_init(PSDocumentClass *klass) gs_class = klass; object_class->finalize = ps_document_finalize; - object_class->get_property = ps_document_get_property; - object_class->set_property = ps_document_set_property; klass->gs_atom = gdk_atom_intern ("GHOSTVIEW", FALSE); klass->next_atom = gdk_atom_intern ("NEXT", FALSE); klass->page_atom = gdk_atom_intern ("PAGE", FALSE); klass->string_atom = gdk_atom_intern ("STRING", FALSE); - - g_object_class_override_property (object_class, PROP_TITLE, "title"); } static void @@ -206,12 +168,13 @@ push_pixbuf (PSDocument *gs) { GdkColormap *cmap; GdkPixbuf *pixbuf; + int width, height; cmap = gdk_window_get_colormap (gs->pstarget); - + gdk_drawable_get_size (gs->bpixmap, &width, &height); pixbuf = gdk_pixbuf_get_from_drawable (NULL, gs->bpixmap, cmap, 0, 0, 0, 0, - gs->width, gs->height); + width, height); g_mutex_lock (pixbuf_mutex); current_pixbuf = pixbuf; g_cond_signal (pixbuf_cond); @@ -260,7 +223,6 @@ ps_document_cleanup (PSDocument *gs) gs->gs_filename_unc = NULL; } - gs->current_page = 0; gs->loaded = FALSE; } @@ -359,31 +321,167 @@ get_ydpi (PSDocument *gs) } static void -setup_pixmap (PSDocument *gs) +setup_pixmap (PSDocument *gs, int page, double scale) { GdkGC *fill; GdkColor white = { 0, 0xFFFF, 0xFFFF, 0xFFFF }; /* pixel, r, g, b */ GdkColormap *colormap; + double width, height; + int pixmap_width, pixmap_height; - LOG ("Create our internal pixmap"); + ev_document_get_page_size (EV_DOCUMENT (gs), page, &width, &height); + pixmap_width = floor (width * scale); + pixmap_height = floor (height * scale); if(gs->bpixmap) { - gdk_drawable_unref(gs->bpixmap); + int w, h; + + gdk_drawable_get_size (gs->bpixmap, &w, &h); + + if (pixmap_width != w || h != pixmap_height) { + gdk_drawable_unref (gs->bpixmap); + gs->bpixmap = NULL; + stop_interpreter (gs); + } + } + + if (!gs->bpixmap) { + LOG ("Create pixmap"); + + fill = gdk_gc_new (gs->pstarget); + colormap = gdk_drawable_get_colormap (gs->pstarget); + gdk_color_alloc (colormap, &white); + gdk_gc_set_foreground (fill, &white); + gs->bpixmap = gdk_pixmap_new (gs->pstarget, pixmap_width, + pixmap_height, -1); + gdk_draw_rectangle (gs->bpixmap, fill, TRUE, + 0, 0, pixmap_width, pixmap_height); + } +} + +#define DEFAULT_PAGE_SIZE 1 + +static void +get_page_box (PSDocument *gs, int page, int *urx, int *ury, int *llx, int *lly) +{ + gint new_llx = 0; + gint new_lly = 0; + gint new_urx = 0; + gint new_ury = 0; + GtkGSPaperSize *papersizes = gtk_gs_defaults_get_paper_sizes(); + int new_pagesize = -1; + + g_return_if_fail(PS_IS_DOCUMENT(gs)); + + if(new_pagesize == -1) { + new_pagesize = DEFAULT_PAGE_SIZE; + if(gs->doc) { + /* If we have a document: + We use -- the page size (if specified) + or the doc. size (if specified) + or the page bbox (if specified) + or the bounding box + */ + if((page >= 0) && (gs->doc->numpages > page) && + (gs->doc->pages) && (gs->doc->pages[page].size)) { + new_pagesize = gs->doc->pages[page].size - gs->doc->size; + } + else if(gs->doc->default_page_size != NULL) { + new_pagesize = gs->doc->default_page_size - gs->doc->size; + } + else if((page >= 0) && + (gs->doc->numpages > page) && + (gs->doc->pages) && + (gs->doc->pages[page].boundingbox[URX] > + gs->doc->pages[page].boundingbox[LLX]) && + (gs->doc->pages[page].boundingbox[URY] > + gs->doc->pages[page].boundingbox[LLY])) { + new_pagesize = -1; + } + else if((gs->doc->boundingbox[URX] > gs->doc->boundingbox[LLX]) && + (gs->doc->boundingbox[URY] > gs->doc->boundingbox[LLY])) { + new_pagesize = -1; + } + } + } + + /* Compute bounding box */ + if(gs->doc && (gs->doc->epsf || new_pagesize == -1)) { /* epsf or bbox */ + if((page >= 0) && + (gs->doc->pages) && + (gs->doc->pages[page].boundingbox[URX] > + gs->doc->pages[page].boundingbox[LLX]) + && (gs->doc->pages[page].boundingbox[URY] > + gs->doc->pages[page].boundingbox[LLY])) { + /* use page bbox */ + new_llx = gs->doc->pages[page].boundingbox[LLX]; + new_lly = gs->doc->pages[page].boundingbox[LLY]; + new_urx = gs->doc->pages[page].boundingbox[URX]; + new_ury = gs->doc->pages[page].boundingbox[URY]; + } + else if((gs->doc->boundingbox[URX] > gs->doc->boundingbox[LLX]) && + (gs->doc->boundingbox[URY] > gs->doc->boundingbox[LLY])) { + /* use doc bbox */ + new_llx = gs->doc->boundingbox[LLX]; + new_lly = gs->doc->boundingbox[LLY]; + new_urx = gs->doc->boundingbox[URX]; + new_ury = gs->doc->boundingbox[URY]; + } + } + else { + if(new_pagesize < 0) + new_pagesize = DEFAULT_PAGE_SIZE; + new_llx = new_lly = 0; + if(gs->doc && gs->doc->size && + (new_pagesize < gs->doc->numsizes)) { + new_urx = gs->doc->size[new_pagesize].width; + new_ury = gs->doc->size[new_pagesize].height; + } + else { + new_urx = papersizes[new_pagesize].width; + new_ury = papersizes[new_pagesize].height; + } + } + + if(new_urx <= new_llx) + new_urx = papersizes[12].width; + if(new_ury <= new_lly) + new_ury = papersizes[12].height; + + *urx = new_urx; + *ury = new_ury; + *llx = new_llx; + *lly = new_lly; +} + +static int +get_page_orientation (PSDocument *gs, int page) +{ + int orientation; + + orientation = GTK_GS_ORIENTATION_NONE; + + if (gs->structured_doc) { + orientation = gs->doc->pages[page].orientation; + } + if (orientation == GTK_GS_ORIENTATION_NONE) { + orientation = gs->doc->default_page_orientation; + } + if (orientation == GTK_GS_ORIENTATION_NONE) { + orientation = gs->doc->orientation; + } + if (orientation == GTK_GS_ORIENTATION_NONE) { + orientation = GTK_GS_ORIENTATION_PORTRAIT; } - fill = gdk_gc_new (gs->pstarget); - colormap = gdk_drawable_get_colormap (gs->pstarget); - gdk_color_alloc (colormap, &white); - gdk_gc_set_foreground (fill, &white); - gs->bpixmap = gdk_pixmap_new (gs->pstarget, gs->width, gs->height, -1); - gdk_draw_rectangle (gs->bpixmap, fill, TRUE, - 0, 0, gs->width, gs->height); + return orientation; } static void -setup_page (PSDocument *gs) +setup_page (PSDocument *gs, int page, double scale) { char buf[1024]; + int urx, ury, llx, lly, orientation; #ifdef HAVE_LOCALE_H char *savelocale; #endif @@ -397,11 +495,13 @@ setup_page (PSDocument *gs) */ savelocale = setlocale (LC_NUMERIC, "C"); #endif + get_page_box (gs, page, &urx, &ury, &llx, &lly); + orientation = get_page_orientation (gs, page); g_snprintf (buf, 1024, "%ld %d %d %d %d %d %f %f %d %d %d %d", - 0L, gs->orientation * 90, gs->llx, gs->lly, gs->urx, gs->ury, - get_xdpi (gs) * gs->zoom_factor, - get_ydpi (gs) * gs->zoom_factor, + 0L, orientation * 90, llx, lly, urx, ury, + get_xdpi (gs) * scale, + get_ydpi (gs) * scale, 0, 0, 0, 0); LOG ("GS property %s", buf); @@ -591,6 +691,9 @@ start_interpreter (PSDocument *gs) } alpha_args = g_strsplit (ALPHA_PARAMS, " ", NUM_ALPHA_ARGS); + for(i = 0; i < NUM_ALPHA_ARGS && alpha_args[i]; i++, argc++) { + argv[argc] = alpha_args[i]; + } argv[argc++] = "-dNOPAUSE"; argv[argc++] = "-dQUIET"; @@ -855,91 +958,6 @@ check_filecompressed(PSDocument * gs) return filename_unc; } -static void -compute_dimensions (PSDocument *gs, int page) -{ - GtkGSPaperSize *paper_sizes = gtk_gs_defaults_get_paper_sizes (); - int urx, ury, llx, lly; - int width, height; - int orientation; - - g_return_if_fail (PS_IS_DOCUMENT (gs)); - g_return_if_fail (gs->doc != NULL); - g_return_if_fail (page >= 0); - g_return_if_fail (gs->doc->numpages > page); - - orientation = GTK_GS_ORIENTATION_NONE; - if (gs->structured_doc) { - orientation = gs->doc->pages[gs->current_page].orientation; - } - if (orientation == GTK_GS_ORIENTATION_NONE) { - orientation = GTK_GS_ORIENTATION_PORTRAIT; - } - - if (gs->doc->pages && gs->doc->pages[page].size) { - int page_size; - - page_size = gs->doc->pages[page].size - gs->doc->size; - llx = lly = 0; - urx = gs->doc->size[page_size].width; - ury = gs->doc->size[page_size].height; - } else if (gs->doc->pages && - (gs->doc->pages[page].boundingbox[URX] > - gs->doc->pages[page].boundingbox[LLX]) && - (gs->doc->pages[page].boundingbox[URY] > - gs->doc->pages[page].boundingbox[LLY])) { - llx = gs->doc->pages[page].boundingbox[LLX]; - lly = gs->doc->pages[page].boundingbox[LLY]; - urx = gs->doc->pages[page].boundingbox[URX]; - ury = gs->doc->pages[page].boundingbox[URY]; - } else if ((gs->doc->boundingbox[URX] > gs->doc->boundingbox[LLX]) && - (gs->doc->boundingbox[URY] > gs->doc->boundingbox[LLY])) { - llx = gs->doc->boundingbox[LLX]; - lly = gs->doc->boundingbox[LLY]; - urx = gs->doc->boundingbox[URX]; - ury = gs->doc->boundingbox[URY]; - } else { - /* Fallback to A4 */ - llx = lly = 0; - urx = paper_sizes[12].width; - ury = paper_sizes[12].height; - } - - switch (orientation) { - case GTK_GS_ORIENTATION_PORTRAIT: - case GTK_GS_ORIENTATION_UPSIDEDOWN: - width = (urx - llx) / 72.0 * get_xdpi (gs) + 0.5; - height = (ury - lly) / 72.0 * get_ydpi (gs) + 0.5; - break; - case GTK_GS_ORIENTATION_LANDSCAPE: - case GTK_GS_ORIENTATION_SEASCAPE: - width = (ury - lly) / 72.0 * get_xdpi (gs) + 0.5; - height = (urx - llx) / 72.0 * get_ydpi (gs) + 0.5; - break; - default: - width = height = 0; - g_assert_not_reached (); - break; - } - - width = width * gs->zoom_factor; - height = height * gs->zoom_factor; - - if (llx != gs->llx || lly != gs->lly || - urx != gs->urx || ury != gs->ury || - gs->width != width || gs->height != height || - orientation != gs->orientation) { - gs->llx = llx; - gs->lly = lly; - gs->urx = urx; - gs->ury = ury; - gs->width = width; - gs->height = height; - gs->orientation = orientation; - gs->changed = TRUE; - } -} - static gint ps_document_enable_interpreter(PSDocument * gs) { @@ -978,12 +996,22 @@ ps_document_get_type(void) NULL }; + static const GInterfaceInfo ps_exporter_info = + { + (GInterfaceInitFunc) ps_document_ps_exporter_iface_init, + NULL, + NULL + }; + gs_type = g_type_register_static(G_TYPE_OBJECT, "PSDocument", &gs_info, 0); g_type_add_interface_static (gs_type, EV_TYPE_DOCUMENT, &document_info); + g_type_add_interface_static (gs_type, + EV_TYPE_PS_EXPORTER, + &ps_exporter_info); } return gs_type; @@ -1009,7 +1037,6 @@ document_load(PSDocument * gs, const gchar * fname) /* prepare this document */ gs->structured_doc = FALSE; gs->send_filename_to_gs = TRUE; - gs->current_page = 0; gs->loaded = FALSE; if(*fname == '/') { /* an absolute path */ @@ -1051,8 +1078,6 @@ document_load(PSDocument * gs, const gchar * fname) /* we grab the vital statistics!!! */ gs->doc = psscan(gs->gs_psfile, TRUE, filename); - g_object_notify (G_OBJECT (gs), "title"); - if(gs->doc == NULL) { /* File does not seem to be a Postscript one */ gchar buf[1024]; @@ -1070,7 +1095,6 @@ document_load(PSDocument * gs, const gchar * fname) } } gs->loaded = TRUE; - compute_dimensions (gs, gs->current_page); gs->gs_status = _("Document loaded."); @@ -1106,7 +1130,7 @@ ps_document_next_page (PSDocument *gs) } static gboolean -render_page (PSDocument *gs) +render_page (PSDocument *gs, int page) { g_return_val_if_fail(gs != NULL, FALSE); g_return_val_if_fail(PS_IS_DOCUMENT(gs), FALSE); @@ -1126,8 +1150,8 @@ render_page (PSDocument *gs) send_ps (gs, gs->doc->beginsetup, gs->doc->lensetup, FALSE); } - send_ps (gs, gs->doc->pages[gs->current_page].begin, - gs->doc->pages[gs->current_page].len, FALSE); + send_ps (gs, gs->doc->pages[page].begin, + gs->doc->pages[page].len, FALSE); } else { /* Unstructured document * @@ -1176,98 +1200,123 @@ ps_document_load (EvDocument *document, } static gboolean -ps_document_save (EvDocument *document, - const char *uri, - GError **error) +save_page_list (PSDocument *document, int *page_list, const char *filename) { - g_warning ("ps_document_save not implemented"); /* FIXME */ - return TRUE; + gboolean result = TRUE; + GtkGSDocSink *sink = gtk_gs_doc_sink_new (); + FILE *f; + gchar *buf; + + pscopydoc (sink, document->gs_filename, document->doc, page_list); + + buf = gtk_gs_doc_sink_get_buffer (sink); + + f = fopen (filename, "w"); + if (f) { + fputs (buf, f); + fclose (f); + } else { + result = FALSE; + } + + g_free (buf); + gtk_gs_doc_sink_free (sink); + g_free (sink); + + return result; } -static int -ps_document_get_n_pages (EvDocument *document) +static gboolean +ps_document_save (EvDocument *document, + const char *uri, + GError **error) { PSDocument *ps = PS_DOCUMENT (document); + int *page_list; + gboolean result; + int i; + char *filename; - g_return_val_if_fail (ps != NULL, -1); + filename = g_filename_from_uri (uri, NULL, error); + if (!filename) + return FALSE; - if (!ps->gs_filename || !ps->doc) { - return -1; + page_list = g_new0 (int, ps->doc->numpages); + for (i = 0; i < ps->doc->numpages; i++) { + page_list[i] = 1; } - return ps->structured_doc ? ps->doc->numpages : 1; -} + result = save_page_list (ps, page_list, filename); -static void -ps_document_set_page (EvDocument *document, - int page) -{ - PSDocument *gs = PS_DOCUMENT (document); - - LOG ("Set document page %d\n", page); + g_free (page_list); + g_free (filename); - gs->current_page = page; - compute_dimensions (gs, page); + return result; } static int -ps_document_get_page (EvDocument *document) +ps_document_get_n_pages (EvDocument *document) { PSDocument *ps = PS_DOCUMENT (document); g_return_val_if_fail (ps != NULL, -1); - return ps->current_page; -} - -static void -ps_document_set_scale (EvDocument *document, - double scale) -{ - PSDocument *gs = PS_DOCUMENT (document); + if (!ps->gs_filename || !ps->doc) { + return -1; + } - gs->zoom_factor = scale; - compute_dimensions (gs, gs->current_page); + return ps->structured_doc ? ps->doc->numpages : 1; } static void ps_document_get_page_size (EvDocument *document, int page, - int *width, - int *height) + double *width, + double *height) { - /* Post script documents never vary in size */ - PSDocument *gs = PS_DOCUMENT (document); + int w, h; + int urx, ury, llx, lly, orientation; + + get_page_box (PS_DOCUMENT (document), page, &urx, &ury, &llx, &lly); + orientation = get_page_orientation (PS_DOCUMENT (document), page); + + switch (orientation) { + case GTK_GS_ORIENTATION_PORTRAIT: + case GTK_GS_ORIENTATION_UPSIDEDOWN: + w = (urx - llx) / 72.0 * get_xdpi (gs) + 0.5; + h = (ury - lly) / 72.0 * get_ydpi (gs) + 0.5; + break; + case GTK_GS_ORIENTATION_LANDSCAPE: + case GTK_GS_ORIENTATION_SEASCAPE: + w = (ury - lly) / 72.0 * get_xdpi (gs) + 0.5; + h = (urx - llx) / 72.0 * get_ydpi (gs) + 0.5; + break; + default: + w = h = 0; + g_assert_not_reached (); + break; + } if (width) { - *width = gs->width; + *width = w; } if (height) { - *height = gs->height; + *height = h; } } -static char * -ps_document_get_text (EvDocument *document, GdkRectangle *rect) -{ - g_warning ("ps_document_get_text not implemented"); /* FIXME ? */ - return NULL; -} - -static EvLink * -ps_document_get_link (EvDocument *document, - int x, - int y) +static gboolean +ps_document_can_get_text (EvDocument *document) { - return NULL; + return FALSE; } static gboolean -render_pixbuf_idle (EvDocument *document) +render_pixbuf_idle (PSRenderJob *job) { - PSDocument *gs = PS_DOCUMENT (document); + PSDocument *gs = job->document; if (gs->pstarget == NULL) { GtkWidget *widget; @@ -1283,24 +1332,24 @@ render_pixbuf_idle (EvDocument *document) gs); } - if (gs->changed) { - stop_interpreter (gs); - setup_pixmap (gs); - setup_page (gs); - gs->changed = FALSE; - } + setup_pixmap (gs, job->page, job->scale); + setup_page (gs, job->page, job->scale); - render_page (PS_DOCUMENT (document)); + render_page (gs, job->page); return FALSE; } static GdkPixbuf * -ps_document_render_pixbuf (EvDocument *document) +ps_document_render_pixbuf (EvDocument *document, int page, double scale) { GdkPixbuf *pixbuf; + PSRenderJob job; - g_idle_add ((GSourceFunc)render_pixbuf_idle, document); + job.page = page; + job.scale = scale; + job.document = PS_DOCUMENT (document); + g_idle_add ((GSourceFunc)render_pixbuf_idle, &job); g_mutex_lock (pixbuf_mutex); while (!current_pixbuf) @@ -1314,17 +1363,68 @@ ps_document_render_pixbuf (EvDocument *document) return pixbuf; } +static EvDocumentInfo * +ps_document_get_info (EvDocument *document) +{ + EvDocumentInfo *info; + PSDocument *ps = PS_DOCUMENT (document); + + info = g_new0 (EvDocumentInfo, 1); + info->fields_mask = EV_DOCUMENT_INFO_TITLE; + info->title = ps->doc->title; + + return info; +} + static void ps_document_document_iface_init (EvDocumentIface *iface) { iface->load = ps_document_load; iface->save = ps_document_save; - iface->get_text = ps_document_get_text; - iface->get_link = ps_document_get_link; + iface->can_get_text = ps_document_can_get_text; iface->get_n_pages = ps_document_get_n_pages; - iface->set_page = ps_document_set_page; - iface->get_page = ps_document_get_page; - iface->set_scale = ps_document_set_scale; iface->get_page_size = ps_document_get_page_size; iface->render_pixbuf = ps_document_render_pixbuf; + iface->get_info = ps_document_get_info; +} + +static void +ps_document_ps_export_begin (EvPSExporter *exporter, const char *filename) +{ + PSDocument *document = PS_DOCUMENT (exporter); + + g_free (document->ps_export_pagelist); + + document->ps_export_pagelist = g_new0 (int, document->doc->numpages); + document->ps_export_filename = g_strdup (filename); +} + +static void +ps_document_ps_export_do_page (EvPSExporter *exporter, int page) +{ + PSDocument *document = PS_DOCUMENT (exporter); + + document->ps_export_pagelist[page] = 1; +} + +static void +ps_document_ps_export_end (EvPSExporter *exporter) +{ + PSDocument *document = PS_DOCUMENT (exporter); + + save_page_list (document, document->ps_export_pagelist, + document->ps_export_filename); + + g_free (document->ps_export_pagelist); + g_free (document->ps_export_filename); + document->ps_export_pagelist = NULL; + document->ps_export_filename = NULL; +} + +static void +ps_document_ps_exporter_iface_init (EvPSExporterIface *iface) +{ + iface->begin = ps_document_ps_export_begin; + iface->do_page = ps_document_ps_export_do_page; + iface->end = ps_document_ps_export_end; }