Commit 1b48c687 authored by Michael Natterer's avatar Michael Natterer 😴

plug-ins: port file-webp to GimpProcedureConfig

parent 04280690
Pipeline #118682 passed with stages
in 13 minutes and 33 seconds
......@@ -32,39 +32,31 @@
#include "libgimp/stdplugins-intl.h"
static void save_dialog_toggle_scale (GtkWidget *widget,
gpointer data);
static void save_dialog_toggle_minsize (GtkWidget *widget,
gpointer data);
static void show_maxkeyframe_hints (GtkAdjustment *adj,
GtkLabel *label);
static void
save_dialog_toggle_scale (GtkWidget *widget,
gpointer data)
save_dialog_toggle_scale (GObject *config,
const GParamSpec *pspec,
GtkAdjustment *adjustment)
{
gimp_scale_entry_set_sensitive (data,
! gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)));
}
gboolean lossless;
static void
save_dialog_toggle_minsize (GtkWidget *widget,
gpointer data)
{
gtk_widget_set_sensitive (GTK_WIDGET (data),
! gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)));
g_object_get (config,
"lossless", &lossless,
NULL);
gimp_scale_entry_set_sensitive (adjustment, ! lossless);
}
static void
show_maxkeyframe_hints (GtkAdjustment *adj,
GtkLabel *label)
show_maxkeyframe_hints (GObject *config,
const GParamSpec *pspec,
GtkLabel *label)
{
gint kmax;
kmax = (gint) gtk_adjustment_get_value (adj);
g_object_get (config,
"keyframe-distance", &kmax,
NULL);
if (kmax == 0)
{
gtk_label_set_text (label, _("(no keyframes)"));
......@@ -80,8 +72,9 @@ show_maxkeyframe_hints (GtkAdjustment *adj,
}
gboolean
save_dialog (WebPSaveParams *params,
GimpImage *image)
save_dialog (GimpImage *image,
GimpProcedure *procedure,
GObject *config)
{
GtkWidget *dialog;
GtkWidget *vbox;
......@@ -91,7 +84,7 @@ save_dialog (WebPSaveParams *params,
GtkWidget *vbox2;
GtkWidget *label;
GtkWidget *toggle;
GtkWidget *toggle_minsize;
GtkListStore *store;
GtkWidget *combo;
GtkAdjustment *quality_scale;
GtkAdjustment *alpha_quality_scale;
......@@ -105,17 +98,16 @@ save_dialog (WebPSaveParams *params,
animation_supported = nlayers > 1;
/* Create the dialog */
dialog = gimp_export_dialog_new (_("WebP"), PLUG_IN_BINARY, SAVE_PROC);
dialog = gimp_procedure_dialog_new (procedure,
GIMP_PROCEDURE_CONFIG (config),
_("Export Image as WebP"));
/* Create the vbox */
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
gtk_container_set_border_width (GTK_CONTAINER (vbox), 12);
gtk_box_pack_start (GTK_BOX (gimp_export_dialog_get_content_area (dialog)),
gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
vbox, FALSE, FALSE, 0);
gtk_widget_show (vbox);
/* Create the grid */
grid = gtk_grid_new ();
gtk_grid_set_row_spacing (GTK_GRID (grid), 6);
gtk_grid_set_column_spacing (GTK_GRID (grid), 6);
......@@ -123,71 +115,48 @@ save_dialog (WebPSaveParams *params,
gtk_widget_show (grid);
/* Create the lossless checkbox */
toggle = gtk_check_button_new_with_mnemonic (_("_Lossless"));
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle),
params->lossless);
toggle = gimp_prop_check_button_new (config, "lossless",
_("_Lossless"));
gtk_grid_attach (GTK_GRID (grid), toggle, 0, row, 3, 1);
gtk_widget_show (toggle);
row++;
g_signal_connect (toggle, "toggled",
G_CALLBACK (gimp_toggle_button_update),
&params->lossless);
/* Create the slider for image quality */
quality_scale = gimp_scale_entry_new (GTK_GRID (grid),
0, row++,
_("Image _quality:"),
125,
0,
params->quality,
0.0, 100.0,
1.0, 10.0,
0, TRUE,
0.0, 0.0,
_("Image quality"),
NULL);
gimp_scale_entry_set_sensitive (quality_scale, ! params->lossless);
g_signal_connect (quality_scale, "value-changed",
G_CALLBACK (gimp_float_adjustment_update),
&params->quality);
quality_scale = gimp_prop_scale_entry_new (config, "quality",
GTK_GRID (grid), 0, row++,
_("Image _quality:"),
1.0, 10.0, 0,
FALSE, 0, 0);
/* Create the slider for alpha channel quality */
alpha_quality_scale = gimp_scale_entry_new (GTK_GRID (grid),
0, row++,
_("Alpha q_uality:"),
125,
0,
params->alpha_quality,
0.0, 100.0,
1.0, 10.0,
0, TRUE,
0.0, 0.0,
_("Alpha channel quality"),
NULL);
gimp_scale_entry_set_sensitive (alpha_quality_scale, ! params->lossless);
g_signal_connect (alpha_quality_scale, "value-changed",
G_CALLBACK (gimp_float_adjustment_update),
&params->alpha_quality);
alpha_quality_scale = gimp_prop_scale_entry_new (config, "alpha-quality",
GTK_GRID (grid), 0, row++,
_("Alpha q_uality:"),
1.0, 10.0, 0,
FALSE, 0, 0);
/* Enable and disable the sliders when the lossless option is selected */
g_signal_connect (toggle, "toggled",
g_signal_connect (config, "notify::lossless",
G_CALLBACK (save_dialog_toggle_scale),
quality_scale);
g_signal_connect (toggle, "toggled",
g_signal_connect (config, "notify::lossless",
G_CALLBACK (save_dialog_toggle_scale),
alpha_quality_scale);
save_dialog_toggle_scale (config, NULL, quality_scale);
save_dialog_toggle_scale (config, NULL, alpha_quality_scale);
/* Create the combobox containing the presets */
combo = gimp_int_combo_box_new ("Default", WEBP_PRESET_DEFAULT,
"Picture", WEBP_PRESET_PICTURE,
"Photo", WEBP_PRESET_PHOTO,
"Drawing", WEBP_PRESET_DRAWING,
"Icon", WEBP_PRESET_ICON,
"Text", WEBP_PRESET_TEXT,
NULL);
store = gimp_int_store_new ("Default", WEBP_PRESET_DEFAULT,
"Picture", WEBP_PRESET_PICTURE,
"Photo", WEBP_PRESET_PHOTO,
"Drawing", WEBP_PRESET_DRAWING,
"Icon", WEBP_PRESET_ICON,
"Text", WEBP_PRESET_TEXT,
NULL);
combo = gimp_prop_int_combo_box_new (config, "preset",
GIMP_INT_STORE (store));
g_object_unref (store);
label = gimp_grid_attach_aligned (GTK_GRID (grid), 0, row++,
_("Source _type:"), 0.0, 0.5,
combo, 2);
......@@ -195,19 +164,12 @@ save_dialog (WebPSaveParams *params,
_("WebP encoder \"preset\""),
NULL);
gimp_int_combo_box_connect (GIMP_INT_COMBO_BOX (combo),
params->preset,
G_CALLBACK (gimp_int_combo_box_get_active),
&params->preset, NULL);
if (animation_supported)
{
GtkWidget *animation_box;
GtkAdjustment *adj;
GtkWidget *delay;
GtkWidget *hbox;
GtkWidget *label_kf;
GtkAdjustment *adj_kf;
GtkWidget *kf_distance;
GtkWidget *hbox_kf;
PangoAttrList *attrs;
......@@ -225,19 +187,13 @@ save_dialog (WebPSaveParams *params,
/* Create the top-level animation checkbox expander */
text = g_strdup_printf ("<b>%s</b>", _("As A_nimation"));
toggle = gtk_check_button_new_with_mnemonic (text);
toggle = gimp_prop_check_button_new (config, "animation",
text);
g_free (text);
gtk_label_set_use_markup (GTK_LABEL (gtk_bin_get_child (GTK_BIN (toggle))),
TRUE);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle),
params->animation);
gtk_box_pack_start (GTK_BOX (vbox2), toggle, TRUE, TRUE, 0);
gtk_widget_show (toggle);
g_signal_connect (toggle, "toggled",
G_CALLBACK (gimp_toggle_button_update),
&params->animation);
frame = gimp_frame_new ("<expander>");
gtk_box_pack_start (GTK_BOX (vbox2), frame, TRUE, TRUE, 0);
......@@ -253,15 +209,10 @@ save_dialog (WebPSaveParams *params,
gtk_widget_show (animation_box);
/* loop animation checkbox */
toggle = gtk_check_button_new_with_mnemonic (_("Loop _forever"));
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), params->loop);
toggle = gimp_prop_check_button_new (config, "animation-loop",
_("Loop _forever"));
gtk_box_pack_start (GTK_BOX (animation_box), toggle,
FALSE, FALSE, 0);
gtk_widget_show (toggle);
g_signal_connect (toggle, "toggled",
G_CALLBACK (gimp_toggle_button_update),
&params->loop);
/* create a hbox for 'max key-frame distance */
hbox_kf = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
......@@ -276,17 +227,9 @@ save_dialog (WebPSaveParams *params,
gtk_widget_show (label_kf);
/* key-frame distance entry */
adj_kf = gtk_adjustment_new (params->kf_distance,
0.0, 10000.0,
1.0, 10.0, 0.0);
kf_distance = gimp_spin_button_new (adj_kf, 1, 0);
gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (kf_distance), TRUE);
kf_distance = gimp_prop_spin_button_new (config, "keyframe-distance",
1.0, 1.0, 0);
gtk_box_pack_start (GTK_BOX (hbox_kf), kf_distance, FALSE, FALSE, 0);
gtk_widget_show (kf_distance);
g_signal_connect (adj_kf, "value-changed",
G_CALLBACK (gimp_int_adjustment_update),
&params->kf_distance);
/* Add some hinting text for special values of key-frame distance. */
label_kf = gtk_label_new (NULL);
......@@ -299,28 +242,25 @@ save_dialog (WebPSaveParams *params,
gtk_label_set_attributes (GTK_LABEL (label_kf), attrs);
pango_attr_list_unref (attrs);
g_signal_connect (adj_kf, "value-changed",
g_signal_connect (config, "notify::keyframe-distance",
G_CALLBACK (show_maxkeyframe_hints),
label_kf);
show_maxkeyframe_hints (adj_kf, GTK_LABEL (label_kf));
show_maxkeyframe_hints (config, NULL, GTK_LABEL (label_kf));
/* minimize-size checkbox */
toggle_minsize = gtk_check_button_new_with_mnemonic (_("_Minimize output size (slower)"));
gtk_box_pack_start (GTK_BOX (animation_box), toggle_minsize,
toggle = gimp_prop_check_button_new (config, "minimize-size",
_("_Minimize output size "
"(slower)"));
gtk_box_pack_start (GTK_BOX (animation_box), toggle,
FALSE, FALSE, 0);
gtk_widget_show (toggle_minsize);
g_signal_connect (toggle_minsize, "toggled",
G_CALLBACK (gimp_toggle_button_update),
&params->minimize_size);
/* Enable and disable the kf-distance box when the 'minimize size' option is selected */
g_signal_connect (toggle_minsize, "toggled",
G_CALLBACK (save_dialog_toggle_minsize),
hbox_kf);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle_minsize), params->minimize_size);
/* Enable and disable the kf-distance box when the 'minimize size'
* option is selected
*/
g_object_bind_property (config, "minimize-size",
hbox_kf, "sensitive",
G_BINDING_SYNC_CREATE |
G_BINDING_INVERT_BOOLEAN);
/* create a hbox for delay */
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
......@@ -334,15 +274,9 @@ save_dialog (WebPSaveParams *params,
gtk_widget_show (label);
/* default delay */
adj = gtk_adjustment_new (params->delay, 1, 10000, 1, 10, 0);
delay = gimp_spin_button_new (adj, 1, 0);
gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (delay), TRUE);
delay = gimp_prop_spin_button_new (config, "default-delay",
1, 10, 0);
gtk_box_pack_start (GTK_BOX (hbox), delay, FALSE, FALSE, 0);
gtk_widget_show (delay);
g_signal_connect (adj, "value-changed",
G_CALLBACK (gimp_int_adjustment_update),
&params->delay);
/* label for 'ms' adjustment */
label = gtk_label_new (_("milliseconds"));
......@@ -350,50 +284,30 @@ save_dialog (WebPSaveParams *params,
gtk_widget_show (label);
/* Create the force-delay checkbox */
toggle = gtk_check_button_new_with_mnemonic (_("Use _delay entered above for all frames"));
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle),
params->force_delay);
toggle = gimp_prop_check_button_new (config, "force-delay",
_("Use _delay entered above for "
"all frames"));
gtk_box_pack_start (GTK_BOX (animation_box), toggle, FALSE, FALSE, 0);
gtk_widget_show (toggle);
g_signal_connect (toggle, "toggled",
G_CALLBACK (gimp_toggle_button_update),
&params->force_delay);
}
/* Save EXIF data */
toggle = gtk_check_button_new_with_mnemonic (_("_Save Exif data"));
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), params->save_exif);
toggle = gimp_prop_check_button_new (config, "save-exif",
_("_Save Exif data"));
gtk_box_pack_start (GTK_BOX (vbox), toggle, FALSE, FALSE, 0);
gtk_widget_show (toggle);
g_signal_connect (toggle, "toggled",
G_CALLBACK (gimp_toggle_button_update),
&params->save_exif);
/* XMP metadata */
toggle = gtk_check_button_new_with_mnemonic (_("Save _XMP data"));
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), params->save_xmp);
toggle = gimp_prop_check_button_new (config, "save-xmp",
_("Save _XMP data"));
gtk_box_pack_start (GTK_BOX (vbox), toggle, FALSE, FALSE, 0);
gtk_widget_show (toggle);
g_signal_connect (toggle, "toggled",
G_CALLBACK (gimp_toggle_button_update),
&params->save_xmp);
/* Color profile */
toggle = gtk_check_button_new_with_mnemonic (_("Save color _profile"));
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), params->save_profile);
toggle = gimp_prop_check_button_new (config, "save-color-profile",
_("Save color _profile"));
gtk_box_pack_start (GTK_BOX (vbox), toggle, FALSE, FALSE, 0);
gtk_widget_show (toggle);
g_signal_connect (toggle, "toggled",
G_CALLBACK (gimp_toggle_button_update),
&params->save_profile);
gtk_widget_show (dialog);
run = (gimp_dialog_run (GIMP_DIALOG (dialog)) == GTK_RESPONSE_OK);
run = gimp_procedure_dialog_run (GIMP_PROCEDURE_DIALOG (dialog));
gtk_widget_destroy (dialog);
......
......@@ -23,11 +23,9 @@
#define __WEBP_DIALOG_H__
#include "file-webp-save.h"
gboolean save_dialog (WebPSaveParams *params,
GimpImage *image);
gboolean save_dialog (GimpImage *image,
GimpProcedure *procedure,
GObject *config);
#endif /* __WEBP_DIALOG_H__ */
......@@ -53,7 +53,7 @@ int webp_file_progress (int percent,
const gchar * webp_error_string (WebPEncodingError error_code);
static void webp_decide_output (GimpImage *image,
WebPSaveParams *params,
GObject *config,
GimpColorProfile **profile,
gboolean *out_linear);
......@@ -125,11 +125,11 @@ webp_error_string (WebPEncodingError error_code)
}
gboolean
save_layer (GFile *file,
GimpImage *image,
GimpDrawable *drawable,
WebPSaveParams *params,
GError **error)
save_layer (GFile *file,
GimpImage *image,
GimpDrawable *drawable,
GObject *config,
GError **error)
{
gboolean status = FALSE;
FILE *outfile = NULL;
......@@ -152,8 +152,19 @@ save_layer (GFile *file,
WebPData chunk;
gboolean out_linear = FALSE;
int res;
webp_decide_output (image, params, &profile, &out_linear);
WebPPreset preset;
gboolean lossless;
gdouble quality;
gdouble alpha_quality;
g_object_get (config,
"preset", &preset,
"lossless", &lossless,
"quality", &quality,
"alpha-quality", &alpha_quality,
NULL);
webp_decide_output (image, config, &profile, &out_linear);
if (profile)
{
space = gimp_color_profile_get_space (profile,
......@@ -229,11 +240,11 @@ save_layer (GFile *file,
/* Initialize the WebP configuration with a preset and fill in the
* remaining values */
WebPConfigPreset (&webp_config, params->preset, params->quality);
WebPConfigPreset (&webp_config, preset, quality);
webp_config.lossless = params->lossless;
webp_config.lossless = lossless;
webp_config.method = 6; /* better quality */
webp_config.alpha_quality = params->alpha_quality;
webp_config.alpha_quality = alpha_quality;
/* Prepare the WebP structure */
WebPPictureInit (&picture);
......@@ -489,17 +500,17 @@ combine_buffers (GeglBuffer *layer_buffer,
}
gboolean
save_animation (GFile *file,
GimpImage *image,
GimpDrawable *drawable,
WebPSaveParams *params,
GError **error)
save_animation (GFile *file,
GimpImage *image,
GimpDrawable *drawable,
GObject *config,
GError **error)
{
GList *layers;
gint32 n_layers;
gboolean status = TRUE;
FILE *outfile = NULL;
guchar *buffer = NULL;
gboolean status = TRUE;
FILE *outfile = NULL;
guchar *buffer = NULL;
gint buffer_size = 0;
gint w, h;
gint bpp;
......@@ -514,6 +525,29 @@ save_animation (GFile *file,
WebPAnimEncoder *enc = NULL;
GeglBuffer *prev_frame = NULL;
gboolean out_linear = FALSE;
WebPPreset preset;
gboolean lossless;
gboolean animation;
gboolean loop;
gboolean minimize_size;
gint keyframe_distance;
gdouble quality;
gdouble alpha_quality;
gint default_delay;
gboolean force_delay;
g_object_get (config,
"preset", &preset,
"lossless", &lossless,
"animation", &animation,
"animation-loop", &loop,
"minimize-size", &minimize_size,
"keyframe-distance", &keyframe_distance,
"quality", &quality,
"alpha-quality", &alpha_quality,
"default-delay", &default_delay,
"force-delay", &force_delay,
NULL);
layers = gimp_image_list_layers (image);
......@@ -523,7 +557,7 @@ save_animation (GFile *file,
layers = g_list_reverse (layers);
n_layers = g_list_length (layers);
webp_decide_output (image, params, &profile, &out_linear);
webp_decide_output (image, config, &profile, &out_linear);
if (profile)
{
space = gimp_color_profile_get_space (profile,
......@@ -549,11 +583,9 @@ save_animation (GFile *file,
do
{
gchar *filename;
GList *list;
gint loop;
gint default_delay = params->delay;
gboolean force_delay = params->force_delay;
gchar *filename;
GList *list;
gint i;
/* Begin displaying export progress */
gimp_progress_init_printf (_("Saving '%s'"),
......@@ -562,7 +594,7 @@ save_animation (GFile *file,
/* Attempt to open the output file */
filename = g_file_get_path (file);
outfile = g_fopen (filename, "wb");
g_free (file);
g_free (filename);
if (! outfile)
{
......@@ -583,21 +615,21 @@ save_animation (GFile *file,
}
enc_options.anim_params.loop_count = 0;
if (! params->loop)
if (! loop)
enc_options.anim_params.loop_count = 1;
enc_options.allow_mixed = params->lossless ? 0 : 1;
enc_options.minimize_size = params->minimize_size ? 1 : 0;
if (! params->minimize_size)
enc_options.allow_mixed = lossless ? 0 : 1;
enc_options.minimize_size = minimize_size ? 1 : 0;
if (! minimize_size)
{
enc_options.kmax = params->kf_distance;
enc_options.kmax = keyframe_distance;
/* explicitly force minimum key-frame distance too, for good measure */
enc_options.kmin = params->kf_distance - 1;
enc_options.kmin = keyframe_distance - 1;
}
for (list = layers, loop = 0;
for (list = layers, i = 0;
list;
list = g_list_next (list), loop++)
list = g_list_next (list), i++)
{
GeglBuffer *geglbuffer;
GeglBuffer *current_frame;
......@@ -642,7 +674,7 @@ save_animation (GFile *file,
w = extent.width;
h = extent.height;
if (loop == 0)
if (i == 0)
{
enc = WebPAnimEncoderNew (w, h, &enc_options);
if (! enc)
......@@ -670,11 +702,11 @@ save_animation (GFile *file,
}
}
WebPConfigPreset (&webp_config, params->preset, params->quality);
WebPConfigPreset (&webp_config, preset, quality);
webp_config.lossless = params->lossless;
webp_config.lossless = lossless;
webp_config.method = 6; /* better quality */
webp_config.alpha_quality = params->alpha_quality;
webp_config.alpha_quality = alpha_quality;
webp_config.exact = 1;
WebPMemoryWriterInit (&mw);
......@@ -688,7 +720,7 @@ save_animation (GFile *file,
picture.custom_ptr = &mw;
picture.writer = WebPMemoryWrite;
if (loop == 0 || ! needs_combine)
if (i == 0 || ! needs_combine)
{
g_clear_object (&prev_frame);
current_frame = geglbuffer;
......@@ -726,8 +758,8 @@ save_animation (GFile *file,
else if (! WebPAnimEncoderAdd (enc, &picture, frame_timestamp,
&webp_config))
{
g_printerr ("ERROR[%d]: %s\n",
picture.error_code,
g_printerr ("ERROR[%d]: line %d: %s\n",
picture.error_code, __LINE__,
webp_error_string (picture.error_code));
status = FALSE;
}
......@@ -738,9 +770,10 @@ save_animation (GFile *file,
if (status == FALSE)
break;
gimp_progress_update ((loop + 1.0) / n_layers);
gimp_progress_update ((i + 1.0) / n_layers);
frame_timestamp += (delay <= 0 || force_delay) ? default_delay : delay;
}
g_free (buffer);
if (status == FALSE)
......@@ -811,15 +844,21 @@ save_animation (GFile *file,
static void
webp_decide_output (GimpImage *image,
WebPSaveParams *params,
GObject *config,
GimpColorProfile **profile,
gboolean *out_linear)
{
gboolean save_profile;
g_return_if_fail (profile && *profile == NULL);
g_object_get (config,
"save-color-profile", &save_profile,
NULL);
*out_linear = FALSE;
if (params->save_profile)
if (save_profile)
{
*profile = gimp_image_get_color_profile (image);
......
......@@ -23,36 +23,17 @@
#define __WEBP_SAVE_H__
typedef struct
{
WebPPreset preset;
gboolean lossless;
gboolean animation;
gboolean loop;
gboolean minimize_size;
gint kf_distance;
gfloat quality;
gfloat alpha_quality;
gboolean save_exif;
gboolean save_iptc;
gboolean save_xmp;
gboolean save_profile;
gint delay;
gboolean force_delay;
} WebPSaveParams;
gboolean save_layer (GFile *file,
GimpImage *image,
GimpDrawable *drawable,
WebPSaveParams *params,
GError **error);
gboolean save_animation (GFile *file,
GimpImage *image,
GimpDrawable *drawable,
WebPSaveParams *params,
GError **error);
gboolean save_layer (GFile *file,
GimpImage *image,
GimpDrawable *drawable,
GObject *config,
GError **</