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