|
Packit Service |
2781ba |
/* This file is an image processing operation for GEGL
|
|
Packit Service |
2781ba |
*
|
|
Packit Service |
2781ba |
* GEGL is free software; you can redistribute it and/or
|
|
Packit Service |
2781ba |
* modify it under the terms of the GNU Lesser General Public
|
|
Packit Service |
2781ba |
* License as published by the Free Software Foundation; either
|
|
Packit Service |
2781ba |
* version 3 of the License, or (at your option) any later version.
|
|
Packit Service |
2781ba |
*
|
|
Packit Service |
2781ba |
* GEGL is distributed in the hope that it will be useful,
|
|
Packit Service |
2781ba |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit Service |
2781ba |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit Service |
2781ba |
* Lesser General Public License for more details.
|
|
Packit Service |
2781ba |
*
|
|
Packit Service |
2781ba |
* You should have received a copy of the GNU Lesser General Public
|
|
Packit Service |
2781ba |
* License along with GEGL; if not, see <http://www.gnu.org/licenses/>.
|
|
Packit Service |
2781ba |
*
|
|
Packit Service |
2781ba |
* Copyright 2011 Rasmus Hahn <rassahah@googlemail.com>
|
|
Packit Service |
2781ba |
*/
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
#ifdef GEGL_CHANT_PROPERTIES
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
gegl_chant_string (path, "File", "", "path of file to write to.")
|
|
Packit Service |
2781ba |
gegl_chant_int (tile, "Tile", 0, 2048, 0, "tile size to use.")
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
#else
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
#define GEGL_CHANT_TYPE_SINK
|
|
Packit Service |
2781ba |
#define GEGL_CHANT_C_FILE "exr-save.cc"
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
extern "C" {
|
|
Packit Service |
2781ba |
#include "gegl-chant.h"
|
|
Packit Service |
2781ba |
} /* extern "C" */
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
#include "config.h"
|
|
Packit Service |
2781ba |
#include <exception>
|
|
Packit Service |
2781ba |
#include <ImfTiledOutputFile.h>
|
|
Packit Service |
2781ba |
#include <ImfOutputFile.h>
|
|
Packit Service |
2781ba |
#include <ImfChannelList.h>
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
/**
|
|
Packit Service |
2781ba |
* create an Imf::Header for writing up to 4 channels (given in d).
|
|
Packit Service |
2781ba |
* d must be between 1 and 4.
|
|
Packit Service |
2781ba |
*/
|
|
Packit Service |
2781ba |
static Imf::Header
|
|
Packit Service |
2781ba |
create_header (int w,
|
|
Packit Service |
2781ba |
int h,
|
|
Packit Service |
2781ba |
int d)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
Imf::Header header (w, h);
|
|
Packit Service |
2781ba |
Imf::FrameBuffer fbuf;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
if (d <= 2)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
header.channels ().insert ("Y", Imf::Channel (Imf::FLOAT));
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
else
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
header.channels ().insert ("R", Imf::Channel (Imf::FLOAT));
|
|
Packit Service |
2781ba |
header.channels ().insert ("G", Imf::Channel (Imf::FLOAT));
|
|
Packit Service |
2781ba |
header.channels ().insert ("B", Imf::Channel (Imf::FLOAT));
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
if (d == 2 || d == 4)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
header.channels ().insert ("A", Imf::Channel (Imf::FLOAT));
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
return header;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
/**
|
|
Packit Service |
2781ba |
* create an Imf::FrameBuffer object for w*h*d floats and return it.
|
|
Packit Service |
2781ba |
*/
|
|
Packit Service |
2781ba |
static Imf::FrameBuffer
|
|
Packit Service |
2781ba |
create_frame_buffer (int w,
|
|
Packit Service |
2781ba |
int h,
|
|
Packit Service |
2781ba |
int d,
|
|
Packit Service |
2781ba |
const float *data)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
Imf::FrameBuffer fbuf;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
if (d <= 2)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
fbuf.insert ("Y", Imf::Slice (Imf::FLOAT, (char *) (&data[0] + 0),
|
|
Packit Service |
2781ba |
d * sizeof *data, d * sizeof *data * w));
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
else
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
fbuf.insert ("R", Imf::Slice (Imf::FLOAT, (char *) (&data[0] + 0),
|
|
Packit Service |
2781ba |
d * sizeof *data, d * sizeof *data * w));
|
|
Packit Service |
2781ba |
fbuf.insert ("G", Imf::Slice (Imf::FLOAT, (char *) (&data[0] + 1),
|
|
Packit Service |
2781ba |
d * sizeof *data, d * sizeof *data * w));
|
|
Packit Service |
2781ba |
fbuf.insert ("B", Imf::Slice (Imf::FLOAT, (char *) (&data[0] + 2),
|
|
Packit Service |
2781ba |
d * sizeof *data, d * sizeof *data * w));
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
if (d == 2 || d == 4)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
fbuf.insert ("A", Imf::Slice (Imf::FLOAT, (char *) (&data[0] + (d - 1)),
|
|
Packit Service |
2781ba |
d * sizeof *data, d * sizeof *data * w));
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
return fbuf;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
/**
|
|
Packit Service |
2781ba |
* write the float buffer to an exr file with tile-size tw x th.
|
|
Packit Service |
2781ba |
* The buffer must contain w*h*d floats.
|
|
Packit Service |
2781ba |
* Currently supported are only values 1-4 for d:
|
|
Packit Service |
2781ba |
* d=1: write a single Y-channel.
|
|
Packit Service |
2781ba |
* d=2: write Y and A.
|
|
Packit Service |
2781ba |
* d=3: write RGB.
|
|
Packit Service |
2781ba |
* d=4: write RGB and A.
|
|
Packit Service |
2781ba |
*/
|
|
Packit Service |
2781ba |
static void
|
|
Packit Service |
2781ba |
write_tiled_exr (const float *pixels,
|
|
Packit Service |
2781ba |
int w,
|
|
Packit Service |
2781ba |
int h,
|
|
Packit Service |
2781ba |
int d,
|
|
Packit Service |
2781ba |
int tw,
|
|
Packit Service |
2781ba |
int th,
|
|
Packit Service |
2781ba |
const std::string &filename)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
Imf::Header header (create_header (w, h, d));
|
|
Packit Service |
2781ba |
header.setTileDescription (Imf::TileDescription (tw, th, Imf::ONE_LEVEL));
|
|
Packit Service |
2781ba |
Imf::TiledOutputFile out (filename.c_str (), header);
|
|
Packit Service |
2781ba |
Imf::FrameBuffer fbuf (create_frame_buffer (w, h, d, pixels));
|
|
Packit Service |
2781ba |
out.setFrameBuffer (fbuf);
|
|
Packit Service |
2781ba |
out.writeTiles (0, out.numXTiles () - 1, 0, out.numYTiles () - 1);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
/**
|
|
Packit Service |
2781ba |
* write an openexr file in scanline mode.
|
|
Packit Service |
2781ba |
* pixels contains the image data as an array of w*h*d floats.
|
|
Packit Service |
2781ba |
* The data is written to the file named filename.
|
|
Packit Service |
2781ba |
*/
|
|
Packit Service |
2781ba |
static void
|
|
Packit Service |
2781ba |
write_scanline_exr (const float *pixels,
|
|
Packit Service |
2781ba |
int w,
|
|
Packit Service |
2781ba |
int h,
|
|
Packit Service |
2781ba |
int d,
|
|
Packit Service |
2781ba |
const std::string &filename)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
Imf::Header header (create_header (w, h, d));
|
|
Packit Service |
2781ba |
Imf::OutputFile out (filename.c_str (), header);
|
|
Packit Service |
2781ba |
Imf::FrameBuffer fbuf (create_frame_buffer (w, h, d, pixels));
|
|
Packit Service |
2781ba |
out.setFrameBuffer (fbuf);
|
|
Packit Service |
2781ba |
out.writePixels (h);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
/**
|
|
Packit Service |
2781ba |
* write the given pixel buffer, which is w * h * d to filename using the
|
|
Packit Service |
2781ba |
* tilesize as tile width and height. This is the only function calling
|
|
Packit Service |
2781ba |
* the openexr lib and therefore should be exception save.
|
|
Packit Service |
2781ba |
*/
|
|
Packit Service |
2781ba |
static void
|
|
Packit Service |
2781ba |
exr_save_process (const float *pixels,
|
|
Packit Service |
2781ba |
int w,
|
|
Packit Service |
2781ba |
int h,
|
|
Packit Service |
2781ba |
int d,
|
|
Packit Service |
2781ba |
int tile_size,
|
|
Packit Service |
2781ba |
const std::string &filename)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
if (tile_size == 0)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
/* write a scanline exr image. */
|
|
Packit Service |
2781ba |
write_scanline_exr (pixels, w, h, d, filename);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
else
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
/* write a tiled exr image. */
|
|
Packit Service |
2781ba |
write_tiled_exr (pixels, w, h, d, tile_size, tile_size, filename);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
/**
|
|
Packit Service |
2781ba |
* main entry function for the exr saver.
|
|
Packit Service |
2781ba |
*/
|
|
Packit Service |
2781ba |
static gboolean
|
|
Packit Service |
2781ba |
gegl_exr_save_process (GeglOperation *operation,
|
|
Packit Service |
2781ba |
GeglBuffer *input,
|
|
Packit Service |
2781ba |
const GeglRectangle *rect,
|
|
Packit Service |
2781ba |
gint level)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
GeglChantO *o = GEGL_CHANT_PROPERTIES (operation);
|
|
Packit Service |
2781ba |
std::string filename (o->path);
|
|
Packit Service |
2781ba |
std::string output_format;
|
|
Packit Service |
2781ba |
int tile_size (o->tile);
|
|
Packit Service |
2781ba |
/*
|
|
Packit Service |
2781ba |
* determine the number of channels in the input buffer and determine
|
|
Packit Service |
2781ba |
* format, data is written with. Currently this only checks for the
|
|
Packit Service |
2781ba |
* numbers of channels and writes only Y or RGB data with optional alpha.
|
|
Packit Service |
2781ba |
*/
|
|
Packit Service |
2781ba |
const Babl *original_format = gegl_buffer_get_format (input);
|
|
Packit Service |
2781ba |
unsigned depth = babl_format_get_n_components (original_format);
|
|
Packit Service |
2781ba |
switch (depth)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
case 1: output_format = "Y float"; break;
|
|
Packit Service |
2781ba |
case 2: output_format = "YA float"; break;
|
|
Packit Service |
2781ba |
case 3: output_format = "RGB float"; break;
|
|
Packit Service |
2781ba |
case 4: output_format = "RGBA float"; break;
|
|
Packit Service |
2781ba |
default:
|
|
Packit Service |
2781ba |
g_warning ("exr-save: cannot write exr with depth %d.", depth);
|
|
Packit Service |
2781ba |
return FALSE;
|
|
Packit Service |
2781ba |
break;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
/*
|
|
Packit Service |
2781ba |
* get the pixel data. The position of the rectangle is effectively
|
|
Packit Service |
2781ba |
* ignored. Always write a file width x height; @todo: check if exr
|
|
Packit Service |
2781ba |
* can set the origin.
|
|
Packit Service |
2781ba |
*/
|
|
Packit Service |
2781ba |
float *pixels
|
|
Packit Service |
2781ba |
= (float *) g_malloc (rect->width * rect->height * depth * sizeof *pixels);
|
|
Packit Service |
2781ba |
if (pixels == 0)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
g_warning ("exr-save: could allocate %d*%d*%d pixels.",
|
|
Packit Service |
2781ba |
rect->width, rect->height, depth);
|
|
Packit Service |
2781ba |
return FALSE;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
gegl_buffer_get (input, rect, 1.0, babl_format (output_format.c_str ()),
|
|
Packit Service |
2781ba |
pixels, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
|
|
Packit Service |
2781ba |
bool status;
|
|
Packit Service |
2781ba |
try
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
exr_save_process (pixels, rect->width, rect->height,
|
|
Packit Service |
2781ba |
depth, tile_size, filename);
|
|
Packit Service |
2781ba |
status = TRUE;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
catch (std::exception &e)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
g_warning ("exr-save: failed to write to '%s': %s",
|
|
Packit Service |
2781ba |
filename.c_str (), e.what ());
|
|
Packit Service |
2781ba |
status = FALSE;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
g_free (pixels);
|
|
Packit Service |
2781ba |
return status;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static void gegl_chant_class_init (GeglChantClass *klass)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
GeglOperationClass *operation_class;
|
|
Packit Service |
2781ba |
GeglOperationSinkClass *sink_class;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
operation_class = GEGL_OPERATION_CLASS (klass);
|
|
Packit Service |
2781ba |
sink_class = GEGL_OPERATION_SINK_CLASS (klass);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
sink_class->process = gegl_exr_save_process;
|
|
Packit Service |
2781ba |
sink_class->needs_full = TRUE;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
gegl_operation_class_set_keys (operation_class,
|
|
Packit Service |
2781ba |
"name" , "gegl:exr-save",
|
|
Packit Service |
2781ba |
"categories" , "output",
|
|
Packit Service |
2781ba |
"description" , "OpenEXR image saver",
|
|
Packit Service |
2781ba |
NULL);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
gegl_extension_handler_register_saver (".exr", "gegl:exr-save");
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
#endif
|
|
Packit Service |
2781ba |
|