thumbnailgtk_extractor.c (6176B)
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 in = gdk_pixbuf_loader_get_pixbuf (loader); 122 gdk_pixbuf_loader_close (loader, NULL); 123 if (NULL == in) 124 { 125 g_object_unref (loader); 126 return; 127 } 128 g_object_ref (in); 129 g_object_unref (loader); 130 height = gdk_pixbuf_get_height (in); 131 width = gdk_pixbuf_get_width (in); 132 snprintf (format, 133 sizeof (format), 134 "%ux%u", 135 (unsigned int) width, 136 (unsigned int) height); 137 if (0 != ec->proc (ec->cls, 138 "thumbnailgtk", 139 EXTRACTOR_METATYPE_IMAGE_DIMENSIONS, 140 EXTRACTOR_METAFORMAT_UTF8, 141 "text/plain", 142 format, 143 strlen (format) + 1)) 144 { 145 g_object_unref (in); 146 return; 147 } 148 if ((height <= THUMBSIZE) && (width <= THUMBSIZE)) 149 { 150 g_object_unref (in); 151 return; 152 } 153 if (height > THUMBSIZE) 154 { 155 width = width * THUMBSIZE / height; 156 height = THUMBSIZE; 157 } 158 if (width > THUMBSIZE) 159 { 160 height = height * THUMBSIZE / width; 161 width = THUMBSIZE; 162 } 163 if ( (0 == height) || (0 == width) ) 164 { 165 g_object_unref (in); 166 return; 167 } 168 out = gdk_pixbuf_scale_simple (in, width, height, 169 GDK_INTERP_BILINEAR); 170 g_object_unref (in); 171 thumb = NULL; 172 length = 0; 173 if (NULL == out) 174 return; 175 if (! gdk_pixbuf_save_to_buffer (out, &thumb, 176 &length, 177 "png", NULL, 178 "compression", "9", 179 NULL)) 180 { 181 g_object_unref (out); 182 return; 183 } 184 g_object_unref (out); 185 if (NULL == thumb) 186 return; 187 ec->proc (ec->cls, 188 "thumbnailgtk", 189 EXTRACTOR_METATYPE_THUMBNAIL, 190 EXTRACTOR_METAFORMAT_BINARY, 191 "image/png", 192 thumb, length); 193 free (thumb); 194 } 195 196 197 /** 198 * This plugin sometimes is installed under the alias 'thumbnail'. 199 * So we need to provide a second entry method. 200 * 201 * @param ec extraction context 202 */ 203 void 204 EXTRACTOR_thumbnail_extract_method (struct EXTRACTOR_ExtractContext *ec); 205 206 void 207 EXTRACTOR_thumbnail_extract_method (struct EXTRACTOR_ExtractContext *ec) 208 { 209 EXTRACTOR_thumbnailgtk_extract_method (ec); 210 } 211 212 213 /** 214 * Initialize glib and load magic file. 215 */ 216 void __attribute__ ((constructor)) 217 thumbnailgtk_gobject_init (void); 218 219 void __attribute__ ((constructor)) 220 thumbnailgtk_gobject_init () 221 { 222 #if ! GLIB_CHECK_VERSION (2, 35, 0) 223 g_type_init (); 224 #endif 225 magic = magic_open (MAGIC_MIME_TYPE); 226 if (0 != magic_load (magic, NULL)) 227 { 228 /* FIXME: how to deal with errors? */ 229 } 230 } 231 232 233 /** 234 * Destructor for the library, cleans up. 235 */ 236 void __attribute__ ((destructor)) 237 thumbnailgtk_ltdl_fini (void); 238 239 void __attribute__ ((destructor)) 240 thumbnailgtk_ltdl_fini () 241 { 242 if (NULL != magic) 243 { 244 magic_close (magic); 245 magic = NULL; 246 } 247 } 248 249 250 /* end of thumbnailgtk_extractor.c */