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;
}
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);
int landscape = w > h;
int orig_larger = landscape ? w : h;
/**
* Scales the given image dimensions if necessary according to the settings.
*
* @param w a pointer to the image width, to be modified in-place
* @param h a pointer to the image height, to be modified in-place
*/
static bool icon_size_clamp(int *w, int *h) {
int _w = *w, _h = *h;
int landscape = _w > _h;
int orig_larger = landscape ? _w : _h;
double larger = orig_larger;
double smaller = landscape ? h : w;
double smaller = landscape ? _h : _w;
if (settings.min_icon_size && smaller < settings.min_icon_size) {
larger = larger / 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;
}
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;
scaled = gdk_pixbuf_scale_simple(pixbuf,
(int) (landscape ? larger : smaller),
(int) (landscape ? smaller : larger),
GDK_INTERP_BILINEAR);
w,
h,
GDK_INTERP_BILINEAR);
g_object_unref(pixbuf);
pixbuf = scaled;
}
@ -145,8 +171,19 @@ GdkPixbuf *get_pixbuf_from_file(const char *filename)
{
char *path = string_to_path(g_strdup(filename));
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) {
LOG_W("%s", error->message);
@ -324,6 +361,8 @@ GdkPixbuf *icon_get_for_data(GVariant *data, char **id)
g_free(data_chk);
g_variant_unref(data_variant);
pixbuf = icon_pixbuf_scale(pixbuf);
return pixbuf;
}

View File

@ -8,18 +8,7 @@
cairo_surface_t *gdk_pixbuf_to_cairo_surface(GdkPixbuf *pixbuf);
/**
* 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.
/** Retrieve an icon by its full filepath, scaled according to settings.
*
* @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);
/** 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
* 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);
/** 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
* 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);
/** 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
* 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);
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)
@ -264,7 +263,6 @@ void notification_icon_replace_data(struct notification *n, GVariant *new_icon)
g_clear_pointer(&n->icon_id, g_free);
n->icon = icon_get_for_data(new_icon, &n->icon_id);
n->icon = icon_pixbuf_scale(n->icon);
}
/* see notification.h */