1
/* vi:set et ai sw=2 sts=2 ts=2: */
3
* Copyright (c) 2010 Jannis Pohlmann <jannis@xfce.org>
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.
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.
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.
28
#include <glib/gi18n.h>
29
#include <glib-object.h>
31
#include <gdk-pixbuf/gdk-pixbuf.h>
35
#include <tumbler/tumbler.h>
37
#include <poppler-thumbnailer/poppler-thumbnailer.h>
41
static void poppler_thumbnailer_create (TumblerAbstractThumbnailer *thumbnailer,
42
GCancellable *cancellable,
43
TumblerFileInfo *info);
47
struct _PopplerThumbnailerClass
49
TumblerAbstractThumbnailerClass __parent__;
52
struct _PopplerThumbnailer
54
TumblerAbstractThumbnailer __parent__;
59
G_DEFINE_DYNAMIC_TYPE (PopplerThumbnailer,
61
TUMBLER_TYPE_ABSTRACT_THUMBNAILER);
66
poppler_thumbnailer_register (TumblerProviderPlugin *plugin)
68
poppler_thumbnailer_register_type (G_TYPE_MODULE (plugin));
74
poppler_thumbnailer_class_init (PopplerThumbnailerClass *klass)
76
TumblerAbstractThumbnailerClass *abstractthumbnailer_class;
78
abstractthumbnailer_class = TUMBLER_ABSTRACT_THUMBNAILER_CLASS (klass);
79
abstractthumbnailer_class->create = poppler_thumbnailer_create;
85
poppler_thumbnailer_class_finalize (PopplerThumbnailerClass *klass)
92
poppler_thumbnailer_init (PopplerThumbnailer *thumbnailer)
99
generate_pixbuf (GdkPixbuf *source,
100
TumblerThumbnailFlavor *flavor)
109
/* determine the source pixbuf dimensions */
110
source_width = gdk_pixbuf_get_width (source);
111
source_height = gdk_pixbuf_get_height (source);
113
/* determine the desired size for this flavor */
114
tumbler_thumbnail_flavor_get_size (flavor, &dest_width, &dest_height);
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);
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;
124
/* adjust the other axis */
126
dest_width = rint (source_width / hratio);
128
dest_height = rint (source_height / wratio);
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);
139
poppler_thumbnailer_create (TumblerAbstractThumbnailer *thumbnailer,
140
GCancellable *cancellable,
141
TumblerFileInfo *info)
143
TumblerThumbnailFlavor *flavor;
144
TumblerImageData data;
145
TumblerThumbnail *thumbnail;
146
PopplerDocument *document;
149
GdkPixbuf *source_pixbuf;
151
GError *error = NULL;
155
gchar *contents = NULL;
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));
162
/* do nothing if cancelled */
163
if (g_cancellable_is_cancelled (cancellable))
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);
170
/* check if that failed */
171
if (document == NULL)
173
/* make sure to free error data */
174
g_clear_error (&error);
176
file = g_file_new_for_uri (uri);
178
/* try to load the file contents using GIO */
179
if (!g_file_load_contents (file, cancellable, &contents, &length, NULL, &error))
181
g_signal_emit_by_name (thumbnailer, "error", uri, TUMBLER_ERROR_UNSUPPORTED,
183
g_error_free (error);
184
g_object_unref (file);
188
/* release the file */
189
g_object_unref (file);
191
/* try to create a poppler document based on the file contents */
192
document = poppler_document_new_from_data (contents, length, NULL, &error);
195
/* emit an error if both ways to load the document failed */
196
if (document == NULL)
198
g_signal_emit_by_name (thumbnailer, "error", uri, TUMBLER_ERROR_INVALID_FORMAT,
200
g_error_free (error);
205
/* check if the document has content (= at least one page) */
206
if (poppler_document_get_n_pages (document) <= 0)
208
g_signal_emit_by_name (thumbnailer, "error", uri, TUMBLER_ERROR_NO_CONTENT,
209
_("The document is empty"));
210
g_object_unref (document);
215
/* get the first page of the document */
216
page = poppler_document_get_page (document, 0);
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);
227
thumbnail = tumbler_file_info_get_thumbnail (info);
228
g_assert (thumbnail != NULL);
230
/* generate a pixbuf for the thumbnail */
231
flavor = tumbler_thumbnail_get_flavor (thumbnail);
233
/* try to extract the embedded thumbnail */
234
source_pixbuf = poppler_page_get_thumbnail_pixbuf (page);
236
if (source_pixbuf == NULL)
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);
244
/* release allocated poppler data */
245
g_object_unref (page);
246
g_object_unref (document);
248
/* generate the final pixbuf (involves rescaling etc.) */
249
pixbuf = generate_pixbuf (source_pixbuf, flavor);
250
g_object_unref (flavor);
252
g_assert (pixbuf != NULL);
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);
262
tumbler_thumbnail_save_image_data (thumbnail, &data,
263
tumbler_file_info_get_mtime (info),
268
g_signal_emit_by_name (thumbnailer, "error", uri, error->code, error->message);
269
g_error_free (error);
273
g_signal_emit_by_name (thumbnailer, "ready", uri);
277
g_object_unref (thumbnail);
278
g_object_unref (pixbuf);
279
g_object_unref (source_pixbuf);