]> www.fi.muni.cz Git - evince.git/blob - backend/ps/ev-spectre.c
Plugin system for backends. Fixes bug #351348.
[evince.git] / backend / ps / ev-spectre.c
1 /* this file is part of evince, a gnome document viewer
2  *
3  *  Copyright (C) 2007 Carlos Garcia Campos <carlosgc@gnome.org>
4  *
5  * Evince is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * Evince is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
18  */
19
20 #include <config.h>
21
22 #include <glib/gi18n.h>
23 #include <stdlib.h>
24 #include <libspectre/spectre.h>
25
26 #include "ev-spectre.h"
27
28 #include "ev-file-exporter.h"
29 #include "ev-document-thumbnails.h"
30 #include "ev-document-misc.h"
31
32 struct _PSDocument {
33         GObject object;
34
35         SpectreDocument *doc;
36         SpectreExporter *exporter;
37 };
38
39 struct _PSDocumentClass {
40         GObjectClass parent_class;
41 };
42
43 static void ps_document_document_iface_init            (EvDocumentIface           *iface);
44 static void ps_document_file_exporter_iface_init       (EvFileExporterIface       *iface);
45 static void ps_document_document_thumbnails_iface_init (EvDocumentThumbnailsIface *iface);
46
47 EV_BACKEND_REGISTER_WITH_CODE (PSDocument, ps_document,
48                          {
49                                  G_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_THUMBNAILS,
50                                                         ps_document_document_thumbnails_iface_init);
51                                  G_IMPLEMENT_INTERFACE (EV_TYPE_FILE_EXPORTER,
52                                                         ps_document_file_exporter_iface_init);
53                          });
54
55 /* PSDocument */
56 static void
57 ps_document_init (PSDocument *ps_document)
58 {
59 }
60
61 static void
62 ps_document_dispose (GObject *object)
63 {
64         PSDocument *ps = PS_DOCUMENT (object);
65
66         if (ps->doc) {
67                 spectre_document_free (ps->doc);
68                 ps->doc = NULL;
69         }
70
71         if (ps->exporter) {
72                 spectre_exporter_free (ps->exporter);
73                 ps->exporter = NULL;
74         }
75
76         G_OBJECT_CLASS (ps_document_parent_class)->dispose (object);
77 }
78
79 static void
80 ps_document_class_init (PSDocumentClass *klass)
81 {
82         GObjectClass *object_class;
83
84         object_class = G_OBJECT_CLASS (klass);
85
86         object_class->dispose = ps_document_dispose;
87 }
88
89 /* EvDocumentIface */
90 static gboolean
91 ps_document_load (EvDocument *document,
92                   const char *uri,
93                   GError    **error)
94 {
95         PSDocument *ps = PS_DOCUMENT (document);
96         gchar      *filename;
97
98         filename = g_filename_from_uri (uri, NULL, error);
99         if (!filename)
100                 return FALSE;
101         
102         ps->doc = spectre_document_new ();
103
104         spectre_document_load (ps->doc, filename);
105         if (spectre_document_status (ps->doc)) {
106                 gchar *filename_dsp;
107                 
108                 filename_dsp = g_filename_display_name (filename);
109                 g_set_error (error,
110                              G_FILE_ERROR,
111                              G_FILE_ERROR_FAILED,
112                              _("Failed to load document ā€œ%sā€"),
113                              filename_dsp);
114                 g_free (filename_dsp);
115                 g_free (filename);
116
117                 return FALSE;
118         }
119
120         g_free (filename);
121
122         return TRUE;
123 }
124
125 static gboolean
126 ps_document_save (EvDocument *document,
127                   const char *uri,
128                   GError    **error)
129 {
130         PSDocument *ps = PS_DOCUMENT (document);
131         gchar      *filename;
132
133         filename = g_filename_from_uri (uri, NULL, error);
134         if (!filename)
135                 return FALSE;
136
137         spectre_document_save (ps->doc, filename);
138         if (spectre_document_status (ps->doc)) {
139                 gchar *filename_dsp;
140
141                 filename_dsp = g_filename_display_name (filename);
142                 g_set_error (error,
143                              G_FILE_ERROR,
144                              G_FILE_ERROR_FAILED,
145                              _("Failed to save document ā€œ%sā€"),
146                              filename_dsp);
147                 g_free (filename_dsp);
148                 g_free (filename);
149
150                 return FALSE;
151         }
152
153         g_free (filename);
154
155         return TRUE;
156 }
157
158 static int
159 ps_document_get_n_pages (EvDocument *document)
160 {
161         PSDocument *ps = PS_DOCUMENT (document);
162
163         return spectre_document_get_n_pages (ps->doc);
164 }
165
166 static gint
167 get_page_rotation (SpectrePage *page)
168 {
169         switch (spectre_page_get_orientation (page)) {
170                 default:
171                 case SPECTRE_ORIENTATION_PORTRAIT:
172                         return 0;
173                 case SPECTRE_ORIENTATION_LANDSCAPE:
174                         return 90;
175                 case SPECTRE_ORIENTATION_REVERSE_PORTRAIT:
176                         return 180;
177                 case SPECTRE_ORIENTATION_REVERSE_LANDSCAPE:
178                         return 270;
179         }
180
181         return 0;
182 }
183
184 static void
185 ps_document_get_page_size (EvDocument *document,
186                            int         page,
187                            double     *width,
188                            double     *height)
189 {
190         PSDocument  *ps = PS_DOCUMENT (document);
191         SpectrePage *ps_page;
192         gdouble      page_width, page_height;
193         gint         pwidth, pheight;
194         gint         rotate;
195
196         ps_page = spectre_document_get_page (ps->doc, page);
197         spectre_page_get_size (ps_page, &pwidth, &pheight);
198
199         rotate = get_page_rotation (ps_page);
200         if (rotate == 90 || rotate == 270) {
201                 page_height = pwidth;
202                 page_width = pheight;
203         } else {
204                 page_width = pwidth;
205                 page_height = pheight;
206         }
207
208         spectre_page_free (ps_page);
209         
210         if (width) {
211                 *width = page_width;
212         }
213
214         if (height) {
215                 *height = page_height;
216         }
217 }
218
219 static char *
220 ps_document_get_page_label (EvDocument *document,
221                             int         page)
222 {
223         PSDocument  *ps = PS_DOCUMENT (document);
224         SpectrePage *ps_page;
225         gchar       *label;
226
227         ps_page = spectre_document_get_page (ps->doc, page);
228         label = g_strdup (spectre_page_get_label (ps_page));
229         spectre_page_free (ps_page);
230         
231         return label;
232 }
233
234 static EvDocumentInfo *
235 ps_document_get_info (EvDocument *document)
236 {
237         PSDocument     *ps = PS_DOCUMENT (document);
238         EvDocumentInfo *info;
239         const gchar    *creator;
240         SpectrePage    *ps_page;
241         gint            width, height;
242
243         info = g_new0 (EvDocumentInfo, 1);
244         info->fields_mask = EV_DOCUMENT_INFO_TITLE |
245                             EV_DOCUMENT_INFO_FORMAT |
246                             EV_DOCUMENT_INFO_CREATOR |
247                             EV_DOCUMENT_INFO_N_PAGES |
248                             EV_DOCUMENT_INFO_PAPER_SIZE;
249
250         creator = spectre_document_get_creator (ps->doc);
251
252         ps_page = spectre_document_get_page (ps->doc, 0);
253         spectre_page_get_size (ps_page, &width, &height);
254         spectre_page_free (ps_page);
255         
256         info->title = g_strdup (spectre_document_get_title (ps->doc));
257         info->format = g_strdup (spectre_document_get_format (ps->doc));
258         info->creator = g_strdup (creator ? creator : spectre_document_get_for (ps->doc));
259         info->n_pages = spectre_document_get_n_pages (ps->doc);
260         info->paper_width  = width / 72.0f * 25.4f;
261         info->paper_height = height / 72.0f * 25.4f;
262
263         return info;
264 }
265
266 static cairo_surface_t *
267 ps_document_render (EvDocument      *document,
268                     EvRenderContext *rc)
269 {
270         PSDocument           *ps = PS_DOCUMENT (document);
271         SpectrePage          *ps_page;
272         SpectreRenderContext *src;
273         gint                  width_points;
274         gint                  height_points;
275         gint                  width, height;
276         gint                  swidth, sheight;
277         guchar               *data = NULL;
278         gint                  stride;
279         gint                  rotation;
280         cairo_surface_t      *surface;
281         static const cairo_user_data_key_t key;
282
283         ps_page = spectre_document_get_page (ps->doc, rc->page);
284         spectre_page_get_size (ps_page, &width_points, &height_points);
285
286         width = (gint) ((width_points * rc->scale) + 0.5);
287         height = (gint) ((height_points * rc->scale) + 0.5);
288         rotation = (rc->rotation + get_page_rotation (ps_page)) % 360;
289
290         src = spectre_render_context_new ();
291         spectre_render_context_set_page_size (src, width, height);
292         spectre_render_context_set_rotation (src, rotation);
293         spectre_page_render (ps_page, src, &data, &stride);
294         spectre_render_context_free (src);
295
296         if (!data) {
297                 spectre_page_free (ps_page);
298                 return NULL;
299         }
300
301         if (spectre_page_status (ps_page)) {
302                 g_warning (spectre_status_to_string (spectre_page_status (ps_page)));
303                 g_free (data);
304                 spectre_page_free (ps_page);
305                 
306                 return NULL;
307         }
308
309         spectre_page_free (ps_page);
310
311         if (rotation == 90 || rotation == 270) {
312                 swidth = height;
313                 sheight = width;
314         } else {
315                 swidth = width;
316                 sheight = height;
317         }
318         
319         surface = cairo_image_surface_create_for_data (data,
320                                                        CAIRO_FORMAT_RGB24,
321                                                        swidth, sheight,
322                                                        stride);
323         cairo_surface_set_user_data (surface, &key,
324                                      data, (cairo_destroy_func_t)g_free);
325         return surface;
326 }
327
328 static void
329 ps_document_document_iface_init (EvDocumentIface *iface)
330 {
331         iface->load = ps_document_load;
332         iface->save = ps_document_save;
333         iface->get_n_pages = ps_document_get_n_pages;
334         iface->get_page_size = ps_document_get_page_size;
335         iface->get_page_label = ps_document_get_page_label;
336         iface->get_info = ps_document_get_info;
337         iface->render = ps_document_render;
338 }
339
340 /* EvDocumentThumbnailsIface */
341 static GdkPixbuf *
342 ps_document_thumbnails_get_thumbnail (EvDocumentThumbnails *document_thumbnails,
343                                       EvRenderContext      *rc, 
344                                       gboolean              border)
345 {
346         PSDocument      *ps = PS_DOCUMENT (document_thumbnails);
347         cairo_surface_t *surface;
348         GdkPixbuf       *pixbuf = NULL;
349
350         surface = ps_document_render (EV_DOCUMENT (ps), rc);
351         pixbuf = ev_document_misc_pixbuf_from_surface (surface);
352         cairo_surface_destroy (surface);
353
354         if (border) {
355                 GdkPixbuf *border_pixbuf;
356                 
357                 border_pixbuf = ev_document_misc_get_thumbnail_frame (-1, -1, pixbuf);
358                 g_object_unref (pixbuf);
359                 pixbuf = border_pixbuf;
360         }
361
362         return pixbuf;
363 }
364
365 static void
366 ps_document_thumbnails_get_dimensions (EvDocumentThumbnails *document_thumbnails,
367                                        EvRenderContext      *rc, 
368                                        gint                 *width,
369                                        gint                 *height)
370 {
371         PSDocument *ps = PS_DOCUMENT (document_thumbnails);
372         gdouble     page_width, page_height;
373
374         ps_document_get_page_size (EV_DOCUMENT (ps),
375                                    rc->page,
376                                    &page_width, &page_height);
377
378         if (rc->rotation == 90 || rc->rotation == 270) {
379                 *width = (gint) (page_height * rc->scale);
380                 *height = (gint) (page_width * rc->scale);
381         } else {
382                 *width = (gint) (page_width * rc->scale);
383                 *height = (gint) (page_height * rc->scale);
384         }
385 }
386
387 static void
388 ps_document_document_thumbnails_iface_init (EvDocumentThumbnailsIface *iface)
389 {
390         iface->get_thumbnail = ps_document_thumbnails_get_thumbnail;
391         iface->get_dimensions = ps_document_thumbnails_get_dimensions;
392 }
393         
394 /* EvFileExporterIface */
395 static void
396 ps_document_file_exporter_begin (EvFileExporter        *exporter,
397                                  EvFileExporterContext *fc)
398 {
399         PSDocument *ps = PS_DOCUMENT (exporter);
400
401         if (ps->exporter)
402                 spectre_exporter_free (ps->exporter);
403
404         switch (fc->format) {
405                 case EV_FILE_FORMAT_PS:
406                         ps->exporter =
407                                 spectre_exporter_new (ps->doc,
408                                                       SPECTRE_EXPORTER_FORMAT_PS);
409                         break;
410                 case EV_FILE_FORMAT_PDF:
411                         ps->exporter =
412                                 spectre_exporter_new (ps->doc,
413                                                       SPECTRE_EXPORTER_FORMAT_PDF);
414                         break;
415                 default:
416                         g_assert_not_reached ();
417         }
418
419         spectre_exporter_begin (ps->exporter, fc->filename);
420 }
421
422 static void
423 ps_document_file_exporter_do_page (EvFileExporter  *exporter,
424                                    EvRenderContext *rc)
425 {
426         PSDocument *ps = PS_DOCUMENT (exporter);
427
428         spectre_exporter_do_page (ps->exporter, rc->page);
429 }
430
431 static void
432 ps_document_file_exporter_end (EvFileExporter *exporter)
433 {
434         PSDocument *ps = PS_DOCUMENT (exporter);
435
436         spectre_exporter_end (ps->exporter);
437 }
438
439 static EvFileExporterCapabilities
440 ps_document_file_exporter_get_capabilities (EvFileExporter *exporter)
441 {
442         return  EV_FILE_EXPORTER_CAN_PAGE_SET |
443                 EV_FILE_EXPORTER_CAN_COPIES |
444                 EV_FILE_EXPORTER_CAN_COLLATE |
445                 EV_FILE_EXPORTER_CAN_REVERSE |
446                 EV_FILE_EXPORTER_CAN_GENERATE_PS |
447                 EV_FILE_EXPORTER_CAN_GENERATE_PDF;
448 }
449
450 static void
451 ps_document_file_exporter_iface_init (EvFileExporterIface *iface)
452 {
453         iface->begin = ps_document_file_exporter_begin;
454         iface->do_page = ps_document_file_exporter_do_page;
455         iface->end = ps_document_file_exporter_end;
456         iface->get_capabilities = ps_document_file_exporter_get_capabilities;
457 }