• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*====================================================================*
2  -  Copyright (C) 2001 Leptonica.  All rights reserved.
3  -  This software is distributed in the hope that it will be
4  -  useful, but with NO WARRANTY OF ANY KIND.
5  -  No author or distributor accepts responsibility to anyone for the
6  -  consequences of using this software, or for whether it serves any
7  -  particular purpose or works at all, unless he or she says so in
8  -  writing.  Everyone is granted permission to copy, modify and
9  -  redistribute this source code, for commercial or non-commercial
10  -  purposes, with the following restrictions: (1) the origin of this
11  -  source code must not be misrepresented; (2) modified versions must
12  -  be plainly marked as such; and (3) this notice may not be removed
13  -  or altered from any source or modified source distribution.
14  *====================================================================*/
15 
16 /*
17  *   pixabasic.c
18  *
19  *      Pixa creation, destruction, copying
20  *           PIXA     *pixaCreate()
21  *           PIXA     *pixaCreateFromPix()
22  *           PIXA     *pixaCreateFromBoxa()
23  *           PIXA     *pixaSplitPix()
24  *           void      pixaDestroy()
25  *           PIXA     *pixaCopy()
26  *
27  *      Pixa addition
28  *           l_int32   pixaAddPix()
29  *           l_int32   pixaExtendArray()
30  *           l_int32   pixaAddBox()
31  *
32  *      Pixa accessors
33  *           l_int32   pixaGetCount()
34  *           l_int32   pixaChangeRefcount()
35  *           PIX      *pixaGetPix()
36  *           l_int32   pixaGetPixDimensions()
37  *           PIX      *pixaGetBoxa()
38  *           l_int32   pixaGetBoxaCount()
39  *           BOX      *pixaGetBox()
40  *           l_int32   pixaGetBoxGeometry()
41  *           PIX     **pixaGetPixArray()
42  *
43  *      Pixa array modifiers
44  *           l_int32   pixaReplacePix()
45  *           l_int32   pixaInsertPix()
46  *           l_int32   pixaRemovePix()
47  *
48  *      Pixa combination
49  *           PIXA     *pixaJoin()
50  *
51  *      Pixaa creation, destruction
52  *           PIXAA    *pixaaCreate()
53  *           PIXAA    *pixaaCreateFromPixa()
54  *           void      pixaaDestroy()
55  *
56  *      Pixaa addition
57  *           l_int32   pixaaAddPixa()
58  *           l_int32   pixaaExtendArray()
59  *           l_int32   pixaaAddBox()
60  *
61  *      Pixaa accessors
62  *           l_int32   pixaaGetCount()
63  *           PIXA     *pixaaGetPixa()
64  *           BOXA     *pixaaGetBoxa()
65  *
66  *      Pixa serialized I/O
67  *           PIXA     *pixaRead()
68  *           PIXA     *pixaReadStream()
69  *           l_int32   pixaWrite()
70  *           l_int32   pixaWriteStream()
71  *
72  *      Pixaa serialized I/O
73  *           PIXAA    *pixaaRead()
74  *           PIXAA    *pixaaReadStream()
75  *           l_int32   pixaaWrite()
76  *           l_int32   pixaaWriteStream()
77  *
78  *
79  *   Important note on reference counting:
80  *     Reference counting for the Pixa is analogous to that for the Boxa.
81  *     See pix.h for details.   pixaCopy() provides three possible modes
82  *     of copy.  The basic rule is that however a Pixa is obtained
83  *     (e.g., from pixaCreate*(), pixaCopy(), or a Pixaa accessor),
84  *     it is necessary to call pixaDestroy() on it.
85  */
86 
87 #include <stdio.h>
88 #include <stdlib.h>
89 #include <string.h>
90 #include "allheaders.h"
91 
92 static const l_int32  INITIAL_PTR_ARRAYSIZE = 20;   /* n'import quoi */
93 
94 
95 /*---------------------------------------------------------------------*
96  *                    Pixa creation, destruction, copy                 *
97  *---------------------------------------------------------------------*/
98 /*!
99  *  pixaCreate()
100  *
101  *      Input:  n  (initial number of ptrs)
102  *      Return: pixa, or null on error
103  */
104 PIXA *
pixaCreate(l_int32 n)105 pixaCreate(l_int32  n)
106 {
107 PIXA  *pixa;
108 
109     PROCNAME("pixaCreate");
110 
111     if (n <= 0)
112         n = INITIAL_PTR_ARRAYSIZE;
113 
114     if ((pixa = (PIXA *)CALLOC(1, sizeof(PIXA))) == NULL)
115         return (PIXA *)ERROR_PTR("pixa not made", procName, NULL);
116     pixa->n = 0;
117     pixa->nalloc = n;
118     pixa->refcount = 1;
119 
120     if ((pixa->pix = (PIX **)CALLOC(n, sizeof(PIX *))) == NULL)
121         return (PIXA *)ERROR_PTR("pix ptrs not made", procName, NULL);
122     if ((pixa->boxa = boxaCreate(n)) == NULL)
123         return (PIXA *)ERROR_PTR("boxa not made", procName, NULL);
124 
125     return pixa;
126 }
127 
128 
129 /*!
130  *  pixaCreateFromPix()
131  *
132  *      Input:  pixs  (with individual components on a lattice)
133  *              n   (number of components)
134  *              cellw   (width of each cell)
135  *              cellh   (height of each cell)
136  *      Return: pixa, or null on error
137  *
138  *  Note: for bpp = 1, we truncate each retrieved pix to
139  *        the ON pixels, which we assume for now start at (0,0)
140  */
141 PIXA *
pixaCreateFromPix(PIX * pixs,l_int32 n,l_int32 cellw,l_int32 cellh)142 pixaCreateFromPix(PIX     *pixs,
143                   l_int32  n,
144                   l_int32  cellw,
145                   l_int32  cellh)
146 {
147 l_int32  w, h, d, nw, nh, i, j, index;
148 PIX     *pix, *pixt;
149 PIXA    *pixa;
150 
151     PROCNAME("pixaCreateFromPix");
152 
153     if (!pixs)
154         return (PIXA *)ERROR_PTR("pixs not defined", procName, NULL);
155     if (n <= 0)
156         return (PIXA *)ERROR_PTR("n must be > 0", procName, NULL);
157 
158     if ((pixa = pixaCreate(n)) == NULL)
159         return (PIXA *)ERROR_PTR("pixa not made", procName, NULL);
160     pixGetDimensions(pixs, &w, &h, &d);
161     if ((pixt = pixCreate(cellw, cellh, d)) == NULL)
162         return (PIXA *)ERROR_PTR("pixt not made", procName, NULL);
163 
164     nw = (w + cellw - 1) / cellw;
165     nh = (h + cellh - 1) / cellh;
166     for (i = 0, index = 0; i < nh; i++) {
167         for (j = 0; j < nw && index < n; j++, index++) {
168             pixRasterop(pixt, 0, 0, cellw, cellh, PIX_SRC, pixs,
169                    j * cellw, i * cellh);
170             if (d == 1 && !pixClipToForeground(pixt, &pix, NULL))
171                 pixaAddPix(pixa, pix, L_INSERT);
172             else
173                 pixaAddPix(pixa, pixt, L_COPY);
174         }
175     }
176 
177     pixDestroy(&pixt);
178     return pixa;
179 }
180 
181 
182 /*!
183  *  pixaCreateFromBoxa()
184  *
185  *      Input:  pixs
186  *              boxa
187  *              &cropwarn (<optional return> TRUE if the boxa extent
188  *                         is larger than pixs.
189  *      Return: pixad, or null on error
190  *
191  *  Notes:
192  *      (1) This simply extracts from pixs the region corresponding to each
193  *          box in the boxa.
194  *      (2) The 3rd arg is optional.  If the extent of the boxa exceeds the
195  *          size of the pixa, so that some boxes are either clipped
196  *          or entirely outside the pix, a warning is returned as TRUE.
197  *      (3) pixad will have only the properly clipped elements, and
198  *          the internal boxa will be correct.
199  */
200 PIXA *
pixaCreateFromBoxa(PIX * pixs,BOXA * boxa,l_int32 * pcropwarn)201 pixaCreateFromBoxa(PIX      *pixs,
202                    BOXA     *boxa,
203                    l_int32  *pcropwarn)
204 {
205 l_int32  i, n, w, h, wbox, hbox, cropwarn;
206 BOX     *box, *boxc;
207 PIX     *pixd;
208 PIXA    *pixad;
209 
210     PROCNAME("pixaCreateFromBoxa");
211 
212     if (!pixs)
213         return (PIXA *)ERROR_PTR("pixs not defined", procName, NULL);
214     if (!boxa)
215         return (PIXA *)ERROR_PTR("boxa not defined", procName, NULL);
216 
217     n = boxaGetCount(boxa);
218     if ((pixad = pixaCreate(n)) == NULL)
219         return (PIXA *)ERROR_PTR("pixad not made", procName, NULL);
220 
221     boxaGetExtent(boxa, &wbox, &hbox, NULL);
222     pixGetDimensions(pixs, &w, &h, NULL);
223     cropwarn = FALSE;
224     if (wbox > w || hbox > h)
225         cropwarn = TRUE;
226     if (pcropwarn)
227         *pcropwarn = cropwarn;
228 
229     for (i = 0; i < n; i++) {
230         box = boxaGetBox(boxa, i, L_COPY);
231         if (cropwarn) {  /* if box is outside pixs, pixd is NULL */
232             pixd = pixClipRectangle(pixs, box, &boxc);  /* may be NULL */
233             if (pixd) {
234                 pixaAddPix(pixad, pixd, L_INSERT);
235                 pixaAddBox(pixad, boxc, L_INSERT);
236             }
237             boxDestroy(&box);
238         }
239         else {
240             pixd = pixClipRectangle(pixs, box, NULL);
241             pixaAddPix(pixad, pixd, L_INSERT);
242             pixaAddBox(pixad, box, L_INSERT);
243         }
244     }
245 
246     return pixad;
247 }
248 
249 
250 /*!
251  *  pixaSplitPix()
252  *
253  *      Input:  pixs  (with individual components on a lattice)
254  *              nx   (number of mosaic cells horizontally)
255  *              ny   (number of mosaic cells vertically)
256  *              borderwidth  (of added border on all sides)
257  *              bordercolor  (in our RGBA format: 0xrrggbbaa)
258  *      Return: pixa, or null on error
259  *
260  *  Notes:
261  *      (1) This is a variant on pixaCreateFromPix(), where we
262  *          simply divide the image up into (approximately) equal
263  *          subunits.  If you want the subimages to have essentially
264  *          the same aspect ratio as the input pix, use nx = ny.
265  *      (2) If borderwidth is 0, we ignore the input bordercolor and
266  *          redefine it to white.
267  *      (3) The bordercolor is always used to initialize each tiled pix,
268  *          so that if the src is clipped, the unblitted part will
269  *          be this color.  This avoids 1 pixel wide black stripes at the
270  *          left and lower edges.
271  */
272 PIXA *
pixaSplitPix(PIX * pixs,l_int32 nx,l_int32 ny,l_int32 borderwidth,l_uint32 bordercolor)273 pixaSplitPix(PIX      *pixs,
274              l_int32   nx,
275              l_int32   ny,
276              l_int32   borderwidth,
277              l_uint32  bordercolor)
278 {
279 l_int32  w, h, d, cellw, cellh, i, j;
280 PIX     *pixt;
281 PIXA    *pixa;
282 
283     PROCNAME("pixaSplitPix");
284 
285     if (!pixs)
286         return (PIXA *)ERROR_PTR("pixs not defined", procName, NULL);
287     if (nx <= 0 || ny <= 0)
288         return (PIXA *)ERROR_PTR("nx and ny must be > 0", procName, NULL);
289     borderwidth = L_MAX(0, borderwidth);
290 
291     if ((pixa = pixaCreate(nx * ny)) == NULL)
292         return (PIXA *)ERROR_PTR("pixa not made", procName, NULL);
293     pixGetDimensions(pixs, &w, &h, &d);
294     cellw = (w + nx - 1) / nx;  /* round up */
295     cellh = (h + ny - 1) / ny;
296 
297     for (i = 0; i < ny; i++) {
298         for (j = 0; j < nx; j++) {
299             if ((pixt = pixCreate(cellw + 2 * borderwidth,
300                                   cellh + 2 * borderwidth, d)) == NULL)
301                 return (PIXA *)ERROR_PTR("pixt not made", procName, NULL);
302             pixCopyColormap(pixt, pixs);
303             if (borderwidth == 0) {  /* initialize full image to white */
304                 if (d == 1)
305                     pixClearAll(pixt);
306                 else
307                     pixSetAll(pixt);
308             }
309             else
310                 pixSetAllArbitrary(pixt, bordercolor);
311             pixRasterop(pixt, borderwidth, borderwidth, cellw, cellh,
312                         PIX_SRC, pixs, j * cellw, i * cellh);
313             pixaAddPix(pixa, pixt, L_INSERT);
314         }
315     }
316 
317     return pixa;
318 }
319 
320 
321 /*!
322  *  pixaDestroy()
323  *
324  *      Input:  &pixa (<can be nulled>)
325  *      Return: void
326  *
327  *  Notes:
328  *      (1) Decrements the ref count and, if 0, destroys the pixa.
329  *      (2) Always nulls the input ptr.
330  */
331 void
pixaDestroy(PIXA ** ppixa)332 pixaDestroy(PIXA  **ppixa)
333 {
334 l_int32  i;
335 PIXA    *pixa;
336 
337     PROCNAME("pixaDestroy");
338 
339     if (ppixa == NULL) {
340         L_WARNING("ptr address is NULL!", procName);
341         return;
342     }
343 
344     if ((pixa = *ppixa) == NULL)
345         return;
346 
347         /* Decrement the refcount.  If it is 0, destroy the pixa. */
348     pixaChangeRefcount(pixa, -1);
349     if (pixa->refcount <= 0) {
350         for (i = 0; i < pixa->n; i++)
351             pixDestroy(&pixa->pix[i]);
352         FREE(pixa->pix);
353         boxaDestroy(&pixa->boxa);
354         FREE(pixa);
355     }
356 
357     *ppixa = NULL;
358     return;
359 }
360 
361 
362 /*!
363  *  pixaCopy()
364  *
365  *      Input:  pixas
366  *              copyflag:
367  *                L_COPY makes a new pixa and copies each pix and each box
368  *                L_CLONE gives a new ref-counted handle to the input pixa
369  *                L_COPY_CLONE makes a new pixa and inserts clones of
370  *                    all pix and boxes
371  *      Return: new pixa, or null on error
372  *
373  *  Note: see pix.h for description of the copy types.
374  */
375 PIXA *
pixaCopy(PIXA * pixa,l_int32 copyflag)376 pixaCopy(PIXA    *pixa,
377          l_int32  copyflag)
378 {
379 l_int32  i;
380 BOX     *boxc;
381 PIX     *pixc;
382 PIXA    *pixac;
383 
384     PROCNAME("pixaCopy");
385 
386     if (!pixa)
387         return (PIXA *)ERROR_PTR("pixa not defined", procName, NULL);
388 
389     if (copyflag == L_CLONE) {
390         pixaChangeRefcount(pixa, 1);
391         return pixa;
392     }
393 
394     if (copyflag != L_COPY && copyflag != L_COPY_CLONE)
395         return (PIXA *)ERROR_PTR("invalid copyflag", procName, NULL);
396 
397     if ((pixac = pixaCreate(pixa->n)) == NULL)
398         return (PIXA *)ERROR_PTR("pixac not made", procName, NULL);
399     for (i = 0; i < pixa->n; i++) {
400         if (copyflag == L_COPY) {
401             pixc = pixaGetPix(pixa, i, L_COPY);
402             boxc = pixaGetBox(pixa, i, L_COPY);
403         }
404         else {  /* copy-clone */
405             pixc = pixaGetPix(pixa, i, L_CLONE);
406             boxc = pixaGetBox(pixa, i, L_CLONE);
407         }
408         pixaAddPix(pixac, pixc, L_INSERT);
409         pixaAddBox(pixac, boxc, L_INSERT);
410     }
411 
412     return pixac;
413 }
414 
415 
416 
417 /*---------------------------------------------------------------------*
418  *                              Pixa addition                          *
419  *---------------------------------------------------------------------*/
420 /*!
421  *  pixaAddPix()
422  *
423  *      Input:  pixa
424  *              pix  (to be added)
425  *              copyflag (L_INSERT, L_COPY, L_CLONE)
426  *      Return: 0 if OK; 1 on error
427  */
428 l_int32
pixaAddPix(PIXA * pixa,PIX * pix,l_int32 copyflag)429 pixaAddPix(PIXA    *pixa,
430            PIX     *pix,
431            l_int32  copyflag)
432 {
433 l_int32  n;
434 PIX     *pixc;
435 
436     PROCNAME("pixaAddPix");
437 
438     if (!pixa)
439         return ERROR_INT("pixa not defined", procName, 1);
440     if (!pix)
441         return ERROR_INT("pix not defined", procName, 1);
442 
443     if (copyflag == L_INSERT)
444         pixc = pix;
445     else if (copyflag == L_COPY)
446         pixc = pixCopy(NULL, pix);
447     else if (copyflag == L_CLONE)
448         pixc = pixClone(pix);
449     else
450         return ERROR_INT("invalid copyflag", procName, 1);
451     if (!pixc)
452         return ERROR_INT("pixc not made", procName, 1);
453 
454     n = pixaGetCount(pixa);
455     if (n >= pixa->nalloc)
456         pixaExtendArray(pixa);
457     pixa->pix[n] = pixc;
458     pixa->n++;
459 
460     return 0;
461 }
462 
463 
464 /*!
465  *  pixaExtendArray()
466  *
467  *      Input:  pixa
468  *      Return: 0 if OK; 1 on error
469  *
470  *  Notes:
471  *      (1) We extend the boxa array simultaneously.  This is
472  *          necessary in case we are NOT adding boxes simultaneously
473  *          with adding pix.  We always want the sizes of the
474  *          pixa and boxa ptr arrays to be equal.
475  */
476 l_int32
pixaExtendArray(PIXA * pixa)477 pixaExtendArray(PIXA  *pixa)
478 {
479     PROCNAME("pixaExtendArray");
480 
481     if (!pixa)
482         return ERROR_INT("pixa not defined", procName, 1);
483 
484     if ((pixa->pix = (PIX **)reallocNew((void **)&pixa->pix,
485                              sizeof(PIX *) * pixa->nalloc,
486                              2 * sizeof(PIX *) * pixa->nalloc)) == NULL)
487         return ERROR_INT("new ptr array not returned", procName, 1);
488     pixa->nalloc = 2 * pixa->nalloc;
489     boxaExtendArray(pixa->boxa);
490     return 0;
491 }
492 
493 
494 /*!
495  *  pixaAddBox()
496  *
497  *      Input:  pixa
498  *              box
499  *              copyflag (L_INSERT, L_COPY, L_CLONE)
500  *      Return: 0 if OK, 1 on error
501  */
502 l_int32
pixaAddBox(PIXA * pixa,BOX * box,l_int32 copyflag)503 pixaAddBox(PIXA    *pixa,
504            BOX     *box,
505            l_int32  copyflag)
506 {
507     PROCNAME("pixaAddBox");
508 
509     if (!pixa)
510         return ERROR_INT("pixa not defined", procName, 1);
511     if (!box)
512         return ERROR_INT("box not defined", procName, 1);
513     if (copyflag != L_INSERT && copyflag != L_COPY && copyflag != L_CLONE)
514         return ERROR_INT("invalid copyflag", procName, 1);
515 
516     boxaAddBox(pixa->boxa, box, copyflag);
517     return 0;
518 }
519 
520 
521 
522 /*---------------------------------------------------------------------*
523  *                             Pixa accessors                          *
524  *---------------------------------------------------------------------*/
525 /*!
526  *  pixaGetCount()
527  *
528  *      Input:  pixa
529  *      Return: count, or 0 if no pixa
530  */
531 l_int32
pixaGetCount(PIXA * pixa)532 pixaGetCount(PIXA  *pixa)
533 {
534     PROCNAME("pixaGetCount");
535 
536     if (!pixa)
537         return ERROR_INT("pixa not defined", procName, 0);
538 
539     return pixa->n;
540 }
541 
542 
543 /*!
544  *  pixaChangeRefcount()
545  *
546  *      Input:  pixa
547  *      Return: 0 if OK, 1 on error
548  */
549 l_int32
pixaChangeRefcount(PIXA * pixa,l_int32 delta)550 pixaChangeRefcount(PIXA    *pixa,
551                    l_int32  delta)
552 {
553     PROCNAME("pixaChangeRefcount");
554 
555     if (!pixa)
556         return ERROR_INT("pixa not defined", procName, 1);
557 
558     pixa->refcount += delta;
559     return 0;
560 }
561 
562 
563 /*!
564  *  pixaGetPix()
565  *
566  *      Input:  pixa
567  *              index  (to the index-th pix)
568  *              accesstype  (L_COPY or L_CLONE)
569  *      Return: pix, or null on error
570  */
571 PIX *
pixaGetPix(PIXA * pixa,l_int32 index,l_int32 accesstype)572 pixaGetPix(PIXA    *pixa,
573            l_int32  index,
574            l_int32  accesstype)
575 {
576     PROCNAME("pixaGetPix");
577 
578     if (!pixa)
579         return (PIX *)ERROR_PTR("pixa not defined", procName, NULL);
580     if (index < 0 || index >= pixa->n)
581         return (PIX *)ERROR_PTR("index not valid", procName, NULL);
582 
583     if (accesstype == L_COPY)
584         return pixCopy(NULL, pixa->pix[index]);
585     else if (accesstype == L_CLONE)
586         return pixClone(pixa->pix[index]);
587     else
588         return (PIX *)ERROR_PTR("invalid accesstype", procName, NULL);
589 }
590 
591 
592 /*!
593  *  pixaGetPixDimensions()
594  *
595  *      Input:  pixa
596  *              index  (to the index-th box)
597  *              &w, &h, &d (<optional return>; each can be null)
598  *      Return: 0 if OK, 1 on error
599  */
600 l_int32
pixaGetPixDimensions(PIXA * pixa,l_int32 index,l_int32 * pw,l_int32 * ph,l_int32 * pd)601 pixaGetPixDimensions(PIXA     *pixa,
602                      l_int32   index,
603                      l_int32  *pw,
604                      l_int32  *ph,
605                      l_int32  *pd)
606 {
607 PIX  *pix;
608 
609     PROCNAME("pixaGetPixDimensions");
610 
611     if (!pixa)
612         return ERROR_INT("pixa not defined", procName, 1);
613     if (index < 0 || index >= pixa->n)
614         return ERROR_INT("index not valid", procName, 1);
615 
616     if ((pix = pixaGetPix(pixa, index, L_CLONE)) == NULL)
617         return ERROR_INT("pix not found!", procName, 1);
618     pixGetDimensions(pix, pw, ph, pd);
619     pixDestroy(&pix);
620     return 0;
621 }
622 
623 
624 /*!
625  *  pixaGetBoxa()
626  *
627  *      Input:  pixa
628  *              accesstype  (L_COPY, L_CLONE, L_COPY_CLONE)
629  *      Return: boxa, or null on error
630  */
631 BOXA *
pixaGetBoxa(PIXA * pixa,l_int32 accesstype)632 pixaGetBoxa(PIXA    *pixa,
633             l_int32  accesstype)
634 {
635     PROCNAME("pixaGetBoxa");
636 
637     if (!pixa)
638         return (BOXA *)ERROR_PTR("pixa not defined", procName, NULL);
639     if (!pixa->boxa)
640         return (BOXA *)ERROR_PTR("boxa not defined", procName, NULL);
641     if (accesstype != L_COPY && accesstype != L_CLONE &&
642         accesstype != L_COPY_CLONE)
643         return (BOXA *)ERROR_PTR("invalid accesstype", procName, NULL);
644 
645     return boxaCopy(pixa->boxa, accesstype);
646 }
647 
648 
649 /*!
650  *  pixaGetBoxaCount()
651  *
652  *      Input:  pixa
653  *      Return: count, or 0 on error
654  */
655 l_int32
pixaGetBoxaCount(PIXA * pixa)656 pixaGetBoxaCount(PIXA  *pixa)
657 {
658     PROCNAME("pixaGetBoxaCount");
659 
660     if (!pixa)
661         return ERROR_INT("pixa not defined", procName, 0);
662 
663     return boxaGetCount(pixa->boxa);
664 }
665 
666 
667 /*!
668  *  pixaGetBox()
669  *
670  *      Input:  pixa
671  *              index  (to the index-th pix)
672  *              accesstype  (L_COPY or L_CLONE)
673  *      Return: box (if null, not automatically an error), or null on error
674  *
675  *  Notes:
676  *      (1) There is always a boxa with a pixa, and it is initialized so
677  *          that each box ptr is NULL.
678  *      (2) In general, we expect that there is either a box associated
679  *          with each pix, or no boxes at all in the boxa.
680  *      (3) Having no boxes is thus not an automatic error.  Whether it
681  *          is an actual error is determined by the calling program.
682  *          If the caller expects to get a box, it is an error; see, e.g.,
683  *          pixaGetBoxGeometry().
684  */
685 BOX *
pixaGetBox(PIXA * pixa,l_int32 index,l_int32 accesstype)686 pixaGetBox(PIXA    *pixa,
687            l_int32  index,
688            l_int32  accesstype)
689 {
690 BOX  *box;
691 
692     PROCNAME("pixaGetBox");
693 
694     if (!pixa)
695         return (BOX *)ERROR_PTR("pixa not defined", procName, NULL);
696     if (!pixa->boxa)
697         return (BOX *)ERROR_PTR("boxa not defined", procName, NULL);
698     if (index < 0 || index >= pixa->boxa->n)
699         return (BOX *)ERROR_PTR("index not valid", procName, NULL);
700     if (accesstype != L_COPY && accesstype != L_CLONE)
701         return (BOX *)ERROR_PTR("invalid accesstype", procName, NULL);
702 
703     box = pixa->boxa->box[index];
704     if (box) {
705         if (accesstype == L_COPY)
706             return boxCopy(box);
707         else  /* accesstype == L_CLONE */
708             return boxClone(box);
709     }
710     else
711         return NULL;
712 }
713 
714 
715 /*!
716  *  pixaGetBoxGeometry()
717  *
718  *      Input:  pixa
719  *              index  (to the index-th box)
720  *              &x, &y, &w, &h (<optional return>; each can be null)
721  *      Return: 0 if OK, 1 on error
722  */
723 l_int32
pixaGetBoxGeometry(PIXA * pixa,l_int32 index,l_int32 * px,l_int32 * py,l_int32 * pw,l_int32 * ph)724 pixaGetBoxGeometry(PIXA     *pixa,
725                    l_int32   index,
726                    l_int32  *px,
727                    l_int32  *py,
728                    l_int32  *pw,
729                    l_int32  *ph)
730 {
731 BOX  *box;
732 
733     PROCNAME("pixaGetBoxGeometry");
734 
735     if (!pixa)
736         return ERROR_INT("pixa not defined", procName, 1);
737     if (index < 0 || index >= pixa->n)
738         return ERROR_INT("index not valid", procName, 1);
739 
740     if ((box = pixaGetBox(pixa, index, L_CLONE)) == NULL)
741         return ERROR_INT("box not found!", procName, 1);
742     boxGetGeometry(box, px, py, pw, ph);
743     boxDestroy(&box);
744     return 0;
745 }
746 
747 
748 /*!
749  *  pixaGetPixArray()
750  *
751  *      Input:  pixa
752  *      Return: pix array, or null on error
753  *
754  *  Notes:
755  *      (1) This returns a ptr to the actual array.  The array is
756  *          owned by the pixa, so it must not be destroyed.
757  *      (2) The caller should always check if the return value is NULL
758  *          before accessing any of the pix ptrs in this array!
759  */
760 PIX **
pixaGetPixArray(PIXA * pixa)761 pixaGetPixArray(PIXA  *pixa)
762 {
763     PROCNAME("pixaGetPixArray");
764 
765     if (!pixa)
766         return (PIX **)ERROR_PTR("pixa not defined", procName, NULL);
767 
768     return pixa->pix;
769 }
770 
771 
772 
773 /*---------------------------------------------------------------------*
774  *                       Pixa array modifiers                          *
775  *---------------------------------------------------------------------*/
776 /*!
777  *  pixaReplacePix()
778  *
779  *      Input:  pixa
780  *              index  (to the index-th pix)
781  *              pix (insert to replace existing one)
782  *              box (<optional> insert to replace existing)
783  *      Return: 0 if OK, 1 on error
784  *
785  *  Notes:
786  *      - In-place replacement of one pix
787  *      - The previous pix at that location is destroyed
788  */
789 l_int32
pixaReplacePix(PIXA * pixa,l_int32 index,PIX * pix,BOX * box)790 pixaReplacePix(PIXA    *pixa,
791                l_int32  index,
792                PIX     *pix,
793                BOX     *box)
794 {
795 BOXA  *boxa;
796 
797     PROCNAME("pixaReplacePix");
798 
799     if (!pixa)
800         return ERROR_INT("pixa not defined", procName, 1);
801     if (index < 0 || index >= pixa->n)
802         return ERROR_INT("index not valid", procName, 1);
803     if (!pix)
804         return ERROR_INT("pix not defined", procName, 1);
805 
806     pixDestroy(&(pixa->pix[index]));
807     pixa->pix[index] = pix;
808 
809     if (box) {
810         boxa = pixa->boxa;
811         if (index > boxa->n)
812             return ERROR_INT("boxa index not valid", procName, 1);
813         boxaReplaceBox(boxa, index, box);
814     }
815 
816     return 0;
817 }
818 
819 
820 /*!
821  *  pixaInsertPix()
822  *
823  *      Input:  pixa
824  *              index (at which pix is to be inserted)
825  *              pixs (new pix to be inserted)
826  *              box (<optional> new box to be inserted)
827  *      Return: 0 if OK, 1 on error
828  *
829  *  Notes:
830  *      (1) This shifts pixa[i] --> pixa[i + 1] for all i >= index,
831  *          and then inserts at pixa[index].
832  *      (2) To insert at the beginning of the array, set index = 0.
833  *      (3) It should not be used repeatedly on large arrays,
834  *          because the function is O(n).
835  *      (4) To append a pix to a pixa, it's easier to use pixaAddPix().
836  */
837 l_int32
pixaInsertPix(PIXA * pixa,l_int32 index,PIX * pixs,BOX * box)838 pixaInsertPix(PIXA    *pixa,
839               l_int32  index,
840               PIX     *pixs,
841               BOX     *box)
842 {
843 l_int32  i, n;
844 
845     PROCNAME("pixaInsertPix");
846 
847     if (!pixa)
848         return ERROR_INT("pixa not defined", procName, 1);
849     n = pixaGetCount(pixa);
850     if (index < 0 || index > n)
851         return ERROR_INT("index not in {0...n}", procName, 1);
852     if (!pixs)
853         return ERROR_INT("pixs not defined", procName, 1);
854 
855     if (n >= pixa->nalloc) {  /* extend both ptr arrays */
856         pixaExtendArray(pixa);
857         boxaExtendArray(pixa->boxa);
858     }
859     pixa->n++;
860     for (i = n; i > index; i--)
861       pixa->pix[i] = pixa->pix[i - 1];
862     pixa->pix[index] = pixs;
863 
864         /* Optionally, insert the box */
865     if (box)
866         boxaInsertBox(pixa->boxa, index, box);
867 
868     return 0;
869 }
870 
871 
872 /*!
873  *  pixaRemovePix()
874  *
875  *      Input:  pixa
876  *              index (of pix to be removed)
877  *      Return: 0 if OK, 1 on error
878  *
879  *  Notes:
880  *      (1) This shifts pixa[i] --> pixa[i - 1] for all i > index.
881  *      (2) It should not be used repeatedly on large arrays,
882  *          because the function is O(n).
883  *      (3) The corresponding box is removed as well, if it exists.
884  */
885 l_int32
pixaRemovePix(PIXA * pixa,l_int32 index)886 pixaRemovePix(PIXA    *pixa,
887               l_int32  index)
888 {
889 l_int32  i, n, nbox;
890 BOXA    *boxa;
891 PIX    **array;
892 
893     PROCNAME("pixaRemovePix");
894 
895     if (!pixa)
896         return ERROR_INT("pixa not defined", procName, 1);
897     n = pixaGetCount(pixa);
898     if (index < 0 || index >= n)
899         return ERROR_INT("index not in {0...n - 1}", procName, 1);
900 
901         /* Remove the pix */
902     array = pixa->pix;
903     pixDestroy(&array[index]);
904     for (i = index + 1; i < n; i++)
905         array[i - 1] = array[i];
906     array[n - 1] = NULL;
907     pixa->n--;
908 
909         /* Remove the box if it exists  */
910     boxa = pixa->boxa;
911     nbox = boxaGetCount(boxa);
912     if (index < nbox)
913         boxaRemoveBox(boxa, index);
914 
915     return 0;
916 }
917 
918 
919 /*---------------------------------------------------------------------*
920  *                           Pixa combination                          *
921  *---------------------------------------------------------------------*/
922 /*!
923  *  pixaJoin()
924  *
925  *      Input:  pixad  (dest pixa; add to this one)
926  *              pixas  (source pixa; add from this one)
927  *              istart  (starting index in nas)
928  *              iend  (ending index in nas; use 0 to cat all)
929  *      Return: 0 if OK, 1 on error
930  *
931  *  Notes:
932  *      (1) This appends a clone of each indicated pix in pixas to pixad
933  *      (2) istart < 0 is taken to mean 'read from the start' (istart = 0)
934  *      (3) iend <= 0 means 'read to the end'
935  */
936 l_int32
pixaJoin(PIXA * pixad,PIXA * pixas,l_int32 istart,l_int32 iend)937 pixaJoin(PIXA    *pixad,
938          PIXA    *pixas,
939          l_int32  istart,
940          l_int32  iend)
941 {
942 l_int32  ns, i;
943 BOXA    *boxas, *boxad;
944 PIX     *pix;
945 
946     PROCNAME("pixaJoin");
947 
948     if (!pixad)
949         return ERROR_INT("pixad not defined", procName, 1);
950     if (!pixas)
951         return ERROR_INT("pixas not defined", procName, 1);
952     ns = pixaGetCount(pixas);
953     if (istart < 0)
954         istart = 0;
955     if (istart >= ns)
956         return ERROR_INT("istart out of bounds", procName, 1);
957     if (iend <= 0)
958         iend = ns - 1;
959     if (iend >= ns)
960         return ERROR_INT("iend out of bounds", procName, 1);
961     if (istart > iend)
962         return ERROR_INT("istart > iend; nothing to add", procName, 1);
963 
964     for (i = istart; i <= iend; i++) {
965         pix = pixaGetPix(pixas, i, L_CLONE);
966         pixaAddPix(pixad, pix, L_INSERT);
967     }
968 
969     boxas = pixaGetBoxa(pixas, L_CLONE);
970     boxad = pixaGetBoxa(pixad, L_CLONE);
971     boxaJoin(boxad, boxas, 0, 0);
972     boxaDestroy(&boxas);  /* just the clones */
973     boxaDestroy(&boxad);
974 
975     return 0;
976 }
977 
978 
979 /*---------------------------------------------------------------------*
980  *                    Pixaa creation and destruction                   *
981  *---------------------------------------------------------------------*/
982 /*!
983  *  pixaaCreate()
984  *
985  *      Input:  n  (initial number of pixa ptrs)
986  *      Return: pixaa, or null on error
987  *
988  *  Notes:
989  *      (1) A pixaa provides a 2-level hierarchy of images.
990  *          A common use is for segmentation masks, which are
991  *          inexpensive to store in png format.
992  *      (2) For example, suppose you want a mask for each textline
993  *          in a two-column page.  The textline masks for each column
994  *          can be represented by a pixa, of which there are 2 in the pixaa.
995  *          The boxes for the textline mask components within a column
996  *          can have their origin referred to the column rather than the page.
997  *          Then the boxa field can be used to represent the two box (regions)
998  *          for the columns, and the (x,y) components of each box can
999  *          be used to get the absolute position of the textlines on
1000  *          the page.
1001  */
1002 PIXAA *
pixaaCreate(l_int32 n)1003 pixaaCreate(l_int32  n)
1004 {
1005 PIXAA  *pixaa;
1006 
1007     PROCNAME("pixaaCreate");
1008 
1009     if (n <= 0)
1010         n = INITIAL_PTR_ARRAYSIZE;
1011 
1012     if ((pixaa = (PIXAA *)CALLOC(1, sizeof(PIXAA))) == NULL)
1013         return (PIXAA *)ERROR_PTR("pixaa not made", procName, NULL);
1014     pixaa->n = 0;
1015     pixaa->nalloc = n;
1016 
1017     if ((pixaa->pixa = (PIXA **)CALLOC(n, sizeof(PIXA *))) == NULL)
1018         return (PIXAA *)ERROR_PTR("pixa ptrs not made", procName, NULL);
1019     pixaa->boxa = boxaCreate(n);
1020 
1021     return pixaa;
1022 }
1023 
1024 
1025 /*!
1026  *  pixaaCreateFromPixa()
1027  *
1028  *      Input:  pixa
1029  *              n (number specifying subdivision of pixa)
1030  *              type (L_CHOOSE_CONSECUTIVE, L_CHOOSE_SKIP_BY)
1031  *              copyflag (L_CLONE, L_COPY)
1032  *      Return: pixaa, or null on error
1033  *
1034  *  Notes:
1035  *      (1) This subdivides a pixa into a set of smaller pixa that
1036  *          are accumulated into a pixaa.
1037  *      (2) If type == L_CHOOSE_CONSECUTIVE, the first 'n' pix are
1038  *          put in a pixa and added to pixaa, then the next 'n', etc.
1039  *          If type == L_CHOOSE_SKIP_BY, the first pixa is made by
1040  *          aggregating pix[0], pix[n], pix[2*n], etc.
1041  *      (3) The copyflag specifies if each new pix is a copy or a clone.
1042  */
1043 PIXAA *
pixaaCreateFromPixa(PIXA * pixa,l_int32 n,l_int32 type,l_int32 copyflag)1044 pixaaCreateFromPixa(PIXA    *pixa,
1045                     l_int32  n,
1046                     l_int32  type,
1047                     l_int32  copyflag)
1048 {
1049 l_int32  count, i, j, npixa;
1050 PIX     *pix;
1051 PIXA    *pixat;
1052 PIXAA   *pixaa;
1053 
1054     PROCNAME("pixaaCreateFromPixa");
1055 
1056     if (!pixa)
1057         return (PIXAA *)ERROR_PTR("pixa not defined", procName, NULL);
1058     count = pixaGetCount(pixa);
1059     if (count == 0)
1060         return (PIXAA *)ERROR_PTR("no pix in pixa", procName, NULL);
1061     if (n <= 0)
1062         return (PIXAA *)ERROR_PTR("n must be > 0", procName, NULL);
1063     if (type != L_CHOOSE_CONSECUTIVE && type != L_CHOOSE_SKIP_BY)
1064         return (PIXAA *)ERROR_PTR("invalid type", procName, NULL);
1065     if (copyflag != L_CLONE && copyflag != L_COPY)
1066         return (PIXAA *)ERROR_PTR("invalid copyflag", procName, NULL);
1067 
1068     if (L_CHOOSE_CONSECUTIVE)
1069         npixa = (count + n - 1) / n;
1070     else  /* L_CHOOSE_SKIP_BY */
1071         npixa = L_MIN(n, count);
1072     pixaa = pixaaCreate(npixa);
1073     if (type == L_CHOOSE_CONSECUTIVE) {
1074         for (i = 0; i < count; i++) {
1075             if (i % n == 0)
1076                 pixat = pixaCreate(n);
1077             pix = pixaGetPix(pixa, i, copyflag);
1078             pixaAddPix(pixat, pix, L_INSERT);
1079             if (i % n == n - 1)
1080                 pixaaAddPixa(pixaa, pixat, L_INSERT);
1081         }
1082         if (i % n != 0)
1083             pixaaAddPixa(pixaa, pixat, L_INSERT);
1084     }
1085     else {  /* L_CHOOSE_SKIP_BY */
1086         for (i = 0; i < npixa; i++) {
1087             pixat = pixaCreate(count / npixa + 1);
1088             for (j = i; j < count; j += n) {
1089                 pix = pixaGetPix(pixa, j, copyflag);
1090                 pixaAddPix(pixat, pix, L_INSERT);
1091             }
1092             pixaaAddPixa(pixaa, pixat, L_INSERT);
1093         }
1094     }
1095 
1096     return pixaa;
1097 }
1098 
1099 
1100 /*!
1101  *  pixaaDestroy()
1102  *
1103  *      Input:  &pixaa <to be nulled>
1104  *      Return: void
1105  */
1106 void
pixaaDestroy(PIXAA ** ppixaa)1107 pixaaDestroy(PIXAA  **ppixaa)
1108 {
1109 l_int32  i;
1110 PIXAA   *pixaa;
1111 
1112     PROCNAME("pixaaDestroy");
1113 
1114     if (ppixaa == NULL) {
1115         L_WARNING("ptr address is NULL!", procName);
1116         return;
1117     }
1118 
1119     if ((pixaa = *ppixaa) == NULL)
1120         return;
1121 
1122     for (i = 0; i < pixaa->n; i++)
1123         pixaDestroy(&pixaa->pixa[i]);
1124     FREE(pixaa->pixa);
1125     boxaDestroy(&pixaa->boxa);
1126 
1127     FREE(pixaa);
1128     *ppixaa = NULL;
1129 
1130     return;
1131 }
1132 
1133 
1134 /*---------------------------------------------------------------------*
1135  *                             Pixaa addition                          *
1136  *---------------------------------------------------------------------*/
1137 /*!
1138  *  pixaaAddPixa()
1139  *
1140  *      Input:  pixaa
1141  *              pixa  (to be added)
1142  *              copyflag:
1143  *                L_INSERT inserts the pixa directly
1144  *                L_COPY makes a new pixa and copies each pix and each box
1145  *                L_CLONE gives a new handle to the input pixa
1146  *                L_COPY_CLONE makes a new pixa and inserts clones of
1147  *                    all pix and boxes
1148  *      Return: 0 if OK; 1 on error
1149  */
1150 l_int32
pixaaAddPixa(PIXAA * pixaa,PIXA * pixa,l_int32 copyflag)1151 pixaaAddPixa(PIXAA   *pixaa,
1152              PIXA    *pixa,
1153              l_int32  copyflag)
1154 {
1155 l_int32  n;
1156 PIXA    *pixac;
1157 
1158     PROCNAME("pixaaAddPixa");
1159 
1160     if (!pixaa)
1161         return ERROR_INT("pixaa not defined", procName, 1);
1162     if (!pixa)
1163         return ERROR_INT("pixa not defined", procName, 1);
1164     if (copyflag != L_INSERT && copyflag != L_COPY &&
1165         copyflag != L_CLONE && copyflag != L_COPY_CLONE)
1166         return ERROR_INT("invalid copyflag", procName, 1);
1167 
1168     if (copyflag == L_INSERT)
1169         pixac = pixa;
1170     else {
1171         if ((pixac = pixaCopy(pixa, copyflag)) == NULL)
1172             return ERROR_INT("pixac not made", procName, 1);
1173     }
1174 
1175     n = pixaaGetCount(pixaa);
1176     if (n >= pixaa->nalloc)
1177         pixaaExtendArray(pixaa);
1178     pixaa->pixa[n] = pixac;
1179     pixaa->n++;
1180 
1181     return 0;
1182 }
1183 
1184 
1185 /*!
1186  *  pixaaExtendArray()
1187  *
1188  *      Input:  pixaa
1189  *      Return: 0 if OK; 1 on error
1190  */
1191 l_int32
pixaaExtendArray(PIXAA * pixaa)1192 pixaaExtendArray(PIXAA  *pixaa)
1193 {
1194     PROCNAME("pixaaExtendArray");
1195 
1196     if (!pixaa)
1197         return ERROR_INT("pixaa not defined", procName, 1);
1198 
1199     if ((pixaa->pixa = (PIXA **)reallocNew((void **)&pixaa->pixa,
1200                              sizeof(PIXA *) * pixaa->nalloc,
1201                              2 * sizeof(PIXA *) * pixaa->nalloc)) == NULL)
1202         return ERROR_INT("new ptr array not returned", procName, 1);
1203 
1204     pixaa->nalloc = 2 * pixaa->nalloc;
1205     return 0;
1206 }
1207 
1208 
1209 /*!
1210  *  pixaaAddBox()
1211  *
1212  *      Input:  pixaa
1213  *              box
1214  *              copyflag (L_INSERT, L_COPY, L_CLONE)
1215  *      Return: 0 if OK, 1 on error
1216  *
1217  *  Notes:
1218  *      (1) The box can be used, for example, to hold the support region
1219  *          of a pixa that is being added to the pixaa.
1220  */
1221 l_int32
pixaaAddBox(PIXAA * pixaa,BOX * box,l_int32 copyflag)1222 pixaaAddBox(PIXAA   *pixaa,
1223             BOX     *box,
1224             l_int32  copyflag)
1225 {
1226     PROCNAME("pixaaAddBox");
1227 
1228     if (!pixaa)
1229         return ERROR_INT("pixaa not defined", procName, 1);
1230     if (!box)
1231         return ERROR_INT("box not defined", procName, 1);
1232     if (copyflag != L_INSERT && copyflag != L_COPY && copyflag != L_CLONE)
1233         return ERROR_INT("invalid copyflag", procName, 1);
1234 
1235     boxaAddBox(pixaa->boxa, box, copyflag);
1236     return 0;
1237 }
1238 
1239 
1240 
1241 /*---------------------------------------------------------------------*
1242  *                            Pixaa accessors                          *
1243  *---------------------------------------------------------------------*/
1244 /*!
1245  *  pixaaGetCount()
1246  *
1247  *      Input:  pixaa
1248  *      Return: count, or 0 if no pixaa
1249  */
1250 l_int32
pixaaGetCount(PIXAA * pixaa)1251 pixaaGetCount(PIXAA  *pixaa)
1252 {
1253     PROCNAME("pixaaGetCount");
1254 
1255     if (!pixaa)
1256         return ERROR_INT("pixaa not defined", procName, 0);
1257 
1258     return pixaa->n;
1259 }
1260 
1261 
1262 /*!
1263  *  pixaaGetPixa()
1264  *
1265  *      Input:  pixaa
1266  *              index  (to the index-th pixa)
1267  *              accesstype  (L_COPY, L_CLONE, L_COPY_CLONE)
1268  *      Return: pixa, or null on error
1269  *
1270  *  Notes:
1271  *      (1) L_COPY makes a new pixa with a copy of every pix
1272  *      (2) L_CLONE just makes a new reference to the pixa,
1273  *          and bumps the counter.  You would use this, for example,
1274  *          when you need to extract some data from a pix within a
1275  *          pixa within a pixaa.
1276  *      (3) L_COPY_CLONE makes a new pixa with a clone of every pix
1277  *          and box
1278  *      (4) In all cases, you must invoke pixaDestroy() on the returned pixa
1279  */
1280 PIXA *
pixaaGetPixa(PIXAA * pixaa,l_int32 index,l_int32 accesstype)1281 pixaaGetPixa(PIXAA   *pixaa,
1282              l_int32  index,
1283              l_int32  accesstype)
1284 {
1285 PIXA  *pixa;
1286 
1287     PROCNAME("pixaaGetPixa");
1288 
1289     if (!pixaa)
1290         return (PIXA *)ERROR_PTR("pixaa not defined", procName, NULL);
1291     if (index < 0 || index >= pixaa->n)
1292         return (PIXA *)ERROR_PTR("index not valid", procName, NULL);
1293     if (accesstype != L_COPY && accesstype != L_CLONE &&
1294         accesstype != L_COPY_CLONE)
1295         return (PIXA *)ERROR_PTR("invalid accesstype", procName, NULL);
1296 
1297     if ((pixa = pixaa->pixa[index]) == NULL)  /* shouldn't happen! */
1298         return (PIXA *)ERROR_PTR("no pixa[index]", procName, NULL);
1299     return pixaCopy(pixa, accesstype);
1300 }
1301 
1302 
1303 /*!
1304  *  pixaaGetBoxa()
1305  *
1306  *      Input:  pixaa
1307  *              accesstype  (L_COPY, L_CLONE)
1308  *      Return: boxa, or null on error
1309  *
1310  *  Notes:
1311  *      (1) L_COPY returns a copy; L_CLONE returns a new reference to the boxa.
1312  *      (2) In both cases, invoke boxaDestroy() on the returned boxa.
1313  */
1314 BOXA *
pixaaGetBoxa(PIXAA * pixaa,l_int32 accesstype)1315 pixaaGetBoxa(PIXAA   *pixaa,
1316              l_int32  accesstype)
1317 {
1318     PROCNAME("pixaaGetBoxa");
1319 
1320     if (!pixaa)
1321         return (BOXA *)ERROR_PTR("pixaa not defined", procName, NULL);
1322     if (accesstype != L_COPY && accesstype != L_CLONE)
1323         return (BOXA *)ERROR_PTR("invalid access type", procName, NULL);
1324 
1325     return boxaCopy(pixaa->boxa, accesstype);
1326 }
1327 
1328 
1329 /*---------------------------------------------------------------------*
1330  *                          Pixa serialized I/O                        *
1331  *---------------------------------------------------------------------*/
1332 /*!
1333  *  pixaRead()
1334  *
1335  *      Input:  filename
1336  *      Return: pixa, or null on error
1337  *
1338  *  Notes:
1339  *      (1) The pix are stored in the file as png.
1340  */
1341 PIXA *
pixaRead(const char * filename)1342 pixaRead(const char  *filename)
1343 {
1344 FILE  *fp;
1345 PIXA  *pixa;
1346 
1347     PROCNAME("pixaRead");
1348 
1349     if (!filename)
1350         return (PIXA *)ERROR_PTR("filename not defined", procName, NULL);
1351     if ((fp = fopenReadStream(filename)) == NULL)
1352         return (PIXA *)ERROR_PTR("stream not opened", procName, NULL);
1353 
1354     if ((pixa = pixaReadStream(fp)) == NULL) {
1355         fclose(fp);
1356         return (PIXA *)ERROR_PTR("pixa not read", procName, NULL);
1357     }
1358 
1359     fclose(fp);
1360     return pixa;
1361 }
1362 
1363 
1364 /*!
1365  *  pixaReadStream()
1366  *
1367  *      Input:  stream
1368  *      Return: pixa, or null on error
1369  */
1370 PIXA *
pixaReadStream(FILE * fp)1371 pixaReadStream(FILE  *fp)
1372 {
1373 l_int32  n, i, xres, yres, version;
1374 l_int32  ignore;
1375 BOXA    *boxa;
1376 PIX     *pix;
1377 PIXA    *pixa;
1378 
1379     PROCNAME("pixaReadStream");
1380 
1381 #if  !HAVE_LIBPNG  /* defined in environ.h */
1382     return (PIXA *)ERROR_PTR("no libpng: can't read data", procName, NULL);
1383 #else
1384 
1385     if (!fp)
1386         return (PIXA *)ERROR_PTR("stream not defined", procName, NULL);
1387 
1388     if (fscanf(fp, "\nPixa Version %d\n", &version) != 1)
1389         return (PIXA *)ERROR_PTR("not a pixa file", procName, NULL);
1390     if (version != PIXA_VERSION_NUMBER)
1391         return (PIXA *)ERROR_PTR("invalid pixa version", procName, NULL);
1392     if (fscanf(fp, "Number of pix = %d\n", &n) != 1)
1393         return (PIXA *)ERROR_PTR("not a pixa file", procName, NULL);
1394 
1395     if ((pixa = pixaCreate(n)) == NULL)
1396         return (PIXA *)ERROR_PTR("pixa not made", procName, NULL);
1397     if ((boxa = boxaReadStream(fp)) == NULL)
1398         return (PIXA *)ERROR_PTR("boxa not made", procName, NULL);
1399     boxaDestroy(&pixa->boxa);
1400     pixa->boxa = boxa;
1401 
1402     for (i = 0; i < n; i++) {
1403         if ((fscanf(fp, " pix[%d]: xres = %d, yres = %d\n",
1404               &ignore, &xres, &yres)) != 3)
1405             return (PIXA *)ERROR_PTR("res reading", procName, NULL);
1406         if ((pix = pixReadStreamPng(fp)) == NULL)
1407             return (PIXA *)ERROR_PTR("pix not read", procName, NULL);
1408         pixSetXRes(pix, xres);
1409         pixSetYRes(pix, yres);
1410         pixaAddPix(pixa, pix, L_INSERT);
1411     }
1412 
1413     return pixa;
1414 
1415 #endif  /* !HAVE_LIBPNG */
1416 }
1417 
1418 
1419 /*!
1420  *  pixaWrite()
1421  *
1422  *      Input:  filename
1423  *              pixa
1424  *      Return: 0 if OK, 1 on error
1425  *
1426  *  Notes:
1427  *      (1) The pix are written to file in png format.
1428  */
1429 l_int32
pixaWrite(const char * filename,PIXA * pixa)1430 pixaWrite(const char  *filename,
1431           PIXA        *pixa)
1432 {
1433 FILE  *fp;
1434 
1435     PROCNAME("pixaWrite");
1436 
1437     if (!filename)
1438         return ERROR_INT("filename not defined", procName, 1);
1439     if (!pixa)
1440         return ERROR_INT("pixa not defined", procName, 1);
1441 
1442     if ((fp = fopen(filename, "w")) == NULL)
1443         return ERROR_INT("stream not opened", procName, 1);
1444     if (pixaWriteStream(fp, pixa))
1445         return ERROR_INT("pixa not written to stream", procName, 1);
1446     fclose(fp);
1447 
1448     return 0;
1449 }
1450 
1451 
1452 /*!
1453  *  pixaWriteStream()
1454  *
1455  *      Input:  stream
1456  *              pixa
1457  *      Return: 0 if OK, 1 on error
1458  */
1459 l_int32
pixaWriteStream(FILE * fp,PIXA * pixa)1460 pixaWriteStream(FILE  *fp,
1461                 PIXA  *pixa)
1462 {
1463 l_int32  n, i;
1464 PIX     *pix;
1465 
1466     PROCNAME("pixaWriteStream");
1467 
1468 #if  !HAVE_LIBPNG  /* defined in environ.h */
1469     return ERROR_INT("no libpng: can't write data", procName, 1);
1470 #else
1471 
1472     if (!fp)
1473         return ERROR_INT("stream not defined", procName, 1);
1474     if (!pixa)
1475         return ERROR_INT("pixa not defined", procName, 1);
1476 
1477     n = pixaGetCount(pixa);
1478     fprintf(fp, "\nPixa Version %d\n", PIXA_VERSION_NUMBER);
1479     fprintf(fp, "Number of pix = %d\n", n);
1480     boxaWriteStream(fp, pixa->boxa);
1481     for (i = 0; i < n; i++) {
1482         if ((pix = pixaGetPix(pixa, i, L_CLONE)) == NULL)
1483             return ERROR_INT("pix not found", procName, 1);
1484         fprintf(fp, " pix[%d]: xres = %d, yres = %d\n",
1485                 i, pix->xres, pix->yres);
1486         pixWriteStreamPng(fp, pix, 0.0);
1487         pixDestroy(&pix);
1488     }
1489     return 0;
1490 
1491 #endif  /* !HAVE_LIBPNG */
1492 }
1493 
1494 
1495 /*---------------------------------------------------------------------*
1496  *                         Pixaa serialized I/O                        *
1497  *---------------------------------------------------------------------*/
1498 /*!
1499  *  pixaaRead()
1500  *
1501  *      Input:  filename
1502  *      Return: pixaa, or null on error
1503  *
1504  *  Notes:
1505  *      (1) The pix are stored in the file as png.
1506  */
1507 PIXAA *
pixaaRead(const char * filename)1508 pixaaRead(const char  *filename)
1509 {
1510 FILE   *fp;
1511 PIXAA  *pixaa;
1512 
1513     PROCNAME("pixaaRead");
1514 
1515     if (!filename)
1516         return (PIXAA *)ERROR_PTR("filename not defined", procName, NULL);
1517     if ((fp = fopenReadStream(filename)) == NULL)
1518         return (PIXAA *)ERROR_PTR("stream not opened", procName, NULL);
1519 
1520     if ((pixaa = pixaaReadStream(fp)) == NULL) {
1521         fclose(fp);
1522         return (PIXAA *)ERROR_PTR("pixaa not read", procName, NULL);
1523     }
1524 
1525     fclose(fp);
1526     return pixaa;
1527 }
1528 
1529 
1530 /*!
1531  *  pixaaReadStream()
1532  *
1533  *      Input:  stream
1534  *      Return: pixaa, or null on error
1535  */
1536 PIXAA *
pixaaReadStream(FILE * fp)1537 pixaaReadStream(FILE  *fp)
1538 {
1539 l_int32  n, i, version;
1540 l_int32  ignore;
1541 BOXA    *boxa;
1542 PIXA    *pixa;
1543 PIXAA   *pixaa;
1544 
1545     PROCNAME("pixaaReadStream");
1546 
1547     if (!fp)
1548         return (PIXAA *)ERROR_PTR("stream not defined", procName, NULL);
1549 
1550     if (fscanf(fp, "\nPixaa Version %d\n", &version) != 1)
1551         return (PIXAA *)ERROR_PTR("not a pixaa file", procName, NULL);
1552     if (version != PIXAA_VERSION_NUMBER)
1553         return (PIXAA *)ERROR_PTR("invalid pixaa version", procName, NULL);
1554     if (fscanf(fp, "Number of pixa = %d\n", &n) != 1)
1555         return (PIXAA *)ERROR_PTR("not a pixaa file", procName, NULL);
1556 
1557     if ((pixaa = pixaaCreate(n)) == NULL)
1558         return (PIXAA *)ERROR_PTR("pixaa not made", procName, NULL);
1559     if ((boxa = boxaReadStream(fp)) == NULL)
1560         return (PIXAA *)ERROR_PTR("boxa not made", procName, NULL);
1561     boxaDestroy(&pixaa->boxa);
1562     pixaa->boxa = boxa;
1563 
1564     for (i = 0; i < n; i++) {
1565         if ((fscanf(fp, "\n\n --------------- pixa[%d] ---------------\n",
1566                     &ignore)) != 1) {
1567             return (PIXAA *)ERROR_PTR("text reading", procName, NULL);
1568         }
1569         if ((pixa = pixaReadStream(fp)) == NULL)
1570             return (PIXAA *)ERROR_PTR("pixa not read", procName, NULL);
1571         pixaaAddPixa(pixaa, pixa, L_INSERT);
1572     }
1573 
1574     return pixaa;
1575 }
1576 
1577 
1578 /*!
1579  *  pixaaWrite()
1580  *
1581  *      Input:  filename
1582  *              pixaa
1583  *      Return: 0 if OK, 1 on error
1584  *
1585  *  Notes:
1586  *      (1) Serialization of pixaa; the pix are written in png
1587  */
1588 l_int32
pixaaWrite(const char * filename,PIXAA * pixaa)1589 pixaaWrite(const char  *filename,
1590            PIXAA       *pixaa)
1591 {
1592 FILE  *fp;
1593 
1594     PROCNAME("pixaaWrite");
1595 
1596     if (!filename)
1597         return ERROR_INT("filename not defined", procName, 1);
1598     if (!pixaa)
1599         return ERROR_INT("pixaa not defined", procName, 1);
1600 
1601     if ((fp = fopen(filename, "w")) == NULL)
1602         return ERROR_INT("stream not opened", procName, 1);
1603     if (pixaaWriteStream(fp, pixaa))
1604         return ERROR_INT("pixaa not written to stream", procName, 1);
1605     fclose(fp);
1606 
1607     return 0;
1608 }
1609 
1610 
1611 /*!
1612  *  pixaaWriteStream()
1613  *
1614  *      Input:  stream
1615  *              pixaa
1616  *      Return: 0 if OK, 1 on error
1617  */
1618 l_int32
pixaaWriteStream(FILE * fp,PIXAA * pixaa)1619 pixaaWriteStream(FILE   *fp,
1620                  PIXAA  *pixaa)
1621 {
1622 l_int32  n, i;
1623 PIXA    *pixa;
1624 
1625     PROCNAME("pixaaWriteStream");
1626 
1627     if (!fp)
1628         return ERROR_INT("stream not defined", procName, 1);
1629     if (!pixaa)
1630         return ERROR_INT("pixaa not defined", procName, 1);
1631 
1632     n = pixaaGetCount(pixaa);
1633     fprintf(fp, "\nPixaa Version %d\n", PIXAA_VERSION_NUMBER);
1634     fprintf(fp, "Number of pixa = %d\n", n);
1635     boxaWriteStream(fp, pixaa->boxa);
1636     for (i = 0; i < n; i++) {
1637         if ((pixa = pixaaGetPixa(pixaa, i, L_CLONE)) == NULL)
1638             return ERROR_INT("pixa not found", procName, 1);
1639         fprintf(fp, "\n\n --------------- pixa[%d] ---------------\n", i);
1640         pixaWriteStream(fp, pixa);
1641         pixaDestroy(&pixa);
1642     }
1643     return 0;
1644 }
1645 
1646 
1647