Leptonica 1.82.0
Image processing and image analysis suite
ccbord.c
Go to the documentation of this file.
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
250#ifdef HAVE_CONFIG_H
251#include <config_auto.h>
252#endif /* HAVE_CONFIG_H */
253
254#include <string.h>
255#include "allheaders.h"
256
257static const l_int32 INITIAL_PTR_ARRAYSIZE = 20; /* n'import quoi */
258
259 /* In ccbaGenerateSinglePath(): don't save holes
260 * in c.c. with ridiculously many small holes */
261static const l_int32 NMAX_HOLES = 150;
262
263 /* Tables used to trace the border.
264 * - The 8 pixel positions of neighbors Q are labeled clockwise
265 * starting from the west:
266 * 1 2 3
267 * 0 P 4
268 * 7 6 5
269 * where the labels are the index offset [0, ... 7] of Q relative to P.
270 * - xpostab[] and ypostab[] give the actual x and y pixel offsets
271 * of Q relative to P, indexed by the index offset.
272 * - qpostab[pos] gives the new index offset of Q relative to P, at
273 * the time that a new P has been chosen to be in index offset
274 * position 'pos' relative to the previous P. The relation
275 * between P and Q is always 4-connected. */
276static const l_int32 xpostab[] = {-1, -1, 0, 1, 1, 1, 0, -1};
277static const l_int32 ypostab[] = {0, -1, -1, -1, 0, 1, 1, 1};
278static const l_int32 qpostab[] = {6, 6, 0, 0, 2, 2, 4, 4};
279
280 /* Static functions */
281static l_int32 ccbaExtendArray(CCBORDA *ccba);
282static CCBORD *pixGetCCBorders(PIX *pixs, BOX *box);
283static PTA *pixGetOuterBorderPta(PIX *pixs, BOX *box);
284static l_ok pixGetHoleBorder(CCBORD *ccb, PIX *pixs, BOX *box,
285 l_int32 xs, l_int32 ys);
286static l_int32 findNextBorderPixel(l_int32 w, l_int32 h, l_uint32 *data,
287 l_int32 wpl, l_int32 px, l_int32 py,
288 l_int32 *pqpos, l_int32 *pnpx,
289 l_int32 *pnpy);
290static void locateOutsideSeedPixel(l_int32 fpx, l_int32 fpy, l_int32 spx,
291 l_int32 spy, l_int32 *pxs, l_int32 *pys);
292
293#ifndef NO_CONSOLE_IO
294#define DEBUG_PRINT 0
295#endif /* NO CONSOLE_IO */
296
297
298/*---------------------------------------------------------------------*
299 * ccba and ccb creation and destruction *
300 *---------------------------------------------------------------------*/
308CCBORDA *
310 l_int32 n)
311{
312CCBORDA *ccba;
313
314 PROCNAME("ccbaCreate");
315
316 if (n <= 0)
317 n = INITIAL_PTR_ARRAYSIZE;
318
319 ccba = (CCBORDA *)LEPT_CALLOC(1, sizeof(CCBORDA));
320 if (pixs) {
321 ccba->pix = pixClone(pixs);
322 ccba->w = pixGetWidth(pixs);
323 ccba->h = pixGetHeight(pixs);
324 }
325 ccba->n = 0;
326 ccba->nalloc = n;
327 if ((ccba->ccb = (CCBORD **)LEPT_CALLOC(n, sizeof(CCBORD *))) == NULL) {
328 ccbaDestroy(&ccba);
329 return (CCBORDA *)ERROR_PTR("ccba ptrs not made", procName, NULL);
330 }
331 return ccba;
332}
333
334
341void
343{
344l_int32 i;
345CCBORDA *ccba;
346
347 PROCNAME("ccbaDestroy");
348
349 if (pccba == NULL) {
350 L_WARNING("ptr address is NULL!\n", procName);
351 return;
352 }
353
354 if ((ccba = *pccba) == NULL)
355 return;
356
357 pixDestroy(&ccba->pix);
358 for (i = 0; i < ccba->n; i++)
359 ccbDestroy(&ccba->ccb[i]);
360 LEPT_FREE(ccba->ccb);
361 LEPT_FREE(ccba);
362 *pccba = NULL;
363}
364
365
372CCBORD *
374{
375BOXA *boxa;
376CCBORD *ccb;
377PTA *start;
378PTAA *local;
379
380 PROCNAME("ccbCreate");
381
382 if (pixs && pixGetDepth(pixs) != 1) /* pixs can be null */
383 return (CCBORD *)ERROR_PTR("pixs defined and not 1bpp", procName, NULL);
384
385 ccb = (CCBORD *)LEPT_CALLOC(1, sizeof(CCBORD));
386 ccb->refcount++;
387 if (pixs)
388 ccb->pix = pixClone(pixs);
389 boxa = boxaCreate(1);
390 ccb->boxa = boxa;
391 start = ptaCreate(1);
392 ccb->start = start;
393 local = ptaaCreate(1);
394 ccb->local = local;
395 return ccb;
396}
397
398
405void
407{
408CCBORD *ccb;
409
410 PROCNAME("ccbDestroy");
411
412 if (pccb == NULL) {
413 L_WARNING("ptr address is NULL!\n", procName);
414 return;
415 }
416
417 if ((ccb = *pccb) == NULL)
418 return;
419
420 ccb->refcount--;
421 if (ccb->refcount == 0) {
422 if (ccb->pix)
423 pixDestroy(&ccb->pix);
424 if (ccb->boxa)
425 boxaDestroy(&ccb->boxa);
426 if (ccb->start)
427 ptaDestroy(&ccb->start);
428 if (ccb->local)
429 ptaaDestroy(&ccb->local);
430 if (ccb->global)
431 ptaaDestroy(&ccb->global);
432 if (ccb->step)
433 numaaDestroy(&ccb->step);
434 if (ccb->splocal)
435 ptaDestroy(&ccb->splocal);
436 if (ccb->spglobal)
437 ptaDestroy(&ccb->spglobal);
438 LEPT_FREE(ccb);
439 *pccb = NULL;
440 }
441}
442
443
444/*---------------------------------------------------------------------*
445 * ccba addition *
446 *---------------------------------------------------------------------*/
454l_ok
456 CCBORD *ccb)
457{
458l_int32 n;
459
460 PROCNAME("ccbaAddCcb");
461
462 if (!ccba)
463 return ERROR_INT("ccba not defined", procName, 1);
464 if (!ccb)
465 return ERROR_INT("ccb not defined", procName, 1);
466
467 n = ccbaGetCount(ccba);
468 if (n >= ccba->nalloc) {
469 if (ccbaExtendArray(ccba))
470 return ERROR_INT("extension failed", procName, 1);
471 }
472 ccba->ccb[n] = ccb;
473 ccba->n++;
474 return 0;
475}
476
477
484static l_int32
486{
487 PROCNAME("ccbaExtendArray");
488
489 if (!ccba)
490 return ERROR_INT("ccba not defined", procName, 1);
491
492 if ((ccba->ccb = (CCBORD **)reallocNew((void **)&ccba->ccb,
493 sizeof(CCBORD *) * ccba->nalloc,
494 2 * sizeof(CCBORD *) * ccba->nalloc)) == NULL)
495 return ERROR_INT("new ptr array not returned", procName, 1);
496
497 ccba->nalloc = 2 * ccba->nalloc;
498 return 0;
499}
500
501
502
503/*---------------------------------------------------------------------*
504 * ccba accessors *
505 *---------------------------------------------------------------------*/
512l_int32
514{
515
516 PROCNAME("ccbaGetCount");
517
518 if (!ccba)
519 return ERROR_INT("ccba not defined", procName, 0);
520
521 return ccba->n;
522}
523
524
537CCBORD *
539 l_int32 index)
540{
541CCBORD *ccb;
542
543 PROCNAME("ccbaGetCcb");
544
545 if (!ccba)
546 return (CCBORD *)ERROR_PTR("ccba not defined", procName, NULL);
547 if (index < 0 || index >= ccba->n)
548 return (CCBORD *)ERROR_PTR("index out of bounds", procName, NULL);
549
550 ccb = ccba->ccb[index];
551 ccb->refcount++;
552 return ccb;
553}
554
555
556
557/*---------------------------------------------------------------------*
558 * Top-level border-finding routines *
559 *---------------------------------------------------------------------*/
566CCBORDA *
568{
569l_int32 n, i;
570BOX *box;
571BOXA *boxa;
572CCBORDA *ccba;
573CCBORD *ccb;
574PIX *pix;
575PIXA *pixa;
576
577 PROCNAME("pixGetAllCCBorders");
578
579 if (!pixs)
580 return (CCBORDA *)ERROR_PTR("pixs not defined", procName, NULL);
581 if (pixGetDepth(pixs) != 1)
582 return (CCBORDA *)ERROR_PTR("pixs not binary", procName, NULL);
583
584 if ((boxa = pixConnComp(pixs, &pixa, 8)) == NULL)
585 return (CCBORDA *)ERROR_PTR("boxa not made", procName, NULL);
586 n = boxaGetCount(boxa);
587
588 if ((ccba = ccbaCreate(pixs, n)) == NULL) {
589 boxaDestroy(&boxa);
590 pixaDestroy(&pixa);
591 return (CCBORDA *)ERROR_PTR("ccba not made", procName, NULL);
592 }
593 for (i = 0; i < n; i++) {
594 if ((pix = pixaGetPix(pixa, i, L_CLONE)) == NULL) {
595 ccbaDestroy(&ccba);
596 pixaDestroy(&pixa);
597 boxaDestroy(&boxa);
598 return (CCBORDA *)ERROR_PTR("pix not found", procName, NULL);
599 }
600 if ((box = pixaGetBox(pixa, i, L_CLONE)) == NULL) {
601 ccbaDestroy(&ccba);
602 pixaDestroy(&pixa);
603 boxaDestroy(&boxa);
604 pixDestroy(&pix);
605 return (CCBORDA *)ERROR_PTR("box not found", procName, NULL);
606 }
607 ccb = pixGetCCBorders(pix, box);
608 pixDestroy(&pix);
609 boxDestroy(&box);
610 if (!ccb) {
611 ccbaDestroy(&ccba);
612 pixaDestroy(&pixa);
613 boxaDestroy(&boxa);
614 return (CCBORDA *)ERROR_PTR("ccb not made", procName, NULL);
615 }
616/* ptaWriteStream(stderr, ccb->local, 1); */
617 ccbaAddCcb(ccba, ccb);
618 }
619
620 boxaDestroy(&boxa);
621 pixaDestroy(&pixa);
622 return ccba;
623}
624
625
652static CCBORD *
654 BOX *box)
655{
656l_int32 allzero, i, x, xh, w, nh;
657l_int32 xs, ys; /* starting hole border pixel, relative in pixs */
658l_uint32 val;
659BOX *boxt, *boxe;
660BOXA *boxa;
661CCBORD *ccb;
662PIX *pixh; /* for hole components */
663PIX *pixt;
664PIXA *pixa;
665
666 PROCNAME("pixGetCCBorders");
667
668 if (!pixs)
669 return (CCBORD *)ERROR_PTR("pixs not defined", procName, NULL);
670 if (!box)
671 return (CCBORD *)ERROR_PTR("box not defined", procName, NULL);
672 if (pixGetDepth(pixs) != 1)
673 return (CCBORD *)ERROR_PTR("pixs not binary", procName, NULL);
674
675 pixZero(pixs, &allzero);
676 if (allzero)
677 return (CCBORD *)ERROR_PTR("pixs all 0", procName, NULL);
678
679 if ((ccb = ccbCreate(pixs)) == NULL)
680 return (CCBORD *)ERROR_PTR("ccb not made", procName, NULL);
681
682 /* Get the exterior border */
683 pixGetOuterBorder(ccb, pixs, box);
684
685 /* Find the holes, if any */
686 if ((pixh = pixHolesByFilling(pixs, 4)) == NULL) {
687 ccbDestroy(&ccb);
688 return (CCBORD *)ERROR_PTR("pixh not made", procName, NULL);
689 }
690 pixZero(pixh, &allzero);
691 if (allzero) { /* no holes */
692 pixDestroy(&pixh);
693 return ccb;
694 }
695
696 /* Get c.c. and locations of the holes */
697 if ((boxa = pixConnComp(pixh, &pixa, 4)) == NULL) {
698 ccbDestroy(&ccb);
699 pixDestroy(&pixh);
700 return (CCBORD *)ERROR_PTR("boxa not made", procName, NULL);
701 }
702 nh = boxaGetCount(boxa);
703/* lept_stderr("%d holes\n", nh); */
704
705 /* For each hole, find an interior pixel within the hole,
706 * then march to the right and stop at the first border
707 * pixel. Save the bounding box of the border, which
708 * is 1 pixel bigger on each side than the bounding box
709 * of the hole itself. Note that we use a pix of the
710 * c.c. of the hole itself to be sure that we start
711 * with a pixel in the hole of the proper component.
712 * If we did everything from the parent component, it is
713 * possible to start in a different hole that is within
714 * the b.b. of a larger hole. */
715 w = pixGetWidth(pixs);
716 for (i = 0; i < nh; i++) {
717 boxt = boxaGetBox(boxa, i, L_CLONE);
718 pixt = pixaGetPix(pixa, i, L_CLONE);
719 ys = boxt->y; /* there must be a hole pixel on this raster line */
720 for (x = 0; x < boxt->w; x++) { /* look for (fg) hole pixel */
721 pixGetPixel(pixt, x, 0, &val);
722 if (val == 1) {
723 xh = x;
724 break;
725 }
726 }
727 if (x == boxt->w) {
728 L_WARNING("no hole pixel found!\n", procName);
729 continue;
730 }
731 for (x = xh + boxt->x; x < w; x++) { /* look for (fg) border pixel */
732 pixGetPixel(pixs, x, ys, &val);
733 if (val == 1) {
734 xs = x;
735 break;
736 }
737 }
738 boxe = boxCreate(boxt->x - 1, boxt->y - 1, boxt->w + 2, boxt->h + 2);
739#if DEBUG_PRINT
740 boxPrintStreamInfo(stderr, box);
741 boxPrintStreamInfo(stderr, boxe);
742 lept_stderr("xs = %d, ys = %d\n", xs, ys);
743#endif /* DEBUG_PRINT */
744 pixGetHoleBorder(ccb, pixs, boxe, xs, ys);
745 boxDestroy(&boxt);
746 boxDestroy(&boxe);
747 pixDestroy(&pixt);
748 }
749
750 boxaDestroy(&boxa);
751 pixaDestroy(&pixa);
752 pixDestroy(&pixh);
753 return ccb;
754}
755
756
763PTAA *
765{
766l_int32 i, n;
767BOX *box;
768BOXA *boxa;
769PIX *pix;
770PIXA *pixa;
771PTA *pta;
772PTAA *ptaa;
773
774 PROCNAME("pixGetOuterBordersPtaa");
775
776 if (!pixs)
777 return (PTAA *)ERROR_PTR("pixs not defined", procName, NULL);
778 if (pixGetDepth(pixs) != 1)
779 return (PTAA *)ERROR_PTR("pixs not binary", procName, NULL);
780
781 boxa = pixConnComp(pixs, &pixa, 8);
782 n = boxaGetCount(boxa);
783 if (n == 0) {
784 boxaDestroy(&boxa);
785 pixaDestroy(&pixa);
786 return (PTAA *)ERROR_PTR("pixs empty", procName, NULL);
787 }
788
789 ptaa = ptaaCreate(n);
790 for (i = 0; i < n; i++) {
791 box = boxaGetBox(boxa, i, L_CLONE);
792 pix = pixaGetPix(pixa, i, L_CLONE);
793 pta = pixGetOuterBorderPta(pix, box);
794 if (pta)
795 ptaaAddPta(ptaa, pta, L_INSERT);
796 boxDestroy(&box);
797 pixDestroy(&pix);
798 }
799
800 pixaDestroy(&pixa);
801 boxaDestroy(&boxa);
802 return ptaa;
803}
804
805
823static PTA *
825 BOX *box)
826{
827l_int32 allzero, x, y;
828BOX *boxt;
829CCBORD *ccb;
830PTA *ptaloc, *ptad;
831
832 PROCNAME("pixGetOuterBorderPta");
833
834 if (!pixs)
835 return (PTA *)ERROR_PTR("pixs not defined", procName, NULL);
836 if (pixGetDepth(pixs) != 1)
837 return (PTA *)ERROR_PTR("pixs not binary", procName, NULL);
838
839 pixZero(pixs, &allzero);
840 if (allzero)
841 return (PTA *)ERROR_PTR("pixs all 0", procName, NULL);
842
843 if ((ccb = ccbCreate(pixs)) == NULL)
844 return (PTA *)ERROR_PTR("ccb not made", procName, NULL);
845 if (!box)
846 boxt = boxCreate(0, 0, pixGetWidth(pixs), pixGetHeight(pixs));
847 else
848 boxt = boxClone(box);
849
850 /* Get the exterior border in local coords */
851 pixGetOuterBorder(ccb, pixs, boxt);
852 if ((ptaloc = ptaaGetPta(ccb->local, 0, L_CLONE)) == NULL) {
853 ccbDestroy(&ccb);
854 boxDestroy(&boxt);
855 return (PTA *)ERROR_PTR("ptaloc not made", procName, NULL);
856 }
857
858 /* Transform to global coordinates, if they are given */
859 if (box) {
860 boxGetGeometry(box, &x, &y, NULL, NULL);
861 ptad = ptaTransform(ptaloc, x, y, 1.0, 1.0);
862 } else {
863 ptad = ptaClone(ptaloc);
864 }
865
866 ptaDestroy(&ptaloc);
867 boxDestroy(&boxt);
868 ccbDestroy(&ccb);
869 return ptad;
870}
871
872
873/*---------------------------------------------------------------------*
874 * Lower-level border-finding routines *
875 *---------------------------------------------------------------------*/
896l_ok
898 PIX *pixs,
899 BOX *box)
900{
901l_int32 fpx, fpy, spx, spy, qpos;
902l_int32 px, py, npx, npy;
903l_int32 w, h, wpl;
904l_uint32 *data;
905PTA *pta;
906PIX *pixb; /* with 1 pixel border */
907
908 PROCNAME("pixGetOuterBorder");
909
910 if (!ccb)
911 return ERROR_INT("ccb not defined", procName, 1);
912 if (!pixs)
913 return ERROR_INT("pixs not defined", procName, 1);
914 if (!box)
915 return ERROR_INT("box not defined", procName, 1);
916
917 /* Add 1-pixel border all around, and find start pixel */
918 if ((pixb = pixAddBorder(pixs, 1, 0)) == NULL)
919 return ERROR_INT("pixs not made", procName, 1);
920 if (!nextOnPixelInRaster(pixb, 1, 1, &px, &py)) {
921 pixDestroy(&pixb);
922 return ERROR_INT("no start pixel found", procName, 1);
923 }
924 qpos = 0; /* relative to p */
925 fpx = px; /* save location of first pixel on border */
926 fpy = py;
927
928 /* Save box and start pixel in relative coords */
929 boxaAddBox(ccb->boxa, box, L_COPY);
930 ptaAddPt(ccb->start, px - 1, py - 1);
931
932 pta = ptaCreate(0);
933 ptaaAddPta(ccb->local, pta, L_INSERT);
934 ptaAddPt(pta, px - 1, py - 1); /* initial point */
935 pixGetDimensions(pixb, &w, &h, NULL);
936 data = pixGetData(pixb);
937 wpl = pixGetWpl(pixb);
938
939 /* Get the second point; if there is none, return */
940 if (findNextBorderPixel(w, h, data, wpl, px, py, &qpos, &npx, &npy)) {
941 pixDestroy(&pixb);
942 return 0;
943 }
944
945 spx = npx; /* save location of second pixel on border */
946 spy = npy;
947 ptaAddPt(pta, npx - 1, npy - 1); /* second point */
948 px = npx;
949 py = npy;
950
951 while (1) {
952 findNextBorderPixel(w, h, data, wpl, px, py, &qpos, &npx, &npy);
953 if (px == fpx && py == fpy && npx == spx && npy == spy)
954 break;
955 ptaAddPt(pta, npx - 1, npy - 1);
956 px = npx;
957 py = npy;
958 }
959
960 pixDestroy(&pixb);
961 return 0;
962}
963
964
984static l_ok
986 PIX *pixs,
987 BOX *box,
988 l_int32 xs,
989 l_int32 ys)
990{
991l_int32 fpx, fpy, spx, spy, qpos;
992l_int32 px, py, npx, npy;
993l_int32 w, h, wpl;
994l_uint32 *data;
995PTA *pta;
996
997 PROCNAME("pixGetHoleBorder");
998
999 if (!ccb)
1000 return ERROR_INT("ccb not defined", procName, 1);
1001 if (!pixs)
1002 return ERROR_INT("pixs not defined", procName, 1);
1003 if (!box)
1004 return ERROR_INT("box not defined", procName, 1);
1005
1006 /* Add border and find start pixel */
1007 qpos = 0; /* orientation of Q relative to P */
1008 fpx = xs; /* save location of first pixel on border */
1009 fpy = ys;
1010
1011 /* Save box and start pixel */
1012 boxaAddBox(ccb->boxa, box, L_COPY);
1013 ptaAddPt(ccb->start, xs, ys);
1014
1015 pta = ptaCreate(0);
1016 ptaaAddPta(ccb->local, pta, L_INSERT);
1017 ptaAddPt(pta, xs, ys); /* initial pixel */
1018
1019 w = pixGetWidth(pixs);
1020 h = pixGetHeight(pixs);
1021 data = pixGetData(pixs);
1022 wpl = pixGetWpl(pixs);
1023
1024 /* Get the second point; there should always be at least 4 pts
1025 * in a minimal hole border! */
1026 if (findNextBorderPixel(w, h, data, wpl, xs, ys, &qpos, &npx, &npy))
1027 return ERROR_INT("isolated hole border point!", procName, 1);
1028
1029 spx = npx; /* save location of second pixel on border */
1030 spy = npy;
1031 ptaAddPt(pta, npx, npy); /* second pixel */
1032 px = npx;
1033 py = npy;
1034
1035 while (1) {
1036 findNextBorderPixel(w, h, data, wpl, px, py, &qpos, &npx, &npy);
1037 if (px == fpx && py == fpy && npx == spx && npy == spy)
1038 break;
1039 ptaAddPt(pta, npx, npy);
1040 px = npx;
1041 py = npy;
1042 }
1043
1044 return 0;
1045}
1046
1047
1066static l_int32
1068 l_int32 h,
1069 l_uint32 *data,
1070 l_int32 wpl,
1071 l_int32 px,
1072 l_int32 py,
1073 l_int32 *pqpos,
1074 l_int32 *pnpx,
1075 l_int32 *pnpy)
1076{
1077l_int32 qpos, i, pos, npx, npy, val;
1078l_uint32 *line;
1079
1080 qpos = *pqpos;
1081 for (i = 1; i < 8; i++) {
1082 pos = (qpos + i) % 8;
1083 npx = px + xpostab[pos];
1084 npy = py + ypostab[pos];
1085 if (npx < 0 || npx >= w || npy < 0 || npy >= h)
1086 continue;
1087 line = data + npy * wpl;
1088 val = GET_DATA_BIT(line, npx);
1089 if (val) {
1090 *pnpx = npx;
1091 *pnpy = npy;
1092 *pqpos = qpostab[pos];
1093 return 0;
1094 }
1095 }
1096
1097 return 1;
1098}
1099
1100
1119static void
1121 l_int32 fpy,
1122 l_int32 spx,
1123 l_int32 spy,
1124 l_int32 *pxs,
1125 l_int32 *pys)
1126{
1127l_int32 dx, dy;
1128
1129 dx = spx - fpx;
1130 dy = spy - fpy;
1131
1132 if (dx * dy == 1) {
1133 *pxs = fpx + dx;
1134 *pys = fpy;
1135 } else if (dx * dy == -1) {
1136 *pxs = fpx;
1137 *pys = fpy + dy;
1138 } else if (dx == 0) {
1139 *pxs = fpx + dy;
1140 *pys = fpy + dy;
1141 } else /* dy == 0 */ {
1142 *pxs = fpx + dx;
1143 *pys = fpy - dx;
1144 }
1145
1146 return;
1147}
1148
1149
1150
1151/*---------------------------------------------------------------------*
1152 * Border conversions *
1153 *---------------------------------------------------------------------*/
1167l_ok
1169{
1170l_int32 ncc, nb, n, i, j, k, xul, yul, x, y;
1171CCBORD *ccb;
1172PTAA *ptaal, *ptaag;
1173PTA *ptal, *ptag;
1174
1175 PROCNAME("ccbaGenerateGlobalLocs");
1176
1177 if (!ccba)
1178 return ERROR_INT("ccba not defined", procName, 1);
1179
1180 ncc = ccbaGetCount(ccba); /* number of c.c. */
1181 for (i = 0; i < ncc; i++) {
1182 ccb = ccbaGetCcb(ccba, i);
1183
1184 /* Get the UL corner in global coords, (xul, yul), of the c.c. */
1185 boxaGetBoxGeometry(ccb->boxa, 0, &xul, &yul, NULL, NULL);
1186
1187 /* Make a new global ptaa, removing any old one */
1188 ptaal = ccb->local;
1189 nb = ptaaGetCount(ptaal); /* number of borders */
1190 if (ccb->global) /* remove old one */
1191 ptaaDestroy(&ccb->global);
1192 if ((ptaag = ptaaCreate(nb)) == NULL) {
1193 ccbDestroy(&ccb);
1194 return ERROR_INT("ptaag not made", procName, 1);
1195 }
1196 ccb->global = ptaag; /* save new one */
1197
1198 /* Iterate through the borders for this c.c. */
1199 for (j = 0; j < nb; j++) {
1200 ptal = ptaaGetPta(ptaal, j, L_CLONE);
1201 n = ptaGetCount(ptal); /* number of pixels in border */
1202 ptag = ptaCreate(n);
1203 ptaaAddPta(ptaag, ptag, L_INSERT);
1204 for (k = 0; k < n; k++) {
1205 ptaGetIPt(ptal, k, &x, &y);
1206 ptaAddPt(ptag, x + xul, y + yul);
1207 }
1208 ptaDestroy(&ptal);
1209 }
1210 ccbDestroy(&ccb);
1211 }
1212
1213 return 0;
1214}
1215
1216
1239l_ok
1241{
1242l_int32 ncc, nb, n, i, j, k;
1243l_int32 px, py, cx, cy, stepdir;
1244l_int32 dirtab[][3] = {{1, 2, 3}, {0, -1, 4}, {7, 6, 5}};
1245CCBORD *ccb;
1246NUMA *na;
1247NUMAA *naa; /* step chain code; to be made */
1248PTA *ptal;
1249PTAA *ptaal; /* local chain code */
1250
1251 PROCNAME("ccbaGenerateStepChains");
1252
1253 if (!ccba)
1254 return ERROR_INT("ccba not defined", procName, 1);
1255
1256 ncc = ccbaGetCount(ccba); /* number of c.c. */
1257 for (i = 0; i < ncc; i++) {
1258 ccb = ccbaGetCcb(ccba, i);
1259
1260 /* Make a new step numaa, removing any old one */
1261 ptaal = ccb->local;
1262 nb = ptaaGetCount(ptaal); /* number of borders */
1263 if (ccb->step) /* remove old one */
1264 numaaDestroy(&ccb->step);
1265 if ((naa = numaaCreate(nb)) == NULL) {
1266 ccbDestroy(&ccb);
1267 return ERROR_INT("naa not made", procName, 1);
1268 }
1269 ccb->step = naa; /* save new one */
1270
1271 /* Iterate through the borders for this c.c. */
1272 for (j = 0; j < nb; j++) {
1273 ptal = ptaaGetPta(ptaal, j, L_CLONE);
1274 n = ptaGetCount(ptal); /* number of pixels in border */
1275 if (n == 1) { /* isolated pixel */
1276 na = numaCreate(1); /* but leave it empty */
1277 } else { /* trace out the boundary */
1278 na = numaCreate(n);
1279 ptaGetIPt(ptal, 0, &px, &py);
1280 for (k = 1; k < n; k++) {
1281 ptaGetIPt(ptal, k, &cx, &cy);
1282 stepdir = dirtab[1 + cy - py][1 + cx - px];
1283 numaAddNumber(na, stepdir);
1284 px = cx;
1285 py = cy;
1286 }
1287 }
1288 numaaAddNuma(naa, na, L_INSERT);
1289 ptaDestroy(&ptal);
1290 }
1291 ccbDestroy(&ccb); /* just decrement refcount */
1292 }
1293
1294 return 0;
1295}
1296
1297
1314l_ok
1316 l_int32 coordtype)
1317{
1318l_int32 ncc, nb, n, i, j, k;
1319l_int32 xul, yul, xstart, ystart, x, y, stepdir;
1320BOXA *boxa;
1321CCBORD *ccb;
1322NUMA *na;
1323NUMAA *naa;
1324PTAA *ptaan; /* new pix coord ptaa */
1325PTA *ptas, *ptan;
1326
1327 PROCNAME("ccbaStepChainsToPixCoords");
1328
1329 if (!ccba)
1330 return ERROR_INT("ccba not defined", procName, 1);
1331 if (coordtype != CCB_GLOBAL_COORDS && coordtype != CCB_LOCAL_COORDS)
1332 return ERROR_INT("coordtype not valid", procName, 1);
1333
1334 ncc = ccbaGetCount(ccba); /* number of c.c. */
1335 for (i = 0; i < ncc; i++) {
1336 ccb = ccbaGetCcb(ccba, i);
1337 if ((naa = ccb->step) == NULL) {
1338 ccbDestroy(&ccb);
1339 return ERROR_INT("step numaa not found", procName, 1);
1340 } if ((boxa = ccb->boxa) == NULL) {
1341 ccbDestroy(&ccb);
1342 return ERROR_INT("boxa not found", procName, 1);
1343 } if ((ptas = ccb->start) == NULL) {
1344 ccbDestroy(&ccb);
1345 return ERROR_INT("start pta not found", procName, 1);
1346 }
1347
1348 /* For global coords, get the (xul, yul) of the c.c.;
1349 * otherwise, use relative coords. */
1350 if (coordtype == CCB_LOCAL_COORDS) {
1351 xul = 0;
1352 yul = 0;
1353 } else { /* coordtype == CCB_GLOBAL_COORDS */
1354 /* Get UL corner in global coords */
1355 if (boxaGetBoxGeometry(boxa, 0, &xul, &yul, NULL, NULL)) {
1356 ccbDestroy(&ccb);
1357 return ERROR_INT("bounding rectangle not found", procName, 1);
1358 }
1359 }
1360
1361 /* Make a new ptaa, removing any old one */
1362 nb = numaaGetCount(naa); /* number of borders */
1363 if ((ptaan = ptaaCreate(nb)) == NULL) {
1364 ccbDestroy(&ccb);
1365 return ERROR_INT("ptaan not made", procName, 1);
1366 }
1367 if (coordtype == CCB_LOCAL_COORDS) {
1368 if (ccb->local) /* remove old one */
1369 ptaaDestroy(&ccb->local);
1370 ccb->local = ptaan; /* save new local chain */
1371 } else { /* coordtype == CCB_GLOBAL_COORDS */
1372 if (ccb->global) /* remove old one */
1373 ptaaDestroy(&ccb->global);
1374 ccb->global = ptaan; /* save new global chain */
1375 }
1376
1377 /* Iterate through the borders for this c.c. */
1378 for (j = 0; j < nb; j++) {
1379 na = numaaGetNuma(naa, j, L_CLONE);
1380 n = numaGetCount(na); /* number of steps in border */
1381 if ((ptan = ptaCreate(n + 1)) == NULL) {
1382 ccbDestroy(&ccb);
1383 numaDestroy(&na);
1384 return ERROR_INT("ptan not made", procName, 1);
1385 }
1386 ptaaAddPta(ptaan, ptan, L_INSERT);
1387 ptaGetIPt(ptas, j, &xstart, &ystart);
1388 x = xul + xstart;
1389 y = yul + ystart;
1390 ptaAddPt(ptan, x, y);
1391 for (k = 0; k < n; k++) {
1392 numaGetIValue(na, k, &stepdir);
1393 x += xpostab[stepdir];
1394 y += ypostab[stepdir];
1395 ptaAddPt(ptan, x, y);
1396 }
1397 numaDestroy(&na);
1398 }
1399 ccbDestroy(&ccb);
1400 }
1401
1402 return 0;
1403}
1404
1405
1425l_ok
1427 l_int32 ptsflag)
1428{
1429l_int32 ncc, npt, i, j, xul, yul, x, y, delx, dely;
1430l_int32 xp, yp, delxp, delyp; /* prev point and increments */
1431CCBORD *ccb;
1432PTA *ptal, *ptag;
1433
1434 PROCNAME("ccbaGenerateSPGlobalLocs");
1435
1436 if (!ccba)
1437 return ERROR_INT("ccba not defined", procName, 1);
1438
1439 /* Make sure we have a local single path representation */
1440 if ((ccb = ccbaGetCcb(ccba, 0)) == NULL)
1441 return ERROR_INT("no ccb", procName, 1);
1442 if (!ccb->splocal)
1444 ccbDestroy(&ccb); /* clone ref */
1445
1446 ncc = ccbaGetCount(ccba); /* number of c.c. */
1447 for (i = 0; i < ncc; i++) {
1448 ccb = ccbaGetCcb(ccba, i);
1449
1450 /* Get the UL corner in global coords, (xul, yul), of the c.c. */
1451 if (boxaGetBoxGeometry(ccb->boxa, 0, &xul, &yul, NULL, NULL)) {
1452 ccbDestroy(&ccb);
1453 return ERROR_INT("bounding rectangle not found", procName, 1);
1454 }
1455
1456 /* Make a new spglobal pta, removing any old one */
1457 ptal = ccb->splocal;
1458 npt = ptaGetCount(ptal); /* number of points */
1459 if (ccb->spglobal) /* remove old one */
1460 ptaDestroy(&ccb->spglobal);
1461 if ((ptag = ptaCreate(npt)) == NULL) {
1462 ccbDestroy(&ccb);
1463 return ERROR_INT("ptag not made", procName, 1);
1464 }
1465 ccb->spglobal = ptag; /* save new one */
1466
1467 /* Convert local to global */
1468 if (ptsflag == CCB_SAVE_ALL_PTS) {
1469 for (j = 0; j < npt; j++) {
1470 ptaGetIPt(ptal, j, &x, &y);
1471 ptaAddPt(ptag, x + xul, y + yul);
1472 }
1473 } else { /* ptsflag = CCB_SAVE_TURNING_PTS */
1474 ptaGetIPt(ptal, 0, &xp, &yp); /* get the 1st pt */
1475 ptaAddPt(ptag, xp + xul, yp + yul); /* save the 1st pt */
1476 if (npt == 2) { /* get and save the 2nd pt */
1477 ptaGetIPt(ptal, 1, &x, &y);
1478 ptaAddPt(ptag, x + xul, y + yul);
1479 } else if (npt > 2) {
1480 ptaGetIPt(ptal, 1, &x, &y);
1481 delxp = x - xp;
1482 delyp = y - yp;
1483 xp = x;
1484 yp = y;
1485 for (j = 2; j < npt; j++) {
1486 ptaGetIPt(ptal, j, &x, &y);
1487 delx = x - xp;
1488 dely = y - yp;
1489 if (delx != delxp || dely != delyp)
1490 ptaAddPt(ptag, xp + xul, yp + yul);
1491 xp = x;
1492 yp = y;
1493 delxp = delx;
1494 delyp = dely;
1495 }
1496 ptaAddPt(ptag, xp + xul, yp + yul);
1497 }
1498 }
1499
1500 ccbDestroy(&ccb); /* clone ref */
1501 }
1502
1503 return 0;
1504}
1505
1506
1507
1508/*---------------------------------------------------------------------*
1509 * Conversion to single path *
1510 *---------------------------------------------------------------------*/
1546l_ok
1548{
1549l_int32 i, j, k, ncc, nb, ncut, npt, dir, len, state, lostholes;
1550l_int32 x, y, xl, yl, xf, yf;
1551BOX *boxinner;
1552BOXA *boxa;
1553CCBORD *ccb;
1554PTA *pta, *ptac, *ptah;
1555PTA *ptahc; /* cyclic permutation of hole border, with end pts at cut */
1556PTA *ptas; /* output result: new single path for c.c. */
1557PTA *ptaf; /* points on the hole borders that intersect with cuts */
1558PTA *ptal; /* points on outer border that intersect with cuts */
1559PTA *ptap, *ptarp; /* path and reverse path between borders */
1560PTAA *ptaa;
1561PTAA *ptaap; /* ptaa for all paths between borders */
1562
1563 PROCNAME("ccbaGenerateSinglePath");
1564
1565 if (!ccba)
1566 return ERROR_INT("ccba not defined", procName, 1);
1567
1568 ncc = ccbaGetCount(ccba); /* number of c.c. */
1569 lostholes = 0;
1570 for (i = 0; i < ncc; i++) {
1571 ccb = ccbaGetCcb(ccba, i);
1572 if ((ptaa = ccb->local) == NULL) {
1573 L_WARNING("local pixel loc array not found\n", procName);
1574 continue;
1575 }
1576 nb = ptaaGetCount(ptaa); /* number of borders in the c.c. */
1577
1578 /* Prepare the output pta */
1579 if (ccb->splocal)
1580 ptaDestroy(&ccb->splocal);
1581 ptas = ptaCreate(0);
1582 ccb->splocal = ptas;
1583
1584 /* If no holes, just concat the outer border */
1585 pta = ptaaGetPta(ptaa, 0, L_CLONE);
1586 if (nb == 1 || nb > NMAX_HOLES + 1) {
1587 ptaJoin(ptas, pta, 0, -1);
1588 ptaDestroy(&pta); /* remove clone */
1589 ccbDestroy(&ccb); /* remove clone */
1590 continue;
1591 }
1592
1593 /* Find the (nb - 1) cut paths that connect holes
1594 * with outer border */
1595 boxa = ccb->boxa;
1596 ptaap = ptaaCreate(nb - 1);
1597 ptaf = ptaCreate(nb - 1);
1598 ptal = ptaCreate(nb - 1);
1599 for (j = 1; j < nb; j++) {
1600 boxinner = boxaGetBox(boxa, j, L_CLONE);
1601
1602 /* Find a short path and store it */
1603 ptac = getCutPathForHole(ccb->pix, pta, boxinner, &dir, &len);
1604 if (len == 0) { /* lost the hole */
1605 lostholes++;
1606/* boxPrintStreamInfo(stderr, boxa->box[0]); */
1607 }
1608 ptaaAddPta(ptaap, ptac, L_INSERT);
1609/* lept_stderr("dir = %d, length = %d\n", dir, len); */
1610/* ptaWriteStream(stderr, ptac, 1); */
1611
1612 /* Store the first and last points in the cut path,
1613 * which must be on a hole border and the outer
1614 * border, respectively */
1615 ncut = ptaGetCount(ptac);
1616 if (ncut == 0) { /* missed hole; neg coords won't match */
1617 ptaAddPt(ptaf, -1, -1);
1618 ptaAddPt(ptal, -1, -1);
1619 } else {
1620 ptaGetIPt(ptac, 0, &x, &y);
1621 ptaAddPt(ptaf, x, y);
1622 ptaGetIPt(ptac, ncut - 1, &x, &y);
1623 ptaAddPt(ptal, x, y);
1624 }
1625 boxDestroy(&boxinner);
1626 }
1627
1628 /* Make a single path for the c.c. using these connections */
1629 npt = ptaGetCount(pta); /* outer border pts */
1630 for (k = 0; k < npt; k++) {
1631 ptaGetIPt(pta, k, &x, &y);
1632 if (k == 0) { /* if there is a cut at the first point,
1633 * we can wait until the end to take it */
1634 ptaAddPt(ptas, x, y);
1635 continue;
1636 }
1637 state = L_NOT_FOUND;
1638 for (j = 0; j < nb - 1; j++) { /* iterate over cut end pts */
1639 ptaGetIPt(ptal, j, &xl, &yl); /* cut point on outer border */
1640 if (x == xl && y == yl) { /* take this cut to the hole */
1641 state = L_FOUND;
1642 ptap = ptaaGetPta(ptaap, j, L_CLONE);
1643 ptarp = ptaReverse(ptap, 1);
1644 /* Cut point on hole border: */
1645 ptaGetIPt(ptaf, j, &xf, &yf);
1646 /* Hole border: */
1647 ptah = ptaaGetPta(ptaa, j + 1, L_CLONE);
1648 ptahc = ptaCyclicPerm(ptah, xf, yf);
1649/* ptaWriteStream(stderr, ptahc, 1); */
1650 ptaJoin(ptas, ptarp, 0, -1);
1651 ptaJoin(ptas, ptahc, 0, -1);
1652 ptaJoin(ptas, ptap, 0, -1);
1653 ptaDestroy(&ptap);
1654 ptaDestroy(&ptarp);
1655 ptaDestroy(&ptah);
1656 ptaDestroy(&ptahc);
1657 break;
1658 }
1659 }
1660 if (state == L_NOT_FOUND)
1661 ptaAddPt(ptas, x, y);
1662 }
1663
1664/* ptaWriteStream(stderr, ptas, 1); */
1665 ptaaDestroy(&ptaap);
1666 ptaDestroy(&ptaf);
1667 ptaDestroy(&ptal);
1668 ptaDestroy(&pta); /* remove clone */
1669 ccbDestroy(&ccb); /* remove clone */
1670 }
1671
1672 if (lostholes > 0)
1673 L_INFO("***** %d lost holes *****\n", procName, lostholes);
1674 return 0;
1675}
1676
1677
1704PTA *
1706 PTA *pta,
1707 BOX *boxinner,
1708 l_int32 *pdir,
1709 l_int32 *plen)
1710{
1711l_int32 w, h, nc, x, y, xl, yl, xmid, ymid;
1712l_uint32 val;
1713PTA *ptac;
1714
1715 PROCNAME("getCutPathForHole");
1716
1717 if (!pix)
1718 return (PTA *)ERROR_PTR("pix not defined", procName, NULL);
1719 if (!pta)
1720 return (PTA *)ERROR_PTR("pta not defined", procName, NULL);
1721 if (!boxinner)
1722 return (PTA *)ERROR_PTR("boxinner not defined", procName, NULL);
1723
1724 pixGetDimensions(pix, &w, &h, NULL);
1725 ptac = ptaCreate(4);
1726 xmid = boxinner->x + boxinner->w / 2;
1727 ymid = boxinner->y + boxinner->h / 2;
1728
1729 /* try top first */
1730 for (y = ymid; y >= 0; y--) {
1731 pixGetPixel(pix, xmid, y, &val);
1732 if (val == 1) {
1733 ptaAddPt(ptac, xmid, y);
1734 break;
1735 }
1736 }
1737 for (y = y - 1; y >= 0; y--) {
1738 pixGetPixel(pix, xmid, y, &val);
1739 if (val == 1)
1740 ptaAddPt(ptac, xmid, y);
1741 else
1742 break;
1743 }
1744 nc = ptaGetCount(ptac);
1745 ptaGetIPt(ptac, nc - 1, &xl, &yl);
1746 if (ptaContainsPt(pta, xl, yl)) {
1747 *pdir = 1;
1748 *plen = nc;
1749 return ptac;
1750 }
1751
1752 /* Next try bottom */
1753 ptaEmpty(ptac);
1754 for (y = ymid; y < h; y++) {
1755 pixGetPixel(pix, xmid, y, &val);
1756 if (val == 1) {
1757 ptaAddPt(ptac, xmid, y);
1758 break;
1759 }
1760 }
1761 for (y = y + 1; y < h; y++) {
1762 pixGetPixel(pix, xmid, y, &val);
1763 if (val == 1)
1764 ptaAddPt(ptac, xmid, y);
1765 else
1766 break;
1767 }
1768 nc = ptaGetCount(ptac);
1769 ptaGetIPt(ptac, nc - 1, &xl, &yl);
1770 if (ptaContainsPt(pta, xl, yl)) {
1771 *pdir = 3;
1772 *plen = nc;
1773 return ptac;
1774 }
1775
1776 /* Next try left */
1777 ptaEmpty(ptac);
1778 for (x = xmid; x >= 0; x--) {
1779 pixGetPixel(pix, x, ymid, &val);
1780 if (val == 1) {
1781 ptaAddPt(ptac, x, ymid);
1782 break;
1783 }
1784 }
1785 for (x = x - 1; x >= 0; x--) {
1786 pixGetPixel(pix, x, ymid, &val);
1787 if (val == 1)
1788 ptaAddPt(ptac, x, ymid);
1789 else
1790 break;
1791 }
1792 nc = ptaGetCount(ptac);
1793 ptaGetIPt(ptac, nc - 1, &xl, &yl);
1794 if (ptaContainsPt(pta, xl, yl)) {
1795 *pdir = 0;
1796 *plen = nc;
1797 return ptac;
1798 }
1799
1800 /* Finally try right */
1801 ptaEmpty(ptac);
1802 for (x = xmid; x < w; x++) {
1803 pixGetPixel(pix, x, ymid, &val);
1804 if (val == 1) {
1805 ptaAddPt(ptac, x, ymid);
1806 break;
1807 }
1808 }
1809 for (x = x + 1; x < w; x++) {
1810 pixGetPixel(pix, x, ymid, &val);
1811 if (val == 1)
1812 ptaAddPt(ptac, x, ymid);
1813 else
1814 break;
1815 }
1816 nc = ptaGetCount(ptac);
1817 ptaGetIPt(ptac, nc - 1, &xl, &yl);
1818 if (ptaContainsPt(pta, xl, yl)) {
1819 *pdir = 2;
1820 *plen = nc;
1821 return ptac;
1822 }
1823
1824 /* Sometimes, there is nothing. */
1825 ptaEmpty(ptac);
1826 *plen = 0;
1827 return ptac;
1828}
1829
1830
1831
1832/*---------------------------------------------------------------------*
1833 * Border rendering *
1834 *---------------------------------------------------------------------*/
1848PIX *
1850{
1851l_int32 ncc, nb, n, i, j, k, x, y;
1852CCBORD *ccb;
1853PIX *pixd;
1854PTAA *ptaa;
1855PTA *pta;
1856
1857 PROCNAME("ccbaDisplayBorder");
1858
1859 if (!ccba)
1860 return (PIX *)ERROR_PTR("ccba not defined", procName, NULL);
1861
1862 if ((pixd = pixCreate(ccba->w, ccba->h, 1)) == NULL)
1863 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1864 ncc = ccbaGetCount(ccba); /* number of c.c. */
1865 for (i = 0; i < ncc; i++) {
1866 ccb = ccbaGetCcb(ccba, i);
1867 if ((ptaa = ccb->global) == NULL) {
1868 L_WARNING("global pixel loc array not found", procName);
1869 ccbDestroy(&ccb);
1870 continue;
1871 }
1872 nb = ptaaGetCount(ptaa); /* number of borders in the c.c. */
1873 for (j = 0; j < nb; j++) {
1874 pta = ptaaGetPta(ptaa, j, L_CLONE);
1875 n = ptaGetCount(pta); /* number of pixels in the border */
1876 for (k = 0; k < n; k++) {
1877 ptaGetIPt(pta, k, &x, &y);
1878 pixSetPixel(pixd, x, y, 1);
1879 }
1880 ptaDestroy(&pta);
1881 }
1882 ccbDestroy(&ccb);
1883 }
1884
1885 return pixd;
1886}
1887
1888
1902PIX *
1904{
1905l_int32 ncc, npt, i, j, x, y;
1906CCBORD *ccb;
1907PIX *pixd;
1908PTA *ptag;
1909
1910 PROCNAME("ccbaDisplaySPBorder");
1911
1912 if (!ccba)
1913 return (PIX *)ERROR_PTR("ccba not defined", procName, NULL);
1914
1915 if ((pixd = pixCreate(ccba->w, ccba->h, 1)) == NULL)
1916 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1917 ncc = ccbaGetCount(ccba); /* number of c.c. */
1918 for (i = 0; i < ncc; i++) {
1919 ccb = ccbaGetCcb(ccba, i);
1920 if ((ptag = ccb->spglobal) == NULL) {
1921 L_WARNING("spglobal pixel loc array not found\n", procName);
1922 ccbDestroy(&ccb);
1923 continue;
1924 }
1925 npt = ptaGetCount(ptag); /* number of pixels on path */
1926 for (j = 0; j < npt; j++) {
1927 ptaGetIPt(ptag, j, &x, &y);
1928 pixSetPixel(pixd, x, y, 1);
1929 }
1930 ccbDestroy(&ccb); /* clone ref */
1931 }
1932
1933 return pixd;
1934}
1935
1936
1993PIX *
1995{
1996l_int32 ncc, i, nb, n, j, k, x, y, xul, yul, xoff, yoff, w, h;
1997l_int32 fpx, fpy, spx, spy, xs, ys;
1998BOX *box;
1999BOXA *boxa;
2000CCBORD *ccb;
2001PIX *pixd, *pixt, *pixh;
2002PTAA *ptaa;
2003PTA *pta;
2004
2005 PROCNAME("ccbaDisplayImage1");
2006
2007 if (!ccba)
2008 return (PIX *)ERROR_PTR("ccba not defined", procName, NULL);
2009
2010 if ((pixd = pixCreate(ccba->w, ccba->h, 1)) == NULL)
2011 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
2012 ncc = ccbaGetCount(ccba);
2013 for (i = 0; i < ncc; i++) {
2014 ccb = ccbaGetCcb(ccba, i);
2015 if ((boxa = ccb->boxa) == NULL) {
2016 pixDestroy(&pixd);
2017 ccbDestroy(&ccb);
2018 return (PIX *)ERROR_PTR("boxa not found", procName, NULL);
2019 }
2020
2021 /* Render border in pixt */
2022 if ((ptaa = ccb->local) == NULL) {
2023 L_WARNING("local chain array not found\n", procName);
2024 ccbDestroy(&ccb);
2025 continue;
2026 }
2027
2028 nb = ptaaGetCount(ptaa); /* number of borders in the c.c. */
2029 for (j = 0; j < nb; j++) {
2030 if ((box = boxaGetBox(boxa, j, L_CLONE)) == NULL) {
2031 pixDestroy(&pixd);
2032 ccbDestroy(&ccb);
2033 return (PIX *)ERROR_PTR("b. box not found", procName, NULL);
2034 }
2035 if (j == 0) {
2036 boxGetGeometry(box, &xul, &yul, &w, &h);
2037 xoff = yoff = 0;
2038 } else {
2039 boxGetGeometry(box, &xoff, &yoff, &w, &h);
2040 }
2041 boxDestroy(&box);
2042
2043 /* Render the border in a minimum-sized pix;
2044 * subtract xoff and yoff because the pixel
2045 * location is stored relative to the c.c., but
2046 * we need it relative to just the hole border. */
2047 if ((pixt = pixCreate(w, h, 1)) == NULL) {
2048 pixDestroy(&pixd);
2049 ccbDestroy(&ccb);
2050 return (PIX *)ERROR_PTR("pixt not made", procName, NULL);
2051 }
2052 pta = ptaaGetPta(ptaa, j, L_CLONE);
2053 n = ptaGetCount(pta); /* number of pixels in the border */
2054 for (k = 0; k < n; k++) {
2055 ptaGetIPt(pta, k, &x, &y);
2056 pixSetPixel(pixt, x - xoff, y - yoff, 1);
2057 if (j > 0) { /* need this for finding hole border pixel */
2058 if (k == 0) {
2059 fpx = x - xoff;
2060 fpy = y - yoff;
2061 }
2062 if (k == 1) {
2063 spx = x - xoff;
2064 spy = y - yoff;
2065 }
2066 }
2067 }
2068 ptaDestroy(&pta);
2069
2070 /* Get the filled component */
2071 if (j == 0) { /* if outer border, fill from outer boundary */
2072 if ((pixh = pixFillClosedBorders(pixt, 4)) == NULL) {
2073 pixDestroy(&pixd);
2074 pixDestroy(&pixt);
2075 ccbDestroy(&ccb);
2076 return (PIX *)ERROR_PTR("pixh not made", procName, NULL);
2077 }
2078 } else { /* fill the hole from inside */
2079 /* get the location of a seed pixel in the hole */
2080 locateOutsideSeedPixel(fpx, fpy, spx, spy, &xs, &ys);
2081
2082 /* Put seed in hole and fill interior of hole,
2083 * using pixt as clipping mask */
2084 pixh = pixCreateTemplate(pixt);
2085 pixSetPixel(pixh, xs, ys, 1); /* put seed pixel in hole */
2086 pixInvert(pixt, pixt); /* to make filling mask */
2087 pixSeedfillBinary(pixh, pixh, pixt, 4); /* 4-fill hole */
2088 }
2089
2090 /* XOR into the dest */
2091 pixRasterop(pixd, xul + xoff, yul + yoff, w, h, PIX_XOR,
2092 pixh, 0, 0);
2093 pixDestroy(&pixt);
2094 pixDestroy(&pixh);
2095 }
2096 ccbDestroy(&ccb);
2097 }
2098 return pixd;
2099}
2100
2101
2102
2124PIX *
2126{
2127l_int32 ncc, nb, n, i, j, k, x, y, xul, yul, w, h;
2128l_int32 fpx, fpy, spx, spy, xs, ys;
2129BOXA *boxa;
2130CCBORD *ccb;
2131PIX *pixd, *pixc, *pixs;
2132PTAA *ptaa;
2133PTA *pta;
2134
2135 PROCNAME("ccbaDisplayImage2");
2136
2137 if (!ccba)
2138 return (PIX *)ERROR_PTR("ccba not defined", procName, NULL);
2139
2140 if ((pixd = pixCreate(ccba->w, ccba->h, 1)) == NULL)
2141 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
2142 ncc = ccbaGetCount(ccba);
2143 for (i = 0; i < ncc; i++) {
2144 /* Generate clipping mask from border pixels and seed image
2145 * from one seed for each closed border. */
2146 ccb = ccbaGetCcb(ccba, i);
2147 if ((boxa = ccb->boxa) == NULL) {
2148 pixDestroy(&pixd);
2149 ccbDestroy(&ccb);
2150 return (PIX *)ERROR_PTR("boxa not found", procName, NULL);
2151 }
2152 if (boxaGetBoxGeometry(boxa, 0, &xul, &yul, &w, &h)) {
2153 pixDestroy(&pixd);
2154 ccbDestroy(&ccb);
2155 return (PIX *)ERROR_PTR("b. box not found", procName, NULL);
2156 }
2157 pixc = pixCreate(w + 2, h + 2, 1);
2158 pixs = pixCreateTemplate(pixc);
2159
2160 if ((ptaa = ccb->local) == NULL) {
2161 pixDestroy(&pixc);
2162 pixDestroy(&pixs);
2163 ccbDestroy(&ccb);
2164 L_WARNING("local chain array not found\n", procName);
2165 continue;
2166 }
2167 nb = ptaaGetCount(ptaa); /* number of borders in the c.c. */
2168 for (j = 0; j < nb; j++) {
2169 pta = ptaaGetPta(ptaa, j, L_CLONE);
2170 n = ptaGetCount(pta); /* number of pixels in the border */
2171
2172 /* Render border pixels in pixc */
2173 for (k = 0; k < n; k++) {
2174 ptaGetIPt(pta, k, &x, &y);
2175 pixSetPixel(pixc, x + 1, y + 1, 1);
2176 if (k == 0) {
2177 fpx = x + 1;
2178 fpy = y + 1;
2179 } else if (k == 1) {
2180 spx = x + 1;
2181 spy = y + 1;
2182 }
2183 }
2184
2185 /* Get and set seed pixel for this border in pixs */
2186 if (n > 1)
2187 locateOutsideSeedPixel(fpx, fpy, spx, spy, &xs, &ys);
2188 else /* isolated c.c. */
2189 xs = ys = 0;
2190 pixSetPixel(pixs, xs, ys, 1);
2191 ptaDestroy(&pta);
2192 }
2193
2194 /* Fill from seeds in pixs, using pixc as the clipping mask,
2195 * to reconstruct the c.c. */
2196 pixInvert(pixc, pixc); /* to convert clipping -> filling mask */
2197 pixSeedfillBinary(pixs, pixs, pixc, 4); /* 4-fill */
2198 pixInvert(pixs, pixs); /* to make the c.c. */
2199
2200 /* XOR into the dest */
2201 pixRasterop(pixd, xul, yul, w, h, PIX_XOR, pixs, 1, 1);
2202
2203 pixDestroy(&pixc);
2204 pixDestroy(&pixs);
2205 ccbDestroy(&ccb); /* ref-counted */
2206 }
2207 return pixd;
2208}
2209
2210
2211/*---------------------------------------------------------------------*
2212 * Serialize for I/O *
2213 *---------------------------------------------------------------------*/
2221l_ok
2222ccbaWrite(const char *filename,
2223 CCBORDA *ccba)
2224{
2225FILE *fp;
2226
2227 PROCNAME("ccbaWrite");
2228
2229 if (!filename)
2230 return ERROR_INT("filename not defined", procName, 1);
2231 if (!ccba)
2232 return ERROR_INT("ccba not defined", procName, 1);
2233
2234 if ((fp = fopenWriteStream(filename, "wb+")) == NULL)
2235 return ERROR_INT("stream not opened", procName, 1);
2236 if (ccbaWriteStream(fp, ccba)) {
2237 fclose(fp);
2238 return ERROR_INT("ccba not written to stream", procName, 1);
2239 }
2240
2241 fclose(fp);
2242 return 0;
2243}
2244
2245
2246
2273l_ok
2275 CCBORDA *ccba)
2276{
2277char strbuf[256];
2278l_uint8 bval;
2279l_uint8 *datain, *dataout;
2280l_int32 i, j, k, bx, by, bw, bh, val, startx, starty;
2281l_int32 ncc, nb, n;
2282l_uint32 w, h;
2283size_t inbytes, outbytes;
2284L_BBUFFER *bbuf;
2285CCBORD *ccb;
2286NUMA *na;
2287NUMAA *naa;
2288PTA *pta;
2289
2290 PROCNAME("ccbaWriteStream");
2291
2292#if !HAVE_LIBZ /* defined in environ.h */
2293 return ERROR_INT("no libz: can't write data", procName, 1);
2294#else
2295
2296 if (!fp)
2297 return ERROR_INT("stream not open", procName, 1);
2298 if (!ccba)
2299 return ERROR_INT("ccba not defined", procName, 1);
2300
2301 if ((bbuf = bbufferCreate(NULL, 1000)) == NULL)
2302 return ERROR_INT("bbuf not made", procName, 1);
2303
2304 ncc = ccbaGetCount(ccba);
2305 snprintf(strbuf, sizeof(strbuf), "ccba: %7d cc\n", ncc);
2306 bbufferRead(bbuf, (l_uint8 *)strbuf, 18);
2307 w = pixGetWidth(ccba->pix);
2308 h = pixGetHeight(ccba->pix);
2309 bbufferRead(bbuf, (l_uint8 *)&w, 4); /* width */
2310 bbufferRead(bbuf, (l_uint8 *)&h, 4); /* height */
2311 for (i = 0; i < ncc; i++) {
2312 ccb = ccbaGetCcb(ccba, i);
2313 if (boxaGetBoxGeometry(ccb->boxa, 0, &bx, &by, &bw, &bh)) {
2314 bbufferDestroy(&bbuf);
2315 ccbDestroy(&ccb);
2316 return ERROR_INT("bounding box not found", procName, 1);
2317 }
2318 bbufferRead(bbuf, (l_uint8 *)&bx, 4); /* ulx of c.c. */
2319 bbufferRead(bbuf, (l_uint8 *)&by, 4); /* uly of c.c. */
2320 bbufferRead(bbuf, (l_uint8 *)&bw, 4); /* w of c.c. */
2321 bbufferRead(bbuf, (l_uint8 *)&bh, 4); /* h of c.c. */
2322 if ((naa = ccb->step) == NULL) {
2324 naa = ccb->step;
2325 }
2326 nb = numaaGetCount(naa);
2327 bbufferRead(bbuf, (l_uint8 *)&nb, 4); /* number of borders in c.c. */
2328 pta = ccb->start;
2329 for (j = 0; j < nb; j++) {
2330 ptaGetIPt(pta, j, &startx, &starty);
2331 bbufferRead(bbuf, (l_uint8 *)&startx, 4); /* starting x in border */
2332 bbufferRead(bbuf, (l_uint8 *)&starty, 4); /* starting y in border */
2333 na = numaaGetNuma(naa, j, L_CLONE);
2334 n = numaGetCount(na);
2335 for (k = 0; k < n; k++) {
2336 numaGetIValue(na, k, &val);
2337 if (k % 2 == 0)
2338 bval = (l_uint8)val << 4;
2339 else
2340 bval |= (l_uint8)val;
2341 if (k % 2 == 1)
2342 bbufferRead(bbuf, (l_uint8 *)&bval, 1); /* 2 border steps */
2343 }
2344 if (n % 2 == 1) {
2345 bval |= 0x8;
2346 bbufferRead(bbuf, (l_uint8 *)&bval, 1); /* end with 0xz8, */
2347 /* where z = {0..7} */
2348 } else { /* n % 2 == 0 */
2349 bval = 0x88;
2350 bbufferRead(bbuf, (l_uint8 *)&bval, 1); /* end with 0x88 */
2351 }
2352 numaDestroy(&na);
2353 }
2354 ccbDestroy(&ccb);
2355 }
2356
2357 datain = bbufferDestroyAndSaveData(&bbuf, &inbytes);
2358 dataout = zlibCompress(datain, inbytes, &outbytes);
2359 fwrite(dataout, 1, outbytes, fp);
2360
2361 LEPT_FREE(datain);
2362 LEPT_FREE(dataout);
2363 return 0;
2364
2365#endif /* !HAVE_LIBZ */
2366}
2367
2368
2375CCBORDA *
2376ccbaRead(const char *filename)
2377{
2378FILE *fp;
2379CCBORDA *ccba;
2380
2381 PROCNAME("ccbaRead");
2382
2383 if (!filename)
2384 return (CCBORDA *)ERROR_PTR("filename not defined", procName, NULL);
2385
2386 if ((fp = fopenReadStream(filename)) == NULL)
2387 return (CCBORDA *)ERROR_PTR("stream not opened", procName, NULL);
2388 ccba = ccbaReadStream(fp);
2389 fclose(fp);
2390
2391 if (!ccba)
2392 return (CCBORDA *)ERROR_PTR("ccba not returned", procName, NULL);
2393 return ccba;
2394}
2395
2396
2421CCBORDA *
2423{
2424char strbuf[256];
2425l_uint8 bval;
2426l_uint8 *datain, *dataout;
2427l_int32 i, j, startx, starty;
2428l_int32 offset, nib1, nib2;
2429l_int32 ncc, nb;
2430l_uint32 width, height, w, h, xoff, yoff;
2431size_t inbytes, outbytes;
2432BOX *box;
2433CCBORD *ccb;
2434CCBORDA *ccba;
2435NUMA *na;
2436NUMAA *step;
2437
2438 PROCNAME("ccbaReadStream");
2439
2440#if !HAVE_LIBZ /* defined in environ.h */
2441 return (CCBORDA *)ERROR_PTR("no libz: can't read data", procName, NULL);
2442#else
2443
2444 if (!fp)
2445 return (CCBORDA *)ERROR_PTR("stream not open", procName, NULL);
2446
2447 if ((datain = l_binaryReadStream(fp, &inbytes)) == NULL)
2448 return (CCBORDA *)ERROR_PTR("data not read from file", procName, NULL);
2449 dataout = zlibUncompress(datain, inbytes, &outbytes);
2450 LEPT_FREE(datain);
2451 if (!dataout)
2452 return (CCBORDA *)ERROR_PTR("dataout not made", procName, NULL);
2453
2454 offset = 18;
2455 memcpy(strbuf, dataout, offset);
2456 strbuf[17] = '\0';
2457 if (memcmp(strbuf, "ccba:", 5) != 0) {
2458 LEPT_FREE(dataout);
2459 return (CCBORDA *)ERROR_PTR("file not type ccba", procName, NULL);
2460 }
2461 sscanf(strbuf, "ccba: %7d cc\n", &ncc);
2462/* lept_stderr("ncc = %d\n", ncc); */
2463 if ((ccba = ccbaCreate(NULL, ncc)) == NULL) {
2464 LEPT_FREE(dataout);
2465 return (CCBORDA *)ERROR_PTR("ccba not made", procName, NULL);
2466 }
2467
2468 memcpy(&width, dataout + offset, 4);
2469 offset += 4;
2470 memcpy(&height, dataout + offset, 4);
2471 offset += 4;
2472 ccba->w = width;
2473 ccba->h = height;
2474/* lept_stderr("width = %d, height = %d\n", width, height); */
2475
2476 for (i = 0; i < ncc; i++) { /* should be ncc */
2477 ccb = ccbCreate(NULL);
2478 ccbaAddCcb(ccba, ccb);
2479
2480 memcpy(&xoff, dataout + offset, 4);
2481 offset += 4;
2482 memcpy(&yoff, dataout + offset, 4);
2483 offset += 4;
2484 memcpy(&w, dataout + offset, 4);
2485 offset += 4;
2486 memcpy(&h, dataout + offset, 4);
2487 offset += 4;
2488 box = boxCreate(xoff, yoff, w, h);
2489 boxaAddBox(ccb->boxa, box, L_INSERT);
2490/* lept_stderr("xoff = %d, yoff = %d, w = %d, h = %d\n",
2491 xoff, yoff, w, h); */
2492
2493 memcpy(&nb, dataout + offset, 4);
2494 offset += 4;
2495/* lept_stderr("num borders = %d\n", nb); */
2496 step = numaaCreate(nb);
2497 ccb->step = step;
2498
2499 for (j = 0; j < nb; j++) { /* should be nb */
2500 memcpy(&startx, dataout + offset, 4);
2501 offset += 4;
2502 memcpy(&starty, dataout + offset, 4);
2503 offset += 4;
2504 ptaAddPt(ccb->start, startx, starty);
2505/* lept_stderr("startx = %d, starty = %d\n", startx, starty); */
2506 na = numaCreate(0);
2507 numaaAddNuma(step, na, L_INSERT);
2508
2509 while(1) {
2510 bval = *(dataout + offset);
2511 offset++;
2512 nib1 = (bval >> 4);
2513 nib2 = bval & 0xf;
2514 if (nib1 != 8)
2515 numaAddNumber(na, nib1);
2516 else
2517 break;
2518 if (nib2 != 8)
2519 numaAddNumber(na, nib2);
2520 else
2521 break;
2522 }
2523 }
2524 }
2525 LEPT_FREE(dataout);
2526 return ccba;
2527
2528#endif /* !HAVE_LIBZ */
2529}
2530
2531
2532/*---------------------------------------------------------------------*
2533 * SVG Output *
2534 *---------------------------------------------------------------------*/
2542l_ok
2543ccbaWriteSVG(const char *filename,
2544 CCBORDA *ccba)
2545{
2546char *svgstr;
2547
2548 PROCNAME("ccbaWriteSVG");
2549
2550 if (!filename)
2551 return ERROR_INT("filename not defined", procName, 1);
2552 if (!ccba)
2553 return ERROR_INT("ccba not defined", procName, 1);
2554
2555 if ((svgstr = ccbaWriteSVGString(ccba)) == NULL)
2556 return ERROR_INT("svgstr not made", procName, 1);
2557
2558 l_binaryWrite(filename, "w", svgstr, strlen(svgstr));
2559 LEPT_FREE(svgstr);
2560
2561 return 0;
2562}
2563
2564
2572char *
2574{
2575char *svgstr;
2576char smallbuf[256];
2577char line0[] = "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>";
2578char line1[] = "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 20000303 Stylable//EN\" \"http://www.w3.org/TR/2000/03/WD-SVG-20000303/DTD/svg-20000303-stylable.dtd\">";
2579char line2[] = "<svg>";
2580char line3[] = "<polygon style=\"stroke-width:1;stroke:black;\" points=\"";
2581char line4[] = "\" />";
2582char line5[] = "</svg>";
2583char space[] = " ";
2584l_int32 i, j, ncc, npt, x, y;
2585CCBORD *ccb;
2586PTA *pta;
2587SARRAY *sa;
2588
2589 PROCNAME("ccbaWriteSVGString");
2590
2591 if (!ccba)
2592 return (char *)ERROR_PTR("ccba not defined", procName, NULL);
2593
2594 sa = sarrayCreate(0);
2595 sarrayAddString(sa, line0, L_COPY);
2596 sarrayAddString(sa, line1, L_COPY);
2597 sarrayAddString(sa, line2, L_COPY);
2598 ncc = ccbaGetCount(ccba);
2599 for (i = 0; i < ncc; i++) {
2600 if ((ccb = ccbaGetCcb(ccba, i)) == NULL) {
2601 sarrayDestroy(&sa);
2602 return (char *)ERROR_PTR("ccb not found", procName, NULL);
2603 }
2604 if ((pta = ccb->spglobal) == NULL) {
2605 sarrayDestroy(&sa);
2606 ccbDestroy(&ccb);
2607 return (char *)ERROR_PTR("spglobal not made", procName, NULL);
2608 }
2609 sarrayAddString(sa, line3, L_COPY);
2610 npt = ptaGetCount(pta);
2611 for (j = 0; j < npt; j++) {
2612 ptaGetIPt(pta, j, &x, &y);
2613 snprintf(smallbuf, sizeof(smallbuf), "%0d,%0d", x, y);
2614 sarrayAddString(sa, smallbuf, L_COPY);
2615 }
2616 sarrayAddString(sa, line4, L_COPY);
2617 ccbDestroy(&ccb);
2618 }
2619 sarrayAddString(sa, line5, L_COPY);
2620 sarrayAddString(sa, space, L_COPY);
2621
2622 svgstr = sarrayToString(sa, 1);
2623/* lept_stderr("%s", svgstr); */
2624
2625 sarrayDestroy(&sa);
2626 return svgstr;
2627}
#define GET_DATA_BIT(pdata, n)
Definition: arrayaccess.h:123
l_ok bbufferRead(L_BBUFFER *bb, l_uint8 *src, l_int32 nbytes)
bbufferRead()
Definition: bbuffer.c:265
l_uint8 * bbufferDestroyAndSaveData(L_BBUFFER **pbb, size_t *pnbytes)
bbufferDestroyAndSaveData()
Definition: bbuffer.c:206
L_BBUFFER * bbufferCreate(const l_uint8 *indata, l_int32 nalloc)
bbufferCreate()
Definition: bbuffer.c:130
void bbufferDestroy(L_BBUFFER **pbb)
bbufferDestroy()
Definition: bbuffer.c:172
BOX * boxaGetBox(BOXA *boxa, l_int32 index, l_int32 accessflag)
boxaGetBox()
Definition: boxbasic.c:779
void boxDestroy(BOX **pbox)
boxDestroy()
Definition: boxbasic.c:282
BOX * boxClone(BOX *box)
boxClone()
Definition: boxbasic.c:256
BOX * boxCreate(l_int32 x, l_int32 y, l_int32 w, l_int32 h)
boxCreate()
Definition: boxbasic.c:172
l_ok boxaGetBoxGeometry(BOXA *boxa, l_int32 index, l_int32 *px, l_int32 *py, l_int32 *pw, l_int32 *ph)
boxaGetBoxGeometry()
Definition: boxbasic.c:879
l_int32 boxaGetCount(BOXA *boxa)
boxaGetCount()
Definition: boxbasic.c:734
l_ok boxGetGeometry(BOX *box, l_int32 *px, l_int32 *py, l_int32 *pw, l_int32 *ph)
boxGetGeometry()
Definition: boxbasic.c:313
BOXA * boxaCreate(l_int32 n)
boxaCreate()
Definition: boxbasic.c:502
l_ok boxaAddBox(BOXA *boxa, BOX *box, l_int32 copyflag)
boxaAddBox()
Definition: boxbasic.c:620
void boxaDestroy(BOXA **pboxa)
boxaDestroy()
Definition: boxbasic.c:583
l_ok boxPrintStreamInfo(FILE *fp, BOX *box)
boxPrintStreamInfo()
Definition: boxbasic.c:2431
PTAA * pixGetOuterBordersPtaa(PIX *pixs)
pixGetOuterBordersPtaa()
Definition: ccbord.c:764
PIX * ccbaDisplayImage2(CCBORDA *ccba)
ccbaDisplayImage2()
Definition: ccbord.c:2125
l_ok ccbaWriteSVG(const char *filename, CCBORDA *ccba)
ccbaWriteSVG()
Definition: ccbord.c:2543
CCBORD * ccbCreate(PIX *pixs)
ccbCreate()
Definition: ccbord.c:373
char * ccbaWriteSVGString(CCBORDA *ccba)
ccbaWriteSVGString()
Definition: ccbord.c:2573
void ccbaDestroy(CCBORDA **pccba)
ccbaDestroy()
Definition: ccbord.c:342
l_ok ccbaAddCcb(CCBORDA *ccba, CCBORD *ccb)
ccbaAddCcb()
Definition: ccbord.c:455
PTA * getCutPathForHole(PIX *pix, PTA *pta, BOX *boxinner, l_int32 *pdir, l_int32 *plen)
getCutPathForHole()
Definition: ccbord.c:1705
CCBORDA * ccbaRead(const char *filename)
ccbaRead()
Definition: ccbord.c:2376
void ccbDestroy(CCBORD **pccb)
ccbDestroy()
Definition: ccbord.c:406
l_ok pixGetOuterBorder(CCBORD *ccb, PIX *pixs, BOX *box)
pixGetOuterBorder()
Definition: ccbord.c:897
l_ok ccbaGenerateSinglePath(CCBORDA *ccba)
ccbaGenerateSinglePath()
Definition: ccbord.c:1547
static l_int32 findNextBorderPixel(l_int32 w, l_int32 h, l_uint32 *data, l_int32 wpl, l_int32 px, l_int32 py, l_int32 *pqpos, l_int32 *pnpx, l_int32 *pnpy)
findNextBorderPixel()
Definition: ccbord.c:1067
CCBORD * ccbaGetCcb(CCBORDA *ccba, l_int32 index)
ccbaGetCcb()
Definition: ccbord.c:538
PIX * ccbaDisplayBorder(CCBORDA *ccba)
ccbaDisplayBorder()
Definition: ccbord.c:1849
l_ok ccbaWrite(const char *filename, CCBORDA *ccba)
ccbaWrite()
Definition: ccbord.c:2222
PIX * ccbaDisplaySPBorder(CCBORDA *ccba)
ccbaDisplaySPBorder()
Definition: ccbord.c:1903
l_ok ccbaStepChainsToPixCoords(CCBORDA *ccba, l_int32 coordtype)
ccbaStepChainsToPixCoords()
Definition: ccbord.c:1315
PIX * ccbaDisplayImage1(CCBORDA *ccba)
ccbaDisplayImage1()
Definition: ccbord.c:1994
l_ok ccbaGenerateGlobalLocs(CCBORDA *ccba)
ccbaGenerateGlobalLocs()
Definition: ccbord.c:1168
static PTA * pixGetOuterBorderPta(PIX *pixs, BOX *box)
pixGetOuterBorderPta()
Definition: ccbord.c:824
static CCBORD * pixGetCCBorders(PIX *pixs, BOX *box)
pixGetCCBorders()
Definition: ccbord.c:653
l_int32 ccbaGetCount(CCBORDA *ccba)
ccbaGetCount()
Definition: ccbord.c:513
l_ok ccbaGenerateStepChains(CCBORDA *ccba)
ccbaGenerateStepChains()
Definition: ccbord.c:1240
CCBORDA * ccbaReadStream(FILE *fp)
ccbaReadStream()
Definition: ccbord.c:2422
CCBORDA * pixGetAllCCBorders(PIX *pixs)
pixGetAllCCBorders()
Definition: ccbord.c:567
static l_ok pixGetHoleBorder(CCBORD *ccb, PIX *pixs, BOX *box, l_int32 xs, l_int32 ys)
pixGetHoleBorder()
Definition: ccbord.c:985
static l_int32 ccbaExtendArray(CCBORDA *ccba)
ccbaExtendArray()
Definition: ccbord.c:485
l_ok ccbaGenerateSPGlobalLocs(CCBORDA *ccba, l_int32 ptsflag)
ccbaGenerateSPGlobalLocs()
Definition: ccbord.c:1426
CCBORDA * ccbaCreate(PIX *pixs, l_int32 n)
ccbaCreate()
Definition: ccbord.c:309
l_ok ccbaWriteStream(FILE *fp, CCBORDA *ccba)
ccbaWriteStream()
Definition: ccbord.c:2274
static void locateOutsideSeedPixel(l_int32 fpx, l_int32 fpy, l_int32 spx, l_int32 spy, l_int32 *pxs, l_int32 *pys)
locateOutsideSeedPixel()
Definition: ccbord.c:1120
BOXA * pixConnComp(PIX *pixs, PIXA **ppixa, l_int32 connectivity)
pixConnComp()
Definition: conncomp.c:151
l_int32 nextOnPixelInRaster(PIX *pixs, l_int32 xstart, l_int32 ystart, l_int32 *px, l_int32 *py)
nextOnPixelInRaster()
Definition: conncomp.c:457
l_ok numaAddNumber(NUMA *na, l_float32 val)
numaAddNumber()
Definition: numabasic.c:478
NUMA * numaaGetNuma(NUMAA *naa, l_int32 index, l_int32 accessflag)
numaaGetNuma()
Definition: numabasic.c:1740
l_int32 numaaGetCount(NUMAA *naa)
numaaGetCount()
Definition: numabasic.c:1631
void numaDestroy(NUMA **pna)
numaDestroy()
Definition: numabasic.c:366
l_int32 numaGetCount(NUMA *na)
numaGetCount()
Definition: numabasic.c:658
l_ok numaGetIValue(NUMA *na, l_int32 index, l_int32 *pival)
numaGetIValue()
Definition: numabasic.c:754
NUMA * numaCreate(l_int32 n)
numaCreate()
Definition: numabasic.c:194
l_ok numaaAddNuma(NUMAA *naa, NUMA *na, l_int32 copyflag)
numaaAddNuma()
Definition: numabasic.c:1546
NUMAA * numaaCreate(l_int32 n)
numaaCreate()
Definition: numabasic.c:1407
void numaaDestroy(NUMAA **pnaa)
numaaDestroy()
Definition: numabasic.c:1510
void pixDestroy(PIX **ppix)
pixDestroy()
Definition: pix1.c:621
l_ok pixGetDimensions(const PIX *pix, l_int32 *pw, l_int32 *ph, l_int32 *pd)
pixGetDimensions()
Definition: pix1.c:1113
PIX * pixClone(PIX *pixs)
pixClone()
Definition: pix1.c:593
PIX * pixCreateTemplate(const PIX *pixs)
pixCreateTemplate()
Definition: pix1.c:383
PIX * pixCreate(l_int32 width, l_int32 height, l_int32 depth)
pixCreate()
Definition: pix1.c:315
l_uint32 * pixGetData(PIX *pix)
pixGetData()
Definition: pix1.c:1763
l_ok pixSetPixel(PIX *pix, l_int32 x, l_int32 y, l_uint32 val)
pixSetPixel()
Definition: pix2.c:263
l_ok pixGetPixel(PIX *pix, l_int32 x, l_int32 y, l_uint32 *pval)
pixGetPixel()
Definition: pix2.c:190
PIX * pixAddBorder(PIX *pixs, l_int32 npix, l_uint32 val)
pixAddBorder()
Definition: pix2.c:1823
l_ok pixZero(PIX *pix, l_int32 *pempty)
pixZero()
Definition: pix3.c:1815
PIX * pixInvert(PIX *pixd, PIX *pixs)
pixInvert()
Definition: pix3.c:1509
@ L_COPY
Definition: pix.h:712
@ L_CLONE
Definition: pix.h:713
@ L_INSERT
Definition: pix.h:711
#define PIX_XOR
Definition: pix.h:340
void pixaDestroy(PIXA **ppixa)
pixaDestroy()
Definition: pixabasic.c:412
BOX * pixaGetBox(PIXA *pixa, l_int32 index, l_int32 accesstype)
pixaGetBox()
Definition: pixabasic.c:816
PIX * pixaGetPix(PIXA *pixa, l_int32 index, l_int32 accesstype)
pixaGetPix()
Definition: pixabasic.c:691
l_ok ptaEmpty(PTA *pta)
ptaEmpty()
Definition: ptabasic.c:321
l_ok ptaGetIPt(PTA *pta, l_int32 index, l_int32 *px, l_int32 *py)
ptaGetIPt()
Definition: ptabasic.c:578
PTA * ptaCreate(l_int32 n)
ptaCreate()
Definition: ptabasic.c:120
PTA * ptaClone(PTA *pta)
ptaClone()
Definition: ptabasic.c:297
l_ok ptaaAddPta(PTAA *ptaa, PTA *pta, l_int32 copyflag)
ptaaAddPta()
Definition: ptabasic.c:1038
l_int32 ptaaGetCount(PTAA *ptaa)
ptaaGetCount()
Definition: ptabasic.c:1125
PTA * ptaaGetPta(PTAA *ptaa, l_int32 index, l_int32 accessflag)
ptaaGetPta()
Definition: ptabasic.c:1145
l_ok ptaAddPt(PTA *pta, l_float32 x, l_float32 y)
ptaAddPt()
Definition: ptabasic.c:343
l_int32 ptaGetCount(PTA *pta)
ptaGetCount()
Definition: ptabasic.c:527
PTAA * ptaaCreate(l_int32 n)
ptaaCreate()
Definition: ptabasic.c:976
void ptaaDestroy(PTAA **pptaa)
ptaaDestroy()
Definition: ptabasic.c:1003
void ptaDestroy(PTA **ppta)
ptaDestroy()
Definition: ptabasic.c:195
l_int32 ptaContainsPt(PTA *pta, l_int32 x, l_int32 y)
ptaContainsPt()
Definition: ptafunc1.c:670
PTA * ptaCyclicPerm(PTA *ptas, l_int32 xs, l_int32 ys)
ptaCyclicPerm()
Definition: ptafunc1.c:333
PTA * ptaTransform(PTA *ptas, l_int32 shiftx, l_int32 shifty, l_float32 scalex, l_float32 scaley)
ptaTransform()
Definition: ptafunc1.c:740
l_ok ptaJoin(PTA *ptad, PTA *ptas, l_int32 istart, l_int32 iend)
ptaJoin()
Definition: ptafunc1.c:167
PTA * ptaReverse(PTA *ptas, l_int32 type)
ptaReverse()
Definition: ptafunc1.c:257
l_ok pixRasterop(PIX *pixd, l_int32 dx, l_int32 dy, l_int32 dw, l_int32 dh, l_int32 op, PIX *pixs, l_int32 sx, l_int32 sy)
pixRasterop()
Definition: rop.c:204
SARRAY * sarrayCreate(l_int32 n)
sarrayCreate()
Definition: sarray1.c:170
char * sarrayToString(SARRAY *sa, l_int32 addnlflag)
sarrayToString()
Definition: sarray1.c:785
void sarrayDestroy(SARRAY **psa)
sarrayDestroy()
Definition: sarray1.c:362
l_ok sarrayAddString(SARRAY *sa, const char *string, l_int32 copyflag)
sarrayAddString()
Definition: sarray1.c:451
PIX * pixSeedfillBinary(PIX *pixd, PIX *pixs, PIX *pixm, l_int32 connectivity)
pixSeedfillBinary()
Definition: seedfill.c:247
PIX * pixFillClosedBorders(PIX *pixs, l_int32 connectivity)
pixFillClosedBorders()
Definition: seedfill.c:660
PIX * pixHolesByFilling(PIX *pixs, l_int32 connectivity)
pixHolesByFilling()
Definition: seedfill.c:609
Definition: pix.h:481
l_int32 y
Definition: pix.h:483
l_int32 x
Definition: pix.h:482
l_int32 w
Definition: pix.h:484
l_int32 h
Definition: pix.h:485
Definition: pix.h:492
Definition: ccbord.h:94
struct Ptaa * global
Definition: ccbord.h:100
struct Pta * spglobal
Definition: ccbord.h:103
struct Numaa * step
Definition: ccbord.h:101
struct Pta * start
Definition: ccbord.h:97
struct Boxa * boxa
Definition: ccbord.h:96
struct Pix * pix
Definition: ccbord.h:95
struct Ptaa * local
Definition: ccbord.h:99
struct Pta * splocal
Definition: ccbord.h:102
l_int32 refcount
Definition: ccbord.h:98
l_int32 w
Definition: ccbord.h:111
l_int32 n
Definition: ccbord.h:113
l_int32 nalloc
Definition: ccbord.h:114
struct CCBord ** ccb
Definition: ccbord.h:115
l_int32 h
Definition: ccbord.h:112
struct Pix * pix
Definition: ccbord.h:110
Definition: array.h:71
Definition: array.h:83
Definition: pix.h:139
Definition: pix.h:456
Definition: pix.h:517
Definition: pix.h:531
Definition: array.h:127
void lept_stderr(const char *fmt,...)
lept_stderr()
Definition: utils1.c:306
FILE * fopenWriteStream(const char *filename, const char *modestring)
fopenWriteStream()
Definition: utils2.c:1975
FILE * fopenReadStream(const char *filename)
fopenReadStream()
Definition: utils2.c:1932
l_uint8 * l_binaryReadStream(FILE *fp, size_t *pnbytes)
l_binaryReadStream()
Definition: utils2.c:1402
void * reallocNew(void **pindata, size_t oldsize, size_t newsize)
reallocNew()
Definition: utils2.c:1302
l_ok l_binaryWrite(const char *filename, const char *operation, const void *data, size_t nbytes)
l_binaryWrite()
Definition: utils2.c:1569
l_uint8 * zlibCompress(const l_uint8 *datain, size_t nin, size_t *pnout)
zlibCompress()
Definition: zlibmem.c:92
l_uint8 * zlibUncompress(const l_uint8 *datain, size_t nin, size_t *pnout)
zlibUncompress()
Definition: zlibmem.c:196