libextractor

GNU libextractor
Log | Files | Refs | Submodules | README | LICENSE

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 */