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