Scale icons during loading to get best quality for e.g. vector images

This commit is contained in:
Jonas Berlin 2019-11-29 21:28:22 +02:00
parent ab3b5c2805
commit 364bce1ed0
3 changed files with 56 additions and 30 deletions

View File

@ -110,16 +110,18 @@ cairo_surface_t *gdk_pixbuf_to_cairo_surface(GdkPixbuf *pixbuf)
return icon_surface; return icon_surface;
} }
GdkPixbuf *icon_pixbuf_scale(GdkPixbuf *pixbuf) /**
{ * Scales the given image dimensions if necessary according to the settings.
ASSERT_OR_RET(pixbuf, NULL); *
* @param w a pointer to the image width, to be modified in-place
int w = gdk_pixbuf_get_width(pixbuf); * @param h a pointer to the image height, to be modified in-place
int h = gdk_pixbuf_get_height(pixbuf); */
int landscape = w > h; static bool icon_size_clamp(int *w, int *h) {
int orig_larger = landscape ? w : h; int _w = *w, _h = *h;
int landscape = _w > _h;
int orig_larger = landscape ? _w : _h;
double larger = orig_larger; double larger = orig_larger;
double smaller = landscape ? h : w; double smaller = landscape ? _h : _w;
if (settings.min_icon_size && smaller < settings.min_icon_size) { if (settings.min_icon_size && smaller < settings.min_icon_size) {
larger = larger / smaller * settings.min_icon_size; larger = larger / smaller * settings.min_icon_size;
smaller = settings.min_icon_size; smaller = settings.min_icon_size;
@ -129,11 +131,35 @@ GdkPixbuf *icon_pixbuf_scale(GdkPixbuf *pixbuf)
larger = settings.max_icon_size; larger = settings.max_icon_size;
} }
if ((int) larger != orig_larger) { if ((int) larger != orig_larger) {
*w = (int) (landscape ? larger : smaller);
*h = (int) (landscape ? smaller : larger);
return TRUE;
}
return FALSE;
}
/**
* Scales the given GdkPixbuf if necessary according to the settings.
*
* @param pixbuf (nullable) The pixbuf, which may be too big.
* Takes ownership of the reference.
* @return the scaled version of the pixbuf. If scaling wasn't
* necessary, it returns the same pixbuf. Transfers full
* ownership of the reference.
*/
static GdkPixbuf *icon_pixbuf_scale(GdkPixbuf *pixbuf)
{
ASSERT_OR_RET(pixbuf, NULL);
int w = gdk_pixbuf_get_width(pixbuf);
int h = gdk_pixbuf_get_height(pixbuf);
if (icon_size_clamp(&w, &h)) {
GdkPixbuf *scaled; GdkPixbuf *scaled;
scaled = gdk_pixbuf_scale_simple(pixbuf, scaled = gdk_pixbuf_scale_simple(pixbuf,
(int) (landscape ? larger : smaller), w,
(int) (landscape ? smaller : larger), h,
GDK_INTERP_BILINEAR); GDK_INTERP_BILINEAR);
g_object_unref(pixbuf); g_object_unref(pixbuf);
pixbuf = scaled; pixbuf = scaled;
} }
@ -145,8 +171,19 @@ GdkPixbuf *get_pixbuf_from_file(const char *filename)
{ {
char *path = string_to_path(g_strdup(filename)); char *path = string_to_path(g_strdup(filename));
GError *error = NULL; GError *error = NULL;
gint w, h;
GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file(path, &error); if (!gdk_pixbuf_get_file_info (path, &w, &h)) {
LOG_W("Failed to load image info for %s", filename);
g_error_free(error);
return NULL;
}
icon_size_clamp(&w, &h);
GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file_at_scale(path,
w,
h,
TRUE,
&error);
if (error) { if (error) {
LOG_W("%s", error->message); LOG_W("%s", error->message);
@ -324,6 +361,8 @@ GdkPixbuf *icon_get_for_data(GVariant *data, char **id)
g_free(data_chk); g_free(data_chk);
g_variant_unref(data_variant); g_variant_unref(data_variant);
pixbuf = icon_pixbuf_scale(pixbuf);
return pixbuf; return pixbuf;
} }

View File

@ -8,18 +8,7 @@
cairo_surface_t *gdk_pixbuf_to_cairo_surface(GdkPixbuf *pixbuf); cairo_surface_t *gdk_pixbuf_to_cairo_surface(GdkPixbuf *pixbuf);
/** /** Retrieve an icon by its full filepath, scaled according to settings.
* Scales the given GdkPixbuf if necessary according to the settings.
*
* @param pixbuf (nullable) The pixbuf, which may be too big.
* Takes ownership of the reference.
* @return the scaled version of the pixbuf. If scaling wasn't
* necessary, it returns the same pixbuf. Transfers full
* ownership of the reference.
*/
GdkPixbuf *icon_pixbuf_scale(GdkPixbuf *pixbuf);
/** Retrieve an icon by its full filepath.
* *
* @param filename A string representing a readable file path * @param filename A string representing a readable file path
* *
@ -28,7 +17,7 @@ GdkPixbuf *icon_pixbuf_scale(GdkPixbuf *pixbuf);
*/ */
GdkPixbuf *get_pixbuf_from_file(const char *filename); GdkPixbuf *get_pixbuf_from_file(const char *filename);
/** Retrieve an icon by its name sent via the notification bus /** Retrieve an icon by its name sent via the notification bus, scaled according to settings
* *
* @param iconname A string describing a `file://` URL, an arbitary filename * @param iconname A string describing a `file://` URL, an arbitary filename
* or an icon name, which then gets searched for in the * or an icon name, which then gets searched for in the
@ -39,7 +28,7 @@ GdkPixbuf *get_pixbuf_from_file(const char *filename);
*/ */
GdkPixbuf *get_pixbuf_from_icon(const char *iconname); GdkPixbuf *get_pixbuf_from_icon(const char *iconname);
/** Read an icon from disk and convert it to a GdkPixbuf. /** Read an icon from disk and convert it to a GdkPixbuf, scaled according to settings
* *
* The returned id will be a unique identifier. To check if two given * The returned id will be a unique identifier. To check if two given
* GdkPixbufs are equal, it's sufficient to just compare the id strings. * GdkPixbufs are equal, it's sufficient to just compare the id strings.
@ -54,7 +43,7 @@ GdkPixbuf *get_pixbuf_from_icon(const char *iconname);
*/ */
GdkPixbuf *icon_get_for_name(const char *name, char **id); GdkPixbuf *icon_get_for_name(const char *name, char **id);
/** Convert a GVariant like described in GdkPixbuf /** Convert a GVariant like described in GdkPixbuf, scaled according to settings
* *
* The returned id will be a unique identifier. To check if two given * The returned id will be a unique identifier. To check if two given
* GdkPixbufs are equal, it's sufficient to just compare the id strings. * GdkPixbufs are equal, it's sufficient to just compare the id strings.

View File

@ -252,7 +252,6 @@ void notification_icon_replace_path(struct notification *n, const char *new_icon
g_clear_pointer(&n->icon_id, g_free); g_clear_pointer(&n->icon_id, g_free);
n->icon = icon_get_for_name(new_icon, &n->icon_id); n->icon = icon_get_for_name(new_icon, &n->icon_id);
n->icon = icon_pixbuf_scale(n->icon);
} }
void notification_icon_replace_data(struct notification *n, GVariant *new_icon) void notification_icon_replace_data(struct notification *n, GVariant *new_icon)
@ -264,7 +263,6 @@ void notification_icon_replace_data(struct notification *n, GVariant *new_icon)
g_clear_pointer(&n->icon_id, g_free); g_clear_pointer(&n->icon_id, g_free);
n->icon = icon_get_for_data(new_icon, &n->icon_id); n->icon = icon_get_for_data(new_icon, &n->icon_id);
n->icon = icon_pixbuf_scale(n->icon);
} }
/* see notification.h */ /* see notification.h */