Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Thumbnails improvements #25

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
6 changes: 6 additions & 0 deletions src/base/fm-config.c
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,8 @@ static void fm_config_init(FmConfig *self)
self->thumbnail_size = FM_CONFIG_DEFAULT_THUMBNAIL_SIZE;
self->show_thumbnail = FM_CONFIG_DEFAULT_SHOW_THUMBNAIL;
self->thumbnail_local = FM_CONFIG_DEFAULT_THUMBNAIL_LOCAL;
self->thumbnail_threshold = FM_CONFIG_DEFAULT_THUMBNAIL_THRESHOLD;
self->thumbnail_overlay = FM_CONFIG_DEFAULT_THUMBNAIL_OVERLAY;
self->thumbnail_max = FM_CONFIG_DEFAULT_THUMBNAIL_MAX;
/* show_internal_volumes defaulted to FALSE */
/* si_unit defaulted to FALSE */
Expand Down Expand Up @@ -303,6 +305,8 @@ void fm_config_load_from_key_file(FmConfig* cfg, GKeyFile* kf)
fm_key_file_get_int(kf, "ui", "small_icon_size", &cfg->small_icon_size);
fm_key_file_get_int(kf, "ui", "pane_icon_size", &cfg->pane_icon_size);
fm_key_file_get_int(kf, "ui", "thumbnail_size", &cfg->thumbnail_size);
fm_key_file_get_int(kf, "ui", "thumbnail_threshold", &cfg->thumbnail_threshold);
fm_key_file_get_bool(kf, "ui", "thumbnail_overlay", &cfg->thumbnail_overlay);
fm_key_file_get_bool(kf, "ui", "show_thumbnail", &cfg->show_thumbnail);
fm_key_file_get_bool(kf, "ui", "shadow_hidden", &cfg->shadow_hidden);
g_free(cfg->list_view_size_units);
Expand Down Expand Up @@ -512,6 +516,8 @@ void fm_config_save(FmConfig* cfg, const char* name)
_save_config_int(str, cfg, small_icon_size);
_save_config_int(str, cfg, pane_icon_size);
_save_config_int(str, cfg, thumbnail_size);
_save_config_int(str, cfg, thumbnail_threshold);
_save_config_bool(str, cfg, thumbnail_overlay);
_save_config_bool(str, cfg, show_thumbnail);
_save_config_bool(str, cfg, shadow_hidden);
if (cfg->list_view_size_units && cfg->list_view_size_units[0])
Expand Down
9 changes: 6 additions & 3 deletions src/base/fm-config.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ typedef struct _FmConfigClass FmConfigClass;

#define FM_CONFIG_DEFAULT_SHOW_THUMBNAIL TRUE
#define FM_CONFIG_DEFAULT_THUMBNAIL_LOCAL TRUE
#define FM_CONFIG_DEFAULT_THUMBNAIL_THRESHOLD 48
#define FM_CONFIG_DEFAULT_THUMBNAIL_OVERLAY TRUE
#define FM_CONFIG_DEFAULT_THUMBNAIL_MAX 2048

#define FM_CONFIG_DEFAULT_FORCE_S_NOTIFY TRUE
Expand Down Expand Up @@ -208,9 +210,10 @@ struct _FmConfig
gboolean smart_desktop_autodrop;
gchar *saved_search;
/*< private >*/
gpointer _reserved1; /* reserved space for updates until next ABI */
gpointer _reserved2;
gpointer _reserved3;

gint thumbnail_threshold;
gboolean thumbnail_overlay;
gpointer _reserved3; /* reserved space for updates until next ABI */
gpointer _reserved4;
gpointer _reserved5;
gpointer _reserved6;
Expand Down
31 changes: 28 additions & 3 deletions src/base/fm-file-info.c
Original file line number Diff line number Diff line change
Expand Up @@ -443,7 +443,32 @@ gboolean _fm_file_info_set_from_native_file(FmFileInfo* fi, const char* path,
}
}
if(!fi->icon)
fi->icon = g_object_ref(fm_mime_type_get_icon(fi->mime_type));
{
if(S_ISDIR(st.st_mode))
{
/* If there is a custom folder icon, use it! */
char* path_name = fm_path_to_str(fi->path);
gchar *dot_dir = g_build_filename (path_name, G_DIR_SEPARATOR_S, ".directory", NULL);
g_free(path_name);
if(g_file_test(dot_dir, G_FILE_TEST_IS_REGULAR))
{
GKeyFile *key = g_key_file_new();
if(g_key_file_load_from_file(key, dot_dir, G_KEY_FILE_NONE, NULL))
{
gchar *icn = g_key_file_get_string(key, "Desktop Entry", "Icon", NULL);
if(icn)
{
fi->icon = fm_icon_from_name(icn);
g_free(icn);
}
}
g_key_file_free(key);
}
g_free(dot_dir);
}
if(!fi->icon)
fi->icon = g_object_ref(fm_mime_type_get_icon(fi->mime_type));
}

gfile = g_file_new_for_path(path);

Expand Down Expand Up @@ -1469,8 +1494,8 @@ gboolean fm_file_info_is_backup(FmFileInfo* fi)
gboolean fm_file_info_can_thumbnail(FmFileInfo* fi)
{
/* We cannot use S_ISREG here as this exclude all symlinks */
if( fi->size == 0 || /* don't generate thumbnails for empty files */
!(fi->mode & S_IFREG) ||
if( (fi->size == 0 && !(fi->mode & S_IFDIR)) || /* don't generate thumbnails for empty files */
!(fi->mode & (S_IFREG | S_IFDIR)) ||
fm_file_info_is_desktop_entry(fi) ||
fm_file_info_is_unknown_type(fi))
return FALSE;
Expand Down
49 changes: 35 additions & 14 deletions src/base/fm-thumbnail-loader.c
Original file line number Diff line number Diff line change
Expand Up @@ -845,23 +845,44 @@ static GObject* scale_pix(GObject* ori_pix, int size)
new_width = new_height = size;
}

if((new_width == width && new_height == height) ||
(size > width && size > height )) /* don't scale up */
/* if original size is smaller, use original size. */
if (size > width && size > height )
{
/* if size is not changed or original size is smaller, use original size. */
scaled_pix = (GObject*)g_object_ref(ori_pix);
}
else
{
/* avoid width or height of 0 pixel.
* FIXME: or we should just fail creating the thumbnail for the image? */
if(new_width == 0)
new_width = 1;
if(new_height == 0)
new_height = 1;
scaled_pix = backend.scale_image(ori_pix, new_width, new_height);
new_width = width;
new_height = height;
}

/* avoid width or height of 0 pixel.
* FIXME: or we should just fail creating the thumbnail for the image? */
if(new_width == 0)
new_width = 1;
if(new_height == 0)
new_height = 1;

double scale_factor = (double)new_width/width;

/* create new size*size image*/
scaled_pix = backend.new_image (
backend.get_colorspace(ori_pix),
TRUE,
backend.get_bits_per_sample(ori_pix),
size,
size);

/* fill the image with transparent pixels */
backend.fill_image(scaled_pix, 0x00000000);

/* scale original image composite it into the new image*/
backend.composite(
ori_pix, scaled_pix, /* src, dst */
(size-new_width)/2, /* dst_x */
(size-new_height)/2, /* dst_y */
new_width, /* dst_width */
new_height, /* dst_height */
(size-new_width)/2, /* offset_x */
(size-new_height)/2, /* offset_y */
scale_factor, scale_factor, /* scale_x, scale_y */
255); /* overall_alpha */
return scaled_pix;
}

Expand Down
11 changes: 11 additions & 0 deletions src/base/fm-thumbnail-loader.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,11 +77,16 @@ typedef struct _FmThumbnailLoaderBackend FmThumbnailLoaderBackend;
* @read_image_from_stream: callback to read image by opened #GInputStream
* @write_image: callback to write thumbnail file from image
* @scale_image: callback to change image sizes
* @new_image: callback to create new image
* @fill_image: callback to fill an image with a uniform color
* @rotate_image: callback to change image orientation
* @get_colorspace: callback to retrieve the image colorspace
* @get_image_width: callback to retrieve width from image
* @get_image_height: callback to retrieve height from image
* @get_bits_per_sample: callback to retrieve the image bit depth
* @get_image_text: callback to retrieve custom attributes text from image
* @set_image_text: callback to set custom attributes text into image
* @composite: callback to merge two images into one
*
* Abstract backend callbacks list.
*/
Expand All @@ -90,11 +95,17 @@ struct _FmThumbnailLoaderBackend {
GObject* (*read_image_from_stream)(GInputStream* stream, guint64 len, GCancellable* cancellable);
gboolean (*write_image)(GObject* image, const char* filename);
GObject* (*scale_image)(GObject* ori_pix, int new_width, int new_height);
GObject* (*new_image)(int colorspace, gboolean has_alpha, int bits_per_sample, int width, int height);
void (*fill_image)(GObject* image, guint32 color);
GObject* (*rotate_image)(GObject* image, int degree);
int (*get_colorspace)(GObject* image);
int (*get_image_width)(GObject* image);
int (*get_image_height)(GObject* image);
int (*get_bits_per_sample)(GObject* image);
char* (*get_image_text)(GObject* image, const char* key);
gboolean (*set_image_text)(GObject* image, const char* key, const char* val);
void (*composite)(GObject* src, GObject* dst, int dst_x, int dst_y, int dst_width, int dst_height,
double offset_x, double offset_y, double scale_x, double scale_y, int overall_alpha);
// const char* (*get_image_orientation)(GObject* image);
// GObject* (*apply_orientation)(GObject* image);
};
Expand Down
31 changes: 30 additions & 1 deletion src/gtk/fm-folder-model.c
Original file line number Diff line number Diff line change
Expand Up @@ -741,7 +741,9 @@ static void fm_folder_model_get_value(GtkTreeModel *tree_model,

/* if we want to show a thumbnail */
/* if we're on local filesystem or thumbnailing for remote files is allowed */
if(fm_config->show_thumbnail && (fm_path_is_native_or_trash(fm_file_info_get_path(info)) || !fm_config->thumbnail_local))
/* if current icon size is at least equal to the threshold size */
if(fm_config->show_thumbnail && (fm_path_is_native_or_trash(fm_file_info_get_path(info)) || !fm_config->thumbnail_local)
&& (model->icon_size >= fm_config->thumbnail_threshold) )
{
if(!item->is_thumbnail && !item->thumbnail_failed && !item->thumbnail_loading)
{
Expand Down Expand Up @@ -1600,7 +1602,30 @@ static void on_thumbnail_loaded(FmThumbnailRequest* req, gpointer user_data)
GDK_THREADS_ENTER();
tp = fm_folder_model_get_path(GTK_TREE_MODEL(model), &it);
if(item->icon)
{
if (fm_config->thumbnail_overlay)
{
float overlay_relative_size = 0.5;
int thumbnail_width = gdk_pixbuf_get_width(pix);
int thumbnail_height = gdk_pixbuf_get_height(pix);
int icon_width = gdk_pixbuf_get_width(item->icon);
int icon_height = gdk_pixbuf_get_height(item->icon);
int overlay_width = thumbnail_width * overlay_relative_size;
int overlay_height = thumbnail_height * overlay_relative_size;
gdk_pixbuf_composite(
item->icon, pix, /* src, dst */
thumbnail_width - overlay_width, /* dst_x */
thumbnail_height - overlay_height, /* dst_y */
overlay_width, /* dst_width */
overlay_height, /* dst_height */
thumbnail_width - overlay_width, /* offset_x */
thumbnail_height - overlay_height, /* offset_y */
overlay_relative_size, overlay_relative_size, /* scale_x, scale_y */
GDK_INTERP_BILINEAR, 255 /* interp_type, overall_alpha */
);
}
g_object_unref(item->icon);
}
item->icon = g_object_ref(pix);
item->is_thumbnail = TRUE;
gtk_tree_model_row_changed(GTK_TREE_MODEL(model), tp, &it);
Expand Down Expand Up @@ -1630,6 +1655,10 @@ void fm_folder_model_set_icon_size(FmFolderModel* model, guint icon_size)
{
if(model->icon_size == icon_size)
return;
if(model->icon_size >= fm_config->thumbnail_threshold && icon_size < fm_config->thumbnail_threshold)
{
g_list_foreach(model->thumbnail_requests, (GFunc)fm_thumbnail_request_cancel, NULL);
}
model->icon_size = icon_size;
reload_icons(model, RELOAD_BOTH);
}
Expand Down
34 changes: 33 additions & 1 deletion src/gtk/fm-thumbnail.c
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,26 @@ static GObject* scale_image(GObject* ori_pix, int new_width, int new_height)
return (GObject*)gdk_pixbuf_scale_simple(GDK_PIXBUF(ori_pix), new_width, new_height, GDK_INTERP_BILINEAR);
}

static GObject* new_image(int colorspace, gboolean has_alpha, int bits_per_sample, int width, int height)
{
return (GObject*)gdk_pixbuf_new(colorspace, has_alpha, bits_per_sample, width, height);
}

static void fill_image(GObject* image, guint32 color)
{
gdk_pixbuf_fill(GDK_PIXBUF(image), color);
}

static int get_colorspace(GObject* image)
{
return (int)gdk_pixbuf_get_colorspace(GDK_PIXBUF(image));
}

static int get_bits_per_sample(GObject* image)
{
return gdk_pixbuf_get_bits_per_sample(GDK_PIXBUF(image));
}

static int get_image_width(GObject* image)
{
return gdk_pixbuf_get_width(GDK_PIXBUF(image));
Expand All @@ -213,16 +233,28 @@ static GObject* rotate_image(GObject* image, int degree)
return (GObject*)gdk_pixbuf_rotate_simple(GDK_PIXBUF(image), (GdkPixbufRotation)degree);
}

static void composite(GObject* src, GObject* dst, int dst_x, int dst_y, int dst_width, int dst_height,
double offset_x, double offset_y, double scale_x, double scale_y, int overall_alpha)
{
gdk_pixbuf_composite(GDK_PIXBUF(src), GDK_PIXBUF(dst), dst_x, dst_y, dst_width, dst_height,
offset_x, offset_y, scale_x, scale_y, GDK_INTERP_BILINEAR, overall_alpha);
}

static FmThumbnailLoaderBackend gtk_backend = {
read_image_from_file,
read_image_from_stream,
write_image,
scale_image,
new_image,
fill_image,
rotate_image,
get_colorspace,
get_image_width,
get_image_height,
get_bits_per_sample,
get_image_text,
set_image_text
set_image_text,
composite
};

/* in main loop */
Expand Down