workshop: reimplment hstack as pack

An op to put two buffers next to each other, with an optional gap.
parent 91458b1f
Pipeline #180505 passed with stages
in 12 minutes and 38 seconds
/* This file is an image processing operation for GEGL
*
* GEGL is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* GEGL is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with GEGL; if not, see <https://www.gnu.org/licenses/>.
*
* Copyright 2007 Øyvind Kolås <oeyvindk@hig.no>
*/
#include "config.h"
#include <glib/gi18n-lib.h>
#ifdef GEGL_PROPERTIES
/* No properties */
#else
#define GEGL_OP_COMPOSER
#define GEGL_OP_NAME hstack
#define GEGL_OP_C_SOURCE hstack.c
#include "gegl-op.h"
#include <math.h>
static void prepare (GeglOperation *operation)
{
gegl_operation_set_format (operation, "output", babl_format ("RGBA float"));
}
static GeglRectangle
get_bounding_box (GeglOperation *operation)
{
GeglRectangle result = {0,0,0,0};
GeglRectangle *in_rect = gegl_operation_source_get_bounding_box (operation,
"input");
GeglRectangle *aux_rect = gegl_operation_source_get_bounding_box (operation,
"aux");
if (!in_rect || !aux_rect)
return result;
result = *in_rect;
if (result.width != 0 &&
result.height != 0)
{
result.width += aux_rect->width;
if (aux_rect->height > result.height)
result.height = aux_rect->height;
}
return result;
}
static GeglRectangle
get_required_for_output (GeglOperation *self,
const gchar *input_pad,
const GeglRectangle *roi)
{
GeglRectangle request = *roi;
if (!strcmp (input_pad, "aux"))
{
GeglRectangle *in_rect = gegl_operation_source_get_bounding_box (self,
"input");
GeglRectangle *aux_rect = gegl_operation_source_get_bounding_box (self,
"aux");
if (request.width != 0 &&
request.height != 0)
{
request.x -= in_rect->width + aux_rect->x;
}
}
return request;
}
static GeglRectangle
get_invalidated_by_change (GeglOperation *self,
const gchar *input_pad,
const GeglRectangle *region)
{
if (!strcmp (input_pad, "input"))
{
return *region;
}
else
{
/*region.x -= radius * 2;*/
}
return *region;
}
static gboolean
process (GeglOperation *operation,
GeglBuffer *input,
GeglBuffer *aux,
GeglBuffer *output,
const GeglRectangle *result,
gint level)
{
GeglBuffer *temp_in;
GeglBuffer *temp_aux;
/* FIXME: just pass the originals buffers if the result rectangle does not
* include both input buffers
*/
if (gegl_rectangle_equal (result, gegl_buffer_get_extent (input)))
temp_in = g_object_ref (input);
else
temp_in = gegl_buffer_create_sub_buffer (input, result);
if (gegl_rectangle_equal (result, gegl_buffer_get_extent (aux)))
temp_aux = g_object_ref (aux);
else
temp_aux = gegl_buffer_create_sub_buffer (aux, result);
{
gfloat *buf = g_new0 (gfloat, result->width * result->height * 4);
gfloat *bufB = g_new0 (gfloat, result->width * result->height * 4);
gegl_buffer_get (temp_in, NULL, 1.0, babl_format ("RGBA float"), buf,
GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
gegl_buffer_get (temp_aux, NULL, 1.0, babl_format ("RGBA float"), bufB,
GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
{
gint offset=0;
gint x,y;
for (y=0;y<gegl_buffer_get_height (output);y++)
for (x=0;x<gegl_buffer_get_width (output);x++)
{
if (x + result->x >= gegl_buffer_get_width (input))
{
buf[offset+0]=bufB[offset+0];
buf[offset+1]=bufB[offset+1];
buf[offset+2]=bufB[offset+2];
buf[offset+3]=bufB[offset+3];
}
offset+=4;
}
}
gegl_buffer_set (output, NULL, 0, babl_format ("RGBA float"), buf,
GEGL_AUTO_ROWSTRIDE);
g_free (buf);
g_free (bufB);
}
g_object_unref (temp_in);
g_object_unref (temp_aux);
return TRUE;
}
static void
gegl_op_class_init (GeglOpClass *klass)
{
GeglOperationClass *operation_class;
GeglOperationComposerClass *composer_class;
operation_class = GEGL_OPERATION_CLASS (klass);
composer_class = GEGL_OPERATION_COMPOSER_CLASS (klass);
composer_class->process = process;
operation_class->prepare = prepare;
operation_class->get_bounding_box = get_bounding_box;
operation_class->get_invalidated_by_change = get_invalidated_by_change;
operation_class->get_required_for_output = get_required_for_output;
gegl_operation_class_set_keys (operation_class,
"name" , "gegl:hstack",
"categories" , "misc",
"description" ,
_("Horizontally stack inputs, (in \"output\" \"aux\" is placed to the right of \"input\")"),
NULL);
}
#endif
...@@ -14,7 +14,7 @@ gegl_workshop_sources = files( ...@@ -14,7 +14,7 @@ gegl_workshop_sources = files(
'band-tune.c', 'band-tune.c',
'gcr.c', 'gcr.c',
'gradient-map.c', 'gradient-map.c',
'hstack.c', 'pack.c',
'integral-image.c', 'integral-image.c',
'rawbayer-load.c', 'rawbayer-load.c',
'segment-kmeans.c', 'segment-kmeans.c',
......
/* This file is an image processing operation for GEGL
*
* GEGL is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* GEGL is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with GEGL; if not, see <https://www.gnu.org/licenses/>.
*
* Copyright 2020 Øyvind Kolås <pippin@gimp.org>
*/
#include "config.h"
#include <glib/gi18n-lib.h>
#include <math.h>
#ifdef GEGL_PROPERTIES
property_double (gap, _("Gap"), 0.0)
description (_("How many pixels of space between items"))
property_enum (orientation, _("Orientation"), GeglOrientation, gegl_orientation, GEGL_ORIENTATION_HORIZONTAL)
#else
#define GEGL_OP_META
#define GEGL_OP_NAME pack
#define GEGL_OP_C_SOURCE pack.c
#include "gegl-op.h"
typedef struct
{
GeglNode *over;
GeglNode *translate;
int width;
int height;
} State;
static void
prepare (GeglOperation *operation)
{
GeglProperties *o = GEGL_PROPERTIES (operation);
GeglNode *gegl = operation->node;
State *state = o->user_data;
if (!state)
return;
GeglNode *input = gegl_node_get_input_proxy (gegl, "input");
GeglRectangle in_rect = gegl_node_get_bounding_box (input);
if (o->orientation == GEGL_ORIENTATION_VERTICAL)
{
if (state->height != in_rect.height)
{
state->height = in_rect.height;
gegl_node_set (state->translate, "x", 0.0f,
"y", 1.0f * in_rect.height + o->gap, NULL);
}
}
else
{
if (state->width != in_rect.width)
{
state->width = in_rect.width;
gegl_node_set (state->translate, "x", 1.0f * in_rect.width + o->gap,
"y", 0.0f, NULL);
}
}
}
static void
update_graph (GeglOperation *operation)
{
GeglProperties *o = GEGL_PROPERTIES (operation);
State *state = o->user_data;
GeglNode *gegl = operation->node;
GeglNode *input = gegl_node_get_input_proxy (gegl, "input");
GeglNode *aux = gegl_node_get_input_proxy (gegl, "aux");
GeglNode *output = gegl_node_get_output_proxy (gegl, "output");
gegl_node_link_many (input, state->over, output, NULL);
gegl_node_link_many (aux, state->translate, NULL);
gegl_node_connect_from (state->over, "aux",
state->translate, "output");
}
static void
attach (GeglOperation *operation)
{
GeglProperties *o = GEGL_PROPERTIES (operation);
GeglNode *gegl = operation->node;
State *state = g_malloc0 (sizeof (State));
o->user_data = state;
state->over = gegl_node_new_child (gegl, "operation", "gegl:over", NULL);
state->translate = gegl_node_new_child (gegl, "operation", "gegl:translate", NULL);
}
static void
dispose (GObject *object)
{
GeglProperties *o = GEGL_PROPERTIES (object);
g_clear_pointer (&o->user_data, g_free);
G_OBJECT_CLASS (gegl_op_parent_class)->dispose (object);
}
static void
gegl_op_class_init (GeglOpClass *klass)
{
GObjectClass *object_class;
GeglOperationClass *operation_class;
GeglOperationMetaClass *operation_meta_class;
object_class = G_OBJECT_CLASS (klass);
operation_class = GEGL_OPERATION_CLASS (klass);
operation_meta_class = GEGL_OPERATION_META_CLASS (klass);
object_class->dispose = dispose;
operation_class->attach = attach;
operation_class->prepare = prepare;
operation_meta_class->update = update_graph;
gegl_operation_class_set_keys (operation_class,
"name", "gegl:pack",
"title", _("Pack"),
"categories", "layout",
"description", _("Packs an image horizontally or vertically next to each other with optional gap, aux right of input."),
NULL);
}
#endif
...@@ -285,8 +285,8 @@ operations/workshop/generated/soft-burn.c ...@@ -285,8 +285,8 @@ operations/workshop/generated/soft-burn.c
operations/workshop/generated/soft-dodge.c operations/workshop/generated/soft-dodge.c
operations/workshop/generated/subtractive.c operations/workshop/generated/subtractive.c
operations/workshop/gradient-map.c operations/workshop/gradient-map.c
operations/workshop/hstack.c
operations/workshop/integral-image.c operations/workshop/integral-image.c
operations/workshop/rawbayer-load.c operations/workshop/rawbayer-load.c
operations/workshop/segment-kmeans.c operations/workshop/segment-kmeans.c
operations/workshop/selective-hue-saturation.c operations/workshop/selective-hue-saturation.c
operations/workshop/pack.c
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment