thumbnailgtk_extractor.c (6203B)
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 void 63 EXTRACTOR_thumbnailgtk_extract_method (struct EXTRACTOR_ExtractContext *ec) 64 { 65 GdkPixbufLoader *loader; 66 GdkPixbuf *in; 67 GdkPixbuf *out; 68 size_t length; 69 char *thumb; 70 unsigned long width; 71 unsigned long height; 72 char format[64]; 73 void *data; 74 uint64_t size; 75 size_t off; 76 ssize_t iret; 77 void *buf; 78 const char *mime; 79 80 if (-1 == (iret = ec->read (ec->cls, 81 &data, 82 16 * 1024))) 83 return; 84 if (NULL == (mime = magic_buffer (magic, data, iret))) 85 return; 86 if (0 != strncmp (mime, 87 "image/", 88 strlen ("image/"))) 89 return; /* not an image */ 90 91 /* read entire image into memory */ 92 size = ec->get_size (ec->cls); 93 if (UINT64_MAX == size) 94 size = MAX_IMAGE_SIZE; /* unknown size, cap at max */ 95 if (size > MAX_IMAGE_SIZE) 96 return; /* FAR too big to be an image */ 97 if (NULL == (buf = malloc (size))) 98 return; /* too big to fit into memory on this system */ 99 100 /* start with data already read */ 101 memcpy (buf, data, iret); 102 off = iret; 103 while (off < size) 104 { 105 iret = ec->read (ec->cls, &data, size - off); 106 if (iret <= 0) 107 { 108 /* io error */ 109 free (buf); 110 return; 111 } 112 memcpy (buf + off, data, iret); 113 off += iret; 114 } 115 116 loader = gdk_pixbuf_loader_new (); 117 gdk_pixbuf_loader_write (loader, 118 buf, 119 size, NULL); 120 free (buf); 121 gdk_pixbuf_loader_close (loader, 122 NULL); 123 in = gdk_pixbuf_loader_get_pixbuf (loader); 124 if (NULL == in) 125 { 126 g_object_unref (loader); 127 return; 128 } 129 g_object_ref (in); 130 g_object_unref (loader); 131 height = gdk_pixbuf_get_height (in); 132 width = gdk_pixbuf_get_width (in); 133 snprintf (format, 134 sizeof (format), 135 "%ux%u", 136 (unsigned int) width, 137 (unsigned int) height); 138 if (0 != ec->proc (ec->cls, 139 "thumbnailgtk", 140 EXTRACTOR_METATYPE_IMAGE_DIMENSIONS, 141 EXTRACTOR_METAFORMAT_UTF8, 142 "text/plain", 143 format, 144 strlen (format) + 1)) 145 { 146 g_object_unref (in); 147 return; 148 } 149 if ((height <= THUMBSIZE) && (width <= THUMBSIZE)) 150 { 151 g_object_unref (in); 152 return; 153 } 154 if (height > THUMBSIZE) 155 { 156 width = width * THUMBSIZE / height; 157 height = THUMBSIZE; 158 } 159 if (width > THUMBSIZE) 160 { 161 height = height * THUMBSIZE / width; 162 width = THUMBSIZE; 163 } 164 if ( (0 == height) || (0 == width) ) 165 { 166 g_object_unref (in); 167 return; 168 } 169 out = gdk_pixbuf_scale_simple (in, width, height, 170 GDK_INTERP_BILINEAR); 171 g_object_unref (in); 172 thumb = NULL; 173 length = 0; 174 if (NULL == out) 175 return; 176 if (! gdk_pixbuf_save_to_buffer (out, &thumb, 177 &length, 178 "png", NULL, 179 "compression", "9", 180 NULL)) 181 { 182 g_object_unref (out); 183 return; 184 } 185 g_object_unref (out); 186 if (NULL == thumb) 187 return; 188 ec->proc (ec->cls, 189 "thumbnailgtk", 190 EXTRACTOR_METATYPE_THUMBNAIL, 191 EXTRACTOR_METAFORMAT_BINARY, 192 "image/png", 193 thumb, length); 194 free (thumb); 195 } 196 197 198 /** 199 * This plugin sometimes is installed under the alias 'thumbnail'. 200 * So we need to provide a second entry method. 201 * 202 * @param ec extraction context 203 */ 204 void 205 EXTRACTOR_thumbnail_extract_method (struct EXTRACTOR_ExtractContext *ec); 206 207 void 208 EXTRACTOR_thumbnail_extract_method (struct EXTRACTOR_ExtractContext *ec) 209 { 210 EXTRACTOR_thumbnailgtk_extract_method (ec); 211 } 212 213 214 /** 215 * Initialize glib and load magic file. 216 */ 217 void __attribute__ ((constructor)) 218 thumbnailgtk_gobject_init (void); 219 220 void __attribute__ ((constructor)) 221 thumbnailgtk_gobject_init () 222 { 223 #if ! GLIB_CHECK_VERSION (2, 35, 0) 224 g_type_init (); 225 #endif 226 magic = magic_open (MAGIC_MIME_TYPE); 227 if (0 != magic_load (magic, NULL)) 228 { 229 /* FIXME: how to deal with errors? */ 230 } 231 } 232 233 234 /** 235 * Destructor for the library, cleans up. 236 */ 237 void __attribute__ ((destructor)) 238 thumbnailgtk_ltdl_fini (void); 239 240 void __attribute__ ((destructor)) 241 thumbnailgtk_ltdl_fini () 242 { 243 if (NULL != magic) 244 { 245 magic_close (magic); 246 magic = NULL; 247 } 248 } 249 250 251 /* end of thumbnailgtk_extractor.c */