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