Evince
Evince is a document viewer capable of displaying multiple and single page document formats like PDF and Postscript.
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
ev-spectre.c
Go to the documentation of this file.
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-misc.h"
31 
32 struct _PSDocument {
34 
35  SpectreDocument *doc;
36  SpectreExporter *exporter;
37 };
38 
41 };
42 
44 
46  {
49  });
50 
51 /* PSDocument */
52 static void
54 {
55 }
56 
57 static void
58 ps_document_dispose (GObject *object)
59 {
60  PSDocument *ps = PS_DOCUMENT (object);
61 
62  if (ps->doc) {
63  spectre_document_free (ps->doc);
64  ps->doc = NULL;
65  }
66 
67  if (ps->exporter) {
68  spectre_exporter_free (ps->exporter);
69  ps->exporter = NULL;
70  }
71 
72  G_OBJECT_CLASS (ps_document_parent_class)->dispose (object);
73 }
74 
75 /* EvDocumentIface */
76 static gboolean
78  const char *uri,
79  GError **error)
80 {
81  PSDocument *ps = PS_DOCUMENT (document);
82  gchar *filename;
83 
84  filename = g_filename_from_uri (uri, NULL, error);
85  if (!filename)
86  return FALSE;
87 
88  ps->doc = spectre_document_new ();
89 
90  spectre_document_load (ps->doc, filename);
91  if (spectre_document_status (ps->doc)) {
92  gchar *filename_dsp;
93 
94  filename_dsp = g_filename_display_name (filename);
95  g_set_error (error,
96  G_FILE_ERROR,
97  G_FILE_ERROR_FAILED,
98  _("Failed to load document ā€œ%sā€"),
99  filename_dsp);
100  g_free (filename_dsp);
101  g_free (filename);
102 
103  return FALSE;
104  }
105 
106  g_free (filename);
107 
108  return TRUE;
109 }
110 
111 static gboolean
113  const char *uri,
114  GError **error)
115 {
116  PSDocument *ps = PS_DOCUMENT (document);
117  gchar *filename;
118 
119  filename = g_filename_from_uri (uri, NULL, error);
120  if (!filename)
121  return FALSE;
122 
123  spectre_document_save (ps->doc, filename);
124  if (spectre_document_status (ps->doc)) {
125  gchar *filename_dsp;
126 
127  filename_dsp = g_filename_display_name (filename);
128  g_set_error (error,
129  G_FILE_ERROR,
130  G_FILE_ERROR_FAILED,
131  _("Failed to save document ā€œ%sā€"),
132  filename_dsp);
133  g_free (filename_dsp);
134  g_free (filename);
135 
136  return FALSE;
137  }
138 
139  g_free (filename);
140 
141  return TRUE;
142 }
143 
144 static int
146 {
147  PSDocument *ps = PS_DOCUMENT (document);
148 
149  return spectre_document_get_n_pages (ps->doc);
150 }
151 
152 static EvPage *
154  gint index)
155 {
156  PSDocument *ps = PS_DOCUMENT (document);
157  SpectrePage *ps_page;
158  EvPage *page;
159 
160  ps_page = spectre_document_get_page (ps->doc, index);
161  page = ev_page_new (index);
162  page->backend_page = (EvBackendPage)ps_page;
163  page->backend_destroy_func = (EvBackendPageDestroyFunc)spectre_page_free;
164 
165  return page;
166 }
167 
168 static gint
169 get_page_rotation (SpectrePage *page)
170 {
171  switch (spectre_page_get_orientation (page)) {
172  default:
173  case SPECTRE_ORIENTATION_PORTRAIT:
174  return 0;
175  case SPECTRE_ORIENTATION_LANDSCAPE:
176  return 90;
177  case SPECTRE_ORIENTATION_REVERSE_PORTRAIT:
178  return 180;
179  case SPECTRE_ORIENTATION_REVERSE_LANDSCAPE:
180  return 270;
181  }
182 
183  return 0;
184 }
185 
186 static void
188  EvPage *page,
189  double *width,
190  double *height)
191 {
192  SpectrePage *ps_page;
193  gdouble page_width, page_height;
194  gint pwidth, pheight;
195  gint rotate;
196 
197  ps_page = (SpectrePage *)page->backend_page;
198 
199  spectre_page_get_size (ps_page, &pwidth, &pheight);
200 
201  rotate = get_page_rotation (ps_page);
202  if (rotate == 90 || rotate == 270) {
203  page_height = pwidth;
204  page_width = pheight;
205  } else {
206  page_width = pwidth;
207  page_height = pheight;
208  }
209 
210  if (width) {
211  *width = page_width;
212  }
213 
214  if (height) {
215  *height = page_height;
216  }
217 }
218 
219 static char *
221  EvPage *page)
222 {
223  const gchar *label = spectre_page_get_label ((SpectrePage *)page->backend_page);
224  gchar *utf8;
225 
226  if (!label)
227  return NULL;
228 
229  if (g_utf8_validate (label, -1, NULL))
230  return g_strdup (label);
231 
232  /* Try with latin1 and ASCII encondings */
233  utf8 = g_convert (label, -1, "utf-8", "latin1", NULL, NULL, NULL);
234  if (!utf8)
235  utf8 = g_convert (label, -1, "utf-8", "ASCII", NULL, NULL, NULL);
236 
237  return utf8;
238 }
239 
240 static EvDocumentInfo *
242 {
243  PSDocument *ps = PS_DOCUMENT (document);
244  EvDocumentInfo *info;
245  const gchar *creator;
246  SpectrePage *ps_page;
247  gint width, height;
248 
249  info = g_new0 (EvDocumentInfo, 1);
250  info->fields_mask = EV_DOCUMENT_INFO_TITLE |
255 
256  creator = spectre_document_get_creator (ps->doc);
257 
258  ps_page = spectre_document_get_page (ps->doc, 0);
259  spectre_page_get_size (ps_page, &width, &height);
260  spectre_page_free (ps_page);
261 
262  info->title = g_strdup (spectre_document_get_title (ps->doc));
263  info->format = g_strdup (spectre_document_get_format (ps->doc));
264  info->creator = g_strdup (creator ? creator : spectre_document_get_for (ps->doc));
265  info->n_pages = spectre_document_get_n_pages (ps->doc);
266  info->paper_width = width / 72.0f * 25.4f;
267  info->paper_height = height / 72.0f * 25.4f;
268 
269  return info;
270 }
271 
272 static gboolean
274  EvDocumentBackendInfo *info)
275 {
276  info->name = "libspectre";
277  info->version = SPECTRE_VERSION_STRING;
278 
279  return TRUE;
280 }
281 
282 static cairo_surface_t *
284  EvRenderContext *rc)
285 {
286  SpectrePage *ps_page;
287  SpectreRenderContext *src;
288  gint width_points;
289  gint height_points;
290  gint width, height;
291  gint swidth, sheight;
292  guchar *data = NULL;
293  gint stride;
294  gint rotation;
295  cairo_surface_t *surface;
296  static const cairo_user_data_key_t key;
297 
298  ps_page = (SpectrePage *)rc->page->backend_page;
299 
300  spectre_page_get_size (ps_page, &width_points, &height_points);
301 
302  ev_render_context_compute_transformed_size (rc, width_points, height_points,
303  &width, &height);
304 
305  rotation = (rc->rotation + get_page_rotation (ps_page)) % 360;
306 
307  if (rotation == 90 || rotation == 270) {
308  swidth = height;
309  sheight = width;
310  } else {
311  swidth = width;
312  sheight = height;
313  }
314 
315  src = spectre_render_context_new ();
316  spectre_render_context_set_scale (src,
317  (gdouble)swidth / width_points,
318  (gdouble)sheight / height_points);
319  spectre_render_context_set_rotation (src, rotation);
320  spectre_page_render (ps_page, src, &data, &stride);
321  spectre_render_context_free (src);
322 
323  if (!data) {
324  return NULL;
325  }
326 
327  if (spectre_page_status (ps_page)) {
328  g_warning ("%s", spectre_status_to_string (spectre_page_status (ps_page)));
329  g_free (data);
330 
331  return NULL;
332  }
333 
334  surface = cairo_image_surface_create_for_data (data,
335  CAIRO_FORMAT_RGB24,
336  width, height,
337  stride);
338  cairo_surface_set_user_data (surface, &key,
339  data, (cairo_destroy_func_t)g_free);
340  return surface;
341 }
342 
343 static void
345 {
346  GObjectClass *object_class = G_OBJECT_CLASS (klass);
347  EvDocumentClass *ev_document_class = EV_DOCUMENT_CLASS (klass);
348 
349  object_class->dispose = ps_document_dispose;
350 
351  ev_document_class->load = ps_document_load;
352  ev_document_class->save = ps_document_save;
353  ev_document_class->get_n_pages = ps_document_get_n_pages;
354  ev_document_class->get_page = ps_document_get_page;
355  ev_document_class->get_page_size = ps_document_get_page_size;
356  ev_document_class->get_page_label = ps_document_get_page_label;
357  ev_document_class->get_info = ps_document_get_info;
358  ev_document_class->get_backend_info = ps_document_get_backend_info;
359  ev_document_class->render = ps_document_render;
360 }
361 
362 /* EvFileExporterIface */
363 static void
366 {
367  PSDocument *ps = PS_DOCUMENT (exporter);
368 
369  if (ps->exporter)
370  spectre_exporter_free (ps->exporter);
371 
372  switch (fc->format) {
373  case EV_FILE_FORMAT_PS:
374  ps->exporter =
375  spectre_exporter_new (ps->doc,
376  SPECTRE_EXPORTER_FORMAT_PS);
377  break;
378  case EV_FILE_FORMAT_PDF:
379  ps->exporter =
380  spectre_exporter_new (ps->doc,
381  SPECTRE_EXPORTER_FORMAT_PDF);
382  break;
383  default:
384  g_assert_not_reached ();
385  }
386 
387  spectre_exporter_begin (ps->exporter, fc->filename);
388 }
389 
390 static void
392  EvRenderContext *rc)
393 {
394  PSDocument *ps = PS_DOCUMENT (exporter);
395 
396  spectre_exporter_do_page (ps->exporter, rc->page->index);
397 }
398 
399 static void
401 {
402  PSDocument *ps = PS_DOCUMENT (exporter);
403 
404  spectre_exporter_end (ps->exporter);
405 }
406 
409 {
416 }
417 
418 static void
420 {
425 }