gimplineart.c 103 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/* GIMP - The GNU Image Manipulation Program
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
 *
 * Copyright (C) 2017 Sébastien Fourey & David Tchumperlé
 * Copyright (C) 2018 Jehan
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (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
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

#include "config.h"

23
#include <gdk-pixbuf/gdk-pixbuf.h>
24
25
#include <gegl.h>

26
#include "libgimpbase/gimpbase.h"
27
28
29
30
#include "libgimpmath/gimpmath.h"

#include "core-types.h"

31
#include "gegl/gimp-gegl-loops.h"
32
#include "gegl/gimp-gegl-utils.h"
33

34
#include "gimp-parallel.h"
35
#include "gimp-priorities.h"
36
37
38
39
40
#include "gimp-utils.h" /* GIMP_TIMER */
#include "gimpasync.h"
#include "gimpcancelable.h"
#include "gimpdrawable.h"
#include "gimpimage.h"
41
#include "gimplineart.h"
42
43
#include "gimppickable.h"
#include "gimpprojection.h"
44
#include "gimpviewable.h"
45
46
47
48
#include "gimpwaitable.h"

#include "gimp-intl.h"

49
50
51
52
53
54
55
enum
{
  COMPUTING_START,
  COMPUTING_END,
  LAST_SIGNAL,
};

56
57
58
59
60
61
enum
{
  PROP_0,
  PROP_SELECT_TRANSPARENT,
  PROP_MAX_GROW,
  PROP_THRESHOLD,
62
  PROP_AUTOMATIC_CLOSURE,
63
64
65
66
67
68
69
70
71
72
73
74
75
  PROP_SPLINE_MAX_LEN,
  PROP_SEGMENT_MAX_LEN,
};

typedef struct _GimpLineArtPrivate GimpLineArtPrivate;

struct _GimpLineArtPrivate
{
  gboolean      frozen;
  gboolean      compute_after_thaw;

  GimpAsync    *async;

76
77
  gint          idle_id;

78
79
80
81
82
83
84
  GimpPickable *input;
  GeglBuffer   *closed;
  gfloat       *distmap;

  /* Used in the closing step. */
  gboolean      select_transparent;
  gdouble       threshold;
85
  gboolean      automatic_closure;
86
87
  gint          spline_max_len;
  gint          segment_max_len;
88
  gboolean      max_len_bound;
89
90
91
92
93
94
95
96
97
98
99

  /* Used in the grow step. */
  gint          max_grow;
};

typedef struct
{
  GeglBuffer  *buffer;

  gboolean     select_transparent;
  gdouble      threshold;
100
  gboolean     automatic_closure;
101
102
103
104
105
106
107
108
109
  gint         spline_max_len;
  gint         segment_max_len;
} LineArtData;

typedef struct
{
  GeglBuffer *closed;
  gfloat     *distmap;
} LineArtResult;
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149

static int DeltaX[4] = {+1, -1, 0, 0};
static int DeltaY[4] = {0, 0, +1, -1};

static const GimpVector2 Direction2Normal[4] =
{
    {  1.0f,  0.0f },
    { -1.0f,  0.0f },
    {  0.0f,  1.0f },
    {  0.0f, -1.0f }
};

typedef enum _Direction
{
  XPlusDirection  = 0,
  XMinusDirection = 1,
  YPlusDirection  = 2,
  YMinusDirection = 3
} Direction;

typedef GimpVector2 Pixel;

typedef struct _SplineCandidate
{
  Pixel p1;
  Pixel p2;
  float quality;
} SplineCandidate;

typedef struct _Edgel
{
  gint      x, y;
  Direction direction;

  gfloat    x_normal;
  gfloat    y_normal;
  gfloat    curvature;
  guint     next, previous;
} Edgel;

150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177

static void            gimp_line_art_finalize                  (GObject               *object);
static void            gimp_line_art_set_property              (GObject                *object,
                                                                guint                   property_id,
                                                                const GValue           *value,
                                                                GParamSpec             *pspec);
static void            gimp_line_art_get_property              (GObject                *object,
                                                                guint                   property_id,
                                                                GValue                 *value,
                                                                GParamSpec             *pspec);

/* Functions for asynchronous computation. */

static void            gimp_line_art_compute                   (GimpLineArt            *line_art);
static void            gimp_line_art_compute_cb                (GimpAsync              *async,
                                                                GimpLineArt            *line_art);

static GimpAsync     * gimp_line_art_prepare_async             (GimpLineArt            *line_art,
                                                                gint                    priority);
static void            gimp_line_art_prepare_async_func        (GimpAsync              *async,
                                                                LineArtData            *data);
static LineArtData   * line_art_data_new                       (GeglBuffer             *buffer,
                                                                GimpLineArt            *line_art);
static void            line_art_data_free                      (LineArtData            *data);
static LineArtResult * line_art_result_new                     (GeglBuffer             *line_art,
                                                                gfloat                 *distmap);
static void            line_art_result_free                    (LineArtResult          *result);

178
179
static gboolean        gimp_line_art_idle                      (GimpLineArt            *line_art);
static void            gimp_line_art_input_invalidate_preview  (GimpViewable           *viewable,
180
181
182
183
184
185
186
187
                                                                GimpLineArt            *line_art);


/* All actual computation functions. */

static GeglBuffer    * gimp_line_art_close                     (GeglBuffer             *buffer,
                                                                gboolean                select_transparent,
                                                                gdouble                 stroke_threshold,
188
                                                                gboolean                automatic_closure,
189
190
191
192
193
194
195
196
197
198
199
200
                                                                gint                    spline_max_length,
                                                                gint                    segment_max_length,
                                                                gint                    minimal_lineart_area,
                                                                gint                    normal_estimate_mask_size,
                                                                gfloat                  end_point_rate,
                                                                gfloat                  spline_max_angle,
                                                                gint                    end_point_connectivity,
                                                                gfloat                  spline_roundness,
                                                                gboolean                allow_self_intersections,
                                                                gint                    created_regions_significant_area,
                                                                gint                    created_regions_minimum_area,
                                                                gboolean                small_segments_from_spline_sources,
201
202
                                                                gfloat                **lineart_distmap,
                                                                GimpAsync              *async);
203
204

static void            gimp_lineart_denoise                    (GeglBuffer             *buffer,
205
206
                                                                int                     size,
                                                                GimpAsync              *async);
207
208
209
210
static void            gimp_lineart_compute_normals_curvatures (GeglBuffer             *mask,
                                                                gfloat                 *normals,
                                                                gfloat                 *curvatures,
                                                                gfloat                 *smoothed_curvatures,
211
212
213
214
                                                                int                     normal_estimate_mask_size,
                                                                GimpAsync              *async);
static gfloat        * gimp_lineart_get_smooth_curvatures      (GArray                 *edgelset,
                                                                GimpAsync              *async);
215
216
217
static GArray        * gimp_lineart_curvature_extremums        (gfloat                 *curvatures,
                                                                gfloat                 *smoothed_curvatures,
                                                                gint                    curvatures_width,
218
219
                                                                gint                    curvatures_height,
                                                                GimpAsync              *async);
220
221
222
223
224
225
226
static gint            gimp_spline_candidate_cmp               (const SplineCandidate  *a,
                                                                const SplineCandidate  *b,
                                                                gpointer                user_data);
static GList         * gimp_lineart_find_spline_candidates     (GArray                 *max_positions,
                                                                gfloat                 *normals,
                                                                gint                    width,
                                                                gint                    distance_threshold,
227
228
                                                                gfloat                  max_angle_deg,
                                                                GimpAsync              *async);
229
230
231
232
233
234
235
236

static GArray        * gimp_lineart_discrete_spline            (Pixel                   p0,
                                                                GimpVector2             n0,
                                                                Pixel                   p1,
                                                                GimpVector2             n1);

static gint            gimp_number_of_transitions               (GArray                 *pixels,
                                                                 GeglBuffer             *buffer);
237
static gboolean        gimp_line_art_allow_closure              (GeglBuffer             *mask,
238
                                                                 GArray                 *pixels,
239
                                                                 GList                 **fill_pixels,
240
241
                                                                 int                     significant_size,
                                                                 int                     minimum_size);
242
243
244
245
static GArray        * gimp_lineart_line_segment_until_hit      (const GeglBuffer       *buffer,
                                                                 Pixel                   start,
                                                                 GimpVector2             direction,
                                                                 int                     size);
246
247
static gfloat        * gimp_lineart_estimate_strokes_radii      (GeglBuffer             *mask,
                                                                 GimpAsync              *async);
248
249
static void            gimp_line_art_simple_fill                (GeglBuffer             *buffer,
                                                                 gint                    x,
250
251
                                                                 gint                    y,
                                                                 gint                   *counter);
252
253
254

/* Some callback-type functions. */

255
256
257
static guint           visited_hash_fun                         (Pixel                  *key);
static gboolean        visited_equal_fun                        (Pixel                  *e1,
                                                                 Pixel                  *e2);
258

259
260
261
262
263
264
static inline gboolean border_in_direction                      (GeglBuffer             *mask,
                                                                 Pixel                   p,
                                                                 int                     direction);
static inline GimpVector2 pair2normal                           (Pixel                   p,
                                                                 gfloat                 *normals,
                                                                 gint                    width);
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282

/* Edgel */

static Edgel    * gimp_edgel_new                  (int                x,
                                                   int                y,
                                                   Direction          direction);
static void       gimp_edgel_init                 (Edgel             *edgel);
static void       gimp_edgel_clear                (Edgel            **edgel);
static int        gimp_edgel_cmp                  (const Edgel       *e1,
                                                   const Edgel       *e2);
static guint      edgel2index_hash_fun            (Edgel              *key);
static gboolean   edgel2index_equal_fun           (Edgel              *e1,
                                                   Edgel              *e2);

static glong      gimp_edgel_track_mark           (GeglBuffer         *mask,
                                                   Edgel               edgel,
                                                   long                size_limit);
static glong      gimp_edgel_region_area          (const GeglBuffer   *mask,
283
                                                   Edgel               start_edgel);
284
285
286

/* Edgel set */

287
288
static GArray   * gimp_edgelset_new               (GeglBuffer         *buffer,
                                                   GimpAsync          *async);
289
290
291
292
293
294
295
static void       gimp_edgelset_add               (GArray             *set,
                                                   int                 x,
                                                   int                 y,
                                                   Direction           direction,
                                                   GHashTable         *edgel2index);
static void       gimp_edgelset_init_normals      (GArray             *set);
static void       gimp_edgelset_smooth_normals    (GArray             *set,
296
297
298
299
                                                   int                 mask_size,
                                                   GimpAsync          *async);
static void       gimp_edgelset_compute_curvature (GArray             *set,
                                                   GimpAsync          *async);
300
301
302

static void       gimp_edgelset_build_graph       (GArray            *set,
                                                   GeglBuffer        *buffer,
303
304
                                                   GHashTable        *edgel2index,
                                                   GimpAsync         *async);
305
306
307
308
static void       gimp_edgelset_next8             (const GeglBuffer  *buffer,
                                                   Edgel             *it,
                                                   Edgel             *n);

309
310
311
G_DEFINE_TYPE_WITH_CODE (GimpLineArt, gimp_line_art, GIMP_TYPE_OBJECT,
                         G_ADD_PRIVATE (GimpLineArt))

312
313
#define parent_class gimp_line_art_parent_class

314
315
static guint gimp_line_art_signals[LAST_SIGNAL] = { 0 };

316
317
318
319
320
static void
gimp_line_art_class_init (GimpLineArtClass *klass)
{
  GObjectClass *object_class = G_OBJECT_CLASS (klass);

321
322
323
324
325
  gimp_line_art_signals[COMPUTING_START] =
    g_signal_new ("computing-start",
                  G_TYPE_FROM_CLASS (klass),
                  G_SIGNAL_RUN_FIRST,
                  G_STRUCT_OFFSET (GimpLineArtClass, computing_start),
326
                  NULL, NULL, NULL,
327
328
329
330
331
332
                  G_TYPE_NONE, 0);
  gimp_line_art_signals[COMPUTING_END] =
    g_signal_new ("computing-end",
                  G_TYPE_FROM_CLASS (klass),
                  G_SIGNAL_RUN_FIRST,
                  G_STRUCT_OFFSET (GimpLineArtClass, computing_end),
333
                  NULL, NULL, NULL,
334
335
                  G_TYPE_NONE, 0);

336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
  object_class->finalize     = gimp_line_art_finalize;
  object_class->set_property = gimp_line_art_set_property;
  object_class->get_property = gimp_line_art_get_property;

  g_object_class_install_property (object_class, PROP_SELECT_TRANSPARENT,
                                   g_param_spec_boolean ("select-transparent",
                                                         _("Select transparent pixels instead of gray ones"),
                                                         _("Select transparent pixels instead of gray ones"),
                                                         TRUE,
                                                         G_PARAM_CONSTRUCT | GIMP_PARAM_READWRITE));

  g_object_class_install_property (object_class, PROP_THRESHOLD,
                                   g_param_spec_double ("threshold",
                                                        _("Line art detection threshold"),
                                                        _("Threshold to detect contour (higher values will include more pixels)"),
                                                        0.0, 1.0, 0.92,
                                                        G_PARAM_CONSTRUCT | GIMP_PARAM_READWRITE));

  g_object_class_install_property (object_class, PROP_MAX_GROW,
                                   g_param_spec_int ("max-grow",
                                                     _("Maximum growing size"),
                                                     _("Maximum number of pixels grown under the line art"),
                                                     1, 100, 3,
                                                     G_PARAM_CONSTRUCT | GIMP_PARAM_READWRITE));

361
362
363
364
365
366
367
  g_object_class_install_property (object_class, PROP_AUTOMATIC_CLOSURE,
                                   g_param_spec_boolean ("automatic-closure",
                                                         _("Whether or not we should perform the closing step"),
                                                         _("Whether or not we should perform the closing step"),
                                                         TRUE,
                                                         G_PARAM_CONSTRUCT | GIMP_PARAM_READWRITE));

368
369
370
371
  g_object_class_install_property (object_class, PROP_SPLINE_MAX_LEN,
                                   g_param_spec_int ("spline-max-length",
                                                     _("Maximum curved closing length"),
                                                     _("Maximum curved length (in pixels) to close the line art"),
372
                                                     0, 1000, 100,
373
374
375
376
377
378
                                                     G_PARAM_CONSTRUCT | GIMP_PARAM_READWRITE));

  g_object_class_install_property (object_class, PROP_SEGMENT_MAX_LEN,
                                   g_param_spec_int ("segment-max-length",
                                                     _("Maximum straight closing length"),
                                                     _("Maximum straight length (in pixels) to close the line art"),
379
                                                     0, 1000, 100,
380
381
382
383
384
385
386
387
388
389
390
391
392
393
                                                     G_PARAM_CONSTRUCT | GIMP_PARAM_READWRITE));
}

static void
gimp_line_art_init (GimpLineArt *line_art)
{
  line_art->priv = gimp_line_art_get_instance_private (line_art);
}

static void
gimp_line_art_finalize (GObject *object)
{
  GimpLineArt *line_art = GIMP_LINE_ART (object);

394
  line_art->priv->frozen = FALSE;
395

396
  gimp_line_art_set_input (line_art, NULL);
397
398

  G_OBJECT_CLASS (parent_class)->finalize (object);
399
400
401
402
403
404
405
406
407
408
409
410
411
}

static void
gimp_line_art_set_property (GObject      *object,
                            guint         property_id,
                            const GValue *value,
                            GParamSpec   *pspec)
{
  GimpLineArt *line_art = GIMP_LINE_ART (object);

  switch (property_id)
    {
    case PROP_SELECT_TRANSPARENT:
412
413
414
415
416
      if (line_art->priv->select_transparent != g_value_get_boolean (value))
        {
          line_art->priv->select_transparent = g_value_get_boolean (value);
          gimp_line_art_compute (line_art);
        }
417
418
419
420
421
      break;
    case PROP_MAX_GROW:
      line_art->priv->max_grow = g_value_get_int (value);
      break;
    case PROP_THRESHOLD:
422
423
424
425
426
      if (line_art->priv->threshold != g_value_get_double (value))
        {
          line_art->priv->threshold = g_value_get_double (value);
          gimp_line_art_compute (line_art);
        }
427
      break;
428
429
430
431
432
433
434
    case PROP_AUTOMATIC_CLOSURE:
      if (line_art->priv->automatic_closure != g_value_get_boolean (value))
        {
          line_art->priv->automatic_closure = g_value_get_boolean (value);
          gimp_line_art_compute (line_art);
        }
      break;
435
    case PROP_SPLINE_MAX_LEN:
436
437
438
439
440
441
442
      if (line_art->priv->spline_max_len != g_value_get_int (value))
        {
          line_art->priv->spline_max_len = g_value_get_int (value);
          if (line_art->priv->max_len_bound)
            line_art->priv->segment_max_len = line_art->priv->spline_max_len;
          gimp_line_art_compute (line_art);
        }
443
444
      break;
    case PROP_SEGMENT_MAX_LEN:
445
446
447
448
449
450
451
      if (line_art->priv->segment_max_len != g_value_get_int (value))
        {
          line_art->priv->segment_max_len = g_value_get_int (value);
          if (line_art->priv->max_len_bound)
            line_art->priv->spline_max_len = line_art->priv->segment_max_len;
          gimp_line_art_compute (line_art);
        }
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
      break;

    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
      break;
    }
}

static void
gimp_line_art_get_property (GObject    *object,
                            guint       property_id,
                            GValue     *value,
                            GParamSpec *pspec)
{
  GimpLineArt *line_art = GIMP_LINE_ART (object);

  switch (property_id)
    {
    case PROP_SELECT_TRANSPARENT:
      g_value_set_boolean (value, line_art->priv->select_transparent);
      break;
    case PROP_MAX_GROW:
      g_value_set_int (value, line_art->priv->max_grow);
      break;
    case PROP_THRESHOLD:
      g_value_set_double (value, line_art->priv->threshold);
      break;
479
480
481
    case PROP_AUTOMATIC_CLOSURE:
      g_value_set_boolean (value, line_art->priv->automatic_closure);
      break;
482
483
484
485
486
487
488
489
490
491
492
493
494
    case PROP_SPLINE_MAX_LEN:
      g_value_set_int (value, line_art->priv->spline_max_len);
      break;
    case PROP_SEGMENT_MAX_LEN:
      g_value_set_int (value, line_art->priv->segment_max_len);
      break;

    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
      break;
    }
}

495
496
/* Public functions */

497
498
499
500
501
502
503
GimpLineArt *
gimp_line_art_new (void)
{
  return g_object_new (GIMP_TYPE_LINE_ART,
                       NULL);
}

504
505
506
507
508
509
510
void
gimp_line_art_bind_gap_length (GimpLineArt *line_art,
                               gboolean     bound)
{
  line_art->priv->max_len_bound = bound;
}

511
512
513
514
void
gimp_line_art_set_input (GimpLineArt  *line_art,
                         GimpPickable *pickable)
{
515
516
  g_return_if_fail (pickable == NULL || GIMP_IS_VIEWABLE (pickable));

517
518
519
520
  if (pickable != line_art->priv->input)
    {
      if (line_art->priv->input)
        g_signal_handlers_disconnect_by_data (line_art->priv->input, line_art);
521

Ell's avatar
Ell committed
522
      g_set_object (&line_art->priv->input, pickable);
523

524
      gimp_line_art_compute (line_art);
525

526
527
528
529
530
531
      if (pickable)
        {
          g_signal_connect (pickable, "invalidate-preview",
                            G_CALLBACK (gimp_line_art_input_invalidate_preview),
                            line_art);
        }
532
533
534
    }
}

535
536
537
538
539
540
GimpPickable *
gimp_line_art_get_input (GimpLineArt *line_art)
{
  return line_art->priv->input;
}

541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
void
gimp_line_art_freeze (GimpLineArt *line_art)
{
  g_return_if_fail (! line_art->priv->frozen);

  line_art->priv->frozen             = TRUE;
  line_art->priv->compute_after_thaw = FALSE;
}

void
gimp_line_art_thaw (GimpLineArt *line_art)
{
  g_return_if_fail (line_art->priv->frozen);

  line_art->priv->frozen = FALSE;
  if (line_art->priv->compute_after_thaw)
    {
      gimp_line_art_compute (line_art);
      line_art->priv->compute_after_thaw = FALSE;
    }
}

563
564
565
566
567
568
gboolean
gimp_line_art_is_frozen (GimpLineArt *line_art)
{
  return line_art->priv->frozen;
}

569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
GeglBuffer *
gimp_line_art_get (GimpLineArt  *line_art,
                   gfloat      **distmap)
{
  g_return_val_if_fail (line_art->priv->input, NULL);

  if (line_art->priv->async)
    {
      gimp_waitable_wait (GIMP_WAITABLE (line_art->priv->async));
    }
  else if (! line_art->priv->closed)
    {
      gimp_line_art_compute (line_art);
      if (line_art->priv->async)
        gimp_waitable_wait (GIMP_WAITABLE (line_art->priv->async));
    }

  g_return_val_if_fail (line_art->priv->closed, NULL);

  if (distmap)
    *distmap = line_art->priv->distmap;

  return line_art->priv->closed;
}

/* Functions for asynchronous computation. */

static void
gimp_line_art_compute (GimpLineArt *line_art)
{
  if (line_art->priv->frozen)
    {
      line_art->priv->compute_after_thaw = TRUE;
      return;
    }

  if (line_art->priv->async)
    {
607
      /* we cancel the async, but don't wait for it to finish, since
608
       * it might take a while to respond.  instead gimp_line_art_compute_cb()
609
610
       * bails if the async has been canceled, to avoid accessing the line art.
       */
611
      g_signal_emit (line_art, gimp_line_art_signals[COMPUTING_END], 0);
612
613
614
615
      gimp_cancelable_cancel (GIMP_CANCELABLE (line_art->priv->async));
      g_clear_object (&line_art->priv->async);
    }

616
617
618
619
620
621
  if (line_art->priv->idle_id)
    {
      g_source_remove (line_art->priv->idle_id);
      line_art->priv->idle_id = 0;
    }

622
623
624
625
626
627
628
629
630
  g_clear_object (&line_art->priv->closed);
  g_clear_pointer (&line_art->priv->distmap, g_free);

  if (line_art->priv->input)
    {
      /* gimp_line_art_prepare_async() will flush the pickable, which
       * may trigger this signal handler, and will leak a line art (as
       * line_art->priv->async has not been set yet).
       */
631
632
633
634
      g_signal_handlers_block_by_func (
        line_art->priv->input,
        G_CALLBACK (gimp_line_art_input_invalidate_preview),
        line_art);
635
      line_art->priv->async = gimp_line_art_prepare_async (line_art, +1);
636
      g_signal_emit (line_art, gimp_line_art_signals[COMPUTING_START], 0);
637
638
639
640
      g_signal_handlers_unblock_by_func (
        line_art->priv->input,
        G_CALLBACK (gimp_line_art_input_invalidate_preview),
        line_art);
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663

      gimp_async_add_callback_for_object (line_art->priv->async,
                                          (GimpAsyncCallback) gimp_line_art_compute_cb,
                                          line_art, line_art);
    }
}

static void
gimp_line_art_compute_cb (GimpAsync   *async,
                          GimpLineArt *line_art)
{
  if (gimp_async_is_canceled (async))
    return;

  if (gimp_async_is_finished (async))
    {
      LineArtResult *result;

      result = gimp_async_get_result (async);

      line_art->priv->closed  = g_object_ref (result->closed);
      line_art->priv->distmap = result->distmap;
      result->distmap  = NULL;
664
      g_signal_emit (line_art, gimp_line_art_signals[COMPUTING_END], 0);
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
    }

  g_clear_object (&line_art->priv->async);
}

static GimpAsync *
gimp_line_art_prepare_async (GimpLineArt *line_art,
                             gint         priority)
{
  GeglBuffer  *buffer;
  GimpAsync   *async;
  LineArtData *data;

  g_return_val_if_fail (GIMP_IS_PICKABLE (line_art->priv->input), NULL);

  gimp_pickable_flush (line_art->priv->input);

682
683
  buffer = gimp_gegl_buffer_dup (
    gimp_pickable_get_buffer (line_art->priv->input));
684
685
686
687
688
689
690

  data  = line_art_data_new (buffer, line_art);

  g_object_unref (buffer);

  async = gimp_parallel_run_async_full (
    priority,
691
    (GimpRunAsyncFunc) gimp_line_art_prepare_async_func,
692
693
694
695
696
697
698
699
700
    data, (GDestroyNotify) line_art_data_free);

  return async;
}

static void
gimp_line_art_prepare_async_func (GimpAsync   *async,
                                  LineArtData *data)
{
701
  GeglBuffer *buffer;
702
703
  GeglBuffer *closed  = NULL;
  gfloat     *distmap = NULL;
704
705
  gint        buffer_x;
  gint        buffer_y;
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
  gboolean    has_alpha;
  gboolean    select_transparent = FALSE;

  has_alpha = babl_format_has_alpha (gegl_buffer_get_format (data->buffer));

  if (has_alpha)
    {
      if (data->select_transparent)
        {
          /*  don't select transparent regions if there are no fully
           *  transparent pixels.
           */
          GeglBufferIterator *gi;

          gi = gegl_buffer_iterator_new (data->buffer, NULL, 0,
                                         babl_format ("A u8"),
                                         GEGL_ACCESS_READ, GEGL_ABYSS_NONE, 3);
          while (gegl_buffer_iterator_next (gi))
            {
              guint8 *p = (guint8*) gi->items[0].data;
              gint    k;

              if (gimp_async_is_canceled (async))
                {
                  gegl_buffer_iterator_stop (gi);

                  gimp_async_abort (async);

                  line_art_data_free (data);

                  return;
                }

              for (k = 0; k < gi->length; k++)
                {
                  if (! *p)
                    {
                      select_transparent = TRUE;
                      break;
                    }
                  p++;
                }
              if (select_transparent)
                break;
            }
          if (select_transparent)
            gegl_buffer_iterator_stop (gi);
        }
    }

756
757
758
759
760
761
762
763
764
765
766
767
768
  buffer   = data->buffer;
  buffer_x = gegl_buffer_get_x (data->buffer);
  buffer_y = gegl_buffer_get_y (data->buffer);

  if (buffer_x != 0 || buffer_y != 0)
    {
      buffer = g_object_new (GEGL_TYPE_BUFFER,
                             "source",  buffer,
                             "shift-x", buffer_x,
                             "shift-y", buffer_y,
                             NULL);
    }

769
770
771
772
773
774
  /* For smart selection, we generate a binarized image with close
   * regions, then run a composite selection with no threshold on
   * this intermediate buffer.
   */
  GIMP_TIMER_START();

775
  closed = gimp_line_art_close (buffer,
776
777
                                select_transparent,
                                data->threshold,
778
                                data->automatic_closure,
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
                                data->spline_max_len,
                                data->segment_max_len,
                                /*minimal_lineart_area,*/
                                5,
                                /*normal_estimate_mask_size,*/
                                5,
                                /*end_point_rate,*/
                                0.85,
                                /*spline_max_angle,*/
                                90.0,
                                /*end_point_connectivity,*/
                                2,
                                /*spline_roundness,*/
                                1.0,
                                /*allow_self_intersections,*/
                                TRUE,
                                /*created_regions_significant_area,*/
                                4,
                                /*created_regions_minimum_area,*/
                                100,
                                /*small_segments_from_spline_sources,*/
                                TRUE,
801
802
                                &distmap,
                                async);
803
804
805

  GIMP_TIMER_END("close line-art");

806
807
808
  if (buffer != data->buffer)
    g_object_unref (buffer);

809
810
  if (! gimp_async_is_stopped (async))
    {
811
812
813
814
815
816
817
818
819
820
821
822
823
      if (buffer_x != 0 || buffer_y != 0)
        {
          buffer = g_object_new (GEGL_TYPE_BUFFER,
                                 "source",  closed,
                                 "shift-x", -buffer_x,
                                 "shift-y", -buffer_y,
                                 NULL);

          g_object_unref (closed);

          closed = buffer;
        }

824
825
826
827
      gimp_async_finish_full (async,
                              line_art_result_new (closed, distmap),
                              (GDestroyNotify) line_art_result_free);
    }
828
829
830
831
832
833
834
835
836
837
838
839
840

  line_art_data_free (data);
}

static LineArtData *
line_art_data_new (GeglBuffer  *buffer,
                   GimpLineArt *line_art)
{
  LineArtData *data = g_slice_new (LineArtData);

  data->buffer             = g_object_ref (buffer);
  data->select_transparent = line_art->priv->select_transparent;
  data->threshold          = line_art->priv->threshold;
841
  data->automatic_closure  = line_art->priv->automatic_closure;
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
  data->spline_max_len     = line_art->priv->spline_max_len;
  data->segment_max_len    = line_art->priv->segment_max_len;

  return data;
}

static void
line_art_data_free (LineArtData *data)
{
  g_object_unref (data->buffer);

  g_slice_free (LineArtData, data);
}

static LineArtResult *
line_art_result_new (GeglBuffer *closed,
                     gfloat     *distmap)
{
  LineArtResult *data;

  data = g_slice_new (LineArtResult);
  data->closed  = closed;
  data->distmap = distmap;

  return data;
}

static void
line_art_result_free (LineArtResult *data)
{
  g_object_unref (data->closed);
  g_clear_pointer (&data->distmap, g_free);

  g_slice_free (LineArtResult, data);
}

878
879
static gboolean
gimp_line_art_idle (GimpLineArt *line_art)
880
{
881
882
  line_art->priv->idle_id = 0;

883
  gimp_line_art_compute (line_art);
884
885

  return G_SOURCE_REMOVE;
886
887
888
}

static void
889
890
gimp_line_art_input_invalidate_preview (GimpViewable *viewable,
                                        GimpLineArt  *line_art)
891
{
892
893
894
895
896
897
898
  if (! line_art->priv->idle_id)
    {
      line_art->priv->idle_id = g_idle_add_full (
        GIMP_PRIORITY_VIEWABLE_IDLE,
        (GSourceFunc) gimp_line_art_idle,
        line_art, NULL);
    }
899
900
901
902
}

/* All actual computation functions. */

903
/**
904
 * gimp_line_art_close:
905
 * @buffer: the input #GeglBuffer.
906
907
908
909
 * @select_transparent: whether we binarize the alpha channel or the
 *                      luminosity.
 * @stroke_threshold: [0-1] threshold value for detecting stroke pixels
 *                    (higher values will detect more stroke pixels).
910
911
912
 * @automatic_closure: whether the closing step should be performed or
 *                     not. @spline_max_length and @segment_max_len are
 *                     used only if @automatic_closure is %TRUE.
913
914
915
916
917
 * @spline_max_length: the maximum length for creating splines between
 *                     end points.
 * @segment_max_length: the maximum length for creating segments
 *                      between end points. Unlike splines, segments
 *                      are straight lines.
918
919
 * @minimal_lineart_area: the minimum size in number pixels for area to
 *                        be considered as line art.
920
 * @normal_estimate_mask_size:
921
922
923
924
 * @end_point_rate: threshold to estimate if a curvature is an end-point
 *                  in [0-1] range value.
 * @spline_max_angle: the maximum angle between end point normals for
 *                    creating splines between them.
925
926
 * @end_point_connectivity:
 * @spline_roundness:
927
928
 * @allow_self_intersections: whether to allow created splines and
 *                            segments to intersect.
929
930
931
 * @created_regions_significant_area:
 * @created_regions_minimum_area:
 * @small_segments_from_spline_sources:
932
 * @closed_distmap: a distance map of the closed line art pixels.
933
 * @async: the #GimpAsync associated with the computation
934
 *
935
 * Creates a binarized version of the strokes of @buffer, detected either
936
937
938
939
940
941
942
943
944
945
 * with luminosity (light means background) or alpha values depending on
 * @select_transparent. This binary version of the strokes will have closed
 * regions allowing adequate selection of "nearly closed regions".
 * This algorithm is meant for digital painting (and in particular on the
 * sketch-only step), and therefore will likely produce unexpected results on
 * other types of input.
 *
 * The algorithm is the first step from the research paper "A Fast and
 * Efficient Semi-guided Algorithm for Flat Coloring Line-arts", by Sébastian
 * Fourey, David Tschumperlé, David Revoy.
946
 * https://hal.archives-ouvertes.fr/hal-01891876
947
948
 *
 * Returns: a new #GeglBuffer of format "Y u8" representing the
949
 *          binarized @line_art. If @lineart_distmap is not %NULL, a
950
951
 *          newly allocated float buffer is returned, which can be used
 *          for overflowing created masks later.
952
 */
953
954
955
956
static GeglBuffer *
gimp_line_art_close (GeglBuffer  *buffer,
                     gboolean     select_transparent,
                     gdouble      stroke_threshold,
957
                     gboolean     automatic_closure,
958
959
960
961
962
963
964
965
966
967
968
969
                     gint         spline_max_length,
                     gint         segment_max_length,
                     gint         minimal_lineart_area,
                     gint         normal_estimate_mask_size,
                     gfloat       end_point_rate,
                     gfloat       spline_max_angle,
                     gint         end_point_connectivity,
                     gfloat       spline_roundness,
                     gboolean     allow_self_intersections,
                     gint         created_regions_significant_area,
                     gint         created_regions_minimum_area,
                     gboolean     small_segments_from_spline_sources,
970
971
                     gfloat     **closed_distmap,
                     GimpAsync   *async)
972
{
Jehan's avatar
Jehan committed
973
974
  const Babl         *gray_format;
  GeglBufferIterator *gi;
975
976
  GeglBuffer         *closed  = NULL;
  GeglBuffer         *strokes = NULL;
Jehan's avatar
Jehan committed
977
  guchar              max_value = 0;
978
979
  gint                width  = gegl_buffer_get_width (buffer);
  gint                height = gegl_buffer_get_height (buffer);
Jehan's avatar
Jehan committed
980
  gint                i;
981
982
983
984
985
986
987
988
989

  if (select_transparent)
    /* Keep alpha channel as gray levels */
    gray_format = babl_format ("A u8");
  else
    /* Keep luminance */
    gray_format = babl_format ("Y' u8");

  /* Transform the line art from any format to gray. */
990
  strokes = gegl_buffer_new (gegl_buffer_get_extent (buffer),
991
                             gray_format);
992
  gimp_gegl_buffer_copy (buffer, NULL, GEGL_ABYSS_NONE, strokes, NULL);
993
994
995
996
997
998
999
1000
  gegl_buffer_set_format (strokes, babl_format ("Y' u8"));

  if (! select_transparent)
    {
      /* Compute the biggest value */
      gi = gegl_buffer_iterator_new (strokes, NULL, 0, NULL,
                                     GEGL_ACCESS_READ, GEGL_ABYSS_NONE, 1);
      while (gegl_buffer_iterator_next (gi))
For faster browsing, not all history is shown. View entire blame