2006-12-09 13:33:38 -08:00
|
|
|
/* GIMP - The GNU Image Manipulation Program
|
2001-05-22 16:05:35 -07:00
|
|
|
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
|
|
|
|
*
|
2006-01-11 16:50:44 -08:00
|
|
|
* gimphistogram module Copyright (C) 1999 Jay Cox <jaycox@gimp.org>
|
2001-05-22 16:05:35 -07:00
|
|
|
*
|
2009-01-17 14:28:01 -08:00
|
|
|
* This program is free software: you can redistribute it and/or modify
|
2001-05-22 16:05:35 -07:00
|
|
|
* it under the terms of the GNU General Public License as published by
|
2009-01-17 14:28:01 -08:00
|
|
|
* the Free Software Foundation; either version 3 of the License, or
|
2001-05-22 16:05:35 -07:00
|
|
|
* (at your option) any later version.
|
|
|
|
|
*
|
|
|
|
|
* This program 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 General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU General Public License
|
2018-07-11 14:47:19 -07:00
|
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
2001-05-22 16:05:35 -07:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
|
2017-08-05 08:15:31 -07:00
|
|
|
#include <cairo.h>
|
2013-10-14 16:58:39 -07:00
|
|
|
#include <gdk-pixbuf/gdk-pixbuf.h>
|
2008-10-09 13:24:04 -07:00
|
|
|
#include <gegl.h>
|
2001-05-22 16:05:35 -07:00
|
|
|
|
2001-05-25 14:17:07 -07:00
|
|
|
#include "core-types.h"
|
2001-05-22 16:05:35 -07:00
|
|
|
|
2012-04-15 22:57:43 -07:00
|
|
|
#include "gegl/gimp-gegl-nodes.h"
|
2017-08-05 08:15:31 -07:00
|
|
|
#include "gegl/gimptilehandlervalidate.h"
|
2012-04-15 22:57:43 -07:00
|
|
|
|
2018-05-11 08:52:49 -07:00
|
|
|
#include "gimpasync.h"
|
2010-09-07 08:43:39 -07:00
|
|
|
#include "gimpchannel.h"
|
2017-08-05 08:15:31 -07:00
|
|
|
#include "gimpdrawable-filters.h"
|
2006-10-30 02:13:06 -08:00
|
|
|
#include "gimpdrawable-histogram.h"
|
2012-03-24 14:29:53 -07:00
|
|
|
#include "gimphistogram.h"
|
2001-05-25 14:17:07 -07:00
|
|
|
#include "gimpimage.h"
|
app: fix pass-through group histograms (proactively)
In gimp_drawable_calculate_histogram(), when including the
drawable's filters in the histogram (i.e., when calculating the
histogram of the drawable's source node, rather than its buffer),
if the drawable is a projectable, call
gimp_projectable_{begin,end}_render() before/after calculating the
histogram, respectively. This is necessary for pass-through
groups, whose {begin,end}_render() functions disconnect/reconnect
the group's backdrop from/to the group's layer stack. If we fail
to do this, the backdrop is erroneously included in the histogram.
Note that currently layer groups can't have any filters applied to
them, so we never run into this situation, but once we have non-
destructive editing we probably will.
2018-05-08 00:34:32 -07:00
|
|
|
#include "gimpprojectable.h"
|
2001-05-22 16:05:35 -07:00
|
|
|
|
|
|
|
|
|
2018-05-11 08:52:49 -07:00
|
|
|
/* local function prototypes */
|
|
|
|
|
|
|
|
|
|
static GimpAsync * gimp_drawable_calculate_histogram_internal (GimpDrawable *drawable,
|
|
|
|
|
GimpHistogram *histogram,
|
|
|
|
|
gboolean with_filters,
|
|
|
|
|
gboolean run_async);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* private functions */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static GimpAsync *
|
|
|
|
|
gimp_drawable_calculate_histogram_internal (GimpDrawable *drawable,
|
|
|
|
|
GimpHistogram *histogram,
|
|
|
|
|
gboolean with_filters,
|
|
|
|
|
gboolean run_async)
|
2001-05-22 16:05:35 -07:00
|
|
|
{
|
2018-05-11 08:52:49 -07:00
|
|
|
GimpAsync *async = NULL;
|
2010-09-07 08:43:39 -07:00
|
|
|
GimpImage *image;
|
2012-04-15 22:57:43 -07:00
|
|
|
GimpChannel *mask;
|
2010-09-07 08:43:39 -07:00
|
|
|
gint x, y, width, height;
|
2001-05-22 16:05:35 -07:00
|
|
|
|
2010-09-07 12:28:00 -07:00
|
|
|
if (! gimp_item_mask_intersect (GIMP_ITEM (drawable), &x, &y, &width, &height))
|
2018-05-11 08:52:49 -07:00
|
|
|
goto end;
|
2004-10-19 15:52:04 -07:00
|
|
|
|
2010-09-07 08:43:39 -07:00
|
|
|
image = gimp_item_get_image (GIMP_ITEM (drawable));
|
2012-04-15 22:57:43 -07:00
|
|
|
mask = gimp_image_get_mask (image);
|
2001-05-22 16:05:35 -07:00
|
|
|
|
2012-04-16 13:36:28 -07:00
|
|
|
if (FALSE)
|
2001-05-22 16:05:35 -07:00
|
|
|
{
|
2012-04-15 22:57:43 -07:00
|
|
|
GeglNode *node = gegl_node_new ();
|
2017-08-05 08:15:31 -07:00
|
|
|
GeglNode *source;
|
2012-04-15 22:57:43 -07:00
|
|
|
GeglNode *histogram_sink;
|
|
|
|
|
GeglProcessor *processor;
|
|
|
|
|
|
2017-08-05 08:15:31 -07:00
|
|
|
if (with_filters)
|
|
|
|
|
{
|
|
|
|
|
source = gimp_drawable_get_source_node (drawable);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
source =
|
|
|
|
|
gimp_gegl_add_buffer_source (node,
|
|
|
|
|
gimp_drawable_get_buffer (drawable),
|
|
|
|
|
0, 0);
|
|
|
|
|
}
|
2012-04-15 22:57:43 -07:00
|
|
|
|
|
|
|
|
histogram_sink =
|
|
|
|
|
gegl_node_new_child (node,
|
|
|
|
|
"operation", "gimp:histogram-sink",
|
|
|
|
|
"histogram", histogram,
|
|
|
|
|
NULL);
|
|
|
|
|
|
2017-08-05 08:15:31 -07:00
|
|
|
gegl_node_connect_to (source, "output",
|
2012-04-15 22:57:43 -07:00
|
|
|
histogram_sink, "input");
|
|
|
|
|
|
|
|
|
|
if (! gimp_channel_is_empty (mask))
|
|
|
|
|
{
|
|
|
|
|
GeglNode *mask_source;
|
|
|
|
|
gint off_x, off_y;
|
|
|
|
|
|
|
|
|
|
g_printerr ("adding mask aux\n");
|
|
|
|
|
|
|
|
|
|
gimp_item_get_offset (GIMP_ITEM (drawable), &off_x, &off_y);
|
|
|
|
|
|
|
|
|
|
mask_source =
|
|
|
|
|
gimp_gegl_add_buffer_source (node,
|
|
|
|
|
gimp_drawable_get_buffer (GIMP_DRAWABLE (mask)),
|
|
|
|
|
-off_x, -off_y);
|
|
|
|
|
|
|
|
|
|
gegl_node_connect_to (mask_source, "output",
|
|
|
|
|
histogram_sink, "aux");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
processor = gegl_node_new_processor (histogram_sink,
|
|
|
|
|
GEGL_RECTANGLE (x, y, width, height));
|
|
|
|
|
|
|
|
|
|
while (gegl_processor_work (processor, NULL));
|
|
|
|
|
|
|
|
|
|
g_object_unref (processor);
|
|
|
|
|
g_object_unref (node);
|
2001-05-22 16:05:35 -07:00
|
|
|
}
|
2012-04-16 13:36:28 -07:00
|
|
|
else
|
2012-04-16 12:01:39 -07:00
|
|
|
{
|
app: fix pass-through group histograms (proactively)
In gimp_drawable_calculate_histogram(), when including the
drawable's filters in the histogram (i.e., when calculating the
histogram of the drawable's source node, rather than its buffer),
if the drawable is a projectable, call
gimp_projectable_{begin,end}_render() before/after calculating the
histogram, respectively. This is necessary for pass-through
groups, whose {begin,end}_render() functions disconnect/reconnect
the group's backdrop from/to the group's layer stack. If we fail
to do this, the backdrop is erroneously included in the histogram.
Note that currently layer groups can't have any filters applied to
them, so we never run into this situation, but once we have non-
destructive editing we probably will.
2018-05-08 00:34:32 -07:00
|
|
|
GeglBuffer *buffer = gimp_drawable_get_buffer (drawable);
|
|
|
|
|
GimpProjectable *projectable = NULL;
|
2017-08-05 08:15:31 -07:00
|
|
|
|
|
|
|
|
if (with_filters && gimp_drawable_has_filters (drawable))
|
|
|
|
|
{
|
|
|
|
|
GimpTileHandlerValidate *validate;
|
|
|
|
|
GeglNode *node;
|
|
|
|
|
|
|
|
|
|
node = gimp_drawable_get_source_node (drawable);
|
|
|
|
|
|
|
|
|
|
buffer = gegl_buffer_new (gegl_buffer_get_extent (buffer),
|
|
|
|
|
gegl_buffer_get_format (buffer));
|
|
|
|
|
|
|
|
|
|
validate =
|
|
|
|
|
GIMP_TILE_HANDLER_VALIDATE (gimp_tile_handler_validate_new (node));
|
|
|
|
|
|
|
|
|
|
gimp_tile_handler_validate_assign (validate, buffer);
|
|
|
|
|
|
|
|
|
|
g_object_unref (validate);
|
|
|
|
|
|
|
|
|
|
gimp_tile_handler_validate_invalidate (validate,
|
|
|
|
|
gegl_buffer_get_extent (buffer));
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
/* this would keep the buffer updated across drawable or
|
|
|
|
|
* filter changes, but the histogram is created in one go
|
|
|
|
|
* and doesn't need the signal connection
|
|
|
|
|
*/
|
|
|
|
|
g_signal_connect_object (node, "invalidated",
|
|
|
|
|
G_CALLBACK (gimp_tile_handler_validate_invalidate),
|
|
|
|
|
validate, G_CONNECT_SWAPPED);
|
|
|
|
|
#endif
|
app: fix pass-through group histograms (proactively)
In gimp_drawable_calculate_histogram(), when including the
drawable's filters in the histogram (i.e., when calculating the
histogram of the drawable's source node, rather than its buffer),
if the drawable is a projectable, call
gimp_projectable_{begin,end}_render() before/after calculating the
histogram, respectively. This is necessary for pass-through
groups, whose {begin,end}_render() functions disconnect/reconnect
the group's backdrop from/to the group's layer stack. If we fail
to do this, the backdrop is erroneously included in the histogram.
Note that currently layer groups can't have any filters applied to
them, so we never run into this situation, but once we have non-
destructive editing we probably will.
2018-05-08 00:34:32 -07:00
|
|
|
|
|
|
|
|
if (GIMP_IS_PROJECTABLE (drawable))
|
|
|
|
|
projectable = GIMP_PROJECTABLE (drawable);
|
2017-08-05 08:15:31 -07:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
g_object_ref (buffer);
|
|
|
|
|
}
|
|
|
|
|
|
app: fix pass-through group histograms (proactively)
In gimp_drawable_calculate_histogram(), when including the
drawable's filters in the histogram (i.e., when calculating the
histogram of the drawable's source node, rather than its buffer),
if the drawable is a projectable, call
gimp_projectable_{begin,end}_render() before/after calculating the
histogram, respectively. This is necessary for pass-through
groups, whose {begin,end}_render() functions disconnect/reconnect
the group's backdrop from/to the group's layer stack. If we fail
to do this, the backdrop is erroneously included in the histogram.
Note that currently layer groups can't have any filters applied to
them, so we never run into this situation, but once we have non-
destructive editing we probably will.
2018-05-08 00:34:32 -07:00
|
|
|
if (projectable)
|
|
|
|
|
gimp_projectable_begin_render (projectable);
|
|
|
|
|
|
2012-04-16 12:01:39 -07:00
|
|
|
if (! gimp_channel_is_empty (mask))
|
|
|
|
|
{
|
|
|
|
|
gint off_x, off_y;
|
|
|
|
|
|
|
|
|
|
gimp_item_get_offset (GIMP_ITEM (drawable), &off_x, &off_y);
|
|
|
|
|
|
2018-05-11 08:52:49 -07:00
|
|
|
if (run_async)
|
|
|
|
|
{
|
|
|
|
|
async = gimp_histogram_calculate_async (
|
|
|
|
|
histogram, buffer,
|
|
|
|
|
GEGL_RECTANGLE (x, y, width, height),
|
|
|
|
|
gimp_drawable_get_buffer (GIMP_DRAWABLE (mask)),
|
|
|
|
|
GEGL_RECTANGLE (x + off_x, y + off_y,
|
|
|
|
|
width, height));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
gimp_histogram_calculate (
|
|
|
|
|
histogram, buffer,
|
|
|
|
|
GEGL_RECTANGLE (x, y, width, height),
|
|
|
|
|
gimp_drawable_get_buffer (GIMP_DRAWABLE (mask)),
|
|
|
|
|
GEGL_RECTANGLE (x + off_x, y + off_y,
|
|
|
|
|
width, height));
|
|
|
|
|
}
|
2012-04-16 12:01:39 -07:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2018-05-11 08:52:49 -07:00
|
|
|
if (run_async)
|
|
|
|
|
{
|
|
|
|
|
async = gimp_histogram_calculate_async (
|
|
|
|
|
histogram, buffer,
|
|
|
|
|
GEGL_RECTANGLE (x, y, width, height),
|
|
|
|
|
NULL, NULL);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
gimp_histogram_calculate (
|
|
|
|
|
histogram, buffer,
|
|
|
|
|
GEGL_RECTANGLE (x, y, width, height),
|
|
|
|
|
NULL, NULL);
|
|
|
|
|
}
|
2012-04-16 12:01:39 -07:00
|
|
|
}
|
2017-08-05 08:15:31 -07:00
|
|
|
|
app: fix pass-through group histograms (proactively)
In gimp_drawable_calculate_histogram(), when including the
drawable's filters in the histogram (i.e., when calculating the
histogram of the drawable's source node, rather than its buffer),
if the drawable is a projectable, call
gimp_projectable_{begin,end}_render() before/after calculating the
histogram, respectively. This is necessary for pass-through
groups, whose {begin,end}_render() functions disconnect/reconnect
the group's backdrop from/to the group's layer stack. If we fail
to do this, the backdrop is erroneously included in the histogram.
Note that currently layer groups can't have any filters applied to
them, so we never run into this situation, but once we have non-
destructive editing we probably will.
2018-05-08 00:34:32 -07:00
|
|
|
if (projectable)
|
|
|
|
|
gimp_projectable_end_render (projectable);
|
|
|
|
|
|
2017-08-05 08:15:31 -07:00
|
|
|
g_object_unref (buffer);
|
2012-04-16 12:01:39 -07:00
|
|
|
}
|
2018-05-11 08:52:49 -07:00
|
|
|
|
|
|
|
|
end:
|
|
|
|
|
if (run_async && ! async)
|
|
|
|
|
{
|
|
|
|
|
async = gimp_async_new ();
|
|
|
|
|
|
|
|
|
|
gimp_async_finish (async, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return async;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* public functions */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
gimp_drawable_calculate_histogram (GimpDrawable *drawable,
|
|
|
|
|
GimpHistogram *histogram,
|
|
|
|
|
gboolean with_filters)
|
|
|
|
|
{
|
|
|
|
|
g_return_if_fail (GIMP_IS_DRAWABLE (drawable));
|
|
|
|
|
g_return_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)));
|
|
|
|
|
g_return_if_fail (histogram != NULL);
|
|
|
|
|
|
|
|
|
|
gimp_drawable_calculate_histogram_internal (drawable,
|
|
|
|
|
histogram, with_filters,
|
|
|
|
|
FALSE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GimpAsync *
|
|
|
|
|
gimp_drawable_calculate_histogram_async (GimpDrawable *drawable,
|
|
|
|
|
GimpHistogram *histogram,
|
|
|
|
|
gboolean with_filters)
|
|
|
|
|
{
|
|
|
|
|
g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL);
|
|
|
|
|
g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)), NULL);
|
|
|
|
|
g_return_val_if_fail (histogram != NULL, NULL);
|
|
|
|
|
|
|
|
|
|
return gimp_drawable_calculate_histogram_internal (drawable,
|
|
|
|
|
histogram, with_filters,
|
|
|
|
|
TRUE);
|
2001-05-22 16:05:35 -07:00
|
|
|
}
|