Logo Search packages:      
Sourcecode: eog version File versions  Download package

eog-thumbnail.c

/* Eye Of Gnome - Thumbnailing functions 
 *
 * Copyright (C) 2000-2007 The Free Software Foundation
 *
 * Author: Lucas Rocha <lucasr@gnome.org>
 *
 * Based on eel code (eel/eel-graphic-effects.c) by: 
 *    - Andy Hertzfeld <andy@eazel.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <libgnomeui/libgnomeui.h>
#include <libart_lgpl/art_rgb.h>

#include "eog-thumbnail.h"
#include "eog-list-store.h"

#define THUMB_DEBUG 0 
#define EOG_THUMB_ERROR eog_thumb_error_quark ()

static GnomeThumbnailFactory *factory = NULL;
static GdkPixbuf *frame = NULL;

typedef enum {
      EOG_THUMB_ERROR_VFS,
      EOG_THUMB_ERROR_GENERIC,
      EOG_THUMB_ERROR_UNKNOWN
} EogThumbError;

typedef struct {
      char   *uri_str;
      char   *thumb_path;
      time_t  mtime;
      char   *mime_type;
} EogThumbData;

static GQuark
eog_thumb_error_quark (void)
{
      static GQuark q = 0;
      if (q == 0)
            q = g_quark_from_static_string ("eog-thumb-error-quark");
      
      return q;
}

static void
set_vfs_error (GError **error, GnomeVFSResult result)
{
      g_set_error (error, 
                 EOG_THUMB_ERROR, 
                 EOG_THUMB_ERROR_VFS,
                 gnome_vfs_result_to_string (result));
}

static void
set_thumb_error (GError **error, int error_id, const char *string) 
{
      g_set_error (error, 
                 EOG_THUMB_ERROR, 
                 error_id,
                 string);
}

static GdkPixbuf*
get_valid_thumbnail (EogThumbData *data, GError **error)
{
      GdkPixbuf *thumb = NULL;

      g_return_val_if_fail (data != NULL, NULL);

      /* does a thumbnail under the path exists? */
      if (g_file_test (data->thumb_path, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR)) {
            thumb = gdk_pixbuf_new_from_file (data->thumb_path, error);
            
            /* is this thumbnail file up to date=? */
            if (thumb != NULL && !gnome_thumbnail_is_valid (thumb, data->uri_str, data->mtime)) {
                  g_object_unref (thumb);
                  thumb = NULL;
#if THUMB_DEBUG
                  g_print ("uri: %s, thumbnail is invalid\n", uri_str);
#endif
            }
      }
#if THUMB_DEBUG
      else {
            g_print ("uri: %s, has no thumbnail file\n", uri_str);
      }
#endif
      return thumb;
}

static GdkPixbuf *
create_thumbnail_from_pixbuf (EogThumbData *data,
                        GdkPixbuf *pixbuf,
                        GError **error)
{
      GdkPixbuf *thumb;
      gint width, height;
      gfloat perc;
      
      g_assert (factory != NULL);

      width = gdk_pixbuf_get_width (pixbuf);
      height = gdk_pixbuf_get_height (pixbuf);
      
      perc = CLAMP (128.0/(MAX (width, height)), 0, 1);

      thumb = gnome_thumbnail_scale_down_pixbuf (pixbuf,
                                       width*perc, height*perc);
      
      gnome_thumbnail_factory_save_thumbnail (factory, thumb, data->uri_str, data->mtime);

      return thumb;
}

static GdkPixbuf* 
create_thumbnail (EogThumbData *data, GError **error)
{
      GdkPixbuf *thumb = NULL;
      
#if THUMB_DEBUG
      g_print ("create thumbnail for uri: %s\n -> mtime: %i\n -> mime_type; %s\n -> thumbpath: %s\n", 
             data->uri_str, (int) data->mtime, data->mime_type, data->thumb_path);
#endif
      g_assert (factory != NULL);
      
      if (gnome_thumbnail_factory_can_thumbnail (factory, data->uri_str, data->mime_type, data->mtime)) 
      {
            thumb = gnome_thumbnail_factory_generate_thumbnail (factory, data->uri_str, data->mime_type);
            
            if (thumb != NULL) {
                  gnome_thumbnail_factory_save_thumbnail (factory, thumb, data->uri_str, data->mtime);
            }
            else {
                  set_thumb_error (error, EOG_THUMB_ERROR_GENERIC, "Thumbnail creation failed");
            }
      } 
      else {
            set_thumb_error (error, EOG_THUMB_ERROR_GENERIC, "Thumbnail creation failed");
      }
      
      return thumb;
}

static void
eog_thumb_data_free (EogThumbData *data)
{
      if (data == NULL)
            return;

      g_free (data->thumb_path);
      g_free (data->mime_type);
      g_free (data->uri_str);
      g_free (data);
}

static EogThumbData*
eog_thumb_data_new (GnomeVFSURI *uri, GError **error)
{
      EogThumbData *data;
      GnomeVFSFileInfo *info;
      GnomeVFSResult result;

      g_return_val_if_fail (uri != NULL, NULL);
      g_return_val_if_fail (error != NULL && *error == NULL, NULL);
      
      data = g_new0 (EogThumbData, 1);
      
      data->uri_str    = gnome_vfs_uri_to_string (uri, GNOME_VFS_URI_HIDE_NONE);
      data->thumb_path = gnome_thumbnail_path_for_uri (data->uri_str, GNOME_THUMBNAIL_SIZE_NORMAL);

      info    = gnome_vfs_file_info_new ();
      result  = gnome_vfs_get_file_info_uri (uri, info, 
                                     GNOME_VFS_FILE_INFO_DEFAULT |
                                     GNOME_VFS_FILE_INFO_FOLLOW_LINKS |
                                     GNOME_VFS_FILE_INFO_GET_MIME_TYPE);
      
      if (result != GNOME_VFS_OK) {
            set_vfs_error (error, result);
      }
      else if (((info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_MTIME) == 0) ||
             ((info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_MIME_TYPE) == 0)) {
            /* check required info fields */
            set_thumb_error (error, EOG_THUMB_ERROR_GENERIC, "MTime or mime type not available");
      }
      
      if (*error == NULL) {
            /* if available, copy data */
            data->mtime = info->mtime;
            data->mime_type = g_strdup (info->mime_type);
      }
      else {
            eog_thumb_data_free (data);
            data = NULL;
      }

      gnome_vfs_file_info_unref (info);

      return data;
}

static void
draw_frame_row (GdkPixbuf *frame_image, 
            gint target_width, 
            gint source_width, 
            gint source_v_position, 
            gint dest_v_position, 
            GdkPixbuf *result_pixbuf, 
            gint left_offset, 
            gint height)
{
      gint remaining_width, h_offset, slab_width;
      
      remaining_width = target_width;
      h_offset = 0;

      while (remaining_width > 0) { 
            slab_width = remaining_width > source_width ? 
                       source_width : remaining_width;

            gdk_pixbuf_copy_area (frame_image, 
                              left_offset, 
                              source_v_position, 
                              slab_width, 
                              height, 
                              result_pixbuf, 
                              left_offset + h_offset, 
                              dest_v_position);

            remaining_width -= slab_width;
            h_offset += slab_width; 
      }
}

static void
draw_frame_column (GdkPixbuf *frame_image, 
               gint target_height, 
               gint source_height, 
               gint source_h_position, 
               gint dest_h_position, 
               GdkPixbuf *result_pixbuf, 
               gint top_offset, 
               gint width)
{
      gint remaining_height, v_offset, slab_height;
      
      remaining_height = target_height;
      v_offset = 0;

      while (remaining_height > 0) {      
            slab_height = remaining_height > source_height ? 
                        source_height : remaining_height;

            gdk_pixbuf_copy_area (frame_image, 
                              source_h_position, 
                              top_offset, 
                              width, 
                              slab_height, 
                              result_pixbuf, 
                              dest_h_position, 
                              top_offset + v_offset);

            remaining_height -= slab_height;
            v_offset += slab_height; 
      }
}

static GdkPixbuf *
eog_thumbnail_stretch_frame_image (GdkPixbuf *frame_image, 
                           gint left_offset, 
                           gint top_offset, 
                           gint right_offset, 
                           gint bottom_offset,
                                   gint dest_width, 
                           gint dest_height, 
                           gboolean fill_flag)
{
        GdkPixbuf *result_pixbuf;
        guchar *pixels_ptr;
        gint frame_width, frame_height;
        gint y, row_stride;
        gint target_width, target_frame_width;
        gint target_height, target_frame_height;

        frame_width  = gdk_pixbuf_get_width  (frame_image);
        frame_height = gdk_pixbuf_get_height (frame_image );

        if (fill_flag) {
            result_pixbuf = gdk_pixbuf_scale_simple (frame_image, 
                                           dest_width, 
                                           dest_height, 
                                           GDK_INTERP_NEAREST);
        } else {
                result_pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, 
                                    TRUE, 
                                    8, 
                                    dest_width, 
                                    dest_height);
        }

        row_stride = gdk_pixbuf_get_rowstride (result_pixbuf);
        pixels_ptr = gdk_pixbuf_get_pixels (result_pixbuf);

        if (!fill_flag) {
            for (y = 0; y < dest_height; y++) {
                  art_rgb_run_alpha (pixels_ptr, 
                                 255, 255, 
                                 255, 255, 
                                 dest_width);
                  pixels_ptr += row_stride;
            }
        }

        target_width  = dest_width - left_offset - right_offset;
        target_frame_width = frame_width - left_offset - right_offset;

        target_height  = dest_height - top_offset - bottom_offset;
        target_frame_height = frame_height - top_offset - bottom_offset;

        /* Draw the left top corner  and top row */
        gdk_pixbuf_copy_area (frame_image, 
                        0, 0, 
                        left_offset, 
                        top_offset, 
                        result_pixbuf, 
                        0, 0);

        draw_frame_row (frame_image, 
                  target_width, 
                  target_frame_width, 
                  0, 0, 
                  result_pixbuf, 
                  left_offset, 
                  top_offset);

        /* Draw the right top corner and left column */
        gdk_pixbuf_copy_area (frame_image, 
                        frame_width - right_offset, 
                        0, 
                        right_offset, 
                        top_offset, 
                        result_pixbuf, 
                        dest_width - right_offset,  
                        0);

        draw_frame_column (frame_image, 
                     target_height, 
                     target_frame_height, 
                     0, 0, 
                     result_pixbuf, 
                     top_offset, 
                     left_offset);

        /* Draw the bottom right corner and bottom row */
        gdk_pixbuf_copy_area (frame_image, 
                        frame_width - right_offset, 
                        frame_height - bottom_offset, 
                        right_offset, 
                        bottom_offset, 
                        result_pixbuf, 
                        dest_width - right_offset,  
                        dest_height - bottom_offset);

        draw_frame_row (frame_image, 
                  target_width, 
                  target_frame_width, 
                  frame_height - bottom_offset, 
                  dest_height - bottom_offset, 
                  result_pixbuf, 
                  left_offset, bottom_offset);

        /* Draw the bottom left corner and the right column */
        gdk_pixbuf_copy_area (frame_image, 
                        0, 
                        frame_height - bottom_offset, 
                        left_offset, 
                        bottom_offset, 
                        result_pixbuf, 
                        0,
                        dest_height - bottom_offset);

        draw_frame_column (frame_image, 
                     target_height, 
                     target_frame_height, 
                     frame_width - right_offset, 
                     dest_width - right_offset, 
                     result_pixbuf, top_offset, 
                     right_offset);

        return result_pixbuf;
}

void 
eog_thumbnail_add_frame (GdkPixbuf **thumbnail)
{
      GdkPixbuf *result_pixbuf;
      gint source_width, source_height;
      gint dest_width, dest_height;

      source_width  = gdk_pixbuf_get_width  (*thumbnail);
      source_height = gdk_pixbuf_get_height (*thumbnail);
      
      dest_width  = source_width  + 9;
      dest_height = source_height + 9;

      result_pixbuf = eog_thumbnail_stretch_frame_image (frame, 
                                             3, 3, 6, 6,
                                                     dest_width, 
                                             dest_height,
                                             FALSE);

      gdk_pixbuf_copy_area (*thumbnail, 
                        0, 0, 
                        source_width, 
                        source_height, 
                        result_pixbuf, 
                        3, 3);

      g_object_unref (*thumbnail);

      *thumbnail = result_pixbuf;
}

void
eog_thumbnail_fit_to_size (GdkPixbuf **thumbnail, gint dimension)
{
      gint width, height;

      width = gdk_pixbuf_get_width (*thumbnail);
      height = gdk_pixbuf_get_height (*thumbnail);

      if (width > dimension || height > dimension) {
            GdkPixbuf *result_pixbuf;
            gfloat factor;

            if (width > height) {
                  factor = (gfloat) dimension / (gfloat) width;
            } else {
                  factor = (gfloat) dimension / (gfloat) height;              
            }
            
            width  = MAX (width  * factor, 1);
            height = MAX (height * factor, 1);
            
            result_pixbuf = gnome_thumbnail_scale_down_pixbuf (*thumbnail, 
                                                     width, height);
            
            g_object_unref (*thumbnail);

            *thumbnail = result_pixbuf;
      }
}

GdkPixbuf*
eog_thumbnail_load (EogImage *image, GError **error)
{
      GdkPixbuf *thumb = NULL;
      GnomeVFSURI *uri;
      EogThumbData *data;
      GdkPixbuf *pixbuf;

      g_return_val_if_fail (image != NULL, NULL);
      g_return_val_if_fail (error != NULL && *error == NULL, NULL);

      uri = eog_image_get_uri (image);
      data = eog_thumb_data_new (uri, error);
      gnome_vfs_uri_unref (uri);
      
      if (data == NULL)
            return NULL;

      /* check if there is already a valid thumbnail */
      thumb = get_valid_thumbnail (data, error);

      if (*error == NULL && thumb == NULL) {
            pixbuf = eog_image_get_pixbuf (image);
            if (pixbuf != NULL) {
                  thumb = create_thumbnail_from_pixbuf (data, pixbuf, error);
                  g_object_unref (pixbuf);
            } else {
                  thumb = create_thumbnail (data, error);
            }
      }

      eog_thumb_data_free (data);

      return thumb;
}

void
eog_thumbnail_init (void)
{
      if (factory == NULL) {
            factory = gnome_thumbnail_factory_new (GNOME_THUMBNAIL_SIZE_NORMAL);
      }

      if (frame == NULL) {
            frame = gdk_pixbuf_new_from_file (EOG_DATA_DIR "/pixmaps/thumbnail-frame.png", NULL);
      }
}

Generated by  Doxygen 1.6.0   Back to index