libextractor

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

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