We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Won't open configure panel with some icons
```
2021-11-03 02:59:23,691: Unable to load icon from image fl-studio
Traceback (most recent call last):
  File "/usr/lib/python3/dist-packages/lutris/game_actions.py", line 178, in on_edit_game_configuration
    EditGameConfigDialog(self.window, self.game)
  File "/usr/lib/python3/dist-packages/lutris/gui/config/edit_game.py", line 16, in __init__
    self.build_tabs("game")
  File "/usr/lib/python3/dist-packages/lutris/gui/config/common.py", line 70, in build_tabs
    self._build_info_tab()
  File "/usr/lib/python3/dist-packages/lutris/gui/config/common.py", line 79, in _build_info_tab
    info_box.pack_start(self._get_banner_box(), False, False, 6)  # Banner
  File "/usr/lib/python3/dist-packages/lutris/gui/config/common.py", line 155, in _get_banner_box
    self._set_image("banner")
  File "/usr/lib/python3/dist-packages/lutris/gui/config/common.py", line 195, in _set_image
    image.set_from_pixbuf(get_pixbuf_for_game(game_slug, size))
  File "/usr/lib/python3/dist-packages/lutris/gui/widgets/utils.py", line 127, in get_pixbuf_for_game
    return get_pixbuf(image_abspath, size, fallback=get_default_icon(size), is_installed=is_installed)
  File "/usr/lib/python3/dist-packages/lutris/gui/widgets/utils.py", line 58, in get_pixbuf
    pixbuf = pixbuf.scale_simple(width, height, GdkPixbuf.InterpType.NEAREST)
AttributeError: 'NoneType' object has no attribute 'scale_simple'
```


This seems to happen with the icon for "FL Studio", right click > configure to reproduce.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `lutris/gui/widgets/utils.py`
Content:
```
1 """Various utilities using the GObject framework"""
2 import array
3 import os
4 
5 from gi.repository import Gdk, GdkPixbuf, Gio, GLib, Gtk
6 
7 from lutris import settings
8 from lutris.util import datapath, system
9 from lutris.util.log import logger
10 
11 try:
12     from PIL import Image
13 except ImportError:
14     Image = None
15 
16 ICON_SIZE = (32, 32)
17 BANNER_SIZE = (184, 69)
18 
19 
20 def get_main_window(widget):
21     """Return the application's main window from one of its widget"""
22     parent = widget.get_toplevel()
23     if not isinstance(parent, Gtk.Window):
24         # The sync dialog may have closed
25         parent = Gio.Application.get_default().props.active_window
26     for window in parent.application.get_windows():
27         if "LutrisWindow" in window.__class__.__name__:
28             return window
29     return
30 
31 
32 def open_uri(uri):
33     """Opens a local or remote URI with the default application"""
34     system.reset_library_preloads()
35     try:
36         Gtk.show_uri(None, uri, Gdk.CURRENT_TIME)
37     except GLib.Error as ex:
38         logger.exception("Failed to open URI %s: %s, falling back to xdg-open", uri, ex)
39         system.execute(["xdg-open", uri])
40 
41 
42 def get_pixbuf(image, size, fallback=None, is_installed=True):
43     """Return a pixbuf from file `image` at `size` or fallback to `fallback`"""
44     width, height = size
45     pixbuf = None
46     if system.path_exists(image, exclude_empty=True):
47         try:
48             pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(image, width, height)
49             pixbuf = pixbuf.scale_simple(width, height, GdkPixbuf.InterpType.NEAREST)
50         except GLib.GError:
51             logger.error("Unable to load icon from image %s", image)
52     else:
53         if not fallback:
54             fallback = get_default_icon(size)
55         if system.path_exists(fallback):
56             pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(fallback, width, height)
57     if is_installed:
58         pixbuf = pixbuf.scale_simple(width, height, GdkPixbuf.InterpType.NEAREST)
59         return pixbuf
60     overlay = os.path.join(datapath.get(), "media/unavailable.png")
61     transparent_pixbuf = get_overlay(overlay, size).copy()
62     if pixbuf:
63         pixbuf.composite(
64             transparent_pixbuf,
65             0,
66             0,
67             size[0],
68             size[1],
69             0,
70             0,
71             1,
72             1,
73             GdkPixbuf.InterpType.NEAREST,
74             100,
75         )
76     return transparent_pixbuf
77 
78 
79 def get_stock_icon(name, size):
80     """Return a pixbuf from a stock icon name"""
81     theme = Gtk.IconTheme.get_default()
82     try:
83         return theme.load_icon(name, size, Gtk.IconLookupFlags.GENERIC_FALLBACK)
84     except GLib.GError:
85         logger.error("Failed to read icon %s", name)
86         return None
87 
88 
89 def get_icon(icon_name, icon_format="image", size=None, icon_type="runner"):
90     """Return an icon based on the given name, format, size and type.
91 
92     Keyword arguments:
93     icon_name -- The name of the icon to retrieve
94     format -- The format of the icon, which should be either 'image' or 'pixbuf' (default 'image')
95     size -- The size for the desired image (default None)
96     icon_type -- Retrieve either a 'runner' or 'platform' icon (default 'runner')
97     """
98     filename = icon_name.lower().replace(" ", "") + ".png"
99     icon_path = os.path.join(settings.RUNTIME_DIR, "icons/hicolor/64x64/apps", filename)
100     if not os.path.exists(icon_path):
101         return None
102     if icon_format == "image":
103         icon = Gtk.Image()
104         if size:
105             icon.set_from_pixbuf(get_pixbuf(icon_path, size))
106         else:
107             icon.set_from_file(icon_path)
108         return icon
109     if icon_format == "pixbuf" and size:
110         return get_pixbuf(icon_path, size)
111     raise ValueError("Invalid arguments")
112 
113 
114 def get_overlay(overlay_path, size):
115     width, height = size
116     transparent_pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(overlay_path, width, height)
117     transparent_pixbuf = transparent_pixbuf.scale_simple(width, height, GdkPixbuf.InterpType.NEAREST)
118     return transparent_pixbuf
119 
120 
121 def get_default_icon(size):
122     if size[0] == size[1]:
123         return os.path.join(datapath.get(), "media/default_icon.png")
124     return os.path.join(datapath.get(), "media/default_banner.png")
125 
126 
127 def convert_to_background(background_path, target_size=(320, 1080)):
128     """Converts a image to a pane background"""
129     coverart = Image.open(background_path)
130     coverart = coverart.convert("RGBA")
131 
132     target_width, target_height = target_size
133     image_height = int(target_height * 0.80)  # 80% of the mask is visible
134     orig_width, orig_height = coverart.size
135 
136     # Resize and crop coverart
137     width = int(orig_width * (image_height / orig_height))
138     offset = int((width - target_width) / 2)
139     coverart = coverart.resize((width, image_height), resample=Image.BICUBIC)
140     coverart = coverart.crop((offset, 0, target_width + offset, image_height))
141 
142     # Resize canvas of coverart by putting transparent pixels on the bottom
143     coverart_bg = Image.new('RGBA', (target_width, target_height), (0, 0, 0, 0))
144     coverart_bg.paste(coverart, (0, 0, target_width, image_height))
145 
146     # Apply a tint to the base image
147     # tint = Image.new('RGBA', (target_width, target_height), (0, 0, 0, 255))
148     # coverart = Image.blend(coverart, tint, 0.6)
149 
150     # Paste coverart on transparent image while applying a gradient mask
151     background = Image.new('RGBA', (target_width, target_height), (0, 0, 0, 0))
152     mask = Image.open(os.path.join(datapath.get(), "media/mask.png"))
153     background.paste(coverart_bg, mask=mask)
154 
155     return background
156 
157 
158 def thumbnail_image(base_image, target_size):
159     base_width, base_height = base_image.size
160     base_ratio = base_width / base_height
161     target_width, target_height = target_size
162     target_ratio = target_width / target_height
163 
164     # Resize and crop coverart
165     if base_ratio >= target_ratio:
166         width = int(base_width * (target_height / base_height))
167         height = target_height
168     else:
169         width = target_width
170         height = int(base_height * (target_width / base_width))
171     x_offset = int((width - target_width) / 2)
172     y_offset = int((height - target_height) / 2)
173     base_image = base_image.resize((width, height), resample=Image.BICUBIC)
174     base_image = base_image.crop((x_offset, y_offset, width - x_offset, height - y_offset))
175     return base_image
176 
177 
178 def paste_overlay(base_image, overlay_image, position=0.7):
179     base_width, base_height = base_image.size
180     overlay_width, overlay_height = overlay_image.size
181     offset_x = int((base_width - overlay_width) / 2)
182     offset_y = int((base_height - overlay_height) / 2)
183     base_image.paste(
184         overlay_image, (
185             offset_x,
186             offset_y,
187             overlay_width + offset_x,
188             overlay_height + offset_y
189         ),
190         mask=overlay_image
191     )
192     return base_image
193 
194 
195 def image2pixbuf(image):
196     """Converts a PIL Image to a GDK Pixbuf"""
197     image_array = array.array('B', image.tobytes())
198     width, height = image.size
199     return GdkPixbuf.Pixbuf.new_from_data(image_array, GdkPixbuf.Colorspace.RGB, True, 8, width, height, width * 4)
200 
201 
202 def get_link_button(text):
203     """Return a transparent text button for the side panels"""
204     button = Gtk.Button(text, visible=True)
205     button.props.relief = Gtk.ReliefStyle.NONE
206     button.get_children()[0].set_alignment(0, 0.5)
207     button.get_style_context().add_class("panel-button")
208     button.set_size_request(-1, 24)
209     return button
210 
211 
212 def load_icon_theme():
213     """Add the lutris icon folder to the default theme"""
214     icon_theme = Gtk.IconTheme.get_default()
215     local_theme_path = os.path.join(settings.RUNTIME_DIR, "icons")
216     if local_theme_path not in icon_theme.get_search_path():
217         icon_theme.prepend_search_path(local_theme_path)
218
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/lutris/gui/widgets/utils.py b/lutris/gui/widgets/utils.py
--- a/lutris/gui/widgets/utils.py
+++ b/lutris/gui/widgets/utils.py
@@ -54,7 +54,7 @@
             fallback = get_default_icon(size)
         if system.path_exists(fallback):
             pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(fallback, width, height)
-    if is_installed:
+    if is_installed and pixbuf:
         pixbuf = pixbuf.scale_simple(width, height, GdkPixbuf.InterpType.NEAREST)
         return pixbuf
     overlay = os.path.join(datapath.get(), "media/unavailable.png")

{"golden_diff": "diff --git a/lutris/gui/widgets/utils.py b/lutris/gui/widgets/utils.py\n--- a/lutris/gui/widgets/utils.py\n+++ b/lutris/gui/widgets/utils.py\n@@ -54,7 +54,7 @@\n             fallback = get_default_icon(size)\n         if system.path_exists(fallback):\n             pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(fallback, width, height)\n-    if is_installed:\n+    if is_installed and pixbuf:\n         pixbuf = pixbuf.scale_simple(width, height, GdkPixbuf.InterpType.NEAREST)\n         return pixbuf\n     overlay = os.path.join(datapath.get(), \"media/unavailable.png\")\n", "issue": "Won't open configure panel with some icons\n```\r\n2021-11-03 02:59:23,691: Unable to load icon from image fl-studio\r\nTraceback (most recent call last):\r\n  File \"/usr/lib/python3/dist-packages/lutris/game_actions.py\", line 178, in on_edit_game_configuration\r\n    EditGameConfigDialog(self.window, self.game)\r\n  File \"/usr/lib/python3/dist-packages/lutris/gui/config/edit_game.py\", line 16, in __init__\r\n    self.build_tabs(\"game\")\r\n  File \"/usr/lib/python3/dist-packages/lutris/gui/config/common.py\", line 70, in build_tabs\r\n    self._build_info_tab()\r\n  File \"/usr/lib/python3/dist-packages/lutris/gui/config/common.py\", line 79, in _build_info_tab\r\n    info_box.pack_start(self._get_banner_box(), False, False, 6)  # Banner\r\n  File \"/usr/lib/python3/dist-packages/lutris/gui/config/common.py\", line 155, in _get_banner_box\r\n    self._set_image(\"banner\")\r\n  File \"/usr/lib/python3/dist-packages/lutris/gui/config/common.py\", line 195, in _set_image\r\n    image.set_from_pixbuf(get_pixbuf_for_game(game_slug, size))\r\n  File \"/usr/lib/python3/dist-packages/lutris/gui/widgets/utils.py\", line 127, in get_pixbuf_for_game\r\n    return get_pixbuf(image_abspath, size, fallback=get_default_icon(size), is_installed=is_installed)\r\n  File \"/usr/lib/python3/dist-packages/lutris/gui/widgets/utils.py\", line 58, in get_pixbuf\r\n    pixbuf = pixbuf.scale_simple(width, height, GdkPixbuf.InterpType.NEAREST)\r\nAttributeError: 'NoneType' object has no attribute 'scale_simple'\r\n```\r\n\r\n\r\nThis seems to happen with the icon for \"FL Studio\", right click > configure to reproduce.\n", "before_files": [{"content": "\"\"\"Various utilities using the GObject framework\"\"\"\nimport array\nimport os\n\nfrom gi.repository import Gdk, GdkPixbuf, Gio, GLib, Gtk\n\nfrom lutris import settings\nfrom lutris.util import datapath, system\nfrom lutris.util.log import logger\n\ntry:\n    from PIL import Image\nexcept ImportError:\n    Image = None\n\nICON_SIZE = (32, 32)\nBANNER_SIZE = (184, 69)\n\n\ndef get_main_window(widget):\n    \"\"\"Return the application's main window from one of its widget\"\"\"\n    parent = widget.get_toplevel()\n    if not isinstance(parent, Gtk.Window):\n        # The sync dialog may have closed\n        parent = Gio.Application.get_default().props.active_window\n    for window in parent.application.get_windows():\n        if \"LutrisWindow\" in window.__class__.__name__:\n            return window\n    return\n\n\ndef open_uri(uri):\n    \"\"\"Opens a local or remote URI with the default application\"\"\"\n    system.reset_library_preloads()\n    try:\n        Gtk.show_uri(None, uri, Gdk.CURRENT_TIME)\n    except GLib.Error as ex:\n        logger.exception(\"Failed to open URI %s: %s, falling back to xdg-open\", uri, ex)\n        system.execute([\"xdg-open\", uri])\n\n\ndef get_pixbuf(image, size, fallback=None, is_installed=True):\n    \"\"\"Return a pixbuf from file `image` at `size` or fallback to `fallback`\"\"\"\n    width, height = size\n    pixbuf = None\n    if system.path_exists(image, exclude_empty=True):\n        try:\n            pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(image, width, height)\n            pixbuf = pixbuf.scale_simple(width, height, GdkPixbuf.InterpType.NEAREST)\n        except GLib.GError:\n            logger.error(\"Unable to load icon from image %s\", image)\n    else:\n        if not fallback:\n            fallback = get_default_icon(size)\n        if system.path_exists(fallback):\n            pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(fallback, width, height)\n    if is_installed:\n        pixbuf = pixbuf.scale_simple(width, height, GdkPixbuf.InterpType.NEAREST)\n        return pixbuf\n    overlay = os.path.join(datapath.get(), \"media/unavailable.png\")\n    transparent_pixbuf = get_overlay(overlay, size).copy()\n    if pixbuf:\n        pixbuf.composite(\n            transparent_pixbuf,\n            0,\n            0,\n            size[0],\n            size[1],\n            0,\n            0,\n            1,\n            1,\n            GdkPixbuf.InterpType.NEAREST,\n            100,\n        )\n    return transparent_pixbuf\n\n\ndef get_stock_icon(name, size):\n    \"\"\"Return a pixbuf from a stock icon name\"\"\"\n    theme = Gtk.IconTheme.get_default()\n    try:\n        return theme.load_icon(name, size, Gtk.IconLookupFlags.GENERIC_FALLBACK)\n    except GLib.GError:\n        logger.error(\"Failed to read icon %s\", name)\n        return None\n\n\ndef get_icon(icon_name, icon_format=\"image\", size=None, icon_type=\"runner\"):\n    \"\"\"Return an icon based on the given name, format, size and type.\n\n    Keyword arguments:\n    icon_name -- The name of the icon to retrieve\n    format -- The format of the icon, which should be either 'image' or 'pixbuf' (default 'image')\n    size -- The size for the desired image (default None)\n    icon_type -- Retrieve either a 'runner' or 'platform' icon (default 'runner')\n    \"\"\"\n    filename = icon_name.lower().replace(\" \", \"\") + \".png\"\n    icon_path = os.path.join(settings.RUNTIME_DIR, \"icons/hicolor/64x64/apps\", filename)\n    if not os.path.exists(icon_path):\n        return None\n    if icon_format == \"image\":\n        icon = Gtk.Image()\n        if size:\n            icon.set_from_pixbuf(get_pixbuf(icon_path, size))\n        else:\n            icon.set_from_file(icon_path)\n        return icon\n    if icon_format == \"pixbuf\" and size:\n        return get_pixbuf(icon_path, size)\n    raise ValueError(\"Invalid arguments\")\n\n\ndef get_overlay(overlay_path, size):\n    width, height = size\n    transparent_pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(overlay_path, width, height)\n    transparent_pixbuf = transparent_pixbuf.scale_simple(width, height, GdkPixbuf.InterpType.NEAREST)\n    return transparent_pixbuf\n\n\ndef get_default_icon(size):\n    if size[0] == size[1]:\n        return os.path.join(datapath.get(), \"media/default_icon.png\")\n    return os.path.join(datapath.get(), \"media/default_banner.png\")\n\n\ndef convert_to_background(background_path, target_size=(320, 1080)):\n    \"\"\"Converts a image to a pane background\"\"\"\n    coverart = Image.open(background_path)\n    coverart = coverart.convert(\"RGBA\")\n\n    target_width, target_height = target_size\n    image_height = int(target_height * 0.80)  # 80% of the mask is visible\n    orig_width, orig_height = coverart.size\n\n    # Resize and crop coverart\n    width = int(orig_width * (image_height / orig_height))\n    offset = int((width - target_width) / 2)\n    coverart = coverart.resize((width, image_height), resample=Image.BICUBIC)\n    coverart = coverart.crop((offset, 0, target_width + offset, image_height))\n\n    # Resize canvas of coverart by putting transparent pixels on the bottom\n    coverart_bg = Image.new('RGBA', (target_width, target_height), (0, 0, 0, 0))\n    coverart_bg.paste(coverart, (0, 0, target_width, image_height))\n\n    # Apply a tint to the base image\n    # tint = Image.new('RGBA', (target_width, target_height), (0, 0, 0, 255))\n    # coverart = Image.blend(coverart, tint, 0.6)\n\n    # Paste coverart on transparent image while applying a gradient mask\n    background = Image.new('RGBA', (target_width, target_height), (0, 0, 0, 0))\n    mask = Image.open(os.path.join(datapath.get(), \"media/mask.png\"))\n    background.paste(coverart_bg, mask=mask)\n\n    return background\n\n\ndef thumbnail_image(base_image, target_size):\n    base_width, base_height = base_image.size\n    base_ratio = base_width / base_height\n    target_width, target_height = target_size\n    target_ratio = target_width / target_height\n\n    # Resize and crop coverart\n    if base_ratio >= target_ratio:\n        width = int(base_width * (target_height / base_height))\n        height = target_height\n    else:\n        width = target_width\n        height = int(base_height * (target_width / base_width))\n    x_offset = int((width - target_width) / 2)\n    y_offset = int((height - target_height) / 2)\n    base_image = base_image.resize((width, height), resample=Image.BICUBIC)\n    base_image = base_image.crop((x_offset, y_offset, width - x_offset, height - y_offset))\n    return base_image\n\n\ndef paste_overlay(base_image, overlay_image, position=0.7):\n    base_width, base_height = base_image.size\n    overlay_width, overlay_height = overlay_image.size\n    offset_x = int((base_width - overlay_width) / 2)\n    offset_y = int((base_height - overlay_height) / 2)\n    base_image.paste(\n        overlay_image, (\n            offset_x,\n            offset_y,\n            overlay_width + offset_x,\n            overlay_height + offset_y\n        ),\n        mask=overlay_image\n    )\n    return base_image\n\n\ndef image2pixbuf(image):\n    \"\"\"Converts a PIL Image to a GDK Pixbuf\"\"\"\n    image_array = array.array('B', image.tobytes())\n    width, height = image.size\n    return GdkPixbuf.Pixbuf.new_from_data(image_array, GdkPixbuf.Colorspace.RGB, True, 8, width, height, width * 4)\n\n\ndef get_link_button(text):\n    \"\"\"Return a transparent text button for the side panels\"\"\"\n    button = Gtk.Button(text, visible=True)\n    button.props.relief = Gtk.ReliefStyle.NONE\n    button.get_children()[0].set_alignment(0, 0.5)\n    button.get_style_context().add_class(\"panel-button\")\n    button.set_size_request(-1, 24)\n    return button\n\n\ndef load_icon_theme():\n    \"\"\"Add the lutris icon folder to the default theme\"\"\"\n    icon_theme = Gtk.IconTheme.get_default()\n    local_theme_path = os.path.join(settings.RUNTIME_DIR, \"icons\")\n    if local_theme_path not in icon_theme.get_search_path():\n        icon_theme.prepend_search_path(local_theme_path)\n", "path": "lutris/gui/widgets/utils.py"}], "after_files": [{"content": "\"\"\"Various utilities using the GObject framework\"\"\"\nimport array\nimport os\n\nfrom gi.repository import Gdk, GdkPixbuf, Gio, GLib, Gtk\n\nfrom lutris import settings\nfrom lutris.util import datapath, system\nfrom lutris.util.log import logger\n\ntry:\n    from PIL import Image\nexcept ImportError:\n    Image = None\n\nICON_SIZE = (32, 32)\nBANNER_SIZE = (184, 69)\n\n\ndef get_main_window(widget):\n    \"\"\"Return the application's main window from one of its widget\"\"\"\n    parent = widget.get_toplevel()\n    if not isinstance(parent, Gtk.Window):\n        # The sync dialog may have closed\n        parent = Gio.Application.get_default().props.active_window\n    for window in parent.application.get_windows():\n        if \"LutrisWindow\" in window.__class__.__name__:\n            return window\n    return\n\n\ndef open_uri(uri):\n    \"\"\"Opens a local or remote URI with the default application\"\"\"\n    system.reset_library_preloads()\n    try:\n        Gtk.show_uri(None, uri, Gdk.CURRENT_TIME)\n    except GLib.Error as ex:\n        logger.exception(\"Failed to open URI %s: %s, falling back to xdg-open\", uri, ex)\n        system.execute([\"xdg-open\", uri])\n\n\ndef get_pixbuf(image, size, fallback=None, is_installed=True):\n    \"\"\"Return a pixbuf from file `image` at `size` or fallback to `fallback`\"\"\"\n    width, height = size\n    pixbuf = None\n    if system.path_exists(image, exclude_empty=True):\n        try:\n            pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(image, width, height)\n            pixbuf = pixbuf.scale_simple(width, height, GdkPixbuf.InterpType.NEAREST)\n        except GLib.GError:\n            logger.error(\"Unable to load icon from image %s\", image)\n    else:\n        if not fallback:\n            fallback = get_default_icon(size)\n        if system.path_exists(fallback):\n            pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(fallback, width, height)\n    if is_installed and pixbuf:\n        pixbuf = pixbuf.scale_simple(width, height, GdkPixbuf.InterpType.NEAREST)\n        return pixbuf\n    overlay = os.path.join(datapath.get(), \"media/unavailable.png\")\n    transparent_pixbuf = get_overlay(overlay, size).copy()\n    if pixbuf:\n        pixbuf.composite(\n            transparent_pixbuf,\n            0,\n            0,\n            size[0],\n            size[1],\n            0,\n            0,\n            1,\n            1,\n            GdkPixbuf.InterpType.NEAREST,\n            100,\n        )\n    return transparent_pixbuf\n\n\ndef get_stock_icon(name, size):\n    \"\"\"Return a pixbuf from a stock icon name\"\"\"\n    theme = Gtk.IconTheme.get_default()\n    try:\n        return theme.load_icon(name, size, Gtk.IconLookupFlags.GENERIC_FALLBACK)\n    except GLib.GError:\n        logger.error(\"Failed to read icon %s\", name)\n        return None\n\n\ndef get_icon(icon_name, icon_format=\"image\", size=None, icon_type=\"runner\"):\n    \"\"\"Return an icon based on the given name, format, size and type.\n\n    Keyword arguments:\n    icon_name -- The name of the icon to retrieve\n    format -- The format of the icon, which should be either 'image' or 'pixbuf' (default 'image')\n    size -- The size for the desired image (default None)\n    icon_type -- Retrieve either a 'runner' or 'platform' icon (default 'runner')\n    \"\"\"\n    filename = icon_name.lower().replace(\" \", \"\") + \".png\"\n    icon_path = os.path.join(settings.RUNTIME_DIR, \"icons/hicolor/64x64/apps\", filename)\n    if not os.path.exists(icon_path):\n        return None\n    if icon_format == \"image\":\n        icon = Gtk.Image()\n        if size:\n            icon.set_from_pixbuf(get_pixbuf(icon_path, size))\n        else:\n            icon.set_from_file(icon_path)\n        return icon\n    if icon_format == \"pixbuf\" and size:\n        return get_pixbuf(icon_path, size)\n    raise ValueError(\"Invalid arguments\")\n\n\ndef get_overlay(overlay_path, size):\n    width, height = size\n    transparent_pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(overlay_path, width, height)\n    transparent_pixbuf = transparent_pixbuf.scale_simple(width, height, GdkPixbuf.InterpType.NEAREST)\n    return transparent_pixbuf\n\n\ndef get_default_icon(size):\n    if size[0] == size[1]:\n        return os.path.join(datapath.get(), \"media/default_icon.png\")\n    return os.path.join(datapath.get(), \"media/default_banner.png\")\n\n\ndef convert_to_background(background_path, target_size=(320, 1080)):\n    \"\"\"Converts a image to a pane background\"\"\"\n    coverart = Image.open(background_path)\n    coverart = coverart.convert(\"RGBA\")\n\n    target_width, target_height = target_size\n    image_height = int(target_height * 0.80)  # 80% of the mask is visible\n    orig_width, orig_height = coverart.size\n\n    # Resize and crop coverart\n    width = int(orig_width * (image_height / orig_height))\n    offset = int((width - target_width) / 2)\n    coverart = coverart.resize((width, image_height), resample=Image.BICUBIC)\n    coverart = coverart.crop((offset, 0, target_width + offset, image_height))\n\n    # Resize canvas of coverart by putting transparent pixels on the bottom\n    coverart_bg = Image.new('RGBA', (target_width, target_height), (0, 0, 0, 0))\n    coverart_bg.paste(coverart, (0, 0, target_width, image_height))\n\n    # Apply a tint to the base image\n    # tint = Image.new('RGBA', (target_width, target_height), (0, 0, 0, 255))\n    # coverart = Image.blend(coverart, tint, 0.6)\n\n    # Paste coverart on transparent image while applying a gradient mask\n    background = Image.new('RGBA', (target_width, target_height), (0, 0, 0, 0))\n    mask = Image.open(os.path.join(datapath.get(), \"media/mask.png\"))\n    background.paste(coverart_bg, mask=mask)\n\n    return background\n\n\ndef thumbnail_image(base_image, target_size):\n    base_width, base_height = base_image.size\n    base_ratio = base_width / base_height\n    target_width, target_height = target_size\n    target_ratio = target_width / target_height\n\n    # Resize and crop coverart\n    if base_ratio >= target_ratio:\n        width = int(base_width * (target_height / base_height))\n        height = target_height\n    else:\n        width = target_width\n        height = int(base_height * (target_width / base_width))\n    x_offset = int((width - target_width) / 2)\n    y_offset = int((height - target_height) / 2)\n    base_image = base_image.resize((width, height), resample=Image.BICUBIC)\n    base_image = base_image.crop((x_offset, y_offset, width - x_offset, height - y_offset))\n    return base_image\n\n\ndef paste_overlay(base_image, overlay_image, position=0.7):\n    base_width, base_height = base_image.size\n    overlay_width, overlay_height = overlay_image.size\n    offset_x = int((base_width - overlay_width) / 2)\n    offset_y = int((base_height - overlay_height) / 2)\n    base_image.paste(\n        overlay_image, (\n            offset_x,\n            offset_y,\n            overlay_width + offset_x,\n            overlay_height + offset_y\n        ),\n        mask=overlay_image\n    )\n    return base_image\n\n\ndef image2pixbuf(image):\n    \"\"\"Converts a PIL Image to a GDK Pixbuf\"\"\"\n    image_array = array.array('B', image.tobytes())\n    width, height = image.size\n    return GdkPixbuf.Pixbuf.new_from_data(image_array, GdkPixbuf.Colorspace.RGB, True, 8, width, height, width * 4)\n\n\ndef get_link_button(text):\n    \"\"\"Return a transparent text button for the side panels\"\"\"\n    button = Gtk.Button(text, visible=True)\n    button.props.relief = Gtk.ReliefStyle.NONE\n    button.get_children()[0].set_alignment(0, 0.5)\n    button.get_style_context().add_class(\"panel-button\")\n    button.set_size_request(-1, 24)\n    return button\n\n\ndef load_icon_theme():\n    \"\"\"Add the lutris icon folder to the default theme\"\"\"\n    icon_theme = Gtk.IconTheme.get_default()\n    local_theme_path = os.path.join(settings.RUNTIME_DIR, \"icons\")\n    if local_theme_path not in icon_theme.get_search_path():\n        icon_theme.prepend_search_path(local_theme_path)\n", "path": "lutris/gui/widgets/utils.py"}]}