static void make_preview (void) { destroy_preview (); if (jsvals.preview) { gchar *tn = gimp_temp_name ("jpeg"); if (! undo_touched) { /* we freeze undo saving so that we can avoid sucking up * tile cache with our unneeded preview steps. */ gimp_image_undo_freeze (preview_image_ID); undo_touched = TRUE; } save_image (tn, preview_image_ID, drawable_ID_global, orig_image_ID_global, TRUE, NULL); if (display_ID == -1) display_ID = gimp_display_new (preview_image_ID); } else { gtk_label_set_text (GTK_LABEL (preview_size), _("File size: unknown")); gimp_displays_flush (); } }
gint32 load_image (const gchar *filename, GimpRunMode runmode, gboolean preview, gboolean *resolution_loaded, GError **error) { gint32 volatile image_ID; gint32 layer_ID; struct jpeg_decompress_struct cinfo; struct my_error_mgr jerr; jpeg_saved_marker_ptr marker; FILE *infile; guchar *buf; guchar **rowbuf; GimpImageBaseType image_type; GimpImageType layer_type; GeglBuffer *buffer = NULL; const Babl *format; gint tile_height; gint scanlines; gint i, start, end; cmsHTRANSFORM cmyk_transform = NULL; /* We set up the normal JPEG error routines. */ cinfo.err = jpeg_std_error (&jerr.pub); jerr.pub.error_exit = my_error_exit; if (!preview) { jerr.pub.output_message = my_output_message; gimp_progress_init_printf (_("Opening '%s'"), gimp_filename_to_utf8 (filename)); } if ((infile = g_fopen (filename, "rb")) == NULL) { g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errno), _("Could not open '%s' for reading: %s"), gimp_filename_to_utf8 (filename), g_strerror (errno)); return -1; } image_ID = -1; /* Establish the setjmp return context for my_error_exit to use. */ if (setjmp (jerr.setjmp_buffer)) { /* If we get here, the JPEG code has signaled an error. * We need to clean up the JPEG object, close the input file, and return. */ jpeg_destroy_decompress (&cinfo); if (infile) fclose (infile); if (image_ID != -1 && !preview) gimp_image_delete (image_ID); if (preview) destroy_preview (); if (buffer) g_object_unref (buffer); return -1; } /* Now we can initialize the JPEG decompression object. */ jpeg_create_decompress (&cinfo); /* Step 2: specify data source (eg, a file) */ jpeg_stdio_src (&cinfo, infile); if (! preview) { /* - step 2.1: tell the lib to save the comments */ jpeg_save_markers (&cinfo, JPEG_COM, 0xffff); /* - step 2.2: tell the lib to save APP1 data (Exif or XMP) */ jpeg_save_markers (&cinfo, JPEG_APP0 + 1, 0xffff); /* - step 2.3: tell the lib to save APP2 data (ICC profiles) */ jpeg_save_markers (&cinfo, JPEG_APP0 + 2, 0xffff); } /* Step 3: read file parameters with jpeg_read_header() */ jpeg_read_header (&cinfo, TRUE); /* We can ignore the return value from jpeg_read_header since * (a) suspension is not possible with the stdio data source, and * (b) we passed TRUE to reject a tables-only JPEG file as an error. * See libjpeg.doc for more info. */ /* Step 4: set parameters for decompression */ /* In this example, we don't need to change any of the defaults set by * jpeg_read_header(), so we do nothing here. */ /* Step 5: Start decompressor */ jpeg_start_decompress (&cinfo); /* We may need to do some setup of our own at this point before reading * the data. After jpeg_start_decompress() we have the correct scaled * output image dimensions available, as well as the output colormap * if we asked for color quantization. */ /* temporary buffer */ tile_height = gimp_tile_height (); buf = g_new (guchar, tile_height * cinfo.output_width * cinfo.output_components); rowbuf = g_new (guchar *, tile_height); for (i = 0; i < tile_height; i++) rowbuf[i] = buf + cinfo.output_width * cinfo.output_components * i; switch (cinfo.output_components) { case 1: image_type = GIMP_GRAY; layer_type = GIMP_GRAY_IMAGE; break; case 3: image_type = GIMP_RGB; layer_type = GIMP_RGB_IMAGE; break; case 4: if (cinfo.out_color_space == JCS_CMYK) { image_type = GIMP_RGB; layer_type = GIMP_RGB_IMAGE; break; } /*fallthrough*/ default: g_message ("Don't know how to load JPEG images " "with %d color channels, using colorspace %d (%d).", cinfo.output_components, cinfo.out_color_space, cinfo.jpeg_color_space); return -1; break; } if (preview) { image_ID = preview_image_ID; } else { image_ID = gimp_image_new_with_precision (cinfo.output_width, cinfo.output_height, image_type, GIMP_PRECISION_U8_GAMMA); gimp_image_undo_disable (image_ID); gimp_image_set_filename (image_ID, filename); } if (preview) { preview_layer_ID = gimp_layer_new (preview_image_ID, _("JPEG preview"), cinfo.output_width, cinfo.output_height, layer_type, 100, GIMP_NORMAL_MODE); layer_ID = preview_layer_ID; } else { layer_ID = gimp_layer_new (image_ID, _("Background"), cinfo.output_width, cinfo.output_height, layer_type, 100, GIMP_NORMAL_MODE); } if (! preview) { GString *comment_buffer = NULL; guint8 *profile = NULL; guint profile_size = 0; /* Step 5.0: save the original JPEG settings in a parasite */ jpeg_detect_original_settings (&cinfo, image_ID); /* Step 5.1: check for comments, or Exif metadata in APP1 markers */ for (marker = cinfo.marker_list; marker; marker = marker->next) { const gchar *data = (const gchar *) marker->data; gsize len = marker->data_length; if (marker->marker == JPEG_COM) { #ifdef GIMP_UNSTABLE g_print ("jpeg-load: found image comment (%d bytes)\n", marker->data_length); #endif if (! comment_buffer) { comment_buffer = g_string_new_len (data, len); } else { /* concatenate multiple comments, separate them with LF */ g_string_append_c (comment_buffer, '\n'); g_string_append_len (comment_buffer, data, len); } } else if ((marker->marker == JPEG_APP0 + 1) && (len > sizeof (JPEG_APP_HEADER_EXIF) + 8) && ! strcmp (JPEG_APP_HEADER_EXIF, data)) { #ifdef GIMP_UNSTABLE g_print ("jpeg-load: found Exif block (%d bytes)\n", (gint) (len - sizeof (JPEG_APP_HEADER_EXIF))); #endif } } if (jpeg_load_resolution (image_ID, &cinfo)) { if (resolution_loaded) *resolution_loaded = TRUE; } /* if we found any comments, then make a parasite for them */ if (comment_buffer && comment_buffer->len) { GimpParasite *parasite; jpeg_load_sanitize_comment (comment_buffer->str); parasite = gimp_parasite_new ("gimp-comment", GIMP_PARASITE_PERSISTENT, strlen (comment_buffer->str) + 1, comment_buffer->str); gimp_image_attach_parasite (image_ID, parasite); gimp_parasite_free (parasite); g_string_free (comment_buffer, TRUE); } /* Step 5.3: check for an embedded ICC profile in APP2 markers */ jpeg_icc_read_profile (&cinfo, &profile, &profile_size); if (cinfo.out_color_space == JCS_CMYK) { cmyk_transform = jpeg_load_cmyk_transform (profile, profile_size); } else if (profile) /* don't attach the profile if we are transforming */ { GimpParasite *parasite; parasite = gimp_parasite_new ("icc-profile", GIMP_PARASITE_PERSISTENT | GIMP_PARASITE_UNDOABLE, profile_size, profile); gimp_image_attach_parasite (image_ID, parasite); gimp_parasite_free (parasite); } g_free (profile); /* Do not attach the "jpeg-save-options" parasite to the image * because this conflicts with the global defaults (bug #75398). */ } /* Step 6: while (scan lines remain to be read) */ /* jpeg_read_scanlines(...); */ /* Here we use the library's state variable cinfo.output_scanline as the * loop counter, so that we don't have to keep track ourselves. */ buffer = gimp_drawable_get_buffer (layer_ID); format = babl_format (image_type == GIMP_RGB ? "R'G'B' u8" : "Y' u8"); while (cinfo.output_scanline < cinfo.output_height) { start = cinfo.output_scanline; end = cinfo.output_scanline + tile_height; end = MIN (end, cinfo.output_height); scanlines = end - start; for (i = 0; i < scanlines; i++) jpeg_read_scanlines (&cinfo, (JSAMPARRAY) &rowbuf[i], 1); if (cinfo.out_color_space == JCS_CMYK) jpeg_load_cmyk_to_rgb (buf, cinfo.output_width * scanlines, cmyk_transform); gegl_buffer_set (buffer, GEGL_RECTANGLE (0, start, cinfo.output_width, scanlines), 0, format, buf, GEGL_AUTO_ROWSTRIDE); if (! preview && (cinfo.output_scanline % 32) == 0) gimp_progress_update ((gdouble) cinfo.output_scanline / (gdouble) cinfo.output_height); } /* Step 7: Finish decompression */ jpeg_finish_decompress (&cinfo); /* We can ignore the return value since suspension is not possible * with the stdio data source. */ if (cmyk_transform) cmsDeleteTransform (cmyk_transform); /* Step 8: Release JPEG decompression object */ /* This is an important step since it will release a good deal of memory. */ jpeg_destroy_decompress (&cinfo); g_object_unref (buffer); /* free up the temporary buffers */ g_free (rowbuf); g_free (buf); /* After finish_decompress, we can close the input file. * Here we postpone it until after no more JPEG errors are possible, * so as to simplify the setjmp error logic above. (Actually, I don't * think that jpeg_destroy can do an error exit, but why assume anything...) */ fclose (infile); /* At this point you may want to check to see whether any corrupt-data * warnings occurred (test whether jerr.num_warnings is nonzero). */ /* Detach from the drawable and add it to the image. */ if (! preview) { gimp_progress_update (1.0); } gimp_image_insert_layer (image_ID, layer_ID, -1, 0); return image_ID; }
gboolean save_dialog (void) { JpegSaveGui pg; GtkWidget *dialog; GtkWidget *vbox; GtkObject *entry; GtkWidget *table; GtkWidget *table2; GtkWidget *tabledefaults; 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); table = gtk_table_new (1, 3, FALSE); gtk_table_set_col_spacings (GTK_TABLE (table), 6); gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0); gtk_widget_show (table); pg.quality = entry = gimp_scale_entry_new (GTK_TABLE (table), 0, 0, _("_Quality:"), SCALE_WIDTH, 0, jsvals.quality, 0.0, 100.0, 1.0, 10.0, 0, TRUE, 0.0, 0.0, _("JPEG quality parameter"), "file-jpeg-save-quality"); g_signal_connect (entry, "value-changed", G_CALLBACK (gimp_double_adjustment_update), &jsvals.quality); g_signal_connect (entry, "value-changed", G_CALLBACK (make_preview), NULL); preview_size = gtk_label_new (_("File size: unknown")); gtk_misc_set_alignment (GTK_MISC (preview_size), 0.0, 0.5); 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 (vbox), 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 (vbox), 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); 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); table = gtk_table_new (4, 8, FALSE); gtk_table_set_col_spacings (GTK_TABLE (table), 6); gtk_table_set_row_spacings (GTK_TABLE (table), 6); gtk_table_set_col_spacing (GTK_TABLE (table), 1, 12); gtk_container_add (GTK_CONTAINER (frame), table); table2 = gtk_table_new (1, 3, FALSE); gtk_table_set_col_spacings (GTK_TABLE (table2), 6); gtk_table_attach (GTK_TABLE (table), table2, 2, 6, 0, 1, GTK_FILL, GTK_FILL, 0, 0); gtk_widget_show (table2); pg.smoothing = entry = gimp_scale_entry_new (GTK_TABLE (table2), 0, 0, _("S_moothing:"), 100, 0, jsvals.smoothing, 0.0, 1.0, 0.01, 0.1, 2, TRUE, 0.0, 0.0, NULL, "file-jpeg-save-smoothing"); g_signal_connect (entry, "value-changed", G_CALLBACK (gimp_double_adjustment_update), &jsvals.smoothing); g_signal_connect (entry, "value-changed", G_CALLBACK (make_preview), NULL); restart_markers_label = gtk_label_new (_("Interval (MCU rows):")); gtk_misc_set_alignment (GTK_MISC (restart_markers_label), 1.0, 0.5); gtk_table_attach (GTK_TABLE (table), restart_markers_label, 4, 5, 1, 2, GTK_FILL | GTK_EXPAND, GTK_FILL, 0, 0); gtk_widget_show (restart_markers_label); pg.scale_data = (GtkAdjustment *) 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 = gtk_spin_button_new (pg.scale_data, 1.0, 0); gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinbutton), TRUE); gtk_table_attach (GTK_TABLE (table), spinbutton, 5, 6, 1, 2, GTK_FILL, GTK_FILL, 0, 0); gtk_widget_show (spinbutton); pg.use_restart_markers = toggle = gtk_check_button_new_with_mnemonic (_("Use _restart markers")); gtk_table_attach (GTK_TABLE (table), toggle, 2, 4, 1, 2, GTK_FILL, 0, 0, 0); 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_table_attach (GTK_TABLE (table), toggle, 0, 1, row, row + 1, GTK_FILL, 0, 0, 0); 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); row++; if (arithc_supported) { /* 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_table_attach (GTK_TABLE (table), toggle, 0, 1, row, row + 1, GTK_FILL, 0, 0, 0); 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++; } /* Progressive */ pg.progressive = toggle = gtk_check_button_new_with_mnemonic (_("_Progressive")); gtk_table_attach (GTK_TABLE (table), toggle, 0, 1, row, row + 1, GTK_FILL, 0, 0, 0); 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++; /* 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_table_attach (GTK_TABLE (table), toggle, 0, 1, row, row + 1, GTK_FILL, 0, 0, 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); gtk_widget_set_sensitive (toggle, TRUE); row++; /* 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_table_attach (GTK_TABLE (table), toggle, 0, 1, row, row + 1, GTK_FILL, 0, 0, 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); row++; /* 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_table_attach (GTK_TABLE (table), toggle, 0, 1, row, row + 1, GTK_FILL, 0, 0, 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); gtk_widget_set_sensitive (toggle, TRUE); row++; /* 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_table_attach (GTK_TABLE (table), toggle, 0, 1, row, row + 1, GTK_FILL, 0, 0, 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); gtk_widget_set_sensitive (toggle, TRUE); row++; /* 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_table_attach (GTK_TABLE (table), toggle, 0, 4, row, row + 1, GTK_FILL, 0, 0, 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)); gtk_widget_set_sensitive (toggle, (orig_quality > 0)); /* changing quality disables custom quantization tables, and vice-versa */ g_signal_connect (pg.quality, "value-changed", G_CALLBACK (quality_changed), pg.use_orig_quality); g_signal_connect (pg.use_orig_quality, "toggled", G_CALLBACK (use_orig_qual_changed), pg.quality); /* Subsampling */ label = gtk_label_new_with_mnemonic (_("Su_bsampling:")); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); gtk_table_attach (GTK_TABLE (table), label, 2, 3, 2, 3, GTK_FILL, GTK_FILL, 0, 0); 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_table_attach (GTK_TABLE (table), combo, 3, 6, 2, 3, GTK_FILL | GTK_EXPAND, GTK_FILL, 0, 0); gtk_widget_show (combo); gtk_label_set_mnemonic_widget (GTK_LABEL (label), combo); if (gimp_drawable_is_rgb (drawable_ID_global)) { gimp_int_combo_box_connect (GIMP_INT_COMBO_BOX (combo), jsvals.subsmp, G_CALLBACK (subsampling_changed), entry); g_signal_connect (pg.use_orig_quality, "toggled", G_CALLBACK (use_orig_qual_changed2), pg.subsmp); } else { gimp_int_combo_box_set_active (GIMP_INT_COMBO_BOX (combo), JPEG_SUBSAMPLING_1x1_1x1_1x1); gtk_widget_set_sensitive (combo, FALSE); } /* DCT method */ label = gtk_label_new_with_mnemonic (_("_DCT method:")); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); gtk_table_attach (GTK_TABLE (table), label, 2, 3, 3, 4, GTK_FILL, GTK_FILL, 0, 0); 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_table_attach (GTK_TABLE (table), combo, 3, 6, 3, 4, GTK_FILL | GTK_EXPAND, GTK_FILL, 0, 0); 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", G_CALLBACK (make_preview), NULL); 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); 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); tabledefaults = gtk_table_new (1, 3, FALSE); gtk_table_set_col_spacings (GTK_TABLE (tabledefaults), 6); gtk_box_pack_start (GTK_BOX (vbox), tabledefaults, FALSE, FALSE, 0); gtk_widget_show (tabledefaults); button = gtk_button_new_with_mnemonic (_("_Load Defaults")); gtk_table_attach (GTK_TABLE (tabledefaults), button, 0, 1, 1, 2, GTK_FILL, 0, 0, 0); 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_table_attach (GTK_TABLE (tabledefaults), button, 1, 2, 1, 2, GTK_FILL, 0, 0, 0); gtk_widget_show (button); g_signal_connect_swapped (button, "clicked", G_CALLBACK (save_defaults), &pg); gtk_widget_show (frame); gtk_widget_show (table); gtk_widget_show (dialog); make_preview (); pg.run = FALSE; gtk_main (); destroy_preview (); return pg.run; }