~ubuntu-branches/ubuntu/precise/tumbler/precise

« back to all changes in this revision

Viewing changes to plugins/poppler-thumbnailer/poppler-thumbnailer.c

  • Committer: Bazaar Package Importer
  • Author(s): Lionel Le Folgoc
  • Date: 2010-11-07 16:34:58 UTC
  • Revision ID: james.westby@ubuntu.com-20101107163458-skwfq34vnuavipne
Tags: upstream-0.1.4
ImportĀ upstreamĀ versionĀ 0.1.4

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* vi:set et ai sw=2 sts=2 ts=2: */
 
2
/*-
 
3
 * Copyright (c) 2010 Jannis Pohlmann <jannis@xfce.org>
 
4
 *
 
5
 * This library is free software; you can redistribute it and/or
 
6
 * modify it under the terms of the GNU Library General Public
 
7
 * License as published by the Free Software Foundation; either
 
8
 * version 2 of the License, or (at your option) any later version.
 
9
 *
 
10
 * This library is distributed in the hope that it will be useful,
 
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 
13
 * GNU Library General Public License for more details.
 
14
 *
 
15
 * You should have received a copy of the GNU Library General 
 
16
 * Public License along with this library; if not, write to the 
 
17
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 
18
 * Boston, MA 02110-1301, USA.
 
19
 */
 
20
 
 
21
#ifdef HAVE_CONFIG_H
 
22
#include <config.h>
 
23
#endif
 
24
 
 
25
#include <math.h>
 
26
 
 
27
#include <glib.h>
 
28
#include <glib/gi18n.h>
 
29
#include <glib-object.h>
 
30
 
 
31
#include <gdk-pixbuf/gdk-pixbuf.h>
 
32
 
 
33
#include <poppler.h>
 
34
 
 
35
#include <tumbler/tumbler.h>
 
36
 
 
37
#include <poppler-thumbnailer/poppler-thumbnailer.h>
 
38
 
 
39
 
 
40
 
 
41
static void poppler_thumbnailer_create (TumblerAbstractThumbnailer *thumbnailer,
 
42
                                        GCancellable               *cancellable,
 
43
                                        TumblerFileInfo            *info);
 
44
 
 
45
 
 
46
 
 
47
struct _PopplerThumbnailerClass
 
48
{
 
49
  TumblerAbstractThumbnailerClass __parent__;
 
50
};
 
51
 
 
52
struct _PopplerThumbnailer
 
53
{
 
54
  TumblerAbstractThumbnailer __parent__;
 
55
};
 
56
 
 
57
 
 
58
 
 
59
G_DEFINE_DYNAMIC_TYPE (PopplerThumbnailer, 
 
60
                       poppler_thumbnailer,
 
61
                       TUMBLER_TYPE_ABSTRACT_THUMBNAILER);
 
62
 
 
63
 
 
64
 
 
65
void
 
66
poppler_thumbnailer_register (TumblerProviderPlugin *plugin)
 
67
{
 
68
  poppler_thumbnailer_register_type (G_TYPE_MODULE (plugin));
 
69
}
 
70
 
 
71
 
 
72
 
 
73
static void
 
74
poppler_thumbnailer_class_init (PopplerThumbnailerClass *klass)
 
75
{
 
76
  TumblerAbstractThumbnailerClass *abstractthumbnailer_class;
 
77
 
 
78
  abstractthumbnailer_class = TUMBLER_ABSTRACT_THUMBNAILER_CLASS (klass);
 
79
  abstractthumbnailer_class->create = poppler_thumbnailer_create;
 
80
}
 
81
 
 
82
 
 
83
 
 
84
static void
 
85
poppler_thumbnailer_class_finalize (PopplerThumbnailerClass *klass)
 
86
{
 
87
}
 
88
 
 
89
 
 
90
 
 
91
static void
 
92
poppler_thumbnailer_init (PopplerThumbnailer *thumbnailer)
 
93
{
 
94
}
 
95
 
 
96
 
 
97
 
 
98
static GdkPixbuf *
 
99
generate_pixbuf (GdkPixbuf              *source,
 
100
                 TumblerThumbnailFlavor *flavor)
 
101
{
 
102
  gdouble    hratio;
 
103
  gdouble    wratio;
 
104
  gint       dest_width;
 
105
  gint       dest_height;
 
106
  gint       source_width;
 
107
  gint       source_height;
 
108
 
 
109
  /* determine the source pixbuf dimensions */
 
110
  source_width = gdk_pixbuf_get_width (source);
 
111
  source_height = gdk_pixbuf_get_height (source);
 
112
 
 
113
  /* determine the desired size for this flavor */
 
114
  tumbler_thumbnail_flavor_get_size (flavor, &dest_width, &dest_height);
 
115
 
 
116
  /* return the same pixbuf if no scaling is required */
 
117
  if (source_width <= dest_width && source_height <= dest_height)
 
118
    return g_object_ref (source);
 
119
 
 
120
  /* determine which axis needs to be scaled down more */
 
121
  wratio = (gdouble) source_width / (gdouble) dest_width;
 
122
  hratio = (gdouble) source_height / (gdouble) dest_height;
 
123
 
 
124
  /* adjust the other axis */
 
125
  if (hratio > wratio)
 
126
    dest_width = rint (source_width / hratio);
 
127
  else
 
128
    dest_height = rint (source_height / wratio);
 
129
  
 
130
  /* scale the pixbuf down to the desired size */
 
131
  return gdk_pixbuf_scale_simple (source, 
 
132
                                  MAX (dest_width, 1), MAX (dest_height, 1), 
 
133
                                  GDK_INTERP_BILINEAR);
 
134
}
 
135
 
 
136
 
 
137
 
 
138
static void
 
139
poppler_thumbnailer_create (TumblerAbstractThumbnailer *thumbnailer,
 
140
                            GCancellable               *cancellable,
 
141
                            TumblerFileInfo            *info)
 
142
{
 
143
  TumblerThumbnailFlavor *flavor;
 
144
  TumblerImageData        data;
 
145
  TumblerThumbnail       *thumbnail;
 
146
  PopplerDocument        *document;
 
147
  PopplerPage            *page;
 
148
  const gchar            *uri;
 
149
  GdkPixbuf              *source_pixbuf;
 
150
  GdkPixbuf              *pixbuf;
 
151
  GError                 *error = NULL;
 
152
  gdouble                 page_width;
 
153
  gdouble                 page_height;
 
154
  GFile                  *file;
 
155
  gchar                  *contents = NULL;
 
156
  gsize                   length;
 
157
 
 
158
  g_return_if_fail (IS_POPPLER_THUMBNAILER (thumbnailer));
 
159
  g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
 
160
  g_return_if_fail (TUMBLER_IS_FILE_INFO (info));
 
161
 
 
162
  /* do nothing if cancelled */
 
163
  if (g_cancellable_is_cancelled (cancellable)) 
 
164
    return;
 
165
 
 
166
  /* try to load the PDF/PS file based on the URI */
 
167
  uri = tumbler_file_info_get_uri (info);
 
168
  document = poppler_document_new_from_file (uri, NULL, &error);
 
169
 
 
170
  /* check if that failed */
 
171
  if (document == NULL)
 
172
    {
 
173
      /* make sure to free error data */
 
174
      g_clear_error (&error);
 
175
 
 
176
      file = g_file_new_for_uri (uri);
 
177
 
 
178
      /* try to load the file contents using GIO */
 
179
      if (!g_file_load_contents (file, cancellable, &contents, &length, NULL, &error))
 
180
        {
 
181
          g_signal_emit_by_name (thumbnailer, "error", uri, TUMBLER_ERROR_UNSUPPORTED, 
 
182
                                 error->message);
 
183
          g_error_free (error);
 
184
          g_object_unref (file);
 
185
          return;
 
186
        }
 
187
 
 
188
      /* release the file */
 
189
      g_object_unref (file);
 
190
 
 
191
      /* try to create a poppler document based on the file contents */
 
192
      document = poppler_document_new_from_data (contents, length, NULL, &error);
 
193
    }
 
194
 
 
195
  /* emit an error if both ways to load the document failed */
 
196
  if (document == NULL)
 
197
    {
 
198
      g_signal_emit_by_name (thumbnailer, "error", uri, TUMBLER_ERROR_INVALID_FORMAT, 
 
199
                             error->message);
 
200
      g_error_free (error);
 
201
      g_free (contents);
 
202
      return;
 
203
    }
 
204
 
 
205
  /* check if the document has content (= at least one page) */
 
206
  if (poppler_document_get_n_pages (document) <= 0)
 
207
    {
 
208
      g_signal_emit_by_name (thumbnailer, "error", uri, TUMBLER_ERROR_NO_CONTENT, 
 
209
                             _("The document is empty"));
 
210
      g_object_unref (document);
 
211
      g_free (contents);
 
212
      return;
 
213
    }
 
214
 
 
215
  /* get the first page of the document */
 
216
  page = poppler_document_get_page (document, 0);
 
217
 
 
218
  if (page == NULL)
 
219
    {
 
220
      g_signal_emit_by_name (thumbnailer, "error", uri, TUMBLER_ERROR_NO_CONTENT,
 
221
                             _("First page of the document could not be read"));
 
222
      g_object_unref (document);
 
223
      g_free (contents);
 
224
      return;
 
225
    }
 
226
 
 
227
  thumbnail = tumbler_file_info_get_thumbnail (info);
 
228
  g_assert (thumbnail != NULL);
 
229
 
 
230
  /* generate a pixbuf for the thumbnail */
 
231
  flavor = tumbler_thumbnail_get_flavor (thumbnail);
 
232
 
 
233
  /* try to extract the embedded thumbnail */
 
234
  source_pixbuf = poppler_page_get_thumbnail_pixbuf (page);
 
235
 
 
236
  if (source_pixbuf == NULL)
 
237
    {
 
238
      /* fall back to rendering the page ourselves */
 
239
      poppler_page_get_size (page, &page_width, &page_height);
 
240
      source_pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, page_width, page_height);
 
241
      poppler_page_render_to_pixbuf (page, 0, 0, page_width, page_height, 1.0, 0, source_pixbuf);
 
242
    }
 
243
 
 
244
  /* release allocated poppler data */
 
245
  g_object_unref (page);
 
246
  g_object_unref (document);
 
247
 
 
248
  /* generate the final pixbuf (involves rescaling etc.) */
 
249
  pixbuf = generate_pixbuf (source_pixbuf, flavor);
 
250
  g_object_unref (flavor);
 
251
 
 
252
  g_assert (pixbuf != NULL);
 
253
 
 
254
  data.data = gdk_pixbuf_get_pixels (pixbuf);
 
255
  data.has_alpha = gdk_pixbuf_get_has_alpha (pixbuf);
 
256
  data.bits_per_sample = gdk_pixbuf_get_bits_per_sample (pixbuf);
 
257
  data.width = gdk_pixbuf_get_width (pixbuf);
 
258
  data.height = gdk_pixbuf_get_height (pixbuf);
 
259
  data.rowstride = gdk_pixbuf_get_rowstride (pixbuf);
 
260
  data.colorspace = (TumblerColorspace) gdk_pixbuf_get_colorspace (pixbuf);
 
261
 
 
262
  tumbler_thumbnail_save_image_data (thumbnail, &data, 
 
263
                                     tumbler_file_info_get_mtime (info), 
 
264
                                     NULL, &error);
 
265
 
 
266
  if (error != NULL)
 
267
    {
 
268
      g_signal_emit_by_name (thumbnailer, "error", uri, error->code, error->message);
 
269
      g_error_free (error);
 
270
    }
 
271
  else
 
272
    {
 
273
      g_signal_emit_by_name (thumbnailer, "ready", uri);
 
274
    }
 
275
 
 
276
 
 
277
  g_object_unref (thumbnail);
 
278
  g_object_unref (pixbuf);
 
279
  g_object_unref (source_pixbuf);
 
280
  g_free (contents);
 
281
}