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