libextractor

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

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