diff --git a/lib/rb-util.c b/lib/rb-util.c index 48dbffe8bfda415e8a077025447d170846f584e8..53d82973be44dda26a48a4037cc5b64d16732bef 100644 --- a/lib/rb-util.c +++ b/lib/rb-util.c @@ -51,6 +51,11 @@ static GPrivate private_is_primary_thread; +typedef struct { + const gchar *name; + int val; /* just 'int' for now */ +} PixbufOptions; + /** * rb_true_function: (skip) * @dummy: unused @@ -1177,6 +1182,107 @@ rb_scale_pixbuf_to_size (GdkPixbuf *pixbuf, GtkIconSize size) return gdk_pixbuf_scale_simple (pixbuf, d_width, d_height, GDK_INTERP_BILINEAR); } +/** + * rb_pixbuf_new_with_pixel: + * @width: pixbuf width + * @height: pixbuf height + * @pixel: RGBA pixel to apply to each pixel location + * (0xffffffff is opaque white, 0x00000000 transparent black) + * + * Creates a new #GdkPixbuf of the given @width and @height filling + * each pixel with @pixel RGBA value. + * + * Return value: (nullable) (transfer full): A newly-created + * #GdkPixbuf with a reference count of 1, or %NULL if not enough + * memory could be allocated for the image buffer. + */ +GdkPixbuf * +rb_pixbuf_new_with_pixel (int width, int height, guint32 pixel) +{ + GdkPixbuf *pixbuf; + + g_return_val_if_fail (width > 0, NULL); + g_return_val_if_fail (height > 0, NULL); + + pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, width, height); + g_return_val_if_fail (pixbuf != NULL, NULL); + + gdk_pixbuf_fill (pixbuf, pixel); + + return pixbuf; +} + +/** + * rb_pixbuf_center_in_new_pixbuf: + * @pixbuf: the #GdkPixbuf containing the original image + * @dest_width: destination pixbuf width ( must be >= @pixbuf width ) + * @dest_height: destination pixbuf height ( must be >= @pixbuf height ) + * @dest_pixel: RGBA pixel to apply to each pixel location in + * destination pixbuf (0xffffffff is opaque white, + * 0x00000000 transparent black) + * + * Creates a new #GdkPixbuf of the given @dest_width and @dest_height + * filling each pixel with @dest_pixel RGBA value, after which @pixbuf + * will be centered vertically and horizontally within it. The options + * from @pixbuf are copied over to the newly created pixbuf. + * + * Return value: (nullable) (transfer full): The newly-created + * #GdkPixbuf with @pixbuf centered, or %NULL if not enough memory + * could be allocated for the image buffer. + */ +GdkPixbuf * +rb_pixbuf_center_in_new_pixbuf (const GdkPixbuf *pixbuf, + guint dest_width, + guint dest_height, + guint32 dest_pixel) +{ + int i; + int dest_x, dest_y; + int width, height; + GdkPixbuf *dest_pixbuf; + gboolean success; + const gchar *option_name; + + PixbufOptions overwrite_options[] = { + { "original-width", 0 }, + { "original-height", 0 }, + }; + + width = gdk_pixbuf_get_width (pixbuf); + height = gdk_pixbuf_get_height (pixbuf); + + g_return_val_if_fail (width > 0 && width <= dest_width, NULL); + g_return_val_if_fail (height > 0 && height <= dest_height, NULL); + + dest_pixbuf = rb_pixbuf_new_with_pixel (dest_width, dest_height, dest_pixel); + g_return_val_if_fail (dest_pixbuf != NULL, NULL); + + dest_x = (dest_width - width) / 2; + dest_y = (dest_height - height) / 2; + gdk_pixbuf_copy_area (pixbuf, 0, 0, width, height, dest_pixbuf, dest_x, dest_y); + + if (gdk_pixbuf_copy_options ((GdkPixbuf *) pixbuf, dest_pixbuf) == FALSE) { + g_warning ("failed to copy pixbuf options"); + return dest_pixbuf; + } + + overwrite_options[0].val = gdk_pixbuf_get_width (dest_pixbuf); + overwrite_options[1].val = gdk_pixbuf_get_height (dest_pixbuf); + + for (i = 0; i < G_N_ELEMENTS (overwrite_options); i++) { + gchar *str; + option_name = overwrite_options[i].name; + gdk_pixbuf_remove_option (dest_pixbuf, option_name); + str = g_strdup_printf ("%d", overwrite_options[i].val); + success = gdk_pixbuf_set_option (dest_pixbuf, option_name, str); + if (!success) + g_warning ("failed to set pixbuf option: '%s'", option_name); + g_free (str); + } + + return dest_pixbuf; +} + #define DELAYED_SYNC_ITEM "rb-delayed-sync" #define DELAYED_SYNC_FUNC_ITEM "rb-delayed-sync-func" #define DELAYED_SYNC_DATA_ITEM "rb-delayed-sync-data" diff --git a/lib/rb-util.h b/lib/rb-util.h index 68d3dd4aa7eba6dc54226326c0aaa53b0dfa1fbc..26934c4168b6bdce163ca2beca33f609ce8c1f96 100644 --- a/lib/rb-util.h +++ b/lib/rb-util.h @@ -106,6 +106,11 @@ void rb_set_tree_view_column_fixed_width (GtkWidget *treeview, GdkPixbuf *rb_scale_pixbuf_to_size (GdkPixbuf *pixbuf, GtkIconSize size); +GdkPixbuf *rb_pixbuf_center_in_new_pixbuf (const GdkPixbuf *pixbuf, + guint dest_width, + guint dest_height, + guint32 dest_pixel); +GdkPixbuf *rb_pixbuf_new_with_pixel (int width, int height, guint32 pixel); typedef void (*RBDelayedSyncFunc)(GSettings *settings, gpointer data); diff --git a/podcast/rb-podcast-add-dialog.c b/podcast/rb-podcast-add-dialog.c index ef948845940967955fe604c27f049564e4a10277..22f997bd9bca25cc5009f5dca20f289843c2ad06 100644 --- a/podcast/rb-podcast-add-dialog.c +++ b/podcast/rb-podcast-add-dialog.c @@ -43,6 +43,8 @@ #include "rb-search-entry.h" #include "nautilus-floating-bar.h" +#define WHITE_SMOKE 0xF5F5F5FF + static void rb_podcast_add_dialog_class_init (RBPodcastAddDialogClass *klass); static void rb_podcast_add_dialog_init (RBPodcastAddDialog *dialog); @@ -91,6 +93,7 @@ struct RBPodcastAddDialogPrivate gboolean have_selection; gboolean clearing; GtkTreeIter selected_feed; + GdkPixbuf *default_pixbuf; int running_searches; gboolean search_successful; @@ -171,13 +174,14 @@ add_posts_for_feed (RBPodcastAddDialog *dialog, RBPodcastChannel *channel) } static void -image_file_read_cb (GObject *file, GAsyncResult *result, RBPodcastAddDialog *dialog) +image_file_read_cb (GFile *file, GAsyncResult *result, RBPodcastAddDialog *dialog) { GFileInputStream *stream; GdkPixbuf *pixbuf; GError *error = NULL; + GdkPixbuf *centered_pixbuf; - stream = g_file_read_finish (G_FILE (file), result, &error); + stream = g_file_read_finish (file, result, &error); if (error != NULL) { rb_debug ("podcast image read failed: %s", error->message); g_clear_error (&error); @@ -191,14 +195,35 @@ image_file_read_cb (GObject *file, GAsyncResult *result, RBPodcastAddDialog *dia g_clear_error (&error); } else { GtkTreeIter iter; - + guint width, height; + + width = gdk_pixbuf_get_width (pixbuf); + height = gdk_pixbuf_get_height (pixbuf); + + if (width < PODCAST_IMAGE_SIZE || height < PODCAST_IMAGE_SIZE) { + char *uri; + uri = g_file_get_uri (file); + rb_debug ("image size not as expected: [ %d x %d ] [%s]\n", width, height, uri); + g_free (uri); + + centered_pixbuf = rb_pixbuf_center_in_new_pixbuf (pixbuf, + PODCAST_IMAGE_SIZE, + PODCAST_IMAGE_SIZE, + 0x0FFFFFFFF); + if (centered_pixbuf != NULL) { + g_object_unref (pixbuf); + pixbuf = centered_pixbuf; + } else { + g_warning ("failed to center image"); + } + } if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (dialog->priv->feed_model), &iter)) { do { GFile *feedfile; gtk_tree_model_get (GTK_TREE_MODEL (dialog->priv->feed_model), &iter, FEED_COLUMN_IMAGE_FILE, &feedfile, -1); - if (feedfile == G_FILE (file)) { + if (feedfile == file) { gtk_list_store_set (dialog->priv->feed_model, &iter, FEED_COLUMN_IMAGE, g_object_ref (pixbuf), @@ -235,13 +260,19 @@ insert_search_result (RBPodcastAddDialog *dialog, RBPodcastChannel *channel, gbo image_file = NULL; } + if (dialog->priv->default_pixbuf == NULL) { + dialog->priv->default_pixbuf = rb_pixbuf_new_with_pixel (PODCAST_IMAGE_SIZE, + PODCAST_IMAGE_SIZE, + WHITE_SMOKE); + } + gtk_list_store_insert_with_values (dialog->priv->feed_model, &iter, G_MAXINT, FEED_COLUMN_TITLE, channel->title, FEED_COLUMN_AUTHOR, channel->author, FEED_COLUMN_EPISODE_COUNT, episodes, - FEED_COLUMN_IMAGE, NULL, + FEED_COLUMN_IMAGE, dialog->priv->default_pixbuf, FEED_COLUMN_IMAGE_FILE, image_file, FEED_COLUMN_PARSED_FEED, channel, -1); @@ -854,6 +885,7 @@ impl_dispose (GObject *object) dialog->priv->db = NULL; } + g_clear_object (&dialog->priv->default_pixbuf); G_OBJECT_CLASS (rb_podcast_add_dialog_parent_class)->dispose (object); }