thumbnailgtk_extractor.c (5877B)
1 /* 2 This file is part of libextractor. 3 Copyright (C) 2005, 2009, 2012 Vidyut Samanta and Christian Grothoff 4 5 libextractor is free software; you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published 7 by the Free Software Foundation; either version 3, or (at your 8 option) any later version. 9 10 libextractor 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 libextractor; see the file COPYING. If not, write to the 17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 18 Boston, MA 02110-1301, USA. 19 */ 20 /** 21 * @file plugins/thumbnailgtk_extractor.c 22 * @author Christian Grothoff 23 * @brief this extractor produces a binary (!) encoded 24 * thumbnail of images (using gdk pixbuf). The bottom 25 * of the file includes a decoder method that can be used 26 * to reproduce the 128x128 PNG thumbnails. We use 27 * libmagic to test if the input data is actually an 28 * image before trying to give it to gdk-pixbuf. 29 */ 30 #include "platform.h" 31 #include "extractor.h" 32 #include <magic.h> 33 #include <glib.h> 34 #include <gdk-pixbuf/gdk-pixbuf.h> 35 36 /** 37 * Target size for the thumbnails (width and height). 38 */ 39 #define THUMBSIZE 128 40 41 /** 42 * Maximum image size supported (to avoid unreasonable 43 * allocations) 44 */ 45 #define MAX_IMAGE_SIZE (32 * 1024 * 1024) 46 47 48 /** 49 * Global handle to MAGIC data. 50 */ 51 static magic_t magic; 52 53 54 /** 55 * Main method for the gtk-thumbnailer plugin. 56 * 57 * @param ec extraction context 58 */ 59 void 60 EXTRACTOR_thumbnailgtk_extract_method (struct EXTRACTOR_ExtractContext *ec) 61 { 62 GdkPixbufLoader *loader; 63 GdkPixbuf *in; 64 GdkPixbuf *out; 65 size_t length; 66 char *thumb; 67 unsigned long width; 68 unsigned long height; 69 char format[64]; 70 void *data; 71 uint64_t size; 72 size_t off; 73 ssize_t iret; 74 void *buf; 75 const char *mime; 76 77 if (-1 == (iret = ec->read (ec->cls, 78 &data, 79 16 * 1024))) 80 return; 81 if (NULL == (mime = magic_buffer (magic, data, iret))) 82 return; 83 if (0 != strncmp (mime, 84 "image/", 85 strlen ("image/"))) 86 return; /* not an image */ 87 88 /* read entire image into memory */ 89 size = ec->get_size (ec->cls); 90 if (UINT64_MAX == size) 91 size = MAX_IMAGE_SIZE; /* unknown size, cap at max */ 92 if (size > MAX_IMAGE_SIZE) 93 return; /* FAR too big to be an image */ 94 if (NULL == (buf = malloc (size))) 95 return; /* too big to fit into memory on this system */ 96 97 /* start with data already read */ 98 memcpy (buf, data, iret); 99 off = iret; 100 while (off < size) 101 { 102 iret = ec->read (ec->cls, &data, size - off); 103 if (iret <= 0) 104 { 105 /* io error */ 106 free (buf); 107 return; 108 } 109 memcpy (buf + off, data, iret); 110 off += iret; 111 } 112 113 loader = gdk_pixbuf_loader_new (); 114 gdk_pixbuf_loader_write (loader, 115 buf, 116 size, NULL); 117 free (buf); 118 in = gdk_pixbuf_loader_get_pixbuf (loader); 119 gdk_pixbuf_loader_close (loader, NULL); 120 if (NULL == in) 121 { 122 g_object_unref (loader); 123 return; 124 } 125 g_object_ref (in); 126 g_object_unref (loader); 127 height = gdk_pixbuf_get_height (in); 128 width = gdk_pixbuf_get_width (in); 129 snprintf (format, 130 sizeof (format), 131 "%ux%u", 132 (unsigned int) width, 133 (unsigned int) height); 134 if (0 != ec->proc (ec->cls, 135 "thumbnailgtk", 136 EXTRACTOR_METATYPE_IMAGE_DIMENSIONS, 137 EXTRACTOR_METAFORMAT_UTF8, 138 "text/plain", 139 format, 140 strlen (format) + 1)) 141 { 142 g_object_unref (in); 143 return; 144 } 145 if ((height <= THUMBSIZE) && (width <= THUMBSIZE)) 146 { 147 g_object_unref (in); 148 return; 149 } 150 if (height > THUMBSIZE) 151 { 152 width = width * THUMBSIZE / height; 153 height = THUMBSIZE; 154 } 155 if (width > THUMBSIZE) 156 { 157 height = height * THUMBSIZE / width; 158 width = THUMBSIZE; 159 } 160 if ( (0 == height) || (0 == width) ) 161 { 162 g_object_unref (in); 163 return; 164 } 165 out = gdk_pixbuf_scale_simple (in, width, height, 166 GDK_INTERP_BILINEAR); 167 g_object_unref (in); 168 thumb = NULL; 169 length = 0; 170 if (NULL == out) 171 return; 172 if (! gdk_pixbuf_save_to_buffer (out, &thumb, 173 &length, 174 "png", NULL, 175 "compression", "9", 176 NULL)) 177 { 178 g_object_unref (out); 179 return; 180 } 181 g_object_unref (out); 182 if (NULL == thumb) 183 return; 184 ec->proc (ec->cls, 185 "thumbnailgtk", 186 EXTRACTOR_METATYPE_THUMBNAIL, 187 EXTRACTOR_METAFORMAT_BINARY, 188 "image/png", 189 thumb, length); 190 free (thumb); 191 } 192 193 194 /** 195 * This plugin sometimes is installed under the alias 'thumbnail'. 196 * So we need to provide a second entry method. 197 * 198 * @param ec extraction context 199 */ 200 void 201 EXTRACTOR_thumbnail_extract_method (struct EXTRACTOR_ExtractContext *ec) 202 { 203 EXTRACTOR_thumbnailgtk_extract_method (ec); 204 } 205 206 207 /** 208 * Initialize glib and load magic file. 209 */ 210 void __attribute__ ((constructor)) 211 thumbnailgtk_gobject_init () 212 { 213 #if ! GLIB_CHECK_VERSION (2, 35, 0) 214 g_type_init (); 215 #endif 216 magic = magic_open (MAGIC_MIME_TYPE); 217 if (0 != magic_load (magic, NULL)) 218 { 219 /* FIXME: how to deal with errors? */ 220 } 221 } 222 223 224 /** 225 * Destructor for the library, cleans up. 226 */ 227 void __attribute__ ((destructor)) 228 thumbnailgtk_ltdl_fini () 229 { 230 if (NULL != magic) 231 { 232 magic_close (magic); 233 magic = NULL; 234 } 235 } 236 237 238 /* end of thumbnailgtk_extractor.c */