2
* UFRaw - Unidentified Flying Raw converter for digital camera images
5
* ufraw.c - The standalone interface to UFRaw.
7
* UFRaw is licensed under the GNU General Public License.
8
* It uses DCRaw code to do the actual raw decoding.
11
#include <stdio.h> /* for printf */
12
#include <stdlib.h> /* for exit */
13
#include <errno.h> /* for errno */
15
#include <math.h> /* for isnan */
28
#include "ufraw_icon.h"
33
"UFRaw 0.3 - Unidentified Flying Raw converter for digital camera images.\n"
35
"Usage: ufraw [ options ... ] [ raw-image-files ... ]\n"
37
"By default UFRaw displays a preview window for each raw image allowing\n"
38
"the user to tweak the image parameters before saving. If no raw images\n"
39
"are given at the command line, UFRaw will display a file chooser dialog.\n"
40
"To process the images with no questions asked (and no preview) use\n"
41
"the --batch option. The rest of the options are separated into two groups.\n"
42
"The options which are related to the image manipulation are:\n"
44
"--wb=camera|auto White balance setting.\n"
45
"--temperature=TEMP Color temperature in Kelvins (2000 - 7000).\n"
46
"--green=GREEN Green color normalization.\n"
47
"--curve=gamma|log|linear|camera\n"
48
" Type of tone curve to use (default camera if such\n"
49
" exsists, log otherwise).\n"
50
"--[no]unclip Unclip [clip] highlights.\n"
51
"--contrast=CONTRAST Contrast adjustment (default 1.0).\n"
52
"--gamma=GAMMA Gamma adjustment (default 0.45).\n"
53
"--saturation=SAT Saturation adjustment (default 1.0, 0 for B&W output).\n"
54
"--shadow=SHADOW Suppress enhance shadow details (default 0).\n"
55
"--shadow-depth=DEPTH Define what are shadows (default 0.1).\n"
56
"--exposure=EXPOSURE Exposure correction in EV (default 0).\n"
57
"--black-point=BLACK Set black point (default 0).\n"
59
"The options which are related to the final output are:\n"
61
"--interpolation=full|four-color|quick|half\n"
62
" Interpolation algorithm to use (default full).\n"
63
"--shrink=FACTOR Shrink the image by FACTOR (default 1).\n"
64
"--out-type=ppm8|ppm16|tiff8|tiff16|jpeg\n"
65
" Output file formati (default ppm8).\n"
66
"--compression=VALUE JPEG compression (0-100, default 85).\n"
67
"--[no]zip Enable [disable] TIFF zip compression (default nozip).\n"
68
"--out-path=PATH PATH for output file (default use input file's path).\n"
69
"--overwrite Overwrite existing files without asking (default no).\n"
71
"UFRaw first reads the setting from the configuration file $HOME/.ufrawrc\n"
72
"and then sets the options from the command line. In batch mode, the second\n"
73
"group of options is NOT read from the configuration file, and therefore,\n"
74
"must be specified explicitly if non-default values are desired.\n"
76
"Last, but not least, --help displays this help message and exits.\n";
78
int ufraw_saver(GtkWidget *widget, gpointer user_data);
79
int ufraw_write_image(image_data *image, char *outFilename);
80
void ufraw_chooser(cfg_data *cfg);
82
int main (int argc, char **argv)
86
GtkWidget *dummyWindow=NULL;
90
gboolean batch=FALSE, unclip=-1, losslessCompress=-1, overwrite=-1;
91
char *curveName=NULL, *outTypeName=NULL, *outPath=NULL;
93
float contrast=NULLF, gamma=NULLF, saturation=NULLF, shadow=NULLF,
94
shadowDepth=NULLF, blackPoint=NULLF, exposure=NULLF,
95
temperature=NULLF, green=NULLF, compression=NULLF;
96
char *interpolationName=NULL;
98
static struct option options[] = {
100
{"temperature", 1, 0, 't'},
101
{"green", 1, 0, 'g'},
102
{"curve", 1, 0, 'c'},
103
{"contrast", 1, 0, 'C'},
104
{"gamma", 1, 0, 'G'},
105
{"saturation", 1, 0, 's'},
106
{"shadow", 1, 0, 'S'},
107
{"shadow-depth", 1, 0, 'd'},
108
{"exposure", 1, 0, 'e'},
109
{"black-point", 1, 0, 'k'},
110
{"interpolation", 1, 0, 'i'},
111
{"shrink", 1, 0, 'x'},
112
{"compression", 1, 0, 'j'},
113
{"out-type", 1, 0, 'T'},
114
{"out-path", 1, 0, 'p'},
115
/* Binary flags that don't have a value are here at the end */
116
{"batch", 0, 0, 'B'},
117
{"unclip", 0, 0, 'u'},
118
{"nounclip", 0, 0, 'U'},
120
{"nozip", 0, 0, 'Z'},
121
{"overwrite", 0, 0, 'o'},
125
void *optPointer[] = { &wbName, &temperature, &green, &curveName,
126
&contrast, &gamma, &saturation, &shadow, &shadowDepth,
127
&exposure, &blackPoint, &interpolationName, &shrink,
128
&compression, &outTypeName, &outPath };
131
locale = setlocale(LC_ALL, "");
133
(!strncmp(locale, "he", 2) || !strncmp(locale, "iw", 2) ||
134
!strncmp(locale, "ar", 2) ||
135
!strncmp(locale, "Hebrew", 6) || !strncmp(locale, "Arabic", 6) ) ) {
136
/* I'm not sure why the following doesn't work (on Windows at least) */
137
/* locale = setlocale(LC_ALL, "en_US");
138
gtk_disable_setlocale(); */
139
/* so I'm using setenv */
140
g_setenv("LC_ALL", "en_US", TRUE);
142
gtk_init(&argc, &argv);
144
c = getopt_long (argc, argv, "", options, &index);
158
if (sscanf(optarg, "%f", (float *)optPointer[index])==0){
159
ufraw_message(UFRAW_ERROR,
160
"ufraw: '%s' is not a valid value for the --%s option.\n",
161
optarg, options[index].name);
170
*(char **)optPointer[index] = optarg;
172
case 'B': batch = TRUE; break;
173
case 'u': unclip = TRUE; break;
174
case 'U': unclip = FALSE; break;
175
case 'o': overwrite = TRUE; break;
178
ufraw_message(UFRAW_ERROR,
179
"ufraw: ufraw was build without ZIP support.\n");
182
losslessCompress = TRUE; break;
184
case 'Z': losslessCompress = FALSE; break;
186
fprintf(stderr, helpText);
188
case '?': /* invalid option. Warning printed by getopt() */
191
ufraw_message(UFRAW_ERROR, "getopt returned "
192
"character code 0%o ??\n", c);
197
dummyWindow = gtk_window_new(GTK_WINDOW_TOPLEVEL);
198
gtk_window_set_icon(GTK_WINDOW(dummyWindow),
199
gdk_pixbuf_new_from_inline(-1, ufraw_icon, FALSE, NULL));
200
ufraw_message_handler(UFRAW_SET_PARENT, (char *)dummyWindow);
202
ufraw_config(NULL, &cfg);
204
if (g_file_test(outPath, G_FILE_TEST_IS_DIR))
205
g_strlcpy(cfg.outputFilename, outPath, max_path);
207
ufraw_message(UFRAW_ERROR, "'%s' is not a valid path.\n", outPath);
212
/* The save options are always set to default */
213
if (cfg.interpolation!=four_color_interpolation)
214
cfg.interpolation = full_interpolation;
215
cfg.shrink = cfg_default.shrink;
216
cfg.type = cfg_default.type;
217
cfg.compression = cfg_default.compression;
218
cfg.losslessCompress = cfg_default.losslessCompress;
219
/* Disable some of the resetting done in ufraw_config() */
220
cfg.wbLoad = load_preserve;
221
if (temperature!=NULLF || green!=NULLF) cfg.wb = preserve_wb;
222
cfg.curveLoad = load_preserve;
223
if (cfg.exposureLoad!=load_auto ||
224
exposure!=NULLF || blackPoint!=NULLF)
225
cfg.exposureLoad = load_preserve;
226
if (isnan(cfg.exposure) && exposure==NULLF && blackPoint!=NULLF)
227
exposure = cfg_default.exposure;
228
if (outPath==NULL) outPath = "";
229
cfg.overwrite = FALSE;
231
if (overwrite!=-1) cfg.overwrite = overwrite;
232
if (unclip!=-1) cfg.unclip = unclip;
233
if (losslessCompress!=-1) cfg.losslessCompress = losslessCompress;
234
if (compression!=NULLF) cfg.compression = compression;
235
if (exposure!=NULLF) cfg.exposure = exposure;
236
if (temperature!=NULLF) cfg.temperature = temperature;
237
if (green!=NULLF) cfg.green = green;
238
if (shrink!=NULLF) cfg.shrink = shrink;
240
if (!strcmp(wbName, "camera")) cfg.wb = camera_wb;
241
else if (!strcmp(wbName, "auto")) cfg.wb = auto_wb;
243
ufraw_message(UFRAW_ERROR,
244
"'%s' is not a valid white balance option.\n", wbName);
248
curveType = camera_curve;
249
if (curveName!=NULL) {
250
if (!strcmp(curveName, "gamma")) cfg.curveIndex = gamma_curve;
251
else if (!strcmp(curveName, "log")) cfg.curveIndex = log_curve;
252
else if (!strcmp(curveName, "linear")) cfg.curveIndex=linear_curve;
253
else if (!strcmp(curveName, "camera")) cfg.curveIndex=camera_curve;
255
ufraw_message(UFRAW_ERROR,
256
"'%s' is not a valid curve name.\n", curveName);
260
if (contrast!=NULLF) cfg.curve[cfg.curveIndex].contrast = contrast;
261
if (gamma!=NULLF) cfg.curve[cfg.curveIndex].gamma = gamma;
262
if (saturation!=NULLF) cfg.curve[cfg.curveIndex].saturation=saturation;
263
if (shadow!=NULLF) cfg.curve[cfg.curveIndex].shadow = shadow;
264
if (shadowDepth!=NULLF) cfg.curve[cfg.curveIndex].depth = shadowDepth;
265
if (blackPoint!=NULLF) cfg.curve[cfg.curveIndex].black = blackPoint;
266
if (interpolationName!=NULL) {
267
if (!strcmp(interpolationName, "full"))
268
cfg.interpolation = full_interpolation;
269
else if (!strcmp(interpolationName, "four-color"))
270
cfg.interpolation = four_color_interpolation;
271
else if (!strcmp(interpolationName, "quick"))
272
cfg.interpolation = quick_interpolation;
273
else if (!strcmp(interpolationName, "half"))
274
cfg.interpolation = half_interpolation;
276
ufraw_message(UFRAW_ERROR,
277
"'%s' is not a valid interpolation option.\n",
282
if (outTypeName!=NULL) {
283
if (!strcmp(outTypeName, "ppm8"))
284
cfg.type = ppm8_type;
285
else if (!strcmp(outTypeName, "ppm16"))
286
cfg.type = ppm16_type;
287
else if (!strcmp(outTypeName, "tiff8"))
290
ufraw_message(UFRAW_ERROR,
291
"ufraw was build without TIFF support.\n");
295
cfg.type = tiff8_type;
297
else if (!strcmp(outTypeName, "tiff16"))
300
ufraw_message(UFRAW_ERROR,
301
"ufraw was build without TIFF support.\n");
305
cfg.type = tiff16_type;
307
else if (!strcmp(outTypeName, "jpeg"))
310
ufraw_message(UFRAW_ERROR,
311
"ufraw was build without JPEG support.\n");
315
cfg.type = jpeg_type;
318
ufraw_message(UFRAW_ERROR,
319
"'%s' is not a valid output type.\n", outTypeName);
324
if (batch) ufraw_message(UFRAW_WARNING,
325
"no input file, nothing to do.\n")
326
else ufraw_chooser(&cfg);
329
for (; optind<argc; optind++) {
330
image = ufraw_open(argv[optind]);
332
ufraw_message(UFRAW_REPORT, NULL);
335
ufraw_config(image, &cfg);
337
if (ufraw_load_raw(image, FALSE)!=UFRAW_SUCCESS)
339
ufraw_message(UFRAW_MESSAGE, "loaded %s\n",
341
g_strlcpy(cfg.outputFilename, outPath, max_path);
342
if (ufraw_saver(NULL, image)==UFRAW_SUCCESS)
343
ufraw_message(UFRAW_MESSAGE, "saved %s\n", cfg.outputFilename);
347
ufraw_preview(image, FALSE, ufraw_saver);
350
if (dummyWindow!=NULL) gtk_widget_destroy(dummyWindow);
354
void ufraw_radio_button_update(GtkWidget *button, int *valuep)
356
char *filename, newFilename[max_path], *cp;
357
GtkWidget *dialog = gtk_widget_get_ancestor(button, GTK_TYPE_DIALOG);
358
if (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button)))
360
*valuep = (long)g_object_get_data(G_OBJECT(button), "ButtonValue");
361
filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
362
g_strlcpy(newFilename, filename, max_path);
364
if ( (cp=strrchr(newFilename, '.'))!=NULL) *cp= '\0';
365
g_strlcat(newFilename, file_type[*valuep], max_path);
366
if ( (cp=strrchr(newFilename, '/'))!=NULL) cp++;
367
else if ( (cp=strrchr(newFilename, '\\'))!=NULL) cp++;
368
else cp = newFilename;
369
gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), cp);
372
void ufraw_saver_set_type(GtkWidget *widget, cfg_data *cfg)
374
char *filename, *type;
375
filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(widget));
376
type = strrchr(filename, '.');
381
if (!strcmp(type,".ppm") && cfg->type!=ppm16_type)
382
cfg->type = ppm8_type;
383
if (!strcmp(type,".tif") && cfg->type!=tiff16_type)
384
cfg->type = tiff8_type;
385
if (!strcmp(type,".jpg"))
386
cfg->type = jpeg_type;
388
gtk_dialog_response(GTK_DIALOG(widget), GTK_RESPONSE_APPLY);
391
int ufraw_saver(GtkWidget *widget, gpointer user_data)
393
GtkWindow *parentWindow;
394
GtkFileChooser *fileChooser;
395
GtkWidget *expander, *box, *table, *widg, *button, *overwriteButton;
396
GtkAdjustment *shrinkAdj;
397
GtkComboBox *intCombo;
398
GtkToggleButton *ppmButton, *tiffButton, *jpegButton;
399
#if !defined(NO_TIFF) && !defined(NO_ZLIB)
400
GtkWidget *losslessButton;
403
GtkAdjustment *compressAdj;
405
image_data *image = user_data;
406
char *filename, defFilename[max_path], *cp;
409
g_strlcpy(defFilename, image->filename, max_path);
410
if ( (cp=strrchr(defFilename, '.'))!=NULL) *cp= '\0';
411
g_strlcat(defFilename, file_type[image->cfg->type], max_path);
413
if (strlen(image->cfg->outputFilename)>0) {
414
cp = g_path_get_basename(defFilename);
415
filename = g_build_filename(image->cfg->outputFilename, cp , NULL);
416
g_strlcpy(defFilename, filename, max_path);
420
if (!image->cfg->overwrite) {
421
if (g_file_test(defFilename, G_FILE_TEST_EXISTS)) {
423
fprintf(stderr, "ufraw: overwrite '%s'? [y/N] ", defFilename);
426
if (ans!='y' && ans!='Y') return UFRAW_CANCEL;
429
return ufraw_write_image(image, defFilename);
431
parentWindow = GTK_WINDOW(gtk_widget_get_toplevel(widget));
432
fileChooser = GTK_FILE_CHOOSER(gtk_file_chooser_dialog_new(
433
"Save image", parentWindow, GTK_FILE_CHOOSER_ACTION_SAVE,
434
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
435
GTK_STOCK_SAVE, GTK_RESPONSE_OK, NULL));
436
gtk_dialog_set_default_response(GTK_DIALOG(fileChooser), GTK_RESPONSE_OK);
437
ufraw_message_handler(UFRAW_SET_PARENT, (char *)fileChooser);
438
if (strlen(image->cfg->outputFilename)>0) {
439
if (g_path_is_absolute(image->cfg->outputFilename))
440
gtk_file_chooser_set_current_folder(fileChooser,
441
image->cfg->outputFilename);
443
char *cd = g_get_current_dir();
444
char *fn = g_build_filename(cd, image->cfg->outputFilename, NULL);
445
gtk_file_chooser_set_current_folder(fileChooser, fn);
450
expander = gtk_expander_new("Output options");
451
gtk_expander_set_expanded(GTK_EXPANDER(expander), TRUE);
452
gtk_file_chooser_set_extra_widget(fileChooser, expander);
453
box = gtk_vbox_new(FALSE, 0);
454
gtk_container_add(GTK_CONTAINER(expander), box);
455
table = gtk_table_new(5, 1, FALSE);
456
gtk_box_pack_start(GTK_BOX(box), table, TRUE, TRUE, 0);
457
if (image->cfg->interpolation==half_interpolation) {
458
image->cfg->interpolation = full_interpolation;
459
if (image->cfg->shrink<2) image->cfg->shrink = 2;
461
intCombo = GTK_COMBO_BOX(gtk_combo_box_new_text());
462
gtk_combo_box_append_text(intCombo, "Full interpolation");
463
gtk_combo_box_append_text(intCombo, "Four color interpolation");
464
gtk_combo_box_append_text(intCombo, "Quick interpolation");
465
gtk_combo_box_set_active(intCombo, image->cfg->interpolation);
466
gtk_table_attach(GTK_TABLE(table), GTK_WIDGET(intCombo),
467
0, 3, 0, 1, 0, 0, 0, 0);
468
widg = gtk_label_new("Shrink factor");
469
gtk_table_attach(GTK_TABLE(table), widg, 0, 1, 1, 2, 0, 0, 0, 0);
470
shrinkAdj = GTK_ADJUSTMENT(gtk_adjustment_new(image->cfg->shrink,
472
widg = gtk_spin_button_new(shrinkAdj, 1, 0);
473
gtk_table_attach(GTK_TABLE(table), widg, 1, 2, 1, 2, 0, 0, 0, 0);
475
gtk_box_pack_start(GTK_BOX(box), gtk_hseparator_new(), TRUE, TRUE, 0);
476
button = gtk_radio_button_new_with_label(NULL, "8-bit ppm");
477
ppmButton = GTK_TOGGLE_BUTTON(button);
478
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button),
479
image->cfg->type==ppm8_type);
480
g_object_set_data(G_OBJECT(button), "ButtonValue", (gpointer)ppm8_type);
481
g_signal_connect(G_OBJECT(button), "toggled",
482
G_CALLBACK(ufraw_radio_button_update), &image->cfg->type);
483
gtk_box_pack_start(GTK_BOX(box), button, TRUE, TRUE, 0);
485
button = gtk_radio_button_new_with_label_from_widget(
486
GTK_RADIO_BUTTON(button), "16-bit ppm");
487
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button),
488
image->cfg->type==ppm16_type);
489
g_object_set_data(G_OBJECT(button), "ButtonValue", (gpointer)ppm16_type);
490
g_signal_connect(G_OBJECT(button), "toggled",
491
G_CALLBACK(ufraw_radio_button_update), &image->cfg->type);
492
gtk_box_pack_start(GTK_BOX(box), button, TRUE, TRUE, 0);
494
gtk_box_pack_start(GTK_BOX(box), gtk_hseparator_new(), TRUE, TRUE, 0);
495
table = gtk_table_new(5, 1, FALSE);
496
gtk_box_pack_start(GTK_BOX(box), table, TRUE, TRUE, 0);
497
button = gtk_radio_button_new_with_label_from_widget(
498
GTK_RADIO_BUTTON(button), "8-bit TIFF");
499
tiffButton = GTK_TOGGLE_BUTTON(button);
500
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button),
501
image->cfg->type==tiff8_type);
502
g_object_set_data(G_OBJECT(button), "ButtonValue", (gpointer)tiff8_type);
503
g_signal_connect(G_OBJECT(button), "toggled",
504
G_CALLBACK(ufraw_radio_button_update), &image->cfg->type);
505
gtk_table_attach(GTK_TABLE(table), button, 0, 1, 0, 1, 0, 0, 0, 0);
506
button = gtk_radio_button_new_with_label_from_widget(
507
GTK_RADIO_BUTTON(button), "16-bit TIFF");
508
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button),
509
image->cfg->type==tiff16_type);
510
g_object_set_data(G_OBJECT(button), "ButtonValue", (gpointer)tiff16_type);
511
g_signal_connect(G_OBJECT(button), "toggled",
512
G_CALLBACK(ufraw_radio_button_update), &image->cfg->type);
513
gtk_table_attach(GTK_TABLE(table), button, 0, 1, 1, 2, 0, 0, 0, 0);
515
#if !defined(NO_TIFF) && !defined(NO_ZLIB)
516
losslessButton = gtk_check_button_new_with_label("ZIP Compress (lossless)");
517
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(losslessButton),
518
image->cfg->losslessCompress);
519
gtk_table_attach(GTK_TABLE(table), losslessButton, 1, 2, 2, 3, 0, 0, 0, 0);
522
gtk_box_pack_start(GTK_BOX(box), gtk_hseparator_new(), TRUE, TRUE, 0);
523
table = gtk_table_new(5, 1, FALSE);
524
gtk_box_pack_start(GTK_BOX(box), table, TRUE, TRUE, 0);
525
button = gtk_radio_button_new_with_label_from_widget(
526
GTK_RADIO_BUTTON(button), "JPEG");
527
jpegButton = GTK_TOGGLE_BUTTON(button);
528
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button),
529
image->cfg->type==jpeg_type);
530
g_object_set_data(G_OBJECT(button), "ButtonValue", (gpointer)jpeg_type);
531
g_signal_connect(G_OBJECT(button), "toggled",
532
G_CALLBACK(ufraw_radio_button_update), &image->cfg->type);
533
gtk_table_attach(GTK_TABLE(table), button, 0, 1, 0, 1, 0, 0, 0, 0);
534
widg = gtk_label_new("Compression level");
535
gtk_table_attach(GTK_TABLE(table), widg, 1, 2, 1, 2, 0, 0, 0, 0);
536
compressAdj = GTK_ADJUSTMENT(gtk_adjustment_new(image->cfg->compression,
538
widg = gtk_hscale_new(compressAdj);
539
gtk_scale_set_draw_value(GTK_SCALE(widg), FALSE);
540
gtk_table_attach(GTK_TABLE(table), widg, 2, 3, 1, 2,
541
GTK_EXPAND|GTK_FILL, 0, 0, 0);
542
widg = gtk_spin_button_new(compressAdj, 5, 0);
543
gtk_table_attach(GTK_TABLE(table), widg, 3, 4, 1, 2, 0, 0, 0, 0);
545
gtk_box_pack_start(GTK_BOX(box), gtk_hseparator_new(), TRUE, TRUE, 0);
546
overwriteButton = gtk_check_button_new_with_label(
547
"Overwrite existing files without asking");
548
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(overwriteButton),
549
image->cfg->overwrite);
550
gtk_box_pack_start(GTK_BOX(box), overwriteButton, TRUE, TRUE, 0);
551
gtk_widget_show_all(expander);
552
if ( (cp=strrchr(defFilename, '/'))!=NULL) cp++;
553
else if ( (cp=strrchr(defFilename, '\\'))!=NULL) cp++;
554
else cp = defFilename;
555
gtk_file_chooser_set_current_name(fileChooser, cp);
556
if (strlen(image->cfg->inputFilename)>0) {
557
char *cp = g_path_get_dirname(image->cfg->inputFilename);
559
gtk_file_chooser_add_shortcut_folder( fileChooser, cp, NULL);
562
g_signal_connect(G_OBJECT(fileChooser), "selection-changed",
563
G_CALLBACK(ufraw_saver_set_type), image->cfg);
565
status = gtk_dialog_run(GTK_DIALOG(fileChooser));
566
if (status==GTK_RESPONSE_CANCEL) {
567
gtk_widget_destroy(GTK_WIDGET(fileChooser));
568
ufraw_message_handler(UFRAW_SET_PARENT, (char *)parentWindow);
571
if (status==GTK_RESPONSE_APPLY) {
572
gtk_toggle_button_set_active(ppmButton,
573
image->cfg->type==ppm8_type);
574
gtk_toggle_button_set_active(tiffButton,
575
image->cfg->type==tiff8_type);
576
gtk_toggle_button_set_active(jpegButton,
577
image->cfg->type==jpeg_type);
580
filename = gtk_file_chooser_get_filename(fileChooser);
581
image->cfg->interpolation = gtk_combo_box_get_active(intCombo);
582
image->cfg->shrink = gtk_adjustment_get_value(shrinkAdj);
583
image->cfg->overwrite = gtk_toggle_button_get_active(
584
GTK_TOGGLE_BUTTON(overwriteButton));
585
#if !defined(NO_TIFF) && !defined(NO_ZLIB)
586
image->cfg->losslessCompress = gtk_toggle_button_get_active(
587
GTK_TOGGLE_BUTTON(losslessButton));
590
image->cfg->compression = gtk_adjustment_get_value(compressAdj);
592
if (!image->cfg->overwrite && g_file_test(filename, G_FILE_TEST_EXISTS))
595
char message[max_path];
597
dialog = gtk_dialog_new_with_buttons("File exists",
598
GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(fileChooser))),
599
GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR,
600
GTK_STOCK_NO, GTK_RESPONSE_NO,
601
GTK_STOCK_YES, GTK_RESPONSE_YES, NULL);
602
snprintf(message, max_path,
603
"File '%s' already exists.\nOverwrite?", filename);
604
widg = gtk_label_new(message);
605
gtk_label_set_line_wrap(GTK_LABEL(widg), TRUE);
606
gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), widg);
607
gtk_widget_show_all(dialog);
608
response = gtk_dialog_run(GTK_DIALOG(dialog));
609
gtk_widget_destroy(dialog);
610
if (response!=GTK_RESPONSE_YES)
613
status = ufraw_write_image(image, filename);
615
if (status==UFRAW_SUCCESS || status==UFRAW_ABORT_SAVE) {
616
gtk_widget_destroy(GTK_WIDGET(fileChooser));
617
ufraw_message_handler(UFRAW_SET_PARENT, (char *)parentWindow);
618
if (status==UFRAW_SUCCESS)
619
g_object_set_data(G_OBJECT(parentWindow), "WindowResponse",
620
(gpointer)GTK_RESPONSE_OK);
622
g_object_set_data(G_OBJECT(parentWindow), "WindowResponse",
623
(gpointer)GTK_RESPONSE_CANCEL);
625
return UFRAW_SUCCESS;
631
void ufraw_tiff_message(const char *module, const char *fmt, va_list ap)
635
vsnprintf(buf, max_path, fmt, ap);
636
ufraw_message(UFRAW_VERBOSE, buf);
641
void ufraw_jpeg_message(j_common_ptr cinfo)
643
ufraw_message(UFRAW_VERBOSE, cinfo->err->jpeg_message_table
644
[cinfo->err->msg_code],
645
cinfo->err->msg_parm.i[0],
646
cinfo->err->msg_parm.i[1],
647
cinfo->err->msg_parm.i[2],
648
cinfo->err->msg_parm.i[3]);
652
int ufraw_write_image(image_data *image, char *outFilename)
654
void *out; /* out is a pointer to FILE or TIFF */
655
int row, rowStride, i, status=UFRAW_SUCCESS;
656
image_type *rawImage;
657
guint8 *pixbuf8=NULL;
661
ufraw_message(UFRAW_CLEAN, NULL);
663
if (image->cfg->type==tiff8_type || image->cfg->type==tiff16_type) {
664
TIFFSetErrorHandler(ufraw_tiff_message);
665
TIFFSetWarningHandler(ufraw_tiff_message);
666
if ( (out=TIFFOpen(outFilename, "w"))==NULL ) {
667
message=ufraw_message_handler(UFRAW_GET_MESSAGE, NULL);
668
ufraw_message(UFRAW_ERROR, "Error creating file '%s'.\n%s",
669
outFilename, message);
674
if ( (out=fopen(outFilename, "wb"))==NULL) {
675
ufraw_message(UFRAW_ERROR, "Error creating file '%s': %s",
676
outFilename, g_strerror(errno));
679
ufraw_convert_image(image, image);
680
ufraw_message(UFRAW_CLEAN, NULL);
681
rowStride = image->width + 2*image->trim;
682
rawImage = image->image + image->trim*rowStride + image->trim;
683
pixbuf16 = g_new(guint16, image->width*3);
684
if (image->cfg->type==ppm8_type) {
685
fprintf(out, "P6\n%d %d\n%d\n", image->width, image->height, 0xFF);
686
pixbuf8 = g_new(guint8, image->width*3);
687
for (row=0; row<image->height; row++) {
689
preview_progress("Saving image", 0.5 + 0.5*row/image->height);
690
develope(pixbuf8, rawImage[row*rowStride],
691
image->developer, 8, pixbuf16, image->width);
692
if ((int)fwrite(pixbuf8, 3, image->width, out)<image->width) {
693
ufraw_message(UFRAW_ERROR, "Error creating file '%s': %s.",
694
outFilename, g_strerror(errno));
695
status = UFRAW_ABORT_SAVE;
699
} else if (image->cfg->type==ppm16_type) {
700
fprintf(out, "P6\n%d %d\n%d\n", image->width, image->height, 0xFFFF);
701
for (row=0; row<image->height; row++) {
703
preview_progress("Saving image", 0.5 + 0.5*row/image->height);
704
develope(pixbuf16, rawImage[row*rowStride],
705
image->developer, 16, pixbuf16, image->width);
706
for (i=0; i<3*image->width; i++)
707
pixbuf16[i] = g_htons(pixbuf16[i]);
708
if ((int)fwrite(pixbuf16, 6, image->width, out)<image->width) {
709
ufraw_message(UFRAW_ERROR, "Error creating file '%s': %s.",
710
outFilename, g_strerror(errno));
711
status = UFRAW_ABORT_SAVE;
716
} else if (image->cfg->type==tiff8_type ||
717
image->cfg->type==tiff16_type) {
718
TIFFSetField(out, TIFFTAG_IMAGEWIDTH, image->width);
719
TIFFSetField(out, TIFFTAG_IMAGELENGTH, image->height);
720
TIFFSetField(out, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
721
TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, 3);
722
if (image->cfg->type==tiff8_type)
723
TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, 8);
725
TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, 16);
726
TIFFSetField(out, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
727
TIFFSetField(out, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
729
if (image->cfg->losslessCompress) {
730
TIFFSetField(out, TIFFTAG_COMPRESSION, COMPRESSION_DEFLATE);
731
TIFFSetField(out, TIFFTAG_ZIPQUALITY, 9);
735
TIFFSetField(out, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
736
/* Embed output profile if it is not the internal sRGB*/
737
if (strcmp(image->developer->file[out_profile], "")) {
740
if (g_file_get_contents(image->developer->file[out_profile],
742
TIFFSetField(out, TIFFTAG_ICCPROFILE, len, buf);
744
} else ufraw_message(UFRAW_WARNING,
745
"Failed to embed output profile '%s' in '%s'",
746
image->developer->file[out_profile], outFilename);
748
TIFFSetField(out, TIFFTAG_ROWSPERSTRIP, TIFFDefaultStripSize(out, 0));
749
if (image->cfg->type==tiff8_type) {
750
pixbuf8 = g_new(guint8, image->width*3);
751
for (row=0; row<image->height; row++) {
753
preview_progress("Saving image", 0.5+0.5*row/image->height);
754
develope(pixbuf8, rawImage[row*rowStride],
755
image->developer, 8, pixbuf16, image->width);
756
if (TIFFWriteScanline(out, pixbuf8, row, 0)<0) {
757
message=ufraw_message_handler(UFRAW_GET_MESSAGE, NULL);
758
ufraw_message(UFRAW_ERROR, "Error creating file '%s'.\n%s",
759
outFilename, message);
760
status = UFRAW_ABORT_SAVE;
765
for (row=0; row<image->height; row++) {
767
preview_progress("Saving image", 0.5+0.5*row/image->height);
768
develope(pixbuf16, rawImage[row*rowStride],
769
image->developer, 16, pixbuf16, image->width);
770
if (TIFFWriteScanline(out, pixbuf16, row, 0)<0) {
771
message=ufraw_message_handler(UFRAW_GET_MESSAGE, NULL);
772
ufraw_message(UFRAW_ERROR, "Error creating file '%s'.\n%s",
773
outFilename, message);
774
status = UFRAW_ABORT_SAVE;
781
} else if (image->cfg->type==jpeg_type) {
782
struct jpeg_compress_struct cinfo;
783
struct jpeg_error_mgr jerr;
785
cinfo.err = jpeg_std_error(&jerr);
786
cinfo.err->output_message = ufraw_jpeg_message;
787
cinfo.err->error_exit = ufraw_jpeg_message;
788
jpeg_create_compress(&cinfo);
789
jpeg_stdio_dest(&cinfo, out);
790
cinfo.image_width = image->width;
791
cinfo.image_height = image->height;
792
cinfo.input_components = 3;
793
cinfo.in_color_space = JCS_RGB;
794
jpeg_set_defaults(&cinfo);
795
jpeg_set_quality(&cinfo, image->cfg->compression, TRUE);
796
/* Embed output profile if it is not the internal sRGB*/
797
if (strcmp(image->developer->file[out_profile], "")) {
800
if (g_file_get_contents(image->developer->file[out_profile],
802
write_icc_profile(&cinfo, buf, len);
804
} else ufraw_message(UFRAW_WARNING,
805
"Failed to embed output profile '%s' in '%s'",
806
image->developer->file[out_profile], outFilename);
808
jpeg_start_compress(&cinfo, TRUE);
809
message=ufraw_message_handler(UFRAW_GET_MESSAGE, NULL);
810
pixbuf8 = g_new(guint8, image->width*3);
811
for (row=0; row<image->height; row++) {
813
preview_progress("Saving image", 0.5 + 0.5*row/image->height);
814
develope(pixbuf8, rawImage[row*rowStride],
815
image->developer, 8, pixbuf16, image->width);
816
jpeg_write_scanlines(&cinfo, &pixbuf8, 1);
817
message=ufraw_message_handler(UFRAW_GET_MESSAGE, NULL);
818
if (message!=NULL ) break;
820
if (message==NULL) jpeg_finish_compress(&cinfo);
821
jpeg_destroy_compress(&cinfo);
822
if ( (message=ufraw_message_handler(UFRAW_GET_MESSAGE, NULL))!=NULL) {
823
ufraw_message(UFRAW_ERROR, "Error creating file '%s'.\n%s",
824
outFilename, message);
825
status = UFRAW_ABORT_SAVE;
829
ufraw_message(UFRAW_ERROR,
830
"Error creating file '%s'. Unknown file type %d.",
831
outFilename, image->cfg->type);
832
status = UFRAW_ABORT_SAVE;
837
if (image->cfg->type==tiff8_type || image->cfg->type==tiff16_type) {
839
if ( (message=ufraw_message_handler(UFRAW_GET_MESSAGE, NULL))!=NULL) {
840
ufraw_message(UFRAW_ERROR, "Error creating file '%s'.\n%s",
841
outFilename, message);
842
status = UFRAW_ABORT_SAVE;
847
if (status==UFRAW_SUCCESS)
848
g_strlcpy(image->cfg->outputFilename, outFilename, max_path);
852
void ufraw_chooser(cfg_data *cfg)
855
GtkFileChooser *fileChooser;
856
GSList *list, *saveList;
857
GtkFileFilter *filter;
859
char **extList, **l, ext[max_name];
861
fileChooser = GTK_FILE_CHOOSER(gtk_file_chooser_dialog_new("UFRaw", NULL,
862
GTK_FILE_CHOOSER_ACTION_OPEN,
863
GTK_STOCK_QUIT, GTK_RESPONSE_CANCEL,
864
GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL));
865
gtk_window_set_icon(GTK_WINDOW(fileChooser),
866
gdk_pixbuf_new_from_inline(-1, ufraw_icon, FALSE, NULL));
867
ufraw_message_handler(UFRAW_SET_PARENT, (char *)fileChooser);
868
filter = GTK_FILE_FILTER(gtk_file_filter_new());
869
gtk_file_filter_set_name(filter, "Raw images");
870
extList = g_strsplit(raw_ext, ",", 100);
871
for (l=extList; *l!=NULL; l++)
872
if (strcmp(*l, "jpg") && strcmp(*l, "tif")) {
873
snprintf(ext, max_name, "*.%s", *l);
874
gtk_file_filter_add_pattern(filter, ext);
875
gtk_file_filter_add_pattern(filter, cp=g_ascii_strup(ext,-1));
879
gtk_file_chooser_add_filter(fileChooser, filter);
880
filter = GTK_FILE_FILTER(gtk_file_filter_new());
881
gtk_file_filter_set_name(filter, "Raw jpg's");
882
gtk_file_filter_add_pattern(filter, "*.jpg");
883
gtk_file_filter_add_pattern(filter, "*.JPG");
884
gtk_file_chooser_add_filter(fileChooser, filter);
885
filter = GTK_FILE_FILTER(gtk_file_filter_new());
886
gtk_file_filter_set_name(filter, "Raw tif's");
887
gtk_file_filter_add_pattern(filter, "*.tif");
888
gtk_file_filter_add_pattern(filter, "*.TIF");
889
gtk_file_chooser_add_filter(fileChooser, filter);
890
filter = GTK_FILE_FILTER(gtk_file_filter_new());
891
gtk_file_filter_set_name(filter, "All files");
892
gtk_file_filter_add_pattern(filter, "*");
893
gtk_file_chooser_add_filter(fileChooser, filter);
894
gtk_widget_show(GTK_WIDGET(fileChooser));
895
gtk_file_chooser_set_select_multiple(fileChooser, TRUE);
896
/* Add shortcut to folder of last opened file */
897
if (strlen(cfg->inputFilename)>0) {
898
char *cp = g_path_get_dirname(cfg->inputFilename);
899
gtk_file_chooser_add_shortcut_folder( fileChooser, cp, NULL);
902
while (gtk_dialog_run(GTK_DIALOG(fileChooser))==GTK_RESPONSE_ACCEPT) {
903
for(list=saveList=gtk_file_chooser_get_filenames(fileChooser);
904
list!=NULL; list=g_slist_next(list)) {
905
filename = list->data;
906
image = ufraw_open(filename);
908
ufraw_message(UFRAW_REPORT, NULL);
911
ufraw_config(image, cfg);
912
ufraw_preview(image, FALSE, ufraw_saver);
915
g_slist_free(saveList);
917
gtk_widget_destroy(GTK_WIDGET(fileChooser));
918
ufraw_message_handler(UFRAW_SET_PARENT, NULL);