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