summaryrefslogtreecommitdiffstats
path: root/lib/tools/profile-key-colors.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/tools/profile-key-colors.c')
-rw-r--r--lib/tools/profile-key-colors.c175
1 files changed, 175 insertions, 0 deletions
diff --git a/lib/tools/profile-key-colors.c b/lib/tools/profile-key-colors.c
new file mode 100644
index 0000000..44df6a4
--- /dev/null
+++ b/lib/tools/profile-key-colors.c
@@ -0,0 +1,175 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ * vi:set noexpandtab tabstop=8 shiftwidth=8:
+ *
+ * Copyright (C) 2021 Endless OS Foundation LLC
+ *
+ * Authors:
+ * - Philip Withnall <pwithnall@endlessos.org>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <glib.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <gdk/gdk.h>
+#include <locale.h>
+#include <math.h>
+
+#include "gs-key-colors.h"
+
+/* Test program which can be used to check the output and performance of the
+ * gs_calculate_key_colors() function. It is linked against libgnomesoftware, so
+ * will use the function implementation from there. It outputs a HTML page which
+ * lists each icon from the flathub appstream data in your home directory, along
+ * with its extracted key colors and how long extraction took. */
+
+static void
+print_colours (GString *html_output,
+ GArray *colours)
+{
+ g_string_append_printf (html_output, "<table class='colour-swatch'><tr>");
+ for (guint i = 0; i < colours->len; i++) {
+ GdkRGBA *rgba = &g_array_index (colours, GdkRGBA, i);
+
+ g_string_append_printf (html_output,
+ "<td style='background-color: rgb(%u, %u, %u)'></td>",
+ (guint) (rgba->red * 255),
+ (guint) (rgba->green * 255),
+ (guint) (rgba->blue * 255));
+
+ if (i % 3 == 2)
+ g_string_append (html_output, "</tr><tr>");
+ }
+ g_string_append_printf (html_output, "</tr></table>");
+}
+
+static void
+print_summary_statistics (GString *html_output,
+ GArray *durations /* (element-type gint64) */)
+{
+ gint64 sum = 0, min = G_MAXINT64, max = G_MININT64;
+ guint n_measurements = durations->len;
+ gint64 mean, stddev;
+ gint64 sum_of_square_deviations = 0;
+
+ for (guint i = 0; i < durations->len; i++) {
+ gint64 duration = g_array_index (durations, gint64, i);
+ sum += duration;
+ min = MIN (min, duration);
+ max = MAX (max, duration);
+ }
+
+ mean = sum / n_measurements;
+
+ for (guint i = 0; i < durations->len; i++) {
+ gint64 duration = g_array_index (durations, gint64, i);
+ gint64 diff = duration - mean;
+ sum_of_square_deviations += diff * diff;
+ }
+
+ stddev = sqrt (sum_of_square_deviations / n_measurements);
+
+ g_string_append_printf (html_output,
+ "[%" G_GINT64_FORMAT ", %" G_GINT64_FORMAT "]μs, mean %" G_GINT64_FORMAT "±%" G_GINT64_FORMAT "μs, n = %u",
+ min, max, mean, stddev, n_measurements);
+}
+
+int
+main (void)
+{
+ const gchar *icons_subdir = ".local/share/flatpak/appstream/flathub/x86_64/active/icons/128x128";
+ g_autofree gchar *icons_dir = g_build_filename (g_get_home_dir (), icons_subdir, NULL);
+ g_autoptr(GDir) dir = NULL;
+ const gchar *entry;
+ g_autoptr(GPtrArray) filenames = g_ptr_array_new_with_free_func (g_free);
+ g_autoptr(GPtrArray) pixbufs = g_ptr_array_new_with_free_func (g_object_unref);
+ g_autoptr(GString) html_output = g_string_new ("");
+ g_autoptr(GArray) durations = g_array_new (FALSE, FALSE, sizeof (gint64));
+
+ setlocale (LC_ALL, "");
+
+ /* Load pixbufs from the icons directory. */
+ dir = g_dir_open (icons_dir, 0, NULL);
+ if (dir == NULL)
+ return 1;
+
+ while ((entry = g_dir_read_name (dir)) != NULL) {
+ g_autofree gchar *filename = g_build_filename (icons_dir, entry, NULL);
+ g_autoptr(GdkPixbuf) pixbuf = gdk_pixbuf_new_from_file (filename, NULL);
+
+ if (pixbuf == NULL)
+ continue;
+
+ g_ptr_array_add (filenames, g_steal_pointer (&filename));
+ g_ptr_array_add (pixbufs, g_steal_pointer (&pixbuf));
+ }
+
+ if (!pixbufs->len)
+ return 2;
+
+ /* Set up an output page */
+ g_string_append (html_output,
+ "<!DOCTYPE html>\n"
+ "<html>\n"
+ " <head>\n"
+ " <meta charset='UTF-8'>\n"
+ " <style>\n"
+ " #main-table, #main-table th, #main-table td { border: 1px solid black; border-collapse: collapse }\n"
+ " #main-table th, #main-table td { padding: 4px }\n"
+ " td.number { text-align: right }\n"
+ " table.colour-swatch td { width: 30px; height: 30px }\n"
+ " .faster { background-color: rgb(190, 236, 57) }\n"
+ " .slower { background-color: red }\n"
+ " </style>\n"
+ " </head>\n"
+ " <body>\n"
+ " <table id='main-table'>\n"
+ " <thead>\n"
+ " <tr>\n"
+ " <td>Filename</td>\n"
+ " <td>Icon</td>\n"
+ " <td>Code duration (μs)</td>\n"
+ " <td>Code colours</td>\n"
+ " </tr>\n"
+ " </thead>\n");
+
+ /* For each pixbuf, run both algorithms. */
+ for (guint i = 0; i < pixbufs->len; i++) {
+ GdkPixbuf *pixbuf = pixbufs->pdata[i];
+ const gchar *filename = filenames->pdata[i];
+ g_autofree gchar *basename = g_path_get_basename (filename);
+ g_autoptr(GArray) colours = NULL;
+ gint64 start_time, duration;
+
+ g_message ("Processing %u of %u, %s", i + 1, pixbufs->len, filename);
+
+ start_time = g_get_real_time ();
+ colours = gs_calculate_key_colors (pixbuf);
+ duration = g_get_real_time () - start_time;
+
+ g_string_append_printf (html_output,
+ "<tr>\n"
+ "<th>%s</th>\n"
+ "<td><img src='file:%s'></td>\n"
+ "<td class='number'>%" G_GINT64_FORMAT "</td>\n"
+ "<td>",
+ basename, filename, duration);
+ print_colours (html_output, colours);
+ g_string_append (html_output,
+ "</td>\n"
+ "</tr>\n");
+
+ g_array_append_val (durations, duration);
+ }
+
+ /* Summary statistics for the timings. */
+ g_string_append (html_output, "<tfoot><tr><td></td><td></td><td>");
+ print_summary_statistics (html_output, durations);
+ g_string_append (html_output, "</td><td></td></tr></tfoot>");
+
+ g_string_append (html_output, "</table></body></html>");
+
+ g_print ("%s\n", html_output->str);
+
+ return 0;
+}