app: improve line art filling when clicking on a line art closure.

When clicking on a line art pixel, only this pixel gets colored, which
is fine for actual (original) line art pixels. But on generated ones
(closure pixels, which are internal only), you end up with a single
pixel colored while the whole surrounding area is empty. This feels like
a bug (even though it was not one technically) as you have no way to
guess you are clicking on a closure pixel.
Instead, when this happens, simulate clicks on all neighbour pixels,
hence potentially coloring all surrounding regions, which is most likely
what you wanted.

(cherry picked from commit f310db6c21)
This commit is contained in:
Jehan
2019-03-04 18:28:11 +01:00
parent 03744e3012
commit 07080d4540
2 changed files with 98 additions and 22 deletions

View File

@ -1055,7 +1055,7 @@ gimp_line_art_close (GeglBuffer *buffer,
if (p.x >= 0 && p.x < gegl_buffer_get_width (closed) &&
p.y >= 0 && p.y < gegl_buffer_get_height (closed))
{
guchar val = 1;
guchar val = 2;
gegl_buffer_set (closed, GEGL_RECTANGLE ((gint) p.x, (gint) p.y, 1, 1), 0,
NULL, &val, GEGL_AUTO_ROWSTRIDE);
@ -1111,7 +1111,7 @@ gimp_line_art_close (GeglBuffer *buffer,
for (j = 0; j < segment->len; j++)
{
Pixel p2 = g_array_index (segment, Pixel, j);
guchar val = 1;
guchar val = 2;
gegl_buffer_set (closed, GEGL_RECTANGLE ((gint) p2.x, (gint) p2.y, 1, 1), 0,
NULL, &val, GEGL_AUTO_ROWSTRIDE);

View File

@ -297,9 +297,9 @@ gimp_pickable_contiguous_region_by_line_art (GimpPickable *pickable,
const Babl *format = babl_format ("Y float");
gfloat *distmap = NULL;
GeglRectangle extent;
gfloat start_col;
gboolean free_line_art = FALSE;
gint line_art_max_grow;
gboolean free_line_art = FALSE;
gboolean filled = FALSE;
guchar start_col;
g_return_val_if_fail (GIMP_IS_PICKABLE (pickable) || GIMP_IS_LINE_ART (line_art), NULL);
@ -317,40 +317,116 @@ gimp_pickable_contiguous_region_by_line_art (GimpPickable *pickable,
src_buffer = gimp_line_art_get (line_art, &distmap);
g_return_val_if_fail (src_buffer && distmap, NULL);
gegl_buffer_sample (src_buffer, x, y, NULL, &start_col, format,
gegl_buffer_sample (src_buffer, x, y, NULL, &start_col, NULL,
GEGL_SAMPLER_NEAREST, GEGL_ABYSS_NONE);
extent = *gegl_buffer_get_extent (src_buffer);
mask_buffer = gegl_buffer_new (&extent, babl_format ("Y float"));
mask_buffer = gegl_buffer_new (&extent, format);
if (start_col)
{
/* As a special exception, if you fill over a line art pixel, only
* fill the pixel and exit
*/
start_col = 1.0;
gegl_buffer_set (mask_buffer, GEGL_RECTANGLE (x, y, 1, 1),
0, babl_format ("Y float"), &start_col,
GEGL_AUTO_ROWSTRIDE);
if (start_col == 1)
{
/* As a special exception, if you fill over a line art pixel, only
* fill the pixel and exit
*/
gfloat col = 1.0;
gegl_buffer_set (mask_buffer, GEGL_RECTANGLE (x, y, 1, 1),
0, format, &col, GEGL_AUTO_ROWSTRIDE);
}
else /* start_col == 2 */
{
/* If you fill over a closure pixel, let's fill on all sides
* of the start point. Otherwise we get a very weird result
* with only a single pixel filled in the middle of an empty
* region (since closure pixels are invisible by nature).
*/
gfloat col = 0.0;
if (x - 1 >= extent.x && x - 1 < extent.x + extent.width &&
y - 1 >= extent.y && y - 1 < (extent.y + extent.height))
find_contiguous_region (src_buffer, mask_buffer,
format, 1, FALSE,
FALSE, GIMP_SELECT_CRITERION_COMPOSITE,
FALSE, 0.0, FALSE,
x - 1, y - 1, &col);
if (x - 1 >= extent.x && x - 1 < extent.x + extent.width &&
y >= extent.y && y < (extent.y + extent.height))
find_contiguous_region (src_buffer, mask_buffer,
format, 1, FALSE,
FALSE, GIMP_SELECT_CRITERION_COMPOSITE,
FALSE, 0.0, FALSE,
x - 1, y, &col);
if (x - 1 >= extent.x && x - 1 < extent.x + extent.width &&
y + 1 >= extent.y && y + 1 < (extent.y + extent.height))
find_contiguous_region (src_buffer, mask_buffer,
format, 1, FALSE,
FALSE, GIMP_SELECT_CRITERION_COMPOSITE,
FALSE, 0.0, FALSE,
x - 1, y + 1, &col);
if (x >= extent.x && x < extent.x + extent.width &&
y - 1 >= extent.y && y - 1 < (extent.y + extent.height))
find_contiguous_region (src_buffer, mask_buffer,
format, 1, FALSE,
FALSE, GIMP_SELECT_CRITERION_COMPOSITE,
FALSE, 0.0, FALSE,
x, y - 1, &col);
if (x >= extent.x && x < extent.x + extent.width &&
y + 1 >= extent.y && y + 1 < (extent.y + extent.height))
find_contiguous_region (src_buffer, mask_buffer,
format, 1, FALSE,
FALSE, GIMP_SELECT_CRITERION_COMPOSITE,
FALSE, 0.0, FALSE,
x, y + 1, &col);
if (x + 1 >= extent.x && x + 1 < extent.x + extent.width &&
y - 1 >= extent.y && y - 1 < (extent.y + extent.height))
find_contiguous_region (src_buffer, mask_buffer,
format, 1, FALSE,
FALSE, GIMP_SELECT_CRITERION_COMPOSITE,
FALSE, 0.0, FALSE,
x + 1, y - 1, &col);
if (x + 1 >= extent.x && x + 1 < extent.x + extent.width &&
y >= extent.y && y < (extent.y + extent.height))
find_contiguous_region (src_buffer, mask_buffer,
format, 1, FALSE,
FALSE, GIMP_SELECT_CRITERION_COMPOSITE,
FALSE, 0.0, FALSE,
x + 1, y, &col);
if (x + 1 >= extent.x && x + 1 < extent.x + extent.width &&
y + 1 >= extent.y && y + 1 < (extent.y + extent.height))
find_contiguous_region (src_buffer, mask_buffer,
format, 1, FALSE,
FALSE, GIMP_SELECT_CRITERION_COMPOSITE,
FALSE, 0.0, FALSE,
x + 1, y + 1, &col);
filled = TRUE;
}
}
else if (x >= extent.x && x < (extent.x + extent.width) &&
y >= extent.y && y < (extent.y + extent.height))
{
gfloat *mask;
GQueue *queue = g_queue_new ();
gint width = gegl_buffer_get_width (src_buffer);
gint height = gegl_buffer_get_height (src_buffer);
gint nx, ny;
GIMP_TIMER_START();
gfloat col = 0.0;
find_contiguous_region (src_buffer, mask_buffer,
format, 1, FALSE,
FALSE, GIMP_SELECT_CRITERION_COMPOSITE,
FALSE, 0.0, FALSE,
x, y, &start_col);
x, y, &col);
filled = TRUE;
}
if (filled)
{
GQueue *queue = g_queue_new ();
gfloat *mask;
gint width = gegl_buffer_get_width (src_buffer);
gint height = gegl_buffer_get_height (src_buffer);
gint line_art_max_grow;
gint nx, ny;
GIMP_TIMER_START();
/* The last step of the line art algorithm is to make sure that
* selections does not leave "holes" between its borders and the
* line arts, while not stepping over as well.