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 
28 /*!
29  * \file  ptabasic.c
30  * <pre>
31  *
32  *      Pta creation, destruction, copy, clone, empty
33  *           PTA            *ptaCreate()
34  *           PTA            *ptaCreateFromNuma()
35  *           void            ptaDestroy()
36  *           PTA            *ptaCopy()
37  *           PTA            *ptaCopyRange()
38  *           PTA            *ptaClone()
39  *           l_int32         ptaEmpty()
40  *
41  *      Pta array extension
42  *           l_int32         ptaAddPt()
43  *           static l_int32  ptaExtendArrays()
44  *
45  *      Pta insertion and removal
46  *           l_int32         ptaInsertPt()
47  *           l_int32         ptaRemovePt()
48  *
49  *      Pta accessors
50  *           l_int32         ptaGetRefcount()
51  *           l_int32         ptaChangeRefcount()
52  *           l_int32         ptaGetCount()
53  *           l_int32         ptaGetPt()
54  *           l_int32         ptaGetIPt()
55  *           l_int32         ptaSetPt()
56  *           l_int32         ptaGetArrays()
57  *
58  *      Pta serialized for I/O
59  *           PTA            *ptaRead()
60  *           PTA            *ptaReadStream()
61  *           PTA            *ptaReadMem()
62  *           l_int32         ptaWriteDebug()
63  *           l_int32         ptaWrite()
64  *           l_int32         ptaWriteStream()
65  *           l_int32         ptaWriteMem()
66  *
67  *      Ptaa creation, destruction
68  *           PTAA           *ptaaCreate()
69  *           void            ptaaDestroy()
70  *
71  *      Ptaa array extension
72  *           l_int32         ptaaAddPta()
73  *           static l_int32  ptaaExtendArray()
74  *
75  *      Ptaa accessors
76  *           l_int32         ptaaGetCount()
77  *           l_int32         ptaaGetPta()
78  *           l_int32         ptaaGetPt()
79  *
80  *      Ptaa array modifiers
81  *           l_int32         ptaaInitFull()
82  *           l_int32         ptaaReplacePta()
83  *           l_int32         ptaaAddPt()
84  *           l_int32         ptaaTruncate()
85  *
86  *      Ptaa serialized for I/O
87  *           PTAA           *ptaaRead()
88  *           PTAA           *ptaaReadStream()
89  *           PTAA           *ptaaReadMem()
90  *           l_int32         ptaaWrite()
91  *           l_int32         ptaaWriteStream()
92  *           l_int32         ptaaWriteMem()
93  * </pre>
94  */
95 
96 #include <string.h>
97 #include "allheaders.h"
98 
99 static const l_int32  INITIAL_PTR_ARRAYSIZE = 20;   /* n'import quoi */
100 
101     /* Static functions */
102 static l_int32 ptaExtendArrays(PTA *pta);
103 static l_int32 ptaaExtendArray(PTAA *ptaa);
104 
105 
106 /*---------------------------------------------------------------------*
107  *                Pta creation, destruction, copy, clone               *
108  *---------------------------------------------------------------------*/
109 /*!
110  * \brief   ptaCreate()
111  *
112  * \param[in]    n  initial array sizes
113  * \return  pta, or NULL on error.
114  */
115 PTA *
ptaCreate(l_int32 n)116 ptaCreate(l_int32  n)
117 {
118 PTA  *pta;
119 
120     PROCNAME("ptaCreate");
121 
122     if (n <= 0)
123         n = INITIAL_PTR_ARRAYSIZE;
124 
125     pta = (PTA *)LEPT_CALLOC(1, sizeof(PTA));
126     pta->n = 0;
127     pta->nalloc = n;
128     ptaChangeRefcount(pta, 1);  /* sets to 1 */
129 
130     pta->x = (l_float32 *)LEPT_CALLOC(n, sizeof(l_float32));
131     pta->y = (l_float32 *)LEPT_CALLOC(n, sizeof(l_float32));
132     if (!pta->x || !pta->y) {
133         ptaDestroy(&pta);
134         return (PTA *)ERROR_PTR("x and y arrays not both made", procName, NULL);
135     }
136 
137     return pta;
138 }
139 
140 
141 /*!
142  * \brief   ptaCreateFromNuma()
143  *
144  * \param[in]    nax [optional] can be null
145  * \param[in]    nay
146  * \return  pta, or NULL on error.
147  */
148 PTA *
ptaCreateFromNuma(NUMA * nax,NUMA * nay)149 ptaCreateFromNuma(NUMA  *nax,
150                   NUMA  *nay)
151 {
152 l_int32    i, n;
153 l_float32  startx, delx, xval, yval;
154 PTA       *pta;
155 
156     PROCNAME("ptaCreateFromNuma");
157 
158     if (!nay)
159         return (PTA *)ERROR_PTR("nay not defined", procName, NULL);
160     n = numaGetCount(nay);
161     if (nax && numaGetCount(nax) != n)
162         return (PTA *)ERROR_PTR("nax and nay sizes differ", procName, NULL);
163 
164     pta = ptaCreate(n);
165     numaGetParameters(nay, &startx, &delx);
166     for (i = 0; i < n; i++) {
167         if (nax)
168             numaGetFValue(nax, i, &xval);
169         else  /* use implicit x values from nay */
170             xval = startx + i * delx;
171         numaGetFValue(nay, i, &yval);
172         ptaAddPt(pta, xval, yval);
173     }
174 
175     return pta;
176 }
177 
178 
179 /*!
180  * \brief   ptaDestroy()
181  *
182  * \param[in,out]   ppta to be nulled
183  * \return  void
184  *
185  * <pre>
186  * Notes:
187  *      (1) Decrements the ref count and, if 0, destroys the pta.
188  *      (2) Always nulls the input ptr.
189  * </pre>
190  */
191 void
ptaDestroy(PTA ** ppta)192 ptaDestroy(PTA  **ppta)
193 {
194 PTA  *pta;
195 
196     PROCNAME("ptaDestroy");
197 
198     if (ppta == NULL) {
199         L_WARNING("ptr address is NULL!\n", procName);
200         return;
201     }
202 
203     if ((pta = *ppta) == NULL)
204         return;
205 
206     ptaChangeRefcount(pta, -1);
207     if (ptaGetRefcount(pta) <= 0) {
208         LEPT_FREE(pta->x);
209         LEPT_FREE(pta->y);
210         LEPT_FREE(pta);
211     }
212 
213     *ppta = NULL;
214     return;
215 }
216 
217 
218 /*!
219  * \brief   ptaCopy()
220  *
221  * \param[in]    pta
222  * \return  copy of pta, or NULL on error
223  */
224 PTA *
ptaCopy(PTA * pta)225 ptaCopy(PTA  *pta)
226 {
227 l_int32    i;
228 l_float32  x, y;
229 PTA       *npta;
230 
231     PROCNAME("ptaCopy");
232 
233     if (!pta)
234         return (PTA *)ERROR_PTR("pta not defined", procName, NULL);
235 
236     if ((npta = ptaCreate(pta->nalloc)) == NULL)
237         return (PTA *)ERROR_PTR("npta not made", procName, NULL);
238 
239     for (i = 0; i < pta->n; i++) {
240         ptaGetPt(pta, i, &x, &y);
241         ptaAddPt(npta, x, y);
242     }
243 
244     return npta;
245 }
246 
247 
248 /*!
249  * \brief   ptaCopyRange()
250  *
251  * \param[in]    ptas
252  * \param[in]    istart  starting index in ptas
253  * \param[in]    iend  ending index in ptas; use 0 to copy to end
254  * \return  0 if OK, 1 on error
255  */
256 PTA *
ptaCopyRange(PTA * ptas,l_int32 istart,l_int32 iend)257 ptaCopyRange(PTA     *ptas,
258              l_int32  istart,
259              l_int32  iend)
260 {
261 l_int32  n, i, x, y;
262 PTA     *ptad;
263 
264     PROCNAME("ptaCopyRange");
265 
266     if (!ptas)
267         return (PTA *)ERROR_PTR("ptas not defined", procName, NULL);
268     n = ptaGetCount(ptas);
269     if (istart < 0)
270         istart = 0;
271     if (istart >= n)
272         return (PTA *)ERROR_PTR("istart out of bounds", procName, NULL);
273     if (iend <= 0 || iend >= n)
274         iend = n - 1;
275     if (istart > iend)
276         return (PTA *)ERROR_PTR("istart > iend; no pts", procName, NULL);
277 
278     if ((ptad = ptaCreate(iend - istart + 1)) == NULL)
279         return (PTA *)ERROR_PTR("ptad not made", procName, NULL);
280     for (i = istart; i <= iend; i++) {
281         ptaGetIPt(ptas, i, &x, &y);
282         ptaAddPt(ptad, x, y);
283     }
284 
285     return ptad;
286 }
287 
288 
289 /*!
290  * \brief   ptaClone()
291  *
292  * \param[in]    pta
293  * \return  ptr to same pta, or NULL on error
294  */
295 PTA *
ptaClone(PTA * pta)296 ptaClone(PTA  *pta)
297 {
298     PROCNAME("ptaClone");
299 
300     if (!pta)
301         return (PTA *)ERROR_PTR("pta not defined", procName, NULL);
302 
303     ptaChangeRefcount(pta, 1);
304     return pta;
305 }
306 
307 
308 /*!
309  * \brief   ptaEmpty()
310  *
311  * \param[in]    pta
312  * \return  0 if OK, 1 on error
313  *
314  * <pre>
315  * Notes:
316  *      This only resets the Pta::n field, for reuse
317  * </pre>
318  */
319 l_int32
ptaEmpty(PTA * pta)320 ptaEmpty(PTA  *pta)
321 {
322     PROCNAME("ptaEmpty");
323 
324     if (!pta)
325         return ERROR_INT("ptad not defined", procName, 1);
326     pta->n = 0;
327     return 0;
328 }
329 
330 
331 /*---------------------------------------------------------------------*
332  *                         Pta array extension                         *
333  *---------------------------------------------------------------------*/
334 /*!
335  * \brief   ptaAddPt()
336  *
337  * \param[in]    pta
338  * \param[in]    x, y
339  * \return  0 if OK, 1 on error
340  */
341 l_int32
ptaAddPt(PTA * pta,l_float32 x,l_float32 y)342 ptaAddPt(PTA       *pta,
343          l_float32  x,
344          l_float32  y)
345 {
346 l_int32  n;
347 
348     PROCNAME("ptaAddPt");
349 
350     if (!pta)
351         return ERROR_INT("pta not defined", procName, 1);
352 
353     n = pta->n;
354     if (n >= pta->nalloc)
355         ptaExtendArrays(pta);
356     pta->x[n] = x;
357     pta->y[n] = y;
358     pta->n++;
359 
360     return 0;
361 }
362 
363 
364 /*!
365  * \brief   ptaExtendArrays()
366  *
367  * \param[in]    pta
368  * \return  0 if OK; 1 on error
369  */
370 static l_int32
ptaExtendArrays(PTA * pta)371 ptaExtendArrays(PTA  *pta)
372 {
373     PROCNAME("ptaExtendArrays");
374 
375     if (!pta)
376         return ERROR_INT("pta not defined", procName, 1);
377 
378     if ((pta->x = (l_float32 *)reallocNew((void **)&pta->x,
379                                sizeof(l_float32) * pta->nalloc,
380                                2 * sizeof(l_float32) * pta->nalloc)) == NULL)
381         return ERROR_INT("new x array not returned", procName, 1);
382     if ((pta->y = (l_float32 *)reallocNew((void **)&pta->y,
383                                sizeof(l_float32) * pta->nalloc,
384                                2 * sizeof(l_float32) * pta->nalloc)) == NULL)
385         return ERROR_INT("new y array not returned", procName, 1);
386 
387     pta->nalloc = 2 * pta->nalloc;
388     return 0;
389 }
390 
391 
392 /*---------------------------------------------------------------------*
393  *                     Pta insertion and removal                       *
394  *---------------------------------------------------------------------*/
395 /*!
396  * \brief   ptaInsertPt()
397  *
398  * \param[in]    pta
399  * \param[in]    index at which pt is to be inserted
400  * \param[in]    x, y point values
401  * \return  0 if OK; 1 on error
402  */
403 l_int32
ptaInsertPt(PTA * pta,l_int32 index,l_int32 x,l_int32 y)404 ptaInsertPt(PTA     *pta,
405             l_int32  index,
406             l_int32  x,
407             l_int32  y)
408 {
409 l_int32  i, n;
410 
411     PROCNAME("ptaInsertPt");
412 
413     if (!pta)
414         return ERROR_INT("pta not defined", procName, 1);
415     n = ptaGetCount(pta);
416     if (index < 0 || index > n)
417         return ERROR_INT("index not in {0...n}", procName, 1);
418 
419     if (n > pta->nalloc)
420         ptaExtendArrays(pta);
421     pta->n++;
422     for (i = n; i > index; i--) {
423         pta->x[i] = pta->x[i - 1];
424         pta->y[i] = pta->y[i - 1];
425     }
426     pta->x[index] = x;
427     pta->y[index] = y;
428     return 0;
429 }
430 
431 
432 /*!
433  * \brief   ptaRemovePt()
434  *
435  * \param[in]    pta
436  * \param[in]    index of point to be removed
437  * \return  0 if OK, 1 on error
438  *
439  * <pre>
440  * Notes:
441  *      (1) This shifts pta[i] --> pta[i - 1] for all i > index.
442  *      (2) It should not be used repeatedly on large arrays,
443  *          because the function is O(n).
444  * </pre>
445  */
446 l_int32
ptaRemovePt(PTA * pta,l_int32 index)447 ptaRemovePt(PTA     *pta,
448             l_int32  index)
449 {
450 l_int32  i, n;
451 
452     PROCNAME("ptaRemovePt");
453 
454     if (!pta)
455         return ERROR_INT("pta not defined", procName, 1);
456     n = ptaGetCount(pta);
457     if (index < 0 || index >= n)
458         return ERROR_INT("index not in {0...n - 1}", procName, 1);
459 
460         /* Remove the point */
461     for (i = index + 1; i < n; i++) {
462         pta->x[i - 1] = pta->x[i];
463         pta->y[i - 1] = pta->y[i];
464     }
465     pta->n--;
466     return 0;
467 }
468 
469 
470 /*---------------------------------------------------------------------*
471  *                           Pta accessors                             *
472  *---------------------------------------------------------------------*/
473 l_int32
ptaGetRefcount(PTA * pta)474 ptaGetRefcount(PTA  *pta)
475 {
476     PROCNAME("ptaGetRefcount");
477 
478     if (!pta)
479         return ERROR_INT("pta not defined", procName, 1);
480     return pta->refcount;
481 }
482 
483 
484 l_int32
ptaChangeRefcount(PTA * pta,l_int32 delta)485 ptaChangeRefcount(PTA     *pta,
486                   l_int32  delta)
487 {
488     PROCNAME("ptaChangeRefcount");
489 
490     if (!pta)
491         return ERROR_INT("pta not defined", procName, 1);
492     pta->refcount += delta;
493     return 0;
494 }
495 
496 
497 /*!
498  * \brief   ptaGetCount()
499  *
500  * \param[in]    pta
501  * \return  count, or 0 if no pta
502  */
503 l_int32
ptaGetCount(PTA * pta)504 ptaGetCount(PTA  *pta)
505 {
506     PROCNAME("ptaGetCount");
507 
508     if (!pta)
509         return ERROR_INT("pta not defined", procName, 0);
510 
511     return pta->n;
512 }
513 
514 
515 /*!
516  * \brief   ptaGetPt()
517  *
518  * \param[in]    pta
519  * \param[in]    index  into arrays
520  * \param[out]   px [optional] float x value
521  * \param[out]   py [optional] float y value
522  * \return  0 if OK; 1 on error
523  */
524 l_int32
ptaGetPt(PTA * pta,l_int32 index,l_float32 * px,l_float32 * py)525 ptaGetPt(PTA        *pta,
526          l_int32     index,
527          l_float32  *px,
528          l_float32  *py)
529 {
530     PROCNAME("ptaGetPt");
531 
532     if (px) *px = 0;
533     if (py) *py = 0;
534     if (!pta)
535         return ERROR_INT("pta not defined", procName, 1);
536     if (index < 0 || index >= pta->n)
537         return ERROR_INT("invalid index", procName, 1);
538 
539     if (px) *px = pta->x[index];
540     if (py) *py = pta->y[index];
541     return 0;
542 }
543 
544 
545 /*!
546  * \brief   ptaGetIPt()
547  *
548  * \param[in]    pta
549  * \param[in]    index  into arrays
550  * \param[out]   px [optional] integer x value
551  * \param[out]   py [optional] integer y value
552  * \return  0 if OK; 1 on error
553  */
554 l_int32
ptaGetIPt(PTA * pta,l_int32 index,l_int32 * px,l_int32 * py)555 ptaGetIPt(PTA      *pta,
556           l_int32   index,
557           l_int32  *px,
558           l_int32  *py)
559 {
560     PROCNAME("ptaGetIPt");
561 
562     if (px) *px = 0;
563     if (py) *py = 0;
564     if (!pta)
565         return ERROR_INT("pta not defined", procName, 1);
566     if (index < 0 || index >= pta->n)
567         return ERROR_INT("invalid index", procName, 1);
568 
569     if (px) *px = (l_int32)(pta->x[index] + 0.5);
570     if (py) *py = (l_int32)(pta->y[index] + 0.5);
571     return 0;
572 }
573 
574 
575 /*!
576  * \brief   ptaSetPt()
577  *
578  * \param[in]    pta
579  * \param[in]    index  into arrays
580  * \param[in]    x, y
581  * \return  0 if OK; 1 on error
582  */
583 l_int32
ptaSetPt(PTA * pta,l_int32 index,l_float32 x,l_float32 y)584 ptaSetPt(PTA       *pta,
585          l_int32    index,
586          l_float32  x,
587          l_float32  y)
588 {
589     PROCNAME("ptaSetPt");
590 
591     if (!pta)
592         return ERROR_INT("pta not defined", procName, 1);
593     if (index < 0 || index >= pta->n)
594         return ERROR_INT("invalid index", procName, 1);
595 
596     pta->x[index] = x;
597     pta->y[index] = y;
598     return 0;
599 }
600 
601 
602 /*!
603  * \brief   ptaGetArrays()
604  *
605  * \param[in]    pta
606  * \param[out]   pnax [optional] numa of x array
607  * \param[out]   pnay [optional] numa of y array
608  * \return  0 if OK; 1 on error or if pta is empty
609  *
610  * <pre>
611  * Notes:
612  *      (1) This copies the internal arrays into new Numas.
613  * </pre>
614  */
615 l_int32
ptaGetArrays(PTA * pta,NUMA ** pnax,NUMA ** pnay)616 ptaGetArrays(PTA    *pta,
617              NUMA  **pnax,
618              NUMA  **pnay)
619 {
620 l_int32  i, n;
621 NUMA    *nax, *nay;
622 
623     PROCNAME("ptaGetArrays");
624 
625     if (!pnax && !pnay)
626         return ERROR_INT("no output requested", procName, 1);
627     if (pnax) *pnax = NULL;
628     if (pnay) *pnay = NULL;
629     if (!pta)
630         return ERROR_INT("pta not defined", procName, 1);
631     if ((n = ptaGetCount(pta)) == 0)
632         return ERROR_INT("pta is empty", procName, 1);
633 
634     if (pnax) {
635         if ((nax = numaCreate(n)) == NULL)
636             return ERROR_INT("nax not made", procName, 1);
637         *pnax = nax;
638         for (i = 0; i < n; i++)
639             nax->array[i] = pta->x[i];
640         nax->n = n;
641     }
642     if (pnay) {
643         if ((nay = numaCreate(n)) == NULL)
644             return ERROR_INT("nay not made", procName, 1);
645         *pnay = nay;
646         for (i = 0; i < n; i++)
647             nay->array[i] = pta->y[i];
648         nay->n = n;
649     }
650     return 0;
651 }
652 
653 
654 /*---------------------------------------------------------------------*
655  *                       Pta serialized for I/O                        *
656  *---------------------------------------------------------------------*/
657 /*!
658  * \brief   ptaRead()
659  *
660  * \param[in]    filename
661  * \return  pta, or NULL on error
662  */
663 PTA *
ptaRead(const char * filename)664 ptaRead(const char  *filename)
665 {
666 FILE  *fp;
667 PTA   *pta;
668 
669     PROCNAME("ptaRead");
670 
671     if (!filename)
672         return (PTA *)ERROR_PTR("filename not defined", procName, NULL);
673 
674     if ((fp = fopenReadStream(filename)) == NULL)
675         return (PTA *)ERROR_PTR("stream not opened", procName, NULL);
676     pta = ptaReadStream(fp);
677     fclose(fp);
678     if (!pta)
679         return (PTA *)ERROR_PTR("pta not read", procName, NULL);
680     return pta;
681 }
682 
683 
684 /*!
685  * \brief   ptaReadStream()
686  *
687  * \param[in]    fp file stream
688  * \return  pta, or NULL on error
689  */
690 PTA *
ptaReadStream(FILE * fp)691 ptaReadStream(FILE  *fp)
692 {
693 char       typestr[128];  /* hardcoded below in fscanf */
694 l_int32    i, n, ix, iy, type, version;
695 l_float32  x, y;
696 PTA       *pta;
697 
698     PROCNAME("ptaReadStream");
699 
700     if (!fp)
701         return (PTA *)ERROR_PTR("stream not defined", procName, NULL);
702 
703     if (fscanf(fp, "\n Pta Version %d\n", &version) != 1)
704         return (PTA *)ERROR_PTR("not a pta file", procName, NULL);
705     if (version != PTA_VERSION_NUMBER)
706         return (PTA *)ERROR_PTR("invalid pta version", procName, NULL);
707     if (fscanf(fp, " Number of pts = %d; format = %127s\n", &n, typestr) != 2)
708         return (PTA *)ERROR_PTR("not a pta file", procName, NULL);
709     if (!strcmp(typestr, "float"))
710         type = 0;
711     else  /* typestr is "integer" */
712         type = 1;
713 
714     if ((pta = ptaCreate(n)) == NULL)
715         return (PTA *)ERROR_PTR("pta not made", procName, NULL);
716     for (i = 0; i < n; i++) {
717         if (type == 0) {  /* data is float */
718             if (fscanf(fp, "   (%f, %f)\n", &x, &y) != 2) {
719                 ptaDestroy(&pta);
720                 return (PTA *)ERROR_PTR("error reading floats", procName, NULL);
721             }
722             ptaAddPt(pta, x, y);
723         } else {   /* data is integer */
724             if (fscanf(fp, "   (%d, %d)\n", &ix, &iy) != 2) {
725                 ptaDestroy(&pta);
726                 return (PTA *)ERROR_PTR("error reading ints", procName, NULL);
727             }
728             ptaAddPt(pta, ix, iy);
729         }
730     }
731 
732     return pta;
733 }
734 
735 
736 /*!
737  * \brief   ptaReadMem()
738  *
739  * \param[in]    data  serialization in ascii
740  * \param[in]    size  of data in bytes; can use strlen to get it
741  * \return  pta, or NULL on error
742  */
743 PTA *
ptaReadMem(const l_uint8 * data,size_t size)744 ptaReadMem(const l_uint8  *data,
745            size_t          size)
746 {
747 FILE  *fp;
748 PTA   *pta;
749 
750     PROCNAME("ptaReadMem");
751 
752     if (!data)
753         return (PTA *)ERROR_PTR("data not defined", procName, NULL);
754     if ((fp = fopenReadFromMemory(data, size)) == NULL)
755         return (PTA *)ERROR_PTR("stream not opened", procName, NULL);
756 
757     pta = ptaReadStream(fp);
758     fclose(fp);
759     if (!pta) L_ERROR("pta not read\n", procName);
760     return pta;
761 }
762 
763 
764 /*!
765  * \brief   ptaWriteDebug()
766  *
767  * \param[in]    filename
768  * \param[in]    pta
769  * \param[in]    type  0 for float values; 1 for integer values
770  * \return  0 if OK, 1 on error
771  *
772  * <pre>
773  * Notes:
774  *      (1) Debug version, intended for use in the library when writing
775  *          to files in a temp directory with names that are compiled in.
776  *          This is used instead of ptaWrite() for all such library calls.
777  *      (2) The global variable LeptDebugOK defaults to 0, and can be set
778  *          or cleared by the function setLeptDebugOK().
779  * </pre>
780  */
781 l_int32
ptaWriteDebug(const char * filename,PTA * pta,l_int32 type)782 ptaWriteDebug(const char  *filename,
783               PTA         *pta,
784               l_int32      type)
785 {
786     PROCNAME("ptaWriteDebug");
787 
788     if (LeptDebugOK) {
789         return ptaWrite(filename, pta, type);
790     } else {
791         L_INFO("write to named temp file %s is disabled\n", procName, filename);
792         return 0;
793     }
794 }
795 
796 
797 /*!
798  * \brief   ptaWrite()
799  *
800  * \param[in]    filename
801  * \param[in]    pta
802  * \param[in]    type  0 for float values; 1 for integer values
803  * \return  0 if OK, 1 on error
804  */
805 l_int32
ptaWrite(const char * filename,PTA * pta,l_int32 type)806 ptaWrite(const char  *filename,
807          PTA         *pta,
808          l_int32      type)
809 {
810 l_int32  ret;
811 FILE    *fp;
812 
813     PROCNAME("ptaWrite");
814 
815     if (!filename)
816         return ERROR_INT("filename not defined", procName, 1);
817     if (!pta)
818         return ERROR_INT("pta not defined", procName, 1);
819 
820     if ((fp = fopenWriteStream(filename, "w")) == NULL)
821         return ERROR_INT("stream not opened", procName, 1);
822     ret = ptaWriteStream(fp, pta, type);
823     fclose(fp);
824     if (ret)
825         return ERROR_INT("pta not written to stream", procName, 1);
826     return 0;
827 }
828 
829 
830 /*!
831  * \brief   ptaWriteStream()
832  *
833  * \param[in]    fp file stream
834  * \param[in]    pta
835  * \param[in]    type  0 for float values; 1 for integer values
836  * \return  0 if OK; 1 on error
837  */
838 l_int32
ptaWriteStream(FILE * fp,PTA * pta,l_int32 type)839 ptaWriteStream(FILE    *fp,
840                PTA     *pta,
841                l_int32  type)
842 {
843 l_int32    i, n, ix, iy;
844 l_float32  x, y;
845 
846     PROCNAME("ptaWriteStream");
847 
848     if (!fp)
849         return ERROR_INT("stream not defined", procName, 1);
850     if (!pta)
851         return ERROR_INT("pta not defined", procName, 1);
852 
853     n = ptaGetCount(pta);
854     fprintf(fp, "\n Pta Version %d\n", PTA_VERSION_NUMBER);
855     if (type == 0)
856         fprintf(fp, " Number of pts = %d; format = float\n", n);
857     else  /* type == 1 */
858         fprintf(fp, " Number of pts = %d; format = integer\n", n);
859     for (i = 0; i < n; i++) {
860         if (type == 0) {  /* data is float */
861             ptaGetPt(pta, i, &x, &y);
862             fprintf(fp, "   (%f, %f)\n", x, y);
863         } else {   /* data is integer */
864             ptaGetIPt(pta, i, &ix, &iy);
865             fprintf(fp, "   (%d, %d)\n", ix, iy);
866         }
867     }
868 
869     return 0;
870 }
871 
872 
873 /*!
874  * \brief   ptaWriteMem()
875  *
876  * \param[out]   pdata data of serialized pta; ascii
877  * \param[out]   psize size of returned data
878  * \param[in]    pta
879  * \param[in]    type  0 for float values; 1 for integer values
880  * \return  0 if OK, 1 on error
881  *
882  * <pre>
883  * Notes:
884  *      (1) Serializes a pta in memory and puts the result in a buffer.
885  * </pre>
886  */
887 l_int32
ptaWriteMem(l_uint8 ** pdata,size_t * psize,PTA * pta,l_int32 type)888 ptaWriteMem(l_uint8  **pdata,
889             size_t    *psize,
890             PTA       *pta,
891             l_int32    type)
892 {
893 l_int32  ret;
894 FILE    *fp;
895 
896     PROCNAME("ptaWriteMem");
897 
898     if (pdata) *pdata = NULL;
899     if (psize) *psize = 0;
900     if (!pdata)
901         return ERROR_INT("&data not defined", procName, 1);
902     if (!psize)
903         return ERROR_INT("&size not defined", procName, 1);
904     if (!pta)
905         return ERROR_INT("pta not defined", procName, 1);
906 
907 #if HAVE_FMEMOPEN
908     if ((fp = open_memstream((char **)pdata, psize)) == NULL)
909         return ERROR_INT("stream not opened", procName, 1);
910     ret = ptaWriteStream(fp, pta, type);
911 #else
912     L_INFO("work-around: writing to a temp file\n", procName);
913   #ifdef _WIN32
914     if ((fp = fopenWriteWinTempfile()) == NULL)
915         return ERROR_INT("tmpfile stream not opened", procName, 1);
916   #else
917     if ((fp = tmpfile()) == NULL)
918         return ERROR_INT("tmpfile stream not opened", procName, 1);
919   #endif  /* _WIN32 */
920     ret = ptaWriteStream(fp, pta, type);
921     rewind(fp);
922     *pdata = l_binaryReadStream(fp, psize);
923 #endif  /* HAVE_FMEMOPEN */
924     fclose(fp);
925     return ret;
926 }
927 
928 
929 /*---------------------------------------------------------------------*
930  *                     PTAA creation, destruction                      *
931  *---------------------------------------------------------------------*/
932 /*!
933  * \brief   ptaaCreate()
934  *
935  * \param[in]    n  initial number of ptrs
936  * \return  ptaa, or NULL on error
937  */
938 PTAA *
ptaaCreate(l_int32 n)939 ptaaCreate(l_int32  n)
940 {
941 PTAA  *ptaa;
942 
943     PROCNAME("ptaaCreate");
944 
945     if (n <= 0)
946         n = INITIAL_PTR_ARRAYSIZE;
947 
948     if ((ptaa = (PTAA *)LEPT_CALLOC(1, sizeof(PTAA))) == NULL)
949         return (PTAA *)ERROR_PTR("ptaa not made", procName, NULL);
950     ptaa->n = 0;
951     ptaa->nalloc = n;
952     if ((ptaa->pta = (PTA **)LEPT_CALLOC(n, sizeof(PTA *))) == NULL) {
953         ptaaDestroy(&ptaa);
954         return (PTAA *)ERROR_PTR("pta ptrs not made", procName, NULL);
955     }
956     return ptaa;
957 }
958 
959 
960 /*!
961  * \brief   ptaaDestroy()
962  *
963  * \param[in,out]   pptaa to be nulled
964  * \return  void
965  */
966 void
ptaaDestroy(PTAA ** pptaa)967 ptaaDestroy(PTAA  **pptaa)
968 {
969 l_int32  i;
970 PTAA    *ptaa;
971 
972     PROCNAME("ptaaDestroy");
973 
974     if (pptaa == NULL) {
975         L_WARNING("ptr address is NULL!\n", procName);
976         return;
977     }
978 
979     if ((ptaa = *pptaa) == NULL)
980         return;
981 
982     for (i = 0; i < ptaa->n; i++)
983         ptaDestroy(&ptaa->pta[i]);
984     LEPT_FREE(ptaa->pta);
985 
986     LEPT_FREE(ptaa);
987     *pptaa = NULL;
988     return;
989 }
990 
991 
992 /*---------------------------------------------------------------------*
993  *                          PTAA array extension                       *
994  *---------------------------------------------------------------------*/
995 /*!
996  * \brief   ptaaAddPta()
997  *
998  * \param[in]    ptaa
999  * \param[in]    pta  to be added
1000  * \param[in]    copyflag  L_INSERT, L_COPY, L_CLONE
1001  * \return  0 if OK, 1 on error
1002  */
1003 l_int32
ptaaAddPta(PTAA * ptaa,PTA * pta,l_int32 copyflag)1004 ptaaAddPta(PTAA    *ptaa,
1005            PTA     *pta,
1006            l_int32  copyflag)
1007 {
1008 l_int32  n;
1009 PTA     *ptac;
1010 
1011     PROCNAME("ptaaAddPta");
1012 
1013     if (!ptaa)
1014         return ERROR_INT("ptaa not defined", procName, 1);
1015     if (!pta)
1016         return ERROR_INT("pta not defined", procName, 1);
1017 
1018     if (copyflag == L_INSERT) {
1019         ptac = pta;
1020     } else if (copyflag == L_COPY) {
1021         if ((ptac = ptaCopy(pta)) == NULL)
1022             return ERROR_INT("ptac not made", procName, 1);
1023     } else if (copyflag == L_CLONE) {
1024         if ((ptac = ptaClone(pta)) == NULL)
1025             return ERROR_INT("pta clone not made", procName, 1);
1026     } else {
1027         return ERROR_INT("invalid copyflag", procName, 1);
1028     }
1029 
1030     n = ptaaGetCount(ptaa);
1031     if (n >= ptaa->nalloc)
1032         ptaaExtendArray(ptaa);
1033     ptaa->pta[n] = ptac;
1034     ptaa->n++;
1035 
1036     return 0;
1037 }
1038 
1039 
1040 /*!
1041  * \brief   ptaaExtendArray()
1042  *
1043  * \param[in]    ptaa
1044  * \return  0 if OK, 1 on error
1045  */
1046 static l_int32
ptaaExtendArray(PTAA * ptaa)1047 ptaaExtendArray(PTAA  *ptaa)
1048 {
1049     PROCNAME("ptaaExtendArray");
1050 
1051     if (!ptaa)
1052         return ERROR_INT("ptaa not defined", procName, 1);
1053 
1054     if ((ptaa->pta = (PTA **)reallocNew((void **)&ptaa->pta,
1055                              sizeof(PTA *) * ptaa->nalloc,
1056                              2 * sizeof(PTA *) * ptaa->nalloc)) == NULL)
1057         return ERROR_INT("new ptr array not returned", procName, 1);
1058 
1059     ptaa->nalloc = 2 * ptaa->nalloc;
1060     return 0;
1061 }
1062 
1063 
1064 /*---------------------------------------------------------------------*
1065  *                          Ptaa accessors                             *
1066  *---------------------------------------------------------------------*/
1067 /*!
1068  * \brief   ptaaGetCount()
1069  *
1070  * \param[in]    ptaa
1071  * \return  count, or 0 if no ptaa
1072  */
1073 l_int32
ptaaGetCount(PTAA * ptaa)1074 ptaaGetCount(PTAA  *ptaa)
1075 {
1076     PROCNAME("ptaaGetCount");
1077 
1078     if (!ptaa)
1079         return ERROR_INT("ptaa not defined", procName, 0);
1080 
1081     return ptaa->n;
1082 }
1083 
1084 
1085 /*!
1086  * \brief   ptaaGetPta()
1087  *
1088  * \param[in]    ptaa
1089  * \param[in]    index  to the i-th pta
1090  * \param[in]    accessflag  L_COPY or L_CLONE
1091  * \return  pta, or NULL on error
1092  */
1093 PTA *
ptaaGetPta(PTAA * ptaa,l_int32 index,l_int32 accessflag)1094 ptaaGetPta(PTAA    *ptaa,
1095            l_int32  index,
1096            l_int32  accessflag)
1097 {
1098     PROCNAME("ptaaGetPta");
1099 
1100     if (!ptaa)
1101         return (PTA *)ERROR_PTR("ptaa not defined", procName, NULL);
1102     if (index < 0 || index >= ptaa->n)
1103         return (PTA *)ERROR_PTR("index not valid", procName, NULL);
1104 
1105     if (accessflag == L_COPY)
1106         return ptaCopy(ptaa->pta[index]);
1107     else if (accessflag == L_CLONE)
1108         return ptaClone(ptaa->pta[index]);
1109     else
1110         return (PTA *)ERROR_PTR("invalid accessflag", procName, NULL);
1111 }
1112 
1113 
1114 /*!
1115  * \brief   ptaaGetPt()
1116  *
1117  * \param[in]    ptaa
1118  * \param[in]    ipta  to the i-th pta
1119  * \param[in]    jpt index to the j-th pt in the pta
1120  * \param[out]   px [optional] float x value
1121  * \param[out]   py [optional] float y value
1122  * \return  0 if OK; 1 on error
1123  */
1124 l_int32
ptaaGetPt(PTAA * ptaa,l_int32 ipta,l_int32 jpt,l_float32 * px,l_float32 * py)1125 ptaaGetPt(PTAA       *ptaa,
1126            l_int32     ipta,
1127            l_int32     jpt,
1128            l_float32  *px,
1129            l_float32  *py)
1130 {
1131 PTA  *pta;
1132 
1133     PROCNAME("ptaaGetPt");
1134 
1135     if (px) *px = 0;
1136     if (py) *py = 0;
1137     if (!ptaa)
1138         return ERROR_INT("ptaa not defined", procName, 1);
1139     if (ipta < 0 || ipta >= ptaa->n)
1140         return ERROR_INT("index ipta not valid", procName, 1);
1141 
1142     pta = ptaaGetPta(ptaa, ipta, L_CLONE);
1143     if (jpt < 0 || jpt >= pta->n) {
1144         ptaDestroy(&pta);
1145         return ERROR_INT("index jpt not valid", procName, 1);
1146     }
1147 
1148     ptaGetPt(pta, jpt, px, py);
1149     ptaDestroy(&pta);
1150     return 0;
1151 }
1152 
1153 
1154 /*---------------------------------------------------------------------*
1155  *                        Ptaa array modifiers                         *
1156  *---------------------------------------------------------------------*/
1157 /*!
1158  * \brief   ptaaInitFull()
1159  *
1160  * \param[in]    ptaa can have non-null ptrs in the ptr array
1161  * \param[in]    pta to be replicated into the entire ptr array
1162  * \return  0 if OK; 1 on error
1163  */
1164 l_int32
ptaaInitFull(PTAA * ptaa,PTA * pta)1165 ptaaInitFull(PTAA  *ptaa,
1166              PTA   *pta)
1167 {
1168 l_int32  n, i;
1169 PTA     *ptat;
1170 
1171     PROCNAME("ptaaInitFull");
1172 
1173     if (!ptaa)
1174         return ERROR_INT("ptaa not defined", procName, 1);
1175     if (!pta)
1176         return ERROR_INT("pta not defined", procName, 1);
1177 
1178     n = ptaa->nalloc;
1179     ptaa->n = n;
1180     for (i = 0; i < n; i++) {
1181         ptat = ptaCopy(pta);
1182         ptaaReplacePta(ptaa, i, ptat);
1183     }
1184     return 0;
1185 }
1186 
1187 
1188 /*!
1189  * \brief   ptaaReplacePta()
1190  *
1191  * \param[in]    ptaa
1192  * \param[in]    index  to the index-th pta
1193  * \param[in]    pta insert and replace any existing one
1194  * \return  0 if OK, 1 on error
1195  *
1196  * <pre>
1197  * Notes:
1198  *      (1) Any existing pta is destroyed, and the input one
1199  *          is inserted in its place.
1200  *      (2) If the index is invalid, return 1 (error)
1201  * </pre>
1202  */
1203 l_int32
ptaaReplacePta(PTAA * ptaa,l_int32 index,PTA * pta)1204 ptaaReplacePta(PTAA    *ptaa,
1205                l_int32  index,
1206                PTA     *pta)
1207 {
1208 l_int32  n;
1209 
1210     PROCNAME("ptaaReplacePta");
1211 
1212     if (!ptaa)
1213         return ERROR_INT("ptaa not defined", procName, 1);
1214     if (!pta)
1215         return ERROR_INT("pta not defined", procName, 1);
1216     n = ptaaGetCount(ptaa);
1217     if (index < 0 || index >= n)
1218         return ERROR_INT("index not valid", procName, 1);
1219 
1220     ptaDestroy(&ptaa->pta[index]);
1221     ptaa->pta[index] = pta;
1222     return 0;
1223 }
1224 
1225 
1226 /*!
1227  * \brief   ptaaAddPt()
1228  *
1229  * \param[in]    ptaa
1230  * \param[in]    ipta  to the i-th pta
1231  * \param[in]    x,y point coordinates
1232  * \return  0 if OK; 1 on error
1233  */
1234 l_int32
ptaaAddPt(PTAA * ptaa,l_int32 ipta,l_float32 x,l_float32 y)1235 ptaaAddPt(PTAA      *ptaa,
1236           l_int32    ipta,
1237           l_float32  x,
1238           l_float32  y)
1239 {
1240 PTA  *pta;
1241 
1242     PROCNAME("ptaaAddPt");
1243 
1244     if (!ptaa)
1245         return ERROR_INT("ptaa not defined", procName, 1);
1246     if (ipta < 0 || ipta >= ptaa->n)
1247         return ERROR_INT("index ipta not valid", procName, 1);
1248 
1249     pta = ptaaGetPta(ptaa, ipta, L_CLONE);
1250     ptaAddPt(pta, x, y);
1251     ptaDestroy(&pta);
1252     return 0;
1253 }
1254 
1255 
1256 /*!
1257  * \brief   ptaaTruncate()
1258  *
1259  * \param[in]    ptaa
1260  * \return  0 if OK, 1 on error
1261  *
1262  * <pre>
1263  * Notes:
1264  *      (1) This identifies the largest index containing a pta that
1265  *          has any points within it, destroys all pta above that index,
1266  *          and resets the count.
1267  * </pre>
1268  */
1269 l_int32
ptaaTruncate(PTAA * ptaa)1270 ptaaTruncate(PTAA  *ptaa)
1271 {
1272 l_int32  i, n, np;
1273 PTA     *pta;
1274 
1275     PROCNAME("ptaaTruncate");
1276 
1277     if (!ptaa)
1278         return ERROR_INT("ptaa not defined", procName, 1);
1279 
1280     n = ptaaGetCount(ptaa);
1281     for (i = n - 1; i >= 0; i--) {
1282         pta = ptaaGetPta(ptaa, i, L_CLONE);
1283         if (!pta) {
1284             ptaa->n--;
1285             continue;
1286         }
1287         np = ptaGetCount(pta);
1288         ptaDestroy(&pta);
1289         if (np == 0) {
1290             ptaDestroy(&ptaa->pta[i]);
1291             ptaa->n--;
1292         } else {
1293             break;
1294         }
1295     }
1296     return 0;
1297 }
1298 
1299 
1300 /*---------------------------------------------------------------------*
1301  *                       Ptaa serialized for I/O                       *
1302  *---------------------------------------------------------------------*/
1303 /*!
1304  * \brief   ptaaRead()
1305  *
1306  * \param[in]    filename
1307  * \return  ptaa, or NULL on error
1308  */
1309 PTAA *
ptaaRead(const char * filename)1310 ptaaRead(const char  *filename)
1311 {
1312 FILE  *fp;
1313 PTAA  *ptaa;
1314 
1315     PROCNAME("ptaaRead");
1316 
1317     if (!filename)
1318         return (PTAA *)ERROR_PTR("filename not defined", procName, NULL);
1319 
1320     if ((fp = fopenReadStream(filename)) == NULL)
1321         return (PTAA *)ERROR_PTR("stream not opened", procName, NULL);
1322     ptaa = ptaaReadStream(fp);
1323     fclose(fp);
1324     if (!ptaa)
1325         return (PTAA *)ERROR_PTR("ptaa not read", procName, NULL);
1326     return ptaa;
1327 }
1328 
1329 
1330 /*!
1331  * \brief   ptaaReadStream()
1332  *
1333  * \param[in]    fp file stream
1334  * \return  ptaa, or NULL on error
1335  */
1336 PTAA *
ptaaReadStream(FILE * fp)1337 ptaaReadStream(FILE  *fp)
1338 {
1339 l_int32  i, n, version;
1340 PTA     *pta;
1341 PTAA    *ptaa;
1342 
1343     PROCNAME("ptaaReadStream");
1344 
1345     if (!fp)
1346         return (PTAA *)ERROR_PTR("stream not defined", procName, NULL);
1347 
1348     if (fscanf(fp, "\nPtaa Version %d\n", &version) != 1)
1349         return (PTAA *)ERROR_PTR("not a ptaa file", procName, NULL);
1350     if (version != PTA_VERSION_NUMBER)
1351         return (PTAA *)ERROR_PTR("invalid ptaa version", procName, NULL);
1352     if (fscanf(fp, "Number of Pta = %d\n", &n) != 1)
1353         return (PTAA *)ERROR_PTR("not a ptaa file", procName, NULL);
1354 
1355     if ((ptaa = ptaaCreate(n)) == NULL)
1356         return (PTAA *)ERROR_PTR("ptaa not made", procName, NULL);
1357     for (i = 0; i < n; i++) {
1358         if ((pta = ptaReadStream(fp)) == NULL) {
1359             ptaaDestroy(&ptaa);
1360             return (PTAA *)ERROR_PTR("error reading pta", procName, NULL);
1361         }
1362         ptaaAddPta(ptaa, pta, L_INSERT);
1363     }
1364 
1365     return ptaa;
1366 }
1367 
1368 
1369 /*!
1370  * \brief   ptaaReadMem()
1371  *
1372  * \param[in]    data  serialization in ascii
1373  * \param[in]    size  of data in bytes; can use strlen to get it
1374  * \return  ptaa, or NULL on error
1375  */
1376 PTAA *
ptaaReadMem(const l_uint8 * data,size_t size)1377 ptaaReadMem(const l_uint8  *data,
1378             size_t          size)
1379 {
1380 FILE  *fp;
1381 PTAA  *ptaa;
1382 
1383     PROCNAME("ptaaReadMem");
1384 
1385     if (!data)
1386         return (PTAA *)ERROR_PTR("data not defined", procName, NULL);
1387     if ((fp = fopenReadFromMemory(data, size)) == NULL)
1388         return (PTAA *)ERROR_PTR("stream not opened", procName, NULL);
1389 
1390     ptaa = ptaaReadStream(fp);
1391     fclose(fp);
1392     if (!ptaa) L_ERROR("ptaa not read\n", procName);
1393     return ptaa;
1394 }
1395 
1396 
1397 /*!
1398  * \brief   ptaaWriteDebug()
1399  *
1400  * \param[in]    filename
1401  * \param[in]    ptaa
1402  * \param[in]    type  0 for float values; 1 for integer values
1403  * \return  0 if OK, 1 on error
1404  *
1405  * <pre>
1406  * Notes:
1407  *      (1) Debug version, intended for use in the library when writing
1408  *          to files in a temp directory with names that are compiled in.
1409  *          This is used instead of ptaaWrite() for all such library calls.
1410  *      (2) The global variable LeptDebugOK defaults to 0, and can be set
1411  *          or cleared by the function setLeptDebugOK().
1412  * </pre>
1413  */
1414 l_int32
ptaaWriteDebug(const char * filename,PTAA * ptaa,l_int32 type)1415 ptaaWriteDebug(const char  *filename,
1416                PTAA        *ptaa,
1417                l_int32      type)
1418 {
1419     PROCNAME("ptaaWriteDebug");
1420 
1421     if (LeptDebugOK) {
1422         return ptaaWrite(filename, ptaa, type);
1423     } else {
1424         L_INFO("write to named temp file %s is disabled\n", procName, filename);
1425         return 0;
1426     }
1427 }
1428 
1429 
1430 /*!
1431  * \brief   ptaaWrite()
1432  *
1433  * \param[in]    filename
1434  * \param[in]    ptaa
1435  * \param[in]    type  0 for float values; 1 for integer values
1436  * \return  0 if OK, 1 on error
1437  */
1438 l_int32
ptaaWrite(const char * filename,PTAA * ptaa,l_int32 type)1439 ptaaWrite(const char  *filename,
1440           PTAA        *ptaa,
1441           l_int32      type)
1442 {
1443 l_int32  ret;
1444 FILE    *fp;
1445 
1446     PROCNAME("ptaaWrite");
1447 
1448     if (!filename)
1449         return ERROR_INT("filename not defined", procName, 1);
1450     if (!ptaa)
1451         return ERROR_INT("ptaa not defined", procName, 1);
1452 
1453     if ((fp = fopenWriteStream(filename, "w")) == NULL)
1454         return ERROR_INT("stream not opened", procName, 1);
1455     ret = ptaaWriteStream(fp, ptaa, type);
1456     fclose(fp);
1457     if (ret)
1458         return ERROR_INT("ptaa not written to stream", procName, 1);
1459     return 0;
1460 }
1461 
1462 
1463 /*!
1464  * \brief   ptaaWriteStream()
1465  *
1466  * \param[in]    fp file stream
1467  * \param[in]    ptaa
1468  * \param[in]    type  0 for float values; 1 for integer values
1469  * \return  0 if OK; 1 on error
1470  */
1471 l_int32
ptaaWriteStream(FILE * fp,PTAA * ptaa,l_int32 type)1472 ptaaWriteStream(FILE    *fp,
1473                 PTAA    *ptaa,
1474                 l_int32  type)
1475 {
1476 l_int32  i, n;
1477 PTA     *pta;
1478 
1479     PROCNAME("ptaaWriteStream");
1480 
1481     if (!fp)
1482         return ERROR_INT("stream not defined", procName, 1);
1483     if (!ptaa)
1484         return ERROR_INT("ptaa not defined", procName, 1);
1485 
1486     n = ptaaGetCount(ptaa);
1487     fprintf(fp, "\nPtaa Version %d\n", PTA_VERSION_NUMBER);
1488     fprintf(fp, "Number of Pta = %d\n", n);
1489     for (i = 0; i < n; i++) {
1490         pta = ptaaGetPta(ptaa, i, L_CLONE);
1491         ptaWriteStream(fp, pta, type);
1492         ptaDestroy(&pta);
1493     }
1494 
1495     return 0;
1496 }
1497 
1498 
1499 /*!
1500  * \brief   ptaaWriteMem()
1501  *
1502  * \param[out]   pdata data of serialized ptaa; ascii
1503  * \param[out]   psize size of returned data
1504  * \param[in]    ptaa
1505  * \param[in]    type  0 for float values; 1 for integer values
1506  * \return  0 if OK, 1 on error
1507  *
1508  * <pre>
1509  * Notes:
1510  *      (1) Serializes a ptaa in memory and puts the result in a buffer.
1511  * </pre>
1512  */
1513 l_int32
ptaaWriteMem(l_uint8 ** pdata,size_t * psize,PTAA * ptaa,l_int32 type)1514 ptaaWriteMem(l_uint8  **pdata,
1515              size_t    *psize,
1516              PTAA      *ptaa,
1517              l_int32    type)
1518 {
1519 l_int32  ret;
1520 FILE    *fp;
1521 
1522     PROCNAME("ptaaWriteMem");
1523 
1524     if (pdata) *pdata = NULL;
1525     if (psize) *psize = 0;
1526     if (!pdata)
1527         return ERROR_INT("&data not defined", procName, 1);
1528     if (!psize)
1529         return ERROR_INT("&size not defined", procName, 1);
1530     if (!ptaa)
1531         return ERROR_INT("ptaa not defined", procName, 1);
1532 
1533 #if HAVE_FMEMOPEN
1534     if ((fp = open_memstream((char **)pdata, psize)) == NULL)
1535         return ERROR_INT("stream not opened", procName, 1);
1536     ret = ptaaWriteStream(fp, ptaa, type);
1537 #else
1538     L_INFO("work-around: writing to a temp file\n", procName);
1539   #ifdef _WIN32
1540     if ((fp = fopenWriteWinTempfile()) == NULL)
1541         return ERROR_INT("tmpfile stream not opened", procName, 1);
1542   #else
1543     if ((fp = tmpfile()) == NULL)
1544         return ERROR_INT("tmpfile stream not opened", procName, 1);
1545   #endif  /* _WIN32 */
1546     ret = ptaaWriteStream(fp, ptaa, type);
1547     rewind(fp);
1548     *pdata = l_binaryReadStream(fp, psize);
1549 #endif  /* HAVE_FMEMOPEN */
1550     fclose(fp);
1551     return ret;
1552 }
1553 
1554