2
* UFRaw - Unidentified Flying Raw converter for digital camera images
5
* ufraw_saver.c - The GUI file saver.
7
* UFRaw is licensed under the GNU General Public License.
8
* It uses DCRaw code to do the actual raw decoding.
15
#include <stdio.h> /* for printf */
17
#include <math.h> /* for fabs, floor */
21
void ufraw_radio_button_update(GtkWidget *button, int *valuep)
23
GtkWidget *dialog = gtk_widget_get_ancestor(button, GTK_TYPE_DIALOG);
24
if (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button)))
26
*valuep = (long)g_object_get_data(G_OBJECT(button), "ButtonValue");
27
char *filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
28
char *base = g_path_get_basename(filename);
30
char *newname = uf_file_set_type(base, file_type[*valuep]);
32
gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), newname);
36
void ufraw_saver_adjustment_update(GObject *adj, gboolean *valuep)
38
GtkDialog *dialog = GTK_DIALOG(g_object_get_data(adj, "ufraw-dialog"));
39
if (!g_object_get_data(G_OBJECT(dialog), "ufraw-dialog-run"))
42
gtk_dialog_response(dialog, GTK_RESPONSE_APPLY);
45
void ufraw_saver_set_type(GtkWidget *widget, cfg_data *cfg)
47
char *filename, *type;
48
filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(widget));
49
type = strrchr(filename, '.');
54
if (!strcmp(type,".ppm") && cfg->type!=ppm16_type)
55
cfg->type = ppm8_type;
56
if (!strcmp(type,".tif") && cfg->type!=tiff16_type)
57
cfg->type = tiff8_type;
58
if (!strcmp(type,".jpg"))
59
cfg->type = jpeg_type;
61
gtk_dialog_response(GTK_DIALOG(widget), GTK_RESPONSE_APPLY);
64
long ufraw_saver(void *widget, gpointer user_data)
66
GtkWindow *parentWindow;
67
GtkFileChooser *fileChooser;
68
GtkWidget *expander, *box, *table, *widg, *button, *align, *overwriteButton;
69
GtkWidget *event, *label;
70
GtkAdjustment *shrinkAdj, *heightAdj, *widthAdj;
71
GtkComboBox *intCombo, *idCombo, *confCombo;
72
GtkToggleButton *ppmButton, *tiffButton, *jpegButton;
73
#if defined(HAVE_LIBZ) && defined(HAVE_LIBTIFF)
74
GtkWidget *losslessButton;
77
GtkWidget *exifButton;
80
GtkAdjustment *compressAdj;
82
ufraw_data *uf = user_data;
83
tiffButton = tiffButton;
84
jpegButton = jpegButton;
87
gboolean shrinkUpdate=FALSE, heightUpdate=FALSE, widthUpdate=FALSE;
88
char *filename, *absFilename;
91
if (uf->cfg->size > 0) {
92
if (uf->predictateHeight > uf->predictateWidth) {
93
height = uf->cfg->size;
94
width = uf->cfg->size * uf->predictateWidth / uf->predictateHeight;
95
shrink = (float)uf->predictateHeight / uf->cfg->size;
97
width = uf->cfg->size;
98
height = uf->cfg->size * uf->predictateHeight / uf->predictateWidth;
99
shrink = (float)uf->predictateWidth / uf->cfg->size;
102
if (uf->cfg->shrink<1) {
103
ufraw_message(UFRAW_ERROR, "Fatal Error: uf->cfg->shrink<1");
106
height = uf->predictateHeight / uf->cfg->shrink;
107
width = uf->predictateWidth / uf->cfg->shrink;
108
shrink = uf->cfg->shrink;
110
filename = uf_file_set_type(uf->filename, file_type[uf->cfg->type]);
111
if (strlen(uf->cfg->outputPath)>0) {
112
char *cp = g_path_get_basename(filename);
114
filename = g_build_filename(uf->cfg->outputPath, cp, NULL);
117
absFilename = uf_file_set_absolute(filename);
119
char *text = g_strdup_printf("Filename: %s\nSize: %d x %d%s",
120
absFilename, (int)height, (int)width,
121
uf->cfg->createID==also_id ? "\nCreate also ID file" :
122
uf->cfg->createID==only_id ? "\nCreate only ID file" : "");
125
parentWindow = GTK_WINDOW(gtk_widget_get_toplevel(widget));
126
if (!strcmp(gtk_button_get_label(GTK_BUTTON(widget)), GTK_STOCK_SAVE)) {
127
if ( !uf->cfg->overwrite && uf->cfg->createID!=only_id
128
&& g_file_test(absFilename, G_FILE_TEST_EXISTS) ) {
130
char message[max_path];
132
dialog = gtk_dialog_new_with_buttons("File exists", parentWindow,
133
GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR,
134
GTK_STOCK_NO, GTK_RESPONSE_NO,
135
GTK_STOCK_YES, GTK_RESPONSE_YES, NULL);
136
snprintf(message, max_path,
137
"File '%s' already exists.\nOverwrite?", filename);
138
widg = gtk_label_new(message);
139
gtk_label_set_line_wrap(GTK_LABEL(widg), TRUE);
140
gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), widg);
141
gtk_widget_show_all(dialog);
142
response = gtk_dialog_run(GTK_DIALOG(dialog));
143
gtk_widget_destroy(dialog);
144
if (response!=GTK_RESPONSE_YES)
145
return UFRAW_SUCCESS;
147
g_strlcpy(uf->cfg->outputFilename, absFilename, max_path);
150
status = ufraw_write_image(uf);
151
if (status==UFRAW_SUCCESS) {
152
g_object_set_data(G_OBJECT(parentWindow), "WindowResponse",
153
(gpointer)GTK_RESPONSE_OK);
155
} else if (status==UFRAW_ABORT_SAVE) {
156
g_object_set_data(G_OBJECT(parentWindow), "WindowResponse",
157
(gpointer)GTK_RESPONSE_CANCEL);
160
preview_progress(widget, "", 0);
161
return UFRAW_SUCCESS;
163
fileChooser = GTK_FILE_CHOOSER(gtk_file_chooser_dialog_new(
164
"Save image", parentWindow, GTK_FILE_CHOOSER_ACTION_SAVE,
165
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
166
GTK_STOCK_SAVE, GTK_RESPONSE_OK, NULL));
168
gtk_dialog_set_default_response(GTK_DIALOG(fileChooser), GTK_RESPONSE_OK);
169
ufraw_focus(fileChooser, TRUE);
171
gtk_file_chooser_set_show_hidden(fileChooser, TRUE);
173
char *path = g_path_get_dirname(absFilename);
174
gtk_file_chooser_set_current_folder(fileChooser, path);
176
char *base = g_path_get_basename(filename);
177
gtk_file_chooser_set_current_name(fileChooser, base);
180
GtkTooltips *tips = gtk_tooltips_new();
182
expander = gtk_expander_new("Output options");
183
gtk_expander_set_expanded(GTK_EXPANDER(expander), TRUE);
184
gtk_file_chooser_set_extra_widget(fileChooser, expander);
185
box = gtk_vbox_new(FALSE, 0);
186
gtk_container_add(GTK_CONTAINER(expander), box);
188
if (uf->cfg->interpolation==half_interpolation) {
189
uf->cfg->interpolation = full_interpolation;
190
if (uf->cfg->shrink<2) uf->cfg->shrink = 2;
192
intCombo = GTK_COMBO_BOX(gtk_combo_box_new_text());
193
gtk_combo_box_append_text(intCombo, "Full interpolation");
194
gtk_combo_box_append_text(intCombo, "Four color interpolation");
195
gtk_combo_box_append_text(intCombo, "Quick interpolation");
196
gtk_combo_box_set_active(intCombo, uf->cfg->interpolation);
197
align = gtk_alignment_new(0.0, 0.5, 0.0, 0.0);
198
gtk_container_add(GTK_CONTAINER(align), GTK_WIDGET(intCombo));
199
gtk_box_pack_start(GTK_BOX(box), align, FALSE, FALSE, 0);
201
table = gtk_table_new(5, 1, FALSE);
202
gtk_box_pack_start(GTK_BOX(box), table, TRUE, TRUE, 0);
203
widg = gtk_label_new("Shrink factor ");
204
gtk_table_attach(GTK_TABLE(table), widg, 0, 1, 1, 2, 0, 0, 0, 0);
205
shrinkAdj = GTK_ADJUSTMENT(gtk_adjustment_new(shrink,
207
g_object_set_data(G_OBJECT(shrinkAdj), "ufraw-dialog", fileChooser);
208
g_signal_connect(G_OBJECT(shrinkAdj), "value-changed",
209
G_CALLBACK(ufraw_saver_adjustment_update), &shrinkUpdate);
210
widg = gtk_spin_button_new(shrinkAdj, 1, 3);
211
gtk_table_attach(GTK_TABLE(table), widg, 1, 2, 1, 2, 0, 0, 0, 0);
213
widg = gtk_label_new("\tHeight ");
214
gtk_table_attach(GTK_TABLE(table), widg, 2, 3, 1, 2, 0, 0, 0, 0);
215
heightAdj = GTK_ADJUSTMENT(gtk_adjustment_new(height,
216
uf->predictateHeight/100, uf->predictateHeight, 10, 100, 0));
217
g_object_set_data(G_OBJECT(heightAdj), "ufraw-dialog", fileChooser);
218
g_signal_connect(G_OBJECT(heightAdj), "value-changed",
219
G_CALLBACK(ufraw_saver_adjustment_update), &heightUpdate);
220
widg = gtk_spin_button_new(heightAdj, 10, 0);
221
gtk_table_attach(GTK_TABLE(table), widg, 3, 4, 1, 2, 0, 0, 0, 0);
223
widg = gtk_label_new("\tWidth ");
224
gtk_table_attach(GTK_TABLE(table), widg, 4, 5, 1, 2, 0, 0, 0, 0);
225
widthAdj = GTK_ADJUSTMENT(gtk_adjustment_new(width,
226
uf->predictateWidth/100, uf->predictateWidth, 10, 100, 0));
227
g_object_set_data(G_OBJECT(widthAdj), "ufraw-dialog", fileChooser);
228
g_signal_connect(G_OBJECT(widthAdj), "value-changed",
229
G_CALLBACK(ufraw_saver_adjustment_update), &widthUpdate);
230
widg = gtk_spin_button_new(widthAdj, 10, 0);
231
gtk_table_attach(GTK_TABLE(table), widg, 5, 6, 1, 2, 0, 0, 0, 0);
233
gtk_box_pack_start(GTK_BOX(box), gtk_hseparator_new(), TRUE, TRUE, 0);
234
button = gtk_radio_button_new_with_label(NULL, "8-bit ppm");
235
ppmButton = GTK_TOGGLE_BUTTON(button);
236
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button),
237
uf->cfg->type==ppm8_type);
238
g_object_set_data(G_OBJECT(button), "ButtonValue", (gpointer)ppm8_type);
239
g_signal_connect(G_OBJECT(button), "toggled",
240
G_CALLBACK(ufraw_radio_button_update), &uf->cfg->type);
241
gtk_box_pack_start(GTK_BOX(box), button, TRUE, TRUE, 0);
243
button = gtk_radio_button_new_with_label_from_widget(
244
GTK_RADIO_BUTTON(button), "16-bit ppm");
245
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button),
246
uf->cfg->type==ppm16_type);
247
g_object_set_data(G_OBJECT(button), "ButtonValue", (gpointer)ppm16_type);
248
g_signal_connect(G_OBJECT(button), "toggled",
249
G_CALLBACK(ufraw_radio_button_update), &uf->cfg->type);
250
gtk_box_pack_start(GTK_BOX(box), button, TRUE, TRUE, 0);
252
gtk_box_pack_start(GTK_BOX(box), gtk_hseparator_new(), TRUE, TRUE, 0);
253
table = gtk_table_new(5, 1, FALSE);
254
gtk_box_pack_start(GTK_BOX(box), table, TRUE, TRUE, 0);
255
button = gtk_radio_button_new_with_label_from_widget(
256
GTK_RADIO_BUTTON(button), "8-bit TIFF");
257
tiffButton = GTK_TOGGLE_BUTTON(button);
258
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button),
259
uf->cfg->type==tiff8_type);
260
g_object_set_data(G_OBJECT(button), "ButtonValue", (gpointer)tiff8_type);
261
g_signal_connect(G_OBJECT(button), "toggled",
262
G_CALLBACK(ufraw_radio_button_update), &uf->cfg->type);
263
gtk_table_attach(GTK_TABLE(table), button, 0, 1, 0, 1, 0, 0, 0, 0);
264
button = gtk_radio_button_new_with_label_from_widget(
265
GTK_RADIO_BUTTON(button), "16-bit TIFF");
266
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button),
267
uf->cfg->type==tiff16_type);
268
g_object_set_data(G_OBJECT(button), "ButtonValue", (gpointer)tiff16_type);
269
g_signal_connect(G_OBJECT(button), "toggled",
270
G_CALLBACK(ufraw_radio_button_update), &uf->cfg->type);
271
gtk_table_attach(GTK_TABLE(table), button, 0, 1, 1, 2, 0, 0, 0, 0);
273
losslessButton = gtk_check_button_new_with_label("ZIP Compress (lossless)");
274
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(losslessButton),
275
uf->cfg->losslessCompress);
276
gtk_table_attach(GTK_TABLE(table), losslessButton, 1, 2, 2, 3, 0, 0, 0, 0);
278
#endif /*HAVE_LIBTIFF*/
280
gtk_box_pack_start(GTK_BOX(box), gtk_hseparator_new(), TRUE, TRUE, 0);
281
table = gtk_table_new(5, 1, FALSE);
282
gtk_box_pack_start(GTK_BOX(box), table, TRUE, TRUE, 0);
283
button = gtk_radio_button_new_with_label_from_widget(
284
GTK_RADIO_BUTTON(button), "JPEG");
285
jpegButton = GTK_TOGGLE_BUTTON(button);
286
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button),
287
uf->cfg->type==jpeg_type);
288
g_object_set_data(G_OBJECT(button), "ButtonValue", (gpointer)jpeg_type);
289
g_signal_connect(G_OBJECT(button), "toggled",
290
G_CALLBACK(ufraw_radio_button_update), &uf->cfg->type);
291
gtk_table_attach(GTK_TABLE(table), button, 0, 1, 0, 1, 0, 0, 0, 0);
292
widg = gtk_label_new("Compression level");
293
gtk_table_attach(GTK_TABLE(table), widg, 1, 2, 1, 2, 0, 0, 0, 0);
294
compressAdj = GTK_ADJUSTMENT(gtk_adjustment_new(uf->cfg->compression,
296
widg = gtk_hscale_new(compressAdj);
297
gtk_scale_set_draw_value(GTK_SCALE(widg), FALSE);
298
gtk_table_attach(GTK_TABLE(table), widg, 2, 3, 1, 2,
299
GTK_EXPAND|GTK_FILL, 0, 0, 0);
300
widg = gtk_spin_button_new(compressAdj, 5, 0);
301
gtk_table_attach(GTK_TABLE(table), widg, 3, 4, 1, 2, 0, 0, 0, 0);
303
exifButton = gtk_check_button_new_with_label("Embed EXIF data");
304
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(exifButton),
305
uf->cfg->embedExif && uf->exifBuf!=NULL);
306
gtk_widget_set_sensitive(exifButton, uf->exifBuf!=NULL);
307
gtk_table_attach(GTK_TABLE(table), exifButton, 1, 2, 2, 3, 0, 0, 0, 0);
309
#endif /*HAVE_LIBJPEG*/
311
gtk_box_pack_start(GTK_BOX(box), gtk_hseparator_new(), TRUE, TRUE, 0);
312
table = gtk_table_new(1, 5, FALSE);
313
gtk_box_pack_start(GTK_BOX(box), table, TRUE, TRUE, 0);
314
label = gtk_label_new("Create ID file ");
315
gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, 0, 0, 0, 0);
316
idCombo = GTK_COMBO_BOX(gtk_combo_box_new_text());
317
gtk_combo_box_append_text(idCombo, "No");
318
gtk_combo_box_append_text(idCombo, "Also");
319
gtk_combo_box_append_text(idCombo, "Only");
320
gtk_combo_box_set_active(idCombo, uf->cfg->createID);
321
gtk_table_attach(GTK_TABLE(table), GTK_WIDGET(idCombo), 1, 2, 0, 1,
324
label = gtk_label_new("\tSave image defaults ");
325
event = gtk_event_box_new();
326
gtk_container_add(GTK_CONTAINER(event), label);
327
gtk_tooltips_set_tip(tips, event,
328
"Save current image manipulation parameters as defaults.\n"
329
"The output parameters in this window are always saved.", NULL);
330
gtk_table_attach(GTK_TABLE(table), event, 3, 4, 0, 1, 0, 0, 0, 0);
331
confCombo = GTK_COMBO_BOX(gtk_combo_box_new_text());
332
gtk_combo_box_append_text(confCombo, "Never again");
333
gtk_combo_box_append_text(confCombo, "Always");
334
gtk_combo_box_append_text(confCombo, "Just this once");
335
gtk_combo_box_set_active(confCombo, uf->cfg->saveConfiguration);
336
gtk_table_attach(GTK_TABLE(table), GTK_WIDGET(confCombo), 4, 5, 0, 1,
339
gtk_box_pack_start(GTK_BOX(box), gtk_hseparator_new(), TRUE, TRUE, 0);
340
overwriteButton = gtk_check_button_new_with_label(
341
"Overwrite existing files without asking");
342
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(overwriteButton),
344
gtk_box_pack_start(GTK_BOX(box), overwriteButton, TRUE, TRUE, 0);
345
gtk_widget_show_all(expander);
347
if (strlen(uf->cfg->inputFilename)>0) {
348
char *cp = g_path_get_dirname(uf->cfg->inputFilename);
350
gtk_file_chooser_add_shortcut_folder(fileChooser, cp, NULL);
353
g_signal_connect(G_OBJECT(fileChooser), "selection-changed",
354
G_CALLBACK(ufraw_saver_set_type), uf->cfg);
356
g_object_set_data(G_OBJECT(fileChooser), "ufraw-dialog-run",
358
status = gtk_dialog_run(GTK_DIALOG(fileChooser));
359
g_object_set_data(G_OBJECT(fileChooser), "ufraw-dialog-run",
361
if (status==GTK_RESPONSE_CANCEL) {
362
ufraw_focus(fileChooser, FALSE);
363
gtk_widget_destroy(GTK_WIDGET(fileChooser));
366
if (status==GTK_RESPONSE_APPLY) {
367
gtk_toggle_button_set_active(ppmButton,
368
uf->cfg->type==ppm8_type);
370
gtk_toggle_button_set_active(tiffButton,
371
uf->cfg->type==tiff8_type);
374
gtk_toggle_button_set_active(jpegButton,
375
uf->cfg->type==jpeg_type);
378
shrink = gtk_adjustment_get_value(shrinkAdj);
379
height = uf->predictateHeight / shrink;
380
width = uf->predictateWidth / shrink;
381
shrinkUpdate = FALSE;
384
height = gtk_adjustment_get_value(heightAdj);
385
width = height * uf->predictateWidth / uf->predictateHeight;
386
shrink = (float)uf->predictateHeight / height;
387
heightUpdate = FALSE;
390
width = gtk_adjustment_get_value(widthAdj);
391
height = width * uf->predictateHeight / uf->predictateWidth;
392
shrink = (float)uf->predictateWidth / width;
395
gtk_adjustment_set_value(shrinkAdj, shrink);
396
gtk_adjustment_set_value(heightAdj, height);
397
gtk_adjustment_set_value(widthAdj, width);
400
filename = gtk_file_chooser_get_filename(fileChooser);
401
uf->cfg->interpolation = gtk_combo_box_get_active(intCombo);
402
uf->cfg->createID = gtk_combo_box_get_active(idCombo);
403
uf->cfg->saveConfiguration = gtk_combo_box_get_active(confCombo);
404
if (fabs(shrink-floor(shrink+0.0005))<0.0005) {
405
uf->cfg->shrink = floor(shrink+0.0005);
409
uf->cfg->size = floor(MAX(height, width)+0.5);
411
uf->cfg->overwrite = gtk_toggle_button_get_active(
412
GTK_TOGGLE_BUTTON(overwriteButton));
413
#if defined(HAVE_LIBZ) && defined(HAVE_LIBTIFF)
414
uf->cfg->losslessCompress = gtk_toggle_button_get_active(
415
GTK_TOGGLE_BUTTON(losslessButton));
418
uf->cfg->compression = gtk_adjustment_get_value(compressAdj);
421
uf->cfg->embedExif = gtk_toggle_button_get_active(
422
GTK_TOGGLE_BUTTON(exifButton));
424
if ( !uf->cfg->overwrite && uf->cfg->createID!=only_id
425
&& g_file_test(filename, G_FILE_TEST_EXISTS) ) {
427
char message[max_path];
429
dialog = gtk_dialog_new_with_buttons("File exists",
430
GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(fileChooser))),
431
GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR,
432
GTK_STOCK_NO, GTK_RESPONSE_NO,
433
GTK_STOCK_YES, GTK_RESPONSE_YES, NULL);
434
snprintf(message, max_path,
435
"File '%s' already exists.\nOverwrite?", filename);
436
widg = gtk_label_new(message);
437
gtk_label_set_line_wrap(GTK_LABEL(widg), TRUE);
438
gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), widg);
439
gtk_widget_show_all(dialog);
440
response = gtk_dialog_run(GTK_DIALOG(dialog));
441
gtk_widget_destroy(dialog);
442
if (response!=GTK_RESPONSE_YES)
445
g_strlcpy(uf->cfg->outputFilename, filename, max_path);
447
status = ufraw_write_image(uf);
448
if (status==UFRAW_SUCCESS || status==UFRAW_ABORT_SAVE) {
449
ufraw_focus(fileChooser, FALSE);
450
gtk_widget_destroy(GTK_WIDGET(fileChooser));
451
if (status==UFRAW_SUCCESS)
452
g_object_set_data(G_OBJECT(parentWindow), "WindowResponse",
453
(gpointer)GTK_RESPONSE_OK);
455
g_object_set_data(G_OBJECT(parentWindow), "WindowResponse",
456
(gpointer)GTK_RESPONSE_CANCEL);
458
gtk_object_sink(GTK_OBJECT(tips));
459
return UFRAW_SUCCESS;