Leptonica  1.77.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 
257 static 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 */
261 static 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. */
276 static const l_int32 xpostab[] = {-1, -1, 0, 1, 1, 1, 0, -1};
277 static const l_int32 ypostab[] = {0, -1, -1, -1, 0, 1, 1, 1};
278 static const l_int32 qpostab[] = {6, 6, 0, 0, 2, 2, 4, 4};
279 
280  /* Static function */
281 static l_int32 ccbaExtendArray(CCBORDA *ccba);
282 
283 #ifndef NO_CONSOLE_IO
284 #define DEBUG_PRINT 0
285 #endif /* NO CONSOLE_IO */
286 
287 
288 /*---------------------------------------------------------------------*
289  * ccba and ccb creation and destruction *
290  *---------------------------------------------------------------------*/
298 CCBORDA *
300  l_int32 n)
301 {
302 CCBORDA *ccba;
303 
304  PROCNAME("ccbaCreate");
305 
306  if (n <= 0)
307  n = INITIAL_PTR_ARRAYSIZE;
308 
309  ccba = (CCBORDA *)LEPT_CALLOC(1, sizeof(CCBORDA));
310  if (pixs) {
311  ccba->pix = pixClone(pixs);
312  ccba->w = pixGetWidth(pixs);
313  ccba->h = pixGetHeight(pixs);
314  }
315  ccba->n = 0;
316  ccba->nalloc = n;
317  if ((ccba->ccb = (CCBORD **)LEPT_CALLOC(n, sizeof(CCBORD *))) == NULL) {
318  ccbaDestroy(&ccba);
319  return (CCBORDA *)ERROR_PTR("ccba ptrs not made", procName, NULL);
320  }
321  return ccba;
322 }
323 
324 
331 void
333 {
334 l_int32 i;
335 CCBORDA *ccba;
336 
337  PROCNAME("ccbaDestroy");
338 
339  if (pccba == NULL) {
340  L_WARNING("ptr address is NULL!\n", procName);
341  return;
342  }
343 
344  if ((ccba = *pccba) == NULL)
345  return;
346 
347  pixDestroy(&ccba->pix);
348  for (i = 0; i < ccba->n; i++)
349  ccbDestroy(&ccba->ccb[i]);
350  LEPT_FREE(ccba->ccb);
351  LEPT_FREE(ccba);
352  *pccba = NULL;
353  return;
354 }
355 
356 
363 CCBORD *
365 {
366 BOXA *boxa;
367 CCBORD *ccb;
368 PTA *start;
369 PTAA *local;
370 
371  PROCNAME("ccbCreate");
372 
373  if (pixs) {
374  if (pixGetDepth(pixs) != 1)
375  return (CCBORD *)ERROR_PTR("pixs not binary", procName, NULL);
376  }
377 
378  if ((ccb = (CCBORD *)LEPT_CALLOC(1, sizeof(CCBORD))) == NULL)
379  return (CCBORD *)ERROR_PTR("ccb not made", procName, NULL);
380  ccb->refcount++;
381  if (pixs)
382  ccb->pix = pixClone(pixs);
383  if ((boxa = boxaCreate(1)) == NULL)
384  return (CCBORD *)ERROR_PTR("boxa not made", procName, NULL);
385  ccb->boxa = boxa;
386  if ((start = ptaCreate(1)) == NULL)
387  return (CCBORD *)ERROR_PTR("start pta not made", procName, NULL);
388  ccb->start = start;
389  if ((local = ptaaCreate(1)) == NULL)
390  return (CCBORD *)ERROR_PTR("local ptaa not made", procName, NULL);
391  ccb->local = local;
392 
393  return ccb;
394 }
395 
396 
403 void
405 {
406 CCBORD *ccb;
407 
408  PROCNAME("ccbDestroy");
409 
410  if (pccb == NULL) {
411  L_WARNING("ptr address is NULL!\n", procName);
412  return;
413  }
414 
415  if ((ccb = *pccb) == NULL)
416  return;
417 
418  ccb->refcount--;
419  if (ccb->refcount == 0) {
420  if (ccb->pix)
421  pixDestroy(&ccb->pix);
422  if (ccb->boxa)
423  boxaDestroy(&ccb->boxa);
424  if (ccb->start)
425  ptaDestroy(&ccb->start);
426  if (ccb->local)
427  ptaaDestroy(&ccb->local);
428  if (ccb->global)
429  ptaaDestroy(&ccb->global);
430  if (ccb->step)
431  numaaDestroy(&ccb->step);
432  if (ccb->splocal)
433  ptaDestroy(&ccb->splocal);
434  if (ccb->spglobal)
435  ptaDestroy(&ccb->spglobal);
436  LEPT_FREE(ccb);
437  *pccb = NULL;
438  }
439  return;
440 }
441 
442 
443 /*---------------------------------------------------------------------*
444  * ccba addition *
445  *---------------------------------------------------------------------*/
453 l_ok
455  CCBORD *ccb)
456 {
457 l_int32 n;
458 
459  PROCNAME("ccbaAddCcb");
460 
461  if (!ccba)
462  return ERROR_INT("ccba not defined", procName, 1);
463  if (!ccb)
464  return ERROR_INT("ccb not defined", procName, 1);
465 
466  n = ccbaGetCount(ccba);
467  if (n >= ccba->nalloc)
468  ccbaExtendArray(ccba);
469  ccba->ccb[n] = ccb;
470  ccba->n++;
471  return 0;
472 }
473 
474 
481 static l_int32
483 {
484  PROCNAME("ccbaExtendArray");
485 
486  if (!ccba)
487  return ERROR_INT("ccba not defined", procName, 1);
488 
489  if ((ccba->ccb = (CCBORD **)reallocNew((void **)&ccba->ccb,
490  sizeof(CCBORD *) * ccba->nalloc,
491  2 * sizeof(CCBORD *) * ccba->nalloc)) == NULL)
492  return ERROR_INT("new ptr array not returned", procName, 1);
493 
494  ccba->nalloc = 2 * ccba->nalloc;
495  return 0;
496 }
497 
498 
499 
500 /*---------------------------------------------------------------------*
501  * ccba accessors *
502  *---------------------------------------------------------------------*/
509 l_int32
511 {
512 
513  PROCNAME("ccbaGetCount");
514 
515  if (!ccba)
516  return ERROR_INT("ccba not defined", procName, 0);
517 
518  return ccba->n;
519 }
520 
521 
534 CCBORD *
536  l_int32 index)
537 {
538 CCBORD *ccb;
539 
540  PROCNAME("ccbaGetCcb");
541 
542  if (!ccba)
543  return (CCBORD *)ERROR_PTR("ccba not defined", procName, NULL);
544  if (index < 0 || index >= ccba->n)
545  return (CCBORD *)ERROR_PTR("index out of bounds", procName, NULL);
546 
547  ccb = ccba->ccb[index];
548  ccb->refcount++;
549  return ccb;
550 }
551 
552 
553 
554 /*---------------------------------------------------------------------*
555  * Top-level border-finding routines *
556  *---------------------------------------------------------------------*/
563 CCBORDA *
565 {
566 l_int32 n, i;
567 BOX *box;
568 BOXA *boxa;
569 CCBORDA *ccba;
570 CCBORD *ccb;
571 PIX *pix;
572 PIXA *pixa;
573 
574  PROCNAME("pixGetAllCCBorders");
575 
576  if (!pixs)
577  return (CCBORDA *)ERROR_PTR("pixs not defined", procName, NULL);
578  if (pixGetDepth(pixs) != 1)
579  return (CCBORDA *)ERROR_PTR("pixs not binary", procName, NULL);
580 
581  if ((boxa = pixConnComp(pixs, &pixa, 8)) == NULL)
582  return (CCBORDA *)ERROR_PTR("boxa not made", procName, NULL);
583  n = boxaGetCount(boxa);
584 
585  if ((ccba = ccbaCreate(pixs, n)) == NULL) {
586  boxaDestroy(&boxa);
587  pixaDestroy(&pixa);
588  return (CCBORDA *)ERROR_PTR("ccba not made", procName, NULL);
589  }
590  for (i = 0; i < n; i++) {
591  if ((pix = pixaGetPix(pixa, i, L_CLONE)) == NULL) {
592  ccbaDestroy(&ccba);
593  pixaDestroy(&pixa);
594  boxaDestroy(&boxa);
595  return (CCBORDA *)ERROR_PTR("pix not found", procName, NULL);
596  }
597  if ((box = pixaGetBox(pixa, i, L_CLONE)) == NULL) {
598  ccbaDestroy(&ccba);
599  pixaDestroy(&pixa);
600  boxaDestroy(&boxa);
601  pixDestroy(&pix);
602  return (CCBORDA *)ERROR_PTR("box not found", procName, NULL);
603  }
604  ccb = pixGetCCBorders(pix, box);
605  pixDestroy(&pix);
606  boxDestroy(&box);
607  if (!ccb) {
608  ccbaDestroy(&ccba);
609  pixaDestroy(&pixa);
610  boxaDestroy(&boxa);
611  return (CCBORDA *)ERROR_PTR("ccb not made", procName, NULL);
612  }
613 /* ptaWriteStream(stderr, ccb->local, 1); */
614  ccbaAddCcb(ccba, ccb);
615  }
616 
617  boxaDestroy(&boxa);
618  pixaDestroy(&pixa);
619  return ccba;
620 }
621 
622 
649 CCBORD *
651  BOX *box)
652 {
653 l_int32 allzero, i, x, xh, w, nh;
654 l_int32 xs, ys; /* starting hole border pixel, relative in pixs */
655 l_uint32 val;
656 BOX *boxt, *boxe;
657 BOXA *boxa;
658 CCBORD *ccb;
659 PIX *pixh; /* for hole components */
660 PIX *pixt;
661 PIXA *pixa;
662 
663  PROCNAME("pixGetCCBorders");
664 
665  if (!pixs)
666  return (CCBORD *)ERROR_PTR("pixs not defined", procName, NULL);
667  if (!box)
668  return (CCBORD *)ERROR_PTR("box not defined", procName, NULL);
669  if (pixGetDepth(pixs) != 1)
670  return (CCBORD *)ERROR_PTR("pixs not binary", procName, NULL);
671 
672  pixZero(pixs, &allzero);
673  if (allzero)
674  return (CCBORD *)ERROR_PTR("pixs all 0", procName, NULL);
675 
676  if ((ccb = ccbCreate(pixs)) == NULL)
677  return (CCBORD *)ERROR_PTR("ccb not made", procName, NULL);
678 
679  /* Get the exterior border */
680  pixGetOuterBorder(ccb, pixs, box);
681 
682  /* Find the holes, if any */
683  if ((pixh = pixHolesByFilling(pixs, 4)) == NULL) {
684  ccbDestroy(&ccb);
685  return (CCBORD *)ERROR_PTR("pixh not made", procName, NULL);
686  }
687  pixZero(pixh, &allzero);
688  if (allzero) { /* no holes */
689  pixDestroy(&pixh);
690  return ccb;
691  }
692 
693  /* Get c.c. and locations of the holes */
694  if ((boxa = pixConnComp(pixh, &pixa, 4)) == NULL) {
695  ccbDestroy(&ccb);
696  pixDestroy(&pixh);
697  return (CCBORD *)ERROR_PTR("boxa not made", procName, NULL);
698  }
699  nh = boxaGetCount(boxa);
700 /* fprintf(stderr, "%d holes\n", nh); */
701 
702  /* For each hole, find an interior pixel within the hole,
703  * then march to the right and stop at the first border
704  * pixel. Save the bounding box of the border, which
705  * is 1 pixel bigger on each side than the bounding box
706  * of the hole itself. Note that we use a pix of the
707  * c.c. of the hole itself to be sure that we start
708  * with a pixel in the hole of the proper component.
709  * If we did everything from the parent component, it is
710  * possible to start in a different hole that is within
711  * the b.b. of a larger hole. */
712  w = pixGetWidth(pixs);
713  for (i = 0; i < nh; i++) {
714  boxt = boxaGetBox(boxa, i, L_CLONE);
715  pixt = pixaGetPix(pixa, i, L_CLONE);
716  ys = boxt->y; /* there must be a hole pixel on this raster line */
717  for (x = 0; x < boxt->w; x++) { /* look for (fg) hole pixel */
718  pixGetPixel(pixt, x, 0, &val);
719  if (val == 1) {
720  xh = x;
721  break;
722  }
723  }
724  if (x == boxt->w) {
725  L_WARNING("no hole pixel found!\n", procName);
726  continue;
727  }
728  for (x = xh + boxt->x; x < w; x++) { /* look for (fg) border pixel */
729  pixGetPixel(pixs, x, ys, &val);
730  if (val == 1) {
731  xs = x;
732  break;
733  }
734  }
735  boxe = boxCreate(boxt->x - 1, boxt->y - 1, boxt->w + 2, boxt->h + 2);
736 #if DEBUG_PRINT
737  boxPrintStreamInfo(stderr, box);
738  boxPrintStreamInfo(stderr, boxe);
739  fprintf(stderr, "xs = %d, ys = %d\n", xs, ys);
740 #endif /* DEBUG_PRINT */
741  pixGetHoleBorder(ccb, pixs, boxe, xs, ys);
742  boxDestroy(&boxt);
743  boxDestroy(&boxe);
744  pixDestroy(&pixt);
745  }
746 
747  boxaDestroy(&boxa);
748  pixaDestroy(&pixa);
749  pixDestroy(&pixh);
750  return ccb;
751 }
752 
753 
760 PTAA *
762 {
763 l_int32 i, n;
764 BOX *box;
765 BOXA *boxa;
766 PIX *pix;
767 PIXA *pixa;
768 PTA *pta;
769 PTAA *ptaa;
770 
771  PROCNAME("pixGetOuterBordersPtaa");
772 
773  if (!pixs)
774  return (PTAA *)ERROR_PTR("pixs not defined", procName, NULL);
775  if (pixGetDepth(pixs) != 1)
776  return (PTAA *)ERROR_PTR("pixs not binary", procName, NULL);
777 
778  boxa = pixConnComp(pixs, &pixa, 8);
779  n = boxaGetCount(boxa);
780  if (n == 0) {
781  boxaDestroy(&boxa);
782  pixaDestroy(&pixa);
783  return (PTAA *)ERROR_PTR("pixs empty", procName, NULL);
784  }
785 
786  ptaa = ptaaCreate(n);
787  for (i = 0; i < n; i++) {
788  box = boxaGetBox(boxa, i, L_CLONE);
789  pix = pixaGetPix(pixa, i, L_CLONE);
790  pta = pixGetOuterBorderPta(pix, box);
791  if (pta)
792  ptaaAddPta(ptaa, pta, L_INSERT);
793  boxDestroy(&box);
794  pixDestroy(&pix);
795  }
796 
797  pixaDestroy(&pixa);
798  boxaDestroy(&boxa);
799  return ptaa;
800 }
801 
802 
820 PTA *
822  BOX *box)
823 {
824 l_int32 allzero, x, y;
825 BOX *boxt;
826 CCBORD *ccb;
827 PTA *ptaloc, *ptad;
828 
829  PROCNAME("pixGetOuterBorderPta");
830 
831  if (!pixs)
832  return (PTA *)ERROR_PTR("pixs not defined", procName, NULL);
833  if (pixGetDepth(pixs) != 1)
834  return (PTA *)ERROR_PTR("pixs not binary", procName, NULL);
835 
836  pixZero(pixs, &allzero);
837  if (allzero)
838  return (PTA *)ERROR_PTR("pixs all 0", procName, NULL);
839 
840  if ((ccb = ccbCreate(pixs)) == NULL)
841  return (PTA *)ERROR_PTR("ccb not made", procName, NULL);
842  if (!box)
843  boxt = boxCreate(0, 0, pixGetWidth(pixs), pixGetHeight(pixs));
844  else
845  boxt = boxClone(box);
846 
847  /* Get the exterior border in local coords */
848  pixGetOuterBorder(ccb, pixs, boxt);
849  if ((ptaloc = ptaaGetPta(ccb->local, 0, L_CLONE)) == NULL) {
850  ccbDestroy(&ccb);
851  boxDestroy(&boxt);
852  return (PTA *)ERROR_PTR("ptaloc not made", procName, NULL);
853  }
854 
855  /* Transform to global coordinates, if they are given */
856  if (box) {
857  boxGetGeometry(box, &x, &y, NULL, NULL);
858  ptad = ptaTransform(ptaloc, x, y, 1.0, 1.0);
859  } else {
860  ptad = ptaClone(ptaloc);
861  }
862 
863  ptaDestroy(&ptaloc);
864  boxDestroy(&boxt);
865  ccbDestroy(&ccb);
866  return ptad;
867 }
868 
869 
870 /*---------------------------------------------------------------------*
871  * Lower-level border-finding routines *
872  *---------------------------------------------------------------------*/
893 l_ok
895  PIX *pixs,
896  BOX *box)
897 {
898 l_int32 fpx, fpy, spx, spy, qpos;
899 l_int32 px, py, npx, npy;
900 l_int32 w, h, wpl;
901 l_uint32 *data;
902 PTA *pta;
903 PIX *pixb; /* with 1 pixel border */
904 
905  PROCNAME("pixGetOuterBorder");
906 
907  if (!ccb)
908  return ERROR_INT("ccb not defined", procName, 1);
909  if (!pixs)
910  return ERROR_INT("pixs not defined", procName, 1);
911  if (!box)
912  return ERROR_INT("box not defined", procName, 1);
913 
914  /* Add 1-pixel border all around, and find start pixel */
915  if ((pixb = pixAddBorder(pixs, 1, 0)) == NULL)
916  return ERROR_INT("pixs not made", procName, 1);
917  if (!nextOnPixelInRaster(pixb, 1, 1, &px, &py)) {
918  pixDestroy(&pixb);
919  return ERROR_INT("no start pixel found", procName, 1);
920  }
921  qpos = 0; /* relative to p */
922  fpx = px; /* save location of first pixel on border */
923  fpy = py;
924 
925  /* Save box and start pixel in relative coords */
926  boxaAddBox(ccb->boxa, box, L_COPY);
927  ptaAddPt(ccb->start, px - 1, py - 1);
928 
929  pta = ptaCreate(0);
930  ptaaAddPta(ccb->local, pta, L_INSERT);
931  ptaAddPt(pta, px - 1, py - 1); /* initial point */
932  pixGetDimensions(pixb, &w, &h, NULL);
933  data = pixGetData(pixb);
934  wpl = pixGetWpl(pixb);
935 
936  /* Get the second point; if there is none, return */
937  if (findNextBorderPixel(w, h, data, wpl, px, py, &qpos, &npx, &npy)) {
938  pixDestroy(&pixb);
939  return 0;
940  }
941 
942  spx = npx; /* save location of second pixel on border */
943  spy = npy;
944  ptaAddPt(pta, npx - 1, npy - 1); /* second point */
945  px = npx;
946  py = npy;
947 
948  while (1) {
949  findNextBorderPixel(w, h, data, wpl, px, py, &qpos, &npx, &npy);
950  if (px == fpx && py == fpy && npx == spx && npy == spy)
951  break;
952  ptaAddPt(pta, npx - 1, npy - 1);
953  px = npx;
954  py = npy;
955  }
956 
957  pixDestroy(&pixb);
958  return 0;
959 }
960 
961 
981 l_ok
983  PIX *pixs,
984  BOX *box,
985  l_int32 xs,
986  l_int32 ys)
987 {
988 l_int32 fpx, fpy, spx, spy, qpos;
989 l_int32 px, py, npx, npy;
990 l_int32 w, h, wpl;
991 l_uint32 *data;
992 PTA *pta;
993 
994  PROCNAME("pixGetHoleBorder");
995 
996  if (!ccb)
997  return ERROR_INT("ccb not defined", procName, 1);
998  if (!pixs)
999  return ERROR_INT("pixs not defined", procName, 1);
1000  if (!box)
1001  return ERROR_INT("box not defined", procName, 1);
1002 
1003  /* Add border and find start pixel */
1004  qpos = 0; /* orientation of Q relative to P */
1005  fpx = xs; /* save location of first pixel on border */
1006  fpy = ys;
1007 
1008  /* Save box and start pixel */
1009  boxaAddBox(ccb->boxa, box, L_COPY);
1010  ptaAddPt(ccb->start, xs, ys);
1011 
1012  if ((pta = ptaCreate(0)) == NULL)
1013  return ERROR_INT("pta not made", procName, 1);
1014  ptaaAddPta(ccb->local, pta, L_INSERT);
1015  ptaAddPt(pta, xs, ys); /* initial pixel */
1016 
1017  w = pixGetWidth(pixs);
1018  h = pixGetHeight(pixs);
1019  data = pixGetData(pixs);
1020  wpl = pixGetWpl(pixs);
1021 
1022  /* Get the second point; there should always be at least 4 pts
1023  * in a minimal hole border! */
1024  if (findNextBorderPixel(w, h, data, wpl, xs, ys, &qpos, &npx, &npy))
1025  return ERROR_INT("isolated hole border point!", procName, 1);
1026 
1027  spx = npx; /* save location of second pixel on border */
1028  spy = npy;
1029  ptaAddPt(pta, npx, npy); /* second pixel */
1030  px = npx;
1031  py = npy;
1032 
1033  while (1) {
1034  findNextBorderPixel(w, h, data, wpl, px, py, &qpos, &npx, &npy);
1035  if (px == fpx && py == fpy && npx == spx && npy == spy)
1036  break;
1037  ptaAddPt(pta, npx, npy);
1038  px = npx;
1039  py = npy;
1040  }
1041 
1042  return 0;
1043 }
1044 
1045 
1063 l_int32
1065  l_int32 h,
1066  l_uint32 *data,
1067  l_int32 wpl,
1068  l_int32 px,
1069  l_int32 py,
1070  l_int32 *pqpos,
1071  l_int32 *pnpx,
1072  l_int32 *pnpy)
1073 {
1074 l_int32 qpos, i, pos, npx, npy, val;
1075 l_uint32 *line;
1076 
1077  qpos = *pqpos;
1078  for (i = 1; i < 8; i++) {
1079  pos = (qpos + i) % 8;
1080  npx = px + xpostab[pos];
1081  npy = py + ypostab[pos];
1082  line = data + npy * wpl;
1083  val = GET_DATA_BIT(line, npx);
1084  if (val) {
1085  *pnpx = npx;
1086  *pnpy = npy;
1087  *pqpos = qpostab[pos];
1088  return 0;
1089  }
1090  }
1091 
1092  return 1;
1093 }
1094 
1095 
1114 void
1116  l_int32 fpy,
1117  l_int32 spx,
1118  l_int32 spy,
1119  l_int32 *pxs,
1120  l_int32 *pys)
1121 {
1122 l_int32 dx, dy;
1123 
1124  dx = spx - fpx;
1125  dy = spy - fpy;
1126 
1127  if (dx * dy == 1) {
1128  *pxs = fpx + dx;
1129  *pys = fpy;
1130  } else if (dx * dy == -1) {
1131  *pxs = fpx;
1132  *pys = fpy + dy;
1133  } else if (dx == 0) {
1134  *pxs = fpx + dy;
1135  *pys = fpy + dy;
1136  } else /* dy == 0 */ {
1137  *pxs = fpx + dx;
1138  *pys = fpy - dx;
1139  }
1140 
1141  return;
1142 }
1143 
1144 
1145 
1146 /*---------------------------------------------------------------------*
1147  * Border conversions *
1148  *---------------------------------------------------------------------*/
1159 l_ok
1161 {
1162 l_int32 ncc, nb, n, i, j, k, xul, yul, x, y;
1163 CCBORD *ccb;
1164 PTAA *ptaal, *ptaag;
1165 PTA *ptal, *ptag;
1166 
1167  PROCNAME("ccbaGenerateGlobalLocs");
1168 
1169  if (!ccba)
1170  return ERROR_INT("ccba not defined", procName, 1);
1171 
1172  ncc = ccbaGetCount(ccba); /* number of c.c. */
1173  for (i = 0; i < ncc; i++) {
1174  ccb = ccbaGetCcb(ccba, i);
1175 
1176  /* Get the UL corner in global coords, (xul, yul), of the c.c. */
1177  boxaGetBoxGeometry(ccb->boxa, 0, &xul, &yul, NULL, NULL);
1178 
1179  /* Make a new global ptaa, removing any old one */
1180  ptaal = ccb->local;
1181  nb = ptaaGetCount(ptaal); /* number of borders */
1182  if (ccb->global) /* remove old one */
1183  ptaaDestroy(&ccb->global);
1184  if ((ptaag = ptaaCreate(nb)) == NULL)
1185  return ERROR_INT("ptaag not made", procName, 1);
1186  ccb->global = ptaag; /* save new one */
1187 
1188  /* Iterate through the borders for this c.c. */
1189  for (j = 0; j < nb; j++) {
1190  ptal = ptaaGetPta(ptaal, j, L_CLONE);
1191  n = ptaGetCount(ptal); /* number of pixels in border */
1192  if ((ptag = ptaCreate(n)) == NULL)
1193  return ERROR_INT("ptag not made", procName, 1);
1194  ptaaAddPta(ptaag, ptag, L_INSERT);
1195  for (k = 0; k < n; k++) {
1196  ptaGetIPt(ptal, k, &x, &y);
1197  ptaAddPt(ptag, x + xul, y + yul);
1198  }
1199  ptaDestroy(&ptal);
1200  }
1201  ccbDestroy(&ccb);
1202  }
1203 
1204  return 0;
1205 }
1206 
1207 
1230 l_ok
1232 {
1233 l_int32 ncc, nb, n, i, j, k;
1234 l_int32 px, py, cx, cy, stepdir;
1235 l_int32 dirtab[][3] = {{1, 2, 3}, {0, -1, 4}, {7, 6, 5}};
1236 CCBORD *ccb;
1237 NUMA *na;
1238 NUMAA *naa; /* step chain code; to be made */
1239 PTA *ptal;
1240 PTAA *ptaal; /* local chain code */
1241 
1242  PROCNAME("ccbaGenerateStepChains");
1243 
1244  if (!ccba)
1245  return ERROR_INT("ccba not defined", procName, 1);
1246 
1247  ncc = ccbaGetCount(ccba); /* number of c.c. */
1248  for (i = 0; i < ncc; i++) {
1249  ccb = ccbaGetCcb(ccba, i);
1250 
1251  /* Make a new step numaa, removing any old one */
1252  ptaal = ccb->local;
1253  nb = ptaaGetCount(ptaal); /* number of borders */
1254  if (ccb->step) /* remove old one */
1255  numaaDestroy(&ccb->step);
1256  if ((naa = numaaCreate(nb)) == NULL)
1257  return ERROR_INT("naa not made", procName, 1);
1258  ccb->step = naa; /* save new one */
1259 
1260  /* Iterate through the borders for this c.c. */
1261  for (j = 0; j < nb; j++) {
1262  ptal = ptaaGetPta(ptaal, j, L_CLONE);
1263  n = ptaGetCount(ptal); /* number of pixels in border */
1264  if (n == 1) { /* isolated pixel */
1265  na = numaCreate(1); /* but leave it empty */
1266  } else { /* trace out the boundary */
1267  if ((na = numaCreate(n)) == NULL)
1268  return ERROR_INT("na not made", procName, 1);
1269  ptaGetIPt(ptal, 0, &px, &py);
1270  for (k = 1; k < n; k++) {
1271  ptaGetIPt(ptal, k, &cx, &cy);
1272  stepdir = dirtab[1 + cy - py][1 + cx - px];
1273  numaAddNumber(na, stepdir);
1274  px = cx;
1275  py = cy;
1276  }
1277  }
1278  numaaAddNuma(naa, na, L_INSERT);
1279  ptaDestroy(&ptal);
1280  }
1281  ccbDestroy(&ccb); /* just decrement refcount */
1282  }
1283 
1284  return 0;
1285 }
1286 
1287 
1304 l_ok
1306  l_int32 coordtype)
1307 {
1308 l_int32 ncc, nb, n, i, j, k;
1309 l_int32 xul, yul, xstart, ystart, x, y, stepdir;
1310 BOXA *boxa;
1311 CCBORD *ccb;
1312 NUMA *na;
1313 NUMAA *naa;
1314 PTAA *ptaan; /* new pix coord ptaa */
1315 PTA *ptas, *ptan;
1316 
1317  PROCNAME("ccbaStepChainsToPixCoords");
1318 
1319  if (!ccba)
1320  return ERROR_INT("ccba not defined", procName, 1);
1321  if (coordtype != CCB_GLOBAL_COORDS && coordtype != CCB_LOCAL_COORDS)
1322  return ERROR_INT("coordtype not valid", procName, 1);
1323 
1324  ncc = ccbaGetCount(ccba); /* number of c.c. */
1325  for (i = 0; i < ncc; i++) {
1326  ccb = ccbaGetCcb(ccba, i);
1327  if ((naa = ccb->step) == NULL)
1328  return ERROR_INT("step numaa not found", procName, 1);
1329  if ((boxa = ccb->boxa) == NULL)
1330  return ERROR_INT("boxa not found", procName, 1);
1331  if ((ptas = ccb->start) == NULL)
1332  return ERROR_INT("start pta not found", procName, 1);
1333 
1334  /* For global coords, get the (xul, yul) of the c.c.;
1335  * otherwise, use relative coords. */
1336  if (coordtype == CCB_LOCAL_COORDS) {
1337  xul = 0;
1338  yul = 0;
1339  } else { /* coordtype == CCB_GLOBAL_COORDS */
1340  /* Get UL corner in global coords */
1341  if (boxaGetBoxGeometry(boxa, 0, &xul, &yul, NULL, NULL))
1342  return ERROR_INT("bounding rectangle not found", procName, 1);
1343  }
1344 
1345  /* Make a new ptaa, removing any old one */
1346  nb = numaaGetCount(naa); /* number of borders */
1347  if ((ptaan = ptaaCreate(nb)) == NULL)
1348  return ERROR_INT("ptaan not made", procName, 1);
1349  if (coordtype == CCB_LOCAL_COORDS) {
1350  if (ccb->local) /* remove old one */
1351  ptaaDestroy(&ccb->local);
1352  ccb->local = ptaan; /* save new local chain */
1353  } else { /* coordtype == CCB_GLOBAL_COORDS */
1354  if (ccb->global) /* remove old one */
1355  ptaaDestroy(&ccb->global);
1356  ccb->global = ptaan; /* save new global chain */
1357  }
1358 
1359  /* Iterate through the borders for this c.c. */
1360  for (j = 0; j < nb; j++) {
1361  na = numaaGetNuma(naa, j, L_CLONE);
1362  n = numaGetCount(na); /* number of steps in border */
1363  if ((ptan = ptaCreate(n + 1)) == NULL)
1364  return ERROR_INT("ptan not made", procName, 1);
1365  ptaaAddPta(ptaan, ptan, L_INSERT);
1366  ptaGetIPt(ptas, j, &xstart, &ystart);
1367  x = xul + xstart;
1368  y = yul + ystart;
1369  ptaAddPt(ptan, x, y);
1370  for (k = 0; k < n; k++) {
1371  numaGetIValue(na, k, &stepdir);
1372  x += xpostab[stepdir];
1373  y += ypostab[stepdir];
1374  ptaAddPt(ptan, x, y);
1375  }
1376  numaDestroy(&na);
1377  }
1378  ccbDestroy(&ccb);
1379  }
1380 
1381  return 0;
1382 }
1383 
1384 
1404 l_ok
1406  l_int32 ptsflag)
1407 {
1408 l_int32 ncc, npt, i, j, xul, yul, x, y, delx, dely;
1409 l_int32 xp, yp, delxp, delyp; /* prev point and increments */
1410 CCBORD *ccb;
1411 PTA *ptal, *ptag;
1412 
1413  PROCNAME("ccbaGenerateSPGlobalLocs");
1414 
1415  if (!ccba)
1416  return ERROR_INT("ccba not defined", procName, 1);
1417 
1418  /* Make sure we have a local single path representation */
1419  if ((ccb = ccbaGetCcb(ccba, 0)) == NULL)
1420  return ERROR_INT("no ccb", procName, 1);
1421  if (!ccb->splocal)
1422  ccbaGenerateSinglePath(ccba);
1423  ccbDestroy(&ccb); /* clone ref */
1424 
1425  ncc = ccbaGetCount(ccba); /* number of c.c. */
1426  for (i = 0; i < ncc; i++) {
1427  ccb = ccbaGetCcb(ccba, i);
1428 
1429  /* Get the UL corner in global coords, (xul, yul), of the c.c. */
1430  if (boxaGetBoxGeometry(ccb->boxa, 0, &xul, &yul, NULL, NULL))
1431  return ERROR_INT("bounding rectangle not found", procName, 1);
1432 
1433  /* Make a new spglobal pta, removing any old one */
1434  ptal = ccb->splocal;
1435  npt = ptaGetCount(ptal); /* number of points */
1436  if (ccb->spglobal) /* remove old one */
1437  ptaDestroy(&ccb->spglobal);
1438  if ((ptag = ptaCreate(npt)) == NULL)
1439  return ERROR_INT("ptag not made", procName, 1);
1440  ccb->spglobal = ptag; /* save new one */
1441 
1442  /* Convert local to global */
1443  if (ptsflag == CCB_SAVE_ALL_PTS) {
1444  for (j = 0; j < npt; j++) {
1445  ptaGetIPt(ptal, j, &x, &y);
1446  ptaAddPt(ptag, x + xul, y + yul);
1447  }
1448  } else { /* ptsflag = CCB_SAVE_TURNING_PTS */
1449  ptaGetIPt(ptal, 0, &xp, &yp); /* get the 1st pt */
1450  ptaAddPt(ptag, xp + xul, yp + yul); /* save the 1st pt */
1451  if (npt == 2) { /* get and save the 2nd pt */
1452  ptaGetIPt(ptal, 1, &x, &y);
1453  ptaAddPt(ptag, x + xul, y + yul);
1454  } else if (npt > 2) {
1455  ptaGetIPt(ptal, 1, &x, &y);
1456  delxp = x - xp;
1457  delyp = y - yp;
1458  xp = x;
1459  yp = y;
1460  for (j = 2; j < npt; j++) {
1461  ptaGetIPt(ptal, j, &x, &y);
1462  delx = x - xp;
1463  dely = y - yp;
1464  if (delx != delxp || dely != delyp)
1465  ptaAddPt(ptag, xp + xul, yp + yul);
1466  xp = x;
1467  yp = y;
1468  delxp = delx;
1469  delyp = dely;
1470  }
1471  ptaAddPt(ptag, xp + xul, yp + yul);
1472  }
1473  }
1474 
1475  ccbDestroy(&ccb); /* clone ref */
1476  }
1477 
1478  return 0;
1479 }
1480 
1481 
1482 
1483 /*---------------------------------------------------------------------*
1484  * Conversion to single path *
1485  *---------------------------------------------------------------------*/
1521 l_ok
1523 {
1524 l_int32 i, j, k, ncc, nb, ncut, npt, dir, len, state, lostholes;
1525 l_int32 x, y, xl, yl, xf, yf;
1526 BOX *boxinner;
1527 BOXA *boxa;
1528 CCBORD *ccb;
1529 PTA *pta, *ptac, *ptah;
1530 PTA *ptahc; /* cyclic permutation of hole border, with end pts at cut */
1531 PTA *ptas; /* output result: new single path for c.c. */
1532 PTA *ptaf; /* points on the hole borders that intersect with cuts */
1533 PTA *ptal; /* points on outer border that intersect with cuts */
1534 PTA *ptap, *ptarp; /* path and reverse path between borders */
1535 PTAA *ptaa;
1536 PTAA *ptaap; /* ptaa for all paths between borders */
1537 
1538  PROCNAME("ccbaGenerateSinglePath");
1539 
1540  if (!ccba)
1541  return ERROR_INT("ccba not defined", procName, 1);
1542 
1543  ncc = ccbaGetCount(ccba); /* number of c.c. */
1544  lostholes = 0;
1545  for (i = 0; i < ncc; i++) {
1546  ccb = ccbaGetCcb(ccba, i);
1547  if ((ptaa = ccb->local) == NULL) {
1548  L_WARNING("local pixel loc array not found\n", procName);
1549  continue;
1550  }
1551  nb = ptaaGetCount(ptaa); /* number of borders in the c.c. */
1552 
1553  /* Prepare the output pta */
1554  if (ccb->splocal)
1555  ptaDestroy(&ccb->splocal);
1556  ptas = ptaCreate(0);
1557  ccb->splocal = ptas;
1558 
1559  /* If no holes, just concat the outer border */
1560  pta = ptaaGetPta(ptaa, 0, L_CLONE);
1561  if (nb == 1 || nb > NMAX_HOLES + 1) {
1562  ptaJoin(ptas, pta, 0, -1);
1563  ptaDestroy(&pta); /* remove clone */
1564  ccbDestroy(&ccb); /* remove clone */
1565  continue;
1566  }
1567 
1568  /* Find the (nb - 1) cut paths that connect holes
1569  * with outer border */
1570  boxa = ccb->boxa;
1571  ptaap = ptaaCreate(nb - 1);
1572  ptaf = ptaCreate(nb - 1);
1573  ptal = ptaCreate(nb - 1);
1574  for (j = 1; j < nb; j++) {
1575  boxinner = boxaGetBox(boxa, j, L_CLONE);
1576 
1577  /* Find a short path and store it */
1578  ptac = getCutPathForHole(ccb->pix, pta, boxinner, &dir, &len);
1579  if (len == 0) { /* bad: we lose the hole! */
1580  lostholes++;
1581 /* boxPrintStreamInfo(stderr, boxa->box[0]); */
1582  }
1583  ptaaAddPta(ptaap, ptac, L_INSERT);
1584 /* fprintf(stderr, "dir = %d, length = %d\n", dir, len); */
1585 /* ptaWriteStream(stderr, ptac, 1); */
1586 
1587  /* Store the first and last points in the cut path,
1588  * which must be on a hole border and the outer
1589  * border, respectively */
1590  ncut = ptaGetCount(ptac);
1591  if (ncut == 0) { /* missed hole; neg coords won't match */
1592  ptaAddPt(ptaf, -1, -1);
1593  ptaAddPt(ptal, -1, -1);
1594  } else {
1595  ptaGetIPt(ptac, 0, &x, &y);
1596  ptaAddPt(ptaf, x, y);
1597  ptaGetIPt(ptac, ncut - 1, &x, &y);
1598  ptaAddPt(ptal, x, y);
1599  }
1600  boxDestroy(&boxinner);
1601  }
1602 
1603  /* Make a single path for the c.c. using these connections */
1604  npt = ptaGetCount(pta); /* outer border pts */
1605  for (k = 0; k < npt; k++) {
1606  ptaGetIPt(pta, k, &x, &y);
1607  if (k == 0) { /* if there is a cut at the first point,
1608  * we can wait until the end to take it */
1609  ptaAddPt(ptas, x, y);
1610  continue;
1611  }
1612  state = L_NOT_FOUND;
1613  for (j = 0; j < nb - 1; j++) { /* iterate over cut end pts */
1614  ptaGetIPt(ptal, j, &xl, &yl); /* cut point on outer border */
1615  if (x == xl && y == yl) { /* take this cut to the hole */
1616  state = L_FOUND;
1617  ptap = ptaaGetPta(ptaap, j, L_CLONE);
1618  ptarp = ptaReverse(ptap, 1);
1619  /* Cut point on hole border: */
1620  ptaGetIPt(ptaf, j, &xf, &yf);
1621  /* Hole border: */
1622  ptah = ptaaGetPta(ptaa, j + 1, L_CLONE);
1623  ptahc = ptaCyclicPerm(ptah, xf, yf);
1624 /* ptaWriteStream(stderr, ptahc, 1); */
1625  ptaJoin(ptas, ptarp, 0, -1);
1626  ptaJoin(ptas, ptahc, 0, -1);
1627  ptaJoin(ptas, ptap, 0, -1);
1628  ptaDestroy(&ptap);
1629  ptaDestroy(&ptarp);
1630  ptaDestroy(&ptah);
1631  ptaDestroy(&ptahc);
1632  break;
1633  }
1634  }
1635  if (state == L_NOT_FOUND)
1636  ptaAddPt(ptas, x, y);
1637  }
1638 
1639 /* ptaWriteStream(stderr, ptas, 1); */
1640  ptaaDestroy(&ptaap);
1641  ptaDestroy(&ptaf);
1642  ptaDestroy(&ptal);
1643  ptaDestroy(&pta); /* remove clone */
1644  ccbDestroy(&ccb); /* remove clone */
1645  }
1646 
1647  if (lostholes > 0)
1648  L_WARNING("***** %d lost holes *****\n", procName, lostholes);
1649 
1650  return 0;
1651 }
1652 
1653 
1679 PTA *
1681  PTA *pta,
1682  BOX *boxinner,
1683  l_int32 *pdir,
1684  l_int32 *plen)
1685 {
1686 l_int32 w, h, nc, x, y, xl, yl, xmid, ymid;
1687 l_uint32 val;
1688 PTA *ptac;
1689 
1690  PROCNAME("getCutPathForHole");
1691 
1692  if (!pix)
1693  return (PTA *)ERROR_PTR("pix not defined", procName, NULL);
1694  if (!pta)
1695  return (PTA *)ERROR_PTR("pta not defined", procName, NULL);
1696  if (!boxinner)
1697  return (PTA *)ERROR_PTR("boxinner not defined", procName, NULL);
1698 
1699  w = pixGetWidth(pix);
1700  h = pixGetHeight(pix);
1701 
1702  if ((ptac = ptaCreate(4)) == NULL)
1703  return (PTA *)ERROR_PTR("ptac not made", procName, NULL);
1704  xmid = boxinner->x + boxinner->w / 2;
1705  ymid = boxinner->y + boxinner->h / 2;
1706 
1707  /* try top first */
1708  for (y = ymid; y >= 0; y--) {
1709  pixGetPixel(pix, xmid, y, &val);
1710  if (val == 1) {
1711  ptaAddPt(ptac, xmid, y);
1712  break;
1713  }
1714  }
1715  for (y = y - 1; y >= 0; y--) {
1716  pixGetPixel(pix, xmid, y, &val);
1717  if (val == 1)
1718  ptaAddPt(ptac, xmid, y);
1719  else
1720  break;
1721  }
1722  nc = ptaGetCount(ptac);
1723  ptaGetIPt(ptac, nc - 1, &xl, &yl);
1724  if (ptaContainsPt(pta, xl, yl)) {
1725  *pdir = 1;
1726  *plen = nc;
1727  return ptac;
1728  }
1729 
1730  /* Next try bottom */
1731  ptaEmpty(ptac);
1732  for (y = ymid; y < h; y++) {
1733  pixGetPixel(pix, xmid, y, &val);
1734  if (val == 1) {
1735  ptaAddPt(ptac, xmid, y);
1736  break;
1737  }
1738  }
1739  for (y = y + 1; y < h; y++) {
1740  pixGetPixel(pix, xmid, y, &val);
1741  if (val == 1)
1742  ptaAddPt(ptac, xmid, y);
1743  else
1744  break;
1745  }
1746  nc = ptaGetCount(ptac);
1747  ptaGetIPt(ptac, nc - 1, &xl, &yl);
1748  if (ptaContainsPt(pta, xl, yl)) {
1749  *pdir = 3;
1750  *plen = nc;
1751  return ptac;
1752  }
1753 
1754  /* Next try left */
1755  ptaEmpty(ptac);
1756  for (x = xmid; x >= 0; x--) {
1757  pixGetPixel(pix, x, ymid, &val);
1758  if (val == 1) {
1759  ptaAddPt(ptac, x, ymid);
1760  break;
1761  }
1762  }
1763  for (x = x - 1; x >= 0; x--) {
1764  pixGetPixel(pix, x, ymid, &val);
1765  if (val == 1)
1766  ptaAddPt(ptac, x, ymid);
1767  else
1768  break;
1769  }
1770  nc = ptaGetCount(ptac);
1771  ptaGetIPt(ptac, nc - 1, &xl, &yl);
1772  if (ptaContainsPt(pta, xl, yl)) {
1773  *pdir = 0;
1774  *plen = nc;
1775  return ptac;
1776  }
1777 
1778  /* Finally try right */
1779  ptaEmpty(ptac);
1780  for (x = xmid; x < w; x++) {
1781  pixGetPixel(pix, x, ymid, &val);
1782  if (val == 1) {
1783  ptaAddPt(ptac, x, ymid);
1784  break;
1785  }
1786  }
1787  for (x = x + 1; x < w; x++) {
1788  pixGetPixel(pix, x, ymid, &val);
1789  if (val == 1)
1790  ptaAddPt(ptac, x, ymid);
1791  else
1792  break;
1793  }
1794  nc = ptaGetCount(ptac);
1795  ptaGetIPt(ptac, nc - 1, &xl, &yl);
1796  if (ptaContainsPt(pta, xl, yl)) {
1797  *pdir = 2;
1798  *plen = nc;
1799  return ptac;
1800  }
1801 
1802  /* If we get here, we've failed! */
1803  ptaEmpty(ptac);
1804  L_WARNING("no path found\n", procName);
1805  *plen = 0;
1806  return ptac;
1807 }
1808 
1809 
1810 
1811 /*---------------------------------------------------------------------*
1812  * Border rendering *
1813  *---------------------------------------------------------------------*/
1827 PIX *
1829 {
1830 l_int32 ncc, nb, n, i, j, k, x, y;
1831 CCBORD *ccb;
1832 PIX *pixd;
1833 PTAA *ptaa;
1834 PTA *pta;
1835 
1836  PROCNAME("ccbaDisplayBorder");
1837 
1838  if (!ccba)
1839  return (PIX *)ERROR_PTR("ccba not defined", procName, NULL);
1840 
1841  if ((pixd = pixCreate(ccba->w, ccba->h, 1)) == NULL)
1842  return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1843  ncc = ccbaGetCount(ccba); /* number of c.c. */
1844  for (i = 0; i < ncc; i++) {
1845  ccb = ccbaGetCcb(ccba, i);
1846  if ((ptaa = ccb->global) == NULL) {
1847  L_WARNING("global pixel loc array not found", procName);
1848  continue;
1849  }
1850  nb = ptaaGetCount(ptaa); /* number of borders in the c.c. */
1851  for (j = 0; j < nb; j++) {
1852  pta = ptaaGetPta(ptaa, j, L_CLONE);
1853  n = ptaGetCount(pta); /* number of pixels in the border */
1854  for (k = 0; k < n; k++) {
1855  ptaGetIPt(pta, k, &x, &y);
1856  pixSetPixel(pixd, x, y, 1);
1857  }
1858  ptaDestroy(&pta);
1859  }
1860  ccbDestroy(&ccb);
1861  }
1862 
1863  return pixd;
1864 }
1865 
1866 
1880 PIX *
1882 {
1883 l_int32 ncc, npt, i, j, x, y;
1884 CCBORD *ccb;
1885 PIX *pixd;
1886 PTA *ptag;
1887 
1888  PROCNAME("ccbaDisplaySPBorder");
1889 
1890  if (!ccba)
1891  return (PIX *)ERROR_PTR("ccba not defined", procName, NULL);
1892 
1893  if ((pixd = pixCreate(ccba->w, ccba->h, 1)) == NULL)
1894  return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1895  ncc = ccbaGetCount(ccba); /* number of c.c. */
1896  for (i = 0; i < ncc; i++) {
1897  ccb = ccbaGetCcb(ccba, i);
1898  if ((ptag = ccb->spglobal) == NULL) {
1899  L_WARNING("spglobal pixel loc array not found\n", procName);
1900  continue;
1901  }
1902  npt = ptaGetCount(ptag); /* number of pixels on path */
1903  for (j = 0; j < npt; j++) {
1904  ptaGetIPt(ptag, j, &x, &y);
1905  pixSetPixel(pixd, x, y, 1);
1906  }
1907  ccbDestroy(&ccb); /* clone ref */
1908  }
1909 
1910  return pixd;
1911 }
1912 
1913 
1970 PIX *
1972 {
1973 l_int32 ncc, i, nb, n, j, k, x, y, xul, yul, xoff, yoff, w, h;
1974 l_int32 fpx, fpy, spx, spy, xs, ys;
1975 BOX *box;
1976 BOXA *boxa;
1977 CCBORD *ccb;
1978 PIX *pixd, *pixt, *pixh;
1979 PTAA *ptaa;
1980 PTA *pta;
1981 
1982  PROCNAME("ccbaDisplayImage1");
1983 
1984  if (!ccba)
1985  return (PIX *)ERROR_PTR("ccba not defined", procName, NULL);
1986 
1987  if ((pixd = pixCreate(ccba->w, ccba->h, 1)) == NULL)
1988  return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1989  ncc = ccbaGetCount(ccba);
1990  for (i = 0; i < ncc; i++) {
1991  ccb = ccbaGetCcb(ccba, i);
1992  if ((boxa = ccb->boxa) == NULL) {
1993  pixDestroy(&pixd);
1994  return (PIX *)ERROR_PTR("boxa not found", procName, NULL);
1995  }
1996 
1997  /* Render border in pixt */
1998  if ((ptaa = ccb->local) == NULL) {
1999  L_WARNING("local chain array not found\n", procName);
2000  continue;
2001  }
2002 
2003  nb = ptaaGetCount(ptaa); /* number of borders in the c.c. */
2004  for (j = 0; j < nb; j++) {
2005  if ((box = boxaGetBox(boxa, j, L_CLONE)) == NULL) {
2006  pixDestroy(&pixd);
2007  return (PIX *)ERROR_PTR("b. box not found", procName, NULL);
2008  }
2009  if (j == 0) {
2010  boxGetGeometry(box, &xul, &yul, &w, &h);
2011  xoff = yoff = 0;
2012  } else {
2013  boxGetGeometry(box, &xoff, &yoff, &w, &h);
2014  }
2015  boxDestroy(&box);
2016 
2017  /* Render the border in a minimum-sized pix;
2018  * subtract xoff and yoff because the pixel
2019  * location is stored relative to the c.c., but
2020  * we need it relative to just the hole border. */
2021  if ((pixt = pixCreate(w, h, 1)) == NULL) {
2022  pixDestroy(&pixd);
2023  return (PIX *)ERROR_PTR("pixt not made", procName, NULL);
2024  }
2025  pta = ptaaGetPta(ptaa, j, L_CLONE);
2026  n = ptaGetCount(pta); /* number of pixels in the border */
2027  for (k = 0; k < n; k++) {
2028  ptaGetIPt(pta, k, &x, &y);
2029  pixSetPixel(pixt, x - xoff, y - yoff, 1);
2030  if (j > 0) { /* need this for finding hole border pixel */
2031  if (k == 0) {
2032  fpx = x - xoff;
2033  fpy = y - yoff;
2034  }
2035  if (k == 1) {
2036  spx = x - xoff;
2037  spy = y - yoff;
2038  }
2039  }
2040  }
2041  ptaDestroy(&pta);
2042 
2043  /* Get the filled component */
2044  if (j == 0) { /* if outer border, fill from outer boundary */
2045  if ((pixh = pixFillClosedBorders(pixt, 4)) == NULL) {
2046  pixDestroy(&pixd);
2047  pixDestroy(&pixt);
2048  return (PIX *)ERROR_PTR("pixh not made", procName, NULL);
2049  }
2050  } else { /* fill the hole from inside */
2051  /* get the location of a seed pixel in the hole */
2052  locateOutsideSeedPixel(fpx, fpy, spx, spy, &xs, &ys);
2053 
2054  /* Put seed in hole and fill interior of hole,
2055  * using pixt as clipping mask */
2056  pixh = pixCreateTemplate(pixt);
2057  pixSetPixel(pixh, xs, ys, 1); /* put seed pixel in hole */
2058  pixInvert(pixt, pixt); /* to make filling mask */
2059  pixSeedfillBinary(pixh, pixh, pixt, 4); /* 4-fill hole */
2060  }
2061 
2062  /* XOR into the dest */
2063  pixRasterop(pixd, xul + xoff, yul + yoff, w, h, PIX_XOR,
2064  pixh, 0, 0);
2065  pixDestroy(&pixt);
2066  pixDestroy(&pixh);
2067  }
2068  ccbDestroy(&ccb);
2069  }
2070  return pixd;
2071 }
2072 
2073 
2074 
2096 PIX *
2098 {
2099 l_int32 ncc, nb, n, i, j, k, x, y, xul, yul, w, h;
2100 l_int32 fpx, fpy, spx, spy, xs, ys;
2101 BOXA *boxa;
2102 CCBORD *ccb;
2103 PIX *pixd, *pixc, *pixs;
2104 PTAA *ptaa;
2105 PTA *pta;
2106 
2107  PROCNAME("ccbaDisplayImage2");
2108 
2109  if (!ccba)
2110  return (PIX *)ERROR_PTR("ccba not defined", procName, NULL);
2111 
2112  if ((pixd = pixCreate(ccba->w, ccba->h, 1)) == NULL)
2113  return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
2114  ncc = ccbaGetCount(ccba);
2115  for (i = 0; i < ncc; i++) {
2116  /* Generate clipping mask from border pixels and seed image
2117  * from one seed for each closed border. */
2118  ccb = ccbaGetCcb(ccba, i);
2119  if ((boxa = ccb->boxa) == NULL) {
2120  pixDestroy(&pixd);
2121  ccbDestroy(&ccb);
2122  return (PIX *)ERROR_PTR("boxa not found", procName, NULL);
2123  }
2124  if (boxaGetBoxGeometry(boxa, 0, &xul, &yul, &w, &h)) {
2125  pixDestroy(&pixd);
2126  ccbDestroy(&ccb);
2127  return (PIX *)ERROR_PTR("b. box not found", procName, NULL);
2128  }
2129  pixc = pixCreate(w + 2, h + 2, 1);
2130  pixs = pixCreateTemplate(pixc);
2131 
2132  if ((ptaa = ccb->local) == NULL) {
2133  pixDestroy(&pixc);
2134  pixDestroy(&pixs);
2135  ccbDestroy(&ccb);
2136  L_WARNING("local chain array not found\n", procName);
2137  continue;
2138  }
2139  nb = ptaaGetCount(ptaa); /* number of borders in the c.c. */
2140  for (j = 0; j < nb; j++) {
2141  pta = ptaaGetPta(ptaa, j, L_CLONE);
2142  n = ptaGetCount(pta); /* number of pixels in the border */
2143 
2144  /* Render border pixels in pixc */
2145  for (k = 0; k < n; k++) {
2146  ptaGetIPt(pta, k, &x, &y);
2147  pixSetPixel(pixc, x + 1, y + 1, 1);
2148  if (k == 0) {
2149  fpx = x + 1;
2150  fpy = y + 1;
2151  } else if (k == 1) {
2152  spx = x + 1;
2153  spy = y + 1;
2154  }
2155  }
2156 
2157  /* Get and set seed pixel for this border in pixs */
2158  if (n > 1)
2159  locateOutsideSeedPixel(fpx, fpy, spx, spy, &xs, &ys);
2160  else /* isolated c.c. */
2161  xs = ys = 0;
2162  pixSetPixel(pixs, xs, ys, 1);
2163  ptaDestroy(&pta);
2164  }
2165 
2166  /* Fill from seeds in pixs, using pixc as the clipping mask,
2167  * to reconstruct the c.c. */
2168  pixInvert(pixc, pixc); /* to convert clipping -> filling mask */
2169  pixSeedfillBinary(pixs, pixs, pixc, 4); /* 4-fill */
2170  pixInvert(pixs, pixs); /* to make the c.c. */
2171 
2172  /* XOR into the dest */
2173  pixRasterop(pixd, xul, yul, w, h, PIX_XOR, pixs, 1, 1);
2174 
2175  pixDestroy(&pixc);
2176  pixDestroy(&pixs);
2177  ccbDestroy(&ccb); /* ref-counted */
2178  }
2179  return pixd;
2180 }
2181 
2182 
2183 
2184 /*---------------------------------------------------------------------*
2185  * Serialize for I/O *
2186  *---------------------------------------------------------------------*/
2194 l_ok
2195 ccbaWrite(const char *filename,
2196  CCBORDA *ccba)
2197 {
2198 FILE *fp;
2199 
2200  PROCNAME("ccbaWrite");
2201 
2202  if (!filename)
2203  return ERROR_INT("filename not defined", procName, 1);
2204  if (!ccba)
2205  return ERROR_INT("ccba not defined", procName, 1);
2206 
2207  if ((fp = fopenWriteStream(filename, "wb+")) == NULL)
2208  return ERROR_INT("stream not opened", procName, 1);
2209  if (ccbaWriteStream(fp, ccba)) {
2210  fclose(fp);
2211  return ERROR_INT("ccba not written to stream", procName, 1);
2212  }
2213 
2214  fclose(fp);
2215  return 0;
2216 }
2217 
2218 
2219 
2246 l_ok
2248  CCBORDA *ccba)
2249 {
2250 char strbuf[256];
2251 l_uint8 bval;
2252 l_uint8 *datain, *dataout;
2253 l_int32 i, j, k, bx, by, bw, bh, val, startx, starty;
2254 l_int32 ncc, nb, n;
2255 l_uint32 w, h;
2256 size_t inbytes, outbytes;
2257 L_BBUFFER *bbuf;
2258 CCBORD *ccb;
2259 NUMA *na;
2260 NUMAA *naa;
2261 PTA *pta;
2262 
2263  PROCNAME("ccbaWriteStream");
2264 
2265 #if !HAVE_LIBZ /* defined in environ.h */
2266  return ERROR_INT("no libz: can't write data", procName, 1);
2267 #else
2268 
2269  if (!fp)
2270  return ERROR_INT("stream not open", procName, 1);
2271  if (!ccba)
2272  return ERROR_INT("ccba not defined", procName, 1);
2273 
2274  if ((bbuf = bbufferCreate(NULL, 1000)) == NULL)
2275  return ERROR_INT("bbuf not made", procName, 1);
2276 
2277  ncc = ccbaGetCount(ccba);
2278  snprintf(strbuf, sizeof(strbuf), "ccba: %7d cc\n", ncc);
2279  bbufferRead(bbuf, (l_uint8 *)strbuf, 18);
2280  w = pixGetWidth(ccba->pix);
2281  h = pixGetHeight(ccba->pix);
2282  bbufferRead(bbuf, (l_uint8 *)&w, 4); /* width */
2283  bbufferRead(bbuf, (l_uint8 *)&h, 4); /* height */
2284  for (i = 0; i < ncc; i++) {
2285  ccb = ccbaGetCcb(ccba, i);
2286  if (boxaGetBoxGeometry(ccb->boxa, 0, &bx, &by, &bw, &bh)) {
2287  bbufferDestroy(&bbuf);
2288  return ERROR_INT("bounding box not found", procName, 1);
2289  }
2290  bbufferRead(bbuf, (l_uint8 *)&bx, 4); /* ulx of c.c. */
2291  bbufferRead(bbuf, (l_uint8 *)&by, 4); /* uly of c.c. */
2292  bbufferRead(bbuf, (l_uint8 *)&bw, 4); /* w of c.c. */
2293  bbufferRead(bbuf, (l_uint8 *)&bh, 4); /* h of c.c. */
2294  if ((naa = ccb->step) == NULL) {
2295  ccbaGenerateStepChains(ccba);
2296  naa = ccb->step;
2297  }
2298  nb = numaaGetCount(naa);
2299  bbufferRead(bbuf, (l_uint8 *)&nb, 4); /* number of borders in c.c. */
2300  pta = ccb->start;
2301  for (j = 0; j < nb; j++) {
2302  ptaGetIPt(pta, j, &startx, &starty);
2303  bbufferRead(bbuf, (l_uint8 *)&startx, 4); /* starting x in border */
2304  bbufferRead(bbuf, (l_uint8 *)&starty, 4); /* starting y in border */
2305  na = numaaGetNuma(naa, j, L_CLONE);
2306  n = numaGetCount(na);
2307  for (k = 0; k < n; k++) {
2308  numaGetIValue(na, k, &val);
2309  if (k % 2 == 0)
2310  bval = (l_uint8)val << 4;
2311  else
2312  bval |= (l_uint8)val;
2313  if (k % 2 == 1)
2314  bbufferRead(bbuf, (l_uint8 *)&bval, 1); /* 2 border steps */
2315  }
2316  if (n % 2 == 1) {
2317  bval |= 0x8;
2318  bbufferRead(bbuf, (l_uint8 *)&bval, 1); /* end with 0xz8, */
2319  /* where z = {0..7} */
2320  } else { /* n % 2 == 0 */
2321  bval = 0x88;
2322  bbufferRead(bbuf, (l_uint8 *)&bval, 1); /* end with 0x88 */
2323  }
2324  numaDestroy(&na);
2325  }
2326  ccbDestroy(&ccb);
2327  }
2328 
2329  datain = bbufferDestroyAndSaveData(&bbuf, &inbytes);
2330  dataout = zlibCompress(datain, inbytes, &outbytes);
2331  fwrite(dataout, 1, outbytes, fp);
2332 
2333  LEPT_FREE(datain);
2334  LEPT_FREE(dataout);
2335  return 0;
2336 
2337 #endif /* !HAVE_LIBZ */
2338 }
2339 
2340 
2347 CCBORDA *
2348 ccbaRead(const char *filename)
2349 {
2350 FILE *fp;
2351 CCBORDA *ccba;
2352 
2353  PROCNAME("ccbaRead");
2354 
2355  if (!filename)
2356  return (CCBORDA *)ERROR_PTR("filename not defined", procName, NULL);
2357 
2358  if ((fp = fopenReadStream(filename)) == NULL)
2359  return (CCBORDA *)ERROR_PTR("stream not opened", procName, NULL);
2360  ccba = ccbaReadStream(fp);
2361  fclose(fp);
2362 
2363  if (!ccba)
2364  return (CCBORDA *)ERROR_PTR("ccba not returned", procName, NULL);
2365  return ccba;
2366 }
2367 
2368 
2393 CCBORDA *
2395 {
2396 char strbuf[256];
2397 l_uint8 bval;
2398 l_uint8 *datain, *dataout;
2399 l_int32 i, j, startx, starty;
2400 l_int32 offset, nib1, nib2;
2401 l_int32 ncc, nb;
2402 l_uint32 width, height, w, h, xoff, yoff;
2403 size_t inbytes, outbytes;
2404 BOX *box;
2405 CCBORD *ccb;
2406 CCBORDA *ccba;
2407 NUMA *na;
2408 NUMAA *step;
2409 
2410  PROCNAME("ccbaReadStream");
2411 
2412 #if !HAVE_LIBZ /* defined in environ.h */
2413  return (CCBORDA *)ERROR_PTR("no libz: can't read data", procName, NULL);
2414 #else
2415 
2416  if (!fp)
2417  return (CCBORDA *)ERROR_PTR("stream not open", procName, NULL);
2418 
2419  if ((datain = l_binaryReadStream(fp, &inbytes)) == NULL)
2420  return (CCBORDA *)ERROR_PTR("data not read from file", procName, NULL);
2421  dataout = zlibUncompress(datain, inbytes, &outbytes);
2422  LEPT_FREE(datain);
2423  if (!dataout)
2424  return (CCBORDA *)ERROR_PTR("dataout not made", procName, NULL);
2425 
2426  offset = 18;
2427  memcpy(strbuf, dataout, offset);
2428  strbuf[17] = '\0';
2429  if (memcmp(strbuf, "ccba:", 5) != 0) {
2430  LEPT_FREE(dataout);
2431  return (CCBORDA *)ERROR_PTR("file not type ccba", procName, NULL);
2432  }
2433  sscanf(strbuf, "ccba: %7d cc\n", &ncc);
2434 /* fprintf(stderr, "ncc = %d\n", ncc); */
2435  if ((ccba = ccbaCreate(NULL, ncc)) == NULL) {
2436  LEPT_FREE(dataout);
2437  return (CCBORDA *)ERROR_PTR("ccba not made", procName, NULL);
2438  }
2439 
2440  memcpy(&width, dataout + offset, 4);
2441  offset += 4;
2442  memcpy(&height, dataout + offset, 4);
2443  offset += 4;
2444  ccba->w = width;
2445  ccba->h = height;
2446 /* fprintf(stderr, "width = %d, height = %d\n", width, height); */
2447 
2448  for (i = 0; i < ncc; i++) { /* should be ncc */
2449  ccb = ccbCreate(NULL);
2450  ccbaAddCcb(ccba, ccb);
2451 
2452  memcpy(&xoff, dataout + offset, 4);
2453  offset += 4;
2454  memcpy(&yoff, dataout + offset, 4);
2455  offset += 4;
2456  memcpy(&w, dataout + offset, 4);
2457  offset += 4;
2458  memcpy(&h, dataout + offset, 4);
2459  offset += 4;
2460  box = boxCreate(xoff, yoff, w, h);
2461  boxaAddBox(ccb->boxa, box, L_INSERT);
2462 /* fprintf(stderr, "xoff = %d, yoff = %d, w = %d, h = %d\n",
2463  xoff, yoff, w, h); */
2464 
2465  memcpy(&nb, dataout + offset, 4);
2466  offset += 4;
2467 /* fprintf(stderr, "num borders = %d\n", nb); */
2468  step = numaaCreate(nb);
2469  ccb->step = step;
2470 
2471  for (j = 0; j < nb; j++) { /* should be nb */
2472  memcpy(&startx, dataout + offset, 4);
2473  offset += 4;
2474  memcpy(&starty, dataout + offset, 4);
2475  offset += 4;
2476  ptaAddPt(ccb->start, startx, starty);
2477 /* fprintf(stderr, "startx = %d, starty = %d\n", startx, starty); */
2478  na = numaCreate(0);
2479  numaaAddNuma(step, na, L_INSERT);
2480 
2481  while(1) {
2482  bval = *(dataout + offset);
2483  offset++;
2484  nib1 = (bval >> 4);
2485  nib2 = bval & 0xf;
2486  if (nib1 != 8)
2487  numaAddNumber(na, nib1);
2488  else
2489  break;
2490  if (nib2 != 8)
2491  numaAddNumber(na, nib2);
2492  else
2493  break;
2494  }
2495  }
2496  }
2497  LEPT_FREE(dataout);
2498  return ccba;
2499 
2500 #endif /* !HAVE_LIBZ */
2501 }
2502 
2503 
2504 /*---------------------------------------------------------------------*
2505  * SVG Output *
2506  *---------------------------------------------------------------------*/
2514 l_ok
2515 ccbaWriteSVG(const char *filename,
2516  CCBORDA *ccba)
2517 {
2518 char *svgstr;
2519 
2520  PROCNAME("ccbaWriteSVG");
2521 
2522  if (!filename)
2523  return ERROR_INT("filename not defined", procName, 1);
2524  if (!ccba)
2525  return ERROR_INT("ccba not defined", procName, 1);
2526 
2527  if ((svgstr = ccbaWriteSVGString(filename, ccba)) == NULL)
2528  return ERROR_INT("svgstr not made", procName, 1);
2529 
2530  l_binaryWrite(filename, "w", svgstr, strlen(svgstr));
2531  LEPT_FREE(svgstr);
2532 
2533  return 0;
2534 }
2535 
2536 
2545 char *
2546 ccbaWriteSVGString(const char *filename,
2547  CCBORDA *ccba)
2548 {
2549 char *svgstr;
2550 char smallbuf[256];
2551 char line0[] = "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>";
2552 char 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\">";
2553 char line2[] = "<svg>";
2554 char line3[] = "<polygon style=\"stroke-width:1;stroke:black;\" points=\"";
2555 char line4[] = "\" />";
2556 char line5[] = "</svg>";
2557 char space[] = " ";
2558 l_int32 i, j, ncc, npt, x, y;
2559 CCBORD *ccb;
2560 PTA *pta;
2561 SARRAY *sa;
2562 
2563  PROCNAME("ccbaWriteSVGString");
2564 
2565  if (!filename)
2566  return (char *)ERROR_PTR("filename not defined", procName, NULL);
2567  if (!ccba)
2568  return (char *)ERROR_PTR("ccba not defined", procName, NULL);
2569 
2570  sa = sarrayCreate(0);
2571  sarrayAddString(sa, line0, L_COPY);
2572  sarrayAddString(sa, line1, L_COPY);
2573  sarrayAddString(sa, line2, L_COPY);
2574  ncc = ccbaGetCount(ccba);
2575  for (i = 0; i < ncc; i++) {
2576  if ((ccb = ccbaGetCcb(ccba, i)) == NULL) {
2577  sarrayDestroy(&sa);
2578  return (char *)ERROR_PTR("ccb not found", procName, NULL);
2579  }
2580  if ((pta = ccb->spglobal) == NULL) {
2581  sarrayDestroy(&sa);
2582  ccbDestroy(&ccb);
2583  return (char *)ERROR_PTR("spglobal not made", procName, NULL);
2584  }
2585  sarrayAddString(sa, line3, L_COPY);
2586  npt = ptaGetCount(pta);
2587  for (j = 0; j < npt; j++) {
2588  ptaGetIPt(pta, j, &x, &y);
2589  snprintf(smallbuf, sizeof(smallbuf), "%0d,%0d", x, y);
2590  sarrayAddString(sa, smallbuf, L_COPY);
2591  }
2592  sarrayAddString(sa, line4, L_COPY);
2593  ccbDestroy(&ccb);
2594  }
2595  sarrayAddString(sa, line5, L_COPY);
2596  sarrayAddString(sa, space, L_COPY);
2597 
2598  svgstr = sarrayToString(sa, 1);
2599 /* fprintf(stderr, "%s", svgstr); */
2600 
2601  sarrayDestroy(&sa);
2602  return svgstr;
2603 }
l_int32 ccbaGetCount(CCBORDA *ccba)
ccbaGetCount()
Definition: ccbord.c:510
l_ok ccbaGenerateStepChains(CCBORDA *ccba)
ccbaGenerateStepChains()
Definition: ccbord.c:1231
struct Pta * splocal
Definition: ccbord.h:100
l_uint8 * zlibCompress(l_uint8 *datain, size_t nin, size_t *pnout)
zlibCompress()
Definition: zlibmem.c:92
char * sarrayToString(SARRAY *sa, l_int32 addnlflag)
sarrayToString()
Definition: sarray1.c:763
PIX * pixHolesByFilling(PIX *pixs, l_int32 connectivity)
pixHolesByFilling()
Definition: seedfill.c:605
Definition: pix.h:717
struct Ptaa * global
Definition: ccbord.h:98
CCBORDA * ccbaCreate(PIX *pixs, l_int32 n)
ccbaCreate()
Definition: ccbord.c:299
L_BBUFFER * bbufferCreate(const l_uint8 *indata, l_int32 nalloc)
bbufferCreate()
Definition: bbuffer.c:124
l_ok ccbaGenerateSPGlobalLocs(CCBORDA *ccba, l_int32 ptsflag)
ccbaGenerateSPGlobalLocs()
Definition: ccbord.c:1405
PIX * ccbaDisplaySPBorder(CCBORDA *ccba)
ccbaDisplaySPBorder()
Definition: ccbord.c:1881
CCBORD * ccbCreate(PIX *pixs)
ccbCreate()
Definition: ccbord.c:364
l_ok ptaAddPt(PTA *pta, l_float32 x, l_float32 y)
ptaAddPt()
Definition: ptabasic.c:342
l_ok numaAddNumber(NUMA *na, l_float32 val)
numaAddNumber()
Definition: numabasic.c:473
void ccbaDestroy(CCBORDA **pccba)
ccbaDestroy()
Definition: ccbord.c:332
l_int32 nextOnPixelInRaster(PIX *pixs, l_int32 xstart, l_int32 ystart, l_int32 *px, l_int32 *py)
nextOnPixelInRaster()
Definition: conncomp.c:453
PIX * ccbaDisplayImage1(CCBORDA *ccba)
ccbaDisplayImage1()
Definition: ccbord.c:1971
l_int32 n
Definition: ccbord.h:111
CCBORD * pixGetCCBorders(PIX *pixs, BOX *box)
pixGetCCBorders()
Definition: ccbord.c:650
PIX * ccbaDisplayBorder(CCBORDA *ccba)
ccbaDisplayBorder()
Definition: ccbord.c:1828
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:193
PTA * ptaCreate(l_int32 n)
ptaCreate()
Definition: ptabasic.c:116
CCBORDA * ccbaRead(const char *filename)
ccbaRead()
Definition: ccbord.c:2348
l_int32 y
Definition: pix.h:483
CCBORDA * ccbaReadStream(FILE *fp)
ccbaReadStream()
Definition: ccbord.c:2394
PIX * pixCreate(l_int32 width, l_int32 height, l_int32 depth)
pixCreate()
Definition: pix1.c:302
SARRAY * sarrayCreate(l_int32 n)
sarrayCreate()
Definition: sarray1.c:163
PIX * pixInvert(PIX *pixd, PIX *pixs)
pixInvert()
Definition: pix3.c:1395
NUMA * numaCreate(l_int32 n)
numaCreate()
Definition: numabasic.c:187
l_int32 ptaGetCount(PTA *pta)
ptaGetCount()
Definition: ptabasic.c:504
void boxaDestroy(BOXA **pboxa)
boxaDestroy()
Definition: boxbasic.c:580
l_uint32 * pixGetData(PIX *pix)
pixGetData()
Definition: pix1.c:1624
BOX * pixaGetBox(PIXA *pixa, l_int32 index, l_int32 accesstype)
pixaGetBox()
Definition: pixabasic.c:797
l_ok ccbaWriteStream(FILE *fp, CCBORDA *ccba)
ccbaWriteStream()
Definition: ccbord.c:2247
void locateOutsideSeedPixel(l_int32 fpx, l_int32 fpy, l_int32 spx, l_int32 spy, l_int32 *pxs, l_int32 *pys)
locateOutsideSeedPixel()
Definition: ccbord.c:1115
l_ok ccbaWriteSVG(const char *filename, CCBORDA *ccba)
ccbaWriteSVG()
Definition: ccbord.c:2515
#define GET_DATA_BIT(pdata, n)
Definition: arrayaccess.h:123
PIX * pixCreateTemplate(PIX *pixs)
pixCreateTemplate()
Definition: pix1.c:367
NUMAA * numaaCreate(l_int32 n)
numaaCreate()
Definition: numabasic.c:1340
Definition: pix.h:492
void * reallocNew(void **pindata, l_int32 oldsize, l_int32 newsize)
reallocNew()
Definition: utils2.c:1161
PIX * ccbaDisplayImage2(CCBORDA *ccba)
ccbaDisplayImage2()
Definition: ccbord.c:2097
char * ccbaWriteSVGString(const char *filename, CCBORDA *ccba)
ccbaWriteSVGString()
Definition: ccbord.c:2546
void numaaDestroy(NUMAA **pnaa)
numaaDestroy()
Definition: numabasic.c:1444
l_ok ptaJoin(PTA *ptad, PTA *ptas, l_int32 istart, l_int32 iend)
ptaJoin()
Definition: ptafunc1.c:164
Definition: array.h:116
struct CCBord ** ccb
Definition: ccbord.h:113
l_uint8 * bbufferDestroyAndSaveData(L_BBUFFER **pbb, size_t *pnbytes)
bbufferDestroyAndSaveData()
Definition: bbuffer.c:203
PIX * pixAddBorder(PIX *pixs, l_int32 npix, l_uint32 val)
pixAddBorder()
Definition: pix2.c:1748
static l_int32 ccbaExtendArray(CCBORDA *ccba)
ccbaExtendArray()
Definition: ccbord.c:482
BOX * boxClone(BOX *box)
boxClone()
Definition: boxbasic.c:252
l_ok l_binaryWrite(const char *filename, const char *operation, const void *data, size_t nbytes)
l_binaryWrite()
Definition: utils2.c:1429
struct Boxa * boxa
Definition: ccbord.h:94
BOXA * pixConnComp(PIX *pixs, PIXA **ppixa, l_int32 connectivity)
pixConnComp()
Definition: conncomp.c:147
NUMA * numaaGetNuma(NUMAA *naa, l_int32 index, l_int32 accessflag)
numaaGetNuma()
Definition: numabasic.c:1659
PTA * ptaaGetPta(PTAA *ptaa, l_int32 index, l_int32 accessflag)
ptaaGetPta()
Definition: ptabasic.c:1094
l_ok numaGetIValue(NUMA *na, l_int32 index, l_int32 *pival)
numaGetIValue()
Definition: numabasic.c:727
Definition: array.h:59
Definition: ccbord.h:91
l_int32 numaGetCount(NUMA *na)
numaGetCount()
Definition: numabasic.c:631
l_ok sarrayAddString(SARRAY *sa, const char *string, l_int32 copyflag)
sarrayAddString()
Definition: sarray1.c:446
l_int32 w
Definition: pix.h:484
PTA * ptaClone(PTA *pta)
ptaClone()
Definition: ptabasic.c:296
CCBORDA * pixGetAllCCBorders(PIX *pixs)
pixGetAllCCBorders()
Definition: ccbord.c:564
struct Pta * spglobal
Definition: ccbord.h:101
l_ok boxaGetBoxGeometry(BOXA *boxa, l_int32 index, l_int32 *px, l_int32 *py, l_int32 *pw, l_int32 *ph)
boxaGetBoxGeometry()
Definition: boxbasic.c:863
Definition: pix.h:532
struct Pix * pix
Definition: ccbord.h:108
l_ok pixSetPixel(PIX *pix, l_int32 x, l_int32 y, l_uint32 val)
pixSetPixel()
Definition: pix2.c:253
PTA * getCutPathForHole(PIX *pix, PTA *pta, BOX *boxinner, l_int32 *pdir, l_int32 *plen)
getCutPathForHole()
Definition: ccbord.c:1680
struct Ptaa * local
Definition: ccbord.h:97
void ptaaDestroy(PTAA **pptaa)
ptaaDestroy()
Definition: ptabasic.c:967
l_ok boxaAddBox(BOXA *boxa, BOX *box, l_int32 copyflag)
boxaAddBox()
Definition: boxbasic.c:618
PTA * ptaCyclicPerm(PTA *ptas, l_int32 xs, l_int32 ys)
ptaCyclicPerm()
Definition: ptafunc1.c:328
struct Pta * start
Definition: ccbord.h:95
l_int32 refcount
Definition: ccbord.h:96
l_int32 ptaContainsPt(PTA *pta, l_int32 x, l_int32 y)
ptaContainsPt()
Definition: ptafunc1.c:665
l_int32 h
Definition: ccbord.h:110
l_int32 w
Definition: ccbord.h:109
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:1064
CCBORD * ccbaGetCcb(CCBORDA *ccba, l_int32 index)
ccbaGetCcb()
Definition: ccbord.c:535
l_ok ccbaGenerateGlobalLocs(CCBORDA *ccba)
ccbaGenerateGlobalLocs()
Definition: ccbord.c:1160
PIX * pixClone(PIX *pixs)
pixClone()
Definition: pix1.c:515
Definition: array.h:71
struct Numaa * step
Definition: ccbord.h:99
void pixDestroy(PIX **ppix)
pixDestroy()
Definition: pix1.c:543
l_uint8 * zlibUncompress(l_uint8 *datain, size_t nin, size_t *pnout)
zlibUncompress()
Definition: zlibmem.c:198
PIX * pixFillClosedBorders(PIX *pixs, l_int32 connectivity)
pixFillClosedBorders()
Definition: seedfill.c:656
BOX * boxaGetBox(BOXA *boxa, l_int32 index, l_int32 accessflag)
boxaGetBox()
Definition: boxbasic.c:763
l_int32 x
Definition: pix.h:482
Definition: pix.h:454
l_ok ccbaWrite(const char *filename, CCBORDA *ccba)
ccbaWrite()
Definition: ccbord.c:2195
void numaDestroy(NUMA **pna)
numaDestroy()
Definition: numabasic.c:360
void bbufferDestroy(L_BBUFFER **pbb)
bbufferDestroy()
Definition: bbuffer.c:167
l_ok pixGetPixel(PIX *pix, l_int32 x, l_int32 y, l_uint32 *pval)
pixGetPixel()
Definition: pix2.c:180
l_ok bbufferRead(L_BBUFFER *bb, l_uint8 *src, l_int32 nbytes)
bbufferRead()
Definition: bbuffer.c:262
PIX * pixSeedfillBinary(PIX *pixd, PIX *pixs, PIX *pixm, l_int32 connectivity)
pixSeedfillBinary()
Definition: seedfill.c:243
l_ok pixGetDimensions(const PIX *pix, l_int32 *pw, l_int32 *ph, l_int32 *pd)
pixGetDimensions()
Definition: pix1.c:1065
FILE * fopenWriteStream(const char *filename, const char *modestring)
fopenWriteStream()
Definition: utils2.c:1700
FILE * fopenReadStream(const char *filename)
fopenReadStream()
Definition: utils2.c:1657
l_uint8 * l_binaryReadStream(FILE *fp, size_t *pnbytes)
l_binaryReadStream()
Definition: utils2.c:1262
l_int32 ptaaGetCount(PTAA *ptaa)
ptaaGetCount()
Definition: ptabasic.c:1074
l_ok ptaEmpty(PTA *pta)
ptaEmpty()
Definition: ptabasic.c:320
l_int32 numaaGetCount(NUMAA *naa)
numaaGetCount()
Definition: numabasic.c:1550
PIX * pixaGetPix(PIXA *pixa, l_int32 index, l_int32 accesstype)
pixaGetPix()
Definition: pixabasic.c:672
Definition: pix.h:718
l_ok pixGetHoleBorder(CCBORD *ccb, PIX *pixs, BOX *box, l_int32 xs, l_int32 ys)
pixGetHoleBorder()
Definition: ccbord.c:982
void ccbDestroy(CCBORD **pccb)
ccbDestroy()
Definition: ccbord.c:404
l_int32 h
Definition: pix.h:485
Definition: pix.h:134
Definition: pix.h:719
void ptaDestroy(PTA **ppta)
ptaDestroy()
Definition: ptabasic.c:192
l_ok pixZero(PIX *pix, l_int32 *pempty)
pixZero()
Definition: pix3.c:1701
BOXA * boxaCreate(l_int32 n)
boxaCreate()
Definition: boxbasic.c:499
l_ok ccbaStepChainsToPixCoords(CCBORDA *ccba, l_int32 coordtype)
ccbaStepChainsToPixCoords()
Definition: ccbord.c:1305
l_int32 nalloc
Definition: ccbord.h:112
void boxDestroy(BOX **pbox)
boxDestroy()
Definition: boxbasic.c:278
l_int32 boxaGetCount(BOXA *boxa)
boxaGetCount()
Definition: boxbasic.c:718
PTA * ptaTransform(PTA *ptas, l_int32 shiftx, l_int32 shifty, l_float32 scalex, l_float32 scaley)
ptaTransform()
Definition: ptafunc1.c:735
l_ok ptaGetIPt(PTA *pta, l_int32 index, l_int32 *px, l_int32 *py)
ptaGetIPt()
Definition: ptabasic.c:555
l_ok boxPrintStreamInfo(FILE *fp, BOX *box)
boxPrintStreamInfo()
Definition: boxbasic.c:2340
l_ok ptaaAddPta(PTAA *ptaa, PTA *pta, l_int32 copyflag)
ptaaAddPta()
Definition: ptabasic.c:1004
l_ok ccbaGenerateSinglePath(CCBORDA *ccba)
ccbaGenerateSinglePath()
Definition: ccbord.c:1522
PTA * pixGetOuterBorderPta(PIX *pixs, BOX *box)
pixGetOuterBorderPta()
Definition: ccbord.c:821
PTA * ptaReverse(PTA *ptas, l_int32 type)
ptaReverse()
Definition: ptafunc1.c:252
#define PIX_XOR
Definition: pix.h:337
l_ok ccbaAddCcb(CCBORDA *ccba, CCBORD *ccb)
ccbaAddCcb()
Definition: ccbord.c:454
l_ok pixGetOuterBorder(CCBORD *ccb, PIX *pixs, BOX *box)
pixGetOuterBorder()
Definition: ccbord.c:894
l_ok boxGetGeometry(BOX *box, l_int32 *px, l_int32 *py, l_int32 *pw, l_int32 *ph)
boxGetGeometry()
Definition: boxbasic.c:310
Definition: pix.h:480
void pixaDestroy(PIXA **ppixa)
pixaDestroy()
Definition: pixabasic.c:408
BOX * boxCreate(l_int32 x, l_int32 y, l_int32 w, l_int32 h)
boxCreate()
Definition: boxbasic.c:165
struct Pix * pix
Definition: ccbord.h:93
PTAA * pixGetOuterBordersPtaa(PIX *pixs)
pixGetOuterBordersPtaa()
Definition: ccbord.c:761
PTAA * ptaaCreate(l_int32 n)
ptaaCreate()
Definition: ptabasic.c:939
l_ok numaaAddNuma(NUMAA *naa, NUMA *na, l_int32 copyflag)
numaaAddNuma()
Definition: numabasic.c:1482
Definition: pix.h:517
void sarrayDestroy(SARRAY **psa)
sarrayDestroy()
Definition: sarray1.c:355