twain3.0/3rdparty/hgOCR/leptonica/ptabasic.c

1552 lines
37 KiB
C
Raw Normal View History

2021-11-20 06:24:33 +00:00
/*====================================================================*
- Copyright (C) 2001 Leptonica. All rights reserved.
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions
- are met:
- 1. Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- 2. Redistributions in binary form must reproduce the above
- copyright notice, this list of conditions and the following
- disclaimer in the documentation and/or other materials
- provided with the distribution.
-
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ANY
- CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*====================================================================*/
/*!
* \file ptabasic.c
* <pre>
*
* Pta creation, destruction, copy, clone, empty
* PTA *ptaCreate()
* PTA *ptaCreateFromNuma()
* void ptaDestroy()
* PTA *ptaCopy()
* PTA *ptaCopyRange()
* PTA *ptaClone()
* l_int32 ptaEmpty()
*
* Pta array extension
* l_int32 ptaAddPt()
* static l_int32 ptaExtendArrays()
*
* Pta insertion and removal
* l_int32 ptaInsertPt()
* l_int32 ptaRemovePt()
*
* Pta accessors
* l_int32 ptaGetRefcount()
* l_int32 ptaChangeRefcount()
* l_int32 ptaGetCount()
* l_int32 ptaGetPt()
* l_int32 ptaGetIPt()
* l_int32 ptaSetPt()
* l_int32 ptaGetArrays()
*
* Pta serialized for I/O
* PTA *ptaRead()
* PTA *ptaReadStream()
* PTA *ptaReadMem()
* l_int32 ptaWriteDebug()
* l_int32 ptaWrite()
* l_int32 ptaWriteStream()
* l_int32 ptaWriteMem()
*
* Ptaa creation, destruction
* PTAA *ptaaCreate()
* void ptaaDestroy()
*
* Ptaa array extension
* l_int32 ptaaAddPta()
* static l_int32 ptaaExtendArray()
*
* Ptaa accessors
* l_int32 ptaaGetCount()
* l_int32 ptaaGetPta()
* l_int32 ptaaGetPt()
*
* Ptaa array modifiers
* l_int32 ptaaInitFull()
* l_int32 ptaaReplacePta()
* l_int32 ptaaAddPt()
* l_int32 ptaaTruncate()
*
* Ptaa serialized for I/O
* PTAA *ptaaRead()
* PTAA *ptaaReadStream()
* PTAA *ptaaReadMem()
* l_int32 ptaaWrite()
* l_int32 ptaaWriteStream()
* l_int32 ptaaWriteMem()
* </pre>
*/
#include <string.h>
#include "allheaders.h"
static const l_uint32 MaxPtrArraySize = 10000000;
static const l_int32 InitialPtrArraySize = 50; /*!< n'importe quoi */
/* Static functions */
static l_int32 ptaExtendArrays(PTA *pta);
static l_int32 ptaaExtendArray(PTAA *ptaa);
/*---------------------------------------------------------------------*
* Pta creation, destruction, copy, clone *
*---------------------------------------------------------------------*/
/*!
* \brief ptaCreate()
*
* \param[in] n initial array sizes
* \return pta, or NULL on error.
*/
PTA *
ptaCreate(l_int32 n)
{
PTA *pta;
PROCNAME("ptaCreate");
if (n <= 0 || n > MaxPtrArraySize)
n = InitialPtrArraySize;
pta = (PTA *)LEPT_CALLOC(1, sizeof(PTA));
pta->n = 0;
pta->nalloc = n;
ptaChangeRefcount(pta, 1); /* sets to 1 */
pta->x = (l_float32 *)LEPT_CALLOC(n, sizeof(l_float32));
pta->y = (l_float32 *)LEPT_CALLOC(n, sizeof(l_float32));
if (!pta->x || !pta->y) {
ptaDestroy(&pta);
return (PTA *)ERROR_PTR("x and y arrays not both made", procName, NULL);
}
return pta;
}
/*!
* \brief ptaCreateFromNuma()
*
* \param[in] nax [optional] can be null
* \param[in] nay
* \return pta, or NULL on error.
*/
PTA *
ptaCreateFromNuma(NUMA *nax,
NUMA *nay)
{
l_int32 i, n;
l_float32 startx, delx, xval, yval;
PTA *pta;
PROCNAME("ptaCreateFromNuma");
if (!nay)
return (PTA *)ERROR_PTR("nay not defined", procName, NULL);
n = numaGetCount(nay);
if (nax && numaGetCount(nax) != n)
return (PTA *)ERROR_PTR("nax and nay sizes differ", procName, NULL);
pta = ptaCreate(n);
numaGetParameters(nay, &startx, &delx);
for (i = 0; i < n; i++) {
if (nax)
numaGetFValue(nax, i, &xval);
else /* use implicit x values from nay */
xval = startx + i * delx;
numaGetFValue(nay, i, &yval);
ptaAddPt(pta, xval, yval);
}
return pta;
}
/*!
* \brief ptaDestroy()
*
* \param[in,out] ppta will be set to null before returning
* \return void
*
* <pre>
* Notes:
* (1) Decrements the ref count and, if 0, destroys the pta.
* (2) Always nulls the input ptr.
* </pre>
*/
void
ptaDestroy(PTA **ppta)
{
PTA *pta;
PROCNAME("ptaDestroy");
if (ppta == NULL) {
L_WARNING("ptr address is NULL!\n", procName);
return;
}
if ((pta = *ppta) == NULL)
return;
ptaChangeRefcount(pta, -1);
if (ptaGetRefcount(pta) <= 0) {
LEPT_FREE(pta->x);
LEPT_FREE(pta->y);
LEPT_FREE(pta);
}
*ppta = NULL;
return;
}
/*!
* \brief ptaCopy()
*
* \param[in] pta
* \return copy of pta, or NULL on error
*/
PTA *
ptaCopy(PTA *pta)
{
l_int32 i;
l_float32 x, y;
PTA *npta;
PROCNAME("ptaCopy");
if (!pta)
return (PTA *)ERROR_PTR("pta not defined", procName, NULL);
if ((npta = ptaCreate(pta->nalloc)) == NULL)
return (PTA *)ERROR_PTR("npta not made", procName, NULL);
for (i = 0; i < pta->n; i++) {
ptaGetPt(pta, i, &x, &y);
ptaAddPt(npta, x, y);
}
return npta;
}
/*!
* \brief ptaCopyRange()
*
* \param[in] ptas
* \param[in] istart starting index in ptas
* \param[in] iend ending index in ptas; use 0 to copy to end
* \return 0 if OK, 1 on error
*/
PTA *
ptaCopyRange(PTA *ptas,
l_int32 istart,
l_int32 iend)
{
l_int32 n, i, x, y;
PTA *ptad;
PROCNAME("ptaCopyRange");
if (!ptas)
return (PTA *)ERROR_PTR("ptas not defined", procName, NULL);
n = ptaGetCount(ptas);
if (istart < 0)
istart = 0;
if (istart >= n)
return (PTA *)ERROR_PTR("istart out of bounds", procName, NULL);
if (iend <= 0 || iend >= n)
iend = n - 1;
if (istart > iend)
return (PTA *)ERROR_PTR("istart > iend; no pts", procName, NULL);
if ((ptad = ptaCreate(iend - istart + 1)) == NULL)
return (PTA *)ERROR_PTR("ptad not made", procName, NULL);
for (i = istart; i <= iend; i++) {
ptaGetIPt(ptas, i, &x, &y);
ptaAddPt(ptad, x, y);
}
return ptad;
}
/*!
* \brief ptaClone()
*
* \param[in] pta
* \return ptr to same pta, or NULL on error
*/
PTA *
ptaClone(PTA *pta)
{
PROCNAME("ptaClone");
if (!pta)
return (PTA *)ERROR_PTR("pta not defined", procName, NULL);
ptaChangeRefcount(pta, 1);
return pta;
}
/*!
* \brief ptaEmpty()
*
* \param[in] pta
* \return 0 if OK, 1 on error
*
* <pre>
* Notes:
* This only resets the Pta::n field, for reuse
* </pre>
*/
l_ok
ptaEmpty(PTA *pta)
{
PROCNAME("ptaEmpty");
if (!pta)
return ERROR_INT("ptad not defined", procName, 1);
pta->n = 0;
return 0;
}
/*---------------------------------------------------------------------*
* Pta array extension *
*---------------------------------------------------------------------*/
/*!
* \brief ptaAddPt()
*
* \param[in] pta
* \param[in] x, y
* \return 0 if OK, 1 on error
*/
l_ok
ptaAddPt(PTA *pta,
l_float32 x,
l_float32 y)
{
l_int32 n;
PROCNAME("ptaAddPt");
if (!pta)
return ERROR_INT("pta not defined", procName, 1);
n = pta->n;
if (n >= pta->nalloc)
ptaExtendArrays(pta);
pta->x[n] = x;
pta->y[n] = y;
pta->n++;
return 0;
}
/*!
* \brief ptaExtendArrays()
*
* \param[in] pta
* \return 0 if OK; 1 on error
*/
static l_int32
ptaExtendArrays(PTA *pta)
{
PROCNAME("ptaExtendArrays");
if (!pta)
return ERROR_INT("pta not defined", procName, 1);
if ((pta->x = (l_float32 *)reallocNew((void **)&pta->x,
sizeof(l_float32) * pta->nalloc,
2 * sizeof(l_float32) * pta->nalloc)) == NULL)
return ERROR_INT("new x array not returned", procName, 1);
if ((pta->y = (l_float32 *)reallocNew((void **)&pta->y,
sizeof(l_float32) * pta->nalloc,
2 * sizeof(l_float32) * pta->nalloc)) == NULL)
return ERROR_INT("new y array not returned", procName, 1);
pta->nalloc = 2 * pta->nalloc;
return 0;
}
/*---------------------------------------------------------------------*
* Pta insertion and removal *
*---------------------------------------------------------------------*/
/*!
* \brief ptaInsertPt()
*
* \param[in] pta
* \param[in] index at which pt is to be inserted
* \param[in] x, y point values
* \return 0 if OK; 1 on error
*/
l_ok
ptaInsertPt(PTA *pta,
l_int32 index,
l_int32 x,
l_int32 y)
{
l_int32 i, n;
PROCNAME("ptaInsertPt");
if (!pta)
return ERROR_INT("pta not defined", procName, 1);
n = ptaGetCount(pta);
if (index < 0 || index > n)
return ERROR_INT("index not in {0...n}", procName, 1);
if (n > pta->nalloc)
ptaExtendArrays(pta);
pta->n++;
for (i = n; i > index; i--) {
pta->x[i] = pta->x[i - 1];
pta->y[i] = pta->y[i - 1];
}
pta->x[index] = x;
pta->y[index] = y;
return 0;
}
/*!
* \brief ptaRemovePt()
*
* \param[in] pta
* \param[in] index of point to be removed
* \return 0 if OK, 1 on error
*
* <pre>
* Notes:
* (1) This shifts pta[i] --> pta[i - 1] for all i > index.
* (2) It should not be used repeatedly on large arrays,
* because the function is O(n).
* </pre>
*/
l_ok
ptaRemovePt(PTA *pta,
l_int32 index)
{
l_int32 i, n;
PROCNAME("ptaRemovePt");
if (!pta)
return ERROR_INT("pta not defined", procName, 1);
n = ptaGetCount(pta);
if (index < 0 || index >= n)
return ERROR_INT("index not in {0...n - 1}", procName, 1);
/* Remove the point */
for (i = index + 1; i < n; i++) {
pta->x[i - 1] = pta->x[i];
pta->y[i - 1] = pta->y[i];
}
pta->n--;
return 0;
}
/*---------------------------------------------------------------------*
* Pta accessors *
*---------------------------------------------------------------------*/
l_int32
ptaGetRefcount(PTA *pta)
{
PROCNAME("ptaGetRefcount");
if (!pta)
return ERROR_INT("pta not defined", procName, 1);
return pta->refcount;
}
l_int32
ptaChangeRefcount(PTA *pta,
l_int32 delta)
{
PROCNAME("ptaChangeRefcount");
if (!pta)
return ERROR_INT("pta not defined", procName, 1);
pta->refcount += delta;
return 0;
}
/*!
* \brief ptaGetCount()
*
* \param[in] pta
* \return count, or 0 if no pta
*/
l_int32
ptaGetCount(PTA *pta)
{
PROCNAME("ptaGetCount");
if (!pta)
return ERROR_INT("pta not defined", procName, 0);
return pta->n;
}
/*!
* \brief ptaGetPt()
*
* \param[in] pta
* \param[in] index into arrays
* \param[out] px [optional] float x value
* \param[out] py [optional] float y value
* \return 0 if OK; 1 on error
*/
l_ok
ptaGetPt(PTA *pta,
l_int32 index,
l_float32 *px,
l_float32 *py)
{
PROCNAME("ptaGetPt");
if (px) *px = 0;
if (py) *py = 0;
if (!pta)
return ERROR_INT("pta not defined", procName, 1);
if (index < 0 || index >= pta->n)
return ERROR_INT("invalid index", procName, 1);
if (px) *px = pta->x[index];
if (py) *py = pta->y[index];
return 0;
}
/*!
* \brief ptaGetIPt()
*
* \param[in] pta
* \param[in] index into arrays
* \param[out] px [optional] integer x value
* \param[out] py [optional] integer y value
* \return 0 if OK; 1 on error
*/
l_ok
ptaGetIPt(PTA *pta,
l_int32 index,
l_int32 *px,
l_int32 *py)
{
PROCNAME("ptaGetIPt");
if (px) *px = 0;
if (py) *py = 0;
if (!pta)
return ERROR_INT("pta not defined", procName, 1);
if (index < 0 || index >= pta->n)
return ERROR_INT("invalid index", procName, 1);
if (px) *px = (l_int32)(pta->x[index] + 0.5);
if (py) *py = (l_int32)(pta->y[index] + 0.5);
return 0;
}
/*!
* \brief ptaSetPt()
*
* \param[in] pta
* \param[in] index into arrays
* \param[in] x, y
* \return 0 if OK; 1 on error
*/
l_ok
ptaSetPt(PTA *pta,
l_int32 index,
l_float32 x,
l_float32 y)
{
PROCNAME("ptaSetPt");
if (!pta)
return ERROR_INT("pta not defined", procName, 1);
if (index < 0 || index >= pta->n)
return ERROR_INT("invalid index", procName, 1);
pta->x[index] = x;
pta->y[index] = y;
return 0;
}
/*!
* \brief ptaGetArrays()
*
* \param[in] pta
* \param[out] pnax [optional] numa of x array
* \param[out] pnay [optional] numa of y array
* \return 0 if OK; 1 on error or if pta is empty
*
* <pre>
* Notes:
* (1) This copies the internal arrays into new Numas.
* </pre>
*/
l_ok
ptaGetArrays(PTA *pta,
NUMA **pnax,
NUMA **pnay)
{
l_int32 i, n;
NUMA *nax, *nay;
PROCNAME("ptaGetArrays");
if (!pnax && !pnay)
return ERROR_INT("no output requested", procName, 1);
if (pnax) *pnax = NULL;
if (pnay) *pnay = NULL;
if (!pta)
return ERROR_INT("pta not defined", procName, 1);
if ((n = ptaGetCount(pta)) == 0)
return ERROR_INT("pta is empty", procName, 1);
if (pnax) {
if ((nax = numaCreate(n)) == NULL)
return ERROR_INT("nax not made", procName, 1);
*pnax = nax;
for (i = 0; i < n; i++)
nax->array[i] = pta->x[i];
nax->n = n;
}
if (pnay) {
if ((nay = numaCreate(n)) == NULL)
return ERROR_INT("nay not made", procName, 1);
*pnay = nay;
for (i = 0; i < n; i++)
nay->array[i] = pta->y[i];
nay->n = n;
}
return 0;
}
/*---------------------------------------------------------------------*
* Pta serialized for I/O *
*---------------------------------------------------------------------*/
/*!
* \brief ptaRead()
*
* \param[in] filename
* \return pta, or NULL on error
*/
PTA *
ptaRead(const char *filename)
{
FILE *fp;
PTA *pta;
PROCNAME("ptaRead");
if (!filename)
return (PTA *)ERROR_PTR("filename not defined", procName, NULL);
if ((fp = fopenReadStream(filename)) == NULL)
return (PTA *)ERROR_PTR("stream not opened", procName, NULL);
pta = ptaReadStream(fp);
fclose(fp);
if (!pta)
return (PTA *)ERROR_PTR("pta not read", procName, NULL);
return pta;
}
/*!
* \brief ptaReadStream()
*
* \param[in] fp file stream
* \return pta, or NULL on error
*/
PTA *
ptaReadStream(FILE *fp)
{
char typestr[128]; /* hardcoded below in fscanf */
l_int32 i, n, ix, iy, type, version;
l_float32 x, y;
PTA *pta;
PROCNAME("ptaReadStream");
if (!fp)
return (PTA *)ERROR_PTR("stream not defined", procName, NULL);
if (fscanf(fp, "\n Pta Version %d\n", &version) != 1)
return (PTA *)ERROR_PTR("not a pta file", procName, NULL);
if (version != PTA_VERSION_NUMBER)
return (PTA *)ERROR_PTR("invalid pta version", procName, NULL);
if (fscanf(fp, " Number of pts = %d; format = %127s\n", &n, typestr) != 2)
return (PTA *)ERROR_PTR("not a pta file", procName, NULL);
if (!strcmp(typestr, "float"))
type = 0;
else /* typestr is "integer" */
type = 1;
if ((pta = ptaCreate(n)) == NULL)
return (PTA *)ERROR_PTR("pta not made", procName, NULL);
for (i = 0; i < n; i++) {
if (type == 0) { /* data is float */
if (fscanf(fp, " (%f, %f)\n", &x, &y) != 2) {
ptaDestroy(&pta);
return (PTA *)ERROR_PTR("error reading floats", procName, NULL);
}
ptaAddPt(pta, x, y);
} else { /* data is integer */
if (fscanf(fp, " (%d, %d)\n", &ix, &iy) != 2) {
ptaDestroy(&pta);
return (PTA *)ERROR_PTR("error reading ints", procName, NULL);
}
ptaAddPt(pta, ix, iy);
}
}
return pta;
}
/*!
* \brief ptaReadMem()
*
* \param[in] data serialization in ascii
* \param[in] size of data in bytes; can use strlen to get it
* \return pta, or NULL on error
*/
PTA *
ptaReadMem(const l_uint8 *data,
size_t size)
{
FILE *fp;
PTA *pta;
PROCNAME("ptaReadMem");
if (!data)
return (PTA *)ERROR_PTR("data not defined", procName, NULL);
if ((fp = fopenReadFromMemory(data, size)) == NULL)
return (PTA *)ERROR_PTR("stream not opened", procName, NULL);
pta = ptaReadStream(fp);
fclose(fp);
if (!pta) L_ERROR("pta not read\n", procName);
return pta;
}
/*!
* \brief ptaWriteDebug()
*
* \param[in] filename
* \param[in] pta
* \param[in] type 0 for float values; 1 for integer values
* \return 0 if OK, 1 on error
*
* <pre>
* Notes:
* (1) Debug version, intended for use in the library when writing
* to files in a temp directory with names that are compiled in.
* This is used instead of ptaWrite() for all such library calls.
* (2) The global variable LeptDebugOK defaults to 0, and can be set
* or cleared by the function setLeptDebugOK().
* </pre>
*/
l_ok
ptaWriteDebug(const char *filename,
PTA *pta,
l_int32 type)
{
PROCNAME("ptaWriteDebug");
if (LeptDebugOK) {
return ptaWrite(filename, pta, type);
} else {
L_INFO("write to named temp file %s is disabled\n", procName, filename);
return 0;
}
}
/*!
* \brief ptaWrite()
*
* \param[in] filename
* \param[in] pta
* \param[in] type 0 for float values; 1 for integer values
* \return 0 if OK, 1 on error
*/
l_ok
ptaWrite(const char *filename,
PTA *pta,
l_int32 type)
{
l_int32 ret;
FILE *fp;
PROCNAME("ptaWrite");
if (!filename)
return ERROR_INT("filename not defined", procName, 1);
if (!pta)
return ERROR_INT("pta not defined", procName, 1);
if ((fp = fopenWriteStream(filename, "w")) == NULL)
return ERROR_INT("stream not opened", procName, 1);
ret = ptaWriteStream(fp, pta, type);
fclose(fp);
if (ret)
return ERROR_INT("pta not written to stream", procName, 1);
return 0;
}
/*!
* \brief ptaWriteStream()
*
* \param[in] fp file stream
* \param[in] pta
* \param[in] type 0 for float values; 1 for integer values
* \return 0 if OK; 1 on error
*/
l_ok
ptaWriteStream(FILE *fp,
PTA *pta,
l_int32 type)
{
l_int32 i, n, ix, iy;
l_float32 x, y;
PROCNAME("ptaWriteStream");
if (!fp)
return ERROR_INT("stream not defined", procName, 1);
if (!pta)
return ERROR_INT("pta not defined", procName, 1);
n = ptaGetCount(pta);
fprintf(fp, "\n Pta Version %d\n", PTA_VERSION_NUMBER);
if (type == 0)
fprintf(fp, " Number of pts = %d; format = float\n", n);
else /* type == 1 */
fprintf(fp, " Number of pts = %d; format = integer\n", n);
for (i = 0; i < n; i++) {
if (type == 0) { /* data is float */
ptaGetPt(pta, i, &x, &y);
fprintf(fp, " (%f, %f)\n", x, y);
} else { /* data is integer */
ptaGetIPt(pta, i, &ix, &iy);
fprintf(fp, " (%d, %d)\n", ix, iy);
}
}
return 0;
}
/*!
* \brief ptaWriteMem()
*
* \param[out] pdata data of serialized pta; ascii
* \param[out] psize size of returned data
* \param[in] pta
* \param[in] type 0 for float values; 1 for integer values
* \return 0 if OK, 1 on error
*
* <pre>
* Notes:
* (1) Serializes a pta in memory and puts the result in a buffer.
* </pre>
*/
l_ok
ptaWriteMem(l_uint8 **pdata,
size_t *psize,
PTA *pta,
l_int32 type)
{
l_int32 ret;
FILE *fp;
PROCNAME("ptaWriteMem");
if (pdata) *pdata = NULL;
if (psize) *psize = 0;
if (!pdata)
return ERROR_INT("&data not defined", procName, 1);
if (!psize)
return ERROR_INT("&size not defined", procName, 1);
if (!pta)
return ERROR_INT("pta not defined", procName, 1);
#if HAVE_FMEMOPEN
if ((fp = open_memstream((char **)pdata, psize)) == NULL)
return ERROR_INT("stream not opened", procName, 1);
ret = ptaWriteStream(fp, pta, type);
#else
L_INFO("work-around: writing to a temp file\n", procName);
#ifdef _WIN32
if ((fp = fopenWriteWinTempfile()) == NULL)
return ERROR_INT("tmpfile stream not opened", procName, 1);
#else
if ((fp = tmpfile()) == NULL)
return ERROR_INT("tmpfile stream not opened", procName, 1);
#endif /* _WIN32 */
ret = ptaWriteStream(fp, pta, type);
rewind(fp);
*pdata = l_binaryReadStream(fp, psize);
#endif /* HAVE_FMEMOPEN */
fclose(fp);
return ret;
}
/*---------------------------------------------------------------------*
* PTAA creation, destruction *
*---------------------------------------------------------------------*/
/*!
* \brief ptaaCreate()
*
* \param[in] n initial number of ptrs
* \return ptaa, or NULL on error
*/
PTAA *
ptaaCreate(l_int32 n)
{
PTAA *ptaa;
PROCNAME("ptaaCreate");
if (n <= 0 || n > MaxPtrArraySize)
n = InitialPtrArraySize;
ptaa = (PTAA *)LEPT_CALLOC(1, sizeof(PTAA));
ptaa->n = 0;
ptaa->nalloc = n;
if ((ptaa->pta = (PTA **)LEPT_CALLOC(n, sizeof(PTA *))) == NULL) {
ptaaDestroy(&ptaa);
return (PTAA *)ERROR_PTR("pta ptrs not made", procName, NULL);
}
return ptaa;
}
/*!
* \brief ptaaDestroy()
*
* \param[in,out] pptaa will be set to null before returning
* \return void
*/
void
ptaaDestroy(PTAA **pptaa)
{
l_int32 i;
PTAA *ptaa;
PROCNAME("ptaaDestroy");
if (pptaa == NULL) {
L_WARNING("ptr address is NULL!\n", procName);
return;
}
if ((ptaa = *pptaa) == NULL)
return;
for (i = 0; i < ptaa->n; i++)
ptaDestroy(&ptaa->pta[i]);
LEPT_FREE(ptaa->pta);
LEPT_FREE(ptaa);
*pptaa = NULL;
return;
}
/*---------------------------------------------------------------------*
* PTAA array extension *
*---------------------------------------------------------------------*/
/*!
* \brief ptaaAddPta()
*
* \param[in] ptaa
* \param[in] pta to be added
* \param[in] copyflag L_INSERT, L_COPY, L_CLONE
* \return 0 if OK, 1 on error
*/
l_ok
ptaaAddPta(PTAA *ptaa,
PTA *pta,
l_int32 copyflag)
{
l_int32 n;
PTA *ptac;
PROCNAME("ptaaAddPta");
if (!ptaa)
return ERROR_INT("ptaa not defined", procName, 1);
if (!pta)
return ERROR_INT("pta not defined", procName, 1);
if (copyflag == L_INSERT) {
ptac = pta;
} else if (copyflag == L_COPY) {
if ((ptac = ptaCopy(pta)) == NULL)
return ERROR_INT("ptac not made", procName, 1);
} else if (copyflag == L_CLONE) {
if ((ptac = ptaClone(pta)) == NULL)
return ERROR_INT("pta clone not made", procName, 1);
} else {
return ERROR_INT("invalid copyflag", procName, 1);
}
n = ptaaGetCount(ptaa);
if (n >= ptaa->nalloc)
ptaaExtendArray(ptaa);
ptaa->pta[n] = ptac;
ptaa->n++;
return 0;
}
/*!
* \brief ptaaExtendArray()
*
* \param[in] ptaa
* \return 0 if OK, 1 on error
*/
static l_int32
ptaaExtendArray(PTAA *ptaa)
{
PROCNAME("ptaaExtendArray");
if (!ptaa)
return ERROR_INT("ptaa not defined", procName, 1);
if ((ptaa->pta = (PTA **)reallocNew((void **)&ptaa->pta,
sizeof(PTA *) * ptaa->nalloc,
2 * sizeof(PTA *) * ptaa->nalloc)) == NULL)
return ERROR_INT("new ptr array not returned", procName, 1);
ptaa->nalloc = 2 * ptaa->nalloc;
return 0;
}
/*---------------------------------------------------------------------*
* Ptaa accessors *
*---------------------------------------------------------------------*/
/*!
* \brief ptaaGetCount()
*
* \param[in] ptaa
* \return count, or 0 if no ptaa
*/
l_int32
ptaaGetCount(PTAA *ptaa)
{
PROCNAME("ptaaGetCount");
if (!ptaa)
return ERROR_INT("ptaa not defined", procName, 0);
return ptaa->n;
}
/*!
* \brief ptaaGetPta()
*
* \param[in] ptaa
* \param[in] index to the i-th pta
* \param[in] accessflag L_COPY or L_CLONE
* \return pta, or NULL on error
*/
PTA *
ptaaGetPta(PTAA *ptaa,
l_int32 index,
l_int32 accessflag)
{
PROCNAME("ptaaGetPta");
if (!ptaa)
return (PTA *)ERROR_PTR("ptaa not defined", procName, NULL);
if (index < 0 || index >= ptaa->n)
return (PTA *)ERROR_PTR("index not valid", procName, NULL);
if (accessflag == L_COPY)
return ptaCopy(ptaa->pta[index]);
else if (accessflag == L_CLONE)
return ptaClone(ptaa->pta[index]);
else
return (PTA *)ERROR_PTR("invalid accessflag", procName, NULL);
}
/*!
* \brief ptaaGetPt()
*
* \param[in] ptaa
* \param[in] ipta to the i-th pta
* \param[in] jpt index to the j-th pt in the pta
* \param[out] px [optional] float x value
* \param[out] py [optional] float y value
* \return 0 if OK; 1 on error
*/
l_ok
ptaaGetPt(PTAA *ptaa,
l_int32 ipta,
l_int32 jpt,
l_float32 *px,
l_float32 *py)
{
PTA *pta;
PROCNAME("ptaaGetPt");
if (px) *px = 0;
if (py) *py = 0;
if (!ptaa)
return ERROR_INT("ptaa not defined", procName, 1);
if (ipta < 0 || ipta >= ptaa->n)
return ERROR_INT("index ipta not valid", procName, 1);
pta = ptaaGetPta(ptaa, ipta, L_CLONE);
if (jpt < 0 || jpt >= pta->n) {
ptaDestroy(&pta);
return ERROR_INT("index jpt not valid", procName, 1);
}
ptaGetPt(pta, jpt, px, py);
ptaDestroy(&pta);
return 0;
}
/*---------------------------------------------------------------------*
* Ptaa array modifiers *
*---------------------------------------------------------------------*/
/*!
* \brief ptaaInitFull()
*
* \param[in] ptaa can have non-null ptrs in the ptr array
* \param[in] pta to be replicated into the entire ptr array
* \return 0 if OK; 1 on error
*/
l_ok
ptaaInitFull(PTAA *ptaa,
PTA *pta)
{
l_int32 n, i;
PTA *ptat;
PROCNAME("ptaaInitFull");
if (!ptaa)
return ERROR_INT("ptaa not defined", procName, 1);
if (!pta)
return ERROR_INT("pta not defined", procName, 1);
n = ptaa->nalloc;
ptaa->n = n;
for (i = 0; i < n; i++) {
ptat = ptaCopy(pta);
ptaaReplacePta(ptaa, i, ptat);
}
return 0;
}
/*!
* \brief ptaaReplacePta()
*
* \param[in] ptaa
* \param[in] index to the index-th pta
* \param[in] pta insert and replace any existing one
* \return 0 if OK, 1 on error
*
* <pre>
* Notes:
* (1) Any existing pta is destroyed, and the input one
* is inserted in its place.
* (2) If %index is invalid, return 1 (error)
* </pre>
*/
l_ok
ptaaReplacePta(PTAA *ptaa,
l_int32 index,
PTA *pta)
{
l_int32 n;
PROCNAME("ptaaReplacePta");
if (!ptaa)
return ERROR_INT("ptaa not defined", procName, 1);
if (!pta)
return ERROR_INT("pta not defined", procName, 1);
n = ptaaGetCount(ptaa);
if (index < 0 || index >= n)
return ERROR_INT("index not valid", procName, 1);
ptaDestroy(&ptaa->pta[index]);
ptaa->pta[index] = pta;
return 0;
}
/*!
* \brief ptaaAddPt()
*
* \param[in] ptaa
* \param[in] ipta to the i-th pta
* \param[in] x,y point coordinates
* \return 0 if OK; 1 on error
*/
l_ok
ptaaAddPt(PTAA *ptaa,
l_int32 ipta,
l_float32 x,
l_float32 y)
{
PTA *pta;
PROCNAME("ptaaAddPt");
if (!ptaa)
return ERROR_INT("ptaa not defined", procName, 1);
if (ipta < 0 || ipta >= ptaa->n)
return ERROR_INT("index ipta not valid", procName, 1);
pta = ptaaGetPta(ptaa, ipta, L_CLONE);
ptaAddPt(pta, x, y);
ptaDestroy(&pta);
return 0;
}
/*!
* \brief ptaaTruncate()
*
* \param[in] ptaa
* \return 0 if OK, 1 on error
*
* <pre>
* Notes:
* (1) This identifies the largest index containing a pta that
* has any points within it, destroys all pta above that index,
* and resets the count.
* </pre>
*/
l_ok
ptaaTruncate(PTAA *ptaa)
{
l_int32 i, n, np;
PTA *pta;
PROCNAME("ptaaTruncate");
if (!ptaa)
return ERROR_INT("ptaa not defined", procName, 1);
n = ptaaGetCount(ptaa);
for (i = n - 1; i >= 0; i--) {
pta = ptaaGetPta(ptaa, i, L_CLONE);
if (!pta) {
ptaa->n--;
continue;
}
np = ptaGetCount(pta);
ptaDestroy(&pta);
if (np == 0) {
ptaDestroy(&ptaa->pta[i]);
ptaa->n--;
} else {
break;
}
}
return 0;
}
/*---------------------------------------------------------------------*
* Ptaa serialized for I/O *
*---------------------------------------------------------------------*/
/*!
* \brief ptaaRead()
*
* \param[in] filename
* \return ptaa, or NULL on error
*/
PTAA *
ptaaRead(const char *filename)
{
FILE *fp;
PTAA *ptaa;
PROCNAME("ptaaRead");
if (!filename)
return (PTAA *)ERROR_PTR("filename not defined", procName, NULL);
if ((fp = fopenReadStream(filename)) == NULL)
return (PTAA *)ERROR_PTR("stream not opened", procName, NULL);
ptaa = ptaaReadStream(fp);
fclose(fp);
if (!ptaa)
return (PTAA *)ERROR_PTR("ptaa not read", procName, NULL);
return ptaa;
}
/*!
* \brief ptaaReadStream()
*
* \param[in] fp file stream
* \return ptaa, or NULL on error
*/
PTAA *
ptaaReadStream(FILE *fp)
{
l_int32 i, n, version;
PTA *pta;
PTAA *ptaa;
PROCNAME("ptaaReadStream");
if (!fp)
return (PTAA *)ERROR_PTR("stream not defined", procName, NULL);
if (fscanf(fp, "\nPtaa Version %d\n", &version) != 1)
return (PTAA *)ERROR_PTR("not a ptaa file", procName, NULL);
if (version != PTA_VERSION_NUMBER)
return (PTAA *)ERROR_PTR("invalid ptaa version", procName, NULL);
if (fscanf(fp, "Number of Pta = %d\n", &n) != 1)
return (PTAA *)ERROR_PTR("not a ptaa file", procName, NULL);
if ((ptaa = ptaaCreate(n)) == NULL)
return (PTAA *)ERROR_PTR("ptaa not made", procName, NULL);
for (i = 0; i < n; i++) {
if ((pta = ptaReadStream(fp)) == NULL) {
ptaaDestroy(&ptaa);
return (PTAA *)ERROR_PTR("error reading pta", procName, NULL);
}
ptaaAddPta(ptaa, pta, L_INSERT);
}
return ptaa;
}
/*!
* \brief ptaaReadMem()
*
* \param[in] data serialization in ascii
* \param[in] size of data in bytes; can use strlen to get it
* \return ptaa, or NULL on error
*/
PTAA *
ptaaReadMem(const l_uint8 *data,
size_t size)
{
FILE *fp;
PTAA *ptaa;
PROCNAME("ptaaReadMem");
if (!data)
return (PTAA *)ERROR_PTR("data not defined", procName, NULL);
if ((fp = fopenReadFromMemory(data, size)) == NULL)
return (PTAA *)ERROR_PTR("stream not opened", procName, NULL);
ptaa = ptaaReadStream(fp);
fclose(fp);
if (!ptaa) L_ERROR("ptaa not read\n", procName);
return ptaa;
}
/*!
* \brief ptaaWriteDebug()
*
* \param[in] filename
* \param[in] ptaa
* \param[in] type 0 for float values; 1 for integer values
* \return 0 if OK, 1 on error
*
* <pre>
* Notes:
* (1) Debug version, intended for use in the library when writing
* to files in a temp directory with names that are compiled in.
* This is used instead of ptaaWrite() for all such library calls.
* (2) The global variable LeptDebugOK defaults to 0, and can be set
* or cleared by the function setLeptDebugOK().
* </pre>
*/
l_ok
ptaaWriteDebug(const char *filename,
PTAA *ptaa,
l_int32 type)
{
PROCNAME("ptaaWriteDebug");
if (LeptDebugOK) {
return ptaaWrite(filename, ptaa, type);
} else {
L_INFO("write to named temp file %s is disabled\n", procName, filename);
return 0;
}
}
/*!
* \brief ptaaWrite()
*
* \param[in] filename
* \param[in] ptaa
* \param[in] type 0 for float values; 1 for integer values
* \return 0 if OK, 1 on error
*/
l_ok
ptaaWrite(const char *filename,
PTAA *ptaa,
l_int32 type)
{
l_int32 ret;
FILE *fp;
PROCNAME("ptaaWrite");
if (!filename)
return ERROR_INT("filename not defined", procName, 1);
if (!ptaa)
return ERROR_INT("ptaa not defined", procName, 1);
if ((fp = fopenWriteStream(filename, "w")) == NULL)
return ERROR_INT("stream not opened", procName, 1);
ret = ptaaWriteStream(fp, ptaa, type);
fclose(fp);
if (ret)
return ERROR_INT("ptaa not written to stream", procName, 1);
return 0;
}
/*!
* \brief ptaaWriteStream()
*
* \param[in] fp file stream
* \param[in] ptaa
* \param[in] type 0 for float values; 1 for integer values
* \return 0 if OK; 1 on error
*/
l_ok
ptaaWriteStream(FILE *fp,
PTAA *ptaa,
l_int32 type)
{
l_int32 i, n;
PTA *pta;
PROCNAME("ptaaWriteStream");
if (!fp)
return ERROR_INT("stream not defined", procName, 1);
if (!ptaa)
return ERROR_INT("ptaa not defined", procName, 1);
n = ptaaGetCount(ptaa);
fprintf(fp, "\nPtaa Version %d\n", PTA_VERSION_NUMBER);
fprintf(fp, "Number of Pta = %d\n", n);
for (i = 0; i < n; i++) {
pta = ptaaGetPta(ptaa, i, L_CLONE);
ptaWriteStream(fp, pta, type);
ptaDestroy(&pta);
}
return 0;
}
/*!
* \brief ptaaWriteMem()
*
* \param[out] pdata data of serialized ptaa; ascii
* \param[out] psize size of returned data
* \param[in] ptaa
* \param[in] type 0 for float values; 1 for integer values
* \return 0 if OK, 1 on error
*
* <pre>
* Notes:
* (1) Serializes %ptaa in memory and puts the result in a buffer.
* </pre>
*/
l_ok
ptaaWriteMem(l_uint8 **pdata,
size_t *psize,
PTAA *ptaa,
l_int32 type)
{
l_int32 ret;
FILE *fp;
PROCNAME("ptaaWriteMem");
if (pdata) *pdata = NULL;
if (psize) *psize = 0;
if (!pdata)
return ERROR_INT("&data not defined", procName, 1);
if (!psize)
return ERROR_INT("&size not defined", procName, 1);
if (!ptaa)
return ERROR_INT("ptaa not defined", procName, 1);
#if HAVE_FMEMOPEN
if ((fp = open_memstream((char **)pdata, psize)) == NULL)
return ERROR_INT("stream not opened", procName, 1);
ret = ptaaWriteStream(fp, ptaa, type);
#else
L_INFO("work-around: writing to a temp file\n", procName);
#ifdef _WIN32
if ((fp = fopenWriteWinTempfile()) == NULL)
return ERROR_INT("tmpfile stream not opened", procName, 1);
#else
if ((fp = tmpfile()) == NULL)
return ERROR_INT("tmpfile stream not opened", procName, 1);
#endif /* _WIN32 */
ret = ptaaWriteStream(fp, ptaa, type);
rewind(fp);
*pdata = l_binaryReadStream(fp, psize);
#endif /* HAVE_FMEMOPEN */
fclose(fp);
return ret;
}