[gimp] plug-ins: port file-jpeg export procedure to new API.



commit 731537befd6b13c8679b8555f8f56286d58e0a9b
Author: Jehan <jehan girinstud io>
Date:   Wed Nov 25 22:44:43 2020 +0100

    plug-ins: port file-jpeg export procedure to new API.
    
    This is nearly 600 lines less for basically the same logics! Removed
    code is in particular all the GUI code is favor of the new GUI
    generation.
    I also cleaned a lot of stuff, removing many global variables or ugly
    pieces of code. I also removed a lot of redundant code of things which
    are now generic, such as handling of "gimp-comment" parasite (this is
    now handled by GimpSaveProcedure and GimpImageMetadata) as well as
    saving previous run's values (this is also handled generically).
    
    Note that Advanced Options used to be in an expander. For now I chose to
    get them immediately visible (still in their own "Advanced Options"
    section, but it's now a normal frame, not an expander hidden by default)
    since lately we got some input that many "advanced options" in various
    dialogs should not be hidden away. So let's try like this for now (even
    though it packs quite a lot of options in the same dialog!).
    
    I thoroughly tested, yet that were so many changes that bugs may have
    sneaked in. Please anyone, test JPEG export!

 plug-ins/file-jpeg/jpeg-save.c     | 1028 +++++++++---------------------------
 plug-ins/file-jpeg/jpeg-save.h     |   40 +-
 plug-ins/file-jpeg/jpeg-settings.c |    4 +-
 plug-ins/file-jpeg/jpeg.c          |  289 ++++------
 plug-ins/file-jpeg/jpeg.h          |    4 -
 5 files changed, 384 insertions(+), 981 deletions(-)
---
diff --git a/plug-ins/file-jpeg/jpeg-save.c b/plug-ins/file-jpeg/jpeg-save.c
index 8f2537b05f..83a8e13162 100644
--- a/plug-ins/file-jpeg/jpeg-save.c
+++ b/plug-ins/file-jpeg/jpeg-save.c
@@ -44,32 +44,8 @@
 #include "jpeg-save.h"
 #include "jpeg-settings.h"
 
-#ifdef C_ARITH_CODING_SUPPORTED
-static gboolean arithc_supported = TRUE;
-#else
-static gboolean arithc_supported = FALSE;
-#endif
-
 /* See bugs #63610 and #61088 for a discussion about the quality settings */
-#define DEFAULT_IJG_QUALITY      90.0
-#define DEFAULT_SMOOTHING        0.0
-#define DEFAULT_OPTIMIZE         TRUE
-#define DEFAULT_ARITHMETIC_CODING FALSE
-#define DEFAULT_PROGRESSIVE      TRUE
-#define DEFAULT_BASELINE         TRUE
-#define DEFAULT_SUBSMP           JPEG_SUBSAMPLING_1x1_1x1_1x1
-#define DEFAULT_RESTART          0
 #define DEFAULT_RESTART_MCU_ROWS 16
-#define DEFAULT_DCT              0
-#define DEFAULT_PREVIEW          FALSE
-#define DEFAULT_EXIF             FALSE
-#define DEFAULT_XMP              FALSE
-#define DEFAULT_IPTC             FALSE
-#define DEFAULT_THUMBNAIL        FALSE
-#define DEFAULT_PROFILE          TRUE
-#define DEFAULT_USE_ORIG_QUALITY FALSE
-
-#define JPEG_DEFAULTS_PARASITE  "jpeg-save-defaults"
 
 
 typedef struct
@@ -89,61 +65,19 @@ typedef struct
   guint         source_id;
 } PreviewPersistent;
 
-/*le added : struct containing pointers to export dialog*/
-typedef struct
-{
-  gboolean       run;
-  GtkWidget     *use_restart_markers;   /*checkbox setting use restart markers*/
-  GtkTextBuffer *text_buffer;
-  GtkAdjustment *scale_data;            /*for restart markers*/
-  gulong         handler_id_restart;
-
-  GtkWidget     *quality;               /*quality slidebar*/
-  GtkWidget     *smoothing;             /*smoothing slidebar*/
-  GtkWidget     *optimize;              /*optimize toggle*/
-  GtkWidget     *arithmetic_coding;     /*arithmetic coding toggle*/
-  GtkWidget     *progressive;           /*progressive toggle*/
-  GtkWidget     *subsmp;                /*subsampling side select*/
-  GtkWidget     *restart;               /*spinner for setting frequency restart markers*/
-  GtkWidget     *dct;                   /*DCT side select*/
-  GtkWidget     *preview;               /*show preview toggle checkbox*/
-  GtkWidget     *save_exif;
-  GtkWidget     *save_xmp;
-  GtkWidget     *save_iptc;
-  GtkWidget     *save_thumbnail;
-  GtkWidget     *save_profile;
-  GtkWidget     *use_orig_quality;      /*quant tables toggle*/
-} JpegSaveGui;
-
-static void  make_preview           (void);
-
-static void  scale_entry_update     (GimpLabelSpin  *entry,
-                                     gdouble        *value);
-static void  save_restart_update    (GtkAdjustment  *adjustment,
-                                     GtkWidget      *toggle);
-static void  subsampling_changed    (GtkWidget      *combo,
-                                     GtkWidget      *entry);
-static void  quality_changed        (GimpScaleEntry *scale_entry,
-                                     GtkWidget      *toggle);
-static void  subsampling_changed2   (GtkWidget      *combo,
-                                     GtkWidget      *toggle);
-static void  use_orig_qual_changed  (GtkWidget      *toggle,
-                                     GimpLabelSpin  *scale_entry);
-static void  use_orig_qual_changed2 (GtkWidget      *toggle,
-                                     GtkWidget      *combo);
-
-
-static GtkWidget *restart_markers_scale = NULL;
-static GtkWidget *restart_markers_label = NULL;
-static GtkWidget *preview_size          = NULL;
-static PreviewPersistent *prev_p        = NULL;
 
-static void   save_dialog_response (GtkWidget   *widget,
-                                    gint         response_id,
-                                    gpointer     data);
+static void  make_preview              (GimpProcedureConfig *config);
 
-static void   load_gui_defaults    (JpegSaveGui *pg);
-static void   save_defaults        (void);
+static void  quality_changed           (GimpProcedureConfig *config);
+static void  subsampling_changed       (GimpProcedureConfig *config,
+                                        const GParamSpec    *pspec,
+                                        GtkWidget           *smoothing_scale);
+static void  use_orig_qual_changed     (GimpProcedureConfig *config);
+static void  use_orig_qual_changed_rgb (GimpProcedureConfig *config);
+
+
+static GtkWidget         *preview_size  = NULL;
+static PreviewPersistent *prev_p        = NULL;
 
 
 /*
@@ -259,12 +193,13 @@ background_jpeg_save (PreviewPersistent *pp)
 }
 
 gboolean
-save_image (GFile        *file,
-            GimpImage    *image,
-            GimpDrawable *drawable,
-            GimpImage    *orig_image,
-            gboolean      preview,
-            GError      **error)
+save_image (GFile                *file,
+            GimpProcedureConfig  *config,
+            GimpImage            *image,
+            GimpDrawable         *drawable,
+            GimpImage            *orig_image,
+            gboolean              preview,
+            GError              **error)
 {
   static struct jpeg_compress_struct cinfo;
   static struct my_error_mgr         jerr;
@@ -285,6 +220,48 @@ save_image (GFile        *file,
   gboolean         out_linear = FALSE;
   gint             rowstride, yend;
 
+  gint             quality;
+  gdouble          dquality      = 1.0;
+  gdouble          smoothing;
+  gboolean         optimize;
+  gboolean         progressive;
+  gint             subsmp;
+  gboolean         baseline;
+  gint             restart;
+  gint             dct;
+  gboolean         save_profile          = TRUE;
+  gboolean         save_comment;
+  gboolean         use_orig_quality      = FALSE;
+  gint             orig_num_quant_tables = -1;
+  gboolean         use_arithmetic_coding = FALSE;
+  gboolean         use_restart           = FALSE;
+  gchar           *comment;
+
+  g_object_get (config,
+                "quality",                   &dquality,
+                "smoothing",                 &smoothing,
+                "optimize",                  &optimize,
+                "progressive",               &progressive,
+                "sub-sampling",              &subsmp,
+                "baseline",                  &baseline,
+                "restart",                   &restart,
+                "dct",                       &dct,
+
+                /* Original quality settings. */
+                "use-original-quality",      &use_orig_quality,
+                "original-num-quant-tables", &orig_num_quant_tables,
+
+                "use-arithmetic-coding",     &use_arithmetic_coding,
+                "use-restart",               &use_restart,
+
+                "save-color-profile",        &save_profile,
+                "save-comment",              &save_comment,
+                "gimp-comment",              &comment,
+
+                NULL);
+
+  quality = (gint) (dquality * 100.0 + 0.5);
+
   drawable_type = gimp_drawable_type (drawable);
   buffer = gimp_drawable_get_buffer (drawable);
   space = gimp_drawable_get_format (drawable);
@@ -348,7 +325,7 @@ save_image (GFile        *file,
    * If we save the default linear profile (i.e. no assigned
    * profile), we convert it to sRGB, except when it is 8-bit linear.
    */
-  if (jsvals.save_profile)
+  if (save_profile)
     {
       profile = gimp_image_get_color_profile (orig_image);
 
@@ -472,47 +449,46 @@ save_image (GFile        *file,
    */
   jpeg_set_defaults (&cinfo);
 
-  jpeg_set_quality (&cinfo, (gint) (jsvals.quality + 0.5), jsvals.baseline);
+  jpeg_set_quality (&cinfo, quality, baseline);
 
-  if (jsvals.use_orig_quality && num_quant_tables > 0)
+  if (use_orig_quality && orig_num_quant_tables > 0)
     {
       guint **quant_tables;
       gint    t;
 
       /* override tables generated by jpeg_set_quality() with custom tables */
-      quant_tables = jpeg_restore_original_tables (image, num_quant_tables);
+      quant_tables = jpeg_restore_original_tables (image, orig_num_quant_tables);
       if (quant_tables)
         {
-          for (t = 0; t < num_quant_tables; t++)
+          for (t = 0; t < orig_num_quant_tables; t++)
             {
               jpeg_add_quant_table (&cinfo, t, quant_tables[t],
-                                    100, jsvals.baseline);
+                                    100, baseline);
               g_free (quant_tables[t]);
             }
           g_free (quant_tables);
         }
     }
 
-  if (arithc_supported)
-    {
-      cinfo.arith_code = jsvals.arithmetic_coding;
-      if (!jsvals.arithmetic_coding)
-        cinfo.optimize_coding = jsvals.optimize;
-    }
-  else
-    cinfo.optimize_coding = jsvals.optimize;
+#ifdef C_ARITH_CODING_SUPPORTED
+  cinfo.arith_code = use_arithmetic_coding;
+  if (! use_arithmetic_coding)
+    cinfo.optimize_coding = optimize;
+#else
+  cinfo.optimize_coding = optimize;
+#endif
 
   subsampling = (gimp_drawable_is_rgb (drawable) ?
-                 jsvals.subsmp : JPEG_SUBSAMPLING_1x1_1x1_1x1);
+                 subsmp : JPEG_SUBSAMPLING_1x1_1x1_1x1);
 
   /*  smoothing is not supported with nonstandard sampling ratios  */
   if (subsampling != JPEG_SUBSAMPLING_2x1_1x1_1x1 &&
       subsampling != JPEG_SUBSAMPLING_1x2_1x1_1x1)
     {
-      cinfo.smoothing_factor = (gint) (jsvals.smoothing * 100);
+      cinfo.smoothing_factor = (gint) (smoothing * 100);
     }
 
-  if (jsvals.progressive)
+  if (progressive)
     {
       jpeg_simple_progression (&cinfo);
     }
@@ -558,9 +534,9 @@ save_image (GFile        *file,
     }
 
   cinfo.restart_interval = 0;
-  cinfo.restart_in_rows = jsvals.restart;
+  cinfo.restart_in_rows = use_restart ? restart : 0;
 
-  switch (jsvals.dct)
+  switch (dct)
     {
     case 0:
     default:
@@ -614,18 +590,18 @@ save_image (GFile        *file,
   jpeg_start_compress (&cinfo, TRUE);
 
   /* Step 4.1: Write the comment out - pw */
-  if (image_comment && *image_comment)
+  if (save_comment && comment && *comment)
     {
 #ifdef GIMP_UNSTABLE
       g_print ("jpeg-save: saving image comment (%d bytes)\n",
-               (int) strlen (image_comment));
+               (int) strlen (comment));
 #endif
       jpeg_write_marker (&cinfo, JPEG_COM,
-                         (guchar *) image_comment, strlen (image_comment));
+                         (guchar *) comment, strlen (comment));
     }
 
   /* Step 4.2: store the color profile */
-  if (jsvals.save_profile)
+  if (save_profile)
     {
       const guint8 *icc_data;
       gsize         icc_length;
@@ -738,11 +714,15 @@ save_image (GFile        *file,
 }
 
 static void
-make_preview (void)
+make_preview (GimpProcedureConfig *config)
 {
+  gboolean show_preview;
+
   destroy_preview ();
 
-  if (jsvals.preview)
+  g_object_get (config, "show-preview", &show_preview, NULL);
+
+  if (show_preview)
     {
       GFile *file = gimp_temp_file ("jpeg");
 
@@ -755,7 +735,7 @@ make_preview (void)
           undo_touched = TRUE;
         }
 
-      save_image (file,
+      save_image (file, config,
                   preview_image,
                   drawable_global,
                   orig_image_global,
@@ -798,726 +778,236 @@ destroy_preview (void)
     }
 }
 
-static void
-toggle_arithmetic_coding (GtkToggleButton *togglebutton,
-                          gpointer         user_data)
-{
-  GtkWidget *optimize = GTK_WIDGET (user_data);
-
-  gtk_widget_set_sensitive (optimize,
-                            !gtk_toggle_button_get_active (togglebutton));
-}
-
 gboolean
-save_dialog (GimpDrawable *drawable)
+save_dialog (GimpProcedure       *procedure,
+             GimpProcedureConfig *config,
+             GimpDrawable        *drawable)
 {
-  JpegSaveGui    pg;
-  GtkWidget     *dialog;
-  GtkWidget     *vbox;
-  GtkWidget     *vbox2;
-  GtkWidget     *grid;
-  GtkWidget     *griddefaults;
-  GtkWidget     *expander;
-  GtkWidget     *frame;
-  GtkWidget     *toggle;
-  GtkWidget     *spinbutton;
-  GtkWidget     *label;
-  GtkWidget     *combo;
-  GtkWidget     *text_view;
-  GtkTextBuffer *text_buffer;
-  GtkWidget     *scrolled_window;
-  GtkWidget     *button;
-  gchar         *text;
-  gint           row;
-
-  dialog = gimp_export_dialog_new (_("JPEG"), PLUG_IN_BINARY, SAVE_PROC);
-
-  g_signal_connect (dialog, "response",
-                    G_CALLBACK (save_dialog_response),
-                    &pg);
-  g_signal_connect (dialog, "destroy",
-                    G_CALLBACK (gtk_main_quit),
-                    NULL);
-
-  gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
-
-  vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
-  gtk_container_set_border_width (GTK_CONTAINER (vbox), 12);
-  gtk_box_pack_start (GTK_BOX (gimp_export_dialog_get_content_area (dialog)),
-                      vbox, TRUE, TRUE, 0);
-  gtk_widget_show (vbox);
-
-  vbox2 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
-  gtk_box_pack_start (GTK_BOX (vbox), vbox2, FALSE, FALSE, 0);
-  gtk_widget_show (vbox2);
-
-  pg.quality = gimp_scale_entry_new (_("_Quality:"), jsvals.quality, 0.0, 100.0, 0);
-  gimp_help_set_help_data (pg.quality, _("JPEG quality parameter"), "file-jpeg-save-quality");
-
-  g_signal_connect (pg.quality, "value-changed",
-                    G_CALLBACK (scale_entry_update),
-                    &jsvals.quality);
-  g_signal_connect (pg.quality, "value-changed",
-                    G_CALLBACK (make_preview),
-                    NULL);
-  gtk_box_pack_start (GTK_BOX (vbox2), pg.quality, FALSE, FALSE, 0);
-  gtk_widget_show (pg.quality);
+  GtkWidget    *dialog;
+  GtkWidget    *widget;
+  GtkListStore *store;
+  gint          orig_quality;
+  gint          restart;
+  gboolean      run;
+
+  g_object_get (config,
+                "original-quality", &orig_quality,
+                "restart",          &restart,
+                NULL);
+
+  dialog = gimp_save_procedure_dialog_new (GIMP_SAVE_PROCEDURE (procedure),
+                                           GIMP_PROCEDURE_CONFIG (config),
+                                           _("Export Image as JPEG"));
 
   /* custom quantization tables - now used also for original quality */
-  pg.use_orig_quality = toggle =
-    gtk_check_button_new_with_mnemonic (_("_Use quality settings from original "
-                                          "image"));
-  gtk_box_pack_start (GTK_BOX (vbox2), toggle, FALSE, FALSE, 0);
-  gtk_widget_show (toggle);
-
-  gimp_help_set_help_data (toggle,
-                           _("If the original image was loaded from a JPEG "
-                             "file using non-standard quality settings "
-                             "(quantization tables), enable this option to "
-                             "get almost the same quality and file size."),
-                           NULL);
-
-  g_signal_connect (toggle, "toggled",
-                    G_CALLBACK (gimp_toggle_button_update),
-                    &jsvals.use_orig_quality);
-
-  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle),
-                                jsvals.use_orig_quality
-                                && (orig_quality > 0)
-                                && (orig_subsmp == jsvals.subsmp)
-                               );
-  gtk_widget_set_sensitive (toggle, (orig_quality > 0));
+  widget = gimp_procedure_dialog_get_widget (GIMP_PROCEDURE_DIALOG (dialog),
+                                                                   "use-original-quality", G_TYPE_NONE);
+  gtk_widget_set_sensitive (widget, (orig_quality > 0));
+
+  /* Quality as a GimpScaleEntry. */
+  gimp_procedure_dialog_get_scale_entry (GIMP_PROCEDURE_DIALOG (dialog), "quality", 100.0);
 
   /* changing quality disables custom quantization tables, and vice-versa */
-  g_signal_connect (pg.quality, "value-changed",
+  g_signal_connect (config, "notify::quality",
                     G_CALLBACK (quality_changed),
-                    pg.use_orig_quality);
-  g_signal_connect (pg.use_orig_quality, "toggled",
+                    NULL);
+  g_signal_connect (config, "notify::use-original-quality",
                     G_CALLBACK (use_orig_qual_changed),
-                    pg.quality);
-
-  /* File size */
-  vbox2 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
-  gtk_box_pack_start (GTK_BOX (vbox), vbox2, FALSE, FALSE, 0);
-  gtk_widget_show (vbox2);
+                    NULL);
 
-  preview_size = gtk_label_new (_("File size: unknown"));
+  /* File size label. */
+  preview_size = gimp_procedure_dialog_get_label (GIMP_PROCEDURE_DIALOG (dialog),
+                                                  "preview-size", _("File size: unknown"));
   gtk_label_set_xalign (GTK_LABEL (preview_size), 0.0);
   gtk_label_set_ellipsize (GTK_LABEL (preview_size), PANGO_ELLIPSIZE_END);
   gimp_label_set_attributes (GTK_LABEL (preview_size),
                              PANGO_ATTR_STYLE, PANGO_STYLE_ITALIC,
                              -1);
-  gtk_box_pack_start (GTK_BOX (vbox2), preview_size, FALSE, FALSE, 0);
-  gtk_widget_show (preview_size);
-
   gimp_help_set_help_data (preview_size,
                            _("Enable preview to obtain the file size."), NULL);
 
-  pg.preview = toggle =
-    gtk_check_button_new_with_mnemonic (_("Sho_w preview in image window"));
-  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), jsvals.preview);
-  gtk_box_pack_start (GTK_BOX (vbox2), toggle, FALSE, FALSE, 0);
-  gtk_widget_show (toggle);
-
-  g_signal_connect (toggle, "toggled",
-                    G_CALLBACK (gimp_toggle_button_update),
-                    &jsvals.preview);
-  g_signal_connect (toggle, "toggled",
-                    G_CALLBACK (make_preview),
-                    NULL);
-
-  vbox2 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
-  gtk_box_pack_start (GTK_BOX (vbox), vbox2, FALSE, FALSE, 0);
-  gtk_widget_show (vbox2);
-
-  /* Save EXIF data */
-  pg.save_exif = toggle =
-    gtk_check_button_new_with_mnemonic (_("Save _Exif data"));
-  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), jsvals.save_exif);
-  gtk_box_pack_start (GTK_BOX (vbox2), toggle, FALSE, FALSE, 0);
-  gtk_widget_show (toggle);
-
-  g_signal_connect (toggle, "toggled",
-                    G_CALLBACK (gimp_toggle_button_update),
-                    &jsvals.save_exif);
-  g_signal_connect (toggle, "toggled",
-                    G_CALLBACK (make_preview),
-                    NULL);
-
-  /* Save XMP metadata */
-  pg.save_xmp = toggle =
-    gtk_check_button_new_with_mnemonic (_("Save _XMP data"));
-  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), jsvals.save_xmp);
-  gtk_box_pack_start (GTK_BOX (vbox2), toggle, FALSE, FALSE, 0);
-  gtk_widget_show (toggle);
-
-  g_signal_connect (toggle, "toggled",
-                    G_CALLBACK (gimp_toggle_button_update),
-                    &jsvals.save_xmp);
-  g_signal_connect (toggle, "toggled",
-                    G_CALLBACK (make_preview),
-                    NULL);
-
-  /* Save IPTC metadata */
-  pg.save_iptc = toggle =
-    gtk_check_button_new_with_mnemonic (_("Save _IPTC data"));
-  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), jsvals.save_iptc);
-  gtk_box_pack_start (GTK_BOX (vbox2), toggle, FALSE, FALSE, 0);
-  gtk_widget_show (toggle);
-
-  g_signal_connect (toggle, "toggled",
-                    G_CALLBACK (gimp_toggle_button_update),
-                    &jsvals.save_iptc);
-  g_signal_connect (toggle, "toggled",
-                    G_CALLBACK (make_preview),
-                    NULL);
-
-  /* Save thumbnail */
-  pg.save_thumbnail = toggle =
-    gtk_check_button_new_with_mnemonic (_("Save _thumbnail"));
-  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), jsvals.save_thumbnail);
-  gtk_box_pack_start (GTK_BOX (vbox2), toggle, FALSE, FALSE, 0);
-  gtk_widget_show (toggle);
-
-  g_signal_connect (toggle, "toggled",
-                    G_CALLBACK (gimp_toggle_button_update),
-                    &jsvals.save_thumbnail);
-  g_signal_connect (toggle, "toggled",
-                    G_CALLBACK (make_preview),
-                    NULL);
-
-  /* Save color profile */
-  pg.save_profile = toggle =
-    gtk_check_button_new_with_mnemonic (_("Save color _profile"));
-  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), jsvals.save_profile);
-  gtk_box_pack_start (GTK_BOX (vbox2), toggle, FALSE, FALSE, 0);
-  gtk_widget_show (toggle);
-
-  g_signal_connect (toggle, "toggled",
-                    G_CALLBACK (gimp_toggle_button_update),
-                    &jsvals.save_profile);
-  g_signal_connect (toggle, "toggled",
-                    G_CALLBACK (make_preview),
-                    NULL);
 
-  /* Comment */
-  frame = gimp_frame_new (_("Comment"));
-  gtk_box_pack_start (GTK_BOX (vbox), frame, TRUE, TRUE, 0);
-  gtk_widget_show (frame);
-
-  scrolled_window = gtk_scrolled_window_new (NULL, NULL);
-  gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_window),
-                                       GTK_SHADOW_IN);
-  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
-                                  GTK_POLICY_AUTOMATIC,
-                                  GTK_POLICY_AUTOMATIC);
-  gtk_widget_set_size_request (scrolled_window, 250, 50);
-  gtk_container_add (GTK_CONTAINER (frame), scrolled_window);
-  gtk_widget_show (scrolled_window);
-
-  pg.text_buffer = text_buffer = gtk_text_buffer_new (NULL);
-  if (image_comment)
-    gtk_text_buffer_set_text (text_buffer, image_comment, -1);
-
-  text_view = gtk_text_view_new_with_buffer (text_buffer);
-  gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (text_view), GTK_WRAP_WORD);
-
-  gtk_container_add (GTK_CONTAINER (scrolled_window), text_view);
-  gtk_widget_show (text_view);
-
-  g_object_unref (text_buffer);
-
-  /* Advanced expander */
-  text = g_strdup_printf ("<b>%s</b>", _("_Advanced Options"));
-  expander = gtk_expander_new_with_mnemonic (text);
-  gtk_expander_set_use_markup (GTK_EXPANDER (expander), TRUE);
-  g_free (text);
-
-  gtk_box_pack_start (GTK_BOX (vbox), expander, TRUE, TRUE, 0);
-  gtk_widget_show (expander);
-
-  vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
-  gtk_container_add (GTK_CONTAINER (expander), vbox);
-  gtk_widget_show (vbox);
-
-  frame = gimp_frame_new ("<expander>");
-  gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
-  gtk_widget_show (frame);
-
-  grid = gtk_grid_new ();
-  gtk_grid_set_column_spacing (GTK_GRID (grid), 6);
-  gtk_grid_set_row_spacing (GTK_GRID (grid), 6);
-  gtk_container_add (GTK_CONTAINER (frame), grid);
-  gtk_widget_show (grid);
-
-  pg.smoothing = gimp_scale_entry_new (_("S_moothing:"), jsvals.smoothing, 0.0, 1.0, 2);
-  gimp_help_set_help_data (pg.smoothing, NULL, "file-jpeg-save-smoothing");
-  g_signal_connect (pg.smoothing, "value-changed",
-                    G_CALLBACK (scale_entry_update),
-                    &jsvals.smoothing);
-  g_signal_connect (pg.smoothing, "value-changed",
-                    G_CALLBACK (make_preview),
-                    NULL);
-  gtk_grid_attach (GTK_GRID (grid), pg.smoothing, 2, 0, 4, 1);
-  gtk_widget_show (pg.smoothing);
-
-  restart_markers_label = gtk_label_new (_("Interval (MCU rows):"));
-  gtk_label_set_xalign (GTK_LABEL (restart_markers_label), 1.0);
-  gtk_grid_attach (GTK_GRID (grid), restart_markers_label, 4, 1, 1, 1);
-  gtk_widget_show (restart_markers_label);
-
-  pg.scale_data = gtk_adjustment_new (((jsvals.restart == 0) ?
-                                       DEFAULT_RESTART_MCU_ROWS : jsvals.restart),
-                                      1.0, 64.0, 1.0, 1.0, 0);
-  pg.restart = restart_markers_scale = spinbutton =
-    gimp_spin_button_new (pg.scale_data, 1.0, 0);
-  gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinbutton), TRUE);
-  gtk_grid_attach (GTK_GRID (grid), spinbutton, 5, 1, 1, 1);
-  gtk_widget_show (spinbutton);
-
-  pg.use_restart_markers = toggle =
-    gtk_check_button_new_with_mnemonic (_("Use _restart markers"));
-  gtk_grid_attach (GTK_GRID (grid), toggle, 2, 1, 2, 1);
-  gtk_widget_show (toggle);
-
-  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), jsvals.restart);
-
-  gtk_widget_set_sensitive (restart_markers_label, jsvals.restart);
-  gtk_widget_set_sensitive (restart_markers_scale, jsvals.restart);
-
-  g_signal_connect (pg.scale_data, "value-changed",
-                    G_CALLBACK (save_restart_update),
-                    toggle);
-  pg.handler_id_restart = g_signal_connect_swapped (toggle, "toggled",
-                            G_CALLBACK (save_restart_update),
-                            pg.scale_data);
-
-  row = 0;
-
-  /* Optimize */
-  pg.optimize = toggle = gtk_check_button_new_with_mnemonic (_("_Optimize"));
-  gtk_grid_attach (GTK_GRID (grid), toggle, 0, row, 1, 1);
-  gtk_widget_show (toggle);
-
-  g_signal_connect (toggle, "toggled",
-                    G_CALLBACK (gimp_toggle_button_update),
-                    &jsvals.optimize);
-  g_signal_connect (toggle, "toggled",
-                    G_CALLBACK (make_preview),
-                    NULL);
-
-  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), jsvals.optimize);
-
-  if (arithc_supported)
-    gtk_widget_set_sensitive (toggle, !jsvals.arithmetic_coding);
+#ifdef C_ARITH_CODING_SUPPORTED
+  gimp_procedure_dialog_fill_frame (GIMP_PROCEDURE_DIALOG (dialog),
+                                    "arithmetic-frame", "use-arithmetic-coding", TRUE,
+                                    "optimize");
+#endif
 
-  row++;
+  /* Restart marker. */
+  /* TODO: apparently when toggle is unchecked, we want to show the
+   * scale as 0.
+   */
+  gimp_procedure_dialog_fill_frame (GIMP_PROCEDURE_DIALOG (dialog),
+                                    "restart-frame", "use-restart", FALSE,
+                                    "restart");
+  if (restart == 0)
+    g_object_set (config,
+                  "restart",     DEFAULT_RESTART_MCU_ROWS,
+                  "use-restart", FALSE,
+                  NULL);
 
-  if (arithc_supported)
+  /* Subsampling */
+  store = gimp_int_store_new (_("4:4:4 (best quality)"),
+                              JPEG_SUBSAMPLING_1x1_1x1_1x1,
+                              _("4:2:2 horizontal (chroma halved)"),
+                              JPEG_SUBSAMPLING_2x1_1x1_1x1,
+                              _("4:2:2 vertical (chroma halved)"),
+                              JPEG_SUBSAMPLING_1x2_1x1_1x1,
+                              _("4:2:0 (chroma quartered)"),
+                              JPEG_SUBSAMPLING_2x2_1x1_1x1,
+                              NULL);
+  widget = gimp_procedure_dialog_get_int_combo (GIMP_PROCEDURE_DIALOG (dialog),
+                                               "sub-sampling", GIMP_INT_STORE (store));
+  widget = gimp_label_int_widget_get_widget (GIMP_LABEL_INT_WIDGET (widget));
+  g_object_unref (store);
+
+  if (! gimp_drawable_is_rgb (drawable))
     {
-      /* Arithmetic coding */
-      pg.arithmetic_coding = toggle = gtk_check_button_new_with_mnemonic
-        (_("Use arithmetic _coding"));
-      gtk_widget_set_tooltip_text
-        (toggle, _("Older software may have trouble opening "
-                   "arithmetic-coded images"));
-      gtk_grid_attach (GTK_GRID (grid), toggle, 0, row, 1, 1);
-      gtk_widget_show (toggle);
-
-      g_signal_connect (toggle, "toggled",
-                        G_CALLBACK (gimp_toggle_button_update),
-                        &jsvals.arithmetic_coding);
-      g_signal_connect (toggle, "toggled",
-                        G_CALLBACK (make_preview),
-                        NULL);
-      g_signal_connect (toggle, "toggled",
-                        G_CALLBACK (toggle_arithmetic_coding),
-                        pg.optimize);
-      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle),
-                                    jsvals.arithmetic_coding);
-
-      row++;
+      g_object_set (config, "sub-sampling", JPEG_SUBSAMPLING_1x1_1x1_1x1, NULL);
+      gtk_widget_set_sensitive (widget, FALSE);
     }
 
-  /* Progressive */
-  pg.progressive = toggle =
-    gtk_check_button_new_with_mnemonic (_("_Progressive"));
-  gtk_grid_attach (GTK_GRID (grid), toggle, 0, row, 1, 1);
-  gtk_widget_show (toggle);
-
-  g_signal_connect (toggle, "toggled",
-                    G_CALLBACK (gimp_toggle_button_update),
-                    &jsvals.progressive);
-  g_signal_connect (toggle, "toggled",
-                    G_CALLBACK (make_preview),
-                    NULL);
-
-  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle),
-                                jsvals.progressive);
-
-  row++;
-
-  /* Subsampling */
-  label = gtk_label_new_with_mnemonic (_("Su_bsampling:"));
-  gtk_label_set_xalign (GTK_LABEL (label), 0.0);
-  gtk_grid_attach (GTK_GRID (grid), label, 2, 2, 1, 1);
-  gtk_widget_show (label);
-
-  pg.subsmp =
-    combo = gimp_int_combo_box_new (_("4:4:4 (best quality)"),
-                                    JPEG_SUBSAMPLING_1x1_1x1_1x1,
-                                    _("4:2:2 horizontal (chroma halved)"),
-                                    JPEG_SUBSAMPLING_2x1_1x1_1x1,
-                                    _("4:2:2 vertical (chroma halved)"),
-                                    JPEG_SUBSAMPLING_1x2_1x1_1x1,
-                                    _("4:2:0 (chroma quartered)"),
-                                    JPEG_SUBSAMPLING_2x2_1x1_1x1,
-                                    NULL);
-  gtk_grid_attach (GTK_GRID (grid), combo, 3, 2, 3, 1);
-  gtk_widget_show (combo);
-
-  gtk_label_set_mnemonic_widget (GTK_LABEL (label), combo);
-
+  /* DCT method */
+  store = gimp_int_store_new (_("Fast Integer"),   1,
+                              _("Integer"),        0,
+                              _("Floating-Point"), 2,
+                              NULL);
+  gimp_procedure_dialog_get_int_combo (GIMP_PROCEDURE_DIALOG (dialog),
+                                               "dct", GIMP_INT_STORE (store));
+  g_object_unref (store);
+
+  gimp_procedure_dialog_get_label (GIMP_PROCEDURE_DIALOG (dialog),
+                                   "advanced-title", _("Advanced Options"));
+  widget = gimp_procedure_dialog_get_widget (GIMP_PROCEDURE_DIALOG (dialog),
+                                             "smoothing", GIMP_TYPE_SCALE_ENTRY);
+  gimp_help_set_help_data (widget, NULL, "file-jpeg-save-smoothing");
+
+  /* Add some logics for "Use original quality". */
   if (gimp_drawable_is_rgb (drawable))
     {
-      gimp_int_combo_box_connect (GIMP_INT_COMBO_BOX (combo),
-                                  jsvals.subsmp,
-                                  G_CALLBACK (subsampling_changed),
-                                  pg.smoothing, NULL);
-      g_signal_connect (pg.subsmp, "changed",
-                        G_CALLBACK (subsampling_changed2),
-                        pg.use_orig_quality);
-      g_signal_connect (pg.use_orig_quality, "toggled",
-                        G_CALLBACK (use_orig_qual_changed2),
-                        pg.subsmp);
+      g_signal_connect (config, "notify::sub-sampling",
+                        G_CALLBACK (subsampling_changed),
+                        widget);
+      subsampling_changed (config, NULL, widget);
+      g_signal_connect (config, "notify::use-original-quality",
+                        G_CALLBACK (use_orig_qual_changed_rgb),
+                        NULL);
     }
-  else
-    {
-      gimp_int_combo_box_set_active (GIMP_INT_COMBO_BOX (combo),
-                                     JPEG_SUBSAMPLING_1x1_1x1_1x1);
 
-      gtk_widget_set_sensitive (combo, FALSE);
-    }
+  gimp_procedure_dialog_fill_box (GIMP_PROCEDURE_DIALOG (dialog),
+                                  "advanced-options",
+                                  "smoothing",
+                                  "progressive",
+#ifdef C_ARITH_CODING_SUPPORTED
+                                  "arithmetic-frame",
+#else
+                                  "optimize",
+#endif
+                                  "restart-frame",
+                                  "sub-sampling",
+                                  "dct",
+                                  NULL);
+  gimp_procedure_dialog_fill_frame (GIMP_PROCEDURE_DIALOG (dialog),
+                                    "advanced-frame", "advanced-title", FALSE,
+                                    "advanced-options");
+
+  gimp_procedure_dialog_fill (GIMP_PROCEDURE_DIALOG (dialog),
+                              "quality", "use-original-quality",
+                              "preview-size", "show-preview",
+                              "advanced-frame",
+                              NULL);
 
+  gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
 
-  /* DCT method */
-  label = gtk_label_new_with_mnemonic (_("_DCT method:"));
-  gtk_label_set_xalign (GTK_LABEL (label), 0.0);
-  gtk_grid_attach (GTK_GRID (grid), label, 2, 3, 1, 1);
-  gtk_widget_show (label);
-
-  pg.dct = combo = gimp_int_combo_box_new (_("Fast Integer"),   1,
-                                           _("Integer"),        0,
-                                           _("Floating-Point"), 2,
-                                           NULL);
-  gimp_int_combo_box_set_active (GIMP_INT_COMBO_BOX (combo), jsvals.dct);
-  gtk_grid_attach (GTK_GRID (grid), combo, 3, 3, 3, 1);
-  gtk_widget_show (combo);
-
-  gtk_label_set_mnemonic_widget (GTK_LABEL (label), combo);
-
-  g_signal_connect (combo, "changed",
-                    G_CALLBACK (gimp_int_combo_box_get_active),
-                    &jsvals.dct);
-  g_signal_connect (combo, "changed",
+  /* Run make_preview() when various config are changed. */
+  g_signal_connect (config, "notify",
                     G_CALLBACK (make_preview),
                     NULL);
 
-  /* Load/Save defaults */
-  griddefaults = gtk_grid_new ();
-  gtk_container_set_border_width (GTK_CONTAINER (griddefaults), 12);
-  gtk_grid_set_column_spacing (GTK_GRID (griddefaults), 6);
-  gtk_box_pack_start (GTK_BOX (gimp_export_dialog_get_content_area (dialog)),
-                      griddefaults, FALSE, FALSE, 0);
-  gtk_widget_show (griddefaults);
-
-  button = gtk_button_new_with_mnemonic (_("_Load Defaults"));
-  gtk_grid_attach (GTK_GRID (griddefaults), button, 0, 1, 1, 1);
-  gtk_widget_show (button);
-
-  g_signal_connect_swapped (button, "clicked",
-                            G_CALLBACK (load_gui_defaults),
-                            &pg);
-
-  button = gtk_button_new_with_mnemonic (_("Sa_ve Defaults"));
-  gtk_grid_attach (GTK_GRID (griddefaults), button, 1, 1, 1, 1);
-  gtk_widget_show (button);
-
-  g_signal_connect_swapped (button, "clicked",
-                            G_CALLBACK (save_defaults),
-                            &pg);
-
-  gtk_widget_show (dialog);
-
-  make_preview ();
-
-  pg.run = FALSE;
+  make_preview (config);
 
-  gtk_main ();
+  run = gimp_procedure_dialog_run (GIMP_PROCEDURE_DIALOG (dialog));
+  gtk_widget_destroy (dialog);
 
   destroy_preview ();
 
-  return pg.run;
-}
-
-static void
-save_dialog_response (GtkWidget *widget,
-                      gint       response_id,
-                      gpointer   data)
-{
-  JpegSaveGui *pg = data;
-  GtkTextIter  start_iter;
-  GtkTextIter  end_iter;
-
-  switch (response_id)
-    {
-    case GTK_RESPONSE_OK:
-      gtk_text_buffer_get_bounds (pg->text_buffer, &start_iter, &end_iter);
-      image_comment = gtk_text_buffer_get_text (pg->text_buffer,
-                                                &start_iter, &end_iter, FALSE);
-      pg->run = TRUE;
-      /* fallthrough */
-
-    default:
-      gtk_widget_destroy (widget);
-      break;
-    }
-}
-
-void
-load_defaults (void)
-{
-  jsvals.quality          = DEFAULT_IJG_QUALITY;
-  jsvals.smoothing        = DEFAULT_SMOOTHING;
-  jsvals.optimize         = DEFAULT_OPTIMIZE;
-  jsvals.arithmetic_coding= DEFAULT_ARITHMETIC_CODING;
-  jsvals.progressive      = DEFAULT_PROGRESSIVE;
-  jsvals.baseline         = DEFAULT_BASELINE;
-  jsvals.subsmp           = DEFAULT_SUBSMP;
-  jsvals.restart          = DEFAULT_RESTART;
-  jsvals.dct              = DEFAULT_DCT;
-  jsvals.preview          = DEFAULT_PREVIEW;
-  jsvals.save_exif        = DEFAULT_EXIF;
-  jsvals.save_xmp         = DEFAULT_XMP;
-  jsvals.save_iptc        = DEFAULT_IPTC;
-  jsvals.save_thumbnail   = DEFAULT_THUMBNAIL;
-  jsvals.save_profile     = DEFAULT_PROFILE;
-  jsvals.use_orig_quality = DEFAULT_USE_ORIG_QUALITY;
-}
-
-void
-load_parasite (void)
-{
-  GimpParasite *parasite;
-  gchar        *def_str;
-  JpegSaveVals  tmpvals;
-  gint          num_fields;
-  gint          subsampling;
-
-  parasite = gimp_get_parasite (JPEG_DEFAULTS_PARASITE);
-
-  if (! parasite)
-    return;
-
-  def_str = g_strndup (gimp_parasite_data (parasite),
-                       gimp_parasite_data_size (parasite));
-
-  gimp_parasite_free (parasite);
-
-  /* Initialize tmpvals in case fewer fields exist in the parasite
-     (e.g., when importing from a previous version of GIMP). */
-  memcpy(&tmpvals, &jsvals, sizeof jsvals);
-
-  num_fields = sscanf (def_str,
-                       "%lf %lf %d %d %d %d %d %d %d %d %d %d %d %d %d %d",
-                       &tmpvals.quality,
-                       &tmpvals.smoothing,
-                       &tmpvals.optimize,
-                       &tmpvals.progressive,
-                       &subsampling,
-                       &tmpvals.baseline,
-                       &tmpvals.restart,
-                       &tmpvals.dct,
-                       &tmpvals.preview,
-                       &tmpvals.save_exif,
-                       &tmpvals.save_thumbnail,
-                       &tmpvals.save_xmp,
-                       &tmpvals.use_orig_quality,
-                       &tmpvals.save_iptc,
-                       &tmpvals.arithmetic_coding,
-                       &tmpvals.save_profile);
-
-  tmpvals.subsmp = subsampling;
-
-  if (num_fields == 13 || num_fields == 15 || num_fields == 16)
-    {
-      memcpy (&jsvals, &tmpvals, sizeof (tmpvals));
-    }
-
-  g_free (def_str);
+  return run;
 }
 
 static void
-save_defaults (void)
+quality_changed (GimpProcedureConfig *config)
 {
-  GimpParasite *parasite;
-  gchar        *def_str;
-
-  def_str = g_strdup_printf ("%lf %lf %d %d %d %d %d %d %d %d %d %d %d %d %d %d",
-                             jsvals.quality,
-                             jsvals.smoothing,
-                             jsvals.optimize,
-                             jsvals.progressive,
-                             (gint) jsvals.subsmp,
-                             jsvals.baseline,
-                             jsvals.restart,
-                             jsvals.dct,
-                             jsvals.preview,
-                             jsvals.save_exif,
-                             jsvals.save_thumbnail,
-                             jsvals.save_xmp,
-                             jsvals.use_orig_quality,
-                             jsvals.save_iptc,
-                             jsvals.arithmetic_coding,
-                             jsvals.save_profile);
-  parasite = gimp_parasite_new (JPEG_DEFAULTS_PARASITE,
-                                GIMP_PARASITE_PERSISTENT,
-                                strlen (def_str), def_str);
-
-  gimp_attach_parasite (parasite);
-
-  gimp_parasite_free (parasite);
-  g_free (def_str);
+  gboolean use_orig_quality;
+  gdouble  quality;
+  gint     orig_quality;
+
+  g_object_get (config,
+                "use-original-quality",  &use_orig_quality,
+                "original-quality",      &orig_quality,
+                "quality",               &quality,
+                NULL);
+
+  if (use_orig_quality && (gint) (quality * 100.0) != orig_quality)
+    g_object_set (config, "use-original-quality", FALSE, NULL);
 }
 
 static void
-load_gui_defaults (JpegSaveGui *pg)
+subsampling_changed (GimpProcedureConfig *config,
+                     const GParamSpec    *pspec,
+                     GtkWidget           *smoothing_scale)
 {
-  GtkAdjustment *restart_markers;
-
-  load_defaults ();
-  load_parasite ();
-
-#define SET_ACTIVE_BTTN(field) \
-  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (pg->field), jsvals.field)
-
-  SET_ACTIVE_BTTN (optimize);
-  SET_ACTIVE_BTTN (progressive);
-  SET_ACTIVE_BTTN (use_orig_quality);
-  SET_ACTIVE_BTTN (preview);
-  SET_ACTIVE_BTTN (save_exif);
-  SET_ACTIVE_BTTN (save_xmp);
-  SET_ACTIVE_BTTN (save_iptc);
-  SET_ACTIVE_BTTN (save_thumbnail);
-  SET_ACTIVE_BTTN (save_profile);
-
-#undef SET_ACTIVE_BTTN
-
-/*spin button stuff*/
-  g_signal_handler_block (pg->use_restart_markers, pg->handler_id_restart);
-  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (pg->use_restart_markers),
-                                jsvals.restart);
-  restart_markers = pg->scale_data;
-  gtk_adjustment_set_value (restart_markers, jsvals.restart);
-  g_signal_handler_unblock (pg->use_restart_markers, pg->handler_id_restart);
-
-  gimp_label_spin_set_value (GIMP_LABEL_SPIN (pg->smoothing), jsvals.smoothing);
-
-  /* Don't override quality and subsampling setting if we already set it from original */
-  if (!jsvals.use_orig_quality)
-    {
-      gimp_label_spin_set_value (GIMP_LABEL_SPIN (pg->quality), jsvals.quality);
-
-      if (gimp_drawable_is_rgb (drawable_global))
-        {
-          gimp_int_combo_box_set_active (GIMP_INT_COMBO_BOX (pg->subsmp),
-                                         jsvals.subsmp);
-        }
-    }
+  gboolean use_orig_quality;
+  gint     orig_subsmp;
+  gint     subsmp;
 
-  gimp_int_combo_box_set_active (GIMP_INT_COMBO_BOX (pg->dct),
-                                 jsvals.dct);
-}
+  g_object_get (config,
+                "use-original-quality",  &use_orig_quality,
+                "original-sub-sampling", &orig_subsmp,
+                "sub-sampling",          &subsmp,
+                NULL);
 
-static void
-scale_entry_update (GimpLabelSpin *entry,
-                    gdouble       *value)
-{
-  *value = gimp_label_spin_get_value (entry);
-}
-
-static void
-save_restart_update (GtkAdjustment *adjustment,
-                     GtkWidget     *toggle)
-{
-  if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (toggle)))
-    jsvals.restart = gtk_adjustment_get_value (adjustment);
-  else
-    jsvals.restart = 0;
-
-  gtk_widget_set_sensitive (restart_markers_label, jsvals.restart);
-  gtk_widget_set_sensitive (restart_markers_scale, jsvals.restart);
+  /*  smoothing is not supported with nonstandard sampling ratios  */
+  gtk_widget_set_sensitive (smoothing_scale,
+                            subsmp != JPEG_SUBSAMPLING_2x1_1x1_1x1 &&
+                            subsmp != JPEG_SUBSAMPLING_1x2_1x1_1x1);
 
-  make_preview ();
+  if (use_orig_quality && orig_subsmp != subsmp)
+    g_object_set (config, "use-original-quality", FALSE, NULL);
 }
 
 static void
-subsampling_changed (GtkWidget *combo,
-                     GtkWidget *entry)
+use_orig_qual_changed (GimpProcedureConfig *config)
 {
-  gint value;
-
-  gimp_int_combo_box_get_active (GIMP_INT_COMBO_BOX (combo), &value);
+  gboolean use_orig_quality;
+  gint     orig_quality;
 
-  jsvals.subsmp = value;
+  g_object_get (config,
+                "use-original-quality", &use_orig_quality,
+                "original-quality",     &orig_quality,
+                NULL);
 
-  /*  smoothing is not supported with nonstandard sampling ratios  */
-  gtk_widget_set_sensitive (entry,
-                            jsvals.subsmp != JPEG_SUBSAMPLING_2x1_1x1_1x1 &&
-                            jsvals.subsmp != JPEG_SUBSAMPLING_1x2_1x1_1x1);
-
-  make_preview ();
-}
-
-static void
-quality_changed (GimpScaleEntry *scale_entry,
-                 GtkWidget      *toggle)
-{
-  if (jsvals.use_orig_quality)
+  if (use_orig_quality && orig_quality > 0)
     {
-      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), FALSE);
+      g_signal_handlers_block_by_func (config, quality_changed, NULL);
+      g_object_set (config, "quality", orig_quality / 100.0, NULL);
+      g_signal_handlers_unblock_by_func (config, quality_changed, NULL);
     }
 }
 
 static void
-subsampling_changed2 (GtkWidget *combo,
-                      GtkWidget *toggle)
+use_orig_qual_changed_rgb (GimpProcedureConfig *config)
 {
-  if (jsvals.use_orig_quality && orig_subsmp != jsvals.subsmp)
-    {
-      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), FALSE);
-    }
-}
+  gboolean use_orig_quality;
+  gint     orig_quality;
+  gint     orig_subsmp;
 
-static void
-use_orig_qual_changed (GtkWidget     *toggle,
-                       GimpLabelSpin *scale_entry)
-{
-  if (jsvals.use_orig_quality && orig_quality > 0)
-    {
-      g_signal_handlers_block_by_func (scale_entry, quality_changed, toggle);
-      gimp_label_spin_set_value (scale_entry, orig_quality);
-      g_signal_handlers_unblock_by_func (scale_entry, quality_changed, toggle);
-    }
-}
+  g_object_get (config,
+                "use-original-quality",  &use_orig_quality,
+                "original-sub-sampling", &orig_subsmp,
+                "original-quality",      &orig_quality,
+                NULL);
 
-static void
-use_orig_qual_changed2 (GtkWidget *toggle,
-                        GtkWidget *combo)
-{
   /* the test is (orig_quality > 0), not (orig_subsmp > 0) - this is normal */
-  if (jsvals.use_orig_quality && orig_quality > 0)
-    {
-      gimp_int_combo_box_set_active (GIMP_INT_COMBO_BOX (combo), orig_subsmp);
-    }
+  if (use_orig_quality && orig_quality > 0)
+    g_object_set (config, "sub-sampling", orig_subsmp, NULL);
 }
diff --git a/plug-ins/file-jpeg/jpeg-save.h b/plug-ins/file-jpeg/jpeg-save.h
index c5fd590ffe..14acc47864 100644
--- a/plug-ins/file-jpeg/jpeg-save.h
+++ b/plug-ins/file-jpeg/jpeg-save.h
@@ -18,40 +18,20 @@
 #ifndef __JPEG_SAVE_H__
 #define __JPEG_SAVE_H__
 
-typedef struct
-{
-  gdouble          quality;
-  gdouble          smoothing;
-  gboolean         optimize;
-  gboolean         arithmetic_coding;
-  gboolean         progressive;
-  gboolean         baseline;
-  JpegSubsampling  subsmp;
-  gint             restart;
-  gint             dct;
-  gboolean         preview;
-  gboolean         save_exif;
-  gboolean         save_xmp;
-  gboolean         save_iptc;
-  gboolean         save_thumbnail;
-  gboolean         save_profile;
-  gboolean         use_orig_quality;
-} JpegSaveVals;
-
-extern JpegSaveVals     jsvals;
 
 extern GimpImage       *orig_image_global;
 extern GimpDrawable    *drawable_global;
 
 
-gboolean    save_image         (GFile         *file,
-                                GimpImage     *image,
-                                GimpDrawable  *drawable,
-                                GimpImage     *orig_image,
-                                gboolean       preview,
-                                GError       **error);
-gboolean    save_dialog        (GimpDrawable  *drawable);
-void        load_defaults      (void);
-void        load_parasite      (void);
+gboolean    save_image         (GFile                *file,
+                                GimpProcedureConfig *config,
+                                GimpImage            *image,
+                                GimpDrawable         *drawable,
+                                GimpImage            *orig_image,
+                                gboolean              preview,
+                                GError              **error);
+gboolean    save_dialog        (GimpProcedure        *procedure,
+                                GimpProcedureConfig  *config,
+                                GimpDrawable         *drawable);
 
 #endif /* __JPEG_SAVE_H__ */
diff --git a/plug-ins/file-jpeg/jpeg-settings.c b/plug-ins/file-jpeg/jpeg-settings.c
index ed80db4f81..dbd1264db8 100644
--- a/plug-ins/file-jpeg/jpeg-settings.c
+++ b/plug-ins/file-jpeg/jpeg-settings.c
@@ -208,7 +208,7 @@ jpeg_restore_original_settings (GimpImage       *image,
                 *num_quant_tables = -1;
 
               /* the current plug-in can only use subsampling for YCbCr (3) */
-              *subsmp = -1;
+              *subsmp = JPEG_SUBSAMPLING_1x1_1x1_1x1;
               if (num_components == 3)
                 {
                   h[0] = *src++;
@@ -240,7 +240,7 @@ jpeg_restore_original_settings (GimpImage       *image,
     }
 
   *quality = -1;
-  *subsmp = -1;
+  *subsmp = JPEG_SUBSAMPLING_1x1_1x1_1x1;
   *num_quant_tables = 0;
 
   return FALSE;
diff --git a/plug-ins/file-jpeg/jpeg.c b/plug-ins/file-jpeg/jpeg.c
index bcae891e88..b697d3bbc6 100644
--- a/plug-ins/file-jpeg/jpeg.c
+++ b/plug-ins/file-jpeg/jpeg.c
@@ -84,14 +84,9 @@ GIMP_MAIN (JPEG_TYPE)
 
 
 gboolean         undo_touched      = FALSE;
-gchar           *image_comment     = NULL;
 GimpDisplay     *display           = NULL;
-JpegSaveVals     jsvals            = { 0, };
 GimpImage       *orig_image_global = NULL;
 GimpDrawable    *drawable_global   = NULL;
-gint             orig_quality      = 0;
-JpegSubsampling  orig_subsmp       = JPEG_SUBSAMPLING_2x2_1x1_1x1;;
-gint             num_quant_tables  = 0;
 
 
 static void
@@ -201,13 +196,13 @@ jpeg_create_procedure (GimpPlugIn  *plug_in,
        */
       GIMP_PROC_ARG_DOUBLE (procedure, "quality",
                             "Quality",
-                            "Quality of saved image",
+                            "Quality of exported image",
                             0.0, 1.0, 0.9,
                             G_PARAM_READWRITE);
 
       GIMP_PROC_ARG_DOUBLE (procedure, "smoothing",
-                            "Smoothing",
-                            "Smoothing factor for saved image",
+                            "S_moothing",
+                            "Smoothing factor for exported image",
                             0.0, 1.0, 0.0,
                             G_PARAM_READWRITE);
 
@@ -218,19 +213,13 @@ jpeg_create_procedure (GimpPlugIn  *plug_in,
                              G_PARAM_READWRITE);
 
       GIMP_PROC_ARG_BOOLEAN (procedure, "progressive",
-                             "Progressive",
+                             "_Progressive",
                              "Create progressive JPEG images",
                              TRUE,
                              G_PARAM_READWRITE);
 
-      GIMP_PROC_ARG_STRING (procedure, "comment",
-                            "Comment",
-                            "Image comment",
-                            gimp_get_default_comment (),
-                            G_PARAM_READWRITE);
-
       GIMP_PROC_ARG_INT (procedure, "sub-sampling",
-                         "Sub-sampling",
+                         _("Su_bsampling"),
                          "Sub-sampling type { 0 == 4:2:0 (chroma quartered), "
                          "1 == 4:2:2 Horizontal (chroma halved), "
                          "2 == 4:4:4 (best quality), "
@@ -248,18 +237,66 @@ jpeg_create_procedure (GimpPlugIn  *plug_in,
                              G_PARAM_READWRITE);
 
       GIMP_PROC_ARG_INT (procedure, "restart",
-                         "Restart",
+                         _("Interval (MCU rows):"),
                          "Interval of restart markers "
                          "(in MCU rows, 0 = no restart markers)",
                          0, 64, 0,
                          G_PARAM_READWRITE);
 
       GIMP_PROC_ARG_INT (procedure, "dct",
-                         "DCT",
+                         _("_DCT method"),
                          "DCT method to use { INTEGER (0), FIXED (1), "
                          "FLOAT (2) }",
                          0, 2, 0,
                          G_PARAM_READWRITE);
+
+      /* Some auxiliary arguments mostly for interactive usage. */
+
+      GIMP_PROC_AUX_ARG_BOOLEAN (procedure, "use-original-quality",
+                                 "_Use quality settings from original image",
+                                 "If the original image was loaded from a JPEG "
+                                 "file using non-standard quality settings "
+                                 "(quantization tables), enable this option to "
+                                 "get almost the same quality and file size.",
+                                 FALSE,
+                                 G_PARAM_READWRITE);
+      GIMP_PROC_AUX_ARG_INT (procedure, "original-quality",
+                             NULL, NULL,
+                             -1, 100, -1,
+                             G_PARAM_READWRITE);
+      GIMP_PROC_AUX_ARG_INT (procedure, "original-sub-sampling",
+                             NULL, NULL,
+                             JPEG_SUBSAMPLING_2x2_1x1_1x1,
+                             JPEG_SUBSAMPLING_1x2_1x1_1x1,
+                             JPEG_SUBSAMPLING_2x2_1x1_1x1,
+                             G_PARAM_READWRITE);
+      GIMP_PROC_AUX_ARG_INT (procedure, "original-num-quant-tables",
+                             NULL, NULL,
+                             -1, 4, -1,
+                             G_PARAM_READWRITE);
+
+      GIMP_PROC_AUX_ARG_BOOLEAN (procedure, "show-preview",
+                                 "Sho_w preview in image window",
+                                 "Creates a temporary layer with an export preview",
+                                 FALSE,
+                                 G_PARAM_READWRITE);
+      GIMP_PROC_AUX_ARG_BOOLEAN (procedure, "use-arithmetic-coding",
+                                 "Use arithmetic _coding",
+                                 _("Older software may have trouble opening "
+                                   "arithmetic-coded images"),
+                                 FALSE,
+                                 G_PARAM_READWRITE);
+      GIMP_PROC_AUX_ARG_BOOLEAN (procedure, "use-restart",
+                                 _("Use _restart markers"),
+                                 NULL, FALSE,
+                                 G_PARAM_READWRITE);
+
+      gimp_save_procedure_set_support_exif      (GIMP_SAVE_PROCEDURE (procedure), TRUE);
+      gimp_save_procedure_set_support_iptc      (GIMP_SAVE_PROCEDURE (procedure), TRUE);
+      gimp_save_procedure_set_support_xmp       (GIMP_SAVE_PROCEDURE (procedure), TRUE);
+      gimp_save_procedure_set_support_profile   (GIMP_SAVE_PROCEDURE (procedure), TRUE);
+      gimp_save_procedure_set_support_thumbnail (GIMP_SAVE_PROCEDURE (procedure), TRUE);
+      gimp_save_procedure_set_support_comment   (GIMP_SAVE_PROCEDURE (procedure), TRUE);
     }
 
   return procedure;
@@ -385,16 +422,22 @@ jpeg_save (GimpProcedure        *procedure,
            gpointer              run_data)
 {
   GimpPDBStatusType      status = GIMP_PDB_SUCCESS;
-  GimpParasite          *parasite;
+  GimpProcedureConfig   *config;
   GimpMetadata          *metadata;
-  GimpMetadataSaveFlags  metadata_flags;
   GimpImage             *orig_image;
   GimpExportReturn       export = GIMP_EXPORT_CANCEL;
   GError                *error  = NULL;
 
+  gint                   orig_num_quant_tables = -1;
+  gint                   orig_quality          = -1;
+  JpegSubsampling        orig_subsmp           = JPEG_SUBSAMPLING_2x2_1x1_1x1;
+
   INIT_I18N ();
   gegl_init (NULL, NULL);
 
+  config = gimp_procedure_create_config (procedure);
+  metadata = gimp_procedure_config_begin_export (config, image, run_mode,
+                                                 args, "image/jpeg");
   preview_image = NULL;
   preview_layer = NULL;
 
@@ -453,118 +496,77 @@ jpeg_save (GimpProcedure        *procedure,
                                                error);
     }
 
-  /* Initialize with hardcoded defaults */
-  load_defaults ();
-
-  /* Override the defaults with preferences. */
-  metadata = gimp_image_metadata_save_prepare (orig_image,
-                                               "image/jpeg",
-                                               &metadata_flags);
-  jsvals.save_exif      = (metadata_flags & GIMP_METADATA_SAVE_EXIF) != 0;
-  jsvals.save_xmp       = (metadata_flags & GIMP_METADATA_SAVE_XMP) != 0;
-  jsvals.save_iptc      = (metadata_flags & GIMP_METADATA_SAVE_IPTC) != 0;
-  jsvals.save_thumbnail = (metadata_flags & GIMP_METADATA_SAVE_THUMBNAIL) != 0;
-  jsvals.save_profile   = (metadata_flags & GIMP_METADATA_SAVE_COLOR_PROFILE) != 0;
-
-  parasite = gimp_image_get_parasite (orig_image, "gimp-comment");
-  if (parasite)
-    {
-      image_comment = g_strndup (gimp_parasite_data (parasite),
-                                 gimp_parasite_data_size (parasite));
-      gimp_parasite_free (parasite);
-    }
-
   /* Override preferences from JPG export defaults (if saved). */
-  load_parasite ();
 
   switch (run_mode)
     {
     case GIMP_RUN_NONINTERACTIVE:
-      g_free (image_comment);
-
-      jsvals.quality     = GIMP_VALUES_GET_DOUBLE  (args, 0) * 100.0;
-      jsvals.smoothing   = GIMP_VALUES_GET_DOUBLE  (args, 1);
-      jsvals.optimize    = GIMP_VALUES_GET_BOOLEAN (args, 2);
-      jsvals.progressive = GIMP_VALUES_GET_BOOLEAN (args, 3);
-      image_comment      = GIMP_VALUES_DUP_STRING  (args, 4);
-      jsvals.subsmp      = GIMP_VALUES_GET_DOUBLE  (args, 5);
-      jsvals.baseline    = GIMP_VALUES_GET_DOUBLE  (args, 6);
-      jsvals.restart     = GIMP_VALUES_GET_DOUBLE  (args, 7);
-      jsvals.dct         = GIMP_VALUES_GET_DOUBLE  (args, 8);
-      jsvals.preview     = FALSE;
+      g_object_set (config, "show-preview", FALSE, NULL);
       break;
 
     case GIMP_RUN_INTERACTIVE:
     case GIMP_RUN_WITH_LAST_VALS:
-      /* restore the values found when loading the file (if available) */
-      jpeg_restore_original_settings (orig_image,
-                                      &orig_quality,
-                                      &orig_subsmp,
-                                      &num_quant_tables);
-
-      /* load up the previously used values (if file was saved once) */
-      parasite = gimp_image_get_parasite (orig_image,
-                                          "jpeg-save-options");
-      if (parasite)
         {
-          const JpegSaveVals *save_vals = gimp_parasite_data (parasite);
-
-          jsvals.quality          = save_vals->quality;
-          jsvals.smoothing        = save_vals->smoothing;
-          jsvals.optimize         = save_vals->optimize;
-          jsvals.progressive      = save_vals->progressive;
-          jsvals.baseline         = save_vals->baseline;
-          jsvals.subsmp           = save_vals->subsmp;
-          jsvals.restart          = save_vals->restart;
-          jsvals.dct              = save_vals->dct;
-          jsvals.preview          = save_vals->preview;
-          jsvals.save_exif        = save_vals->save_exif;
-          jsvals.save_thumbnail   = save_vals->save_thumbnail;
-          jsvals.save_xmp         = save_vals->save_xmp;
-          jsvals.save_iptc        = save_vals->save_iptc;
-          jsvals.use_orig_quality = save_vals->use_orig_quality;
-
-          gimp_parasite_free (parasite);
-        }
-      else
-        {
-          /* We are called with GIMP_RUN_WITH_LAST_VALS but this image
-           * doesn't have a "jpeg-save-options" parasite. It's better
-           * to prompt the user with a dialog now so that she has
-           * control over the JPEG encoding parameters.
-           */
-          run_mode = GIMP_RUN_INTERACTIVE;
+          /* restore the values found when loading the file (if available) */
+          gdouble dquality;
+          gint    quality;
+          gint    subsmp;
+
+          jpeg_restore_original_settings (orig_image,
+                                          &orig_quality,
+                                          &orig_subsmp,
+                                          &orig_num_quant_tables);
+
+          g_object_get (config,
+                        "quality",      &dquality,
+                        "sub-sampling", &subsmp,
+                        NULL);
+
+          quality = (gint) (dquality * 100.0);
 
           /* If this image was loaded from a JPEG file and has not
            * been saved yet, try to use some of the settings from the
            * original file if they are better than the default values.
            */
-          if (orig_quality > jsvals.quality)
+          if (orig_quality > quality)
             {
-              jsvals.quality = orig_quality;
+              quality = orig_quality;
+              dquality = (gdouble) quality / 100.0;
+              g_object_set (config, "quality", dquality, NULL);
             }
 
-          /* Skip changing subsampling to original if we already have
-           * best setting or if original have worst setting
-           */
-          if (!(jsvals.subsmp == JPEG_SUBSAMPLING_1x1_1x1_1x1 ||
-                orig_subsmp == JPEG_SUBSAMPLING_2x2_1x1_1x1))
+          if (orig_quality > 0)
             {
-              jsvals.subsmp = orig_subsmp;
-            }
+              /* Skip changing subsampling to original if we already have
+               * best setting or if original have worst setting
+               */
+              if (!(subsmp == JPEG_SUBSAMPLING_1x1_1x1_1x1 ||
+                    orig_subsmp == JPEG_SUBSAMPLING_2x2_1x1_1x1))
+                {
+                  subsmp = orig_subsmp;
+                  g_object_set (config, "sub-sampling", orig_subsmp, NULL);
+                }
 
-          if (orig_quality == jsvals.quality &&
-              orig_subsmp == jsvals.subsmp)
-            {
-              jsvals.use_orig_quality = TRUE;
+              if (orig_quality == quality && orig_subsmp == subsmp)
+                {
+                  g_object_set (config, "use-original-quality", TRUE, NULL);
+                }
             }
         }
       break;
     }
+  g_object_set (config,
+                "original-sub-sampling",     orig_subsmp,
+                "original-quality",          orig_quality,
+                "original-num-quant-tables", orig_num_quant_tables,
+                NULL);
 
   if (run_mode == GIMP_RUN_INTERACTIVE)
     {
-      if (jsvals.preview)
+      gboolean show_preview = FALSE;
+
+      g_object_get (config, "show-preview", &show_preview, NULL);
+      if (show_preview)
         {
           /* we freeze undo saving so that we can avoid sucking up
            * tile cache with our unneeded preview steps. */
@@ -579,7 +581,7 @@ jpeg_save (GimpProcedure        *procedure,
       drawable_global   = drawables[0];
 
       /*  First acquire information with a dialog  */
-      if (! save_dialog (drawables[0]))
+      if (! save_dialog (procedure, config, drawables[0]))
         {
           status = GIMP_PDB_CANCEL;
         }
@@ -596,7 +598,8 @@ jpeg_save (GimpProcedure        *procedure,
 
   if (status == GIMP_PDB_SUCCESS)
     {
-      if (! save_image (file, image, drawables[0], orig_image, FALSE,
+      if (! save_image (file, config,
+                        image, drawables[0], orig_image, FALSE,
                         &error))
         {
           status = GIMP_PDB_EXECUTION_ERROR;
@@ -618,78 +621,12 @@ jpeg_save (GimpProcedure        *procedure,
 
   if (status == GIMP_PDB_SUCCESS)
     {
-      /* pw - now we need to change the defaults to be whatever was
-       * used to save this image.  Dump the old parasites and add new
-       * ones.
-       */
-
-      gimp_image_detach_parasite (orig_image, "gimp-comment");
-      if (image_comment && strlen (image_comment))
-        {
-          parasite = gimp_parasite_new ("gimp-comment",
-                                        GIMP_PARASITE_PERSISTENT,
-                                        strlen (image_comment) + 1,
-                                        image_comment);
-          gimp_image_attach_parasite (orig_image, parasite);
-          gimp_parasite_free (parasite);
-        }
-
-      parasite = gimp_parasite_new ("jpeg-save-options",
-                                    0, sizeof (jsvals), &jsvals);
-      gimp_image_attach_parasite (orig_image, parasite);
-      gimp_parasite_free (parasite);
-
-      /* write metadata */
-
       if (metadata)
-        {
-          gimp_metadata_set_bits_per_sample (metadata, 8);
-
-          if (jsvals.save_exif)
-            metadata_flags |= GIMP_METADATA_SAVE_EXIF;
-          else
-            metadata_flags &= ~GIMP_METADATA_SAVE_EXIF;
-
-          if (jsvals.save_xmp)
-            metadata_flags |= GIMP_METADATA_SAVE_XMP;
-          else
-            metadata_flags &= ~GIMP_METADATA_SAVE_XMP;
-
-          if (jsvals.save_iptc)
-            metadata_flags |= GIMP_METADATA_SAVE_IPTC;
-          else
-            metadata_flags &= ~GIMP_METADATA_SAVE_IPTC;
-
-          if (jsvals.save_thumbnail)
-            metadata_flags |= GIMP_METADATA_SAVE_THUMBNAIL;
-          else
-            metadata_flags &= ~GIMP_METADATA_SAVE_THUMBNAIL;
-
-          if (jsvals.save_profile)
-            metadata_flags |= GIMP_METADATA_SAVE_COLOR_PROFILE;
-          else
-            metadata_flags &= ~GIMP_METADATA_SAVE_COLOR_PROFILE;
-
-          if (! gimp_image_metadata_save_finish (orig_image,
-                                                 "image/jpeg",
-                                                 metadata, metadata_flags,
-                                                 file, &error))
-            {
-              if (error)
-                {
-                  /* Even though a failure to write metadata is not enough
-                     reason to say we failed to save the image, we should
-                     still notify the user about the problem. */
-                  g_message ("%s: saving metadata failed: %s",
-                             G_STRFUNC, error->message);
-                  g_error_free (error);
-                }
-            }
-        }
+        gimp_metadata_set_bits_per_sample (metadata, 8);
     }
 
-  if (metadata)
-    g_object_unref (metadata);
+  gimp_procedure_config_end_export (config, image, file, status);
+  g_object_unref (config);
 
   return gimp_procedure_new_return_values (procedure, status, error);
 }
diff --git a/plug-ins/file-jpeg/jpeg.h b/plug-ins/file-jpeg/jpeg.h
index ca0710c948..4b8a81d622 100644
--- a/plug-ins/file-jpeg/jpeg.h
+++ b/plug-ins/file-jpeg/jpeg.h
@@ -56,10 +56,6 @@ extern GimpLayer *      preview_layer;
 extern gboolean         undo_touched;
 extern gboolean         load_interactive;
 extern GimpDisplay     *display;
-extern gchar           *image_comment;
-extern gint             orig_quality;
-extern JpegSubsampling  orig_subsmp;
-extern gint             num_quant_tables;
 
 
 void      destroy_preview               (void);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]