| /*====================================================================* |
| - Copyright (C) 2001 Leptonica. All rights reserved. |
| - This software is distributed in the hope that it will be |
| - useful, but with NO WARRANTY OF ANY KIND. |
| - No author or distributor accepts responsibility to anyone for the |
| - consequences of using this software, or for whether it serves any |
| - particular purpose or works at all, unless he or she says so in |
| - writing. Everyone is granted permission to copy, modify and |
| - redistribute this source code, for commercial or non-commercial |
| - purposes, with the following restrictions: (1) the origin of this |
| - source code must not be misrepresented; (2) modified versions must |
| - be plainly marked as such; and (3) this notice may not be removed |
| - or altered from any source or modified source distribution. |
| *====================================================================*/ |
| |
| /* |
| * boxbasic.c |
| * |
| * Basic 'class' functions for box, boxa and boxaa, |
| * including accessors and serialization. |
| * |
| * Box creation, copy, clone, destruction |
| * BOX *boxCreate() |
| * BOX *boxCopy() |
| * BOX *boxClone() |
| * void boxDestroy() |
| * |
| * Box accessors |
| * l_int32 boxGetGeometry() |
| * l_int32 boxSetGeometry() |
| * l_int32 boxGetRefcount() |
| * l_int32 boxChangeRefcount() |
| * |
| * Boxa creation, copy, destruction |
| * BOXA *boxaCreate() |
| * BOXA *boxaCopy() |
| * void boxaDestroy() |
| * |
| * Boxa array extension |
| * l_int32 boxaAddBox() |
| * l_int32 boxaExtendArray() |
| * |
| * Boxa accessors |
| * l_int32 boxaGetCount() |
| * l_int32 boxaGetBox() |
| * l_int32 boxaGetBoxGeometry() |
| * |
| * Boxa array modifiers |
| * l_int32 boxaReplaceBox() |
| * l_int32 boxaInsertBox() |
| * l_int32 boxaRemoveBox() |
| * |
| * Boxaa creation, copy, destruction |
| * BOXAA *boxaaCreate() |
| * BOXAA *boxaaCopy() |
| * void boxaaDestroy() |
| * |
| * Boxaa array extension |
| * l_int32 boxaaAddBoxa() |
| * l_int32 boxaaExtendArray() |
| * |
| * Boxaa accessors |
| * l_int32 boxaaGetCount() |
| * l_int32 boxaaGetBoxCount() |
| * BOXA *boxaaGetBoxa() |
| * |
| * Boxa array modifiers |
| * l_int32 boxaaReplaceBoxa() |
| * l_int32 boxaaInsertBoxa() |
| * l_int32 boxaaRemoveBoxa() |
| * l_int32 boxaaAddBox() |
| * |
| * Boxaa serialized I/O |
| * BOXAA *boxaaRead() |
| * BOXAA *boxaaReadStream() |
| * l_int32 boxaaWrite() |
| * l_int32 boxaaWriteStream() |
| * |
| * Boxa serialized I/O |
| * BOXA *boxaRead() |
| * BOXA *boxaReadStream() |
| * l_int32 boxaWrite() |
| * l_int32 boxaWriteStream() |
| * |
| * Box print (for debug) |
| * l_int32 boxPrintStreamInfo() |
| * |
| * Backward compatibility old boxaa read functions |
| * BOXAA *boxaaReadVersion2() |
| * BOXAA *boxaaReadStreamVersion2() |
| */ |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include "allheaders.h" |
| |
| static const l_int32 INITIAL_PTR_ARRAYSIZE = 20; /* n'import quoi */ |
| |
| |
| /*---------------------------------------------------------------------* |
| * Box creation, destruction and copy * |
| *---------------------------------------------------------------------*/ |
| /*! |
| * boxCreate() |
| * |
| * Input: x, y, width, height |
| * Return: box, or null on error |
| * |
| * Notes: |
| * (1) This clips the box to the +quad. If no part of the |
| * box is in the +quad, this returns NULL. |
| */ |
| BOX * |
| boxCreate(l_int32 x, |
| l_int32 y, |
| l_int32 w, |
| l_int32 h) |
| { |
| BOX *box; |
| |
| PROCNAME("boxCreate"); |
| |
| if (w <= 0 || h <= 0) |
| return (BOX *)ERROR_PTR("w and h not both > 0", procName, NULL); |
| if (x < 0) { /* take part in +quad */ |
| w = w + x; |
| x = 0; |
| if (w <= 0) |
| return (BOX *)ERROR_PTR("x < 0 and box off +quad", procName, NULL); |
| } |
| if (y < 0) { /* take part in +quad */ |
| h = h + y; |
| y = 0; |
| if (h <= 0) |
| return (BOX *)ERROR_PTR("y < 0 and box off +quad", procName, NULL); |
| } |
| |
| if ((box = (BOX *)CALLOC(1, sizeof(BOX))) == NULL) |
| return (BOX *)ERROR_PTR("box not made", procName, NULL); |
| boxSetGeometry(box, x, y, w, h); |
| box->refcount = 1; |
| |
| return box; |
| } |
| |
| |
| /*! |
| * boxCopy() |
| * |
| * Input: box |
| * Return: copy of box, or null on error |
| */ |
| BOX * |
| boxCopy(BOX *box) |
| { |
| BOX *boxc; |
| |
| PROCNAME("boxCopy"); |
| |
| if (!box) |
| return (BOX *)ERROR_PTR("box not defined", procName, NULL); |
| |
| boxc = boxCreate(box->x, box->y, box->w, box->h); |
| |
| return boxc; |
| } |
| |
| |
| /*! |
| * boxClone() |
| * |
| * Input: box |
| * Return: ptr to same box, or null on error |
| */ |
| BOX * |
| boxClone(BOX *box) |
| { |
| |
| PROCNAME("boxClone"); |
| |
| if (!box) |
| return (BOX *)ERROR_PTR("box not defined", procName, NULL); |
| |
| boxChangeRefcount(box, 1); |
| return box; |
| } |
| |
| |
| /*! |
| * boxDestroy() |
| * |
| * Input: &box (<will be set to null before returning>) |
| * Return: void |
| * |
| * Notes: |
| * (1) Decrements the ref count and, if 0, destroys the box. |
| * (2) Always nulls the input ptr. |
| */ |
| void |
| boxDestroy(BOX **pbox) |
| { |
| BOX *box; |
| |
| PROCNAME("boxDestroy"); |
| |
| if (pbox == NULL) { |
| L_WARNING("ptr address is null!", procName); |
| return; |
| } |
| if ((box = *pbox) == NULL) |
| return; |
| |
| boxChangeRefcount(box, -1); |
| if (boxGetRefcount(box) <= 0) |
| FREE(box); |
| *pbox = NULL; |
| return; |
| } |
| |
| |
| /*---------------------------------------------------------------------* |
| * Box accessors * |
| *---------------------------------------------------------------------*/ |
| /*! |
| * boxGetGeometry() |
| * |
| * Input: box |
| * &x, &y, &w, &h (<optional return>; each can be null) |
| * Return: 0 if OK, 1 on error |
| */ |
| l_int32 |
| boxGetGeometry(BOX *box, |
| l_int32 *px, |
| l_int32 *py, |
| l_int32 *pw, |
| l_int32 *ph) |
| { |
| PROCNAME("boxGetGeometry"); |
| |
| if (px) *px = 0; |
| if (py) *py = 0; |
| if (pw) *pw = 0; |
| if (ph) *ph = 0; |
| if (!box) |
| return ERROR_INT("box not defined", procName, 1); |
| if (px) *px = box->x; |
| if (py) *py = box->y; |
| if (pw) *pw = box->w; |
| if (ph) *ph = box->h; |
| return 0; |
| } |
| |
| |
| /*! |
| * boxSetGeometry() |
| * |
| * Input: box |
| * x, y, w, h (use -1 to leave unchanged) |
| * Return: 0 if OK, 1 on error |
| */ |
| l_int32 |
| boxSetGeometry(BOX *box, |
| l_int32 x, |
| l_int32 y, |
| l_int32 w, |
| l_int32 h) |
| { |
| PROCNAME("boxSetGeometry"); |
| |
| if (!box) |
| return ERROR_INT("box not defined", procName, 1); |
| if (x != -1) box->x = x; |
| if (y != -1) box->y = y; |
| if (w != -1) box->w = w; |
| if (h != -1) box->h = h; |
| return 0; |
| } |
| |
| |
| l_int32 |
| boxGetRefcount(BOX *box) |
| { |
| PROCNAME("boxGetRefcount"); |
| |
| if (!box) |
| return ERROR_INT("box not defined", procName, UNDEF); |
| |
| return box->refcount; |
| } |
| |
| |
| l_int32 |
| boxChangeRefcount(BOX *box, |
| l_int32 delta) |
| { |
| PROCNAME("boxChangeRefcount"); |
| |
| if (!box) |
| return ERROR_INT("box not defined", procName, 1); |
| |
| box->refcount += delta; |
| return 0; |
| } |
| |
| |
| /*---------------------------------------------------------------------* |
| * Boxa creation, destruction, copy, extension * |
| *---------------------------------------------------------------------*/ |
| /*! |
| * boxaCreate() |
| * |
| * Input: n (initial number of ptrs) |
| * Return: boxa, or null on error |
| */ |
| BOXA * |
| boxaCreate(l_int32 n) |
| { |
| BOXA *boxa; |
| |
| PROCNAME("boxaCreate"); |
| |
| if (n <= 0) |
| n = INITIAL_PTR_ARRAYSIZE; |
| |
| if ((boxa = (BOXA *)CALLOC(1, sizeof(BOXA))) == NULL) |
| return (BOXA *)ERROR_PTR("boxa not made", procName, NULL); |
| boxa->n = 0; |
| boxa->nalloc = n; |
| boxa->refcount = 1; |
| |
| if ((boxa->box = (BOX **)CALLOC(n, sizeof(BOX *))) == NULL) |
| return (BOXA *)ERROR_PTR("boxa ptrs not made", procName, NULL); |
| |
| return boxa; |
| } |
| |
| |
| /*! |
| * boxaCopy() |
| * |
| * Input: boxa |
| * copyflag (L_COPY, L_CLONE, L_COPY_CLONE) |
| * Return: new boxa, or null on error |
| * |
| * Notes: |
| * (1) See pix.h for description of the copyflag. |
| * (2) The copy-clone makes a new boxa that holds clones of each box. |
| */ |
| BOXA * |
| boxaCopy(BOXA *boxa, |
| l_int32 copyflag) |
| { |
| l_int32 i; |
| BOX *boxc; |
| BOXA *boxac; |
| |
| PROCNAME("boxaCopy"); |
| |
| if (!boxa) |
| return (BOXA *)ERROR_PTR("boxa not defined", procName, NULL); |
| |
| if (copyflag == L_CLONE) { |
| boxa->refcount++; |
| return boxa; |
| } |
| |
| if (copyflag != L_COPY && copyflag != L_COPY_CLONE) |
| return (BOXA *)ERROR_PTR("invalid copyflag", procName, NULL); |
| |
| if ((boxac = boxaCreate(boxa->nalloc)) == NULL) |
| return (BOXA *)ERROR_PTR("boxac not made", procName, NULL); |
| for (i = 0; i < boxa->n; i++) { |
| if (copyflag == L_COPY) |
| boxc = boxaGetBox(boxa, i, L_COPY); |
| else /* copy-clone */ |
| boxc = boxaGetBox(boxa, i, L_CLONE); |
| boxaAddBox(boxac, boxc, L_INSERT); |
| } |
| return boxac; |
| } |
| |
| |
| /*! |
| * boxaDestroy() |
| * |
| * Input: &boxa (<will be set to null before returning>) |
| * Return: void |
| * |
| * Note: |
| * - Decrements the ref count and, if 0, destroys the boxa. |
| * - Always nulls the input ptr. |
| */ |
| void |
| boxaDestroy(BOXA **pboxa) |
| { |
| l_int32 i; |
| BOXA *boxa; |
| |
| PROCNAME("boxaDestroy"); |
| |
| if (pboxa == NULL) { |
| L_WARNING("ptr address is null!", procName); |
| return; |
| } |
| |
| if ((boxa = *pboxa) == NULL) |
| return; |
| |
| /* Decrement the ref count. If it is 0, destroy the boxa. */ |
| boxa->refcount--; |
| if (boxa->refcount <= 0) { |
| for (i = 0; i < boxa->n; i++) |
| boxDestroy(&boxa->box[i]); |
| FREE(boxa->box); |
| FREE(boxa); |
| } |
| |
| *pboxa = NULL; |
| return; |
| } |
| |
| |
| /*! |
| * 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; |
| } |
| |
| |
| /*! |
| * boxaExtendArray() |
| * |
| * Input: boxa |
| * Return: 0 if OK; 1 on error |
| */ |
| l_int32 |
| boxaExtendArray(BOXA *boxa) |
| { |
| |
| PROCNAME("boxaExtendArray"); |
| |
| if (!boxa) |
| return ERROR_INT("boxa not defined", procName, 1); |
| |
| if ((boxa->box = (BOX **)reallocNew((void **)&boxa->box, |
| sizeof(BOX *) * boxa->nalloc, |
| 2 * sizeof(BOX *) * boxa->nalloc)) == NULL) |
| return ERROR_INT("new ptr array not returned", procName, 1); |
| |
| boxa->nalloc = 2 * boxa->nalloc; |
| return 0; |
| } |
| |
| |
| |
| /*---------------------------------------------------------------------* |
| * Boxa accessors * |
| *---------------------------------------------------------------------*/ |
| /*! |
| * boxaGetCount() |
| * |
| * Input: boxa |
| * Return: count, or 0 on error |
| */ |
| l_int32 |
| boxaGetCount(BOXA *boxa) |
| { |
| |
| PROCNAME("boxaGetCount"); |
| |
| if (!boxa) |
| return ERROR_INT("boxa not defined", procName, 0); |
| |
| return boxa->n; |
| } |
| |
| |
| /*! |
| * 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); |
| } |
| |
| |
| /*! |
| * boxaGetBoxGeometry() |
| * |
| * Input: boxa |
| * index (to the index-th box) |
| * &x, &y, &w, &h (<optional return>; each can be null) |
| * Return: 0 if OK, 1 on error |
| */ |
| l_int32 |
| boxaGetBoxGeometry(BOXA *boxa, |
| l_int32 index, |
| l_int32 *px, |
| l_int32 *py, |
| l_int32 *pw, |
| l_int32 *ph) |
| { |
| BOX *box; |
| |
| PROCNAME("boxaGetBoxGeometry"); |
| |
| if (px) *px = 0; |
| if (py) *py = 0; |
| if (pw) *pw = 0; |
| if (ph) *ph = 0; |
| if (!boxa) |
| return ERROR_INT("boxa not defined", procName, 1); |
| if (index < 0 || index >= boxa->n) |
| return ERROR_INT("index not valid", procName, 1); |
| |
| if ((box = boxaGetBox(boxa, index, L_CLONE)) == NULL) |
| return ERROR_INT("box not found!", procName, 1); |
| boxGetGeometry(box, px, py, pw, ph); |
| boxDestroy(&box); |
| return 0; |
| } |
| |
| |
| /*---------------------------------------------------------------------* |
| * Boxa array modifiers * |
| *---------------------------------------------------------------------*/ |
| /*! |
| * boxaReplaceBox() |
| * |
| * Input: boxa |
| * index (to the index-th box) |
| * box (insert to replace existing one) |
| * Return: 0 if OK, 1 on error |
| * |
| * Notes: |
| * (1) In-place replacement of one box. |
| * (2) The previous box at that location is destroyed. |
| */ |
| l_int32 |
| boxaReplaceBox(BOXA *boxa, |
| l_int32 index, |
| BOX *box) |
| { |
| PROCNAME("boxaReplaceBox"); |
| |
| if (!boxa) |
| return ERROR_INT("boxa not defined", procName, 1); |
| if (index < 0 || index >= boxa->n) |
| return ERROR_INT("index not valid", procName, 1); |
| if (!box) |
| return ERROR_INT("box not defined", procName, 1); |
| |
| boxDestroy(&(boxa->box[index])); |
| boxa->box[index] = box; |
| return 0; |
| } |
| |
| |
| /*! |
| * boxaInsertBox() |
| * |
| * Input: boxa |
| * index (location in boxa to insert new value) |
| * box (new box to be inserted) |
| * Return: 0 if OK, 1 on error |
| * |
| * Notes: |
| * (1) This shifts box[i] --> box[i + 1] for all i >= index, |
| * and then inserts box as box[index]. |
| * (2) To insert at the beginning of the array, set index = 0. |
| * (3) To append to the array, it's easier to use boxaAddBox(). |
| * (4) This should not be used repeatedly to insert into large arrays, |
| * because the function is O(n). |
| */ |
| l_int32 |
| boxaInsertBox(BOXA *boxa, |
| l_int32 index, |
| BOX *box) |
| { |
| l_int32 i, n; |
| BOX **array; |
| |
| PROCNAME("boxaInsertBox"); |
| |
| if (!boxa) |
| return ERROR_INT("boxa not defined", procName, 1); |
| n = boxaGetCount(boxa); |
| if (index < 0 || index > n) |
| return ERROR_INT("index not in {0...n}", procName, 1); |
| if (!box) |
| return ERROR_INT("box not defined", procName, 1); |
| |
| if (n >= boxa->nalloc) |
| boxaExtendArray(boxa); |
| array = boxa->box; |
| boxa->n++; |
| for (i = n; i > index; i--) |
| array[i] = array[i - 1]; |
| array[index] = box; |
| |
| return 0; |
| } |
| |
| |
| /*! |
| * boxaRemoveBox() |
| * |
| * Input: boxa |
| * index (of box to be removed) |
| * Return: 0 if OK, 1 on error |
| * |
| * Notes: |
| * (1) This removes box[index] and then shifts |
| * box[i] --> box[i - 1] for all i > index. |
| * (2) It should not be used repeatedly to remove boxes from |
| * large arrays, because the function is O(n). |
| */ |
| l_int32 |
| boxaRemoveBox(BOXA *boxa, |
| l_int32 index) |
| { |
| l_int32 i, n; |
| BOX **array; |
| |
| PROCNAME("boxaRemoveBox"); |
| |
| if (!boxa) |
| return ERROR_INT("boxa not defined", procName, 1); |
| n = boxaGetCount(boxa); |
| if (index < 0 || index >= n) |
| return ERROR_INT("index not in {0...n - 1}", procName, 1); |
| |
| array = boxa->box; |
| boxDestroy(&array[index]); |
| for (i = index + 1; i < n; i++) |
| array[i - 1] = array[i]; |
| array[n - 1] = NULL; |
| boxa->n--; |
| |
| return 0; |
| } |
| |
| |
| /*--------------------------------------------------------------------------* |
| * Boxaa creation, destruction * |
| *--------------------------------------------------------------------------*/ |
| /*! |
| * boxaaCreate() |
| * |
| * Input: size of boxa ptr array to be alloc'd (0 for default) |
| * Return: baa, or null on error |
| */ |
| BOXAA * |
| boxaaCreate(l_int32 n) |
| { |
| BOXAA *baa; |
| |
| PROCNAME("boxaaCreate"); |
| |
| if (n <= 0) |
| n = INITIAL_PTR_ARRAYSIZE; |
| |
| if ((baa = (BOXAA *)CALLOC(1, sizeof(BOXAA))) == NULL) |
| return (BOXAA *)ERROR_PTR("baa not made", procName, NULL); |
| if ((baa->boxa = (BOXA **)CALLOC(n, sizeof(BOXA *))) == NULL) |
| return (BOXAA *)ERROR_PTR("boxa ptr array not made", procName, NULL); |
| |
| baa->nalloc = n; |
| baa->n = 0; |
| |
| return baa; |
| } |
| |
| |
| /*! |
| * boxaaCopy() |
| * |
| * Input: baas (input boxaa to be copied) |
| * copyflag (L_COPY, L_CLONE) |
| * Return: baad (new boxaa, composed of copies or clones of the boxa |
| * in baas), or null on error |
| * |
| * Notes: |
| * (1) L_COPY makes a copy of each boxa in baas. |
| * L_CLONE makes a clone of each boxa in baas. |
| */ |
| BOXAA * |
| boxaaCopy(BOXAA *baas, |
| l_int32 copyflag) |
| { |
| l_int32 i, n; |
| BOXA *boxa; |
| BOXAA *baad; |
| |
| PROCNAME("boxaaCopy"); |
| |
| if (!baas) |
| return (BOXAA *)ERROR_PTR("baas not defined", procName, NULL); |
| if (copyflag != L_COPY && copyflag != L_CLONE) |
| return (BOXAA *)ERROR_PTR("invalid copyflag", procName, NULL); |
| |
| n = boxaaGetCount(baas); |
| baad = boxaaCreate(n); |
| for (i = 0; i < n; i++) { |
| boxa = boxaaGetBoxa(baas, i, copyflag); |
| boxaaAddBoxa(baad, boxa, L_INSERT); |
| } |
| |
| return baad; |
| } |
| |
| |
| /*! |
| * boxaaDestroy() |
| * |
| * Input: &boxaa (<will be set to null before returning>) |
| * Return: void |
| */ |
| void |
| boxaaDestroy(BOXAA **pbaa) |
| { |
| l_int32 i; |
| BOXAA *baa; |
| |
| PROCNAME("boxaaDestroy"); |
| |
| if (pbaa == NULL) { |
| L_WARNING("ptr address is NULL!", procName); |
| return; |
| } |
| |
| if ((baa = *pbaa) == NULL) |
| return; |
| |
| for (i = 0; i < baa->n; i++) |
| boxaDestroy(&baa->boxa[i]); |
| FREE(baa->boxa); |
| FREE(baa); |
| *pbaa = NULL; |
| |
| return; |
| } |
| |
| |
| |
| /*--------------------------------------------------------------------------* |
| * Add Boxa to Boxaa * |
| *--------------------------------------------------------------------------*/ |
| /*! |
| * boxaaAddBoxa() |
| * |
| * Input: boxaa |
| * boxa (to be added) |
| * copyflag (L_INSERT, L_COPY, L_CLONE) |
| * Return: 0 if OK, 1 on error |
| */ |
| l_int32 |
| boxaaAddBoxa(BOXAA *baa, |
| BOXA *ba, |
| l_int32 copyflag) |
| { |
| l_int32 n; |
| BOXA *bac; |
| |
| PROCNAME("boxaaAddBoxa"); |
| |
| if (!baa) |
| return ERROR_INT("baa not defined", procName, 1); |
| if (!ba) |
| return ERROR_INT("ba not defined", procName, 1); |
| if (copyflag != L_INSERT && copyflag != L_COPY && copyflag != L_CLONE) |
| return ERROR_INT("invalid copyflag", procName, 1); |
| |
| if (copyflag == L_INSERT) |
| bac = ba; |
| else |
| bac = boxaCopy(ba, copyflag); |
| |
| n = boxaaGetCount(baa); |
| if (n >= baa->nalloc) |
| boxaaExtendArray(baa); |
| baa->boxa[n] = bac; |
| baa->n++; |
| return 0; |
| } |
| |
| |
| /*! |
| * boxaaExtendArray() |
| * |
| * Input: boxaa |
| * Return: 0 if OK, 1 on error |
| */ |
| l_int32 |
| boxaaExtendArray(BOXAA *baa) |
| { |
| |
| PROCNAME("boxaaExtendArray"); |
| |
| if (!baa) |
| return ERROR_INT("baa not defined", procName, 1); |
| |
| if ((baa->boxa = (BOXA **)reallocNew((void **)&baa->boxa, |
| sizeof(BOXA *) * baa->nalloc, |
| 2 * sizeof(BOXA *) * baa->nalloc)) == NULL) |
| return ERROR_INT("new ptr array not returned", procName, 1); |
| |
| baa->nalloc *= 2; |
| return 0; |
| } |
| |
| |
| /*----------------------------------------------------------------------* |
| * Boxaa accessors * |
| *----------------------------------------------------------------------*/ |
| /*! |
| * boxaaGetCount() |
| * |
| * Input: boxaa |
| * Return: count (number of boxa), or 0 if no boxa or on error |
| */ |
| l_int32 |
| boxaaGetCount(BOXAA *baa) |
| { |
| PROCNAME("boxaaGetCount"); |
| |
| if (!baa) |
| return ERROR_INT("baa not defined", procName, 0); |
| return baa->n; |
| } |
| |
| |
| /*! |
| * boxaaGetBoxCount() |
| * |
| * Input: boxaa |
| * Return: count (number of boxes), or 0 if no boxes or on error |
| */ |
| l_int32 |
| boxaaGetBoxCount(BOXAA *baa) |
| { |
| BOXA *boxa; |
| l_int32 n, sum, i; |
| |
| PROCNAME("boxaaGetBoxCount"); |
| |
| if (!baa) |
| return ERROR_INT("baa not defined", procName, 0); |
| |
| n = boxaaGetCount(baa); |
| for (sum = 0, i = 0; i < n; i++) { |
| boxa = boxaaGetBoxa(baa, i, L_CLONE); |
| sum += boxaGetCount(boxa); |
| boxaDestroy(&boxa); |
| } |
| |
| return sum; |
| } |
| |
| |
| /*! |
| * boxaaGetBoxa() |
| * |
| * Input: boxaa |
| * index (to the index-th boxa) |
| * accessflag (L_COPY or L_CLONE) |
| * Return: boxa, or null on error |
| */ |
| BOXA * |
| boxaaGetBoxa(BOXAA *baa, |
| l_int32 index, |
| l_int32 accessflag) |
| { |
| l_int32 n; |
| |
| PROCNAME("boxaaGetBoxa"); |
| |
| if (!baa) |
| return (BOXA *)ERROR_PTR("baa not defined", procName, NULL); |
| n = boxaaGetCount(baa); |
| if (index < 0 || index >= n) |
| return (BOXA *)ERROR_PTR("index not valid", procName, NULL); |
| if (accessflag != L_COPY && accessflag != L_CLONE) |
| return (BOXA *)ERROR_PTR("invalid accessflag", procName, NULL); |
| |
| return boxaCopy(baa->boxa[index], accessflag); |
| } |
| |
| |
| /*! |
| * boxaaReplaceBoxa() |
| * |
| * Input: boxaa |
| * index (to the index-th boxa) |
| * boxa (insert and replace any existing one) |
| * Return: 0 if OK, 1 on error |
| * |
| * Notes: |
| * (1) Any existing boxa is destroyed, and the input one |
| * is inserted in its place. |
| * (2) If the index is invalid, return 1 (error) |
| */ |
| l_int32 |
| boxaaReplaceBoxa(BOXAA *baa, |
| l_int32 index, |
| BOXA *boxa) |
| { |
| l_int32 n; |
| |
| PROCNAME("boxaaReplaceBoxa"); |
| |
| if (!baa) |
| return ERROR_INT("baa not defined", procName, 1); |
| if (!boxa) |
| return ERROR_INT("boxa not defined", procName, 1); |
| n = boxaaGetCount(baa); |
| if (index < 0 || index >= n) |
| return ERROR_INT("index not valid", procName, 1); |
| |
| boxaDestroy(&baa->boxa[index]); |
| baa->boxa[index] = boxa; |
| return 0; |
| } |
| |
| |
| /*! |
| * boxaaInsertBoxa() |
| * |
| * Input: boxaa |
| * index (location in boxaa to insert new boxa) |
| * boxa (new boxa to be inserted) |
| * Return: 0 if OK, 1 on error |
| * |
| * Notes: |
| * (1) This shifts boxa[i] --> boxa[i + 1] for all i >= index, |
| * and then inserts boxa as boxa[index]. |
| * (2) To insert at the beginning of the array, set index = 0. |
| * (3) To append to the array, it's easier to use boxaaAddBoxa(). |
| * (4) This should not be used repeatedly to insert into large arrays, |
| * because the function is O(n). |
| */ |
| l_int32 |
| boxaaInsertBoxa(BOXAA *baa, |
| l_int32 index, |
| BOXA *boxa) |
| { |
| l_int32 i, n; |
| BOXA **array; |
| |
| PROCNAME("boxaaInsertBoxa"); |
| |
| if (!baa) |
| return ERROR_INT("baa not defined", procName, 1); |
| n = boxaaGetCount(baa); |
| if (index < 0 || index > n) |
| return ERROR_INT("index not in {0...n}", procName, 1); |
| if (!boxa) |
| return ERROR_INT("boxa not defined", procName, 1); |
| |
| if (n >= baa->nalloc) |
| boxaaExtendArray(baa); |
| array = baa->boxa; |
| baa->n++; |
| for (i = n; i > index; i--) |
| array[i] = array[i - 1]; |
| array[index] = boxa; |
| |
| return 0; |
| } |
| |
| |
| /*! |
| * boxaaRemoveBoxa() |
| * |
| * Input: boxaa |
| * index (of the boxa to be removed) |
| * Return: 0 if OK, 1 on error |
| * |
| * Notes: |
| * (1) This removes boxa[index] and then shifts |
| * boxa[i] --> boxa[i - 1] for all i > index. |
| * (2) The removed boxaa is destroyed. |
| * (2) This should not be used repeatedly on large arrays, |
| * because the function is O(n). |
| */ |
| l_int32 |
| boxaaRemoveBoxa(BOXAA *baa, |
| l_int32 index) |
| { |
| l_int32 i, n; |
| BOXA **array; |
| |
| PROCNAME("boxaaRemoveBox"); |
| |
| if (!baa) |
| return ERROR_INT("baa not defined", procName, 1); |
| n = boxaaGetCount(baa); |
| if (index < 0 || index >= n) |
| return ERROR_INT("index not valid", procName, 1); |
| |
| array = baa->boxa; |
| boxaDestroy(&array[index]); |
| for (i = index + 1; i < n; i++) |
| array[i - 1] = array[i]; |
| array[n - 1] = NULL; |
| baa->n--; |
| |
| return 0; |
| } |
| |
| |
| /*! |
| * boxaaAddBox() |
| * |
| * Input: boxaa |
| * index (of boxa with boxaa) |
| * box (to be added) |
| * accessflag (L_INSERT, L_COPY or L_CLONE) |
| * Return: 0 if OK, 1 on error |
| * |
| * Notes: |
| * (1) Adds to an existing boxa only. |
| */ |
| l_int32 |
| boxaaAddBox(BOXAA *baa, |
| l_int32 index, |
| BOX *box, |
| l_int32 accessflag) |
| { |
| l_int32 n; |
| BOXA *boxa; |
| PROCNAME("boxaaAddBox"); |
| |
| if (!baa) |
| return ERROR_INT("baa not defined", procName, 1); |
| n = boxaaGetCount(baa); |
| if (index < 0 || index >= n) |
| return ERROR_INT("index not valid", procName, 1); |
| if (accessflag != L_INSERT && accessflag != L_COPY && accessflag != L_CLONE) |
| return ERROR_INT("invalid accessflag", procName, 1); |
| |
| boxa = boxaaGetBoxa(baa, index, L_CLONE); |
| boxaAddBox(boxa, box, accessflag); |
| boxaDestroy(&boxa); |
| return 0; |
| } |
| |
| |
| /*---------------------------------------------------------------------* |
| * Boxaa serialized I/O * |
| *---------------------------------------------------------------------*/ |
| /*! |
| * boxaaRead() |
| * |
| * Input: filename |
| * Return: boxaa, or null on error |
| */ |
| BOXAA * |
| boxaaRead(const char *filename) |
| { |
| FILE *fp; |
| BOXAA *baa; |
| |
| PROCNAME("boxaaRead"); |
| |
| if (!filename) |
| return (BOXAA *)ERROR_PTR("filename not defined", procName, NULL); |
| if ((fp = fopenReadStream(filename)) == NULL) |
| return (BOXAA *)ERROR_PTR("stream not opened", procName, NULL); |
| |
| if ((baa = boxaaReadStream(fp)) == NULL) { |
| fclose(fp); |
| return (BOXAA *)ERROR_PTR("boxaa not read", procName, NULL); |
| } |
| |
| fclose(fp); |
| return baa; |
| } |
| |
| |
| /*! |
| * boxaaReadStream() |
| * |
| * Input: stream |
| * Return: boxaa, or null on error |
| */ |
| BOXAA * |
| boxaaReadStream(FILE *fp) |
| { |
| l_int32 n, i, x, y, w, h, version; |
| l_int32 ignore; |
| BOXA *boxa; |
| BOXAA *baa; |
| |
| PROCNAME("boxaaReadStream"); |
| |
| if (!fp) |
| return (BOXAA *)ERROR_PTR("stream not defined", procName, NULL); |
| |
| if (fscanf(fp, "\nBoxaa Version %d\n", &version) != 1) |
| return (BOXAA *)ERROR_PTR("not a boxaa file", procName, NULL); |
| if (version != BOXAA_VERSION_NUMBER) |
| return (BOXAA *)ERROR_PTR("invalid boxa version", procName, NULL); |
| if (fscanf(fp, "Number of boxa = %d\n", &n) != 1) |
| return (BOXAA *)ERROR_PTR("not a boxaa file", procName, NULL); |
| |
| if ((baa = boxaaCreate(n)) == NULL) |
| return (BOXAA *)ERROR_PTR("boxaa not made", procName, NULL); |
| |
| for (i = 0; i < n; i++) { |
| if (fscanf(fp, "\nBoxa[%d] extent: x = %d, y = %d, w = %d, h = %d", |
| &ignore, &x, &y, &w, &h) != 5) |
| return (BOXAA *)ERROR_PTR("boxa descr not valid", procName, NULL); |
| if ((boxa = boxaReadStream(fp)) == NULL) |
| return (BOXAA *)ERROR_PTR("boxa not made", procName, NULL); |
| boxaaAddBoxa(baa, boxa, L_INSERT); |
| } |
| |
| return baa; |
| } |
| |
| /*! |
| * boxaaWrite() |
| * |
| * Input: filename |
| * boxaa |
| * Return: 0 if OK, 1 on error |
| */ |
| l_int32 |
| boxaaWrite(const char *filename, |
| BOXAA *baa) |
| { |
| FILE *fp; |
| |
| PROCNAME("boxaaWrite"); |
| |
| if (!filename) |
| return ERROR_INT("filename not defined", procName, 1); |
| if (!baa) |
| return ERROR_INT("baa not defined", procName, 1); |
| |
| if ((fp = fopen(filename, "w")) == NULL) |
| return ERROR_INT("stream not opened", procName, 1); |
| if (boxaaWriteStream(fp, baa)) |
| return ERROR_INT("baa not written to stream", procName, 1); |
| fclose(fp); |
| |
| return 0; |
| } |
| |
| |
| /*! |
| * boxaaWriteStream() |
| * |
| * Input: stream |
| * boxaa |
| * Return: 0 if OK, 1 on error |
| */ |
| l_int32 |
| boxaaWriteStream(FILE *fp, |
| BOXAA *baa) |
| { |
| l_int32 n, i, x, y, w, h; |
| BOX *box; |
| BOXA *boxa; |
| |
| PROCNAME("boxaaWriteStream"); |
| |
| if (!fp) |
| return ERROR_INT("stream not defined", procName, 1); |
| if (!baa) |
| return ERROR_INT("baa not defined", procName, 1); |
| |
| n = boxaaGetCount(baa); |
| fprintf(fp, "\nBoxaa Version %d\n", BOXAA_VERSION_NUMBER); |
| fprintf(fp, "Number of boxa = %d\n", n); |
| |
| for (i = 0; i < n; i++) { |
| if ((boxa = boxaaGetBoxa(baa, i, L_CLONE)) == NULL) |
| return ERROR_INT("boxa not found", procName, 1); |
| boxaGetExtent(boxa, NULL, NULL, &box); |
| boxGetGeometry(box, &x, &y, &w, &h); |
| fprintf(fp, "\nBoxa[%d] extent: x = %d, y = %d, w = %d, h = %d", |
| i, x, y, w, h); |
| boxaWriteStream(fp, boxa); |
| boxDestroy(&box); |
| boxaDestroy(&boxa); |
| } |
| return 0; |
| } |
| |
| |
| /*---------------------------------------------------------------------* |
| * Boxa serialized I/O * |
| *---------------------------------------------------------------------*/ |
| /*! |
| * boxaRead() |
| * |
| * Input: filename |
| * Return: boxa, or null on error |
| */ |
| BOXA * |
| boxaRead(const char *filename) |
| { |
| FILE *fp; |
| BOXA *boxa; |
| |
| PROCNAME("boxaRead"); |
| |
| if (!filename) |
| return (BOXA *)ERROR_PTR("filename not defined", procName, NULL); |
| if ((fp = fopenReadStream(filename)) == NULL) |
| return (BOXA *)ERROR_PTR("stream not opened", procName, NULL); |
| |
| if ((boxa = boxaReadStream(fp)) == NULL) { |
| fclose(fp); |
| return (BOXA *)ERROR_PTR("boxa not read", procName, NULL); |
| } |
| |
| fclose(fp); |
| return boxa; |
| } |
| |
| |
| /*! |
| * boxaReadStream() |
| * |
| * Input: stream |
| * Return: boxa, or null on error |
| */ |
| BOXA * |
| boxaReadStream(FILE *fp) |
| { |
| l_int32 n, i, x, y, w, h, version; |
| l_int32 ignore; |
| BOX *box; |
| BOXA *boxa; |
| |
| PROCNAME("boxaReadStream"); |
| |
| if (!fp) |
| return (BOXA *)ERROR_PTR("stream not defined", procName, NULL); |
| |
| if (fscanf(fp, "\nBoxa Version %d\n", &version) != 1) |
| return (BOXA *)ERROR_PTR("not a boxa file", procName, NULL); |
| if (version != BOXA_VERSION_NUMBER) |
| return (BOXA *)ERROR_PTR("invalid boxa version", procName, NULL); |
| if (fscanf(fp, "Number of boxes = %d\n", &n) != 1) |
| return (BOXA *)ERROR_PTR("not a boxa file", procName, NULL); |
| |
| if ((boxa = boxaCreate(n)) == NULL) |
| return (BOXA *)ERROR_PTR("boxa not made", procName, NULL); |
| |
| for (i = 0; i < n; i++) { |
| if (fscanf(fp, " Box[%d]: x = %d, y = %d, w = %d, h = %d\n", |
| &ignore, &x, &y, &w, &h) != 5) |
| return (BOXA *)ERROR_PTR("box descr not valid", procName, NULL); |
| if ((box = boxCreate(x, y, w, h)) == NULL) |
| return (BOXA *)ERROR_PTR("box not made", procName, NULL); |
| boxaAddBox(boxa, box, L_INSERT); |
| } |
| |
| return boxa; |
| } |
| |
| |
| /*! |
| * boxaWrite() |
| * |
| * Input: filename |
| * boxa |
| * Return: 0 if OK, 1 on error |
| */ |
| l_int32 |
| boxaWrite(const char *filename, |
| BOXA *boxa) |
| { |
| FILE *fp; |
| |
| PROCNAME("boxaWrite"); |
| |
| if (!filename) |
| return ERROR_INT("filename not defined", procName, 1); |
| if (!boxa) |
| return ERROR_INT("boxa not defined", procName, 1); |
| |
| if ((fp = fopen(filename, "w")) == NULL) |
| return ERROR_INT("stream not opened", procName, 1); |
| if (boxaWriteStream(fp, boxa)) |
| return ERROR_INT("boxa not written to stream", procName, 1); |
| fclose(fp); |
| |
| return 0; |
| } |
| |
| |
| /*! |
| * boxaWriteStream() |
| * |
| * Input: stream |
| * boxa |
| * Return: 0 if OK, 1 on error |
| */ |
| l_int32 |
| boxaWriteStream(FILE *fp, |
| BOXA *boxa) |
| { |
| l_int32 n, i; |
| BOX *box; |
| |
| PROCNAME("boxaWriteStream"); |
| |
| if (!fp) |
| return ERROR_INT("stream not defined", procName, 1); |
| if (!boxa) |
| return ERROR_INT("boxa not defined", procName, 1); |
| |
| n = boxaGetCount(boxa); |
| fprintf(fp, "\nBoxa Version %d\n", BOXA_VERSION_NUMBER); |
| fprintf(fp, "Number of boxes = %d\n", n); |
| for (i = 0; i < n; i++) { |
| if ((box = boxaGetBox(boxa, i, L_CLONE)) == NULL) |
| return ERROR_INT("box not found", procName, 1); |
| fprintf(fp, " Box[%d]: x = %d, y = %d, w = %d, h = %d\n", |
| i, box->x, box->y, box->w, box->h); |
| boxDestroy(&box); |
| } |
| return 0; |
| } |
| |
| |
| /*---------------------------------------------------------------------* |
| * Debug printing * |
| *---------------------------------------------------------------------*/ |
| /*! |
| * boxPrintStreamInfo() |
| * |
| * Input: stream |
| * box |
| * Return: 0 if OK, 1 on error |
| * |
| * Notes: |
| * (1) This outputs information about the box, for debugging. |
| * (2) Use serialization functions to write to file if you want |
| * to read the data back. |
| */ |
| l_int32 |
| boxPrintStreamInfo(FILE *fp, |
| BOX *box) |
| { |
| PROCNAME("boxPrintStreamInfo"); |
| |
| if (!fp) |
| return ERROR_INT("stream not defined", procName, 1); |
| if (!box) |
| return ERROR_INT("box not defined", procName, 1); |
| |
| fprintf(fp, " Box x (pixels) = %d\n", box->x); |
| fprintf(fp, " Box y (pixels) = %d\n", box->y); |
| fprintf(fp, " Box width (pixels) = %d\n", box->w); |
| fprintf(fp, " Box height (pixels) = %d\n", box->h); |
| |
| return 0; |
| } |
| |
| |
| |
| /*---------------------------------------------------------------------* |
| * Version for reading v.2 boxaa; kept for backward compatibility * |
| *---------------------------------------------------------------------*/ |
| /*! |
| * boxaaReadVersion2() |
| * |
| * Input: filename |
| * Return: boxaa, or null on error |
| * |
| * Notes: |
| * (1) These old functions only work on version 2 boxaa. |
| * They will go to an archive directory sometime after Sept 2009. |
| * (2) The current format uses BOXAA_VERSION_NUMBER == 3) |
| */ |
| BOXAA * |
| boxaaReadVersion2(const char *filename) |
| { |
| FILE *fp; |
| BOXAA *baa; |
| |
| PROCNAME("boxaaReadVersion2"); |
| |
| if (!filename) |
| return (BOXAA *)ERROR_PTR("filename not defined", procName, NULL); |
| if ((fp = fopenReadStream(filename)) == NULL) |
| return (BOXAA *)ERROR_PTR("stream not opened", procName, NULL); |
| |
| if ((baa = boxaaReadStreamVersion2(fp)) == NULL) { |
| fclose(fp); |
| return (BOXAA *)ERROR_PTR("boxaa not read", procName, NULL); |
| } |
| |
| fclose(fp); |
| return baa; |
| } |
| |
| |
| /*! |
| * boxaaReadStreamVersion2() |
| * |
| * Input: stream |
| * Return: boxaa, or null on error |
| * |
| */ |
| BOXAA * |
| boxaaReadStreamVersion2(FILE *fp) |
| { |
| l_int32 n, i, x, y, w, h, version; |
| l_int32 ignore; |
| BOXA *boxa; |
| BOXAA *baa; |
| |
| PROCNAME("boxaaReadStreamVersion2"); |
| |
| if (!fp) |
| return (BOXAA *)ERROR_PTR("stream not defined", procName, NULL); |
| |
| if (fscanf(fp, "\nBoxaa Version %d\n", &version) != 1) |
| return (BOXAA *)ERROR_PTR("not a boxaa file", procName, NULL); |
| if (version != 2) { |
| fprintf(stderr, "This is version %d\n", version); |
| return (BOXAA *)ERROR_PTR("Not old version 2", procName, NULL); |
| } |
| if (fscanf(fp, "Number of boxa = %d\n", &n) != 1) |
| return (BOXAA *)ERROR_PTR("not a boxaa file", procName, NULL); |
| |
| if ((baa = boxaaCreate(n)) == NULL) |
| return (BOXAA *)ERROR_PTR("boxaa not made", procName, NULL); |
| |
| for (i = 0; i < n; i++) { |
| if (fscanf(fp, " Boxa[%d]: x = %d, y = %d, w = %d, h = %d\n", |
| &ignore, &x, &y, &w, &h) != 5) |
| return (BOXAA *)ERROR_PTR("boxa descr not valid", procName, NULL); |
| if ((boxa = boxaReadStream(fp)) == NULL) |
| return (BOXAA *)ERROR_PTR("boxa not made", procName, NULL); |
| boxaaAddBoxa(baa, boxa, L_INSERT); |
| } |
| |
| return baa; |
| } |
| |
| |