Logo Search packages:      
Sourcecode: ufraw version File versions

ufraw_ufraw.c

/*
   UFRaw - Unidentified Flying Raw
   Raw photo loader plugin for The GIMP
   by udi Fuchs,

   based on the gimp plug-in by Pawel T. Jochym jochym at ifj edu pl,
   
   based on the gimp plug-in by Dave Coffin
   http://www.cybercom.net/~dcoffin/

   UFRaw is licensed under the GNU General Public License.
   It uses "dcraw" code to do the actual raw decoding.
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <errno.h>
#include <glib.h>
#include "dcraw_api.h"
#include "ufraw.h"


char *ufraw_message_handler(int code, char *message)
{
    static char *messageBuffer = NULL;
    static void *parentWindow = NULL;
    char *buf;

    if (code==UFRAW_GET_MESSAGE)
        return messageBuffer;
    if (code==UFRAW_REPORT) {
        ufraw_messenger(messageBuffer, parentWindow);
        return messageBuffer;
    }
    if (code==UFRAW_CLEAN) {
        g_free(messageBuffer);
        messageBuffer = NULL;
        return NULL;
    }
    if (code==UFRAW_SET_PARENT) {
        void *saveParentWindow = parentWindow;
        parentWindow = message;
        return saveParentWindow;
    }
#ifdef DEBUG
    if (code!=UFRAW_DCRAW_VERBOSE) fprintf(stderr, "%s", message);
#endif
    if (messageBuffer==NULL)
        messageBuffer = g_strdup(message);
    else {
        buf = g_strconcat(messageBuffer, message, NULL);
        g_free(messageBuffer);
        messageBuffer = buf;
    }
    if (code!=UFRAW_VERBOSE && code!=UFRAW_DCRAW_VERBOSE)
        ufraw_messenger(message, parentWindow);
    return messageBuffer;
}

image_data *ufraw_open(char *filename)
{
    int status;
    image_data *image;
    dcraw_data *raw;

    ufraw_message_handler(UFRAW_CLEAN, NULL);
    raw = g_new(dcraw_data, 1);
    status = dcraw_open(raw, filename);
    if ( status==DCRAW_VERBOSE ) ufraw_message(status, raw->message)
    else if ( status!=DCRAW_SUCCESS) {
        /* Hold the message without displaying it */
        ufraw_message(UFRAW_VERBOSE, raw->message);
        g_free(raw);
        return NULL;
    }
    image = g_new0(image_data, 1);
    g_strlcpy(image->filename, filename, max_path);
    image->raw = raw;
    image->developer = developer_init();
    if (raw->fuji_width) {
        /* copied from dcraw's fuji_rotate() */
        image->width = raw->fuji_width / sqrt(0.5);
        image->height = (raw->height - raw->fuji_width) / sqrt(0.5);
    } else {
        image->height = raw->height;
        image->width = raw->width;
    }
    if (raw->flip & 4) {
        int tmp = image->height;
        image->height = image->width;
        image->width = tmp;
    }
    ufraw_message(UFRAW_VERBOSE, "ufraw_open: w:%d h:%d curvesize:%d\n",
        image->width, image->height, raw->toneCurveSize);
    return image;
}

int ufraw_config(image_data *image, cfg_data *cfg)
{
    int i;
    dcraw_data *raw=NULL;
    char *inPath, *oldInPath, *oldOutPath;

    if (image!=NULL) image->cfg = cfg;
    if (cfg->size!=cfg_default.size || cfg->version!=cfg_default.version)
        load_configuration(cfg);

    if (cfg->wbLoad==load_default) cfg->wb = camera_wb;
    if (cfg->wbLoad==load_auto) cfg->wb = auto_wb;
    if (cfg->curveLoad==load_default)
        for (i=0; i<cfg->curveCount; i++) {
            cfg->curve[i].gamma = cfg_default.curve[0].gamma;
            cfg->curve[i].contrast = cfg_default.curve[0].contrast;
            cfg->curve[i].saturation = cfg_default.curve[0].saturation;
            cfg->curve[i].shadow = cfg_default.curve[0].shadow;
            cfg->curve[i].depth = cfg_default.curve[0].depth;
            cfg->curve[i].brightness = cfg_default.curve[0].brightness;
        }
    if (cfg->exposureLoad==load_default) {
        cfg->exposure = cfg_default.exposure;
        for (i=0; i<cfg->curveCount; i++)
            cfg->curve[i].black = cfg_default.curve[0].black;
    }
    if (cfg->exposureLoad==load_auto) cfg->exposure = nan("");

    if (image==NULL) return UFRAW_SUCCESS;

    /* Guess the prefered output path */
    if (!g_file_test(image->cfg->outputFilename, G_FILE_TEST_IS_DIR)) {
        inPath = g_path_get_dirname(image->filename);
        oldInPath = g_path_get_dirname(image->cfg->inputFilename);
        oldOutPath = g_path_get_dirname(image->cfg->outputFilename);
        if ( !strcmp(oldInPath, oldOutPath) || !strcmp(oldOutPath,".") )
            g_strlcpy(image->cfg->outputFilename, inPath, max_path);
        else
            g_strlcpy(image->cfg->outputFilename, oldOutPath, max_path);
        g_free(inPath);
        g_free(oldInPath);
        g_free(oldOutPath);
        if (!strcmp(image->cfg->outputFilename,"."))
            strcpy(image->cfg->outputFilename,"");
    }
    /* Make sure inputFilename has absolute path */
    if (g_path_is_absolute(image->filename))
        g_strlcpy(cfg->inputFilename, image->filename, max_path);
    else {
        char *cd = g_get_current_dir();
        char *fn = g_build_filename(cd, image->filename, NULL);
        g_strlcpy(cfg->inputFilename, fn, max_path);
        g_free(cd);
        g_free(fn);
    }
    raw = image->raw;
    if (raw->toneCurveSize!=0) {
        void *tone_curve = g_malloc(raw->toneCurveSize-64);
        long pos = ftell(raw->ifp);
        fseek(raw->ifp, raw->toneCurveOffset+64, SEEK_SET);
        fread(tone_curve, 1, raw->toneCurveSize-64, raw->ifp);
        fseek(raw->ifp, pos, SEEK_SET);
        curve_convert(&cfg->curve[camera_curve],
                raw->toneCurveSize-64, tone_curve);
        g_free(tone_curve);
    } else {
        cfg->curve[camera_curve].curveSize = 0;
        /* don't retain camera_curve if no cameraCurve */
        if (cfg->curveIndex==camera_curve) {
            cfg->curveIndex = log_curve;
            cfg->profile[0][cfg->profileIndex[0]].curve = log_curve;
        }
    }
    return UFRAW_SUCCESS;
}

int ufraw_load_raw(image_data *image, int interactive)
{
    int status, half, c;
    dcraw_data *raw = image->raw;

    half = !interactive && (image->cfg->interpolation==half_interpolation ||
                image->cfg->shrink%2==0);
    if ( (status=dcraw_load_raw(raw, half))!=DCRAW_SUCCESS ) {
        ufraw_message(status, raw->message);
        if (status!=DCRAW_VERBOSE) return status;
    }
    image->rgbMax = raw->rgbMax;
    for (c=0; c<4; c++) image->preMul[c] = raw->pre_mul[c];
    return UFRAW_SUCCESS;
}

void ufraw_close(image_data *image)
{
    dcraw_close(image->raw);
    g_free(image->raw);
    developer_destroy(image->developer);
}

/* Convert raw image to standard rgb image */
int ufraw_convert_image(image_data *image, image_data *rawImage)
{
    int c;
    dcraw_data *raw = rawImage->raw;
    dcraw_data *rawCopy = image->raw;
    cfg_data *cfg = rawImage->cfg;

    preview_progress("Loading image", 0.1);
    if (cfg->shrink>1 || cfg->interpolation==half_interpolation) {
        if (image!=rawImage) {
            rawCopy = image->raw = g_new(dcraw_data, 1);
            image->developer = rawImage->developer;
            image->cfg = rawImage->cfg;
        }
        dcraw_copy_shrink(rawCopy, raw, MAX(cfg->shrink,2));
        dcraw_fuji_rotate(rawCopy);
        image->rgbMax = rawCopy->rgbMax;
        image->height = rawCopy->height;
        image->width = rawCopy->width;
        image->image = rawCopy->rawImage;
        for (c=0; c<4; c++) image->preMul[c] = rawCopy->pre_mul[c];
        if (rawCopy->use_coeff) {
            int preMul[4];
            for (c=0; c<4; c++)
                preMul[c] = rawCopy->pre_mul[c]*0x10000;
            dcraw_scale_colors(rawCopy, preMul);
            image->rgbMax = rawCopy->rgbMax;
            for (c=0; c<4; c++) image->preMul[c] = 1.0;
        }
        ufraw_set_wb(image);
        if (isnan(image->cfg->exposure))
            ufraw_auto_adjust(image);
        developer_prepare(image->developer, image->rgbMax,
                pow(2,cfg->exposure), cfg->unclip,
                cfg->temperature, cfg->green, image->preMul,
                &cfg->profile[0][cfg->profileIndex[0]],
                &cfg->profile[1][cfg->profileIndex[1]], cfg->intent,
                cfg->curve[cfg->curveIndex].saturation,
                cfg->curveIndex, &cfg->curve[cfg->curveIndex]);
    } else {
        if (isnan(image->cfg->exposure)) {
            image_data tmpImage;
            int shrinkSave = image->cfg->shrink;
            image->cfg->shrink = 8;
            ufraw_convert_image(&tmpImage, image);
            image->cfg->shrink = shrinkSave;
            tmpImage.developer = NULL;
            ufraw_close(&tmpImage);
        } else
            ufraw_set_wb(image);
        if (raw->use_coeff) {
            int preMul[4];
            for (c=0; c<4; c++)
                preMul[c] = raw->pre_mul[c]*0x10000;
            dcraw_scale_colors(raw, preMul);
            image->rgbMax = raw->rgbMax;
            for (c=0; c<4; c++) image->preMul[c] = 1.0;
            developer_prepare(image->developer, image->rgbMax,
                    pow(2,cfg->exposure), cfg->unclip,
                    cfg->temperature, cfg->green, image->preMul,
                    &cfg->profile[0][cfg->profileIndex[0]],
                    &cfg->profile[1][cfg->profileIndex[1]], cfg->intent,
                    cfg->curve[cfg->curveIndex].saturation,
                    cfg->curveIndex, &cfg->curve[cfg->curveIndex]);
        } else {
            developer_prepare(image->developer, image->rgbMax,
                    pow(2,cfg->exposure), cfg->unclip,
                    cfg->temperature, cfg->green, image->preMul,
                    &cfg->profile[0][cfg->profileIndex[0]],
                    &cfg->profile[1][cfg->profileIndex[1]], cfg->intent,
                    cfg->curve[cfg->curveIndex].saturation,
                    cfg->curveIndex, &cfg->curve[cfg->curveIndex]);
            dcraw_scale_colors(raw, image->developer->rgbWB);
            image->rgbMax = raw->rgbMax;
            for (c=0; c<4; c++)
            image->developer->rgbWB[c] = image->developer->rgbMax;
        }
        dcraw_interpolate(raw, cfg->interpolation==quick_interpolation,
                cfg->interpolation==four_color_interpolation);
        dcraw_fuji_rotate(raw);
    }
    dcraw_convert_to_rgb(rawCopy);
    preview_progress("Loading image", 0.4);
    dcraw_flip_image(rawCopy);
    preview_progress("Loading image", 0.5);
    image->trim = rawCopy->trim;
    image->height = rawCopy->height - 2*image->trim;
    image->width = rawCopy->width - 2*image->trim;
    image->image = rawCopy->rawImage;
    return UFRAW_SUCCESS;
}

int ufraw_set_wb(image_data *image)
{
    dcraw_data *raw = image->raw;
    float rgbWB[3];
    int status, c;

    if (image->cfg->wb==preserve_wb) return UFRAW_SUCCESS;
    if (image->cfg->wb==auto_wb || image->cfg->wb==camera_wb) {
        if ( (status=dcraw_set_color_scale(raw, image->cfg->wb==auto_wb,
                image->cfg->wb==camera_wb))!=DCRAW_SUCCESS ) {
            if (status==DCRAW_NO_CAMERA_WB) {
                ufraw_message(UFRAW_ERROR,
                    "Cannot use camera white balance, "
                    "reverting to auto white balance.\n"
                    "You can set 'Auto WB' as the initial setting "
                    "in 'Preferences' to avoid getting this "
                    "message in the future.\n");
                image->cfg->wb = auto_wb;
                status=dcraw_set_color_scale(raw, TRUE, FALSE);
            }
            if (status!=DCRAW_SUCCESS && status!=DCRAW_VERBOSE)
            return status;
        }
        for (c=0; c<3; c++)
            rgbWB[c] = raw->pre_mul[c]/raw->post_mul[c];
    } else if (image->cfg->wb<wb_preset_count) {
        rgbWB[0] = 1/wb_preset[image->cfg->wb].red;
        rgbWB[1] = 1;
        rgbWB[2] = 1/wb_preset[image->cfg->wb].blue;
    } else return UFRAW_ERROR;
    RGB_to_temperature(rgbWB, &image->cfg->temperature, &image->cfg->green);
    return UFRAW_SUCCESS;
}

/* Calculate optimal exposure and black point */
void ufraw_auto_adjust(image_data *image)
{
    int sum, stop, wp, bp, i, j, c;
    int raw_histogram[0x10000], preview_histogram[0x100]; 
    guint8 *p8 = g_new(guint8, 3*image->width);
    guint16 *pixtmp = g_new(guint16, 3*image->width);

    /* set cutoff at 1/256/4 of the histogram */
    stop = image->width*image->height*3/256/4;
    image->cfg->exposure = 0;
    image->cfg->curve[image->cfg->curveIndex].black = 0;
    developer_prepare(image->developer, image->rgbMax,
            pow(2,image->cfg->exposure), image->cfg->unclip,
            image->cfg->temperature, image->cfg->green, image->preMul,
            &image->cfg->profile[0][image->cfg->profileIndex[0]],
            &image->cfg->profile[1][image->cfg->profileIndex[1]],
            image->cfg->intent,
            image->cfg->curve[image->cfg->curveIndex].saturation,
            image->cfg->curveIndex,
            &image->cfg->curve[image->cfg->curveIndex]);

    /* First calculate the exposure */
    memset(raw_histogram, 0, sizeof(raw_histogram));
    for (i=0; i<image->width*image->height; i++)
        for (c=0; c<3; c++)
            raw_histogram[MIN((guint64)image->image[i][c] *
                    image->developer->rgbWB[c] / 0x10000, 0xFFFF)]++;
    for (wp=0xFFFF, sum=0; wp>0 && sum<stop; wp--)
        sum += raw_histogram[wp];
    image->cfg->exposure = -log((float)wp/image->developer->rgbMax)/log(2);
    if (!image->cfg->unclip)
        image->cfg->exposure = MAX(image->cfg->exposure,0);
    /* Next, calculate the black point */
    developer_prepare(image->developer, image->rgbMax,
            pow(2,image->cfg->exposure), image->cfg->unclip,
            image->cfg->temperature, image->cfg->green, image->preMul,
            &image->cfg->profile[0][image->cfg->profileIndex[0]],
            &image->cfg->profile[1][image->cfg->profileIndex[1]],
            image->cfg->intent,
            image->cfg->curve[image->cfg->curveIndex].saturation,
            image->cfg->curveIndex,
            &image->cfg->curve[image->cfg->curveIndex]);
    memset(preview_histogram, 0, sizeof(preview_histogram));
    for (i=0; i<image->height; i++) {
        develope(p8, image->image[i*image->width], image->developer, 8,
                pixtmp, image->width);
        for (j=0; j<3*image->width; j++) preview_histogram[p8[j]]++;
    }
    for (bp=0, sum=0; bp<0x100 && sum<stop; bp++)
        sum += preview_histogram[bp];
    image->cfg->curve[image->cfg->curveIndex].black = (float)bp/256;
    g_free(p8);
    g_free(pixtmp);
    ufraw_message(UFRAW_VERBOSE, "ufraw_auto_adjust: wp %d, bp %d, "
            "Black %f, Exposure %f\n", wp, bp,
            image->cfg->curve[image->cfg->curveIndex].black,
            image->cfg->exposure);
}


Generated by  Doxygen 1.6.0   Back to index