dcraw/rawphoto.c

356 lines
9.5 KiB
C
Raw Normal View History

/*
Raw photo loader plugin for The GIMP
by Dave Coffin at cybercom dot net, user dcoffin
http://www.cybercom.net/~dcoffin/
$Revision: 1.32 $
$Date: 2008/09/16 05:41:39 $
This code is licensed under the same terms as The GIMP.
To simplify maintenance, it calls my command-line "dcraw"
program to do the actual decoding.
To install locally:
gimptool --install rawphoto.c
To install globally:
gimptool --install-admin rawphoto.c
To build without installing:
gcc -o rawphoto rawphoto.c `gtk-config --cflags --libs` -lgimp -lgimpui
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <gtk/gtk.h>
#include <libgimp/gimp.h>
#include <libgimp/gimpui.h>
#if GIMP_CHECK_VERSION(1,3,2)
#define GimpRunModeType GimpRunMode
#endif
#if GIMP_CHECK_VERSION(1,3,17)
#define RAWPHOTO_CONST const
#else
#define RAWPHOTO_CONST
#endif
#include <locale.h>
#include <libintl.h>
#define _(String) gettext(String)
#define PLUG_IN_VERSION "1.1.20 - 16 September 2008"
static void query(void);
static void run(RAWPHOTO_CONST gchar *name,
gint nparams,
RAWPHOTO_CONST GimpParam *param,
gint *nreturn_vals,
GimpParam **return_vals);
static gint load_dialog (gchar *name);
static gint32 load_image (gchar *filename);
GimpPlugInInfo PLUG_IN_INFO =
{
NULL, /* init_procedure */
NULL, /* quit_procedure */
query, /* query_procedure */
run, /* run_procedure */
};
static struct {
gboolean check_val[6];
gfloat spin_val[2];
} cfg = {
{ FALSE, FALSE, FALSE, FALSE, FALSE, FALSE },
{ 1, 0 }
};
MAIN ()
static void query (void)
{
static GimpParamDef load_args[] =
{
{ GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive" },
{ GIMP_PDB_STRING, "filename", "The name of the file to load" },
{ GIMP_PDB_STRING, "raw_filename", "The name of the file to load" },
};
static GimpParamDef load_return_vals[] =
{
{ GIMP_PDB_IMAGE, "image", "Output image" },
};
static gint num_load_args =
sizeof load_args / sizeof load_args[0];
static gint num_load_return_vals =
sizeof load_return_vals / sizeof load_return_vals[0];
gimp_install_procedure ("file_rawphoto_load",
"Loads raw digital camera files",
"This plug-in loads raw digital camera files.",
"Dave Coffin at cybercom dot net, user dcoffin",
"Copyright 2003-2008 by Dave Coffin",
PLUG_IN_VERSION,
"<Load>/rawphoto",
NULL,
GIMP_PLUGIN,
num_load_args,
num_load_return_vals,
load_args,
load_return_vals);
gimp_register_load_handler ("file_rawphoto_load",
"3fr,arw,bay,bmq,cine,cr2,crw,cs1,dc2,dcr,dng,erf,fff,hdr,ia,jpg,k25,kc2,kdc,mdc,mef,mos,mrw,nef,nrw,orf,pef,pxn,qtk,raf,raw,rdc,rw2,sr2,srf,sti,tif,x3f", "");
}
static void run (RAWPHOTO_CONST gchar *name,
gint nparams,
RAWPHOTO_CONST GimpParam *param,
gint *nreturn_vals,
GimpParam **return_vals)
{
static GimpParam values[2];
GimpRunModeType run_mode;
GimpPDBStatusType status;
gint32 image_id = -1;
gchar *command, *fname;
int stat;
*nreturn_vals = 1;
*return_vals = values;
status = GIMP_PDB_CALLING_ERROR;
if (strcmp (name, "file_rawphoto_load")) goto done;
status = GIMP_PDB_EXECUTION_ERROR;
fname = param[1].data.d_string;
command = g_malloc (strlen(fname)+20);
if (!command) goto done;
/*
Is the file really a raw photo? If not, try loading it
as a regular JPEG or TIFF.
*/
sprintf (command, "dcraw -i '%s'\n",fname);
fputs (command, stderr);
stat = system (command);
g_free (command);
if (stat) {
if (stat > 0x200)
g_message (_("The \"rawphoto\" plugin won't work because "
"there is no \"dcraw\" executable in your path."));
if (!strcasecmp (fname + strlen(fname) - 4, ".jpg"))
*return_vals = gimp_run_procedure2
("file_jpeg_load", nreturn_vals, nparams, param);
else
*return_vals = gimp_run_procedure2
("file_tiff_load", nreturn_vals, nparams, param);
return;
}
gimp_get_data ("plug_in_rawphoto", &cfg);
status = GIMP_PDB_CANCEL;
run_mode = param[0].data.d_int32;
if (run_mode == GIMP_RUN_INTERACTIVE)
if (!load_dialog (param[1].data.d_string)) goto done;
status = GIMP_PDB_EXECUTION_ERROR;
image_id = load_image (param[1].data.d_string);
if (image_id == -1) goto done;
*nreturn_vals = 2;
values[1].type = GIMP_PDB_IMAGE;
values[1].data.d_image = image_id;
status = GIMP_PDB_SUCCESS;
gimp_set_data ("plug_in_rawphoto", &cfg, sizeof cfg);
done:
values[0].type = GIMP_PDB_STATUS;
values[0].data.d_status = status;
}
static gint32 load_image (gchar *filename)
{
int tile_height, depth, width, height, row, nrows;
FILE *pfp;
gint32 image, layer;
GimpDrawable *drawable;
GimpPixelRgn pixel_region;
guchar *pixel;
char *command, nl;
setlocale (LC_NUMERIC, "C");
command = g_malloc (strlen(filename)+100);
if (!command) return -1;
sprintf (command,
"dcraw -c%s%s%s%s%s%s -b %0.2f -H %d '%s'\n",
cfg.check_val[0] ? " -q 0":"",
cfg.check_val[1] ? " -h":"",
cfg.check_val[2] ? " -f":"",
cfg.check_val[3] ? " -d":"",
cfg.check_val[4] ? " -a":"",
cfg.check_val[5] ? " -w":"",
cfg.spin_val[0], (int) cfg.spin_val[1],
filename );
fputs (command, stderr);
pfp = popen (command, "r");
g_free (command);
if (!pfp) {
perror ("dcraw");
return -1;
}
if (fscanf (pfp, "P%d %d %d 255%c", &depth, &width, &height, &nl) != 4
|| (depth-5)/2 ) {
pclose (pfp);
g_message ("Not a raw digital camera image.\n");
return -1;
}
depth = depth*2 - 9;
image = gimp_image_new (width, height, depth == 3 ? GIMP_RGB : GIMP_GRAY);
if (image == -1) {
pclose (pfp);
g_message ("Can't allocate new image.\n");
return -1;
}
gimp_image_set_filename (image, filename);
/* Create the "background" layer to hold the image... */
layer = gimp_layer_new (image, "Background", width, height,
depth == 3 ? GIMP_RGB_IMAGE : GIMP_GRAY_IMAGE,
100, GIMP_NORMAL_MODE);
gimp_image_add_layer (image, layer, 0);
/* Get the drawable and set the pixel region for our load... */
drawable = gimp_drawable_get (layer);
gimp_pixel_rgn_init (&pixel_region, drawable, 0, 0, drawable->width,
drawable->height, TRUE, FALSE);
/* Temporary buffers... */
tile_height = gimp_tile_height();
pixel = g_new (guchar, tile_height * width * depth);
/* Load the image... */
for (row = 0; row < height; row += tile_height) {
nrows = height - row;
if (nrows > tile_height)
nrows = tile_height;
fread (pixel, width * depth, nrows, pfp);
gimp_pixel_rgn_set_rect (&pixel_region, pixel, 0, row, width, nrows);
}
pclose (pfp);
g_free (pixel);
gimp_drawable_flush (drawable);
gimp_drawable_detach (drawable);
return image;
}
#if !GIMP_CHECK_VERSION(1,3,23)
/* this is set to true after OK click in any dialog */
gboolean result = FALSE;
static void callback_ok (GtkWidget * widget, gpointer data)
{
result = TRUE;
gtk_widget_destroy (GTK_WIDGET (data));
}
#endif
#define NCHECK (sizeof cfg.check_val / sizeof (gboolean))
gint load_dialog (gchar * name)
{
GtkWidget *dialog;
GtkWidget *table;
GtkObject *adj;
GtkWidget *widget;
int i;
static const char *label[9] =
{ "Quick interpolation", "Half-size interpolation",
"Four color interpolation", "Grayscale document",
"Automatic white balance", "Camera white balance",
"Brightness", "Highlight mode" };
gimp_ui_init ("rawphoto", TRUE);
dialog = gimp_dialog_new (_("Raw Photo Loader " PLUG_IN_VERSION), "rawphoto",
#if !GIMP_CHECK_VERSION(1,3,23)
gimp_standard_help_func, "rawphoto",
GTK_WIN_POS_MOUSE,
FALSE, TRUE, FALSE,
_("OK"), callback_ok, NULL, NULL, NULL, TRUE,
FALSE, _("Cancel"), gtk_widget_destroy, NULL,
1, NULL, FALSE, TRUE, NULL);
gtk_signal_connect
(GTK_OBJECT(dialog), "destroy", GTK_SIGNAL_FUNC(gtk_main_quit), NULL);
#else
NULL, 0,
gimp_standard_help_func, "rawphoto",
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
GTK_STOCK_OK, GTK_RESPONSE_OK,
NULL);
#endif
table = gtk_table_new (9, 2, FALSE);
gtk_container_set_border_width (GTK_CONTAINER(table), 6);
gtk_box_pack_start
(GTK_BOX(GTK_DIALOG(dialog)->vbox), table, FALSE, FALSE, 0);
gtk_widget_show (table);
for (i=0; i < NCHECK; i++) {
widget = gtk_check_button_new_with_label
(_(label[i]));
gtk_toggle_button_set_active
(GTK_TOGGLE_BUTTON (widget), cfg.check_val[i]);
gtk_table_attach
(GTK_TABLE(table), widget, 0, 2, i, i+1, GTK_FILL, GTK_FILL, 0, 0);
gtk_signal_connect (GTK_OBJECT (widget), "toggled",
GTK_SIGNAL_FUNC (gimp_toggle_button_update),
&cfg.check_val[i]);
gtk_widget_show (widget);
}
for (i=NCHECK; i < NCHECK+2; i++) {
widget = gtk_label_new (_(label[i]));
gtk_misc_set_alignment (GTK_MISC (widget), 1.0, 0.5);
gtk_misc_set_padding (GTK_MISC (widget), 10, 0);
gtk_table_attach
(GTK_TABLE(table), widget, 0, 1, i, i+1, GTK_FILL, GTK_FILL, 0, 0);
gtk_widget_show (widget);
if (i == NCHECK+1)
widget = gimp_spin_button_new
(&adj, cfg.spin_val[i-NCHECK], 0, 9, 1, 9, 1, 1, 0);
else
widget = gimp_spin_button_new
(&adj, cfg.spin_val[i-NCHECK], 0.01, 4.0, 0.01, 0.1, 0.1, 0.1, 2);
gtk_table_attach
(GTK_TABLE(table), widget, 1, 2, i, i+1, GTK_FILL, GTK_FILL, 0, 0);
gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
GTK_SIGNAL_FUNC (gimp_float_adjustment_update),
&cfg.spin_val[i-NCHECK]);
gtk_widget_show (widget);
}
gtk_widget_show (dialog);
#if !GIMP_CHECK_VERSION(1,3,23)
gtk_main();
gdk_flush();
return result;
#else
i = gimp_dialog_run (GIMP_DIALOG (dialog));
gtk_widget_destroy (dialog);
return i == GTK_RESPONSE_OK;
#endif
}