|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
#include <gegl.h>
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
#include <cstdlib>
|
|
Packit Service |
2781ba |
#include <cstdio>
|
|
Packit Service |
2781ba |
#include <cerrno>
|
|
Packit Service |
2781ba |
#include <cmath>
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
#include <iostream>
|
|
Packit Service |
2781ba |
|
|
Packit Service |
952136 |
#include <gexiv2/gexiv2.h>
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
using namespace std;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
enum
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
ARG_COMMAND,
|
|
Packit Service |
2781ba |
ARG_OUTPUT,
|
|
Packit Service |
2781ba |
ARG_PATH_0,
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
NUM_ARGS
|
|
Packit Service |
2781ba |
};
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static const
|
|
Packit Service |
2781ba |
gchar *COMBINER_INPUT_PREFIX = "exposure-";
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static void
|
|
Packit Service |
2781ba |
check_usage (gint argc, gchar **argv)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
if (argc == 1)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
g_print ("This tool combines multiple exposures of one scene into a "
|
|
Packit Service |
2781ba |
"single buffer.\n");
|
|
Packit Service |
2781ba |
goto die;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
if (argc < NUM_ARGS)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
g_print ("Error: Insufficient arguments\n");
|
|
Packit Service |
2781ba |
goto die;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
return;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
die:
|
|
Packit Service |
2781ba |
g_print ("Usage: %s <output> <input> [<input> ...]\n", argv[0]);
|
|
Packit Service |
2781ba |
exit (EXIT_FAILURE);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static gfloat
|
|
Packit Service |
2781ba |
expcombine_get_file_ev (const gchar *path)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
952136 |
GError *error = NULL;
|
|
Packit Service |
952136 |
GExiv2Metadata *e2m = gexiv2_metadata_new ();
|
|
Packit Service |
952136 |
gfloat time, aperture, gain = 1.0f;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
952136 |
gexiv2_metadata_open_path (e2m, path, &error);
|
|
Packit Service |
952136 |
if (error)
|
|
Packit Service |
952136 |
{
|
|
Packit Service |
952136 |
g_warning ("%s", error->message);
|
|
Packit Service |
952136 |
exit (EXIT_FAILURE);
|
|
Packit Service |
952136 |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
/* Calculate the APEX brightness / EV */
|
|
Packit Service |
2781ba |
|
|
Packit Service |
952136 |
{
|
|
Packit Service |
952136 |
gint nom, den;
|
|
Packit Service |
952136 |
gexiv2_metadata_get_exposure_time (e2m, &nom, &den;;
|
|
Packit Service |
952136 |
time = nom * 1.0f / den;
|
|
Packit Service |
952136 |
}
|
|
Packit Service |
952136 |
aperture = gexiv2_metadata_get_fnumber (e2m);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
/* iso */
|
|
Packit Service |
952136 |
if (gexiv2_metadata_has_tag (e2m, "Exif.Image.ISOSpeedRatings"))
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
952136 |
gain = gexiv2_metadata_get_iso_speed (e2m) / 100.0f;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
952136 |
else
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
// Assume ISO is set at 100. It's reasonably likely that the ISO is the
|
|
Packit Service |
2781ba |
// same across all images anyway, and for our purposes the relative
|
|
Packit Service |
2781ba |
// values can be sufficient.
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
gain = 1.0f;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
return log2f (aperture * aperture) + log2f (1 / time) + log2f (gain);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
int
|
|
Packit Service |
2781ba |
main (int argc,
|
|
Packit Service |
2781ba |
char **argv)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
guint cursor;
|
|
Packit Service |
2781ba |
GeglNode *gegl, *combiner, *sink;
|
|
Packit Service |
2781ba |
gchar *all_evs = g_strdup ("");
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
g_thread_init (NULL);
|
|
Packit Service |
2781ba |
gegl_init (&argc, &argv);
|
|
Packit Service |
2781ba |
check_usage (argc, argv);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
gegl = gegl_node_new ();
|
|
Packit Service |
2781ba |
combiner = gegl_node_new_child (gegl,
|
|
Packit Service |
2781ba |
"operation", "gegl:exp-combine",
|
|
Packit Service |
2781ba |
NULL);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
for (cursor = ARG_PATH_0; cursor < argc; ++cursor)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
const gchar *input_path;
|
|
Packit Service |
2781ba |
gchar ev_string[G_ASCII_DTOSTR_BUF_SIZE + 1];
|
|
Packit Service |
2781ba |
gfloat ev_val;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
gchar combiner_pad[strlen (COMBINER_INPUT_PREFIX) +
|
|
Packit Service |
2781ba |
G_ASCII_DTOSTR_BUF_SIZE + 1];
|
|
Packit Service |
2781ba |
gint err;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
GeglNode *img;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
input_path = argv[cursor];
|
|
Packit Service |
2781ba |
ev_val = expcombine_get_file_ev (input_path);
|
|
Packit Service |
2781ba |
if (isnan (ev_val))
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
g_print ("Failed to calculate exposure value for '%s'\n",
|
|
Packit Service |
2781ba |
input_path);
|
|
Packit Service |
2781ba |
exit (EXIT_FAILURE);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
g_ascii_dtostr (ev_string, G_N_ELEMENTS (ev_string), ev_val);
|
|
Packit Service |
2781ba |
all_evs = g_strconcat (all_evs, " ", ev_string, NULL);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
/* Construct and link the input image into the combiner */
|
|
Packit Service |
2781ba |
img = gegl_node_new_child (gegl,
|
|
Packit Service |
2781ba |
"operation", "gegl:load",
|
|
Packit Service |
2781ba |
"path", input_path,
|
|
Packit Service |
2781ba |
NULL);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
/* Create the exposure pad name */
|
|
Packit Service |
2781ba |
err = snprintf (combiner_pad,
|
|
Packit Service |
2781ba |
G_N_ELEMENTS (combiner_pad),
|
|
Packit Service |
2781ba |
"%s%u",
|
|
Packit Service |
2781ba |
COMBINER_INPUT_PREFIX,
|
|
Packit Service |
2781ba |
cursor - ARG_PATH_0);
|
|
Packit Service |
2781ba |
if (err < 1 || err >= G_N_ELEMENTS (combiner_pad))
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
g_warning ("Unable to construct input pad name for exposure %u\n",
|
|
Packit Service |
2781ba |
cursor);
|
|
Packit Service |
2781ba |
return (EXIT_FAILURE);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
gegl_node_connect_to (img, "output", combiner, combiner_pad);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
g_return_val_if_fail (all_evs[0] == ' ', EXIT_FAILURE);
|
|
Packit Service |
2781ba |
gegl_node_set (combiner, "exposures", all_evs + 1, NULL);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
/* We should not have skipped past the last element of the arguments */
|
|
Packit Service |
2781ba |
g_return_val_if_fail (cursor == argc, EXIT_FAILURE);
|
|
Packit Service |
2781ba |
sink = gegl_node_new_child (gegl,
|
|
Packit Service |
2781ba |
"operation", "gegl:save",
|
|
Packit Service |
2781ba |
"path", argv[ARG_OUTPUT],
|
|
Packit Service |
2781ba |
NULL);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
gegl_node_link_many (combiner, sink, NULL);
|
|
Packit Service |
2781ba |
gegl_node_process (sink);
|
|
Packit Service |
2781ba |
return (EXIT_SUCCESS);
|
|
Packit Service |
2781ba |
}
|