[gnome-games] cover-loader: optimize blurring of background
- From: Alexander Mikhaylenko <alexm src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-games] cover-loader: optimize blurring of background
- Date: Sat, 13 Jun 2020 13:57:08 +0000 (UTC)
commit fc3731bfd2fd12ce6f1f8143501583a87cc95e15
Author: Neville <nevilleantony98 gmail com>
Date: Fri Jun 12 11:57:57 2020 +0530
cover-loader: optimize blurring of background
Add a fast path for covers with height == width.
It now blurs only the visible parts of the background and applies
shadows to it..
Co-authored-by: Alexander Mikhaylenko <alexm gnome org>
src/core/cover-loader.vala | 134 ++++++++++++++++++++++++++++++++++-----------
1 file changed, 103 insertions(+), 31 deletions(-)
---
diff --git a/src/core/cover-loader.vala b/src/core/cover-loader.vala
index 8e9da019..4b21abcf 100644
--- a/src/core/cover-loader.vala
+++ b/src/core/cover-loader.vala
@@ -2,6 +2,7 @@
public class Games.CoverLoader : Object {
const double COVER_BLUR_RADIUS_FACTOR = 30.0 / 128.0;
+ const double SHADOW_FACTOR = 20.0 / 128;
public delegate void CoverReadyCallback (int cover_size, Gdk.Pixbuf? cover_pixbuf, int icon_size,
Gdk.Pixbuf? icon_pixbuf);
@@ -123,74 +124,145 @@ public class Games.CoverLoader : Object {
}
}
+ private void draw_cover_blur_rect (Cairo.Context cr, Gdk.Pixbuf pixbuf, int size, bool reverse, int
x, int y, int w, int h) {
+ int radius = (int) (COVER_BLUR_RADIUS_FACTOR * size);
+ int shadow_width = (int) (SHADOW_FACTOR * size);
+
+ if (w == 0 || h == 0)
+ return;
+
+ var gradient = new Cairo.Pattern.linear (0, 0,
+ h > w ? -shadow_width : 0,
+ h < w ? -shadow_width : 0);
+ gradient.add_color_stop_rgba (0, 0, 0, 0, 0.15);
+ gradient.add_color_stop_rgba (1, 0, 0, 0, 0);
+
+ cr.save ();
+
+ cr.rectangle (0, 0, w, h);
+ cr.clip ();
+
+ var subpixbuf = new Gdk.Pixbuf.subpixbuf (pixbuf, x, y, w, h);
+ var surface = Gdk.cairo_surface_create_from_pixbuf (subpixbuf, 0, null);
+ CairoBlur.blur_surface (surface, radius);
+ cr.set_source_surface (surface, 0, 0);
+ cr.paint ();
+
+ if (reverse)
+ cr.rotate (Math.PI);
+ else if (h > w)
+ cr.translate (w, 0);
+ else
+ cr.translate (0, h);
+
+ cr.set_source (gradient);
+ cr.paint ();
+
+ cr.rotate (Math.PI);
+
+ if (h > w)
+ cr.rectangle (0, reverse ? 0 : -h, 1, h);
+ else
+ cr.rectangle (reverse ? 0 : -w, 0, w, 1);
+
+ cr.set_source_rgba (0, 0, 0, 0.2);
+ cr.fill ();
+
+ cr.set_source_rgba (0, 0, 0, 0.1);
+ cr.paint ();
+
+ cr.restore ();
+ }
+
private Gdk.Pixbuf? create_cover_thumbnail (File file, int size) {
Gdk.Pixbuf overlay_pixbuf, blur_pixbuf;
- int blur_x, blur_y, overlay_x, overlay_y;
- int width, height, radius;
+ int overlay_x, overlay_y;
+ int width, height, zoom_width, zoom_height;
double aspect_ratio;
- radius = (int) (COVER_BLUR_RADIUS_FACTOR * size);
Gdk.Pixbuf.get_file_info (file.get_path (), out width, out height);
+
aspect_ratio = (double) width / height;
if (height >= width) {
height = size;
width = (int) (size * aspect_ratio);
- aspect_ratio = (double) width / height;
- blur_x = 0;
- blur_y = (int) (height * (1 - aspect_ratio) / 2);
+ zoom_width = size;
+ zoom_height = (int) (size * height / (double) width);
- overlay_x = (int) ((width/aspect_ratio - width) / 2);
+ overlay_x = (int) ((height - width) / 2);
overlay_y = 0;
}
else {
width = size;
height = (int) (size / aspect_ratio);
- aspect_ratio = (double) height / width;
- blur_x = (int) (width * (1 - aspect_ratio) / 2);
- blur_y = 0;
+ zoom_height = size;
+ zoom_width = (int) (size * width / (double) height);
overlay_x = 0;
- overlay_y = (int) ((height/aspect_ratio - height) / 2);
+ overlay_y = (int) ((width - height) / 2);
}
- var zoom_width = (int) (width / aspect_ratio);
- var zoom_height = (int) (height / aspect_ratio);
+ if (width == height) {
+ try {
+ return new Gdk.Pixbuf.from_file_at_scale (file.get_path (), width, height,
false);
+ }
+ catch (Error e) {
+ critical ("Failed to load cover: %s", e.message);
+ }
+ }
var image_surface = new Cairo.ImageSurface (Cairo.Format.ARGB32, size, size);
- var target_cr = new Cairo.Context (image_surface);
+ var cr = new Cairo.Context (image_surface);
try {
overlay_pixbuf = new Gdk.Pixbuf.from_file_at_scale (file.get_path (), width, height,
false);
- var temp_pixbuf = new Gdk.Pixbuf.from_file_at_scale (file.get_path (), zoom_width,
zoom_height, false);
- blur_pixbuf = new Gdk.Pixbuf.subpixbuf (temp_pixbuf, blur_x, blur_y, size, size);
+ blur_pixbuf = new Gdk.Pixbuf.from_file_at_scale (file.get_path (), zoom_width,
zoom_height, false);
}
catch (Error e) {
critical ("Failed to load cover image: %s", e.message);
return null;
}
- var surface = Gdk.cairo_surface_create_from_pixbuf (blur_pixbuf, 0, null);
- var shadow_cr = new Cairo.Context (surface);
- shadow_cr.rectangle (overlay_x, overlay_y, width, height);
- shadow_cr.set_source_rgba (0, 0, 0, 0.2);
- shadow_cr.fill ();
+ cr.save ();
- shadow_cr.set_source_rgba (0, 0, 0, 0.1);
- shadow_cr.paint ();
+ if (height >= width) {
+ var blur_y = (int) ((double) (height - width) / 2);
- CairoBlur.blur_surface (surface, radius);
- target_cr.set_source_surface (surface, 0, 0);
- target_cr.paint ();
+ draw_cover_blur_rect (cr, blur_pixbuf, size, false,
+ 0, blur_y, overlay_x, size);
+
+ if (height > width)
+ cr.translate (overlay_x + width, 0);
+ else
+ cr.translate (0, blur_y);
+
+ draw_cover_blur_rect (cr, blur_pixbuf, size, true,
+ overlay_x + width, blur_y,
+ size - width - overlay_x, size);
+ }
+ else {
+ var blur_x = (int) ((double) (width - height) / 2);
+
+ draw_cover_blur_rect (cr, blur_pixbuf, size, false,
+ blur_x, 0, size, overlay_y);
+
+ if (height > width)
+ cr.translate (blur_x, 0);
+ else
+ cr.translate (0, overlay_y + height);
+
+ draw_cover_blur_rect (cr, blur_pixbuf, size, true,
+ blur_x, overlay_y + height,
+ size, size - height - overlay_y);
+ }
- target_cr.rectangle (overlay_x - 1, overlay_y - 1, width + 2, height + 2);
- target_cr.set_source_rgba (0, 0, 0, 0.2);
- target_cr.fill ();
+ cr.restore ();
- Gdk.cairo_set_source_pixbuf (target_cr, overlay_pixbuf, overlay_x, overlay_y);
- target_cr.paint ();
+ Gdk.cairo_set_source_pixbuf (cr, overlay_pixbuf, overlay_x, overlay_y);
+ cr.paint ();
return Gdk.pixbuf_get_from_surface (image_surface, 0, 0, size, size);
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]