[gimp-hdrtools] / trunk / hdrtools.c Repository:
ViewVC logotype

View of /trunk/hdrtools.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 9 - (download) (as text) (annotate)
Thu Apr 19 15:36:18 2007 UTC (2 years, 7 months ago) by cocidius
File size: 58958 byte(s)
Added white point setting to log average luminance tone mapping operator
    1 /*
    2    hdrtools GIMP plugin
    3 
    4    Copyright (C) 2007 Shawn Kirst <skirst@fuse.net>
    5 
    6    This program is free software; you can redistribute it and/or
    7    modify it under the terms of the GNU General Public
    8    License as published by the Free Software Foundation; either
    9    version 2 of the License, or (at your option) any later version.
   10 
   11    This program is distributed in the hope that it will be useful,
   12    but WITHOUT ANY WARRANTY; without even the implied warranty of
   13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   14    General Public License for more details.
   15 
   16    You should have received a copy of the GNU General Public License
   17    along with this program; see the file COPYING.  If not, write to
   18    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
   19    Boston, MA 02111-1307, USA.
   20 */
   21 
   22 #include <stdio.h>
   23 #include <stdlib.h>
   24 #include <string.h>
   25 #include <ctype.h>
   26 #include <float.h>
   27 
   28 #include <gtk/gtk.h>
   29 
   30 #include <libgimp/gimp.h>
   31 #include <libgimp/gimpui.h>
   32 
   33 static inline float max(float a, float b)
   34 {
   35    return(a > b ? a : b);
   36 }
   37 
   38 static inline float min(float a, float b)
   39 {
   40    return(a < b ? a : b);
   41 
   42 }
   43 
   44 static inline float clamp(float x, float l, float h)
   45 {
   46    return(max(l, min(h, x)));
   47 }
   48 
   49 typedef struct rgbe_header_s
   50 {
   51    int width;
   52    int height;
   53    int flags;
   54    float gamma;
   55    float exposure;
   56 } rgbe_header_t;
   57 
   58 typedef enum rgbe_flags_e
   59 {
   60    RGBE_HAS_GAMMA = 1 << 0,
   61    RGBE_HAS_EXPOSURE = 1 << 1
   62 } rgbe_flags_t;
   63 
   64 #define PROG_NAME "hdrtools"
   65 #define LOAD_PROC "file_rgbe_load"
   66 #define SAVE_PROC "file_rgbe_save"
   67 
   68 static gint g_run_interactive;
   69 static int g_runme = 0;
   70 
   71 static void query(void);
   72 static void run(const gchar *name, gint nparams, const GimpParam *param,
   73                 gint *nreturn_vals, GimpParam **return_vals);
   74 static int rgbe_read_header(rgbe_header_t *hdr, FILE *fp);
   75 static int rgbe_read_pixels(FILE *fp, unsigned char *data, int num);
   76 static int rgbe_read_pixels_RLE(FILE *fp, unsigned char *data,
   77                                 int width, int height);
   78 static gint32 read_rgbe_image(gchar *filename);
   79 static GimpPDBStatusType write_rgbe_image(gchar *filename, gint32 imageID,
   80                                           gint32 drawableID);
   81 static void convert_rgbe_to_rgbdiv8(GimpPreview *preview,
   82                                     GimpDrawable *drawable);
   83 static float compute_log_average_luminance(unsigned char *pixels,
   84                                            int imgtype, int w, int h);
   85 static void tonemap_image_logavg(GimpPreview *preview, GimpDrawable *drawable);
   86 static void tonemap_image(GimpPreview *preview, GimpDrawable *drawable);
   87 static int tonemap_logavg_dialog(GimpDrawable *drawable);
   88 static int tonemap_dialog(GimpDrawable *drawable);
   89 static int rgbd8_dialog(GimpDrawable *drawable);
   90 static int read_rgbe_dialog(void);
   91 static int write_rgbe_dialog(void);
   92 
   93 GimpPlugInInfo PLUG_IN_INFO =
   94 {
   95    0, 0, query, run
   96 };
   97 
   98 enum
   99 {
  100    IMAGE_TYPE_RGBE,
  101    IMAGE_TYPE_RGBDIV8
  102 };
  103 
  104 /* plug-in data storage structures */
  105 
  106 static struct
  107 {
  108    gboolean preview;
  109    int imgtype;
  110    int tonemap;
  111    int usefilelevels;
  112    int reinhard;
  113    float exposure;
  114    float gamma;
  115    float midtone;
  116    float white;
  117 } g_tonemap_vals = { 1, IMAGE_TYPE_RGBE, 0, 1, 0, 1.0f, 2.2f, 0.36f, 1.0f };
  118 
  119 static struct
  120 {
  121    int rle;
  122    int writelevels;
  123    float exposure;
  124    float gamma;
  125 } g_write_vals = { 1, 0, 1.0f, 2.2f };
  126 
  127 static struct
  128 {
  129    gboolean preview;
  130    float range;
  131 } g_rgbd8_vals = { 1, 1.0f };
  132 
  133 MAIN()
  134 
  135 static void query(void)
  136 {
  137    static GimpParamDef load_args[]=
  138    {
  139       {GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive"},
  140       {GIMP_PDB_STRING, "filename", "The name of the file to load"},
  141       {GIMP_PDB_STRING, "raw_filename", "The name entered"},
  142       {GIMP_PDB_INT32, "tonemap", "Tone map the loaded image"},
  143       {GIMP_PDB_INT32, "use_file_levels", "Use exposure and gamma levels in file for tone mapping"},
  144       {GIMP_PDB_FLOAT, "exposure", "Exposure level (default 1.0)"},
  145       {GIMP_PDB_FLOAT, "gamma", "Gamma level (default 2.2)"}
  146    };
  147 
  148    static GimpParamDef load_return_vals[]=
  149    {
  150       {GIMP_PDB_IMAGE, "image", "Output image"}
  151    };
  152 
  153    static GimpParamDef save_args[]=
  154    {
  155       {GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive"},
  156       {GIMP_PDB_IMAGE, "image", "Input image"},
  157       {GIMP_PDB_DRAWABLE, "drawable", "Drawable to save"},
  158       {GIMP_PDB_STRING, "filename", "The name of the file to save the image as"},
  159       {GIMP_PDB_STRING, "raw_filename", "The name entered"}
  160    };
  161 
  162    static GimpParamDef rgbd8_args[] =
  163    {
  164       {GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive"},
  165       {GIMP_PDB_IMAGE, "image", "Input image (unused)"},
  166       {GIMP_PDB_DRAWABLE, "drawable", "Input drawable"},
  167       {GIMP_PDB_FLOAT, "range", "Map values [0..1] to [0..range] (default 1.0)"}
  168    };
  169 
  170    static GimpParamDef tonemap_args[] =
  171    {
  172       {GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive"},
  173       {GIMP_PDB_IMAGE, "image", "Input image (unused)"},
  174       {GIMP_PDB_DRAWABLE, "drawable", "Input drawable"},
  175       {GIMP_PDB_INT32, "type", "Image type (0 = RGBE, 1 = RGBdiv8)"},
  176       {GIMP_PDB_FLOAT, "exposure", "Exposure"},
  177       {GIMP_PDB_FLOAT, "gamma", "Gamma"},
  178    };
  179 
  180    static GimpParamDef tonemap_logavg_args[] =
  181    {
  182       {GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive"},
  183       {GIMP_PDB_IMAGE, "image", "Input image (unused)"},
  184       {GIMP_PDB_DRAWABLE, "drawable", "Input drawable"},
  185       {GIMP_PDB_INT32, "type", "Image type (0 = RGBE, 1 = RGBdiv8)"},
  186       {GIMP_PDB_FLOAT, "midtone", "Midtone level"},
  187       {GIMP_PDB_FLOAT, "white", "White point"},
  188       {GIMP_PDB_FLOAT, "gamma", "Gamma"},
  189    };
  190 
  191    gimp_install_procedure(LOAD_PROC,
  192                           "Loads files in Radiance RGBE format",
  193                           "Loads files in Radiance RGBE format",
  194                           "Shawn Kirst",
  195                           "Shawn Kirst",
  196                           "2007",
  197                           "<Load>/Radiance RGBE",
  198                           0,
  199                           GIMP_PLUGIN,
  200                           G_N_ELEMENTS(load_args),
  201                           G_N_ELEMENTS(load_return_vals),
  202                           load_args, load_return_vals);
  203 
  204    gimp_register_magic_load_handler(LOAD_PROC,
  205                                     "hdr",
  206                                     "",
  207                                     "0,string,#?RADIANCE");
  208 
  209    gimp_install_procedure(SAVE_PROC,
  210                           "Saves files in Radiance RGBE format",
  211                           "Saves files in Radiance RGBE format",
  212                           "Shawn Kirst",
  213                           "Copyright 2007 Shawn Kirst",
  214                           "2007",
  215                           "<Save>/Radiance RGBE",
  216                           "RGBA",
  217                           GIMP_PLUGIN,
  218                           G_N_ELEMENTS(save_args), 0,
  219                           save_args, 0);
  220 
  221    gimp_register_save_handler(SAVE_PROC, "hdr", "");
  222 
  223    gimp_install_procedure("convert_rgbe_to_rgbdiv8",
  224                           "Converts image from Radiance RGBE to RGBdiv8 format",
  225                           "foo!",
  226                           "Shawn Kirst",
  227                           "Copyright 2007 Shawn Kirst",
  228                           "2007",
  229                           "<Image>/Filters/Colors/HDR Tools/Convert Radiance RGBE to RGBdiv8...",
  230                           "RGBA",
  231                           GIMP_PLUGIN,
  232                           G_N_ELEMENTS(rgbd8_args), 0,
  233                           rgbd8_args, NULL);
  234 
  235    gimp_install_procedure("plug_in_tonemap_rgbe",
  236                           "Converts Radiance RGBE data to LDR RGB",
  237                           "foo!",
  238                           "Shawn Kirst",
  239                           "Copyright 2007 Shawn Kirst",
  240                           "2007",
  241                           "<Image>/Filters/Colors/HDR Tools/Tone map Radiance RGBE image",
  242                           "RGBA",
  243                           GIMP_PLUGIN,
  244                           G_N_ELEMENTS(tonemap_args), 0,
  245                           tonemap_args, NULL);
  246 
  247    gimp_install_procedure("plug_in_tonemap_rgbdiv8",
  248                           "Converts HDR RGBdiv8 data to LDR RGB using the Reinhard tone mapping operator",
  249                           "foo!",
  250                           "Shawn Kirst",
  251                           "Copyright 2007 Shawn Kirst",
  252                           "2007",
  253                           "<Image>/Filters/Colors/HDR Tools/Tone map RGBdiv8 image",
  254                           "RGBA",
  255                           GIMP_PLUGIN,
  256                           G_N_ELEMENTS(tonemap_args), 0,
  257                           tonemap_args, NULL);
  258 
  259    gimp_install_procedure("plug_in_tonemap_logavg_rgbe",
  260                           "Converts Radiance RGBE data to LDR RGB using the Log average luminance tone mapping operator",
  261                           "foo!",
  262                           "Shawn Kirst",
  263                           "Copyright 2007 Shawn Kirst",
  264                           "2007",
  265                           "<Image>/Filters/Colors/HDR Tools/Tone map Radiance RGBE image (Log avg. luminance)",
  266                           "RGBA",
  267                           GIMP_PLUGIN,
  268                           G_N_ELEMENTS(tonemap_logavg_args), 0,
  269                           tonemap_logavg_args, NULL);
  270 
  271    gimp_install_procedure("plug_in_tonemap_logavg_rgbdiv8",
  272                           "Converts HDR RGBdiv8 data to LDR RGB using the Log average luminance tone mapping operator",
  273                           "foo!",
  274                           "Shawn Kirst",
  275                           "Copyright 2007 Shawn Kirst",
  276                           "2007",
  277                           "<Image>/Filters/Colors/HDR Tools/Tone map RGBdiv8 image (Log avg. luminance)",
  278                           "RGBA",
  279                           GIMP_PLUGIN,
  280                           G_N_ELEMENTS(tonemap_logavg_args), 0,
  281                           tonemap_logavg_args, NULL);
  282 
  283 }
  284 
  285 static void run(const gchar *name, gint nparams, const GimpParam *param,
  286                 gint *nreturn_vals, GimpParam **return_vals)
  287 {
  288    static GimpParam values[2];
  289    GimpRunMode run_mode;
  290    GimpPDBStatusType status = GIMP_PDB_SUCCESS;
  291    gint32 imageID, drawableID;
  292    GimpDrawable *drawable;
  293    GimpExportReturn export = GIMP_EXPORT_CANCEL;
  294 
  295    run_mode = param[0].data.d_int32;
  296 
  297    *nreturn_vals = 1;
  298    *return_vals = values;
  299 
  300    values[0].type = GIMP_PDB_STATUS;
  301    values[0].data.d_status = GIMP_PDB_EXECUTION_ERROR;
  302 
  303    if(!strcmp(name, LOAD_PROC))
  304    {
  305       switch(run_mode)
  306       {
  307          case GIMP_RUN_INTERACTIVE:
  308             g_run_interactive = 1;
  309             gimp_ui_init(PROG_NAME, 1);
  310 
  311             if(!gimp_get_data(name, &g_tonemap_vals))
  312             {
  313                g_tonemap_vals.tonemap = 0;
  314                g_tonemap_vals.usefilelevels = 1;
  315                g_tonemap_vals.exposure = 1.0f;
  316                g_tonemap_vals.gamma = 2.2f;
  317                g_tonemap_vals.midtone = 0.36f;
  318             }
  319 
  320             if(!read_rgbe_dialog())
  321             {
  322                status = GIMP_PDB_CANCEL;
  323             }
  324             break;
  325          case GIMP_RUN_NONINTERACTIVE:
  326             g_run_interactive = 0;
  327             if(nparams != 8)
  328                status = GIMP_PDB_CALLING_ERROR;
  329             else
  330             {
  331                g_tonemap_vals.tonemap = param[3].data.d_int32;
  332                g_tonemap_vals.usefilelevels = param[4].data.d_int32;
  333                g_tonemap_vals.exposure = param[5].data.d_float;
  334                g_tonemap_vals.gamma = param[6].data.d_float;
  335                g_tonemap_vals.midtone = param[7].data.d_float;
  336             }
  337             break;
  338          default:
  339             break;
  340       }
  341 
  342       if(status == GIMP_PDB_SUCCESS)
  343       {
  344          imageID = read_rgbe_image(param[1].data.d_string);
  345          if(imageID != -1)
  346          {
  347             *nreturn_vals = 2;
  348             values[1].type = GIMP_PDB_IMAGE;
  349             values[1].data.d_image = imageID;
  350 
  351             if(g_run_interactive)
  352                gimp_set_data(name, &g_tonemap_vals, sizeof(g_tonemap_vals));
  353          }
  354          else
  355             status = GIMP_PDB_EXECUTION_ERROR;
  356       }
  357    }
  358    else if(!strcmp(name, SAVE_PROC))
  359    {
  360       imageID = param[1].data.d_int32;
  361       drawableID = param[2].data.d_int32;
  362 
  363       switch(run_mode)
  364       {
  365          case GIMP_RUN_INTERACTIVE:
  366          case GIMP_RUN_WITH_LAST_VALS:
  367             gimp_ui_init(PROG_NAME, 0);
  368             export = gimp_export_image(&imageID, &drawableID,
  369                                        "Radiance RGBE",
  370                                        (GIMP_EXPORT_CAN_HANDLE_RGB |
  371                                         GIMP_EXPORT_CAN_HANDLE_ALPHA));
  372             if(export == GIMP_EXPORT_CANCEL)
  373             {
  374                values[0].data.d_status = GIMP_PDB_CANCEL;
  375                return;
  376             }
  377          default:
  378             break;
  379       }
  380 
  381       switch(run_mode)
  382       {
  383          case GIMP_RUN_INTERACTIVE:
  384             g_run_interactive = 1;
  385             if(!gimp_get_data(name, &g_write_vals))
  386             {
  387                g_write_vals.rle = 1;
  388                g_write_vals.writelevels = 0;
  389                g_write_vals.exposure = 1.0f;
  390                g_write_vals.gamma = 2.2f;
  391             }
  392             if(!write_rgbe_dialog())
  393             {
  394                values[0].data.d_status = GIMP_PDB_CANCEL;
  395                return;
  396             }
  397             break;
  398          case GIMP_RUN_NONINTERACTIVE:
  399             g_run_interactive = 0;
  400             if(nparams != 5)
  401                status = GIMP_PDB_CALLING_ERROR;
  402             break;
  403          case GIMP_RUN_WITH_LAST_VALS:
  404             g_run_interactive = 1;
  405             gimp_get_data(name, &g_write_vals);
  406             break;
  407          default:
  408             break;
  409       }
  410 
  411       if(status == GIMP_PDB_SUCCESS)
  412       {
  413          status = write_rgbe_image(param[3].data.d_string, imageID,
  414                                    drawableID);
  415          if(g_run_interactive)
  416             gimp_set_data(name, &g_write_vals, sizeof(g_write_vals));
  417       }
  418 
  419       if(export == GIMP_EXPORT_EXPORT)
  420          gimp_image_delete(imageID);
  421    }
  422    else if(!strcmp(name, "convert_rgbe_to_rgbdiv8"))
  423    {
  424       *nreturn_vals = 1;
  425 
  426       drawable = gimp_drawable_get(param[2].data.d_drawable);
  427 
  428       switch(run_mode)
  429       {
  430          case GIMP_RUN_NONINTERACTIVE:
  431             g_run_interactive = 0;
  432             if(nparams != 4)
  433                status = GIMP_PDB_CALLING_ERROR;
  434             g_rgbd8_vals.range = clamp(param[3].data.d_float, 0, 1);
  435             break;
  436          case GIMP_RUN_WITH_LAST_VALS:
  437             g_run_interactive = 1;
  438             gimp_get_data(name, &g_rgbd8_vals);
  439             break;
  440          case GIMP_RUN_INTERACTIVE:
  441             g_run_interactive = 1;
  442             gimp_ui_init(PROG_NAME, 1);
  443             gimp_get_data(name, &g_rgbd8_vals);
  444             if(!rgbd8_dialog(drawable))
  445             {
  446                status = GIMP_PDB_CANCEL;
  447             }
  448             break;
  449       }
  450 
  451       if(status == GIMP_PDB_SUCCESS)
  452       {
  453          convert_rgbe_to_rgbdiv8(NULL, drawable);
  454          if(g_run_interactive)
  455             gimp_set_data(name, &g_rgbd8_vals, sizeof(g_rgbd8_vals));
  456          gimp_displays_flush();
  457          gimp_drawable_detach(drawable);
  458       }
  459    }
  460    else if(!strcmp(name, "plug_in_tonemap_rgbe") ||
  461            !strcmp(name, "plug_in_tonemap_rgbdiv8"))
  462    {
  463       int imgtype = !strcmp(name, "plug_in_tonemap_rgbe") ? IMAGE_TYPE_RGBE : IMAGE_TYPE_RGBDIV8;
  464 
  465       *nreturn_vals = 1;
  466 
  467       drawable = gimp_drawable_get(param[2].data.d_drawable);
  468 
  469       switch(run_mode)
  470       {
  471          case GIMP_RUN_INTERACTIVE:
  472             gimp_ui_init(PROG_NAME, 1);
  473 
  474             if(!gimp_get_data(name, &g_tonemap_vals))
  475             {
  476                g_tonemap_vals.preview = 1;
  477                g_tonemap_vals.exposure = 1.0f;
  478                g_tonemap_vals.gamma = 2.2f;
  479             }
  480 
  481             g_tonemap_vals.imgtype = imgtype;
  482 
  483             if(!tonemap_dialog(drawable))
  484             {
  485                gimp_drawable_detach(drawable);
  486                return;
  487             }
  488             break;
  489          case GIMP_RUN_NONINTERACTIVE:
  490             if(nparams != 6)
  491                status = GIMP_PDB_CALLING_ERROR;
  492             else
  493             {
  494                g_tonemap_vals.imgtype = param[3].data.d_int32;
  495                g_tonemap_vals.exposure = param[4].data.d_float;
  496                g_tonemap_vals.gamma = param[5].data.d_float;
  497             }
  498             break;
  499          case GIMP_RUN_WITH_LAST_VALS:
  500             gimp_get_data(name, &g_tonemap_vals);
  501             g_tonemap_vals.imgtype = imgtype;
  502             break;
  503          default:
  504             break;
  505       }
  506 
  507       tonemap_image(NULL, drawable);
  508 
  509       if(run_mode != GIMP_RUN_NONINTERACTIVE)
  510          gimp_displays_flush();
  511 
  512       if(run_mode == GIMP_RUN_INTERACTIVE)
  513          gimp_set_data(name, &g_tonemap_vals, sizeof(g_tonemap_vals));
  514 
  515       gimp_drawable_detach(drawable);
  516    }
  517    else if(!strcmp(name, "plug_in_tonemap_logavg_rgbe") ||
  518            !strcmp(name, "plug_in_tonemap_logavg_rgbdiv8"))
  519    {
  520       int imgtype = !strcmp(name, "plug_in_tonemap_logavg_rgbe") ? IMAGE_TYPE_RGBE : IMAGE_TYPE_RGBDIV8;
  521 
  522       *nreturn_vals = 1;
  523 
  524       drawable = gimp_drawable_get(param[2].data.d_drawable);
  525 
  526       switch(run_mode)
  527       {
  528          case GIMP_RUN_INTERACTIVE:
  529             gimp_ui_init(PROG_NAME, 1);
  530 
  531             if(!gimp_get_data(name, &g_tonemap_vals))
  532             {
  533                g_tonemap_vals.preview = 1;
  534                g_tonemap_vals.midtone = 0.36f;
  535                g_tonemap_vals.white = 1e6f;
  536                g_tonemap_vals.gamma = 2.2f;
  537             }
  538 
  539             g_tonemap_vals.imgtype = imgtype;
  540 
  541             if(!tonemap_logavg_dialog(drawable))
  542             {
  543                gimp_drawable_detach(drawable);
  544                return;
  545             }
  546             break;
  547          case GIMP_RUN_NONINTERACTIVE:
  548             if(nparams != 7)
  549                status = GIMP_PDB_CALLING_ERROR;
  550             else
  551             {
  552                g_tonemap_vals.imgtype = param[3].data.d_int32;
  553                g_tonemap_vals.midtone = param[4].data.d_float;
  554                g_tonemap_vals.white = param[5].data.d_float;
  555                g_tonemap_vals.gamma = param[6].data.d_float;
  556             }
  557             break;
  558          case GIMP_RUN_WITH_LAST_VALS:
  559             gimp_get_data(name, &g_tonemap_vals);
  560             g_tonemap_vals.imgtype = imgtype;
  561             break;
  562          default:
  563             break;
  564       }
  565 
  566       tonemap_image_logavg(NULL, drawable);
  567 
  568       if(run_mode != GIMP_RUN_NONINTERACTIVE)
  569          gimp_displays_flush();
  570 
  571       if(run_mode == GIMP_RUN_INTERACTIVE)
  572          gimp_set_data(name, &g_tonemap_vals, sizeof(g_tonemap_vals));
  573 
  574       gimp_drawable_detach(drawable);
  575    }
  576    else
  577       status = GIMP_PDB_CALLING_ERROR;
  578 
  579    values[0].data.d_status = status;
  580 }
  581 
  582 static int rgbe_read_header(rgbe_header_t *hdr, FILE *fp)
  583 {
  584    char buf[128];
  585    float val;
  586 
  587    hdr->flags = 0;
  588 
  589    if(fgets(buf, sizeof(buf), fp) == 0)
  590       return(-1);
  591 
  592    if(strncmp(buf, "#?RADIANCE", 10))
  593       return(-2);
  594 
  595    while(fgets(buf, sizeof(buf), fp))
  596    {
  597       if(strncmp(buf, "FORMAT=", 7) == 0)
  598       {
  599          // eat format
  600       }
  601       else if(strncmp(buf, "SOFTWARE=", 9) == 0)
  602       {
  603          // eat creator
  604       }
  605       else if(sscanf(buf, "GAMMA=%g", &val) == 1)
  606       {
  607          hdr->gamma = val;
  608          hdr->flags |= RGBE_HAS_GAMMA;
  609       }
  610       else if(sscanf(buf, "EXPOSURE=%g", &val) == 1)
  611       {
  612          hdr->exposure = val;
  613          hdr->flags |= RGBE_HAS_EXPOSURE;
  614       }
  615       else if(buf[0] == '-' && buf[1] == 'Y')
  616       {
  617          if(sscanf(buf, "-Y %d +X %d", &hdr->height, &hdr->width) < 2)
  618             return(-3);
  619          break;
  620       }
  621       else if(buf[0] == '+' && buf[1] == 'X')
  622       {
  623          if(sscanf(buf, "+X %d +Y %d", &hdr->width, &hdr->height) < 2)
  624             return(-3);
  625          break;
  626       }
  627    }
  628 
  629    return(0);
  630 }
  631 
  632 static int rgbe_read_pixels(FILE *fp, unsigned char *data, int num)
  633 {
  634    int n = num * 4;
  635    int r = fread(data, 1, n, fp);
  636    return(-(n != r));
  637 }
  638 
  639 static int rgbe_read_pixels_RLE(FILE *fp, unsigned char *data,
  640                                 int width, int height)
  641 {
  642    unsigned char rgbe[4], *buffer, *ptr, *end, *dst;
  643    int i, count, rc = 0, h = height;
  644    unsigned char buf[2];
  645 
  646    dst = data;
  647 
  648    if((width < 8) || (width > 0x7fff))
  649       return(rgbe_read_pixels(fp, data, width * height));
  650 
  651    buffer = 0;
  652 
  653    while(h > 0)
  654    {
  655       if(fread(rgbe, 1, 4, fp) != 4)
  656       {
  657          rc = -1;
  658          goto read_error;
  659       }
  660 
  661       if((rgbe[0] != 2) || (rgbe[1] != 2) || (rgbe[2] & 0x80))
  662       {
  663          data[0] = rgbe[0];
  664          data[1] = rgbe[1];
  665          data[2] = rgbe[2];
  666          data[3] = rgbe[3];
  667 
  668          if(buffer)
  669             g_free(buffer);
  670 
  671          rc = rgbe_read_pixels(fp, &data[4], (width * h) - 1);
  672 
  673          return(rc ? -2 : 0);
  674       }
  675 
  676       if((((int)rgbe[2]) << 8 | rgbe[3]) != width)
  677       {
  678          rc = -3;
  679          goto read_error;
  680       }
  681 
  682       if(buffer == 0)
  683          buffer = g_malloc(4 * width);
  684 
  685       ptr = buffer;
  686 
  687       for(i = 0; i < 4; ++i)
  688       {
  689          end = &buffer[(i + 1) * width];
  690          while(ptr < end)
  691          {
  692             if(fread(buf, 1, 2, fp) != 2)
  693             {
  694                rc = -4;
  695                goto read_error;
  696             }
  697 
  698             if(buf[0] > 128)
  699             {
  700                count = buf[0] & 0x7f;
  701                if((count == 0) || (count > (end - ptr)))
  702                {
  703                   rc = -5;
  704                   goto read_error;
  705                }
  706 
  707                while(count-- > 0)
  708                   *ptr++ = buf[1];
  709             }
  710             else
  711             {
  712                count = buf[0];
  713                if((count == 0) || (count > (end - ptr)))
  714                {
  715                   rc = -6;
  716                   goto read_error;
  717                }
  718 
  719                *ptr++ = buf[1];
  720 
  721                if(--count > 0)
  722                {
  723                   if(fread(ptr, 1, count, fp) != count)
  724                   {
  725                      rc = -7;
  726                      goto read_error;
  727                   }
  728 
  729                   ptr += count;
  730                }
  731             }
  732          }
  733       }
  734 
  735       for(i = 0; i < width; ++i)
  736       {
  737          dst[4 * i + 0] = buffer[i];
  738          dst[4 * i + 1] = buffer[i + width];
  739          dst[4 * i + 2] = buffer[i + 2 * width];
  740          dst[4 * i + 3] = buffer[i + 3 * width];
  741       }
  742 
  743       dst += 4 * width;
  744 
  745       --h;
  746 
  747       if(g_run_interactive)
  748          gimp_progress_update((gdouble)(height - h) / (gdouble)height);
  749    }
  750 
  751 read_error:
  752 
  753    if(buffer)
  754       g_free(buffer);
  755 
  756    return(rc);
  757 }
  758 
  759 static gint32 read_rgbe_image(gchar *filename)
  760 {
  761    FILE *fp;
  762    int rc;
  763    rgbe_header_t hdr;
  764    unsigned char *pixels;
  765    gchar *tmp;
  766    GimpPixelRgn pixel_rgn;
  767    gint32 image, layer;
  768    GimpDrawable *drawable;
  769 
  770    if(g_run_interactive)
  771    {
  772       tmp = g_strdup_printf("Loading %s:", filename);
  773       gimp_progress_init(tmp);
  774       g_free(tmp);
  775    }
  776 
  777    fp = fopen(filename, "rb");
  778    if(fp == 0)
  779    {
  780       g_message("%s: can't open \"%s\"", PROG_NAME, filename);
  781       return(-1);
  782    }
  783 
  784    rc = rgbe_read_header(&hdr, fp);
  785 
  786    if(rc != 0)
  787    {
  788       g_message("rgbe_read_header() = %d\n", rc);
  789       fclose(fp);
  790       return(-1);
  791    }
  792 
  793    if(g_tonemap_vals.usefilelevels)
  794    {
  795       if(hdr.flags & RGBE_HAS_EXPOSURE)
  796          g_tonemap_vals.exposure = hdr.exposure;
  797       else
  798          g_tonemap_vals.exposure = 1.0f;
  799 
  800       if(hdr.flags & RGBE_HAS_GAMMA)
  801          g_tonemap_vals.gamma = hdr.gamma;
  802       else
  803          g_tonemap_vals.gamma = 2.2f;
  804    }
  805 
  806    pixels = g_malloc(4 * hdr.width * hdr.height);
  807    if(pixels == 0)
  808    {
  809       g_message("Can't allocate pixel buffer\n%s", filename);
  810       fclose(fp);
  811       return(-1);
  812    }
  813 
  814    image = gimp_image_new(hdr.width, hdr.height, GIMP_RGB);
  815    if(image == -1)
  816    {
  817       g_message("Can't allocate new image\n%s", filename);
  818       fclose(fp);
  819       g_free(pixels);
  820       return(-1);
  821    }
  822 
  823    layer = gimp_layer_new(image, "Background", hdr.width, hdr.height,
  824                           GIMP_RGBA_IMAGE, 100, GIMP_NORMAL_MODE);
  825 
  826    gimp_image_set_filename(image, filename);
  827    gimp_image_add_layer(image, layer, 0);
  828    drawable = gimp_drawable_get(layer);
  829 
  830    rc = rgbe_read_pixels_RLE(fp, pixels, hdr.width, hdr.height);
  831    if(rc != 0)
  832    {
  833       g_message("rgbe_read_pixels_RLE() = %d\n", rc);
  834       fclose(fp);
  835       g_free(pixels);
  836       return(-1);
  837    }
  838 
  839    fclose(fp);
  840 
  841    if(g_run_interactive)
  842       gimp_progress_update(1.0);
  843 
  844    gimp_pixel_rgn_init(&pixel_rgn, drawable, 0, 0, drawable->width,
  845                        drawable->height, 1, 0);
  846    gimp_pixel_rgn_set_rect(&pixel_rgn, pixels, 0, 0, drawable->width,
  847                            drawable->height);
  848 
  849    gimp_drawable_flush(drawable);
  850 
  851    if(g_tonemap_vals.tonemap)
  852    {
  853       g_tonemap_vals.imgtype = IMAGE_TYPE_RGBE;
  854       tonemap_image(NULL, drawable);
  855    }
  856 
  857    gimp_drawable_detach(drawable);
  858 
  859    g_free(pixels);
  860 
  861    return(image);
  862 }
  863 
  864 static int rgbe_write_pixels(FILE *fp, unsigned char *data, int num)
  865 {
  866    int n = 4 * num;
  867    int w = fwrite(data, 1, n, fp);
  868    return(-(w != n));
  869 }
  870 
  871 static int rgbe_write_bytes_RLE(FILE *fp, unsigned char *data, int num)
  872 {
  873 #define MIN_RUN_LENGTH 4
  874 
  875    int cur, beg_run, run_count, old_run_count, nonrun_count;
  876    unsigned char buf[2];
  877 
  878    cur = 0;
  879    while(cur < num)
  880    {
  881       beg_run = cur;
  882 
  883       run_count = old_run_count = 0;
  884       while((run_count < MIN_RUN_LENGTH) && (beg_run < num))
  885       {
  886          beg_run += run_count;
  887          old_run_count = run_count;
  888          run_count = 1;
  889          while((beg_run + run_count < num) && (run_count < 127) &&
  890                (data[beg_run] == data[beg_run + run_count]))
  891             run_count++;
  892       }
  893 
  894       if((old_run_count > 1) && (old_run_count == beg_run - cur))
  895       {
  896          buf[0] = 128 + old_run_count;
  897          buf[1] = data[cur];
  898          if(fwrite(buf, 2, 1, fp) < 1)
  899             return(-1);
  900          cur = beg_run;
  901       }
  902 
  903       while(cur < beg_run)
  904       {
  905          nonrun_count = beg_run - cur;
  906          if(nonrun_count > 128)
  907             nonrun_count = 128;
  908          buf[0] = nonrun_count;
  909          if(fwrite(buf, 1, 1, fp) < 1)
  910             return(-1);
  911          if(fwrite(&data[cur], nonrun_count, 1, fp) < 1)
  912             return(-1);
  913          cur += nonrun_count;
  914       }
  915 
  916       if (run_count >= MIN_RUN_LENGTH)
  917       {
  918          buf[0] = 128 + run_count;
  919          buf[1] = data[beg_run];
  920          if(fwrite(buf, 2, 1, fp) < 1)
  921             return(-1);
  922          cur += run_count;
  923       }
  924    }
  925 
  926    return(0);
  927 
  928 #undef MINRUNLENGTH
  929 }
  930 
  931 static int rgbe_write_pixels_RLE(FILE *fp, unsigned char *data,
  932                                  int rle, int width, int height)
  933 {
  934    unsigned char rgbe[4], *buffer;
  935    int i, rc = 0;
  936 
  937    if(!rle || ((width < 8) || (width > 0x7fff)))
  938       return(rgbe_write_pixels(fp, data, width * height));
  939 
  940    buffer = (unsigned char *)g_malloc(4 * width);
  941 
  942    while(height-- > 0)
  943    {
  944       rgbe[0] = 2;
  945       rgbe[1] = 2;
  946       rgbe[2] = width >> 8;
  947       rgbe[3] = width & 0xff;
  948 
  949       if(fwrite(rgbe, sizeof(rgbe), 1, fp) < 1)
  950       {
  951          g_free(buffer);
  952          return(-1);
  953       }
  954 
  955       for(i = 0; i < width; ++i)
  956       {
  957          buffer[i] = data[4 * i];
  958          buffer[i + width] = data[4 * i + 1];
  959          buffer[i + 2 * width] = data[4 * i + 2];
  960          buffer[i + 3 * width] = data[4 * i + 3];
  961       }
  962 
  963       data += 4 * width;
  964 
  965       /* write out each of the four channels separately run length encoded */
  966       /* first red, then green, then blue, then exponent */
  967       for(i = 0; i < 4; ++i)
  968       {
  969          if((rc = rgbe_write_bytes_RLE(fp, &buffer[i * width], width)))
  970          {
  971             g_free(buffer);
  972             return(rc);
  973          }
  974       }
  975    }
  976 
  977    g_free(buffer);
  978 
  979    return(rc);
  980 }
  981 
  982 static GimpPDBStatusType write_rgbe_image(gchar *filename, gint32 imageID,
  983                                           gint32 drawableID)
  984 {
  985    FILE *fp;
  986    GimpDrawable *drawable;
  987    GimpImageType drawable_type;
  988    GimpPixelRgn rgn;
  989    int rc;
  990    guchar *pixels;
  991    gchar *tmp;
  992 
  993    drawable = gimp_drawable_get(drawableID);
  994    drawable_type = gimp_drawable_type(drawableID);
  995    gimp_pixel_rgn_init(&rgn, drawable, 0, 0, drawable->width,
  996                        drawable->height, 0, 0);
  997 
  998    fp = fopen(filename, "wb");
  999    if(fp == 0)
 1000    {
 1001       g_message("Error opening %s", filename);
 1002       return(GIMP_PDB_EXECUTION_ERROR);
 1003    }
 1004 
 1005    pixels = g_malloc(drawable->width * drawable->height * 4);
 1006    gimp_pixel_rgn_get_rect(&rgn, pixels, 0, 0, drawable->width,
 1007                            drawable->height);
 1008 
 1009    if(g_run_interactive)
 1010    {
 1011       tmp = g_strdup_printf("Saving %s:", filename);
 1012       gimp_progress_init(tmp);
 1013       g_free(tmp);
 1014    }
 1015 
 1016    fprintf(fp,
 1017            "#?RADIANCE\n"
 1018            "# %s\n"
 1019            "SOFTWARE=GIMP HDR tools\n"
 1020            "FORMAT=32-bit_rle_rgbe\n",
 1021            g_write_vals.rle ? "RLE compressed" : "Not RLE compressed");
 1022 
 1023    if(g_write_vals.writelevels)
 1024    {
 1025       fprintf(fp,
 1026               "EXPOSURE=%f\n"
 1027               "GAMMA=%f\n",
 1028               g_write_vals.exposure, g_write_vals.gamma);
 1029    }
 1030 
 1031    fprintf(fp,
 1032            "\n-Y %d +X %d\n",
 1033            drawable->height, drawable->width);
 1034 
 1035    rc = rgbe_write_pixels_RLE(fp, pixels, g_write_vals.rle,
 1036                               drawable->width, drawable->height);
 1037    fclose(fp);
 1038 
 1039    gimp_drawable_detach(drawable);
 1040 
 1041    g_free(pixels);
 1042 
 1043    return(rc ? GIMP_PDB_EXECUTION_ERROR : GIMP_PDB_SUCCESS);
 1044 }
 1045 
 1046 static void convert_rgbe_to_rgbdiv8(GimpPreview *preview,
 1047                                     GimpDrawable *drawable)
 1048 {
 1049    GimpPixelRgn srcrgn, dstrgn;
 1050    unsigned char *src, *dst, *rgbe;
 1051    float rgb[3], maxchan, v, range;
 1052    int sx, sy, x, y, w, h, n, idx = 0;
 1053 
 1054    range = g_rgbd8_vals.range;
 1055 
 1056    if(preview)
 1057    {
 1058       gimp_preview_get_position(preview, &sx, &sy);
 1059       gimp_preview_get_size(preview, &w, &h);
 1060    }
 1061    else
 1062    {
 1063       sx = 0;
 1064       sy = 0;
 1065       w = drawable->width;
 1066       h = drawable->height;
 1067    }
 1068 
 1069    n = w * h;
 1070    dst = g_malloc(n * 4);
 1071    src = g_malloc(n * 4);
 1072 
 1073    gimp_pixel_rgn_init(&srcrgn, drawable, sx, sy, w, h, 0, 0);
 1074    gimp_pixel_rgn_get_rect(&srcrgn, src, sx, sy, w, h);
 1075 
 1076    if(!preview)
 1077       gimp_progress_init("Converting to RGBdiv8...");
 1078 
 1079    for(y = 0; y < h; ++y)
 1080    {
 1081       for(x = 0; x < w; ++x)
 1082       {
 1083          rgbe = &src[idx];
 1084          if(rgbe[3])
 1085          {
 1086             v = ldexpf(1.0f, rgbe[3] - 136);
 1087             rgb[0] = (float)rgbe[0] * v;
 1088             rgb[1] = (float)rgbe[1] * v;
 1089             rgb[2] = (float)rgbe[2] * v;
 1090          }
 1091          else
 1092             rgb[0] = rgb[1] = rgb[2] = 0;
 1093 
 1094          maxchan = max(range, max(rgb[0], max(rgb[1], rgb[2])));
 1095 
 1096          dst[idx++] = (unsigned char)(255.0f * rgb[0] / maxchan);
 1097          dst[idx++] = (unsigned char)(255.0f * rgb[1] / maxchan);
 1098          dst[idx++] = (unsigned char)(255.0f * rgb[2] / maxchan);
 1099          dst[idx++] = (unsigned char)(255.0f * range  / maxchan);
 1100       }
 1101 
 1102       if(!preview)
 1103          gimp_progress_update((gdouble)y / (gdouble)drawable->height);
 1104    }
 1105 
 1106 
 1107    gimp_pixel_rgn_init(&dstrgn, drawable, sx, sy, w, h,
 1108                        preview == NULL, 1);
 1109    gimp_pixel_rgn_set_rect(&dstrgn, dst, sx, sy, w, h);
 1110 
 1111    if(preview)
 1112    {
 1113       gimp_drawable_preview_draw_region(GIMP_DRAWABLE_PREVIEW(preview),
 1114                                         &dstrgn);
 1115    }
 1116    else
 1117    {
 1118       gimp_progress_update(1.0);
 1119 
 1120       gimp_drawable_flush(drawable);
 1121       gimp_drawable_merge_shadow(drawable->drawable_id, 1);
 1122       gimp_drawable_update(drawable->drawable_id, 0, 0, w, h);
 1123    }
 1124 
 1125    g_free(src);
 1126    g_free(dst);
 1127 }
 1128 
 1129 static float compute_log_average_luminance(unsigned char *pixels,
 1130                                            int imgtype, int w, int h)
 1131 {
 1132    int i, n;
 1133    float rgb[3], v, lum, sum = 0;
 1134 
 1135    gimp_progress_init("Computing log average luminance...");
 1136 
 1137    n = w * h;
 1138 
 1139    for(i = 0; i < n; ++i)
 1140    {
 1141       if((i % w) == 0)
 1142          gimp_progress_update((gdouble)i / (gdouble)n);
 1143 
 1144       if(g_tonemap_vals.imgtype == IMAGE_TYPE_RGBE)
 1145       {
 1146          if(pixels[4 * i + 3])
 1147          {
 1148             v = ldexpf(1.0f, pixels[4 * i + 3] - 136);
 1149             rgb[0] = (float)pixels[4 * i + 0] * v;
 1150             rgb[1] = (float)pixels[4 * i + 1] * v;
 1151             rgb[2] = (float)pixels[4 * i + 2] * v;
 1152          }
 1153          else
 1154             rgb[0] = rgb[1] = rgb[2] = 0;
 1155       }
 1156       else
 1157       {
 1158          v = (float)pixels[4 * i + 3] / 255.0f;
 1159          if(v > 0)
 1160          {
 1161             rgb[0] = ((float)pixels[4 * i + 0] / 255.0f) / v;
 1162             rgb[1] = ((float)pixels[4 * i + 1] / 255.0f) / v;
 1163             rgb[2] = ((float)pixels[4 * i + 2] / 255.0f) / v;
 1164          }
 1165          else
 1166             rgb[0] = rgb[1] = rgb[2] = FLT_MAX;
 1167       }
 1168 
 1169       lum = rgb[0] * 0.2126f + rgb[1] * 0.7152f + rgb[2] * 0.0722f;
 1170       sum += logf(1e-04f + lum);
 1171    }
 1172 
 1173    gimp_progress_update(1.0);
 1174 
 1175    return(sum / (float)(w * h));
 1176 }
 1177 
 1178 static void tonemap_image_logavg(GimpPreview *preview, GimpDrawable *drawable)
 1179 {
 1180    GimpPixelRgn srcrgn, dstrgn;
 1181    unsigned char *src, *dst;
 1182    float *data;
 1183    float log_avg_lum = 0, rgb[3], v, weight, white;
 1184    int sx, sy, x, y, w, h, n, idx;
 1185 
 1186    if(preview)
 1187    {
 1188       gimp_preview_get_position(preview, &sx, &sy);
 1189       gimp_preview_get_size(preview, &w, &h);
 1190    }
 1191    else
 1192    {
 1193       sx = 0;
 1194       sy = 0;
 1195       w = drawable->width;
 1196       h = drawable->height;
 1197    }
 1198 
 1199    if(preview)
 1200    {
 1201       data = g_object_get_data(G_OBJECT(preview), "logavglum");
 1202       if(!data)
 1203       {
 1204          data = g_malloc(sizeof(float));
 1205          src = g_malloc(drawable->width * drawable->height * 4);
 1206          gimp_pixel_rgn_init(&srcrgn, drawable, 0, 0, drawable->width,
 1207                              drawable->height, 0, 0);
 1208          gimp_pixel_rgn_get_rect(&srcrgn, src, 0, 0, drawable->width,
 1209                                  drawable->height);
 1210          log_avg_lum = compute_log_average_luminance(src,
 1211                                                      g_tonemap_vals.imgtype,
 1212                                                      drawable->width, drawable->height);
 1213          data[0] = log_avg_lum;
 1214          g_free(src);
 1215          g_object_set_data(G_OBJECT(preview), "logavglum", data);
 1216       }
 1217       else
 1218       {
 1219          log_avg_lum = data[0];
 1220       }
 1221    }
 1222 
 1223    n = w * h;
 1224 
 1225    dst = g_malloc(n * 4);
 1226    src = g_malloc(n * 4);
 1227 
 1228    gimp_pixel_rgn_init(&srcrgn, drawable, sx, sy, w, h, 0, 0);
 1229    gimp_pixel_rgn_get_rect(&srcrgn, src, sx, sy, w, h);
 1230 
 1231    if(!preview)
 1232    {
 1233       log_avg_lum = compute_log_average_luminance(src,
 1234                                                   g_tonemap_vals.imgtype,
 1235                                                   drawable->width,
 1236                                                   drawable->height);
 1237    }
 1238 
 1239    weight = g_tonemap_vals.midtone / (1e-03f + expf(log_avg_lum));
 1240    white = g_tonemap_vals.white;
 1241 
 1242    if(!preview)
 1243       gimp_progress_init("Tone mapping image...");
 1244 
 1245    for(y = 0; y < h; ++y)
 1246    {
 1247       for(x = 0; x < w; ++x)
 1248       {
 1249          idx = (y * (w * 4)) + (x * 4);
 1250 
 1251          if(g_tonemap_vals.imgtype == IMAGE_TYPE_RGBE)
 1252          {
 1253             if(src[idx + 3])
 1254             {
 1255                v = ldexpf(1.0f, src[idx + 3] - 136);
 1256                rgb[0] = (float)src[idx + 0] * v;
 1257                rgb[1] = (float)src[idx + 1] * v;
 1258                rgb[2] = (float)src[idx + 2] * v;
 1259             }
 1260             else
 1261                rgb[0] = rgb[1] = rgb[2] = 0;
 1262          }
 1263          else
 1264          {
 1265             v = (float)src[idx + 3] / 255.0f;
 1266             if(v > 0)
 1267             {
 1268                rgb[0] = ((float)src[idx + 0] / 255.0f) / v;
 1269                rgb[1] = ((float)src[idx + 1] / 255.0f) / v;
 1270                rgb[2] = ((float)src[idx + 2] / 255.0f) / v;
 1271             }
 1272             else
 1273                rgb[0] = rgb[1] = rgb[2] = FLT_MAX;
 1274          }
 1275 
 1276          rgb[0] *= weight;
 1277          rgb[1] *= weight;
 1278          rgb[2] *= weight;
 1279 
 1280          rgb[0] = (rgb[0] * (1.0f + (rgb[0] / white))) / (1.0f + rgb[0]);
 1281          rgb[1] = (rgb[1] * (1.0f + (rgb[1] / white))) / (1.0f + rgb[1]);
 1282          rgb[2] = (rgb[2] * (1.0f + (rgb[2] / white))) / (1.0f + rgb[2]);
 1283 
 1284          //rgb[0] = rgb[0] / (1.0f + rgb[0]);
 1285          //rgb[1] = rgb[1] / (1.0f + rgb[1]);
 1286          //rgb[2] = rgb[2] / (1.0f + rgb[2]);
 1287 
 1288          rgb[0] = powf(rgb[0], 1.0f / g_tonemap_vals.gamma);
 1289          rgb[1] = powf(rgb[1], 1.0f / g_tonemap_vals.gamma);
 1290          rgb[2] = powf(rgb[2], 1.0f / g_tonemap_vals.gamma);
 1291 
 1292          dst[idx + 0] = (unsigned char)(255.0f * min(rgb[0], 1.0f));
 1293          dst[idx + 1] = (unsigned char)(255.0f * min(rgb[1], 1.0f));
 1294          dst[idx + 2] = (unsigned char)(255.0f * min(rgb[2], 1.0f));
 1295          dst[idx + 3] = 255;
 1296       }
 1297 
 1298       if(!preview)
 1299          gimp_progress_update((gdouble)y / (gdouble)h);
 1300    }
 1301 
 1302    gimp_pixel_rgn_init(&dstrgn, drawable, sx, sy, w, h,
 1303                        preview == NULL, 1);
 1304    gimp_pixel_rgn_set_rect(&dstrgn, dst, sx, sy, w, h);
 1305 
 1306    if(preview)
 1307    {
 1308       gimp_drawable_preview_draw_region(GIMP_DRAWABLE_PREVIEW(preview),
 1309                                         &dstrgn);
 1310    }
 1311    else
 1312    {
 1313       gimp_progress_update(1.0);
 1314 
 1315       gimp_drawable_flush(drawable);
 1316       gimp_drawable_merge_shadow(drawable->drawable_id, 1);
 1317       gimp_drawable_update(drawable->drawable_id, 0, 0, w, h);
 1318    }
 1319 
 1320    g_free(src);
 1321    g_free(dst);
 1322 }
 1323 
 1324 static void tonemap_image(GimpPreview *preview, GimpDrawable *drawable)
 1325 {
 1326    GimpPixelRgn srcrgn, dstrgn;
 1327    unsigned char *src, *dst;
 1328    float rgb[3], v;
 1329    int sx, sy, x, y, w, h, n, idx = 0;
 1330 
 1331    if(preview)
 1332    {
 1333       gimp_preview_get_position(preview, &sx, &sy);
 1334       gimp_preview_get_size(preview, &w, &h);
 1335    }
 1336    else
 1337    {
 1338       sx = 0;
 1339       sy = 0;
 1340       w = drawable->width;
 1341       h = drawable->height;
 1342    }
 1343 
 1344    n = w * h;
 1345 
 1346    dst = g_malloc(n * 4);
 1347    src = g_malloc(n * 4);
 1348 
 1349    gimp_pixel_rgn_init(&srcrgn, drawable, sx, sy, w, h, 0, 0);
 1350    gimp_pixel_rgn_get_rect(&srcrgn, src, sx, sy, w, h);
 1351 
 1352    if(!preview)
 1353       gimp_progress_init("Tone mapping image...");
 1354 
 1355    for(y = 0; y < h; ++y)
 1356    {
 1357       for(x = 0; x < w; ++x)
 1358       {
 1359          if(g_tonemap_vals.imgtype == IMAGE_TYPE_RGBE)
 1360          {
 1361             if(src[idx + 3])
 1362             {
 1363                v = ldexpf(1.0f, src[idx + 3] - 136);
 1364                rgb[0] = (float)src[idx + 0] * v;
 1365                rgb[1] = (float)src[idx + 1] * v;
 1366                rgb[2] = (float)src[idx + 2] * v;
 1367             }
 1368             else
 1369                rgb[0] = rgb[1] = rgb[2] = 0;
 1370          }
 1371          else
 1372          {
 1373             v = (float)src[idx + 3] / 255.0f;
 1374             if(v > 0)
 1375             {
 1376                rgb[0] = ((float)src[idx + 0] / 255.0f) / v;
 1377                rgb[1] = ((float)src[idx + 1] / 255.0f) / v;
 1378                rgb[2] = ((float)src[idx + 2] / 255.0f) / v;
 1379             }
 1380             else
 1381                rgb[0] = rgb[1] = rgb[2] = FLT_MAX;
 1382          }
 1383 
 1384          /* exposure */
 1385          rgb[0] = 1.0f - expf(-rgb[0] * g_tonemap_vals.exposure);
 1386          rgb[1] = 1.0f - expf(-rgb[1] * g_tonemap_vals.exposure);
 1387          rgb[2] = 1.0f - expf(-rgb[2] * g_tonemap_vals.exposure);
 1388 
 1389          /* gamma correction */
 1390          rgb[0] = powf(rgb[0], 1.0f / g_tonemap_vals.gamma);
 1391          rgb[1] = powf(rgb[1], 1.0f / g_tonemap_vals.gamma);
 1392          rgb[2] = powf(rgb[2], 1.0f / g_tonemap_vals.gamma);
 1393 
 1394          rgb[0] = clamp(rgb[0], 0, 1);
 1395          rgb[1] = clamp(rgb[1], 0, 1);
 1396          rgb[2] = clamp(rgb[2], 0, 1);
 1397 
 1398          dst[idx++] = (unsigned char)(255.0f * rgb[0]);
 1399          dst[idx++] = (unsigned char)(255.0f * rgb[1]);
 1400          dst[idx++] = (unsigned char)(255.0f * rgb[2]);
 1401          dst[idx++] = 255;
 1402       }
 1403 
 1404       if(!preview)
 1405          gimp_progress_update((gdouble)y / (gdouble)h);
 1406    }
 1407 
 1408    gimp_pixel_rgn_init(&dstrgn, drawable, sx, sy, w, h,
 1409                        preview == NULL, 1);
 1410    gimp_pixel_rgn_set_rect(&dstrgn, dst, sx, sy, w, h);
 1411 
 1412    if(preview)
 1413    {
 1414       gimp_drawable_preview_draw_region(GIMP_DRAWABLE_PREVIEW(preview),
 1415                                         &dstrgn);
 1416    }
 1417    else
 1418    {
 1419       gimp_progress_update(1.0);
 1420 
 1421       gimp_drawable_flush(drawable);
 1422       gimp_drawable_merge_shadow(drawable->drawable_id, 1);
 1423       gimp_drawable_update(drawable->drawable_id, 0, 0, w, h);
 1424    }
 1425 
 1426    g_free(src);
 1427    g_free(dst);
 1428 }
 1429 
 1430 static void on_spin_changed(GtkWidget *widget, gpointer data)
 1431 {
 1432    float *val = (float*)data;
 1433    *val = gtk_spin_button_get_value(GTK_SPIN_BUTTON(widget));
 1434    GimpPreview *preview = g_object_get_data(G_OBJECT(widget), "preview");
 1435    if(preview)
 1436       gimp_preview_invalidate(preview);
 1437 }
 1438 
 1439 static void on_slider_changed(GtkWidget *widget, gpointer data)
 1440 {
 1441    float *val = (float*)data;
 1442    *val = gtk_range_get_value(GTK_RANGE(widget));
 1443    GimpPreview *preview = g_object_get_data(G_OBJECT(widget), "preview");
 1444    if(preview)
 1445       gimp_preview_invalidate(preview);
 1446 }
 1447 
 1448 static void on_checkbox_clicked(GtkWidget *widget, gpointer data)
 1449 {
 1450    int *val = (int*)data;
 1451    *val = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
 1452 }
 1453 
 1454 static void on_preview_destroy(GtkWidget *widget, gpointer data)
 1455 {
 1456    void *ptr = g_object_get_data(G_OBJECT(widget), "logavglum");
 1457    if(ptr)
 1458       g_free(ptr);
 1459 }
 1460 
 1461 static void dialog_response(GtkWidget *widget, gint response_id,
 1462                             gpointer data)
 1463 {
 1464    switch(response_id)
 1465    {
 1466       case GTK_RESPONSE_OK:
 1467          g_runme = 1;
 1468       default:
 1469          gtk_widget_destroy(widget);
 1470          break;
 1471    }
 1472 }
 1473 
 1474 static int tonemap_logavg_dialog(GimpDrawable *drawable)
 1475 {
 1476    GtkWidget *dlg;
 1477    GtkWidget *table;
 1478    GtkWidget *label;
 1479    GtkObject *adj;
 1480    GtkWidget *hbox;
 1481    GtkWidget *preview, *midtone_spin, *white_spin, *gamma_spin;
 1482 
 1483    dlg = gimp_dialog_new("Tone map image (Log average luminance)", PROG_NAME,
 1484                          0, 0, 0, 0,
 1485                          GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
 1486                          GTK_STOCK_OK, GTK_RESPONSE_OK,
 1487                          NULL);
 1488 
 1489    hbox = gtk_hbox_new(0, 8);
 1490    gtk_widget_show(hbox);
 1491    gtk_container_set_border_width(GTK_CONTAINER(hbox), 8);
 1492    gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg)->vbox), hbox, 1, 1, 0);
 1493 
 1494    preview = gimp_drawable_preview_new(drawable, &g_tonemap_vals.preview);
 1495    gtk_widget_show(preview);
 1496    gtk_box_pack_start(GTK_BOX(hbox), preview, 1, 1, 0);
 1497 
 1498    table = gtk_table_new(3, 2, 0);
 1499    gtk_widget_show(table);
 1500    gtk_box_pack_start(GTK_BOX(hbox), table, 1, 1, 0);
 1501    gtk_table_set_row_spacings(GTK_TABLE(table), 8);
 1502    gtk_table_set_col_spacings(GTK_TABLE(table), 8);
 1503 
 1504    label = gtk_label_new("Midtone:");
 1505    gtk_widget_show(label);
 1506    gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
 1507    gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, GTK_FILL, 0, 0, 0);
 1508 
 1509    adj = gtk_adjustment_new(g_tonemap_vals.midtone, 0, 65536, 0.01, 0.05, 1);
 1510    midtone_spin = gtk_spin_button_new(GTK_ADJUSTMENT(adj), 0.01, 2);
 1511    gtk_widget_show(midtone_spin);
 1512    gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(midtone_spin),
 1513                                      GTK_UPDATE_IF_VALID);
 1514    gtk_table_attach(GTK_TABLE(table), midtone_spin, 1, 2, 0, 1,
 1515                     GTK_EXPAND | GTK_FILL, 0, 0, 0);
 1516    g_object_set_data(G_OBJECT(midtone_spin), "preview", preview);
 1517 
 1518 
 1519    label = gtk_label_new("White point:");
 1520    gtk_widget_show(label);
 1521    gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
 1522    gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2, GTK_FILL, 0, 0, 0);
 1523 
 1524    adj = gtk_adjustment_new(g_tonemap_vals.white, 0, FLT_MAX, 0.01, 0.05, 1);
 1525    white_spin = gtk_spin_button_new(GTK_ADJUSTMENT(adj), 0.01, 2);
 1526    gtk_widget_show(white_spin);
 1527    gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(white_spin),
 1528                                      GTK_UPDATE_IF_VALID);
 1529    gtk_table_attach(GTK_TABLE(table), white_spin, 1, 2, 1, 2,
 1530                     GTK_EXPAND | GTK_FILL, 0, 0, 0);
 1531    g_object_set_data(G_OBJECT(white_spin), "preview", preview);
 1532 
 1533    label = gtk_label_new("Gamma:");
 1534    gtk_widget_show(label);
 1535    gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
 1536    gtk_table_attach(GTK_TABLE(table), label, 0, 1, 2, 3, GTK_FILL, 0, 0, 0);
 1537 
 1538    adj = gtk_adjustment_new(g_tonemap_vals.gamma, 0, 100, 0.1, 0.5, 1);
 1539    gamma_spin = gtk_spin_button_new(GTK_ADJUSTMENT(adj), 0.1, 1);
 1540    gtk_widget_show(gamma_spin);
 1541    gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(gamma_spin),
 1542                                      GTK_UPDATE_IF_VALID);
 1543    gtk_table_attach(GTK_TABLE(table), gamma_spin, 1, 2, 2, 3,
 1544                     GTK_EXPAND | GTK_FILL, 0, 0, 0);
 1545    g_object_set_data(G_OBJECT(gamma_spin), "preview", preview);
 1546 
 1547 
 1548    gtk_signal_connect(GTK_OBJECT(dlg), "response",
 1549                       GTK_SIGNAL_FUNC(dialog_response), 0);
 1550    gtk_signal_connect(GTK_OBJECT(dlg), "destroy",
 1551                       GTK_SIGNAL_FUNC(gtk_main_quit), 0);
 1552    gtk_signal_connect(GTK_OBJECT(preview), "invalidated",
 1553                       GTK_SIGNAL_FUNC(tonemap_image_logavg),
 1554                       drawable);
 1555    gtk_signal_connect(GTK_OBJECT(preview), "destroy",
 1556                       GTK_SIGNAL_FUNC(on_preview_destroy), 0);
 1557    gtk_signal_connect(GTK_OBJECT(midtone_spin), "value_changed",
 1558                       GTK_SIGNAL_FUNC(on_spin_changed),
 1559                       &g_tonemap_vals.midtone);
 1560    gtk_signal_connect(GTK_OBJECT(white_spin), "value_changed",
 1561                       GTK_SIGNAL_FUNC(on_spin_changed),
 1562                       &g_tonemap_vals.white);
 1563    gtk_signal_connect(GTK_OBJECT(gamma_spin), "value_changed",
 1564                       GTK_SIGNAL_FUNC(on_spin_changed),
 1565                       &g_tonemap_vals.gamma);
 1566 
 1567    gtk_widget_show(dlg);
 1568 
 1569    g_runme = 0;
 1570 
 1571    gtk_main();
 1572 
 1573    return(g_runme);
 1574 }
 1575 
 1576 static int tonemap_dialog(GimpDrawable *drawable)
 1577 {
 1578    GtkWidget *dlg;
 1579    GtkWidget *table;
 1580    GtkWidget *label;
 1581    GtkObject *adj;
 1582    GtkWidget *hbox;
 1583    GtkWidget *preview, *exposure_spin, *gamma_spin;
 1584 
 1585    dlg = gimp_dialog_new("Tone map image", PROG_NAME,
 1586                          0, 0, 0, 0,
 1587                          GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
 1588                          GTK_STOCK_OK, GTK_RESPONSE_OK,
 1589                          NULL);
 1590 
 1591    hbox = gtk_hbox_new(0, 8);
 1592    gtk_widget_show(hbox);
 1593    gtk_container_set_border_width(GTK_CONTAINER(hbox), 8);
 1594    gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg)->vbox), hbox, 1, 1, 0);
 1595 
 1596    preview = gimp_drawable_preview_new(drawable, &g_tonemap_vals.preview);
 1597    gtk_widget_show(preview);
 1598    gtk_box_pack_start(GTK_BOX(hbox), preview, 1, 1, 0);
 1599 
 1600    table = gtk_table_new(2, 2, 0);
 1601    gtk_widget_show(table);
 1602    gtk_box_pack_start(GTK_BOX(hbox), table, 1, 1, 0);
 1603    gtk_table_set_row_spacings(GTK_TABLE(table), 8);
 1604    gtk_table_set_col_spacings(GTK_TABLE(table), 8);
 1605 
 1606    label = gtk_label_new("Exposure:");
 1607    gtk_widget_show(label);
 1608    gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
 1609    gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, GTK_FILL, 0, 0, 0);
 1610 
 1611    adj = gtk_adjustment_new(g_tonemap_vals.exposure, 0, 100, 0.1, 0.5, 1);
 1612    exposure_spin = gtk_spin_button_new(GTK_ADJUSTMENT(adj), 0.1, 1);
 1613    gtk_widget_show(exposure_spin);
 1614    gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(exposure_spin),
 1615                                      GTK_UPDATE_IF_VALID);
 1616    gtk_table_attach(GTK_TABLE(table), exposure_spin, 1, 2, 0, 1,
 1617                     GTK_EXPAND | GTK_FILL, 0, 0, 0);
 1618    g_object_set_data(G_OBJECT(exposure_spin), "preview", preview);
 1619 
 1620    label = gtk_label_new("Gamma:");
 1621    gtk_widget_show(label);
 1622    gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
 1623    gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2, GTK_FILL, 0, 0, 0);
 1624 
 1625    adj = gtk_adjustment_new(g_tonemap_vals.gamma, 0, 100, 0.1, 0.5, 1);
 1626    gamma_spin = gtk_spin_button_new(GTK_ADJUSTMENT(adj), 0.1, 1);
 1627    gtk_widget_show(gamma_spin);
 1628    gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(gamma_spin),
 1629                                      GTK_UPDATE_IF_VALID);
 1630    gtk_table_attach(GTK_TABLE(table), gamma_spin, 1, 2, 1, 2,
 1631                     GTK_EXPAND | GTK_FILL, 0, 0, 0);
 1632    g_object_set_data(G_OBJECT(gamma_spin), "preview", preview);
 1633 
 1634 
 1635    gtk_signal_connect(GTK_OBJECT(dlg), "response",
 1636                       GTK_SIGNAL_FUNC(dialog_response), 0);
 1637    gtk_signal_connect(GTK_OBJECT(dlg), "destroy",
 1638                       GTK_SIGNAL_FUNC(gtk_main_quit), 0);
 1639    gtk_signal_connect(GTK_OBJECT(preview), "invalidated",
 1640                       GTK_SIGNAL_FUNC(tonemap_image),
 1641                       drawable);
 1642    gtk_signal_connect(GTK_OBJECT(exposure_spin), "value_changed",
 1643                       GTK_SIGNAL_FUNC(on_spin_changed),
 1644                       &g_tonemap_vals.exposure);
 1645    gtk_signal_connect(GTK_OBJECT(gamma_spin), "value_changed",
 1646                       GTK_SIGNAL_FUNC(on_spin_changed),
 1647                       &g_tonemap_vals.gamma);
 1648 
 1649    gtk_widget_show(dlg);
 1650 
 1651    g_runme = 0;
 1652 
 1653    gtk_main();
 1654 
 1655    return(g_runme);
 1656 }
 1657 
 1658 static int rgbd8_dialog(GimpDrawable *drawable)
 1659 {
 1660    GtkWidget *dlg;
 1661    GtkObject *adj;
 1662    GtkWidget *slider;
 1663    GtkWidget *vbox;
 1664    GtkWidget *table;
 1665    GtkWidget *preview;
 1666 
 1667    dlg = gimp_dialog_new("Convert Radiance RGBE to RGBdiv8", PROG_NAME,
 1668                          0, 0, 0, 0,
 1669                          GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
 1670                          GTK_STOCK_OK, GTK_RESPONSE_OK,
 1671                          NULL);
 1672 
 1673    vbox = gtk_vbox_new(0, 0);
 1674    gtk_widget_show(vbox);
 1675    gtk_container_set_border_width(GTK_CONTAINER(vbox), 8);
 1676    gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg)->vbox), vbox, 1, 1, 0);
 1677 
 1678    table = gtk_table_new(2, 2, 0);
 1679    gtk_widget_show(table);
 1680    gtk_box_pack_start(GTK_BOX(vbox), table, 1, 1, 0);
 1681    gtk_table_set_row_spacings(GTK_TABLE(table), 8);
 1682    gtk_table_set_col_spacings(GTK_TABLE(table), 8);
 1683 
 1684    preview = gimp_drawable_preview_new(drawable, &g_rgbd8_vals.preview);
 1685    gtk_widget_show(preview);
 1686    gtk_table_attach(GTK_TABLE(table), preview, 0, 2, 0, 1,
 1687                     GTK_EXPAND | GTK_FILL, 0, 0, 0);
 1688 
 1689    adj = gtk_adjustment_new(g_rgbd8_vals.range, 0, 1, 0.01, 0.1, 0);
 1690    slider = gtk_hscale_new(GTK_ADJUSTMENT(adj));
 1691    gtk_widget_show(slider);
 1692    gtk_scale_set_value_pos(GTK_SCALE(slider), GTK_POS_RIGHT);
 1693    gtk_scale_set_digits(GTK_SCALE(slider), 2);
 1694    gimp_table_attach_aligned(GTK_TABLE(table), 0, 1, "Range:", 0, 0.5,
 1695                              slider, 1, 0);
 1696    g_object_set_data(G_OBJECT(slider), "preview", preview);
 1697 
 1698    gtk_signal_connect(GTK_OBJECT(dlg), "response",
 1699                       GTK_SIGNAL_FUNC(dialog_response), 0);
 1700    gtk_signal_connect(GTK_OBJECT(dlg), "destroy",
 1701                       GTK_SIGNAL_FUNC(gtk_main_quit), 0);
 1702    gtk_signal_connect(GTK_OBJECT(preview), "invalidated",
 1703                       GTK_SIGNAL_FUNC(convert_rgbe_to_rgbdiv8), drawable);
 1704    gtk_signal_connect(GTK_OBJECT(slider), "value_changed",
 1705                       GTK_SIGNAL_FUNC(on_slider_changed),
 1706                       &g_rgbd8_vals.range);
 1707 
 1708    gtk_widget_show(dlg);
 1709 
 1710    g_runme = 0;
 1711 
 1712    gtk_main();
 1713 
 1714    return(g_runme);
 1715 }
 1716 
 1717 static void on_file_levels_checked(GtkWidget *widget, gpointer data)
 1718 {
 1719    GtkWidget *spin;
 1720    int val = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
 1721 
 1722    *((int *)data) = val;
 1723 
 1724    spin = g_object_get_data(G_OBJECT(widget), "exposure_spin");
 1725    gtk_widget_set_sensitive(spin, !val);
 1726    spin = g_object_get_data(G_OBJECT(widget), "gamma_spin");
 1727    gtk_widget_set_sensitive(spin, !val);
 1728 }
 1729 
 1730 static int read_rgbe_dialog(void)
 1731 {
 1732    GtkWidget *dlg;
 1733    GtkWidget *table;
 1734    GtkWidget *label;
 1735    GtkObject *adj;
 1736    GtkWidget *tmchk, *uflchk, *exposure_spin, *gamma_spin;
 1737 
 1738    dlg = gimp_dialog_new("Load RGBE image", PROG_NAME,
 1739                          0, 0, 0, 0,
 1740                          GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
 1741                          GTK_STOCK_OK, GTK_RESPONSE_OK,
 1742                          NULL);
 1743 
 1744    table = gtk_table_new(4, 2, 0);
 1745    gtk_widget_show(table);
 1746    gtk_container_set_border_width(GTK_CONTAINER(table), 8);
 1747    gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg)->vbox), table, 1, 1, 0);
 1748    gtk_table_set_row_spacings(GTK_TABLE(table), 8);
 1749    gtk_table_set_col_spacings(GTK_TABLE(table), 8);
 1750 
 1751    tmchk = gtk_check_button_new_with_label("Tone map image");
 1752    gtk_widget_show(tmchk);
 1753    gtk_table_attach(GTK_TABLE(table), tmchk, 0, 2, 0, 1,
 1754                     GTK_EXPAND | GTK_FILL, 0, 0, 0);
 1755    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(tmchk),
 1756                                 g_tonemap_vals.tonemap);
 1757 
 1758    uflchk = gtk_check_button_new_with_label("Use file levels");
 1759    gtk_widget_show(uflchk);
 1760    gtk_table_attach(GTK_TABLE(table), uflchk, 0, 2, 1, 2,
 1761                     GTK_EXPAND | GTK_FILL, 0, 0, 0);
 1762    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(uflchk),
 1763                                 g_tonemap_vals.usefilelevels);
 1764 
 1765    label = gtk_label_new("Exposure:");
 1766    gtk_widget_show(label);
 1767    gtk_table_attach(GTK_TABLE(table), label, 0, 1, 2, 3, GTK_FILL, 0, 0, 0);
 1768    gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
 1769 
 1770    adj = gtk_adjustment_new(g_tonemap_vals.exposure, 0, 100, 0.1, 0.5, 0.1);
 1771    exposure_spin = gtk_spin_button_new(GTK_ADJUSTMENT(adj), 0.1, 1);
 1772    gtk_widget_show(exposure_spin);
 1773    gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(exposure_spin),
 1774                                      GTK_UPDATE_IF_VALID);
 1775    gtk_table_attach(GTK_TABLE(table), exposure_spin, 1, 2, 2, 3,
 1776                     GTK_EXPAND | GTK_FILL, 0, 0, 0);
 1777    gtk_widget_set_sensitive(exposure_spin, !g_tonemap_vals.usefilelevels);
 1778 
 1779    label = gtk_label_new("Gamma:");
 1780    gtk_widget_show(label);
 1781    gtk_table_attach(GTK_TABLE(table), label, 0, 1, 3, 4, GTK_FILL, 0, 0, 0);
 1782    gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
 1783 
 1784    adj = gtk_adjustment_new(g_tonemap_vals.gamma, 0, 100, 0.1, 0.5, 0.1);
 1785    gamma_spin = gtk_spin_button_new(GTK_ADJUSTMENT(adj), 0.1, 1);
 1786    gtk_widget_show(gamma_spin);
 1787    gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(gamma_spin),
 1788                                      GTK_UPDATE_IF_VALID);
 1789    gtk_table_attach(GTK_TABLE(table), gamma_spin, 1, 2, 3, 4,
 1790                     GTK_EXPAND | GTK_FILL, 0, 0, 0);
 1791    gtk_widget_set_sensitive(gamma_spin, !g_tonemap_vals.usefilelevels);
 1792 
 1793    g_object_set_data(G_OBJECT(uflchk), "exposure_spin", exposure_spin);
 1794    g_object_set_data(G_OBJECT(uflchk), "gamma_spin", gamma_spin);
 1795 
 1796    gtk_signal_connect(GTK_OBJECT(dlg), "response",
 1797                       GTK_SIGNAL_FUNC(dialog_response), 0);
 1798    gtk_signal_connect(GTK_OBJECT(dlg), "destroy",
 1799                       GTK_SIGNAL_FUNC(gtk_main_quit), 0);
 1800    gtk_signal_connect(GTK_OBJECT(tmchk), "clicked",
 1801                       GTK_SIGNAL_FUNC(on_checkbox_clicked),
 1802                       &g_tonemap_vals.tonemap);
 1803    gtk_signal_connect(GTK_OBJECT(uflchk), "clicked",
 1804                       GTK_SIGNAL_FUNC(on_file_levels_checked),
 1805                       &g_tonemap_vals.usefilelevels);
 1806    gtk_signal_connect(GTK_OBJECT(exposure_spin), "value_changed",
 1807                       GTK_SIGNAL_FUNC(on_spin_changed),
 1808                       &g_tonemap_vals.exposure);
 1809    gtk_signal_connect(GTK_OBJECT(gamma_spin), "value_changed",
 1810                       GTK_SIGNAL_FUNC(on_spin_changed),
 1811                       &g_tonemap_vals.gamma);
 1812 
 1813    gtk_widget_show(dlg);
 1814 
 1815    g_runme = 0;
 1816 
 1817    gtk_main();
 1818 
 1819    return(g_runme);
 1820 }
 1821 
 1822 static void on_write_levels_checked(GtkWidget *widget, gpointer data)
 1823 {
 1824    GtkWidget *spin;
 1825    int val = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
 1826 
 1827    *((int *)data) = val;
 1828 
 1829    spin = g_object_get_data(G_OBJECT(widget), "exposure_spin");
 1830    gtk_widget_set_sensitive(spin, val);
 1831    spin = g_object_get_data(G_OBJECT(widget), "gamma_spin");
 1832    gtk_widget_set_sensitive(spin, val);
 1833 }
 1834 
 1835 static int write_rgbe_dialog(void)
 1836 {
 1837    GtkWidget *dlg;
 1838    GtkWidget *table;
 1839    GtkWidget *label;
 1840    GtkObject *adj;
 1841    GtkWidget *rlechk, *wlchk, *exposure_spin, *gamma_spin;
 1842 
 1843    dlg = gimp_dialog_new("Save RGBE image", PROG_NAME,
 1844                          0, 0, 0, 0,
 1845                          GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
 1846                          GTK_STOCK_OK, GTK_RESPONSE_OK,
 1847                          NULL);
 1848 
 1849    table = gtk_table_new(4, 2, 0);
 1850    gtk_widget_show(table);
 1851    gtk_container_set_border_width(GTK_CONTAINER(table), 8);
 1852    gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg)->vbox), table, 1, 1, 0);
 1853    gtk_table_set_row_spacings(GTK_TABLE(table), 8);
 1854    gtk_table_set_col_spacings(GTK_TABLE(table), 8);
 1855 
 1856    rlechk = gtk_check_button_new_with_label("RLE compression");
 1857    gtk_widget_show(rlechk);
 1858    gtk_table_attach(GTK_TABLE(table), rlechk, 0, 2, 0, 1,
 1859                     GTK_EXPAND | GTK_FILL, 0, 0, 0);
 1860    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(rlechk),
 1861                                 g_write_vals.rle);
 1862 
 1863    wlchk = gtk_check_button_new_with_label("Write exposure and gamma");
 1864    gtk_widget_show(wlchk);
 1865    gtk_table_attach(GTK_TABLE(table), wlchk, 0, 2, 1, 2,
 1866                     GTK_EXPAND | GTK_FILL, 0, 0, 0);
 1867    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(wlchk),
 1868                                 g_write_vals.writelevels);
 1869 
 1870    label = gtk_label_new("Exposure:");
 1871    gtk_widget_show(label);
 1872    gtk_table_attach(GTK_TABLE(table), label, 0, 1, 2, 3, GTK_FILL, 0, 0, 0);
 1873    gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
 1874 
 1875    adj = gtk_adjustment_new(g_write_vals.exposure, 0, 100, 0.1, 0.5, 0.1);
 1876    exposure_spin = gtk_spin_button_new(GTK_ADJUSTMENT(adj), 0.1, 1);
 1877    gtk_widget_show(exposure_spin);
 1878    gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(exposure_spin),
 1879                                      GTK_UPDATE_IF_VALID);
 1880    gtk_table_attach(GTK_TABLE(table), exposure_spin, 1, 2, 2, 3,
 1881                     GTK_EXPAND | GTK_FILL, 0, 0, 0);
 1882    gtk_widget_set_sensitive(exposure_spin, g_write_vals.writelevels);
 1883 
 1884    label = gtk_label_new("Gamma:");
 1885    gtk_widget_show(label);
 1886    gtk_table_attach(GTK_TABLE(table), label, 0, 1, 3, 4, GTK_FILL, 0, 0, 0);
 1887    gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
 1888 
 1889    adj = gtk_adjustment_new(g_write_vals.gamma, 0, 100, 0.1, 0.5, 0.1);
 1890    gamma_spin = gtk_spin_button_new(GTK_ADJUSTMENT(adj), 0.1, 1);
 1891    gtk_widget_show(gamma_spin);
 1892    gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(gamma_spin),
 1893                                      GTK_UPDATE_IF_VALID);
 1894    gtk_table_attach(GTK_TABLE(table), gamma_spin, 1, 2, 3, 4,
 1895                     GTK_EXPAND | GTK_FILL, 0, 0, 0);
 1896    gtk_widget_set_sensitive(gamma_spin, g_write_vals.writelevels);
 1897 
 1898    g_object_set_data(G_OBJECT(wlchk), "exposure_spin", exposure_spin);
 1899    g_object_set_data(G_OBJECT(wlchk), "gamma_spin", gamma_spin);
 1900 
 1901    gtk_signal_connect(GTK_OBJECT(dlg), "response",
 1902                       GTK_SIGNAL_FUNC(dialog_response), 0);
 1903    gtk_signal_connect(GTK_OBJECT(dlg), "destroy",
 1904                       GTK_SIGNAL_FUNC(gtk_main_quit), 0);
 1905    gtk_signal_connect(GTK_OBJECT(rlechk), "clicked",
 1906                       GTK_SIGNAL_FUNC(on_checkbox_clicked),
 1907                       &g_write_vals.rle);
 1908    gtk_signal_connect(GTK_OBJECT(wlchk), "clicked",
 1909                       GTK_SIGNAL_FUNC(on_write_levels_checked),
 1910                       &g_write_vals.writelevels);
 1911    gtk_signal_connect(GTK_OBJECT(exposure_spin), "value_changed",
 1912                       GTK_SIGNAL_FUNC(on_spin_changed),
 1913                       &g_write_vals.exposure);
 1914    gtk_signal_connect(GTK_OBJECT(gamma_spin), "value_changed",
 1915                       GTK_SIGNAL_FUNC(on_spin_changed),
 1916                       &g_write_vals.gamma);
 1917 
 1918    gtk_widget_show(dlg);
 1919 
 1920    g_runme = 0;
 1921 
 1922    gtk_main();
 1923 
 1924    return(g_runme);
 1925 }

ViewVC Help
Powered by ViewVC 1.0.4