Logo Search packages:      
Sourcecode: ufraw version File versions

ufraw.c

/*
 * UFRaw - Unidentified Flying Raw converter for digital camera images
 * by Udi Fuchs
 *
 * ufraw.c - The standalone interface to UFRaw.
 *
 * UFRaw is licensed under the GNU General Public License.
 * It uses DCRaw code to do the actual raw decoding.
 */

#include <stdio.h>     /* for printf */
#include <stdlib.h>    /* for exit */
#include <errno.h>     /* for errno */
#include <string.h>
#include <math.h>      /* for isnan */
#include <getopt.h>
#include <glib.h>
#include <gtk/gtk.h>
#include <locale.h>
#ifndef NO_TIFF
#include <tiffio.h>
#endif
#ifndef NO_JPEG
#include <jpeglib.h>
#include "iccjpeg.h"
#endif
#include "ufraw.h"
#include "ufraw_icon.h"

#define NULLF -10000

char helpText[]=
"UFRaw 0.3 - Unidentified Flying Raw converter for digital camera images.\n"
"\n"
"Usage: ufraw [ options ... ] [ raw-image-files ... ]\n"
"\n"
"By default UFRaw displays a preview window for each raw image allowing\n"
"the user to tweak the image parameters before saving. If no raw images\n"
"are given at the command line, UFRaw will display a file chooser dialog.\n"
"To process the images with no questions asked (and no preview) use\n"
"the --batch option. The rest of the options are separated into two groups.\n"
"The options which are related to the image manipulation are:\n"
"\n"
"--wb=camera|auto      White balance setting.\n"
"--temperature=TEMP    Color temperature in Kelvins (2000 - 7000).\n"
"--green=GREEN         Green color normalization.\n"
"--curve=gamma|log|linear|camera\n"
"                      Type of tone curve to use (default camera if such\n"
"                      exsists, log otherwise).\n"
"--[no]unclip          Unclip [clip] highlights.\n"
"--contrast=CONTRAST   Contrast adjustment (default 1.0).\n"
"--gamma=GAMMA         Gamma adjustment (default 0.45).\n"
"--saturation=SAT      Saturation adjustment (default 1.0, 0 for B&W output).\n"
"--shadow=SHADOW       Suppress enhance shadow details (default 0).\n"
"--shadow-depth=DEPTH  Define what are shadows (default 0.1).\n"
"--exposure=EXPOSURE   Exposure correction in EV (default 0).\n"
"--black-point=BLACK   Set black point (default 0).\n"
"\n"
"The options which are related to the final output are:\n"
"\n"
"--interpolation=full|four-color|quick|half\n"
"                      Interpolation algorithm to use (default full).\n"
"--shrink=FACTOR       Shrink the image by FACTOR (default 1).\n"
"--out-type=ppm8|ppm16|tiff8|tiff16|jpeg\n"
"                      Output file formati (default ppm8).\n"
"--compression=VALUE   JPEG compression (0-100, default 85).\n"
"--[no]zip             Enable [disable] TIFF zip compression (default nozip).\n"
"--out-path=PATH       PATH for output file (default use input file's path).\n"
"--overwrite           Overwrite existing files without asking (default no).\n"
"\n"
"UFRaw first reads the setting from the configuration file $HOME/.ufrawrc\n"
"and then sets the options from the command line. In batch mode, the second\n"
"group of options is NOT read from the configuration file, and therefore,\n"
"must be specified explicitly if non-default values are desired.\n"
"\n"
"Last, but not least, --help displays this help message and exits.\n";

int ufraw_saver(GtkWidget *widget, gpointer user_data);
int ufraw_write_image(image_data *image, char *outFilename);
void ufraw_chooser(cfg_data *cfg);

int main (int argc, char **argv)
{
    image_data *image;
    cfg_data cfg;
    GtkWidget *dummyWindow=NULL;
    int c;
    int index=0;
    char *wbName=NULL;
    gboolean batch=FALSE, unclip=-1, losslessCompress=-1, overwrite=-1;
    char *curveName=NULL, *outTypeName=NULL, *outPath=NULL;
    int curveType;
    float contrast=NULLF, gamma=NULLF, saturation=NULLF, shadow=NULLF,
        shadowDepth=NULLF, blackPoint=NULLF, exposure=NULLF,
        temperature=NULLF, green=NULLF, compression=NULLF;
    char *interpolationName=NULL;
    float shrink = NULLF;
    static struct option options[] = {
        {"wb", 1, 0, 'w'},
        {"temperature", 1, 0, 't'},
        {"green", 1, 0, 'g'},
        {"curve", 1, 0, 'c'},
        {"contrast", 1, 0, 'C'},
        {"gamma", 1, 0, 'G'},
        {"saturation", 1, 0, 's'},
        {"shadow", 1, 0, 'S'},
        {"shadow-depth", 1, 0, 'd'},
        {"exposure", 1, 0, 'e'},
        {"black-point", 1, 0, 'k'},
        {"interpolation", 1, 0, 'i'},
        {"shrink", 1, 0, 'x'},
        {"compression", 1, 0, 'j'},
        {"out-type", 1, 0, 'T'},
        {"out-path", 1, 0, 'p'},
/* Binary flags that don't have a value are here at the end */
        {"batch", 0, 0, 'B'},
        {"unclip", 0, 0, 'u'},
        {"nounclip", 0, 0, 'U'},
        {"zip", 0, 0, 'z'},
        {"nozip", 0, 0, 'Z'},
        {"overwrite", 0, 0, 'o'},
        {"help", 0, 0, 'h'},
        {0, 0, 0, 0}
    };
    void *optPointer[] = { &wbName, &temperature, &green, &curveName,
        &contrast, &gamma, &saturation, &shadow, &shadowDepth,
        &exposure, &blackPoint, &interpolationName, &shrink,
        &compression, &outTypeName, &outPath };
    const char *locale;

    locale = setlocale(LC_ALL, "");
    if ( locale!=NULL &&
        (!strncmp(locale, "he", 2) || !strncmp(locale, "iw", 2) ||
        !strncmp(locale, "ar", 2) ||
        !strncmp(locale, "Hebrew", 6) || !strncmp(locale, "Arabic", 6) ) ) {
        /* I'm not sure why the following doesn't work (on Windows at least) */
/*        locale = setlocale(LC_ALL, "en_US");
        gtk_disable_setlocale(); */
        /* so I'm using setenv */
        g_setenv("LC_ALL", "en_US", TRUE);
    }
    gtk_init(&argc, &argv);
    while (1) {
        c = getopt_long (argc, argv, "", options, &index);
        if (c == -1) break;
        switch (c) {
        case 't':
        case 'g':
        case 'C':
        case 'G':
        case 's':
        case 'S':
        case 'd':
        case 'e':
        case 'k':
        case 'x':
        case 'j':
            if (sscanf(optarg, "%f", (float *)optPointer[index])==0){
                ufraw_message(UFRAW_ERROR,
                    "ufraw: '%s' is not a valid value for the --%s option.\n",
                    optarg, options[index].name);
                exit(1);
            }
            break;
        case 'w':
        case 'c':
        case 'i':
        case 'T':
        case 'p':
            *(char **)optPointer[index] = optarg;
            break;
        case 'B': batch = TRUE; break;
        case 'u': unclip = TRUE; break;
        case 'U': unclip = FALSE; break;
        case 'o': overwrite = TRUE; break;
        case 'z':
#ifdef NO_ZLIB
            ufraw_message(UFRAW_ERROR,
                "ufraw: ufraw was build without ZIP support.\n");
            exit(1);
#else
            losslessCompress = TRUE; break;
#endif
        case 'Z': losslessCompress = FALSE; break;
        case 'h':
            fprintf(stderr, helpText);
            exit(0);
        case '?': /* invalid option. Warning printed by getopt() */
            exit(1);
        default:
            ufraw_message(UFRAW_ERROR, "getopt returned "
                       "character code 0%o ??\n", c);
            exit(1);
        }
    }
    if (!batch) {
        dummyWindow = gtk_window_new(GTK_WINDOW_TOPLEVEL);
        gtk_window_set_icon(GTK_WINDOW(dummyWindow),
                gdk_pixbuf_new_from_inline(-1, ufraw_icon, FALSE, NULL));
        ufraw_message_handler(UFRAW_SET_PARENT, (char *)dummyWindow);
    }
    ufraw_config(NULL, &cfg);
    if (outPath!=NULL) {
        if (g_file_test(outPath, G_FILE_TEST_IS_DIR))
             g_strlcpy(cfg.outputFilename, outPath, max_path);
        else {
            ufraw_message(UFRAW_ERROR, "'%s' is not a valid path.\n", outPath);
            exit(1);
        }
    }
    if (batch) {
        /* The save options are always set to default */
        if (cfg.interpolation!=four_color_interpolation)
            cfg.interpolation = full_interpolation;
        cfg.shrink = cfg_default.shrink;
        cfg.type = cfg_default.type;
        cfg.compression = cfg_default.compression;
        cfg.losslessCompress = cfg_default.losslessCompress;
        /* Disable some of the resetting done in ufraw_config() */
        cfg.wbLoad = load_preserve;
        if (temperature!=NULLF || green!=NULLF) cfg.wb = preserve_wb;
        cfg.curveLoad = load_preserve;
        if (cfg.exposureLoad!=load_auto ||
                exposure!=NULLF || blackPoint!=NULLF)
            cfg.exposureLoad = load_preserve;
        if (isnan(cfg.exposure) && exposure==NULLF && blackPoint!=NULLF)
            exposure = cfg_default.exposure;
        if (outPath==NULL) outPath = "";
        cfg.overwrite = FALSE;
    }
    if (overwrite!=-1) cfg.overwrite = overwrite;
    if (unclip!=-1) cfg.unclip = unclip;
    if (losslessCompress!=-1) cfg.losslessCompress = losslessCompress;
    if (compression!=NULLF) cfg.compression = compression;
    if (exposure!=NULLF) cfg.exposure = exposure;
    if (temperature!=NULLF) cfg.temperature = temperature;
    if (green!=NULLF) cfg.green = green;
    if (shrink!=NULLF) cfg.shrink = shrink;
    if (wbName!=NULL) {
        if (!strcmp(wbName, "camera")) cfg.wb = camera_wb;
        else if (!strcmp(wbName, "auto")) cfg.wb = auto_wb;
        else {
            ufraw_message(UFRAW_ERROR,
                "'%s' is not a valid white balance option.\n", wbName);
            exit(1);
        }
    }
    curveType = camera_curve;
    if (curveName!=NULL) {
        if (!strcmp(curveName, "gamma")) cfg.curveIndex = gamma_curve;
        else if (!strcmp(curveName, "log")) cfg.curveIndex = log_curve;
        else if (!strcmp(curveName, "linear")) cfg.curveIndex=linear_curve;
        else if (!strcmp(curveName, "camera")) cfg.curveIndex=camera_curve;
        else {
            ufraw_message(UFRAW_ERROR,
                "'%s' is not a valid curve name.\n", curveName);
            exit(1);
        }
    }
    if (contrast!=NULLF) cfg.curve[cfg.curveIndex].contrast = contrast;
    if (gamma!=NULLF) cfg.curve[cfg.curveIndex].gamma = gamma;
    if (saturation!=NULLF) cfg.curve[cfg.curveIndex].saturation=saturation;
    if (shadow!=NULLF) cfg.curve[cfg.curveIndex].shadow = shadow;
    if (shadowDepth!=NULLF) cfg.curve[cfg.curveIndex].depth = shadowDepth;
    if (blackPoint!=NULLF) cfg.curve[cfg.curveIndex].black = blackPoint;
    if (interpolationName!=NULL) {
        if (!strcmp(interpolationName, "full"))
            cfg.interpolation = full_interpolation;
        else if (!strcmp(interpolationName, "four-color"))
            cfg.interpolation = four_color_interpolation;
        else if (!strcmp(interpolationName, "quick"))
            cfg.interpolation = quick_interpolation;
        else if (!strcmp(interpolationName, "half"))
            cfg.interpolation = half_interpolation;
        else {
            ufraw_message(UFRAW_ERROR,
                "'%s' is not a valid interpolation option.\n",
                interpolationName);
            exit(1);
        }
    }
    if (outTypeName!=NULL) {
        if (!strcmp(outTypeName, "ppm8"))
            cfg.type = ppm8_type;
        else if (!strcmp(outTypeName, "ppm16"))
            cfg.type = ppm16_type;
        else if (!strcmp(outTypeName, "tiff8"))
#ifdef NO_TIFF
        {
            ufraw_message(UFRAW_ERROR,
                "ufraw was build without TIFF support.\n");
            exit(1);
        }
#else
        cfg.type = tiff8_type;
#endif
        else if (!strcmp(outTypeName, "tiff16"))
#ifdef NO_TIFF
        {
            ufraw_message(UFRAW_ERROR,
                "ufraw was build without TIFF support.\n");
            exit(1);
        }
#else
        cfg.type = tiff16_type;
#endif
        else if (!strcmp(outTypeName, "jpeg"))
#ifdef NO_JPEG
        {
            ufraw_message(UFRAW_ERROR,
                "ufraw was build without JPEG support.\n");
            exit(1);
        }
#else
        cfg.type = jpeg_type;
#endif
        else {
            ufraw_message(UFRAW_ERROR,
                "'%s' is not a valid output type.\n", outTypeName);
            exit(1);
        }
    }
    if (optind==argc) {
        if (batch) ufraw_message(UFRAW_WARNING, 
                "no input file, nothing to do.\n")
        else ufraw_chooser(&cfg);
        exit(0);
    }
    for (; optind<argc; optind++) {
        image = ufraw_open(argv[optind]);
        if (image==NULL) {
            ufraw_message(UFRAW_REPORT, NULL);
            continue;    
        }
        ufraw_config(image, &cfg);
        if (batch) {
            if (ufraw_load_raw(image, FALSE)!=UFRAW_SUCCESS)
                continue;
            ufraw_message(UFRAW_MESSAGE, "loaded %s\n",
                image->filename);
            g_strlcpy(cfg.outputFilename, outPath, max_path);
            if (ufraw_saver(NULL, image)==UFRAW_SUCCESS)
                ufraw_message(UFRAW_MESSAGE, "saved %s\n", cfg.outputFilename);
            ufraw_close(image);
            g_free(image);
        } else {
            ufraw_preview(image, FALSE, ufraw_saver);
        }
    }
    if (dummyWindow!=NULL) gtk_widget_destroy(dummyWindow);
    exit(0);
}

void ufraw_radio_button_update(GtkWidget *button, int *valuep)
{
    char *filename, newFilename[max_path], *cp;
    GtkWidget *dialog = gtk_widget_get_ancestor(button, GTK_TYPE_DIALOG);
    if (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button)))
        return;
    *valuep = (long)g_object_get_data(G_OBJECT(button), "ButtonValue");
    filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
    g_strlcpy(newFilename, filename, max_path);
    g_free(filename);
    if ( (cp=strrchr(newFilename, '.'))!=NULL) *cp= '\0';
    g_strlcat(newFilename, file_type[*valuep], max_path);
    if ( (cp=strrchr(newFilename, '/'))!=NULL) cp++;
    else if ( (cp=strrchr(newFilename, '\\'))!=NULL) cp++;
    else cp = newFilename;
    gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), cp);
}

void ufraw_saver_set_type(GtkWidget *widget, cfg_data *cfg)
{
    char *filename, *type;
    filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(widget));
    type = strrchr(filename, '.');
    if (type==NULL) {
        g_free(filename);
        return;
    }
    if (!strcmp(type,".ppm") && cfg->type!=ppm16_type)
        cfg->type = ppm8_type;
    if (!strcmp(type,".tif") && cfg->type!=tiff16_type)
        cfg->type = tiff8_type;
    if (!strcmp(type,".jpg"))
        cfg->type = jpeg_type;
    g_free(filename);
    gtk_dialog_response(GTK_DIALOG(widget), GTK_RESPONSE_APPLY);
}

int ufraw_saver(GtkWidget *widget, gpointer user_data)
{
    GtkWindow *parentWindow;
    GtkFileChooser *fileChooser;
    GtkWidget *expander, *box, *table, *widg, *button, *overwriteButton;
    GtkAdjustment *shrinkAdj;
    GtkComboBox *intCombo;
    GtkToggleButton *ppmButton, *tiffButton, *jpegButton;
#if !defined(NO_TIFF) && !defined(NO_ZLIB)
    GtkWidget *losslessButton;
#endif
#ifndef NO_JPEG
    GtkAdjustment *compressAdj;
#endif
    image_data *image = user_data;
    char *filename, defFilename[max_path], *cp;
    int status;

    g_strlcpy(defFilename, image->filename, max_path);
    if ( (cp=strrchr(defFilename, '.'))!=NULL) *cp= '\0';
    g_strlcat(defFilename, file_type[image->cfg->type], max_path);
    if (widget==NULL) {
        if (strlen(image->cfg->outputFilename)>0) {
            cp = g_path_get_basename(defFilename);
            filename = g_build_filename(image->cfg->outputFilename, cp , NULL);
            g_strlcpy(defFilename, filename, max_path);
            g_free(filename);
            g_free(cp);
        }
        if (!image->cfg->overwrite) {
            if (g_file_test(defFilename, G_FILE_TEST_EXISTS)) {
                char ans;
                fprintf(stderr, "ufraw: overwrite '%s'? [y/N] ", defFilename);
                fflush(stderr);
                scanf("%c", &ans);
                if (ans!='y' && ans!='Y') return UFRAW_CANCEL;
            }
        }
        return ufraw_write_image(image, defFilename);
    }
    parentWindow = GTK_WINDOW(gtk_widget_get_toplevel(widget));
    fileChooser = GTK_FILE_CHOOSER(gtk_file_chooser_dialog_new(
            "Save image", parentWindow, GTK_FILE_CHOOSER_ACTION_SAVE,
            GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
            GTK_STOCK_SAVE, GTK_RESPONSE_OK, NULL));
    gtk_dialog_set_default_response(GTK_DIALOG(fileChooser), GTK_RESPONSE_OK);
    ufraw_message_handler(UFRAW_SET_PARENT, (char *)fileChooser);
    if (strlen(image->cfg->outputFilename)>0) {
        if (g_path_is_absolute(image->cfg->outputFilename))
            gtk_file_chooser_set_current_folder(fileChooser,
                    image->cfg->outputFilename);
        else {
            char *cd = g_get_current_dir();
            char *fn = g_build_filename(cd, image->cfg->outputFilename, NULL);
            gtk_file_chooser_set_current_folder(fileChooser, fn);
            g_free(cd);
            g_free(fn);
        }
    }
    expander = gtk_expander_new("Output options");
    gtk_expander_set_expanded(GTK_EXPANDER(expander), TRUE);
    gtk_file_chooser_set_extra_widget(fileChooser, expander);
    box = gtk_vbox_new(FALSE, 0);
    gtk_container_add(GTK_CONTAINER(expander), box);
    table = gtk_table_new(5, 1, FALSE);
    gtk_box_pack_start(GTK_BOX(box), table, TRUE, TRUE, 0);
    if (image->cfg->interpolation==half_interpolation) {
        image->cfg->interpolation = full_interpolation;
        if (image->cfg->shrink<2) image->cfg->shrink = 2;
    }
    intCombo = GTK_COMBO_BOX(gtk_combo_box_new_text());
    gtk_combo_box_append_text(intCombo, "Full interpolation");
    gtk_combo_box_append_text(intCombo, "Four color interpolation");
    gtk_combo_box_append_text(intCombo, "Quick interpolation");
    gtk_combo_box_set_active(intCombo, image->cfg->interpolation);
    gtk_table_attach(GTK_TABLE(table), GTK_WIDGET(intCombo),
                0, 3, 0, 1, 0, 0, 0, 0);
    widg = gtk_label_new("Shrink factor");
    gtk_table_attach(GTK_TABLE(table), widg, 0, 1, 1, 2, 0, 0, 0, 0);
    shrinkAdj = GTK_ADJUSTMENT(gtk_adjustment_new(image->cfg->shrink,
            1, 100, 1, 2, 0));
    widg = gtk_spin_button_new(shrinkAdj, 1, 0);
    gtk_table_attach(GTK_TABLE(table), widg, 1, 2, 1, 2, 0, 0, 0, 0);

    gtk_box_pack_start(GTK_BOX(box), gtk_hseparator_new(), TRUE, TRUE, 0);
    button = gtk_radio_button_new_with_label(NULL, "8-bit ppm");
    ppmButton = GTK_TOGGLE_BUTTON(button);
    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button),
            image->cfg->type==ppm8_type);
    g_object_set_data(G_OBJECT(button), "ButtonValue", (gpointer)ppm8_type);
    g_signal_connect(G_OBJECT(button), "toggled",
            G_CALLBACK(ufraw_radio_button_update), &image->cfg->type);
    gtk_box_pack_start(GTK_BOX(box), button, TRUE, TRUE, 0);

    button = gtk_radio_button_new_with_label_from_widget(
            GTK_RADIO_BUTTON(button), "16-bit ppm");
    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button),
            image->cfg->type==ppm16_type);
    g_object_set_data(G_OBJECT(button), "ButtonValue", (gpointer)ppm16_type);
    g_signal_connect(G_OBJECT(button), "toggled",
            G_CALLBACK(ufraw_radio_button_update), &image->cfg->type);
    gtk_box_pack_start(GTK_BOX(box), button, TRUE, TRUE, 0);
#ifndef NO_TIFF
    gtk_box_pack_start(GTK_BOX(box), gtk_hseparator_new(), TRUE, TRUE, 0);
    table = gtk_table_new(5, 1, FALSE);
    gtk_box_pack_start(GTK_BOX(box), table, TRUE, TRUE, 0);
    button = gtk_radio_button_new_with_label_from_widget(
            GTK_RADIO_BUTTON(button), "8-bit TIFF");
    tiffButton = GTK_TOGGLE_BUTTON(button);
    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button),
            image->cfg->type==tiff8_type);
    g_object_set_data(G_OBJECT(button), "ButtonValue", (gpointer)tiff8_type);
    g_signal_connect(G_OBJECT(button), "toggled",
            G_CALLBACK(ufraw_radio_button_update), &image->cfg->type);
    gtk_table_attach(GTK_TABLE(table), button, 0, 1, 0, 1, 0, 0, 0, 0);
    button = gtk_radio_button_new_with_label_from_widget(
            GTK_RADIO_BUTTON(button), "16-bit TIFF");
    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button),
            image->cfg->type==tiff16_type);
    g_object_set_data(G_OBJECT(button), "ButtonValue", (gpointer)tiff16_type);
    g_signal_connect(G_OBJECT(button), "toggled",
            G_CALLBACK(ufraw_radio_button_update), &image->cfg->type);
    gtk_table_attach(GTK_TABLE(table), button, 0, 1, 1, 2, 0, 0, 0, 0);
#endif /*NO_TIFF*/
#if !defined(NO_TIFF) && !defined(NO_ZLIB)
    losslessButton = gtk_check_button_new_with_label("ZIP Compress (lossless)");
    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(losslessButton),
                    image->cfg->losslessCompress);
    gtk_table_attach(GTK_TABLE(table), losslessButton, 1, 2, 2, 3, 0, 0, 0, 0);
#endif
#ifndef NO_JPEG
    gtk_box_pack_start(GTK_BOX(box), gtk_hseparator_new(), TRUE, TRUE, 0);
    table = gtk_table_new(5, 1, FALSE);
    gtk_box_pack_start(GTK_BOX(box), table, TRUE, TRUE, 0);
    button = gtk_radio_button_new_with_label_from_widget(
            GTK_RADIO_BUTTON(button), "JPEG");
    jpegButton = GTK_TOGGLE_BUTTON(button);
    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button),
            image->cfg->type==jpeg_type);
    g_object_set_data(G_OBJECT(button), "ButtonValue", (gpointer)jpeg_type);
    g_signal_connect(G_OBJECT(button), "toggled",
            G_CALLBACK(ufraw_radio_button_update), &image->cfg->type);
    gtk_table_attach(GTK_TABLE(table), button, 0, 1, 0, 1, 0, 0, 0, 0);
    widg = gtk_label_new("Compression level");
    gtk_table_attach(GTK_TABLE(table), widg, 1, 2, 1, 2, 0, 0, 0, 0);
    compressAdj = GTK_ADJUSTMENT(gtk_adjustment_new(image->cfg->compression,
            0, 100, 5, 10, 0));
    widg = gtk_hscale_new(compressAdj);
    gtk_scale_set_draw_value(GTK_SCALE(widg), FALSE);
    gtk_table_attach(GTK_TABLE(table), widg, 2, 3, 1, 2,
            GTK_EXPAND|GTK_FILL, 0, 0, 0);
    widg = gtk_spin_button_new(compressAdj, 5, 0);
    gtk_table_attach(GTK_TABLE(table), widg, 3, 4, 1, 2, 0, 0, 0, 0);
#endif /*NO_JPEG*/
    gtk_box_pack_start(GTK_BOX(box), gtk_hseparator_new(), TRUE, TRUE, 0);
    overwriteButton = gtk_check_button_new_with_label(
            "Overwrite existing files without asking");
    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(overwriteButton),
            image->cfg->overwrite);
    gtk_box_pack_start(GTK_BOX(box), overwriteButton, TRUE, TRUE, 0);
    gtk_widget_show_all(expander);
    if ( (cp=strrchr(defFilename, '/'))!=NULL) cp++;
    else if ( (cp=strrchr(defFilename, '\\'))!=NULL) cp++;
    else cp = defFilename;
    gtk_file_chooser_set_current_name(fileChooser, cp);
    if (strlen(image->cfg->inputFilename)>0) {
        char *cp = g_path_get_dirname(image->cfg->inputFilename);
        if (strcmp(cp,"."))
        gtk_file_chooser_add_shortcut_folder( fileChooser, cp, NULL);
        g_free(cp);
    }
    g_signal_connect(G_OBJECT(fileChooser), "selection-changed",
            G_CALLBACK(ufraw_saver_set_type), image->cfg);
    while(1) {
        status = gtk_dialog_run(GTK_DIALOG(fileChooser));
        if (status==GTK_RESPONSE_CANCEL) {
            gtk_widget_destroy(GTK_WIDGET(fileChooser));
            ufraw_message_handler(UFRAW_SET_PARENT, (char *)parentWindow);
            return UFRAW_CANCEL;
        }
        if (status==GTK_RESPONSE_APPLY) {
            gtk_toggle_button_set_active(ppmButton,
                    image->cfg->type==ppm8_type);
            gtk_toggle_button_set_active(tiffButton,
                    image->cfg->type==tiff8_type);
            gtk_toggle_button_set_active(jpegButton,
                    image->cfg->type==jpeg_type);
            continue;
        }
        filename = gtk_file_chooser_get_filename(fileChooser);
        image->cfg->interpolation = gtk_combo_box_get_active(intCombo);
        image->cfg->shrink = gtk_adjustment_get_value(shrinkAdj);
        image->cfg->overwrite = gtk_toggle_button_get_active(
                GTK_TOGGLE_BUTTON(overwriteButton));
#if !defined(NO_TIFF) && !defined(NO_ZLIB)
        image->cfg->losslessCompress = gtk_toggle_button_get_active(
                GTK_TOGGLE_BUTTON(losslessButton));
#endif
#ifndef NO_JPEG
        image->cfg->compression = gtk_adjustment_get_value(compressAdj);
#endif
        if (!image->cfg->overwrite && g_file_test(filename, G_FILE_TEST_EXISTS))
        {
            GtkWidget *dialog;
            char message[max_path];
            int response;
            dialog = gtk_dialog_new_with_buttons("File exists",
                GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(fileChooser))),
                GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR,
                GTK_STOCK_NO, GTK_RESPONSE_NO,
                GTK_STOCK_YES, GTK_RESPONSE_YES, NULL);
            snprintf(message, max_path,
                "File '%s' already exists.\nOverwrite?", filename);
            widg = gtk_label_new(message);
            gtk_label_set_line_wrap(GTK_LABEL(widg), TRUE);
            gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), widg);
            gtk_widget_show_all(dialog);
            response = gtk_dialog_run(GTK_DIALOG(dialog));
            gtk_widget_destroy(dialog);
            if (response!=GTK_RESPONSE_YES)
                continue;
        }
        status = ufraw_write_image(image, filename);
        g_free(filename);
        if (status==UFRAW_SUCCESS || status==UFRAW_ABORT_SAVE) {
            gtk_widget_destroy(GTK_WIDGET(fileChooser));
            ufraw_message_handler(UFRAW_SET_PARENT, (char *)parentWindow);
            if (status==UFRAW_SUCCESS)
                g_object_set_data(G_OBJECT(parentWindow), "WindowResponse",
                        (gpointer)GTK_RESPONSE_OK);
            else
                g_object_set_data(G_OBJECT(parentWindow), "WindowResponse",
                        (gpointer)GTK_RESPONSE_CANCEL);
            gtk_main_quit();
            return UFRAW_SUCCESS;
        }
    }
}

#ifndef NO_TIFF
void ufraw_tiff_message(const char *module, const char *fmt, va_list ap)
{
    module = module;
    char buf[max_path];
    vsnprintf(buf, max_path, fmt, ap);
    ufraw_message(UFRAW_VERBOSE, buf);
}
#endif /*NO_TIFF*/

#ifndef NO_JPEG
void ufraw_jpeg_message(j_common_ptr cinfo)
{
    ufraw_message(UFRAW_VERBOSE, cinfo->err->jpeg_message_table
            [cinfo->err->msg_code],
            cinfo->err->msg_parm.i[0],
            cinfo->err->msg_parm.i[1],
            cinfo->err->msg_parm.i[2],
            cinfo->err->msg_parm.i[3]);
}
#endif /*NO_JPEG*/

int ufraw_write_image(image_data *image, char *outFilename)
{
    void *out; /* out is a pointer to FILE or TIFF */
    int row, rowStride, i, status=UFRAW_SUCCESS;
    image_type *rawImage;
    guint8 *pixbuf8=NULL;
    guint16 *pixbuf16;
    char *message;
    message = message;
    ufraw_message(UFRAW_CLEAN, NULL);
#ifndef NO_TIFF
    if (image->cfg->type==tiff8_type || image->cfg->type==tiff16_type) {
        TIFFSetErrorHandler(ufraw_tiff_message);
        TIFFSetWarningHandler(ufraw_tiff_message);
        if ( (out=TIFFOpen(outFilename, "w"))==NULL ) {
            message=ufraw_message_handler(UFRAW_GET_MESSAGE, NULL);
            ufraw_message(UFRAW_ERROR, "Error creating file '%s'.\n%s",
                    outFilename, message);
            return UFRAW_ERROR;
        }
    } else
#endif
        if ( (out=fopen(outFilename, "wb"))==NULL) {
            ufraw_message(UFRAW_ERROR, "Error creating file '%s': %s",
                    outFilename, g_strerror(errno));
            return UFRAW_ERROR;
        }
    ufraw_convert_image(image, image);
    ufraw_message(UFRAW_CLEAN, NULL);
    rowStride = image->width + 2*image->trim;
    rawImage = image->image + image->trim*rowStride + image->trim;
    pixbuf16 = g_new(guint16, image->width*3);
    if (image->cfg->type==ppm8_type) {
        fprintf(out, "P6\n%d %d\n%d\n", image->width, image->height, 0xFF);
        pixbuf8 = g_new(guint8, image->width*3);
        for (row=0; row<image->height; row++) {
            if (row%100==99)
                preview_progress("Saving image", 0.5 + 0.5*row/image->height);
            develope(pixbuf8, rawImage[row*rowStride],
                    image->developer, 8, pixbuf16, image->width);
            if ((int)fwrite(pixbuf8, 3, image->width, out)<image->width) {
                ufraw_message(UFRAW_ERROR, "Error creating file '%s': %s.",
                        outFilename, g_strerror(errno));
                status = UFRAW_ABORT_SAVE;
                break;
            }
        }
    } else if (image->cfg->type==ppm16_type) {
        fprintf(out, "P6\n%d %d\n%d\n", image->width, image->height, 0xFFFF);
        for (row=0; row<image->height; row++) {
            if (row%100==99)
                preview_progress("Saving image", 0.5 + 0.5*row/image->height);
            develope(pixbuf16, rawImage[row*rowStride],
                    image->developer, 16, pixbuf16, image->width);
            for (i=0; i<3*image->width; i++)
                pixbuf16[i] = g_htons(pixbuf16[i]);
            if ((int)fwrite(pixbuf16, 6, image->width, out)<image->width) {
                ufraw_message(UFRAW_ERROR, "Error creating file '%s': %s.",
                        outFilename, g_strerror(errno));
                status = UFRAW_ABORT_SAVE;
                break;
            }
        }
#ifndef NO_TIFF
    } else if (image->cfg->type==tiff8_type ||
            image->cfg->type==tiff16_type) {
        TIFFSetField(out, TIFFTAG_IMAGEWIDTH, image->width);
        TIFFSetField(out, TIFFTAG_IMAGELENGTH, image->height);
        TIFFSetField(out, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
        TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, 3);
        if (image->cfg->type==tiff8_type)
            TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, 8);
        else
            TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, 16);
        TIFFSetField(out, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
        TIFFSetField(out, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
#ifndef NO_ZLIB
        if (image->cfg->losslessCompress) {
            TIFFSetField(out, TIFFTAG_COMPRESSION, COMPRESSION_DEFLATE);
            TIFFSetField(out, TIFFTAG_ZIPQUALITY, 9);
        }
        else
#endif
            TIFFSetField(out, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
        /* Embed output profile if it is not the internal sRGB*/
        if (strcmp(image->developer->file[out_profile], "")) {
            char *buf;
            int len;
            if (g_file_get_contents(image->developer->file[out_profile],
                &buf, &len, NULL)) {
            TIFFSetField(out, TIFFTAG_ICCPROFILE, len, buf);
            g_free(buf);
            } else ufraw_message(UFRAW_WARNING,
                    "Failed to embed output profile '%s' in '%s'",
                    image->developer->file[out_profile], outFilename);
        }
        TIFFSetField(out, TIFFTAG_ROWSPERSTRIP, TIFFDefaultStripSize(out, 0));
        if (image->cfg->type==tiff8_type) {
            pixbuf8 = g_new(guint8, image->width*3);
            for (row=0; row<image->height; row++) {
                if (row%100==99)
                    preview_progress("Saving image", 0.5+0.5*row/image->height);
                develope(pixbuf8, rawImage[row*rowStride],
                        image->developer, 8, pixbuf16, image->width);
                if (TIFFWriteScanline(out, pixbuf8, row, 0)<0) {
                    message=ufraw_message_handler(UFRAW_GET_MESSAGE, NULL);
                    ufraw_message(UFRAW_ERROR, "Error creating file '%s'.\n%s",
                            outFilename, message);
                    status = UFRAW_ABORT_SAVE;
                    break;
                }
            }
        } else {
            for (row=0; row<image->height; row++) {
                if (row%100==99)
                    preview_progress("Saving image", 0.5+0.5*row/image->height);
                develope(pixbuf16, rawImage[row*rowStride],
                        image->developer, 16, pixbuf16, image->width);
                if (TIFFWriteScanline(out, pixbuf16, row, 0)<0) {
                    message=ufraw_message_handler(UFRAW_GET_MESSAGE, NULL);
                    ufraw_message(UFRAW_ERROR, "Error creating file '%s'.\n%s",
                            outFilename, message);
                    status = UFRAW_ABORT_SAVE;
                    break;
                }
            }
        }
#endif /*NO_TIFF*/
#ifndef NO_JPEG
    } else if (image->cfg->type==jpeg_type) {
        struct jpeg_compress_struct cinfo;
        struct jpeg_error_mgr jerr;

        cinfo.err = jpeg_std_error(&jerr);
        cinfo.err->output_message = ufraw_jpeg_message;
        cinfo.err->error_exit = ufraw_jpeg_message;
        jpeg_create_compress(&cinfo);
        jpeg_stdio_dest(&cinfo, out);
        cinfo.image_width = image->width;
        cinfo.image_height = image->height;
        cinfo.input_components = 3;
        cinfo.in_color_space = JCS_RGB;
        jpeg_set_defaults(&cinfo);
        jpeg_set_quality(&cinfo, image->cfg->compression, TRUE);
        /* Embed output profile if it is not the internal sRGB*/
        if (strcmp(image->developer->file[out_profile], "")) {
            char *buf;
            int len;
            if (g_file_get_contents(image->developer->file[out_profile],
                    &buf, &len, NULL)) {
                write_icc_profile(&cinfo, buf, len);
                g_free(buf);
            } else ufraw_message(UFRAW_WARNING,
                    "Failed to embed output profile '%s' in '%s'",
                    image->developer->file[out_profile], outFilename);
        }
        jpeg_start_compress(&cinfo, TRUE);
        message=ufraw_message_handler(UFRAW_GET_MESSAGE, NULL);
        pixbuf8 = g_new(guint8, image->width*3);
        for (row=0; row<image->height; row++) {
            if (row%100==99)
                preview_progress("Saving image", 0.5 + 0.5*row/image->height);
            develope(pixbuf8, rawImage[row*rowStride],
                    image->developer, 8, pixbuf16, image->width);
            jpeg_write_scanlines(&cinfo, &pixbuf8, 1);
            message=ufraw_message_handler(UFRAW_GET_MESSAGE, NULL);
            if (message!=NULL ) break;
        }
        if (message==NULL) jpeg_finish_compress(&cinfo);
        jpeg_destroy_compress(&cinfo);
        if ( (message=ufraw_message_handler(UFRAW_GET_MESSAGE, NULL))!=NULL) {
            ufraw_message(UFRAW_ERROR, "Error creating file '%s'.\n%s",
                    outFilename, message);
            status = UFRAW_ABORT_SAVE;
        }
#endif /*NO_JPEG*/
    } else {
        ufraw_message(UFRAW_ERROR,
                "Error creating file '%s'. Unknown file type %d.",
                outFilename, image->cfg->type);
        status = UFRAW_ABORT_SAVE;
    }
    g_free(pixbuf16);
    g_free(pixbuf8);
#ifndef NO_TIFF
    if (image->cfg->type==tiff8_type || image->cfg->type==tiff16_type) {
        TIFFClose(out);
        if ( (message=ufraw_message_handler(UFRAW_GET_MESSAGE, NULL))!=NULL) {
            ufraw_message(UFRAW_ERROR, "Error creating file '%s'.\n%s",
                    outFilename, message);
            status = UFRAW_ABORT_SAVE;
        }
    } else
#endif
        fclose(out);
    if (status==UFRAW_SUCCESS)
        g_strlcpy(image->cfg->outputFilename, outFilename, max_path);
    return status;
}

void ufraw_chooser(cfg_data *cfg)
{
    image_data *image;
    GtkFileChooser *fileChooser;
    GSList *list, *saveList;
    GtkFileFilter *filter;
    char *filename, *cp;
    char **extList, **l, ext[max_name];

    fileChooser = GTK_FILE_CHOOSER(gtk_file_chooser_dialog_new("UFRaw", NULL,
            GTK_FILE_CHOOSER_ACTION_OPEN,
            GTK_STOCK_QUIT, GTK_RESPONSE_CANCEL,
            GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL));
    gtk_window_set_icon(GTK_WINDOW(fileChooser),
            gdk_pixbuf_new_from_inline(-1, ufraw_icon, FALSE, NULL));
    ufraw_message_handler(UFRAW_SET_PARENT, (char *)fileChooser);
    filter = GTK_FILE_FILTER(gtk_file_filter_new());
    gtk_file_filter_set_name(filter, "Raw images");
    extList = g_strsplit(raw_ext, ",", 100);
    for (l=extList; *l!=NULL; l++)
        if (strcmp(*l, "jpg") && strcmp(*l, "tif")) {
            snprintf(ext, max_name, "*.%s", *l);
            gtk_file_filter_add_pattern(filter, ext);
            gtk_file_filter_add_pattern(filter, cp=g_ascii_strup(ext,-1));
            g_free(cp);
        }
    g_strfreev(extList);
    gtk_file_chooser_add_filter(fileChooser, filter);
    filter = GTK_FILE_FILTER(gtk_file_filter_new());
    gtk_file_filter_set_name(filter, "Raw jpg's");
    gtk_file_filter_add_pattern(filter, "*.jpg");
    gtk_file_filter_add_pattern(filter, "*.JPG");
    gtk_file_chooser_add_filter(fileChooser, filter);
    filter = GTK_FILE_FILTER(gtk_file_filter_new());
    gtk_file_filter_set_name(filter, "Raw tif's");
    gtk_file_filter_add_pattern(filter, "*.tif");
    gtk_file_filter_add_pattern(filter, "*.TIF");
    gtk_file_chooser_add_filter(fileChooser, filter);
    filter = GTK_FILE_FILTER(gtk_file_filter_new());
    gtk_file_filter_set_name(filter, "All files");
    gtk_file_filter_add_pattern(filter, "*");
    gtk_file_chooser_add_filter(fileChooser, filter);
    gtk_widget_show(GTK_WIDGET(fileChooser));
    gtk_file_chooser_set_select_multiple(fileChooser, TRUE);
    /* Add shortcut to folder of last opened file */
    if (strlen(cfg->inputFilename)>0) {
        char *cp = g_path_get_dirname(cfg->inputFilename);
        gtk_file_chooser_add_shortcut_folder( fileChooser, cp, NULL);
        g_free(cp);
    }
    while (gtk_dialog_run(GTK_DIALOG(fileChooser))==GTK_RESPONSE_ACCEPT) {
        for(list=saveList=gtk_file_chooser_get_filenames(fileChooser);
        list!=NULL; list=g_slist_next(list)) {
            filename = list->data;
            image = ufraw_open(filename);
            if (image==NULL) {
                ufraw_message(UFRAW_REPORT, NULL);
                continue;
            }
            ufraw_config(image, cfg);
            ufraw_preview(image, FALSE, ufraw_saver);
            g_free(filename);
        }
        g_slist_free(saveList);
    }
    gtk_widget_destroy(GTK_WIDGET(fileChooser));
    ufraw_message_handler(UFRAW_SET_PARENT, NULL);
}

Generated by  Doxygen 1.6.0   Back to index