Coverage Report

Created: 2024-02-28 06:46

/src/leptonica/src/conncomp.c
Line
Count
Source (jump to first uncovered line)
1
/*====================================================================*
2
 -  Copyright (C) 2001 Leptonica.  All rights reserved.
3
 -
4
 -  Redistribution and use in source and binary forms, with or without
5
 -  modification, are permitted provided that the following conditions
6
 -  are met:
7
 -  1. Redistributions of source code must retain the above copyright
8
 -     notice, this list of conditions and the following disclaimer.
9
 -  2. Redistributions in binary form must reproduce the above
10
 -     copyright notice, this list of conditions and the following
11
 -     disclaimer in the documentation and/or other materials
12
 -     provided with the distribution.
13
 -
14
 -  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15
 -  ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16
 -  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
17
 -  A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL ANY
18
 -  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19
 -  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20
 -  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21
 -  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22
 -  OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
23
 -  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24
 -  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25
 *====================================================================*/
26
27
/*!
28
 * \file conncomp.c
29
 * <pre>
30
 *
31
 *    Connected component counting and extraction, using Heckbert's
32
 *    stack-based filling algorithm.
33
 *
34
 *      4- and 8-connected components: counts, bounding boxes and images
35
 *
36
 *      Top-level calls:
37
 *            BOXA     *pixConnComp()
38
 *            BOXA     *pixConnCompPixa()
39
 *            BOXA     *pixConnCompBB()
40
 *            l_int32   pixCountConnComp()
41
 *
42
 *      Identify the next c.c. to be erased:
43
 *            l_int32   nextOnPixelInRaster()
44
 *    static  l_int32   nextOnPixelInRasterLow()
45
 *
46
 *      Erase the c.c., saving the b.b.:
47
 *            BOX      *pixSeedfillBB()
48
 *            BOX      *pixSeedfill4BB()
49
 *            BOX      *pixSeedfill8BB()
50
 *
51
 *      Just erase the c.c.:
52
 *            l_int32   pixSeedfill()
53
 *            l_int32   pixSeedfill4()
54
 *            l_int32   pixSeedfill8()
55
 *
56
 *      Static stack helper functions for single raster line seedfill:
57
 *            static void    pushFillsegBB()
58
 *            static void    pushFillseg()
59
 *            static void    popFillseg()
60
 *
61
 *  The basic method in pixConnCompBB() is very simple.  We scan the
62
 *  image in raster order, looking for the next ON pixel.  When it
63
 *  is found, we erase it and every pixel of the 4- or 8-connected
64
 *  component to which it belongs, using Heckbert's seedfill
65
 *  algorithm.  As pixels are erased, we keep track of the
66
 *  minimum rectangle that encloses all erased pixels; after
67
 *  the connected component has been erased, we save its
68
 *  bounding box in an array of boxes.  When all pixels in the
69
 *  image have been erased, we have an array that describes every
70
 *  4- or 8-connected component in terms of its bounding box.
71
 *
72
 *  pixConnCompPixa() is a slight variation on pixConnCompBB(),
73
 *  where we additionally save an array of images (in a Pixa)
74
 *  of each of the 4- or 8-connected components.  This is done trivially
75
 *  by maintaining two temporary images.  We erase a component from one,
76
 *  and use the bounding box to extract the pixels within the b.b.
77
 *  from each of the two images.  An XOR between these subimages
78
 *  gives the erased component.  Then we erase the component from the
79
 *  second image using the XOR again, with the extracted component
80
 *  placed on the second image at the location of the bounding box.
81
 *  Rasterop does all the work.  At the end, we have an array
82
 *  of the 4- or 8-connected components, as well as an array of the
83
 *  bounding boxes that describe where they came from in the original image.
84
 *
85
 *  If you just want the number of connected components, pixCountConnComp()
86
 *  is a bit faster than pixConnCompBB(), because it doesn't have to
87
 *  keep track of the bounding rectangles for each c.c.
88
 * </pre>
89
 */
90
91
#ifdef HAVE_CONFIG_H
92
#include <config_auto.h>
93
#endif  /* HAVE_CONFIG_H */
94
95
#include "allheaders.h"
96
#include "pix_internal.h"
97
98
/*!
99
 * \brief   The struct FillSeg is used by the Heckbert seedfill algorithm to
100
 *  hold information about image segments that are waiting to be
101
 *  investigated.  We use two Stacks, one to hold the FillSegs in use,
102
 *  and an auxiliary Stack as a reservoir to hold FillSegs for re-use.
103
 */
104
struct FillSeg
105
{
106
    l_int32    xleft;    /*!< left edge of run */
107
    l_int32    xright;   /*!< right edge of run */
108
    l_int32    y;        /*!< run y  */
109
    l_int32    dy;       /*!< parent segment direction: 1 above, -1 below) */
110
};
111
typedef struct FillSeg    FILLSEG;
112
113
static l_int32 nextOnPixelInRasterLow(l_uint32 *data, l_int32 w, l_int32 h,
114
                                      l_int32 wpl, l_int32 xstart,
115
                                      l_int32 ystart, l_int32 *px, l_int32 *py);
116
117
    /* Static accessors for FillSegs on a stack */
118
static void pushFillsegBB(L_STACK *stack, l_int32 xleft, l_int32 xright,
119
                          l_int32 y, l_int32 dy, l_int32 ymax,
120
                          l_int32 *pminx, l_int32 *pmaxx,
121
                          l_int32 *pminy, l_int32 *pmaxy);
122
static void pushFillseg(L_STACK *stack, l_int32 xleft, l_int32 xright,
123
                        l_int32 y, l_int32 dy, l_int32 ymax);
124
static void popFillseg(L_STACK *stack, l_int32 *pxleft, l_int32 *pxright,
125
                       l_int32 *py, l_int32 *pdy);
126
127
128
#ifndef  NO_CONSOLE_IO
129
#define   DEBUG    0
130
#endif  /* ~NO_CONSOLE_IO */
131
132
133
/*-----------------------------------------------------------------------*
134
 *                Bounding boxes of 4 Connected Components               *
135
 *-----------------------------------------------------------------------*/
136
/*!
137
 * \brief   pixConnComp()
138
 *
139
 * \param[in]    pixs           1 bpp
140
 * \param[out]   ppixa          [optional] pixa of each c.c.
141
 * \param[in]    connectivity   4 or 8
142
 * \return  boxa, or NULL on error
143
 *
144
 * <pre>
145
 * Notes:
146
 *      (1) This is the top-level call for getting bounding boxes or
147
 *          a pixa of the components, and it can be used instead
148
 *          of either pixConnCompBB() or pixConnCompPixa(), rsp.
149
 * </pre>
150
 */
151
BOXA *
152
pixConnComp(PIX     *pixs,
153
            PIXA   **ppixa,
154
            l_int32  connectivity)
155
12
{
156
157
12
    if (ppixa) *ppixa = NULL;
158
12
    if (!pixs || pixGetDepth(pixs) != 1)
159
0
        return (BOXA *)ERROR_PTR("pixs undefined or not 1 bpp", __func__, NULL);
160
12
    if (connectivity != 4 && connectivity != 8)
161
0
        return (BOXA *)ERROR_PTR("connectivity not 4 or 8", __func__, NULL);
162
163
12
    if (!ppixa)
164
12
        return pixConnCompBB(pixs, connectivity);
165
0
    else
166
0
        return pixConnCompPixa(pixs, ppixa, connectivity);
167
12
}
168
169
170
/*!
171
 * \brief   pixConnCompPixa()
172
 *
173
 * \param[in]    pixs           1 bpp
174
 * \param[out]   ppixa          pixa of each c.c.
175
 * \param[in]    connectivity   4 or 8
176
 * \return  boxa, or NULL on error
177
 *
178
 * <pre>
179
 * Notes:
180
 *      (1) This finds bounding boxes of 4- or 8-connected components
181
 *          in a binary image, and saves images of each c.c
182
 *          in a pixa array.
183
 *      (2) It sets up 2 temporary pix, and for each c.c. that is
184
 *          located in raster order, it erases the c.c. from one pix,
185
 *          then uses the b.b. to extract the c.c. from the two pix using
186
 *          an XOR, and finally erases the c.c. from the second pix.
187
 *      (3) A clone of the returned boxa (where all boxes in the array
188
 *          are clones) is inserted into the pixa.
189
 *      (4) If the input is valid, this always returns a boxa and a pixa.
190
 *          If pixs is empty, the boxa and pixa will be empty.
191
 * </pre>
192
 */
193
BOXA *
194
pixConnCompPixa(PIX     *pixs,
195
                PIXA   **ppixa,
196
                l_int32  connectivity)
197
0
{
198
0
l_int32   h, iszero;
199
0
l_int32   x, y, xstart, ystart;
200
0
PIX      *pix1, *pix2, *pix3, *pix4;
201
0
PIXA     *pixa;
202
0
BOX      *box;
203
0
BOXA     *boxa;
204
0
L_STACK  *stack, *auxstack;
205
206
0
    if (!ppixa)
207
0
        return (BOXA *)ERROR_PTR("&pixa not defined", __func__, NULL);
208
0
    *ppixa = NULL;
209
0
    if (!pixs || pixGetDepth(pixs) != 1)
210
0
        return (BOXA *)ERROR_PTR("pixs undefined or not 1 bpp", __func__, NULL);
211
0
    if (connectivity != 4 && connectivity != 8)
212
0
        return (BOXA *)ERROR_PTR("connectivity not 4 or 8", __func__, NULL);
213
214
0
    pix1 = pix2 = pix3 = pix4 = NULL;
215
0
    stack = NULL;
216
0
    pixa = pixaCreate(0);
217
0
    boxa = NULL;
218
0
    *ppixa = pixa;
219
0
    pixZero(pixs, &iszero);
220
0
    if (iszero)
221
0
        return boxaCreate(1);  /* return empty boxa and empty pixa */
222
223
0
    pixSetPadBits(pixs, 0);
224
0
    pix1 = pixCopy(NULL, pixs);
225
0
    pix2 = pixCopy(NULL, pixs);
226
0
    if (!pix1 || !pix2) {
227
0
        L_ERROR("pix1 or pix2 not made\n", __func__);
228
0
        pixaDestroy(ppixa);
229
0
        goto cleanup;
230
0
    }
231
232
0
    h = pixGetHeight(pixs);
233
0
    if ((stack = lstackCreate(h)) == NULL) {
234
0
        L_ERROR("stack not made\n", __func__);
235
0
        pixaDestroy(ppixa);
236
0
        goto cleanup;
237
0
    }
238
0
    auxstack = lstackCreate(0);
239
0
    stack->auxstack = auxstack;
240
0
    boxa = boxaCreate(0);
241
242
0
    xstart = 0;
243
0
    ystart = 0;
244
0
    while (1) {
245
0
        if (!nextOnPixelInRaster(pix1, xstart, ystart, &x, &y))
246
0
            break;
247
248
0
        if ((box = pixSeedfillBB(pix1, stack, x, y, connectivity)) == NULL) {
249
0
            boxaDestroy(&boxa);
250
0
            pixaDestroy(ppixa);
251
0
            L_ERROR("box not made\n", __func__);
252
0
            goto cleanup;
253
0
        }
254
0
        boxaAddBox(boxa, box, L_INSERT);
255
256
            /* Save the c.c. and remove from pix2 as well */
257
0
        pix3 = pixClipRectangle(pix1, box, NULL);
258
0
        pix4 = pixClipRectangle(pix2, box, NULL);
259
0
        pixXor(pix3, pix3, pix4);
260
0
        pixRasterop(pix2, box->x, box->y, box->w, box->h, PIX_SRC ^ PIX_DST,
261
0
                    pix3, 0, 0);
262
0
        pixaAddPix(pixa, pix3, L_INSERT);
263
0
        pixDestroy(&pix4);
264
265
0
        xstart = x;
266
0
        ystart = y;
267
0
    }
268
269
#if  DEBUG
270
    pixCountPixels(pix1, &iszero, NULL);
271
    lept_stderr("Number of remaining pixels = %d\n", iszero);
272
    lept_mkdir("lept/cc");
273
    pixWriteDebug("/tmp/lept/cc/remain.png", pix1, IFF_PNG);
274
#endif  /* DEBUG */
275
276
        /* Remove old boxa of pixa and replace with a copy */
277
0
    boxaDestroy(&pixa->boxa);
278
0
    pixa->boxa = boxaCopy(boxa, L_COPY);
279
0
    *ppixa = pixa;
280
281
        /* Cleanup, freeing the fillsegs on each stack */
282
0
cleanup:
283
0
    lstackDestroy(&stack, TRUE);
284
0
    pixDestroy(&pix1);
285
0
    pixDestroy(&pix2);
286
0
    return boxa;
287
0
}
288
289
290
/*!
291
 * \brief   pixConnCompBB()
292
 *
293
 * \param[in]    pixs           1 bpp
294
 * \param[in]    connectivity   4 or 8
295
 * \return  boxa, or NULL on error
296
 *
297
 * <pre>
298
 * Notes:
299
 *     (1) Finds bounding boxes of 4- or 8-connected components
300
 *         in a binary image.
301
 *     (2) This works on a copy of the input pix.  The c.c. are located
302
 *         in raster order and erased one at a time.  In the process,
303
 *         the b.b. is computed and saved.
304
 * </pre>
305
 */
306
BOXA *
307
pixConnCompBB(PIX     *pixs,
308
              l_int32  connectivity)
309
12
{
310
12
l_int32   h, iszero;
311
12
l_int32   x, y, xstart, ystart;
312
12
PIX      *pix1;
313
12
BOX      *box;
314
12
BOXA     *boxa;
315
12
L_STACK  *stack, *auxstack;
316
317
12
    if (!pixs || pixGetDepth(pixs) != 1)
318
0
        return (BOXA *)ERROR_PTR("pixs undefined or not 1 bpp", __func__, NULL);
319
12
    if (connectivity != 4 && connectivity != 8)
320
0
        return (BOXA *)ERROR_PTR("connectivity not 4 or 8", __func__, NULL);
321
322
12
    boxa = NULL;
323
12
    pix1 = NULL;
324
12
    stack = NULL;
325
12
    pixZero(pixs, &iszero);
326
12
    if (iszero)
327
0
        return boxaCreate(1);  /* return empty boxa */
328
329
12
    pixSetPadBits(pixs, 0);
330
12
    if ((pix1 = pixCopy(NULL, pixs)) == NULL)
331
0
        return (BOXA *)ERROR_PTR("pix1 not made", __func__, NULL);
332
333
12
    h = pixGetHeight(pixs);
334
12
    if ((stack = lstackCreate(h)) == NULL) {
335
0
        L_ERROR("stack not made\n", __func__);
336
0
        goto cleanup;
337
0
    }
338
12
    auxstack = lstackCreate(0);
339
12
    stack->auxstack = auxstack;
340
12
    boxa = boxaCreate(0);
341
342
12
    xstart = 0;
343
12
    ystart = 0;
344
388
    while (1) {
345
388
        if (!nextOnPixelInRaster(pix1, xstart, ystart, &x, &y))
346
12
            break;
347
348
376
        if ((box = pixSeedfillBB(pix1, stack, x, y, connectivity)) == NULL) {
349
0
            L_ERROR("box not made\n", __func__);
350
0
            boxaDestroy(&boxa);
351
0
            goto cleanup;
352
0
        }
353
376
        boxaAddBox(boxa, box, L_INSERT);
354
355
376
        xstart = x;
356
376
        ystart = y;
357
376
    }
358
359
#if  DEBUG
360
    pixCountPixels(pix1, &iszero, NULL);
361
    lept_stderr("Number of remaining pixels = %d\n", iszero);
362
    lept_mkdir("lept/cc");
363
    pixWriteDebug("/tmp/lept/cc/remain.png", pix1, IFF_PNG);
364
#endif  /* DEBUG */
365
366
        /* Cleanup, freeing the fillsegs on each stack */
367
12
cleanup:
368
12
    lstackDestroy(&stack, TRUE);
369
12
    pixDestroy(&pix1);
370
12
    return boxa;
371
12
}
372
373
374
/*!
375
 * \brief   pixCountConnComp()
376
 *
377
 * \param[in]    pixs           1 bpp
378
 * \param[in]    connectivity   4 or 8
379
 * \param[out]   pcount
380
 * \return  0 if OK, 1 on error
381
 *
382
 * Notes:
383
 *     (1 This is the top-level call for getting the number of
384
 *         4- or 8-connected components in a 1 bpp image.
385
 *     2 It works on a copy of the input pix.  The c.c. are located
386
 *         in raster order and erased one at a time.
387
 */
388
l_ok
389
pixCountConnComp(PIX      *pixs,
390
                 l_int32   connectivity,
391
                 l_int32  *pcount)
392
0
{
393
0
l_int32   h, iszero;
394
0
l_int32   x, y, xstart, ystart;
395
0
PIX      *pix1;
396
0
L_STACK  *stack, *auxstack;
397
398
0
    if (!pcount)
399
0
        return ERROR_INT("&count not defined", __func__, 1);
400
0
    *pcount = 0;  /* initialize the count to 0 */
401
0
    if (!pixs || pixGetDepth(pixs) != 1)
402
0
        return ERROR_INT("pixs not defined or not 1 bpp", __func__, 1);
403
0
    if (connectivity != 4 && connectivity != 8)
404
0
        return ERROR_INT("connectivity not 4 or 8", __func__, 1);
405
406
0
    stack = NULL;
407
0
    pixZero(pixs, &iszero);
408
0
    if (iszero)
409
0
        return 0;
410
411
0
    pixSetPadBits(pixs, 0);
412
0
    if ((pix1 = pixCopy(NULL, pixs)) == NULL)
413
0
        return ERROR_INT("pix1 not made", __func__, 1);
414
0
    h = pixGetHeight(pixs);
415
0
    if ((stack = lstackCreate(h)) == NULL) {
416
0
        pixDestroy(&pix1);
417
0
        return ERROR_INT("stack not made\n", __func__, 1);
418
0
    }
419
0
    auxstack = lstackCreate(0);
420
0
    stack->auxstack = auxstack;
421
422
0
    xstart = 0;
423
0
    ystart = 0;
424
0
    while (1) {
425
0
        if (!nextOnPixelInRaster(pix1, xstart, ystart, &x, &y))
426
0
            break;
427
428
0
        pixSeedfill(pix1, stack, x, y, connectivity);
429
0
        (*pcount)++;
430
0
        xstart = x;
431
0
        ystart = y;
432
0
    }
433
434
        /* Cleanup, freeing the fillsegs on each stack */
435
0
    lstackDestroy(&stack, TRUE);
436
0
    pixDestroy(&pix1);
437
0
    return 0;
438
0
}
439
440
441
/*!
442
 * \brief   nextOnPixelInRaster()
443
 *
444
 * \param[in]    pixs             1 bpp
445
 * \param[in]    xstart, ystart   starting point for search
446
 * \param[out]   px, py           coord value of next ON pixel
447
 * \return  1 if a pixel is found; 0 otherwise or on error
448
 */
449
l_int32
450
nextOnPixelInRaster(PIX      *pixs,
451
                    l_int32   xstart,
452
                    l_int32   ystart,
453
                    l_int32  *px,
454
                    l_int32  *py)
455
388
{
456
388
l_int32    w, h, d, wpl;
457
388
l_uint32  *data;
458
459
388
    if (!pixs)
460
0
        return ERROR_INT("pixs not defined", __func__, 0);
461
388
    pixGetDimensions(pixs, &w, &h, &d);
462
388
    if (d != 1)
463
0
        return ERROR_INT("pixs not 1 bpp", __func__, 0);
464
465
388
    wpl = pixGetWpl(pixs);
466
388
    data = pixGetData(pixs);
467
388
    return nextOnPixelInRasterLow(data, w, h, wpl, xstart, ystart, px, py);
468
388
}
469
470
471
/*!
472
 * \brief   nextOnPixelInRasterLow()
473
 *
474
 * \param[in]    data             pix data
475
 * \param[in]    w, h             width and height
476
 * \param[in]    wpl              words per line
477
 * \param[in]    xstart, ystart   starting point for search
478
 * \param[out]   px, py           coord value of next ON pixel
479
 * \return  1 if a pixel is found; 0 otherwise or on error
480
 */
481
static l_int32
482
nextOnPixelInRasterLow(l_uint32  *data,
483
                       l_int32    w,
484
                       l_int32    h,
485
                       l_int32    wpl,
486
                       l_int32    xstart,
487
                       l_int32    ystart,
488
                       l_int32   *px,
489
                       l_int32   *py)
490
388
{
491
388
l_int32    i, x, y, xend, startword;
492
388
l_uint32  *line, *pword;
493
494
        /* Look at the first word */
495
388
    line = data + ystart * wpl;
496
388
    pword = line + (xstart / 32);
497
388
    if (*pword) {
498
4
        xend = xstart - (xstart % 32) + 31;
499
44
        for (x = xstart; x <= xend && x < w; x++) {
500
44
            if (GET_DATA_BIT(line, x)) {
501
4
                *px = x;
502
4
                *py = ystart;
503
4
                return 1;
504
4
            }
505
44
        }
506
4
    }
507
508
        /* Continue with the rest of the line */
509
384
    startword = (xstart / 32) + 1;
510
384
    x = 32 * startword;
511
4.35k
    for (pword = line + startword; x < w; pword++, x += 32) {
512
4.26k
        if (*pword) {
513
5.07k
            for (i = 0; i < 32 && x < w; i++, x++) {
514
5.07k
                if (GET_DATA_BIT(line, x)) {
515
292
                    *px = x;
516
292
                    *py = ystart;
517
292
                    return 1;
518
292
                }
519
5.07k
            }
520
292
        }
521
4.26k
    }
522
523
        /* Continue with following lines */
524
676
    for (y = ystart + 1; y < h; y++) {
525
664
        line = data + y * wpl;
526
34.8k
        for (pword = line, x = 0; x < w; pword++, x += 32) {
527
34.2k
            if (*pword) {
528
1.22k
                for (i = 0; i < 32 && x < w; i++, x++) {
529
1.22k
                    if (GET_DATA_BIT(line, x)) {
530
80
                        *px = x;
531
80
                        *py = y;
532
80
                        return 1;
533
80
                    }
534
1.22k
                }
535
80
            }
536
34.2k
        }
537
664
    }
538
539
12
    return 0;
540
92
}
541
542
543
/*!
544
 * \brief   pixSeedfillBB()
545
 *
546
 * \param[in]    pixs           1 bpp
547
 * \param[in]    stack          for holding fillsegs
548
 * \param[in]    x,y            location of seed pixel
549
 * \param[in]    connectivity   4 or 8
550
 * \return  box or NULL on error
551
 *
552
 * <pre>
553
 * Notes:
554
 *      (1) This is the high-level interface to Paul Heckbert's
555
 *          stack-based seedfill algorithm.
556
 * </pre>
557
 */
558
BOX *
559
pixSeedfillBB(PIX      *pixs,
560
              L_STACK  *stack,
561
              l_int32   x,
562
              l_int32   y,
563
              l_int32   connectivity)
564
376
{
565
376
BOX  *box;
566
567
376
    if (!pixs || pixGetDepth(pixs) != 1)
568
0
        return (BOX *)ERROR_PTR("pixs undefined or not 1 bpp", __func__, NULL);
569
376
    if (!stack)
570
0
        return (BOX *)ERROR_PTR("stack not defined", __func__, NULL);
571
376
    if (connectivity != 4 && connectivity != 8)
572
0
        return (BOX *)ERROR_PTR("connectivity not 4 or 8", __func__, NULL);
573
574
376
    if (connectivity == 4) {
575
0
        if ((box = pixSeedfill4BB(pixs, stack, x, y)) == NULL)
576
0
            return (BOX *)ERROR_PTR("box not made", __func__, NULL);
577
376
    } else if (connectivity == 8) {
578
376
        if ((box = pixSeedfill8BB(pixs, stack, x, y)) == NULL)
579
0
            return (BOX *)ERROR_PTR("box not made", __func__, NULL);
580
376
    } else {
581
0
        return (BOX *)ERROR_PTR("connectivity not 4 or 8", __func__, NULL);
582
0
    }
583
584
376
    return box;
585
376
}
586
587
588
/*!
589
 * \brief   pixSeedfill4BB()
590
 *
591
 * \param[in]    pixs     1 bpp
592
 * \param[in]    stack    for holding fillsegs
593
 * \param[in]    x,y      location of seed pixel
594
 * \return  box or NULL on error.
595
 *
596
 * <pre>
597
 * Notes:
598
 *      (1) This is Paul Heckbert's stack-based 4-cc seedfill algorithm.
599
 *      (2) This operates on the input 1 bpp pix to remove the fg seed
600
 *          pixel, at (x,y), and all pixels that are 4-connected to it.
601
 *          The seed pixel at (x,y) must initially be ON.
602
 *      (3) Returns the bounding box of the erased 4-cc component.
603
 *      (4) Reference: see Paul Heckbert's stack-based seed fill algorithm
604
 *          in "Graphic Gems", ed. Andrew Glassner, Academic
605
 *          Press, 1990.  The algorithm description is given
606
 *          on pp. 275-277; working C code is on pp. 721-722.)
607
 *          The code here follows Heckbert's exactly, except
608
 *          we use function calls instead of macros for
609
 *          pushing data on and popping data off the stack.
610
 *          This makes sense to do because Heckbert's fixed-size
611
 *          stack with macros is dangerous: images exist that
612
 *          will overrun the stack and crash.   The stack utility
613
 *          here grows dynamically as needed, and the fillseg
614
 *          structures that are not in use are stored in another
615
 *          stack for reuse.  It should be noted that the
616
 *          overhead in the function calls (vs. macros) is negligible.
617
 * </pre>
618
 */
619
BOX *
620
pixSeedfill4BB(PIX      *pixs,
621
               L_STACK  *stack,
622
               l_int32   x,
623
               l_int32   y)
624
0
{
625
0
l_int32    w, h, xstart, wpl, x1, x2, dy;
626
0
l_int32    xmax, ymax;
627
0
l_int32    minx, maxx, miny, maxy;  /* for bounding box of this c.c. */
628
0
l_uint32  *data, *line;
629
0
BOX       *box;
630
631
0
    if (!pixs || pixGetDepth(pixs) != 1)
632
0
        return (BOX *)ERROR_PTR("pixs undefined or not 1 bpp", __func__, NULL);
633
0
    if (!stack)
634
0
        return (BOX *)ERROR_PTR("stack not defined", __func__, NULL);
635
0
    if (!stack->auxstack)
636
0
        stack->auxstack = lstackCreate(0);
637
638
0
    pixGetDimensions(pixs, &w, &h, NULL);
639
0
    xmax = w - 1;
640
0
    ymax = h - 1;
641
0
    data = pixGetData(pixs);
642
0
    wpl = pixGetWpl(pixs);
643
0
    line = data + y * wpl;
644
645
        /* Check pix value of seed; must be within the image and ON */
646
0
    if (x < 0 || x > xmax || y < 0 || y > ymax || (GET_DATA_BIT(line, x) == 0))
647
0
        return NULL;
648
649
        /* Init stack to seed:
650
         * Must first init b.b. values to prevent valgrind from complaining;
651
         * then init b.b. boundaries correctly to seed.  */
652
0
    minx = miny = 100000;
653
0
    maxx = maxy = 0;
654
0
    pushFillsegBB(stack, x, x, y, 1, ymax, &minx, &maxx, &miny, &maxy);
655
0
    pushFillsegBB(stack, x, x, y + 1, -1, ymax, &minx, &maxx, &miny, &maxy);
656
0
    minx = maxx = x;
657
0
    miny = maxy = y;
658
659
0
    while (lstackGetCount(stack) > 0) {
660
            /* Pop segment off stack and fill a neighboring scan line */
661
0
        popFillseg(stack, &x1, &x2, &y, &dy);
662
0
        line = data + y * wpl;
663
664
            /* A segment of scanline y - dy for x1 <= x <= x2 was
665
             * previously filled.  We now explore adjacent pixels
666
             * in scan line y.  There are three regions: to the
667
             * left of x1 - 1, between x1 and x2, and to the right of x2.
668
             * These regions are handled differently.  Leaks are
669
             * possible expansions beyond the previous segment and
670
             * going back in the -dy direction.  These can happen
671
             * for x < x1 - 1 and for x > x2 + 1.  Any "leak" segments
672
             * are plugged with a push in the -dy (opposite) direction.
673
             * And any segments found anywhere are always extended
674
             * in the +dy direction.  */
675
0
        for (x = x1; x >= 0 && (GET_DATA_BIT(line, x) == 1); x--)
676
0
            CLEAR_DATA_BIT(line,x);
677
0
        if (x >= x1)  /* pix at x1 was off and was not cleared */
678
0
            goto skip;
679
0
        xstart = x + 1;
680
0
        if (xstart < x1 - 1)   /* leak on left? */
681
0
            pushFillsegBB(stack, xstart, x1 - 1, y, -dy,
682
0
                          ymax, &minx, &maxx, &miny, &maxy);
683
684
0
        x = x1 + 1;
685
0
        do {
686
0
            for (; x <= xmax && (GET_DATA_BIT(line, x) == 1); x++)
687
0
                CLEAR_DATA_BIT(line, x);
688
0
            pushFillsegBB(stack, xstart, x - 1, y, dy,
689
0
                          ymax, &minx, &maxx, &miny, &maxy);
690
0
            if (x > x2 + 1)   /* leak on right? */
691
0
                pushFillsegBB(stack, x2 + 1, x - 1, y, -dy,
692
0
                              ymax, &minx, &maxx, &miny, &maxy);
693
0
    skip:   for (x++; x <= x2 &&
694
0
                      x <= xmax &&
695
0
                      (GET_DATA_BIT(line, x) == 0); x++)
696
0
                ;
697
0
            xstart = x;
698
0
        } while (x <= x2 && x <= xmax);
699
0
    }
700
701
0
    if ((box = boxCreate(minx, miny, maxx - minx + 1, maxy - miny + 1))
702
0
            == NULL)
703
0
        return (BOX *)ERROR_PTR("box not made", __func__, NULL);
704
0
    return box;
705
0
}
706
707
708
/*!
709
 * \brief   pixSeedfill8BB()
710
 *
711
 * \param[in]    pixs    1 bpp
712
 * \param[in]    stack   for holding fillsegs
713
 * \param[in]    x,y     location of seed pixel
714
 * \return  box or NULL on error.
715
 *
716
 * <pre>
717
 * Notes:
718
 *      (1) This is Paul Heckbert's stack-based 8-cc seedfill algorithm.
719
 *      (2) This operates on the input 1 bpp pix to remove the fg seed
720
 *          pixel, at (x,y), and all pixels that are 8-connected to it.
721
 *          The seed pixel at (x,y) must initially be ON.
722
 *      (3) Returns the bounding box of the erased 8-cc component.
723
 *      (4) Reference: see Paul Heckbert's stack-based seed fill algorithm
724
 *          in "Graphic Gems", ed. Andrew Glassner, Academic
725
 *          Press, 1990.  The algorithm description is given
726
 *          on pp. 275-277; working C code is on pp. 721-722.)
727
 *          The code here follows Heckbert's closely, except
728
 *          the leak checks are changed for 8 connectivity.
729
 *          See comments on pixSeedfill4BB() for more details.
730
 * </pre>
731
 */
732
BOX *
733
pixSeedfill8BB(PIX      *pixs,
734
               L_STACK  *stack,
735
               l_int32   x,
736
               l_int32   y)
737
376
{
738
376
l_int32    w, h, xstart, wpl, x1, x2, dy;
739
376
l_int32    xmax, ymax;
740
376
l_int32    minx, maxx, miny, maxy;  /* for bounding box of this c.c. */
741
376
l_uint32  *data, *line;
742
376
BOX       *box;
743
744
376
    if (!pixs || pixGetDepth(pixs) != 1)
745
0
        return (BOX *)ERROR_PTR("pixs undefined or not 1 bpp", __func__, NULL);
746
376
    if (!stack)
747
0
        return (BOX *)ERROR_PTR("stack not defined", __func__, NULL);
748
376
    if (!stack->auxstack)
749
0
        stack->auxstack = lstackCreate(0);
750
751
376
    pixGetDimensions(pixs, &w, &h, NULL);
752
376
    xmax = w - 1;
753
376
    ymax = h - 1;
754
376
    data = pixGetData(pixs);
755
376
    wpl = pixGetWpl(pixs);
756
376
    line = data + y * wpl;
757
758
        /* Check pix value of seed; must be ON */
759
376
    if (x < 0 || x > xmax || y < 0 || y > ymax || (GET_DATA_BIT(line, x) == 0))
760
0
        return NULL;
761
762
        /* Init stack to seed:
763
         * Must first init b.b. values to prevent valgrind from complaining;
764
         * then init b.b. boundaries correctly to seed.  */
765
376
    minx = miny = 100000;
766
376
    maxx = maxy = 0;
767
376
    pushFillsegBB(stack, x, x, y, 1, ymax, &minx, &maxx, &miny, &maxy);
768
376
    pushFillsegBB(stack, x, x, y + 1, -1, ymax, &minx, &maxx, &miny, &maxy);
769
376
    minx = maxx = x;
770
376
    miny = maxy = y;
771
772
37.8k
    while (lstackGetCount(stack) > 0) {
773
            /* Pop segment off stack and fill a neighboring scan line */
774
37.4k
        popFillseg(stack, &x1, &x2, &y, &dy);
775
37.4k
        line = data + y * wpl;
776
777
            /* A segment of scanline y - dy for x1 <= x <= x2 was
778
             * previously filled.  We now explore adjacent pixels
779
             * in scan line y.  There are three regions: to the
780
             * left of x1, between x1 and x2, and to the right of x2.
781
             * These regions are handled differently.  Leaks are
782
             * possible expansions beyond the previous segment and
783
             * going back in the -dy direction.  These can happen
784
             * for x < x1 and for x > x2.  Any "leak" segments
785
             * are plugged with a push in the -dy (opposite) direction.
786
             * And any segments found anywhere are always extended
787
             * in the +dy direction.  */
788
41.5k
        for (x = x1 - 1; x >= 0 && (GET_DATA_BIT(line, x) == 1); x--)
789
4.08k
            CLEAR_DATA_BIT(line,x);
790
37.4k
        if (x >= x1 - 1)  /* pix at x1 - 1 was off and was not cleared */
791
35.3k
            goto skip;
792
2.09k
        xstart = x + 1;
793
2.09k
        if (xstart < x1)   /* leak on left? */
794
2.09k
            pushFillsegBB(stack, xstart, x1 - 1, y, -dy,
795
2.09k
                          ymax, &minx, &maxx, &miny, &maxy);
796
797
2.09k
        x = x1;
798
18.4k
        do {
799
228k
            for (; x <= xmax && (GET_DATA_BIT(line, x) == 1); x++)
800
209k
                CLEAR_DATA_BIT(line, x);
801
18.4k
            pushFillsegBB(stack, xstart, x - 1, y, dy,
802
18.4k
                          ymax, &minx, &maxx, &miny, &maxy);
803
18.4k
            if (x > x2)   /* leak on right? */
804
16.1k
                pushFillsegBB(stack, x2 + 1, x - 1, y, -dy,
805
16.1k
                              ymax, &minx, &maxx, &miny, &maxy);
806
95.9k
    skip:   for (x++; x <= x2 + 1 &&
807
95.9k
                      x <= xmax &&
808
95.9k
                      (GET_DATA_BIT(line, x) == 0); x++)
809
42.0k
                ;
810
53.8k
            xstart = x;
811
53.8k
        } while (x <= x2 + 1 && x <= xmax);
812
2.09k
    }
813
814
376
    if ((box = boxCreate(minx, miny, maxx - minx + 1, maxy - miny + 1))
815
376
            == NULL)
816
0
        return (BOX *)ERROR_PTR("box not made", __func__, NULL);
817
376
    return box;
818
376
}
819
820
821
/*!
822
 * \brief   pixSeedfill()
823
 *
824
 * \param[in]    pixs           1 bpp
825
 * \param[in]    stack          for holding fillsegs
826
 * \param[in]    x,y            location of seed pixel
827
 * \param[in]    connectivity   4 or 8
828
 * \return  0 if OK, 1 on error
829
 *
830
 * <pre>
831
 * Notes:
832
 *      (1) This removes the component from pixs with a fg pixel at (x,y).
833
 *      (2) See pixSeedfill4() and pixSeedfill8() for details.
834
 * </pre>
835
 */
836
l_ok
837
pixSeedfill(PIX      *pixs,
838
            L_STACK  *stack,
839
            l_int32   x,
840
            l_int32   y,
841
            l_int32   connectivity)
842
0
{
843
0
l_int32  retval;
844
845
0
    if (!pixs || pixGetDepth(pixs) != 1)
846
0
        return ERROR_INT("pixs not defined or not 1 bpp", __func__, 1);
847
0
    if (!stack)
848
0
        return ERROR_INT("stack not defined", __func__, 1);
849
0
    if (connectivity != 4 && connectivity != 8)
850
0
        return ERROR_INT("connectivity not 4 or 8", __func__, 1);
851
852
0
    if (connectivity == 4)
853
0
        retval = pixSeedfill4(pixs, stack, x, y);
854
0
    else  /* connectivity == 8  */
855
0
        retval = pixSeedfill8(pixs, stack, x, y);
856
857
0
    return retval;
858
0
}
859
860
861
/*!
862
 * \brief   pixSeedfill4()
863
 *
864
 * \param[in]    pixs    1 bpp
865
 * \param[in]    stack   for holding fillsegs
866
 * \param[in]    x,y     location of seed pixel
867
 * \return  0 if OK, 1 on error
868
 *
869
 * <pre>
870
 * Notes:
871
 *      (1) This is Paul Heckbert's stack-based 4-cc seedfill algorithm.
872
 *      (2) This operates on the input 1 bpp pix to remove the fg seed
873
 *          pixel, at (x,y), and all pixels that are 4-connected to it.
874
 *          The seed pixel at (x,y) must initially be ON.
875
 *      (3) Reference: see pixSeedFill4BB()
876
 * </pre>
877
 */
878
l_ok
879
pixSeedfill4(PIX      *pixs,
880
             L_STACK  *stack,
881
             l_int32   x,
882
             l_int32   y)
883
0
{
884
0
l_int32    w, h, xstart, wpl, x1, x2, dy;
885
0
l_int32    xmax, ymax;
886
0
l_uint32  *data, *line;
887
888
0
    if (!pixs || pixGetDepth(pixs) != 1)
889
0
        return ERROR_INT("pixs not defined or not 1 bpp", __func__, 1);
890
0
    if (!stack)
891
0
        return ERROR_INT("stack not defined", __func__, 1);
892
0
    if (!stack->auxstack)
893
0
        stack->auxstack = lstackCreate(0);
894
895
0
    pixGetDimensions(pixs, &w, &h, NULL);
896
0
    xmax = w - 1;
897
0
    ymax = h - 1;
898
0
    data = pixGetData(pixs);
899
0
    wpl = pixGetWpl(pixs);
900
0
    line = data + y * wpl;
901
902
        /* Check pix value of seed; must be within the image and ON */
903
0
    if (x < 0 || x > xmax || y < 0 || y > ymax || (GET_DATA_BIT(line, x) == 0))
904
0
        return 0;
905
906
        /* Init stack to seed */
907
0
    pushFillseg(stack, x, x, y, 1, ymax);
908
0
    pushFillseg(stack, x, x, y + 1, -1, ymax);
909
910
0
    while (lstackGetCount(stack) > 0) {
911
            /* Pop segment off stack and fill a neighboring scan line */
912
0
        popFillseg(stack, &x1, &x2, &y, &dy);
913
0
        line = data + y * wpl;
914
915
            /* A segment of scanline y - dy for x1 <= x <= x2 was
916
             * previously filled.  We now explore adjacent pixels
917
             * in scan line y.  There are three regions: to the
918
             * left of x1 - 1, between x1 and x2, and to the right of x2.
919
             * These regions are handled differently.  Leaks are
920
             * possible expansions beyond the previous segment and
921
             * going back in the -dy direction.  These can happen
922
             * for x < x1 - 1 and for x > x2 + 1.  Any "leak" segments
923
             * are plugged with a push in the -dy (opposite) direction.
924
             * And any segments found anywhere are always extended
925
             * in the +dy direction.  */
926
0
        for (x = x1; x >= 0 && (GET_DATA_BIT(line, x) == 1); x--)
927
0
            CLEAR_DATA_BIT(line,x);
928
0
        if (x >= x1)  /* pix at x1 was off and was not cleared */
929
0
            goto skip;
930
0
        xstart = x + 1;
931
0
        if (xstart < x1 - 1)   /* leak on left? */
932
0
            pushFillseg(stack, xstart, x1 - 1, y, -dy, ymax);
933
934
0
        x = x1 + 1;
935
0
        do {
936
0
            for (; x <= xmax && (GET_DATA_BIT(line, x) == 1); x++)
937
0
                CLEAR_DATA_BIT(line, x);
938
0
            pushFillseg(stack, xstart, x - 1, y, dy, ymax);
939
0
            if (x > x2 + 1)   /* leak on right? */
940
0
                pushFillseg(stack, x2 + 1, x - 1, y, -dy, ymax);
941
0
    skip:   for (x++; x <= x2 &&
942
0
                      x <= xmax &&
943
0
                      (GET_DATA_BIT(line, x) == 0); x++)
944
0
                ;
945
0
            xstart = x;
946
0
        } while (x <= x2 && x <= xmax);
947
0
    }
948
949
0
    return 0;
950
0
}
951
952
953
/*!
954
 * \brief   pixSeedfill8()
955
 *
956
 * \param[in]    pixs    1 bpp
957
 * \param[in]    stack   for holding fillsegs
958
 * \param[in]    x,y     location of seed pixel
959
 * \return  0 if OK, 1 on error
960
 *
961
 * <pre>
962
 * Notes:
963
 *      (1) This is Paul Heckbert's stack-based 8-cc seedfill algorithm.
964
 *      (2) This operates on the input 1 bpp pix to remove the fg seed
965
 *          pixel, at (x,y), and all pixels that are 8-connected to it.
966
 *          The seed pixel at (x,y) must initially be ON.
967
 *      (3) Reference: see pixSeedFill8BB()
968
 * </pre>
969
 */
970
l_ok
971
pixSeedfill8(PIX      *pixs,
972
             L_STACK  *stack,
973
             l_int32   x,
974
             l_int32   y)
975
0
{
976
0
l_int32    w, h, xstart, wpl, x1, x2, dy;
977
0
l_int32    xmax, ymax;
978
0
l_uint32  *data, *line;
979
980
0
    if (!pixs || pixGetDepth(pixs) != 1)
981
0
        return ERROR_INT("pixs not defined or not 1 bpp", __func__, 1);
982
0
    if (!stack)
983
0
        return ERROR_INT("stack not defined", __func__, 1);
984
0
    if (!stack->auxstack)
985
0
        stack->auxstack = lstackCreate(0);
986
987
0
    pixGetDimensions(pixs, &w, &h, NULL);
988
0
    xmax = w - 1;
989
0
    ymax = h - 1;
990
0
    data = pixGetData(pixs);
991
0
    wpl = pixGetWpl(pixs);
992
0
    line = data + y * wpl;
993
994
        /* Check pix value of seed; must be ON */
995
0
    if (x < 0 || x > xmax || y < 0 || y > ymax || (GET_DATA_BIT(line, x) == 0))
996
0
        return 0;
997
998
        /* Init stack to seed */
999
0
    pushFillseg(stack, x, x, y, 1, ymax);
1000
0
    pushFillseg(stack, x, x, y + 1, -1, ymax);
1001
1002
0
    while (lstackGetCount(stack) > 0) {
1003
            /* Pop segment off stack and fill a neighboring scan line */
1004
0
        popFillseg(stack, &x1, &x2, &y, &dy);
1005
0
        line = data + y * wpl;
1006
1007
            /* A segment of scanline y - dy for x1 <= x <= x2 was
1008
             * previously filled.  We now explore adjacent pixels
1009
             * in scan line y.  There are three regions: to the
1010
             * left of x1, between x1 and x2, and to the right of x2.
1011
             * These regions are handled differently.  Leaks are
1012
             * possible expansions beyond the previous segment and
1013
             * going back in the -dy direction.  These can happen
1014
             * for x < x1 and for x > x2.  Any "leak" segments
1015
             * are plugged with a push in the -dy (opposite) direction.
1016
             * And any segments found anywhere are always extended
1017
             * in the +dy direction.  */
1018
0
        for (x = x1 - 1; x >= 0 && (GET_DATA_BIT(line, x) == 1); x--)
1019
0
            CLEAR_DATA_BIT(line,x);
1020
0
        if (x >= x1 - 1)  /* pix at x1 - 1 was off and was not cleared */
1021
0
            goto skip;
1022
0
        xstart = x + 1;
1023
0
        if (xstart < x1)   /* leak on left? */
1024
0
            pushFillseg(stack, xstart, x1 - 1, y, -dy, ymax);
1025
1026
0
        x = x1;
1027
0
        do {
1028
0
            for (; x <= xmax && (GET_DATA_BIT(line, x) == 1); x++)
1029
0
                CLEAR_DATA_BIT(line, x);
1030
0
            pushFillseg(stack, xstart, x - 1, y, dy, ymax);
1031
0
            if (x > x2)   /* leak on right? */
1032
0
                pushFillseg(stack, x2 + 1, x - 1, y, -dy, ymax);
1033
0
    skip:   for (x++; x <= x2 + 1 &&
1034
0
                      x <= xmax &&
1035
0
                      (GET_DATA_BIT(line, x) == 0); x++)
1036
0
                ;
1037
0
            xstart = x;
1038
0
        } while (x <= x2 + 1 && x <= xmax);
1039
0
    }
1040
1041
0
    return 0;
1042
0
}
1043
1044
1045
1046
/*-----------------------------------------------------------------------*
1047
 *          Static stack helper functions: push and pop fillsegs         *
1048
 *-----------------------------------------------------------------------*/
1049
/*!
1050
 * \brief   pushFillsegBB()
1051
 *
1052
 * \param[in]    stack
1053
 * \param[in]    xleft, xright
1054
 * \param[in]    y
1055
 * \param[in]    dy
1056
 * \param[in]    ymax
1057
 * \param[out]   pminx            minimum x
1058
 * \param[out]   pmaxx            maximum x
1059
 * \param[out]   pminy            minimum y
1060
 * \param[out]   pmaxy            maximum y
1061
 * \return  void
1062
 *
1063
 * <pre>
1064
 * Notes:
1065
 *      (1) This adds a line segment to the stack, and returns its size.
1066
 *      (2) The auxiliary stack is used as a storage area to recycle
1067
 *          fillsegs that are no longer in use.  We only calloc new
1068
 *          fillsegs if the auxiliary stack is empty.
1069
 * </pre>
1070
 */
1071
static void
1072
pushFillsegBB(L_STACK  *stack,
1073
              l_int32   xleft,
1074
              l_int32   xright,
1075
              l_int32   y,
1076
              l_int32   dy,
1077
              l_int32   ymax,
1078
              l_int32  *pminx,
1079
              l_int32  *pmaxx,
1080
              l_int32  *pminy,
1081
              l_int32  *pmaxy)
1082
37.5k
{
1083
37.5k
FILLSEG  *fseg;
1084
37.5k
L_STACK  *auxstack;
1085
1086
37.5k
    if (!stack) {
1087
0
        L_ERROR("stack not defined\n", __func__);
1088
0
        return;
1089
0
    }
1090
1091
37.5k
    *pminx = L_MIN(*pminx, xleft);
1092
37.5k
    *pmaxx = L_MAX(*pmaxx, xright);
1093
37.5k
    *pminy = L_MIN(*pminy, y);
1094
37.5k
    *pmaxy = L_MAX(*pmaxy, y);
1095
1096
37.5k
    if (y + dy >= 0 && y + dy <= ymax) {
1097
37.4k
        if ((auxstack = stack->auxstack) == NULL) {
1098
0
            L_ERROR("auxstack not defined\n", __func__);
1099
0
            return;
1100
0
        }
1101
1102
            /* Get a fillseg to use */
1103
37.4k
        if (lstackGetCount(auxstack) > 0)
1104
37.2k
            fseg = (FILLSEG *)lstackRemove(auxstack);
1105
276
        else
1106
276
            fseg = (FILLSEG *)LEPT_CALLOC(1, sizeof(FILLSEG));
1107
37.4k
        fseg->xleft = xleft;
1108
37.4k
        fseg->xright = xright;
1109
37.4k
        fseg->y = y;
1110
37.4k
        fseg->dy = dy;
1111
37.4k
        lstackAdd(stack, fseg);
1112
37.4k
    }
1113
37.5k
}
1114
1115
1116
/*!
1117
 * \brief   pushFillseg()
1118
 *
1119
 * \param[in]    stack
1120
 * \param[in]    xleft, xright
1121
 * \param[in]    y
1122
 * \param[in]    dy
1123
 * \param[in]    ymax
1124
 * \return  void
1125
 *
1126
 * <pre>
1127
 * Notes:
1128
 *      (1) This adds a line segment to the stack.
1129
 *      (2) The auxiliary stack is used as a storage area to recycle
1130
 *          fillsegs that are no longer in use.  We only calloc new
1131
 *          fillsegs if the auxiliary stack is empty.
1132
 * </pre>
1133
 */
1134
static void
1135
pushFillseg(L_STACK  *stack,
1136
            l_int32   xleft,
1137
            l_int32   xright,
1138
            l_int32   y,
1139
            l_int32   dy,
1140
            l_int32   ymax)
1141
0
{
1142
0
FILLSEG  *fseg;
1143
0
L_STACK  *auxstack;
1144
1145
0
    if (!stack) {
1146
0
        L_ERROR("stack not defined\n", __func__);
1147
0
        return;
1148
0
    }
1149
1150
0
    if (y + dy >= 0 && y + dy <= ymax) {
1151
0
        if ((auxstack = stack->auxstack) == NULL) {
1152
0
            L_ERROR("auxstack not defined\n", __func__);
1153
0
            return;
1154
0
        }
1155
1156
            /* Get a fillseg to use */
1157
0
        if (lstackGetCount(auxstack) > 0)
1158
0
            fseg = (FILLSEG *)lstackRemove(auxstack);
1159
0
        else
1160
0
            fseg = (FILLSEG *)LEPT_CALLOC(1, sizeof(FILLSEG));
1161
0
        fseg->xleft = xleft;
1162
0
        fseg->xright = xright;
1163
0
        fseg->y = y;
1164
0
        fseg->dy = dy;
1165
0
        lstackAdd(stack, fseg);
1166
0
    }
1167
0
}
1168
1169
1170
/*!
1171
 * \brief   popFillseg()
1172
 *
1173
 * \param[in]    stack
1174
 * \param[out]   pxleft    left x
1175
 * \param[out]   pxright   right x
1176
 * \param[out]   py        y coordinate
1177
 * \param[out]   pdy       delta y
1178
 * \return  void
1179
 *
1180
 * <pre>
1181
 * Notes:
1182
 *      (1) This removes a line segment from the stack, and returns its size.
1183
 *      (2) The surplussed fillseg is placed on the auxiliary stack
1184
 *          for future use.
1185
 * </pre>
1186
 */
1187
static void
1188
popFillseg(L_STACK  *stack,
1189
           l_int32  *pxleft,
1190
           l_int32  *pxright,
1191
           l_int32  *py,
1192
           l_int32  *pdy)
1193
37.4k
{
1194
37.4k
FILLSEG  *fseg;
1195
37.4k
L_STACK  *auxstack;
1196
1197
37.4k
    if (!stack) {
1198
0
        L_ERROR("stack not defined\n", __func__);
1199
0
        return;
1200
0
    }
1201
37.4k
    if ((auxstack = stack->auxstack) == NULL) {
1202
0
        L_ERROR("auxstack not defined\n", __func__);
1203
0
        return;
1204
0
    }
1205
1206
37.4k
    if ((fseg = (FILLSEG *)lstackRemove(stack)) == NULL)
1207
0
        return;
1208
1209
37.4k
    *pxleft = fseg->xleft;
1210
37.4k
    *pxright = fseg->xright;
1211
37.4k
    *py = fseg->y + fseg->dy;  /* this now points to the new line */
1212
37.4k
    *pdy = fseg->dy;
1213
1214
        /* Save it for re-use */
1215
37.4k
    lstackAdd(auxstack, fseg);
1216
37.4k
}