/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* * Pix * * Copyright (C) 2005-2009 Free Software Foundation, Inc. * * 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 . */ #include #include #include #include #include "dlg-resize-images.h" #include "preferences.h" #define GET_WIDGET(name) _gtk_builder_get_widget (data->builder, (name)) #define DEFAULT_WIDTH_PERCENTAGE 100 #define DEFAULT_HEIGHT_PERCENTAGE 100 #define DEFAULT_WIDTH_PIXELS 640 #define DEFAULT_HEIGHT_PIXELS 480 enum { MIME_TYPE_COLUMN_ICON = 0, MIME_TYPE_COLUMN_TYPE, MIME_TYPE_COLUMN_DESCRIPTION }; GthUnit units[] = { GTH_UNIT_PIXELS, GTH_UNIT_PERCENTAGE }; typedef struct { GthBrowser *browser; GSettings *settings; GList *file_list; GtkBuilder *builder; GtkWidget *dialog; gboolean use_destination; gulong width_spinbutton_event; gulong height_spinbutton_event; double latest_width_in_pixel; double latest_height_in_pixel; double latest_width_in_percentage; double latest_height_in_percentage; gboolean known_ratio; double ratio; } DialogData; typedef struct { int width; int height; GthUnit unit; gboolean keep_aspect_ratio; gboolean allow_swap; } ResizeData; static void destroy_cb (GtkWidget *widget, DialogData *data) { gth_browser_set_dialog (data->browser, "resize_images", NULL); g_object_unref (data->settings); g_object_unref (data->builder); _g_object_list_unref (data->file_list); g_free (data); } static gpointer exec_resize (GthAsyncTask *task, gpointer user_data) { ResizeData *resize_data = user_data; cairo_surface_t *source; cairo_surface_t *destination; int w, h; int new_w, new_h; int max_w, max_h; GthImage *destination_image; source = gth_image_task_get_source_surface (GTH_IMAGE_TASK (task)); w = cairo_image_surface_get_width (source); h = cairo_image_surface_get_height (source); if (resize_data->allow_swap && (((h > w) && (resize_data->width > resize_data->height)) || ((h < w) && (resize_data->width < resize_data->height)))) { max_w = resize_data->height; max_h = resize_data->width; } else { max_w = resize_data->width; max_h = resize_data->height; } if (resize_data->unit == GTH_UNIT_PERCENTAGE) { new_w = w * ((double) max_w / 100.0); new_h = h * ((double) max_h / 100.0); } else if (resize_data->keep_aspect_ratio) { new_w = w; new_h = h; scale_keeping_ratio (&new_w, &new_h, max_w, max_h, TRUE); } else { new_w = max_w; new_h = max_h; } destination = _cairo_image_surface_scale (source, new_w, new_h, SCALE_FILTER_BEST, task); destination_image = gth_image_new_for_surface (destination); gth_image_task_set_destination (GTH_IMAGE_TASK (task), destination_image); _g_object_unref (destination_image); cairo_surface_destroy (destination); cairo_surface_destroy (source); return NULL; } static void ok_clicked_cb (GtkWidget *widget, DialogData *data) { ResizeData *resize_data; GtkTreeIter iter; char *mime_type; GthTask *resize_task; GthTask *list_task; resize_data = g_new0 (ResizeData, 1); resize_data->width = gtk_spin_button_get_value (GTK_SPIN_BUTTON (GET_WIDGET ("width_spinbutton"))); resize_data->height = gtk_spin_button_get_value (GTK_SPIN_BUTTON (GET_WIDGET ("height_spinbutton"))); resize_data->unit = units[gtk_combo_box_get_active (GTK_COMBO_BOX (GET_WIDGET ("unit_combobox")))]; resize_data->keep_aspect_ratio = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (GET_WIDGET ("keep_ratio_checkbutton"))); resize_data->allow_swap = FALSE; gtk_combo_box_get_active_iter (GTK_COMBO_BOX (GET_WIDGET ("mime_type_combobox")), &iter); gtk_tree_model_get (GTK_TREE_MODEL (GET_WIDGET ("mime_type_liststore")), &iter, MIME_TYPE_COLUMN_TYPE, &mime_type, -1); g_settings_set_int (data->settings, PREF_RESIZE_IMAGES_SERIES_WIDTH, resize_data->width); g_settings_set_int (data->settings, PREF_RESIZE_IMAGES_SERIES_HEIGHT, resize_data->height); g_settings_set_enum (data->settings, PREF_RESIZE_IMAGES_UNIT, resize_data->unit); g_settings_set_boolean (data->settings, PREF_RESIZE_IMAGES_KEEP_RATIO, resize_data->keep_aspect_ratio); g_settings_set_string (data->settings, PREF_RESIZE_IMAGES_MIME_TYPE, mime_type ? mime_type : ""); resize_task = gth_image_task_new (_("Resizing images"), NULL, exec_resize, NULL, resize_data, g_free); list_task = gth_image_list_task_new (data->browser, data->file_list, GTH_IMAGE_TASK (resize_task)); gth_image_list_task_set_overwrite_mode (GTH_IMAGE_LIST_TASK (list_task), GTH_OVERWRITE_ASK); gth_image_list_task_set_output_mime_type (GTH_IMAGE_LIST_TASK (list_task), mime_type); if (data->use_destination) { GFile *destination; destination = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (GET_WIDGET ("destination_filechooserbutton"))); gth_image_list_task_set_destination (GTH_IMAGE_LIST_TASK (list_task), destination); g_object_unref (destination); } gth_browser_exec_task (data->browser, list_task, GTH_TASK_FLAGS_DEFAULT); g_object_unref (list_task); g_object_unref (resize_task); g_free (mime_type); gtk_widget_destroy (data->dialog); } static void update_width_height_properties (DialogData *data) { GthUnit unit; unit = units[gtk_combo_box_get_active (GTK_COMBO_BOX (GET_WIDGET ("unit_combobox")))]; if (unit == GTH_UNIT_PERCENTAGE) { gtk_spin_button_set_digits (GTK_SPIN_BUTTON (GET_WIDGET ("width_spinbutton")), 2); gtk_spin_button_set_digits (GTK_SPIN_BUTTON (GET_WIDGET ("height_spinbutton")), 2); g_signal_handler_block (GET_WIDGET ("height_spinbutton"), data->height_spinbutton_event); g_signal_handler_block (GET_WIDGET ("width_spinbutton"), data->width_spinbutton_event); gtk_spin_button_set_value (GTK_SPIN_BUTTON (GET_WIDGET ("height_spinbutton")), data->latest_height_in_percentage); gtk_spin_button_set_value (GTK_SPIN_BUTTON (GET_WIDGET ("width_spinbutton")), data->latest_width_in_percentage); g_signal_handler_unblock (GET_WIDGET ("height_spinbutton"), data->height_spinbutton_event); g_signal_handler_unblock (GET_WIDGET ("width_spinbutton"), data->width_spinbutton_event); } else if (unit == GTH_UNIT_PIXELS) { gtk_spin_button_set_digits (GTK_SPIN_BUTTON (GET_WIDGET ("width_spinbutton")), 0); gtk_spin_button_set_digits (GTK_SPIN_BUTTON (GET_WIDGET ("height_spinbutton")), 0); g_signal_handler_block (GET_WIDGET ("height_spinbutton"), data->height_spinbutton_event); g_signal_handler_block (GET_WIDGET ("width_spinbutton"), data->width_spinbutton_event); gtk_spin_button_set_value (GTK_SPIN_BUTTON (GET_WIDGET ("height_spinbutton")), data->latest_height_in_pixel); gtk_spin_button_set_value (GTK_SPIN_BUTTON (GET_WIDGET ("width_spinbutton")), data->latest_width_in_pixel); g_signal_handler_unblock (GET_WIDGET ("height_spinbutton"), data->height_spinbutton_event); g_signal_handler_unblock (GET_WIDGET ("width_spinbutton"), data->width_spinbutton_event); } } static void unit_combobox_changed_cb (GtkComboBox *combobox, DialogData *data) { GthUnit unit; unit = units[gtk_combo_box_get_active (GTK_COMBO_BOX (GET_WIDGET ("unit_combobox")))]; if (unit == GTH_UNIT_PERCENTAGE) { data->latest_width_in_pixel = gtk_spin_button_get_value (GTK_SPIN_BUTTON (GET_WIDGET ("width_spinbutton"))); data->latest_height_in_pixel = gtk_spin_button_get_value (GTK_SPIN_BUTTON (GET_WIDGET ("height_spinbutton"))); } else if (unit == GTH_UNIT_PIXELS) { data->latest_width_in_percentage = gtk_spin_button_get_value (GTK_SPIN_BUTTON (GET_WIDGET ("width_spinbutton"))); data->latest_height_in_percentage = gtk_spin_button_get_value (GTK_SPIN_BUTTON (GET_WIDGET ("height_spinbutton"))); } update_width_height_properties (data); } static void use_destination_checkbutton_toggled_cb (GtkToggleButton *button, gpointer user_data) { DialogData *data = user_data; data->use_destination = ! gtk_toggle_button_get_active (button); gtk_widget_set_sensitive (GET_WIDGET ("destination_filechooserbutton"), data->use_destination); } static void width_spinbutton_value_changed_cb (GtkSpinButton *spinbutton, gpointer user_data) { DialogData *data = user_data; double ratio; GthUnit unit; if (! gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (GET_WIDGET ("keep_ratio_checkbutton")))) return; ratio = 0.0; unit = units[gtk_combo_box_get_active (GTK_COMBO_BOX (GET_WIDGET ("unit_combobox")))]; if ((unit == GTH_UNIT_PIXELS) && data->known_ratio) ratio = 1.0 / data->ratio; else if (unit == GTH_UNIT_PERCENTAGE) ratio = 1.0; if (ratio == 0.0) return; g_signal_handler_block (GET_WIDGET ("height_spinbutton"), data->height_spinbutton_event); gtk_spin_button_set_value (GTK_SPIN_BUTTON (GET_WIDGET ("height_spinbutton")), ratio * gtk_spin_button_get_value (GTK_SPIN_BUTTON (GET_WIDGET ("width_spinbutton")))); g_signal_handler_unblock (GET_WIDGET ("height_spinbutton"), data->height_spinbutton_event); } static void height_spinbutton_value_changed_cb (GtkSpinButton *spinbutton, gpointer user_data) { DialogData *data = user_data; double ratio; GthUnit unit; if (! gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (GET_WIDGET ("keep_ratio_checkbutton")))) return; ratio = 0.0; unit = units[gtk_combo_box_get_active (GTK_COMBO_BOX (GET_WIDGET ("unit_combobox")))]; if ((unit == GTH_UNIT_PIXELS) && data->known_ratio) ratio = data->ratio; else if (unit == GTH_UNIT_PERCENTAGE) ratio = 1.0; if (ratio == 0.0) return; g_signal_handler_block (GET_WIDGET ("width_spinbutton"), data->width_spinbutton_event); gtk_spin_button_set_value (GTK_SPIN_BUTTON (GET_WIDGET ("width_spinbutton")), ratio * gtk_spin_button_get_value (GTK_SPIN_BUTTON (GET_WIDGET ("height_spinbutton")))); g_signal_handler_unblock (GET_WIDGET ("width_spinbutton"), data->width_spinbutton_event); } void dlg_resize_images (GthBrowser *browser, GList *file_list) { DialogData *data; GArray *savers; GthFileData *first_file_data; GthUnit unit; int default_width_in_pixels; int default_height_in_pixels; if (gth_browser_get_dialog (browser, "resize_images") != NULL) { gtk_window_present (GTK_WINDOW (gth_browser_get_dialog (browser, "resize_images"))); return; } data = g_new0 (DialogData, 1); data->browser = browser; data->builder = _gtk_builder_new_from_file ("resize-images.ui", "resize_images"); data->settings = g_settings_new (PIX_RESIZE_IMAGES_SCHEMA); data->file_list = gth_file_data_list_dup (file_list); data->use_destination = TRUE; /* Get the widgets. */ data->dialog = g_object_new (GTK_TYPE_DIALOG, "title", _("Resize Images"), "transient-for", GTK_WINDOW (browser), "modal", FALSE, "destroy-with-parent", FALSE, "use-header-bar", _gtk_settings_get_dialogs_use_header (), NULL); gtk_container_add (GTK_CONTAINER (gtk_dialog_get_content_area (GTK_DIALOG (data->dialog))), _gtk_builder_get_widget (data->builder, "dialog_content")); gtk_dialog_add_buttons (GTK_DIALOG (data->dialog), _GTK_LABEL_CANCEL, GTK_RESPONSE_CANCEL, _GTK_LABEL_EXECUTE, GTK_RESPONSE_OK, NULL); _gtk_dialog_add_class_to_response (GTK_DIALOG (data->dialog), GTK_RESPONSE_OK, GTK_STYLE_CLASS_SUGGESTED_ACTION); gth_browser_set_dialog (browser, "resize_images", data->dialog); g_object_set_data (G_OBJECT (data->dialog), "dialog_data", data); /* Set widgets data. */ first_file_data = (GthFileData *) data->file_list->data; _gtk_file_chooser_set_file_parent (GTK_FILE_CHOOSER (GET_WIDGET ("destination_filechooserbutton")), first_file_data->file, NULL); unit = g_settings_get_enum (data->settings, PREF_RESIZE_IMAGES_UNIT); gtk_combo_box_set_active (GTK_COMBO_BOX (GET_WIDGET ("unit_combobox")), unit); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (GET_WIDGET ("keep_ratio_checkbutton")), g_settings_get_boolean (data->settings, PREF_RESIZE_IMAGES_KEEP_RATIO)); default_width_in_pixels = DEFAULT_WIDTH_PIXELS; default_height_in_pixels = DEFAULT_HEIGHT_PIXELS; if (data->file_list->next == NULL) { GthMetadataProvider *provider; int width; int height; provider = g_object_new (GTH_TYPE_METADATA_PROVIDER_IMAGE, NULL); gth_metadata_provider_read (provider, first_file_data, "image::width,image::height", NULL); width = g_file_info_get_attribute_int32 (first_file_data->info, "image::width"); height = g_file_info_get_attribute_int32 (first_file_data->info, "image::height"); if ((width > 0) && (height > 0)) { data->known_ratio = TRUE; data->ratio = (double) width / height; default_width_in_pixels = width; default_height_in_pixels = height; } g_object_unref (provider); } if (unit == GTH_UNIT_PERCENTAGE) { data->latest_width_in_pixel = default_width_in_pixels; data->latest_height_in_pixel = default_height_in_pixels; data->latest_width_in_percentage = g_settings_get_int (data->settings, PREF_RESIZE_IMAGES_SERIES_WIDTH); data->latest_height_in_percentage = g_settings_get_int (data->settings, PREF_RESIZE_IMAGES_SERIES_HEIGHT); gtk_spin_button_set_value (GTK_SPIN_BUTTON (GET_WIDGET ("width_spinbutton")), data->latest_width_in_percentage); gtk_spin_button_set_value (GTK_SPIN_BUTTON (GET_WIDGET ("height_spinbutton")), data->latest_height_in_percentage); } else if (unit == GTH_UNIT_PIXELS) { data->latest_width_in_percentage = DEFAULT_WIDTH_PERCENTAGE; data->latest_height_in_percentage = DEFAULT_HEIGHT_PERCENTAGE; data->latest_width_in_pixel = g_settings_get_int (data->settings, PREF_RESIZE_IMAGES_SERIES_WIDTH); data->latest_height_in_pixel = g_settings_get_int (data->settings, PREF_RESIZE_IMAGES_SERIES_HEIGHT); gtk_spin_button_set_value (GTK_SPIN_BUTTON (GET_WIDGET ("width_spinbutton")), data->latest_width_in_pixel); gtk_spin_button_set_value (GTK_SPIN_BUTTON (GET_WIDGET ("height_spinbutton")), data->latest_height_in_pixel); } savers = gth_main_get_type_set ("image-saver"); if (savers != NULL) { GtkListStore *list_store; GtkTreeIter iter; char *default_mime_type; GthIconCache *icon_cache; int i; list_store = (GtkListStore *) GET_WIDGET ("mime_type_liststore"); gtk_list_store_append (list_store, &iter); gtk_list_store_set (list_store, &iter, MIME_TYPE_COLUMN_ICON, NULL, MIME_TYPE_COLUMN_TYPE, NULL, MIME_TYPE_COLUMN_DESCRIPTION, _("Keep the original format"), -1); gtk_combo_box_set_active_iter (GTK_COMBO_BOX (GET_WIDGET ("mime_type_combobox")), &iter); default_mime_type = g_settings_get_string (data->settings, PREF_RESIZE_IMAGES_MIME_TYPE); icon_cache = gth_icon_cache_new_for_widget (data->dialog, GTK_ICON_SIZE_MENU); for (i = 0; i < savers->len; i++) { GType saver_type; GthImageSaver *saver; const char *mime_type; GdkPixbuf *pixbuf; saver_type = g_array_index (savers, GType, i); saver = g_object_new (saver_type, NULL); mime_type = gth_image_saver_get_mime_type (saver); pixbuf = gth_icon_cache_get_pixbuf (icon_cache, g_content_type_get_icon (mime_type)); gtk_list_store_append (list_store, &iter); gtk_list_store_set (list_store, &iter, MIME_TYPE_COLUMN_ICON, pixbuf, MIME_TYPE_COLUMN_TYPE, mime_type, MIME_TYPE_COLUMN_DESCRIPTION, g_content_type_get_description (mime_type), -1); if (strcmp (default_mime_type, mime_type) == 0) gtk_combo_box_set_active_iter (GTK_COMBO_BOX (GET_WIDGET ("mime_type_combobox")), &iter); g_object_unref (pixbuf); g_object_unref (saver); } gth_icon_cache_free (icon_cache); g_free (default_mime_type); } /* Set the signals handlers. */ g_signal_connect (G_OBJECT (data->dialog), "destroy", G_CALLBACK (destroy_cb), data); g_signal_connect (gtk_dialog_get_widget_for_response (GTK_DIALOG (data->dialog), GTK_RESPONSE_OK), "clicked", G_CALLBACK (ok_clicked_cb), data); g_signal_connect_swapped (gtk_dialog_get_widget_for_response (GTK_DIALOG (data->dialog), GTK_RESPONSE_CANCEL), "clicked", G_CALLBACK (gtk_widget_destroy), G_OBJECT (data->dialog)); g_signal_connect (GET_WIDGET ("unit_combobox"), "changed", G_CALLBACK (unit_combobox_changed_cb), data); g_signal_connect (GET_WIDGET ("use_destination_checkbutton"), "toggled", G_CALLBACK (use_destination_checkbutton_toggled_cb), data); data->width_spinbutton_event = g_signal_connect (GET_WIDGET ("width_spinbutton"), "value-changed", G_CALLBACK (width_spinbutton_value_changed_cb), data); data->height_spinbutton_event = g_signal_connect (GET_WIDGET ("height_spinbutton"), "value-changed", G_CALLBACK (height_spinbutton_value_changed_cb), data); /* Run dialog. */ update_width_height_properties (data); width_spinbutton_value_changed_cb (NULL, data); if (GTH_IS_FILE_SOURCE_VFS (gth_browser_get_location_source (browser))) gtk_widget_hide (GET_WIDGET ("use_destination_checkbutton")); gtk_widget_show (data->dialog); }