/*! * pixaGetBox() * * Input: pixa * index (to the index-th pix) * accesstype (L_COPY or L_CLONE) * Return: box (if null, not automatically an error), or null on error * * Notes: * (1) There is always a boxa with a pixa, and it is initialized so * that each box ptr is NULL. * (2) In general, we expect that there is either a box associated * with each pix, or no boxes at all in the boxa. * (3) Having no boxes is thus not an automatic error. Whether it * is an actual error is determined by the calling program. * If the caller expects to get a box, it is an error; see, e.g., * pixaGetBoxGeometry(). */ BOX * pixaGetBox(PIXA *pixa, l_int32 index, l_int32 accesstype) { BOX *box; PROCNAME("pixaGetBox"); if (!pixa) return (BOX *)ERROR_PTR("pixa not defined", procName, NULL); if (!pixa->boxa) return (BOX *)ERROR_PTR("boxa not defined", procName, NULL); if (index < 0 || index >= pixa->boxa->n) return (BOX *)ERROR_PTR("index not valid", procName, NULL); if (accesstype != L_COPY && accesstype != L_CLONE) return (BOX *)ERROR_PTR("invalid accesstype", procName, NULL); box = pixa->boxa->box[index]; if (box) { if (accesstype == L_COPY) return boxCopy(box); else /* accesstype == L_CLONE */ return boxClone(box); } else return NULL; }
/*! * boxaAddBox() * * Input: boxa * box (to be added) * copyflag (L_INSERT, L_COPY, L_CLONE) * Return: 0 if OK, 1 on error */ l_int32 boxaAddBox(BOXA *boxa, BOX *box, l_int32 copyflag) { l_int32 n; BOX *boxc; PROCNAME("boxaAddBox"); if (!boxa) return ERROR_INT("boxa not defined", procName, 1); if (!box) return ERROR_INT("box not defined", procName, 1); if (copyflag == L_INSERT) boxc = box; else if (copyflag == L_COPY) boxc = boxCopy(box); else if (copyflag == L_CLONE) boxc = boxClone(box); else return ERROR_INT("invalid copyflag", procName, 1); if (!boxc) return ERROR_INT("boxc not made", procName, 1); n = boxaGetCount(boxa); if (n >= boxa->nalloc) boxaExtendArray(boxa); boxa->box[n] = boxc; boxa->n++; return 0; }
/*! * boxRelocateOneSide() * * Input: boxd (<optional>; this can be null, equal to boxs, * or different from boxs); * boxs (starting box; to have one side relocated) * loc (new location of the side that is changing) * sideflag (L_FROM_LEFT, etc., indicating the side that moves) * Return: boxd, or null on error or if the computed boxd has * width or height <= 0. * * Notes: * (1) Set boxd == NULL to get new box; boxd == boxs for in-place; * or otherwise to resize existing boxd. * (2) For usage, suggest one of these: * boxd = boxRelocateOneSide(NULL, boxs, ...); // new * boxRelocateOneSide(boxs, boxs, ...); // in-place * boxRelocateOneSide(boxd, boxs, ...); // other */ BOX * boxRelocateOneSide(BOX *boxd, BOX *boxs, l_int32 loc, l_int32 sideflag) { l_int32 x, y, w, h; PROCNAME("boxRelocateOneSide"); if (!boxs) return (BOX *)ERROR_PTR("boxs not defined", procName, NULL); if (!boxd) boxd = boxCopy(boxs); boxGetGeometry(boxs, &x, &y, &w, &h); if (sideflag == L_FROM_LEFT) boxSetGeometry(boxd, loc, -1, w + x - loc, -1); else if (sideflag == L_FROM_RIGHT) boxSetGeometry(boxd, -1, -1, loc - x + 1, -1); else if (sideflag == L_FROM_TOP) boxSetGeometry(boxd, -1, loc, -1, h + y - loc); else if (sideflag == L_FROM_BOTTOM) boxSetGeometry(boxd, -1, -1, -1, loc - y + 1); return boxd; }
/*! * boxClipToRectangle() * * Input: box * wi, hi (rectangle representing image) * Return: part of box within given rectangle, or NULL on error * or if box is entirely outside the rectangle * * Note: the rectangle is assumed to go from (0,0) to (wi - 1, hi - 1) */ BOX * boxClipToRectangle(BOX *box, l_int32 wi, l_int32 hi) { BOX *boxd; PROCNAME("boxClipToRectangle"); if (!box) return (BOX *)ERROR_PTR("box not defined", procName, NULL); if (box->x >= wi || box->y >= hi || box->x + box->w <= 0 || box->y + box->h <= 0) return (BOX *)ERROR_PTR("box outside rectangle", procName, NULL); boxd = boxCopy(box); if (boxd->x < 0) { boxd->w += boxd->x; boxd->x = 0; } if (boxd->y < 0) { boxd->h += boxd->y; boxd->y = 0; } if (boxd->x + boxd->w > wi) boxd->w = wi - boxd->x; if (boxd->y + boxd->h > hi) boxd->h = hi - boxd->y; return boxd; }
/*! * boxRotateOrth() * * Input: box * w, h (of image in which the box is embedded) * rotation (0 = noop, 1 = 90 deg, 2 = 180 deg, 3 = 270 deg; * all rotations are clockwise) * Return: boxd, or null on error * * Notes: * (1) Rotate the image with the embedded box by the specified amount. * (2) After rotation, the rotated box is always measured with * respect to the UL corner of the image. */ BOX * boxRotateOrth(BOX *box, l_int32 w, l_int32 h, l_int32 rotation) { l_int32 bx, by, bw, bh, xdist, ydist; PROCNAME("boxRotateOrth"); if (!box) return (BOX *)ERROR_PTR("box not defined", procName, NULL); if (rotation == 0) return boxCopy(box); if (rotation < 1 || rotation > 3) return (BOX *)ERROR_PTR("rotation not in {0,1,2,3}", procName, NULL); boxGetGeometry(box, &bx, &by, &bw, &bh); if (bw <= 0 || bh <= 0) /* invalid */ return boxCreate(0, 0, 0, 0); ydist = h - by - bh; /* below box */ xdist = w - bx - bw; /* to right of box */ if (rotation == 1) /* 90 deg cw */ return boxCreate(ydist, bx, bh, bw); else if (rotation == 2) /* 180 deg cw */ return boxCreate(xdist, ydist, bw, bh); else /* rotation == 3, 270 deg cw */ return boxCreate(by, xdist, bh, bw); }
/*! * boxaGetBox() * * Input: boxa * index (to the index-th box) * accessflag (L_COPY or L_CLONE) * Return: box, or null on error */ BOX * boxaGetBox(BOXA *boxa, l_int32 index, l_int32 accessflag) { PROCNAME("boxaGetBox"); if (!boxa) return (BOX *)ERROR_PTR("boxa not defined", procName, NULL); if (index < 0 || index >= boxa->n) return (BOX *)ERROR_PTR("index not valid", procName, NULL); if (accessflag == L_COPY) return boxCopy(boxa->box[index]); else if (accessflag == L_CLONE) return boxClone(boxa->box[index]); else return (BOX *)ERROR_PTR("invalid accessflag", procName, NULL); }
static void CopyPtras(L_PTRA *papixs, L_PTRA *paboxs, L_PTRA **ppapixd, L_PTRA **ppaboxd) { l_int32 i, imax; BOX *box; PIX *pix; ptraGetMaxIndex(papixs, &imax); *ppapixd = ptraCreate(imax + 1); *ppaboxd = ptraCreate(imax + 1); for (i = 0; i <= imax; i++) { pix = pixCopy(NULL, (PIX *)ptraGetPtrToItem(papixs, i)); box = boxCopy((BOX *)ptraGetPtrToItem(paboxs, i)); ptraAdd(*ppapixd, pix); ptraAdd(*ppaboxd, box); } return; }
/*! * boxaInitFull() * * Input: boxa (typically empty) * box (to be replicated into the entire ptr array) * Return: 0 if OK, 1 on error * * Notes: * (1) This initializes a boxa by filling up the entire box ptr array * with copies of @box. Any existing boxes are destroyed. * After this oepration, the number of boxes is equal to * the number of allocated ptrs. * (2) Note that we use boxaReplaceBox() instead of boxaInsertBox(). * They both have the same effect when inserting into a NULL ptr * in the boxa ptr array: * (3) Example usage. This function is useful to prepare for a * random insertion (or replacement) of boxes into a boxa. * To randomly insert boxes into a boxa, up to some index "max": * Boxa *boxa = boxaCreate(max); * Box *box = boxCreate(...); * boxaInitFull(boxa, box); * If we have an existing boxa with a smaller ptr array, it can * be reused: * boxaExtendArrayToSize(boxa, max); * Box *box = boxCreate(...); * boxaInitFull(boxa, box); * The initialization allows the boxa to always be properly * filled, even if all the boxes are not later replaced. * If you want to know which boxes have been replaced, you can * initialize the array with invalid boxes that have * w = 0 and/or h = 0. Then boxaGetValidBox() will return * NULL for the invalid boxes. */ l_int32 boxaInitFull(BOXA *boxa, BOX *box) { l_int32 i, n; BOX *boxt; PROCNAME("boxaInitFull"); if (!boxa) return ERROR_INT("boxa not defined", procName, 1); if (!box) return ERROR_INT("box not defined", procName, 1); n = boxa->nalloc; boxa->n = n; for (i = 0; i < n; i++) { boxt = boxCopy(box); boxaReplaceBox(boxa, i, boxt); } return 0; }