# HG changeset patch
# Node ID b99522f61366
# Parent  8d642098b453
diff --git a/libpurple/protocols/demo/purpledemocontacts.c b/libpurple/protocols/demo/purpledemocontacts.c
--- a/libpurple/protocols/demo/purpledemocontacts.c
+++ b/libpurple/protocols/demo/purpledemocontacts.c
@@ -76,6 +76,27 @@ purple_demo_protocol_load_status(PurpleA
 }
 
 static void
+purple_demo_protocol_load_icon(PurpleAccount *account, const gchar *name)
+{
+	gchar *path = NULL;
+	GBytes *icon = NULL;
+	gpointer icon_data = NULL;
+	gsize icon_len = 0;
+
+	path = g_strdup_printf("/im/pidgin/purple/demo/buddy_icons/%s.png", name);
+	icon = g_resource_lookup_data(purple_demo_get_resource(), path, G_RESOURCE_LOOKUP_FLAGS_NONE, NULL);
+	g_free(path);
+
+	if(icon == NULL) {
+		/* No stored icon. */
+		return;
+	}
+
+	icon_data = g_bytes_unref_to_data(icon, &icon_len);
+	purple_buddy_icons_set_for_user(account, name, icon_data, icon_len, NULL);
+}
+
+static void
 purple_demo_protocol_load_buddies(PurpleAccount *account, PurpleGroup *group,
                                   PurpleContact *contact, GList *buddies)
 {
@@ -104,6 +125,7 @@ purple_demo_protocol_load_buddies(Purple
 				purple_blist_add_buddy(buddy, contact, group, NULL);
 			}
 
+			purple_demo_protocol_load_icon(account, name);
 			purple_demo_protocol_load_status(account, group, contact, buddy,
 			                                 buddy_object);
 		}
diff --git a/libpurple/protocols/demo/resources/buddy_icons/Eion.png b/libpurple/protocols/demo/resources/buddy_icons/Eion.png
new file mode 100644
index 0000000000000000000000000000000000000000..1dd97beaf0d4fe673f3d66dce5cc12e890770792
GIT binary patch
diff --git a/libpurple/protocols/demo/resources/buddy_icons/Elliott.png b/libpurple/protocols/demo/resources/buddy_icons/Elliott.png
new file mode 100644
index 0000000000000000000000000000000000000000..d997aa60b0d7a141ce11a9f9a4ba68adee53076e
GIT binary patch
diff --git a/libpurple/protocols/demo/resources/buddy_icons/Gary.png b/libpurple/protocols/demo/resources/buddy_icons/Gary.png
new file mode 100644
index 0000000000000000000000000000000000000000..379c2204d6ffbd6253faadca856f7e450028fd2b
GIT binary patch
diff --git a/libpurple/protocols/demo/resources/buddy_icons/John.png b/libpurple/protocols/demo/resources/buddy_icons/John.png
new file mode 100644
index 0000000000000000000000000000000000000000..593a08e08bf0f4011906ee20c753eb3b3817a0e4
GIT binary patch
diff --git a/libpurple/protocols/demo/resources/buddy_icons/Richard.png b/libpurple/protocols/demo/resources/buddy_icons/Richard.png
new file mode 100644
index 0000000000000000000000000000000000000000..23714320171b41850935c21aac463b3efbd807ca
GIT binary patch
diff --git a/libpurple/protocols/demo/resources/buddy_icons/mkicon.py b/libpurple/protocols/demo/resources/buddy_icons/mkicon.py
new file mode 100755
--- /dev/null
+++ b/libpurple/protocols/demo/resources/buddy_icons/mkicon.py
@@ -0,0 +1,90 @@
+#!/usr/bin/env python3
+#
+# Purple - Internet Messaging Library
+# Copyright (C) Pidgin Developers <devel@pidgin.im>
+#
+# Purple is the legal property of its developers, whose names are too numerous
+# to list here.  Please refer to the COPYRIGHT file distributed with this
+# source distribution.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, see <https://www.gnu.org/licenses/>.
+
+import argparse
+import colorsys
+import hashlib
+from pathlib import Path
+
+from PIL import Image, ImageDraw, ImageFont
+
+parser = argparse.ArgumentParser(
+    description='Generate buddy icons from user names.')
+parser.add_argument('name', nargs='+', help='The name(s) to use.')
+parser.add_argument('-f', '--font',
+                    default='/usr/share/fonts/urw-base35/D050000L.otf',
+                    help='Path to (TrueType or OpenType) font to use.')
+parser.add_argument('-s', '--size', default=96, type=int,
+                    help='Size of buddy icons to produce.')
+parser.add_argument('-o', '--output', default='.',
+                    help='Directory in which to place files.')
+args = parser.parse_args()
+
+
+def calculate_colours_for_text(text):
+    """
+    Calculate the foreground and background colours from text.
+
+    This is based on pidgin_color_calculate_for_text in Pidgin C code.
+    """
+    # Hash the string and get the first 2 bytes of the digest.
+    checksum = hashlib.sha1()
+    checksum.update(text.encode('utf-8'))
+    digest = checksum.digest()
+
+    # Calculate the hue based on the digest, scaled to 0-1.
+    hue = (digest[0] << 8 | digest[1]) / 65535
+    # Get the RGB values for the hue at full saturation and value.
+    foreground = colorsys.hsv_to_rgb(hue, 1.0, 1.0)
+
+    # Calculate the hue based on the end of the digest, scaled to 0-1.
+    hue = (digest[-1] << 8 | digest[-2]) / 65535
+    # Get the RGB values for the hue at full saturation and low value.
+    background = colorsys.hsv_to_rgb(hue, 1.0, 0.2)
+
+    # Finally calculate the foreground summing 20% of the inverted background
+    # with 80% of the foreground.
+    foreground = (
+        (0.2 * (1 - bc)) + (0.8 * fc) for bc, fc in zip(background, foreground)
+    )
+
+    # Pillow requires colours in 0-255.
+    return (tuple(int(c * 255) for c in foreground),
+            tuple(int(c * 255) for c in background))
+
+
+output_dir = Path(args.output)
+font = ImageFont.truetype(args.font, size=int(args.size * 96/72))
+
+for name in args.name:
+    fore, back = calculate_colours_for_text(name)
+
+    # Generate an image using the first letter of the name to choose a glyph
+    # from the specified font. The default font generates some star-like or
+    # flower-like symbols.
+    img = Image.new('RGBA', (args.size, args.size), color=back)
+    draw = ImageDraw.Draw(img)
+    letter = name[0].upper()
+    draw.text((args.size // 2, args.size - 1), letter,
+              font=font, anchor='mb', fill=fore)
+
+    img.save(output_dir / f'{name}.png', 'PNG')
diff --git a/libpurple/protocols/demo/resources/contacts.json b/libpurple/protocols/demo/resources/contacts.json
--- a/libpurple/protocols/demo/resources/contacts.json
+++ b/libpurple/protocols/demo/resources/contacts.json
@@ -21,7 +21,7 @@
 	}],
 	"Work": [{
 		"buddies": [{
-			"name": "Elliot",
+			"name": "Elliott",
 			"status": {
 				"id": "away",
 				"message": "Coding..."
diff --git a/libpurple/protocols/demo/resources/purpledemo.gresource.xml b/libpurple/protocols/demo/resources/purpledemo.gresource.xml
--- a/libpurple/protocols/demo/resources/purpledemo.gresource.xml
+++ b/libpurple/protocols/demo/resources/purpledemo.gresource.xml
@@ -6,5 +6,10 @@
     <file>icons/22x22/apps/im-purple-demo.png</file>
     <file>icons/48x48/apps/im-purple-demo.png</file>
     <file>icons/scalable/apps/im-purple-demo.svg</file>
+    <file>buddy_icons/Eion.png</file>
+    <file>buddy_icons/Elliott.png</file>
+    <file>buddy_icons/Gary.png</file>
+    <file>buddy_icons/John.png</file>
+    <file>buddy_icons/Richard.png</file>
   </gresource>
 </gresources>
