Leptonica 1.85.0
Image processing and image analysis suite
Loading...
Searching...
No Matches
pixafunc2.c
Go to the documentation of this file.
1/*====================================================================*
2 - Copyright (C) 2001 Leptonica. All rights reserved.
3 -
4 - Redistribution and use in source and binary forms, with or without
5 - modification, are permitted provided that the following conditions
6 - are met:
7 - 1. Redistributions of source code must retain the above copyright
8 - notice, this list of conditions and the following disclaimer.
9 - 2. Redistributions in binary form must reproduce the above
10 - copyright notice, this list of conditions and the following
11 - disclaimer in the documentation and/or other materials
12 - provided with the distribution.
13 -
14 - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15 - ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16 - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
17 - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ANY
18 - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 - OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
23 - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24 - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 *====================================================================*/
26
159#ifdef HAVE_CONFIG_H
160#include <config_auto.h>
161#endif /* HAVE_CONFIG_H */
162
163#include <string.h>
164#include <math.h> /* for sqrt() */
165#include "allheaders.h"
166
167/*---------------------------------------------------------------------*
168 * Pixa Display *
169 *---------------------------------------------------------------------*/
190PIX *
192 l_int32 w,
193 l_int32 h)
194{
195l_int32 i, n, d, xb, yb, wb, hb, res;
196BOXA *boxa;
197PIX *pix1, *pixd;
198
199 if (!pixa)
200 return (PIX *)ERROR_PTR("pixa not defined", __func__, NULL);
201
202 n = pixaGetCount(pixa);
203 if (n == 0 && w == 0 && h == 0)
204 return (PIX *)ERROR_PTR("no components; no size", __func__, NULL);
205 if (n == 0) {
206 L_WARNING("no components; returning empty 1 bpp pix\n", __func__);
207 return pixCreate(w, h, 1);
208 }
209
210 /* If w and h not input, determine the minimum size required
211 * to contain the origin and all c.c. */
212 if (w == 0 || h == 0) {
213 boxa = pixaGetBoxa(pixa, L_CLONE);
214 boxaGetExtent(boxa, &w, &h, NULL);
215 boxaDestroy(&boxa);
216 if (w == 0 || h == 0)
217 return (PIX *)ERROR_PTR("no associated boxa", __func__, NULL);
218 }
219
220 /* Use the first pix in pixa to determine depth and resolution */
221 pix1 = pixaGetPix(pixa, 0, L_CLONE);
222 d = pixGetDepth(pix1);
223 res = pixGetXRes(pix1);
224 pixDestroy(&pix1);
225
226 if ((pixd = pixCreate(w, h, d)) == NULL)
227 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
228 pixSetResolution(pixd, res, res);
229 if (d > 1)
230 pixSetAll(pixd);
231 for (i = 0; i < n; i++) {
232 if (pixaGetBoxGeometry(pixa, i, &xb, &yb, &wb, &hb)) {
233 L_WARNING("no box found!\n", __func__);
234 continue;
235 }
236 pix1 = pixaGetPix(pixa, i, L_CLONE);
237 if (d == 1)
238 pixRasterop(pixd, xb, yb, wb, hb, PIX_PAINT, pix1, 0, 0);
239 else
240 pixRasterop(pixd, xb, yb, wb, hb, PIX_SRC, pix1, 0, 0);
241 pixDestroy(&pix1);
242 }
243
244 return pixd;
245}
246
247
266PIX *
268 l_int32 w,
269 l_int32 h)
270{
271l_int32 i, n, same, maxd, index, xb, yb, wb, hb, res;
272BOXA *boxa;
273PIX *pixs, *pix1, *pixd;
274PIXCMAP *cmap;
275
276 if (!pixa)
277 return (PIX *)ERROR_PTR("pixa not defined", __func__, NULL);
278
279 if ((n = pixaGetCount(pixa)) == 0)
280 return (PIX *)ERROR_PTR("no components", __func__, NULL);
281 pixaVerifyDepth(pixa, &same, &maxd);
282 if (maxd > 1)
283 return (PIX *)ERROR_PTR("not all components are 1 bpp", __func__, NULL);
284
285 /* If w and h are not input, determine the minimum size required
286 * to contain the origin and all c.c. */
287 if (w == 0 || h == 0) {
288 boxa = pixaGetBoxa(pixa, L_CLONE);
289 boxaGetExtent(boxa, &w, &h, NULL);
290 boxaDestroy(&boxa);
291 }
292
293 /* Set up an 8 bpp dest pix, with a colormap with 254 random colors */
294 if ((pixd = pixCreate(w, h, 8)) == NULL)
295 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
296 cmap = pixcmapCreateRandom(8, 1, 1);
297 pixSetColormap(pixd, cmap);
298
299 /* Color each component and blit it in */
300 for (i = 0; i < n; i++) {
301 index = 1 + (i % 254);
302 pixaGetBoxGeometry(pixa, i, &xb, &yb, &wb, &hb);
303 pixs = pixaGetPix(pixa, i, L_CLONE);
304 if (i == 0) res = pixGetXRes(pixs);
305 pix1 = pixConvert1To8(NULL, pixs, 0, index);
306 pixRasterop(pixd, xb, yb, wb, hb, PIX_PAINT, pix1, 0, 0);
307 pixDestroy(&pixs);
308 pixDestroy(&pix1);
309 }
310
311 pixSetResolution(pixd, res, res);
312 return pixd;
313}
314
315
338PIX *
340 l_int32 direction,
341 l_float32 scalefactor,
342 l_int32 background, /* not used */
343 l_int32 spacing,
344 l_int32 border,
345 BOXA **pboxa)
346{
347l_int32 i, n, x, y, w, h, depth, bordval;
348BOX *box;
349PIX *pix1, *pix2, *pix3, *pixd;
350PIXA *pixa1, *pixa2;
351
352 if (pboxa) *pboxa = NULL;
353 if (!pixas)
354 return (PIX *)ERROR_PTR("pixas not defined", __func__, NULL);
355 if (direction != L_HORIZ && direction != L_VERT)
356 return (PIX *)ERROR_PTR("invalid direction", __func__, NULL);
357
358 /* Make sure all pix are at the same depth */
359 pixa1 = pixaConvertToSameDepth(pixas);
360 pixaGetDepthInfo(pixa1, &depth, NULL);
361
362 /* Scale and add border if requested */
363 n = pixaGetCount(pixa1);
364 pixa2 = pixaCreate(n);
365 bordval = (depth == 1) ? 1 : 0;
366 x = y = 0;
367 for (i = 0; i < n; i++) {
368 if ((pix1 = pixaGetPix(pixa1, i, L_CLONE)) == NULL) {
369 L_WARNING("missing pix at index %d\n", __func__, i);
370 continue;
371 }
372
373 if (scalefactor != 1.0)
374 pix2 = pixScale(pix1, scalefactor, scalefactor);
375 else
376 pix2 = pixClone(pix1);
377 if (border)
378 pix3 = pixAddBorder(pix2, border, bordval);
379 else
380 pix3 = pixClone(pix2);
381
382 pixGetDimensions(pix3, &w, &h, NULL);
383 box = boxCreate(x, y, w, h);
384 if (direction == L_HORIZ)
385 x += w + spacing;
386 else /* vertical */
387 y += h + spacing;
388 pixaAddPix(pixa2, pix3, L_INSERT);
389 pixaAddBox(pixa2, box, L_INSERT);
390 pixDestroy(&pix1);
391 pixDestroy(&pix2);
392 }
393 pixd = pixaDisplay(pixa2, 0, 0);
394
395 if (pboxa)
396 *pboxa = pixaGetBoxa(pixa2, L_COPY);
397 pixaDestroy(&pixa1);
398 pixaDestroy(&pixa2);
399 return pixd;
400}
401
402
429PIX *
431 l_int32 cellw,
432 l_int32 cellh,
433 l_int32 *pncols,
434 BOXA **pboxa)
435{
436char buf[16];
437l_int32 n, nw, nh, w, h, d, wt, ht, res, samedepth;
438l_int32 index, i, j, hascmap;
439BOX *box;
440BOXA *boxa;
441PIX *pix1, *pix2, *pixd;
442PIXA *pixa1;
443
444 if (pncols) *pncols = 0;
445 if (pboxa) *pboxa = NULL;
446 if (!pixa)
447 return (PIX *)ERROR_PTR("pixa not defined", __func__, NULL);
448
449 /* If any pix have colormaps, or if the depths differ, generate rgb */
450 if ((n = pixaGetCount(pixa)) == 0)
451 return (PIX *)ERROR_PTR("no components", __func__, NULL);
452 pixaAnyColormaps(pixa, &hascmap);
453 pixaVerifyDepth(pixa, &samedepth, NULL);
454 if (hascmap || !samedepth) {
455 pixa1 = pixaCreate(n);
456 for (i = 0; i < n; i++) {
457 pix1 = pixaGetPix(pixa, i, L_CLONE);
458 pix2 = pixConvertTo32(pix1);
459 pixaAddPix(pixa1, pix2, L_INSERT);
460 pixDestroy(&pix1);
461 }
462 } else {
463 pixa1 = pixaCopy(pixa, L_CLONE);
464 }
465
466 /* Have number of rows and columns approximately equal */
467 nw = (l_int32)sqrt((l_float64)n);
468 nh = (n + nw - 1) / nw;
469 w = cellw * nw;
470 h = cellh * nh;
471
472 /* Use the first pix to determine output depth and resolution */
473 pix1 = pixaGetPix(pixa1, 0, L_CLONE);
474 d = pixGetDepth(pix1);
475 res = pixGetXRes(pix1);
476 pixDestroy(&pix1);
477 if ((pixd = pixCreate(w, h, d)) == NULL) {
478 pixaDestroy(&pixa1);
479 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
480 }
481 pixSetBlackOrWhite(pixd, L_SET_WHITE);
482 pixSetResolution(pixd, res, res);
483 boxa = boxaCreate(n);
484
485 /* Tile the output */
486 index = 0;
487 for (i = 0; i < nh; i++) {
488 for (j = 0; j < nw && index < n; j++, index++) {
489 pix1 = pixaGetPix(pixa1, index, L_CLONE);
490 pixGetDimensions(pix1, &wt, &ht, NULL);
491 if (wt > cellw || ht > cellh) {
492 L_INFO("pix(%d) omitted; size %dx%x\n", __func__, index,
493 wt, ht);
494 box = boxCreate(0, 0, 0, 0);
495 boxaAddBox(boxa, box, L_INSERT);
496 pixDestroy(&pix1);
497 continue;
498 }
499 pixRasterop(pixd, j * cellw, i * cellh, wt, ht,
500 PIX_SRC, pix1, 0, 0);
501 box = boxCreate(j * cellw, i * cellh, wt, ht);
502 boxaAddBox(boxa, box, L_INSERT);
503 pixDestroy(&pix1);
504 }
505 }
506
507 /* Save the number of tiles in the text field */
508 snprintf(buf, sizeof(buf), "n = %d", boxaGetCount(boxa));
509 pixSetText(pixd, buf);
510
511 if (pncols) *pncols = nw;
512 if (pboxa)
513 *pboxa = boxa;
514 else
515 boxaDestroy(&boxa);
516 pixaDestroy(&pixa1);
517 return pixd;
518}
519
520
544PIX *
546 l_int32 nx,
547 l_int32 ny,
548 l_int32 borderwidth,
549 l_uint32 bordercolor)
550{
551l_int32 w, h, d, wt, ht;
552l_int32 i, j, k, x, y, n;
553PIX *pix1, *pixd;
554
555 if (!pixa)
556 return (PIX *)ERROR_PTR("pixa not defined", __func__, NULL);
557 if (nx <= 0 || ny <= 0)
558 return (PIX *)ERROR_PTR("nx and ny must be > 0", __func__, NULL);
559 if ((n = pixaGetCount(pixa)) == 0)
560 return (PIX *)ERROR_PTR("no components", __func__, NULL);
561 if (n != nx * ny)
562 return (PIX *)ERROR_PTR("n != nx * ny", __func__, NULL);
563 borderwidth = L_MAX(0, borderwidth);
564
565 pixaGetPixDimensions(pixa, 0, &wt, &ht, &d);
566 w = nx * (wt + 2 * borderwidth);
567 h = ny * (ht + 2 * borderwidth);
568
569 if ((pixd = pixCreate(w, h, d)) == NULL)
570 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
571 pix1 = pixaGetPix(pixa, 0, L_CLONE);
572 pixCopyColormap(pixd, pix1);
573 pixDestroy(&pix1);
574 if (borderwidth > 0)
575 pixSetAllArbitrary(pixd, bordercolor);
576
577 y = borderwidth;
578 for (i = 0, k = 0; i < ny; i++) {
579 x = borderwidth;
580 for (j = 0; j < nx; j++, k++) {
581 pix1 = pixaGetPix(pixa, k, L_CLONE);
582 pixRasterop(pixd, x, y, wt, ht, PIX_SRC, pix1, 0, 0);
583 pixDestroy(&pix1);
584 x += wt + 2 * borderwidth;
585 }
586 y += ht + 2 * borderwidth;
587 }
588
589 return pixd;
590}
591
592
617PIX *
619 l_int32 maxwidth,
620 l_int32 background,
621 l_int32 spacing)
622{
623l_int32 wmax, hmax, wd, hd, d, hascmap, res, same;
624l_int32 i, j, n, ni, ncols, nrows;
625l_int32 ystart, xstart, wt, ht;
626PIX *pix1, *pix2, *pixd;
627PIXA *pixa1;
628
629 if (!pixa)
630 return (PIX *)ERROR_PTR("pixa not defined", __func__, NULL);
631 spacing = L_MAX(spacing, 0);
632 if ((n = pixaGetCount(pixa)) == 0)
633 return (PIX *)ERROR_PTR("no components", __func__, NULL);
634
635 /* If any pix have colormaps, generate rgb */
636 pixaAnyColormaps(pixa, &hascmap);
637 if (hascmap) {
638 pixa1 = pixaCreate(n);
639 for (i = 0; i < n; i++) {
640 pix1 = pixaGetPix(pixa, i, L_CLONE);
641 pix2 = pixConvertTo32(pix1);
642 pixaAddPix(pixa1, pix2, L_INSERT);
643 pixDestroy(&pix1);
644 }
645 } else {
646 pixa1 = pixaCopy(pixa, L_CLONE);
647 }
648
649 /* Find the max dimensions and depth subimages */
650 pixaGetDepthInfo(pixa1, &d, &same);
651 if (!same) {
652 pixaDestroy(&pixa1);
653 return (PIX *)ERROR_PTR("depths not equal", __func__, NULL);
654 }
655 pixaSizeRange(pixa1, NULL, NULL, &wmax, &hmax);
656
657 /* Get the number of rows and columns and the output image size */
658 ncols = (l_int32)((l_float32)(maxwidth - spacing) /
659 (l_float32)(wmax + spacing));
660 ncols = L_MAX(ncols, 1);
661 nrows = (n + ncols - 1) / ncols;
662 wd = wmax * ncols + spacing * (ncols + 1);
663 hd = hmax * nrows + spacing * (nrows + 1);
664 if ((pixd = pixCreate(wd, hd, d)) == NULL) {
665 pixaDestroy(&pixa1);
666 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
667 }
668
669 /* Reset the background color if necessary */
670 if ((background == 1 && d == 1) || (background == 0 && d != 1))
671 pixSetAll(pixd);
672
673 /* Blit the images to the dest */
674 for (i = 0, ni = 0; i < nrows; i++) {
675 ystart = spacing + i * (hmax + spacing);
676 for (j = 0; j < ncols && ni < n; j++, ni++) {
677 xstart = spacing + j * (wmax + spacing);
678 pix1 = pixaGetPix(pixa1, ni, L_CLONE);
679 if (ni == 0) res = pixGetXRes(pix1);
680 pixGetDimensions(pix1, &wt, &ht, NULL);
681 pixRasterop(pixd, xstart, ystart, wt, ht, PIX_SRC, pix1, 0, 0);
682 pixDestroy(&pix1);
683 }
684 }
685 pixSetResolution(pixd, res, res);
686
687 pixaDestroy(&pixa1);
688 return pixd;
689}
690
691
729PIX *
731 l_int32 outdepth,
732 l_int32 maxwidth,
733 l_float32 scalefactor,
734 l_int32 background,
735 l_int32 spacing,
736 l_int32 border)
737{
738l_int32 h; /* cumulative height over all the rows */
739l_int32 w; /* cumulative height in the current row */
740l_int32 bordval, wtry, wt, ht;
741l_int32 irow; /* index of current pix in current row */
742l_int32 wmaxrow; /* width of the largest row */
743l_int32 maxh; /* max height in row */
744l_int32 i, j, index, n, x, y, nrows, ninrow, res;
745size_t size;
746l_uint8 *data;
747BOXA *boxa;
748NUMA *nainrow; /* number of pix in the row */
749NUMA *namaxh; /* height of max pix in the row */
750PIX *pix, *pixn, *pix1, *pixd;
751PIXA *pixan;
752
753 if (!pixa)
754 return (PIX *)ERROR_PTR("pixa not defined", __func__, NULL);
755 if (outdepth != 1 && outdepth != 8 && outdepth != 32)
756 return (PIX *)ERROR_PTR("outdepth not in {1, 8, 32}", __func__, NULL);
757 spacing = L_MAX(spacing, 0);
758 border = L_MAX(border, 0);
759 if (scalefactor <= 0.0) scalefactor = 1.0;
760
761 if ((n = pixaGetCount(pixa)) == 0)
762 return (PIX *)ERROR_PTR("no components", __func__, NULL);
763
764 /* Normalize depths, scale, remove colormaps; optionally add border */
765 pixan = pixaCreate(n);
766 bordval = (outdepth == 1) ? 1 : 0;
767 for (i = 0; i < n; i++) {
768 if ((pix = pixaGetPix(pixa, i, L_CLONE)) == NULL)
769 continue;
770
771 if (outdepth == 1)
772 pixn = pixConvertTo1(pix, 128);
773 else if (outdepth == 8)
774 pixn = pixConvertTo8(pix, FALSE);
775 else /* outdepth == 32 */
776 pixn = pixConvertTo32(pix);
777 pixDestroy(&pix);
778
779 if (scalefactor != 1.0)
780 pix1 = pixScale(pixn, scalefactor, scalefactor);
781 else
782 pix1 = pixClone(pixn);
783 if (border)
784 pixd = pixAddBorder(pix1, border, bordval);
785 else
786 pixd = pixClone(pix1);
787 pixDestroy(&pixn);
788 pixDestroy(&pix1);
789
790 pixaAddPix(pixan, pixd, L_INSERT);
791 }
792 if (pixaGetCount(pixan) != n) {
793 n = pixaGetCount(pixan);
794 L_WARNING("only got %d components\n", __func__, n);
795 if (n == 0) {
796 pixaDestroy(&pixan);
797 return (PIX *)ERROR_PTR("no components", __func__, NULL);
798 }
799 }
800
801 /* Compute parameters for layout */
802 nainrow = numaCreate(0);
803 namaxh = numaCreate(0);
804 wmaxrow = 0;
805 w = h = spacing;
806 maxh = 0; /* max height in row */
807 for (i = 0, irow = 0; i < n; i++, irow++) {
808 pixaGetPixDimensions(pixan, i, &wt, &ht, NULL);
809 wtry = w + wt + spacing;
810 if (wtry > maxwidth) { /* end the current row and start next one */
811 numaAddNumber(nainrow, irow);
812 numaAddNumber(namaxh, maxh);
813 wmaxrow = L_MAX(wmaxrow, w);
814 h += maxh + spacing;
815 irow = 0;
816 w = wt + 2 * spacing;
817 maxh = ht;
818 } else {
819 w = wtry;
820 maxh = L_MAX(maxh, ht);
821 }
822 }
823
824 /* Enter the parameters for the last row */
825 numaAddNumber(nainrow, irow);
826 numaAddNumber(namaxh, maxh);
827 wmaxrow = L_MAX(wmaxrow, w);
828 h += maxh + spacing;
829
830 if ((pixd = pixCreate(wmaxrow, h, outdepth)) == NULL) {
831 numaDestroy(&nainrow);
832 numaDestroy(&namaxh);
833 pixaDestroy(&pixan);
834 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
835 }
836
837 /* Reset the background color if necessary */
838 if ((background == 1 && outdepth == 1) ||
839 (background == 0 && outdepth != 1))
840 pixSetAll(pixd);
841
842 /* Blit the images to the dest, and save the boxa identifying
843 * the image regions that do not include the borders. */
844 nrows = numaGetCount(nainrow);
845 y = spacing;
846 boxa = boxaCreate(n);
847 for (i = 0, index = 0; i < nrows; i++) { /* over rows */
848 numaGetIValue(nainrow, i, &ninrow);
849 numaGetIValue(namaxh, i, &maxh);
850 x = spacing;
851 for (j = 0; j < ninrow; j++, index++) { /* over pix in row */
852 pix = pixaGetPix(pixan, index, L_CLONE);
853 if (index == 0) {
854 res = pixGetXRes(pix);
855 pixSetResolution(pixd, res, res);
856 }
857 pixGetDimensions(pix, &wt, &ht, NULL);
858 boxaAddBox(boxa, boxCreate(x + border, y + border,
859 wt - 2 * border, ht - 2 *border), L_INSERT);
860 pixRasterop(pixd, x, y, wt, ht, PIX_SRC, pix, 0, 0);
861 pixDestroy(&pix);
862 x += wt + spacing;
863 }
864 y += maxh + spacing;
865 }
866 if (boxaWriteMem(&data, &size, boxa) == 0)
867 pixSetText(pixd, (char *)data); /* data is ascii */
868 LEPT_FREE(data);
869 boxaDestroy(&boxa);
870
871 numaDestroy(&nainrow);
872 numaDestroy(&namaxh);
873 pixaDestroy(&pixan);
874 return pixd;
875}
876
877
911PIX *
913 l_int32 nx,
914 l_float32 scalefactor,
915 l_int32 spacing,
916 l_int32 border)
917{
918l_int32 i, j, index, n, x, y, nrows, wb, hb, w, h, maxd, maxh, bordval, res;
919size_t size;
920l_uint8 *data;
921BOX *box;
922BOXA *boxa;
923PIX *pix1, *pix2, *pix3, *pixd;
924PIXA *pixa1, *pixa2;
925
926 if (!pixas)
927 return (PIX *)ERROR_PTR("pixas not defined", __func__, NULL);
928 border = L_MAX(border, 0);
929 if (scalefactor <= 0.0) scalefactor = 1.0;
930 if ((n = pixaGetCount(pixas)) == 0)
931 return (PIX *)ERROR_PTR("no components", __func__, NULL);
932
933 /* Convert to same depth, if necessary */
934 pixa1 = pixaConvertToSameDepth(pixas);
935 pixaGetDepthInfo(pixa1, &maxd, NULL);
936
937 /* Scale and optionally add border */
938 pixa2 = pixaCreate(n);
939 bordval = (maxd == 1) ? 1 : 0;
940 for (i = 0; i < n; i++) {
941 if ((pix1 = pixaGetPix(pixa1, i, L_CLONE)) == NULL)
942 continue;
943 if (scalefactor != 1.0)
944 pix2 = pixScale(pix1, scalefactor, scalefactor);
945 else
946 pix2 = pixClone(pix1);
947 if (border)
948 pix3 = pixAddBorder(pix2, border, bordval);
949 else
950 pix3 = pixClone(pix2);
951 if (i == 0) res = pixGetXRes(pix3);
952 pixaAddPix(pixa2, pix3, L_INSERT);
953 pixDestroy(&pix1);
954 pixDestroy(&pix2);
955 }
956 pixaDestroy(&pixa1);
957 if (pixaGetCount(pixa2) != n) {
958 n = pixaGetCount(pixa2);
959 L_WARNING("only got %d components\n", __func__, n);
960 if (n == 0) {
961 pixaDestroy(&pixa2);
962 return (PIX *)ERROR_PTR("no components", __func__, NULL);
963 }
964 }
965
966 /* Compute layout parameters and save as a boxa */
967 boxa = boxaCreate(n);
968 nrows = (n + nx - 1) / nx;
969 y = spacing;
970 for (i = 0, index = 0; i < nrows; i++) {
971 x = spacing;
972 maxh = 0;
973 for (j = 0; j < nx && index < n; j++) {
974 pixaGetPixDimensions(pixa2, index, &wb, &hb, NULL);
975 box = boxCreate(x, y, wb, hb);
976 boxaAddBox(boxa, box, L_INSERT);
977 maxh = L_MAX(maxh, hb + spacing);
978 x += wb + spacing;
979 index++;
980 }
981 y += maxh;
982 }
983 pixaSetBoxa(pixa2, boxa, L_INSERT);
984
985 /* Render the output pix */
986 boxaGetExtent(boxa, &w, &h, NULL);
987 pixd = pixaDisplay(pixa2, w + spacing, h + spacing);
988 pixSetResolution(pixd, res, res);
989
990 /* Save the boxa in the text field of the output pix */
991 if (boxaWriteMem(&data, &size, boxa) == 0)
992 pixSetText(pixd, (char *)data); /* data is ascii */
993 LEPT_FREE(data);
994
995 pixaDestroy(&pixa2);
996 return pixd;
997}
998
999
1024PIX *
1026 l_int32 outdepth,
1027 l_int32 tilewidth,
1028 l_int32 ncols,
1029 l_int32 background,
1030 l_int32 spacing,
1031 l_int32 border)
1032{
1033l_int32 x, y, w, h, wd, hd, d, res;
1034l_int32 i, n, nrows, maxht, ninrow, irow, bordval;
1035l_int32 *rowht;
1036l_float32 scalefact;
1037PIX *pix, *pixn, *pix1, *pixb, *pixd;
1038PIXA *pixan;
1039
1040 if (!pixa)
1041 return (PIX *)ERROR_PTR("pixa not defined", __func__, NULL);
1042 if (outdepth != 1 && outdepth != 8 && outdepth != 32)
1043 return (PIX *)ERROR_PTR("outdepth not in {1, 8, 32}", __func__, NULL);
1044 if (ncols <= 0)
1045 return (PIX *)ERROR_PTR("ncols must be > 0", __func__, NULL);
1046 spacing = L_MAX(spacing, 0);
1047 if (border < 0 || border > tilewidth / 5)
1048 border = 0;
1049 if ((n = pixaGetCount(pixa)) == 0)
1050 return (PIX *)ERROR_PTR("no components", __func__, NULL);
1051
1052 /* Normalize scale and depth for each pix; optionally add border */
1053 pixan = pixaCreate(n);
1054 bordval = (outdepth == 1) ? 1 : 0;
1055 for (i = 0; i < n; i++) {
1056 if ((pix = pixaGetPix(pixa, i, L_CLONE)) == NULL)
1057 continue;
1058
1059 pixGetDimensions(pix, &w, &h, &d);
1060 scalefact = (l_float32)(tilewidth - 2 * border) / (l_float32)w;
1061 if (d == 1 && outdepth > 1 && scalefact < 1.0)
1062 pix1 = pixScaleToGray(pix, scalefact);
1063 else
1064 pix1 = pixScale(pix, scalefact, scalefact);
1065
1066 if (outdepth == 1)
1067 pixn = pixConvertTo1(pix1, 128);
1068 else if (outdepth == 8)
1069 pixn = pixConvertTo8(pix1, FALSE);
1070 else /* outdepth == 32 */
1071 pixn = pixConvertTo32(pix1);
1072 pixDestroy(&pix1);
1073
1074 if (border)
1075 pixb = pixAddBorder(pixn, border, bordval);
1076 else
1077 pixb = pixClone(pixn);
1078
1079 pixaAddPix(pixan, pixb, L_INSERT);
1080 pixDestroy(&pix);
1081 pixDestroy(&pixn);
1082 }
1083 if ((n = pixaGetCount(pixan)) == 0) { /* should not have changed! */
1084 pixaDestroy(&pixan);
1085 return (PIX *)ERROR_PTR("no components", __func__, NULL);
1086 }
1087
1088 /* Determine the size of each row and of pixd */
1089 wd = tilewidth * ncols + spacing * (ncols + 1);
1090 nrows = (n + ncols - 1) / ncols;
1091 if ((rowht = (l_int32 *)LEPT_CALLOC(nrows, sizeof(l_int32))) == NULL) {
1092 pixaDestroy(&pixan);
1093 return (PIX *)ERROR_PTR("rowht array not made", __func__, NULL);
1094 }
1095 maxht = 0;
1096 ninrow = 0;
1097 irow = 0;
1098 for (i = 0; i < n; i++) {
1099 pix = pixaGetPix(pixan, i, L_CLONE);
1100 ninrow++;
1101 pixGetDimensions(pix, &w, &h, NULL);
1102 maxht = L_MAX(h, maxht);
1103 if (ninrow == ncols) {
1104 rowht[irow] = maxht;
1105 maxht = ninrow = 0; /* reset */
1106 irow++;
1107 }
1108 pixDestroy(&pix);
1109 }
1110 if (ninrow > 0) { /* last fencepost */
1111 rowht[irow] = maxht;
1112 irow++; /* total number of rows */
1113 }
1114 nrows = irow;
1115 hd = spacing * (nrows + 1);
1116 for (i = 0; i < nrows; i++)
1117 hd += rowht[i];
1118
1119 pixd = pixCreate(wd, hd, outdepth);
1120 if ((background == 1 && outdepth == 1) ||
1121 (background == 0 && outdepth != 1))
1122 pixSetAll(pixd);
1123
1124 /* Now blit images to pixd */
1125 x = y = spacing;
1126 irow = 0;
1127 for (i = 0; i < n; i++) {
1128 pix = pixaGetPix(pixan, i, L_CLONE);
1129 if (i == 0) {
1130 res = pixGetXRes(pix);
1131 pixSetResolution(pixd, res, res);
1132 }
1133 pixGetDimensions(pix, &w, &h, NULL);
1134 if (i && ((i % ncols) == 0)) { /* start new row */
1135 x = spacing;
1136 y += spacing + rowht[irow];
1137 irow++;
1138 }
1139 pixRasterop(pixd, x, y, w, h, PIX_SRC, pix, 0, 0);
1140 x += tilewidth + spacing;
1141 pixDestroy(&pix);
1142 }
1143
1144 pixaDestroy(&pixan);
1145 LEPT_FREE(rowht);
1146 return pixd;
1147}
1148
1149
1177PIX *
1179 l_int32 maxwidth,
1180 l_float32 scalefactor,
1181 l_int32 spacing,
1182 l_int32 border,
1183 l_int32 fontsize,
1184 l_uint32 textcolor)
1185{
1186char buf[128];
1187char *textstr;
1188l_int32 i, n, maxw;
1189L_BMF *bmf;
1190PIX *pix1, *pix2, *pix3, *pix4, *pixd;
1191PIXA *pixad;
1192
1193 if (!pixa)
1194 return (PIX *)ERROR_PTR("pixa not defined", __func__, NULL);
1195 if ((n = pixaGetCount(pixa)) == 0)
1196 return (PIX *)ERROR_PTR("no components", __func__, NULL);
1197 if (maxwidth <= 0)
1198 return (PIX *)ERROR_PTR("invalid maxwidth", __func__, NULL);
1199 spacing = L_MAX(spacing, 0);
1200 border = L_MAX(border, 0);
1201 if (scalefactor <= 0.0) scalefactor = 1.0;
1202 if (fontsize < 4 || fontsize > 20 || (fontsize & 1)) {
1203 l_int32 fsize = L_MAX(L_MIN(fontsize, 20), 4);
1204 if (fsize & 1) fsize--;
1205 L_WARNING("changed fontsize from %d to %d\n", __func__,
1206 fontsize, fsize);
1207 fontsize = fsize;
1208 }
1209
1210 /* Be sure the width can accommodate a single column of images */
1211 pixaSizeRange(pixa, NULL, NULL, &maxw, NULL);
1212 maxwidth = L_MAX(maxwidth, scalefactor * (maxw + 2 * spacing + 2 * border));
1213
1214 bmf = bmfCreate(NULL, fontsize);
1215 pixad = pixaCreate(n);
1216 for (i = 0; i < n; i++) {
1217 pix1 = pixaGetPix(pixa, i, L_CLONE);
1218 pix2 = pixConvertTo32(pix1);
1219 pix3 = pixAddBorderGeneral(pix2, spacing / 2, spacing / 2, spacing / 2,
1220 spacing / 2, 0xffffff00);
1221 textstr = pixGetText(pix1);
1222 if (textstr && strlen(textstr) > 0) {
1223 snprintf(buf, sizeof(buf), "%s", textstr);
1224 pix4 = pixAddSingleTextblock(pix3, bmf, buf, textcolor,
1225 L_ADD_BELOW, NULL);
1226 } else {
1227 pix4 = pixClone(pix3);
1228 }
1229 pixaAddPix(pixad, pix4, L_INSERT);
1230 pixDestroy(&pix1);
1231 pixDestroy(&pix2);
1232 pixDestroy(&pix3);
1233 }
1234 bmfDestroy(&bmf);
1235
1236 pixd = pixaDisplayTiledInRows(pixad, 32, maxwidth, scalefactor,
1237 0, spacing, border);
1238 pixaDestroy(&pixad);
1239 return pixd;
1240}
1241
1242
1271PIX *
1273 NUMA *na,
1274 l_int32 width,
1275 l_int32 spacing,
1276 l_int32 border,
1277 l_int32 fontsize,
1278 l_uint32 textcolor)
1279{
1280char buf[128];
1281char *textstr;
1282l_int32 i, n, x, y, w, h, yval, index;
1283l_float32 maxindex;
1284L_BMF *bmf;
1285BOX *box;
1286NUMA *nay; /* top of the next pix to add in that column */
1287PIX *pix1, *pix2, *pix3, *pix4, *pix5, *pixd;
1288PIXA *pixad;
1289
1290 if (!pixa)
1291 return (PIX *)ERROR_PTR("pixa not defined", __func__, NULL);
1292 if (!na)
1293 return (PIX *)ERROR_PTR("na not defined", __func__, NULL);
1294 if ((n = pixaGetCount(pixa)) == 0)
1295 return (PIX *)ERROR_PTR("no pixa components", __func__, NULL);
1296 if (n != numaGetCount(na))
1297 return (PIX *)ERROR_PTR("pixa and na counts differ", __func__, NULL);
1298 if (width <= 0)
1299 return (PIX *)ERROR_PTR("invalid width", __func__, NULL);
1300 if (width < 20)
1301 L_WARNING("very small width: %d\n", __func__, width);
1302 spacing = L_MAX(spacing, 0);
1303 border = L_MAX(border, 0);
1304 if (fontsize < 4 || fontsize > 20 || (fontsize & 1)) {
1305 l_int32 fsize = L_MAX(L_MIN(fontsize, 20), 4);
1306 if (fsize & 1) fsize--;
1307 L_WARNING("changed fontsize from %d to %d\n", __func__,
1308 fontsize, fsize);
1309 fontsize = fsize;
1310 }
1311
1312 /* The pix will be rendered in the order they occupy in pixa. */
1313 bmf = bmfCreate(NULL, fontsize);
1314 pixad = pixaCreate(n);
1315 numaGetMax(na, &maxindex, NULL);
1316 nay = numaMakeConstant(spacing, lept_roundftoi(maxindex) + 1);
1317 for (i = 0; i < n; i++) {
1318 numaGetIValue(na, i, &index);
1319 numaGetIValue(nay, index, &yval);
1320 pix1 = pixaGetPix(pixa, i, L_CLONE);
1321 pix2 = pixConvertTo32(pix1);
1322 pix3 = pixScaleToSize(pix2, width, 0);
1323 pix4 = pixAddBorderGeneral(pix3, border, border, border, border, 0);
1324 textstr = pixGetText(pix1);
1325 if (textstr && strlen(textstr) > 0) {
1326 snprintf(buf, sizeof(buf), "%s", textstr);
1327 pix5 = pixAddTextlines(pix4, bmf, textstr, textcolor, L_ADD_BELOW);
1328 } else {
1329 pix5 = pixClone(pix4);
1330 }
1331 pixaAddPix(pixad, pix5, L_INSERT);
1332 x = spacing + border + index * (2 * border + width + spacing);
1333 y = yval;
1334 pixGetDimensions(pix5, &w, &h, NULL);
1335 yval += h + spacing;
1336 numaSetValue(nay, index, yval);
1337 box = boxCreate(x, y, w, h);
1338 pixaAddBox(pixad, box, L_INSERT);
1339 pixDestroy(&pix1);
1340 pixDestroy(&pix2);
1341 pixDestroy(&pix3);
1342 pixDestroy(&pix4);
1343 }
1344 numaDestroy(&nay);
1345 bmfDestroy(&bmf);
1346
1347 pixd = pixaDisplay(pixad, 0, 0);
1348 pixaDestroy(&pixad);
1349 return pixd;
1350}
1351
1352
1353/*---------------------------------------------------------------------*
1354 * Pixa pair display *
1355 *---------------------------------------------------------------------*/
1393PIX *
1395 PIXA *pixas2,
1396 l_int32 nx,
1397 l_float32 scalefactor,
1398 l_int32 spacing1,
1399 l_int32 spacing2,
1400 l_int32 border1,
1401 l_int32 border2,
1402 l_int32 fontsize,
1403 l_int32 startindex,
1404 SARRAY *sa)
1405{
1406l_int32 i, n, w, maxd, maxd1, maxd2, text;
1407NUMA *na;
1408PIX *pixs1, *pixs2, *pix1, *pix2, *pix3, *pix4;
1409PIX *pix5, *pix6, *pix7, *pix8, *pix9;
1410PIXA *pixa1, *pixa2;
1411SARRAY *sa1;
1412
1413 if (!pixas1)
1414 return (PIX *)ERROR_PTR("pixas1 not defined", __func__, NULL);
1415 if (!pixas2)
1416 return (PIX *)ERROR_PTR("pixas2 not defined", __func__, NULL);
1417 spacing1 = L_MAX(spacing1, 0);
1418 spacing2 = L_MAX(spacing2, 0);
1419 border1 = L_MAX(border1, 0);
1420 border2 = L_MAX(border2, 0);
1421 if (scalefactor <= 0.0) scalefactor = 1.0;
1422 if ((n = pixaGetCount(pixas1)) == 0)
1423 return (PIX *)ERROR_PTR("no components", __func__, NULL);
1424 if (n != pixaGetCount(pixas2))
1425 return (PIX *)ERROR_PTR("pixa sizes differ", __func__, NULL);
1426 text = (fontsize <= 0) ? 0 : 1;
1427 if (text && (fontsize < 4 || fontsize > 20 || (fontsize & 1))) {
1428 l_int32 fsize = L_MAX(L_MIN(fontsize, 20), 4);
1429 if (fsize & 1) fsize--;
1430 L_WARNING("changed fontsize from %d to %d\n", __func__,
1431 fontsize, fsize);
1432 fontsize = fsize;
1433 }
1434
1435 /* Convert to same depth, if necessary */
1436 if (text) { /* adding color text; convert to 32 bpp */
1437 maxd = 32;
1438 } else {
1439 pixaGetRenderingDepth(pixas1, &maxd1);
1440 pixaGetRenderingDepth(pixas2, &maxd2);
1441 maxd = L_MAX(maxd1, maxd2);
1442 }
1443
1444 /* Optionally scale and add borders to each pair;
1445 then combine the pairs and add outer border. */
1446 pixa1 = pixaCreate(n);
1447 for (i = 0; i < n; i++) {
1448 pixs1 = pixaGetPix(pixas1, i, L_CLONE);
1449 pixs2 = pixaGetPix(pixas2, i, L_CLONE);
1450 if (!pixs1 || !pixs2) continue;
1451 if (maxd == 1) {
1452 pix1 = pixClone(pixs1);
1453 pix2 = pixClone(pixs2);
1454 } else if (maxd == 8) {
1455 pix1 = pixConvertTo8(pixs1, 0);
1456 pix2 = pixConvertTo8(pixs2, 0);
1457 } else { /* maxd == 32 */
1458 pix1 = pixConvertTo32(pixs1);
1459 pix2 = pixConvertTo32(pixs2);
1460 }
1461 pixDestroy(&pixs1);
1462 pixDestroy(&pixs2);
1463 if (scalefactor != 1.0) {
1464 pix3 = pixScale(pix1, scalefactor, scalefactor);
1465 pix4 = pixScale(pix2, scalefactor, scalefactor);
1466 } else {
1467 pix3 = pixClone(pix1);
1468 pix4 = pixClone(pix2);
1469 }
1470 pixDestroy(&pix1);
1471 pixDestroy(&pix2);
1472 if (border1) {
1473 pix5 = pixAddBlackOrWhiteBorder(pix3, border1, border1, border1,
1474 border1, L_GET_BLACK_VAL);
1475 pix6 = pixAddBlackOrWhiteBorder(pix4, border1, border1, border1,
1476 border1, L_GET_BLACK_VAL);
1477 } else {
1478 pix5 = pixClone(pix3);
1479 pix6 = pixClone(pix4);
1480 }
1481 pixDestroy(&pix3);
1482 pixDestroy(&pix4);
1483 if (spacing1) { /* white border */
1484 pix7 = pixAddBlackOrWhiteBorder(pix5, spacing1 / 2, spacing1 / 2,
1485 spacing1 / 2, spacing1 / 2, L_GET_WHITE_VAL);
1486 pix8 = pixAddBlackOrWhiteBorder(pix6, spacing1 / 2, spacing1 / 2,
1487 spacing1 / 2, spacing1 / 2, L_GET_WHITE_VAL);
1488 } else {
1489 pix7 = pixClone(pix5);
1490 pix8 = pixClone(pix6);
1491 }
1492 pixDestroy(&pix5);
1493 pixDestroy(&pix6);
1494 pixa2 = pixaCreate(2);
1495 pixaAddPix(pixa2, pix7, L_INSERT);
1496 pixaAddPix(pixa2, pix8, L_INSERT);
1497 pix9 = pixaDisplayTiledInColumns(pixa2, 2, 1.0, 0, 0);
1498 pixaAddPix(pixa1, pix9, L_INSERT);
1499 pixaDestroy(&pixa2);
1500 }
1501
1502 if (!text) {
1503 pix1 = pixaDisplayTiledInColumns(pixa1, nx, 1.0, spacing2, border2);
1504 } else {
1505 if (sa) {
1506 pixaSetText(pixa1, NULL, sa);
1507 } else {
1508 n = pixaGetCount(pixa1);
1509 na = numaMakeSequence(startindex, 1, n);
1510 sa1 = numaConvertToSarray(na, 4, 0, 0, L_INTEGER_VALUE);
1511 pixaSetText(pixa1, NULL, sa1);
1512 numaDestroy(&na);
1513 sarrayDestroy(&sa1);
1514 }
1515 pixaSizeRange(pixa1, NULL, NULL, &w, NULL);
1516 pix1 = pixaDisplayTiledWithText(pixa1, w * (nx + 1), 1.0, spacing2,
1517 border2, fontsize, 0xff000000);
1518 }
1519 pixaDestroy(&pixa1);
1520 return pix1;
1521}
1522
1523
1524/*---------------------------------------------------------------------*
1525 * Pixaa Display *
1526 *---------------------------------------------------------------------*/
1542PIX *
1544 l_int32 w,
1545 l_int32 h)
1546{
1547l_int32 i, j, n, nbox, na, d, wmax, hmax, x, y, xb, yb, wb, hb;
1548BOXA *boxa1; /* top-level boxa */
1549BOXA *boxa;
1550PIX *pix1, *pixd;
1551PIXA *pixa;
1552
1553 if (!paa)
1554 return (PIX *)ERROR_PTR("paa not defined", __func__, NULL);
1555
1556 n = pixaaGetCount(paa, NULL);
1557 if (n == 0)
1558 return (PIX *)ERROR_PTR("no components", __func__, NULL);
1559
1560 /* If w and h not input, determine the minimum size required
1561 * to contain the origin and all c.c. */
1562 boxa1 = pixaaGetBoxa(paa, L_CLONE);
1563 nbox = boxaGetCount(boxa1);
1564 if (w == 0 || h == 0) {
1565 if (nbox == n) {
1566 boxaGetExtent(boxa1, &w, &h, NULL);
1567 } else { /* have to use the lower-level boxa for each pixa */
1568 wmax = hmax = 0;
1569 for (i = 0; i < n; i++) {
1570 pixa = pixaaGetPixa(paa, i, L_CLONE);
1571 boxa = pixaGetBoxa(pixa, L_CLONE);
1572 boxaGetExtent(boxa, &w, &h, NULL);
1573 wmax = L_MAX(wmax, w);
1574 hmax = L_MAX(hmax, h);
1575 pixaDestroy(&pixa);
1576 boxaDestroy(&boxa);
1577 }
1578 w = wmax;
1579 h = hmax;
1580 }
1581 }
1582
1583 /* Get depth from first pix */
1584 pixa = pixaaGetPixa(paa, 0, L_CLONE);
1585 pix1 = pixaGetPix(pixa, 0, L_CLONE);
1586 d = pixGetDepth(pix1);
1587 pixaDestroy(&pixa);
1588 pixDestroy(&pix1);
1589
1590 if ((pixd = pixCreate(w, h, d)) == NULL) {
1591 boxaDestroy(&boxa1);
1592 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
1593 }
1594
1595 x = y = 0;
1596 for (i = 0; i < n; i++) {
1597 pixa = pixaaGetPixa(paa, i, L_CLONE);
1598 if (nbox == n)
1599 boxaGetBoxGeometry(boxa1, i, &x, &y, NULL, NULL);
1600 na = pixaGetCount(pixa);
1601 for (j = 0; j < na; j++) {
1602 pixaGetBoxGeometry(pixa, j, &xb, &yb, &wb, &hb);
1603 pix1 = pixaGetPix(pixa, j, L_CLONE);
1604 pixRasterop(pixd, x + xb, y + yb, wb, hb, PIX_PAINT, pix1, 0, 0);
1605 pixDestroy(&pix1);
1606 }
1607 pixaDestroy(&pixa);
1608 }
1609 boxaDestroy(&boxa1);
1610
1611 return pixd;
1612}
1613
1614
1643PIX *
1645 l_int32 maxnx,
1646 l_float32 scalefactor,
1647 l_int32 hspacing,
1648 l_int32 vspacing,
1649 l_int32 border)
1650{
1651l_int32 i, n, vs;
1652PIX *pix1, *pix2;
1653PIXA *pixa1, *pixa2;
1654
1655 if (!paa)
1656 return (PIX *)ERROR_PTR("paa not defined", __func__, NULL);
1657 if (scalefactor <= 0.0) scalefactor = 1.0;
1658 if (hspacing < 0) hspacing = 0;
1659 if (vspacing < 0) vspacing = 0;
1660 if (border < 0) border = 0;
1661
1662 if ((n = pixaaGetCount(paa, NULL)) == 0)
1663 return (PIX *)ERROR_PTR("no components", __func__, NULL);
1664
1665 /* Vertical spacing of amount %hspacing is also added at this step */
1666 pixa2 = pixaCreate(0);
1667 for (i = 0; i < n; i++) {
1668 pixa1 = pixaaGetPixa(paa, i, L_CLONE);
1669 pix1 = pixaDisplayTiledInColumns(pixa1, maxnx, scalefactor,
1670 hspacing, border);
1671 pixaAddPix(pixa2, pix1, L_INSERT);
1672 pixaDestroy(&pixa1);
1673 }
1674
1675 vs = vspacing - 2 * hspacing;
1676 pix2 = pixaDisplayTiledInColumns(pixa2, 1, scalefactor, vs, 0);
1677 pixaDestroy(&pixa2);
1678 return pix2;
1679}
1680
1681
1704PIXA *
1706 l_int32 outdepth,
1707 l_int32 tilewidth,
1708 l_int32 ncols,
1709 l_int32 background,
1710 l_int32 spacing,
1711 l_int32 border)
1712{
1713l_int32 i, n;
1714PIX *pix;
1715PIXA *pixa, *pixad;
1716
1717 if (!paa)
1718 return (PIXA *)ERROR_PTR("paa not defined", __func__, NULL);
1719 if (outdepth != 1 && outdepth != 8 && outdepth != 32)
1720 return (PIXA *)ERROR_PTR("outdepth not in {1, 8, 32}", __func__, NULL);
1721 if (ncols <= 0)
1722 return (PIXA *)ERROR_PTR("ncols must be > 0", __func__, NULL);
1723 if (border < 0 || border > tilewidth / 5)
1724 border = 0;
1725
1726 if ((n = pixaaGetCount(paa, NULL)) == 0)
1727 return (PIXA *)ERROR_PTR("no components", __func__, NULL);
1728
1729 pixad = pixaCreate(n);
1730 for (i = 0; i < n; i++) {
1731 pixa = pixaaGetPixa(paa, i, L_CLONE);
1732 pix = pixaDisplayTiledAndScaled(pixa, outdepth, tilewidth, ncols,
1733 background, spacing, border);
1734 pixaAddPix(pixad, pix, L_INSERT);
1735 pixaDestroy(&pixa);
1736 }
1737
1738 return pixad;
1739}
1740
1741
1742/*---------------------------------------------------------------------*
1743 * Conversion of all pix to specified type (e.g., depth) *
1744 *---------------------------------------------------------------------*/
1752PIXA *
1754 l_int32 thresh)
1755{
1756l_int32 i, n;
1757BOXA *boxa;
1758PIX *pix1, *pix2;
1759PIXA *pixad;
1760
1761 if (!pixas)
1762 return (PIXA *)ERROR_PTR("pixas not defined", __func__, NULL);
1763
1764 n = pixaGetCount(pixas);
1765 pixad = pixaCreate(n);
1766 for (i = 0; i < n; i++) {
1767 pix1 = pixaGetPix(pixas, i, L_CLONE);
1768 pix2 = pixConvertTo1(pix1, thresh);
1769 pixaAddPix(pixad, pix2, L_INSERT);
1770 pixDestroy(&pix1);
1771 }
1772
1773 boxa = pixaGetBoxa(pixas, L_COPY);
1774 pixaSetBoxa(pixad, boxa, L_INSERT);
1775 return pixad;
1776}
1777
1778
1791PIXA *
1793 l_int32 cmapflag)
1794{
1795l_int32 i, n;
1796BOXA *boxa;
1797PIX *pix1, *pix2;
1798PIXA *pixad;
1799
1800 if (!pixas)
1801 return (PIXA *)ERROR_PTR("pixas not defined", __func__, NULL);
1802
1803 n = pixaGetCount(pixas);
1804 pixad = pixaCreate(n);
1805 for (i = 0; i < n; i++) {
1806 pix1 = pixaGetPix(pixas, i, L_CLONE);
1807 pix2 = pixConvertTo8(pix1, cmapflag);
1808 pixaAddPix(pixad, pix2, L_INSERT);
1809 pixDestroy(&pix1);
1810 }
1811
1812 boxa = pixaGetBoxa(pixas, L_COPY);
1813 pixaSetBoxa(pixad, boxa, L_INSERT);
1814 return pixad;
1815}
1816
1817
1830PIXA *
1832 l_int32 dither)
1833{
1834l_int32 i, n;
1835BOXA *boxa;
1836PIX *pix1, *pix2;
1837PIXA *pixad;
1838
1839 if (!pixas)
1840 return (PIXA *)ERROR_PTR("pixas not defined", __func__, NULL);
1841
1842 n = pixaGetCount(pixas);
1843 pixad = pixaCreate(n);
1844 for (i = 0; i < n; i++) {
1845 pix1 = pixaGetPix(pixas, i, L_CLONE);
1846 pix2 = pixConvertTo8Colormap(pix1, dither);
1847 pixaAddPix(pixad, pix2, L_INSERT);
1848 pixDestroy(&pix1);
1849 }
1850
1851 boxa = pixaGetBoxa(pixas, L_COPY);
1852 pixaSetBoxa(pixad, boxa, L_INSERT);
1853 return pixad;
1854}
1855
1856
1870PIXA *
1872{
1873l_int32 i, n;
1874BOXA *boxa;
1875PIX *pix1, *pix2;
1876PIXA *pixad;
1877
1878 if (!pixas)
1879 return (PIXA *)ERROR_PTR("pixas not defined", __func__, NULL);
1880
1881 n = pixaGetCount(pixas);
1882 pixad = pixaCreate(n);
1883 for (i = 0; i < n; i++) {
1884 pix1 = pixaGetPix(pixas, i, L_CLONE);
1885 pix2 = pixConvertTo32(pix1);
1886 pixaAddPix(pixad, pix2, L_INSERT);
1887 pixDestroy(&pix1);
1888 }
1889
1890 boxa = pixaGetBoxa(pixas, L_COPY);
1891 pixaSetBoxa(pixad, boxa, L_INSERT);
1892 return pixad;
1893}
1894
1895
1896/*---------------------------------------------------------------------*
1897 * Pixa constrained selection *
1898 *---------------------------------------------------------------------*/
1921PIXA *
1923 l_int32 first,
1924 l_int32 last,
1925 l_int32 nmax,
1926 l_int32 use_pairs,
1927 l_int32 copyflag)
1928{
1929l_int32 i, n, nselect, index;
1930NUMA *na;
1931PIX *pix1;
1932PIXA *pixad;
1933
1934 if (!pixas)
1935 return (PIXA *)ERROR_PTR("pixas not defined", __func__, NULL);
1936 n = pixaGetCount(pixas);
1937 first = L_MAX(0, first);
1938 last = (last < 0) ? n - 1 : L_MIN(n - 1, last);
1939 if (last < first)
1940 return (PIXA *)ERROR_PTR("last < first!", __func__, NULL);
1941 if (nmax < 1)
1942 return (PIXA *)ERROR_PTR("nmax < 1!", __func__, NULL);
1943
1944 na = genConstrainedNumaInRange(first, last, nmax, use_pairs);
1945 nselect = numaGetCount(na);
1946 pixad = pixaCreate(nselect);
1947 for (i = 0; i < nselect; i++) {
1948 numaGetIValue(na, i, &index);
1949 pix1 = pixaGetPix(pixas, index, copyflag);
1950 pixaAddPix(pixad, pix1, L_INSERT);
1951 }
1952 numaDestroy(&na);
1953 return pixad;
1954}
1955
1956
1987l_ok
1989 l_int32 first,
1990 l_int32 last,
1991 l_int32 res,
1992 l_float32 scalefactor,
1993 l_int32 type,
1994 l_int32 quality,
1995 l_uint32 color,
1996 l_int32 fontsize,
1997 const char *fileout)
1998{
1999l_int32 n;
2000L_BMF *bmf;
2001NUMA *na;
2002PIXA *pixa1, *pixa2;
2003
2004 if (!pixas)
2005 return ERROR_INT("pixas not defined", __func__, 1);
2006 if (type < 0 || type > L_FLATE_ENCODE) {
2007 L_WARNING("invalid compression type; using default\n", __func__);
2008 type = 0;
2009 }
2010 if (!fileout)
2011 return ERROR_INT("fileout not defined", __func__, 1);
2012
2013 /* Select from given range */
2014 n = pixaGetCount(pixas);
2015 first = L_MAX(0, first);
2016 last = (last < 0) ? n - 1 : L_MIN(n - 1, last);
2017 if (first > last) {
2018 L_ERROR("first = %d > last = %d\n", __func__, first, last);
2019 return 1;
2020 }
2021 pixa1 = pixaSelectRange(pixas, first, last, L_CLONE);
2022
2023 /* Optionally add index numbers */
2024 bmf = (fontsize <= 0) ? NULL : bmfCreate(NULL, fontsize);
2025 if (bmf) {
2026 na = numaMakeSequence(first, 1.0, last - first + 1);
2027 pixa2 = pixaAddTextNumber(pixa1, bmf, na, color, L_ADD_LEFT);
2028 numaDestroy(&na);
2029 } else {
2030 pixa2 = pixaCopy(pixa1, L_CLONE);
2031 }
2032 pixaDestroy(&pixa1);
2033 bmfDestroy(&bmf);
2034
2035 pixaConvertToPdf(pixa2, res, scalefactor, type, quality, NULL, fileout);
2036 pixaDestroy(&pixa2);
2037 return 0;
2038}
2039
2040
2041/*---------------------------------------------------------------------*
2042 * Generate pixa from tiled images *
2043 *---------------------------------------------------------------------*/
2064PIXA *
2066 l_int32 w,
2067 l_int32 h,
2068 l_int32 nsamp)
2069{
2070char buf[8];
2071l_int32 ntiles, i;
2072PIX *pix1;
2073PIXA *pixad, *pixa1;
2074
2075 if (!pixas)
2076 return (PIXA *)ERROR_PTR("pixas not defined", __func__, NULL);
2077 if (nsamp > 1000)
2078 return (PIXA *)ERROR_PTR("nsamp too large; typ. 100", __func__, NULL);
2079
2080 if (w <= 0) w = 20;
2081 if (h <= 0) h = 30;
2082 if (nsamp <= 0) nsamp = 100;
2083
2084 /* pixas has 10 pix of mosaic'd digits. Each of these images
2085 * must be extracted into a pixa of templates, where each template
2086 * is labeled with the digit value, and then selectively
2087 * concatenated into an output pixa. */
2088 pixad = pixaCreate(10 * nsamp);
2089 for (i = 0; i < 10; i++) {
2090 pix1 = pixaGetPix(pixas, i, L_CLONE);
2091 pixGetTileCount(pix1, &ntiles);
2092 if (nsamp > ntiles)
2093 L_WARNING("requested %d; only %d tiles\n", __func__, nsamp, ntiles);
2094 pixa1 = pixaMakeFromTiledPix(pix1, w, h, 0, nsamp, NULL);
2095 snprintf(buf, sizeof(buf), "%d", i);
2096 pixaSetText(pixa1, buf, NULL);
2097 pixaJoin(pixad, pixa1, 0, -1);
2098 pixaDestroy(&pixa1);
2099 pixDestroy(&pix1);
2100 }
2101 return pixad;
2102}
2103
2104
2142PIXA *
2144 l_int32 w,
2145 l_int32 h,
2146 l_int32 start,
2147 l_int32 num,
2148 BOXA *boxa)
2149{
2150l_int32 i, j, k, ws, hs, d, nx, ny, n, n_isvalid, ntiles, nmax;
2151PIX *pix1;
2152PIXA *pixa1;
2153PIXCMAP *cmap;
2154
2155 if (!pixs)
2156 return (PIXA *)ERROR_PTR("pixs not defined", __func__, NULL);
2157 if (!boxa && (w <= 0 || h <= 0))
2158 return (PIXA *)ERROR_PTR("w and h must be > 0", __func__, NULL);
2159
2160 if (boxa) /* general case */
2161 return pixaCreateFromBoxa(pixs, boxa, start, num, NULL);
2162
2163 /* All tiles are the same size */
2164 pixGetDimensions(pixs, &ws, &hs, &d);
2165 nx = ws / w;
2166 ny = hs / h;
2167 if (nx < 1 || ny < 1)
2168 return (PIXA *)ERROR_PTR("invalid dimensions", __func__, NULL);
2169 if (nx * w != ws || ny * h != hs)
2170 L_WARNING("some tiles will be clipped\n", __func__);
2171
2172 /* Check the text field of the pix. It may tell how many
2173 * tiles hold valid data. If a valid value is not found,
2174 * assume all (nx * ny) tiles are valid. */
2175 pixGetTileCount(pixs, &n);
2176 n_isvalid = (n <= nx * ny && n > nx * (ny - 1)) ? TRUE : FALSE;
2177 ntiles = (n_isvalid) ? n : nx * ny;
2178 nmax = ntiles - start; /* max available from start */
2179 num = (num == 0) ? nmax : L_MIN(num, nmax);
2180
2181 /* Extract the tiles */
2182 if ((pixa1 = pixaCreate(num)) == NULL) {
2183 return (PIXA *)ERROR_PTR("pixa1 not made", __func__, NULL);
2184 }
2185 cmap = pixGetColormap(pixs);
2186 for (i = 0, k = 0; i < ny; i++) {
2187 for (j = 0; j < nx; j++, k++) {
2188 if (k < start) continue;
2189 if (k >= start + num) break;
2190 pix1 = pixCreate(w, h, d);
2191 if (cmap) pixSetColormap(pix1, pixcmapCopy(cmap));
2192 pixRasterop(pix1, 0, 0, w, h, PIX_SRC, pixs, j * w, i * h);
2193 pixaAddPix(pixa1, pix1, L_INSERT);
2194 }
2195 }
2196 return pixa1;
2197}
2198
2199
2215l_ok
2217 l_int32 *pn)
2218{
2219char *text;
2220l_int32 n;
2221
2222 if (!pn)
2223 return ERROR_INT("&n not defined", __func__, 1);
2224 *pn = 0;
2225 if (!pix)
2226 return ERROR_INT("pix not defined", __func__, 1);
2227
2228 text = pixGetText(pix);
2229 if (text && strlen(text) > 4) {
2230 if (sscanf(text, "n = %d", &n) == 1)
2231 *pn = n;
2232 }
2233 return 0;
2234}
2235
2236
2237/*---------------------------------------------------------------------*
2238 * Pixa display into multiple tiles *
2239 *---------------------------------------------------------------------*/
2261PIXA *
2263 l_int32 nx,
2264 l_int32 ny,
2265 l_int32 maxw,
2266 l_int32 maxh,
2267 l_float32 scalefactor,
2268 l_int32 spacing,
2269 l_int32 border)
2270{
2271l_int32 n, i, j, ntile, nout, index;
2272PIX *pix1, *pix2;
2273PIXA *pixa1, *pixa2, *pixad;
2274
2275 if (!pixas)
2276 return (PIXA *)ERROR_PTR("pixas not defined", __func__, NULL);
2277 if (nx < 1 || ny < 1 || nx > 50 || ny > 50)
2278 return (PIXA *)ERROR_PTR("invalid tiling factor(s)", __func__, NULL);
2279 if ((n = pixaGetCount(pixas)) == 0)
2280 return (PIXA *)ERROR_PTR("pixas is empty", __func__, NULL);
2281
2282 /* Filter out large ones if requested */
2283 if (maxw == 0 && maxh == 0) {
2284 pixa1 = pixaCopy(pixas, L_CLONE);
2285 } else {
2286 maxw = (maxw == 0) ? 1000000 : maxw;
2287 maxh = (maxh == 0) ? 1000000 : maxh;
2288 pixa1 = pixaSelectBySize(pixas, maxw, maxh, L_SELECT_IF_BOTH,
2289 L_SELECT_IF_LTE, NULL);
2290 n = pixaGetCount(pixa1);
2291 }
2292
2293 ntile = nx * ny;
2294 nout = L_MAX(1, (n + ntile - 1) / ntile);
2295 pixad = pixaCreate(nout);
2296 for (i = 0, index = 0; i < nout; i++) { /* over tiles */
2297 pixa2 = pixaCreate(ntile);
2298 for (j = 0; j < ntile && index < n; j++, index++) {
2299 pix1 = pixaGetPix(pixa1, index, L_COPY);
2300 pixaAddPix(pixa2, pix1, L_INSERT);
2301 }
2302 pix2 = pixaDisplayTiledInColumns(pixa2, nx, scalefactor, spacing,
2303 border);
2304 pixaAddPix(pixad, pix2, L_INSERT);
2305 pixaDestroy(&pixa2);
2306 }
2307 pixaDestroy(&pixa1);
2308
2309 return pixad;
2310}
2311
2312
2313/*---------------------------------------------------------------------*
2314 * Split pixa into files *
2315 *---------------------------------------------------------------------*/
2338l_ok
2340 l_int32 nsplit,
2341 l_float32 scale,
2342 l_int32 outwidth,
2343 l_int32 write_pixa,
2344 l_int32 write_pix,
2345 l_int32 write_pdf)
2346{
2347char buf[64];
2348l_int32 i, j, index, n, nt;
2349PIX *pix1, *pix2;
2350PIXA *pixa1;
2351
2352 if (!pixas)
2353 return ERROR_INT("pixas not defined", __func__, 1);
2354 if (nsplit <= 1)
2355 return ERROR_INT("nsplit must be >= 2", __func__, 1);
2356 if ((nt = pixaGetCount(pixas)) == 0)
2357 return ERROR_INT("pixas is empty", __func__, 1);
2358 if (!write_pixa && !write_pix && !write_pdf)
2359 return ERROR_INT("no output is requested", __func__, 1);
2360
2361 lept_mkdir("lept/split");
2362 n = (nt + nsplit - 1) / nsplit;
2363 lept_stderr("nt = %d, n = %d, nsplit = %d\n", nt, n, nsplit);
2364 for (i = 0, index = 0; i < nsplit; i++) {
2365 pixa1 = pixaCreate(n);
2366 for (j = 0; j < n && index < nt; j++, index++) {
2367 pix1 = pixaGetPix(pixas, index, L_CLONE);
2368 pix2 = pixScale(pix1, scale, scale);
2369 pixaAddPix(pixa1, pix2, L_INSERT);
2370 pixDestroy(&pix1);
2371 }
2372 if (write_pixa) {
2373 snprintf(buf, sizeof(buf), "/tmp/lept/split/split%d.pa", i + 1);
2374 pixaWriteDebug(buf, pixa1);
2375 }
2376 if (write_pix) {
2377 snprintf(buf, sizeof(buf), "/tmp/lept/split/split%d.tif", i + 1);
2378 pix1 = pixaDisplayTiledInRows(pixa1, 1, outwidth, 1.0, 0, 20, 2);
2379 pixWriteDebug(buf, pix1, IFF_TIFF_G4);
2380 pixDestroy(&pix1);
2381 }
2382 if (write_pdf) {
2383 snprintf(buf, sizeof(buf), "/tmp/lept/split/split%d.pdf", i + 1);
2384 pixaConvertToPdf(pixa1, 0, 1.0, L_G4_ENCODE, 0, buf, buf);
2385 }
2386 pixaDestroy(&pixa1);
2387 }
2388
2389 return 0;
2390}
2391
2392
2393/*---------------------------------------------------------------------*
2394 * Tile N-Up *
2395 *---------------------------------------------------------------------*/
2425l_ok
2426convertToNUpFiles(const char *dir,
2427 const char *substr,
2428 l_int32 nx,
2429 l_int32 ny,
2430 l_int32 tw,
2431 l_int32 spacing,
2432 l_int32 border,
2433 l_int32 fontsize,
2434 const char *outdir)
2435{
2436l_int32 d, format;
2437char rootpath[256];
2438PIXA *pixa;
2439
2440 if (!dir)
2441 return ERROR_INT("dir not defined", __func__, 1);
2442 if (nx < 1 || ny < 1 || nx > 50 || ny > 50)
2443 return ERROR_INT("invalid tiling N-factor", __func__, 1);
2444 if (fontsize < 0 || fontsize > 20 || fontsize & 1 || fontsize == 2)
2445 return ERROR_INT("invalid fontsize", __func__, 1);
2446 if (!outdir)
2447 return ERROR_INT("outdir not defined", __func__, 1);
2448
2449 pixa = convertToNUpPixa(dir, substr, nx, ny, tw, spacing, border,
2450 fontsize);
2451 if (!pixa)
2452 return ERROR_INT("pixa not made", __func__, 1);
2453
2454 lept_rmdir(outdir);
2455 lept_mkdir(outdir);
2456 pixaGetRenderingDepth(pixa, &d);
2457 format = (d == 1) ? IFF_TIFF_G4 : IFF_JFIF_JPEG;
2458 makeTempDirname(rootpath, 256, outdir);
2459 modifyTrailingSlash(rootpath, 256, L_ADD_TRAIL_SLASH);
2460 pixaWriteFiles(rootpath, pixa, format);
2461 pixaDestroy(&pixa);
2462 return 0;
2463}
2464
2465
2485PIXA *
2486convertToNUpPixa(const char *dir,
2487 const char *substr,
2488 l_int32 nx,
2489 l_int32 ny,
2490 l_int32 tw,
2491 l_int32 spacing,
2492 l_int32 border,
2493 l_int32 fontsize)
2494{
2495l_int32 i, n;
2496char *fname, *tail;
2497PIXA *pixa1, *pixa2;
2498SARRAY *sa1, *sa2;
2499
2500 if (!dir)
2501 return (PIXA *)ERROR_PTR("dir not defined", __func__, NULL);
2502 if (nx < 1 || ny < 1 || nx > 50 || ny > 50)
2503 return (PIXA *)ERROR_PTR("invalid tiling N-factor", __func__, NULL);
2504 if (tw < 20)
2505 return (PIXA *)ERROR_PTR("tw must be >= 20", __func__, NULL);
2506 if (fontsize < 0 || fontsize > 20 || fontsize & 1 || fontsize == 2)
2507 return (PIXA *)ERROR_PTR("invalid fontsize", __func__, NULL);
2508
2509 sa1 = getSortedPathnamesInDirectory(dir, substr, 0, 0);
2510 pixa1 = pixaReadFilesSA(sa1);
2511 n = sarrayGetCount(sa1);
2512 sa2 = sarrayCreate(n);
2513 for (i = 0; i < n; i++) {
2514 fname = sarrayGetString(sa1, i, L_NOCOPY);
2515 splitPathAtDirectory(fname, NULL, &tail);
2516 sarrayAddString(sa2, tail, L_INSERT);
2517 }
2518 sarrayDestroy(&sa1);
2519 pixa2 = pixaConvertToNUpPixa(pixa1, sa2, nx, ny, tw, spacing,
2520 border, fontsize);
2521 pixaDestroy(&pixa1);
2522 sarrayDestroy(&sa2);
2523 return pixa2;
2524}
2525
2526
2549PIXA *
2551 SARRAY *sa,
2552 l_int32 nx,
2553 l_int32 ny,
2554 l_int32 tw,
2555 l_int32 spacing,
2556 l_int32 border,
2557 l_int32 fontsize)
2558{
2559l_int32 i, j, k, nt, n2, nout, d;
2560char *str;
2561L_BMF *bmf;
2562PIX *pix1, *pix2, *pix3, *pix4;
2563PIXA *pixa1, *pixad;
2564
2565 if (!pixas)
2566 return (PIXA *)ERROR_PTR("pixas not defined", __func__, NULL);
2567 if (nx < 1 || ny < 1 || nx > 50 || ny > 50)
2568 return (PIXA *)ERROR_PTR("invalid tiling N-factor", __func__, NULL);
2569 if (tw < 20)
2570 return (PIXA *)ERROR_PTR("tw must be >= 20", __func__, NULL);
2571 if (fontsize < 0 || fontsize > 20 || fontsize & 1 || fontsize == 2)
2572 return (PIXA *)ERROR_PTR("invalid fontsize", __func__, NULL);
2573
2574 nt = pixaGetCount(pixas);
2575 if (sa && (sarrayGetCount(sa) != nt)) {
2576 L_WARNING("pixa size %d not equal to sarray size %d\n", __func__,
2577 nt, sarrayGetCount(sa));
2578 }
2579
2580 n2 = nx * ny;
2581 nout = (nt + n2 - 1) / n2;
2582 pixad = pixaCreate(nout);
2583 bmf = (fontsize == 0) ? NULL : bmfCreate(NULL, fontsize);
2584 for (i = 0, j = 0; i < nout; i++) {
2585 pixa1 = pixaCreate(n2);
2586 for (k = 0; k < n2 && j < nt; j++, k++) {
2587 pix1 = pixaGetPix(pixas, j, L_CLONE);
2588 pix2 = pixScaleToSize(pix1, tw, 0); /* all images have width tw */
2589 if (bmf && sa) {
2590 str = sarrayGetString(sa, j, L_NOCOPY);
2591 pix3 = pixAddTextlines(pix2, bmf, str, 0xff000000,
2592 L_ADD_BELOW);
2593 } else {
2594 pix3 = pixClone(pix2);
2595 }
2596 pixaAddPix(pixa1, pix3, L_INSERT);
2597 pixDestroy(&pix1);
2598 pixDestroy(&pix2);
2599 }
2600 if (pixaGetCount(pixa1) == 0) { /* probably won't happen */
2601 pixaDestroy(&pixa1);
2602 continue;
2603 }
2604
2605 /* Add 2 * border to image width to prevent scaling */
2606 pixaGetRenderingDepth(pixa1, &d);
2607 pix4 = pixaDisplayTiledAndScaled(pixa1, d, tw + 2 * border, nx, 0,
2608 spacing, border);
2609 pixaAddPix(pixad, pix4, L_INSERT);
2610 pixaDestroy(&pixa1);
2611 }
2612
2613 bmfDestroy(&bmf);
2614 return pixad;
2615}
2616
2617
2618/*---------------------------------------------------------------------*
2619 * Render two pixa side-by-side for comparison *
2620 *---------------------------------------------------------------------*/
2660l_ok
2662 PIXA *pixa2,
2663 l_int32 nx,
2664 l_int32 ny,
2665 l_int32 tw,
2666 l_int32 spacing,
2667 l_int32 border,
2668 l_int32 fontsize,
2669 const char *fileout)
2670{
2671l_int32 n1, n2, npairs;
2672PIXA *pixa3, *pixa4, *pixa5;
2673SARRAY *sa;
2674
2675 if (!pixa1 || !pixa2)
2676 return ERROR_INT("pixa1 and pixa2 not both defined", __func__, 1);
2677 if (nx < 1 || ny < 1 || nx > 20 || ny > 20)
2678 return ERROR_INT("invalid tiling factors", __func__, 1);
2679 if (tw < 20)
2680 return ERROR_INT("invalid tw; tw must be >= 20", __func__, 1);
2681 if (fontsize < 0 || fontsize > 20 || fontsize & 1 || fontsize == 2)
2682 return ERROR_INT("invalid fontsize", __func__, 1);
2683 if (!fileout)
2684 return ERROR_INT("fileout not defined", __func__, 1);
2685 n1 = pixaGetCount(pixa1);
2686 n2 = pixaGetCount(pixa2);
2687 if (n1 == 0 || n2 == 0)
2688 return ERROR_INT("at least one pixa is empty", __func__, 1);
2689 if (n1 != n2)
2690 L_WARNING("sizes (%d, %d) differ; using the minimum in interleave\n",
2691 __func__, n1, n2);
2692
2693 /* Interleave the input pixa */
2694 if ((pixa3 = pixaInterleave(pixa1, pixa2, L_CLONE)) == NULL)
2695 return ERROR_INT("pixa3 not made", __func__, 1);
2696
2697 /* Scale the images if necessary and pair them up side/by/side */
2698 pixa4 = pixaConvertToNUpPixa(pixa3, NULL, 2, 1, tw, spacing, border, 0);
2699 pixaDestroy(&pixa3);
2700
2701 /* Label the pairs and mosaic into pages without further scaling */
2702 npairs = pixaGetCount(pixa4);
2703 sa = (fontsize > 0) ? sarrayGenerateIntegers(npairs) : NULL;
2704 pixa5 = pixaConvertToNUpPixa(pixa4, sa, nx, ny,
2705 2 * tw + 4 * border + spacing,
2706 spacing, border, fontsize);
2707 pixaDestroy(&pixa4);
2708 sarrayDestroy(&sa);
2709
2710 /* Output as pdf without scaling */
2711 pixaConvertToPdf(pixa5, 0, 1.0, 0, 0, NULL, fileout);
2712 pixaDestroy(&pixa5);
2713 return 0;
2714}
2715
2716
@ L_INTEGER_VALUE
Definition array.h:105
@ L_FLATE_ENCODE
Definition imageio.h:161
@ L_G4_ENCODE
Definition imageio.h:160
@ L_SELECT_IF_LTE
Definition pix.h:577
@ L_SELECT_IF_BOTH
Definition pix.h:599
@ L_ADD_LEFT
Definition pix.h:1004
@ L_ADD_BELOW
Definition pix.h:1003
@ L_COPY
Definition pix.h:505
@ L_CLONE
Definition pix.h:506
@ L_NOCOPY
Definition pix.h:503
@ L_INSERT
Definition pix.h:504
#define PIX_PAINT
Definition pix.h:450
@ L_SET_WHITE
Definition pix.h:699
@ L_ADD_TRAIL_SLASH
Definition pix.h:1082
#define PIX_SRC
Definition pix.h:444
@ L_GET_BLACK_VAL
Definition pix.h:709
@ L_GET_WHITE_VAL
Definition pix.h:708
PIXA * pixaDisplayMultiTiled(PIXA *pixas, l_int32 nx, l_int32 ny, l_int32 maxw, l_int32 maxh, l_float32 scalefactor, l_int32 spacing, l_int32 border)
pixaDisplayMultiTiled()
Definition pixafunc2.c:2262
PIX * pixaDisplay(PIXA *pixa, l_int32 w, l_int32 h)
pixaDisplay()
Definition pixafunc2.c:191
PIXA * pixaConstrainedSelect(PIXA *pixas, l_int32 first, l_int32 last, l_int32 nmax, l_int32 use_pairs, l_int32 copyflag)
pixaConstrainedSelect()
Definition pixafunc2.c:1922
l_ok pixGetTileCount(PIX *pix, l_int32 *pn)
pixGetTileCount()
Definition pixafunc2.c:2216
PIX * pixaDisplayTiledInColumns(PIXA *pixas, l_int32 nx, l_float32 scalefactor, l_int32 spacing, l_int32 border)
pixaDisplayTiledInColumns()
Definition pixafunc2.c:912
PIXA * pixaMakeFromTiledPixa(PIXA *pixas, l_int32 w, l_int32 h, l_int32 nsamp)
pixaMakeFromTiledPixa()
Definition pixafunc2.c:2065
PIXA * pixaConvertTo32(PIXA *pixas)
pixaConvertTo32()
Definition pixafunc2.c:1871
PIX * pixaDisplayLinearly(PIXA *pixas, l_int32 direction, l_float32 scalefactor, l_int32 background, l_int32 spacing, l_int32 border, BOXA **pboxa)
pixaDisplayLinearly()
Definition pixafunc2.c:339
PIXA * pixaConvertTo8Colormap(PIXA *pixas, l_int32 dither)
pixaConvertTo8Colormap()
Definition pixafunc2.c:1831
PIX * pixaaDisplayByPixa(PIXAA *paa, l_int32 maxnx, l_float32 scalefactor, l_int32 hspacing, l_int32 vspacing, l_int32 border)
pixaaDisplayByPixa()
Definition pixafunc2.c:1644
PIX * pixaDisplayPairTiledInColumns(PIXA *pixas1, PIXA *pixas2, l_int32 nx, l_float32 scalefactor, l_int32 spacing1, l_int32 spacing2, l_int32 border1, l_int32 border2, l_int32 fontsize, l_int32 startindex, SARRAY *sa)
pixaDisplayPairTiledInColumns()
Definition pixafunc2.c:1394
PIX * pixaDisplayTiled(PIXA *pixa, l_int32 maxwidth, l_int32 background, l_int32 spacing)
pixaDisplayTiled()
Definition pixafunc2.c:618
l_ok pixaSplitIntoFiles(PIXA *pixas, l_int32 nsplit, l_float32 scale, l_int32 outwidth, l_int32 write_pixa, l_int32 write_pix, l_int32 write_pdf)
pixaSplitIntoFiles()
Definition pixafunc2.c:2339
PIX * pixaaDisplay(PIXAA *paa, l_int32 w, l_int32 h)
pixaaDisplay()
Definition pixafunc2.c:1543
PIX * pixaDisplayTiledAndScaled(PIXA *pixa, l_int32 outdepth, l_int32 tilewidth, l_int32 ncols, l_int32 background, l_int32 spacing, l_int32 border)
pixaDisplayTiledAndScaled()
Definition pixafunc2.c:1025
PIX * pixaDisplayTiledWithText(PIXA *pixa, l_int32 maxwidth, l_float32 scalefactor, l_int32 spacing, l_int32 border, l_int32 fontsize, l_uint32 textcolor)
pixaDisplayTiledWithText()
Definition pixafunc2.c:1178
l_ok pixaCompareInPdf(PIXA *pixa1, PIXA *pixa2, l_int32 nx, l_int32 ny, l_int32 tw, l_int32 spacing, l_int32 border, l_int32 fontsize, const char *fileout)
pixaCompareInPdf()
Definition pixafunc2.c:2661
l_ok convertToNUpFiles(const char *dir, const char *substr, l_int32 nx, l_int32 ny, l_int32 tw, l_int32 spacing, l_int32 border, l_int32 fontsize, const char *outdir)
convertToNUpFiles()
Definition pixafunc2.c:2426
PIX * pixaDisplayTiledByIndex(PIXA *pixa, NUMA *na, l_int32 width, l_int32 spacing, l_int32 border, l_int32 fontsize, l_uint32 textcolor)
pixaDisplayTiledByIndex()
Definition pixafunc2.c:1272
PIXA * pixaConvertToNUpPixa(PIXA *pixas, SARRAY *sa, l_int32 nx, l_int32 ny, l_int32 tw, l_int32 spacing, l_int32 border, l_int32 fontsize)
pixaConvertToNUpPixa()
Definition pixafunc2.c:2550
PIX * pixaDisplayRandomCmap(PIXA *pixa, l_int32 w, l_int32 h)
pixaDisplayRandomCmap()
Definition pixafunc2.c:267
PIXA * pixaConvertTo1(PIXA *pixas, l_int32 thresh)
pixaConvertTo1()
Definition pixafunc2.c:1753
PIXA * pixaaDisplayTiledAndScaled(PIXAA *paa, l_int32 outdepth, l_int32 tilewidth, l_int32 ncols, l_int32 background, l_int32 spacing, l_int32 border)
pixaaDisplayTiledAndScaled()
Definition pixafunc2.c:1705
PIX * pixaDisplayTiledInRows(PIXA *pixa, l_int32 outdepth, l_int32 maxwidth, l_float32 scalefactor, l_int32 background, l_int32 spacing, l_int32 border)
pixaDisplayTiledInRows()
Definition pixafunc2.c:730
PIX * pixaDisplayUnsplit(PIXA *pixa, l_int32 nx, l_int32 ny, l_int32 borderwidth, l_uint32 bordercolor)
pixaDisplayUnsplit()
Definition pixafunc2.c:545
PIXA * pixaMakeFromTiledPix(PIX *pixs, l_int32 w, l_int32 h, l_int32 start, l_int32 num, BOXA *boxa)
pixaMakeFromTiledPix()
Definition pixafunc2.c:2143
PIXA * convertToNUpPixa(const char *dir, const char *substr, l_int32 nx, l_int32 ny, l_int32 tw, l_int32 spacing, l_int32 border, l_int32 fontsize)
convertToNUpPixa()
Definition pixafunc2.c:2486
PIX * pixaDisplayOnLattice(PIXA *pixa, l_int32 cellw, l_int32 cellh, l_int32 *pncols, BOXA **pboxa)
pixaDisplayOnLattice()
Definition pixafunc2.c:430
l_ok pixaSelectToPdf(PIXA *pixas, l_int32 first, l_int32 last, l_int32 res, l_float32 scalefactor, l_int32 type, l_int32 quality, l_uint32 color, l_int32 fontsize, const char *fileout)
pixaSelectToPdf()
Definition pixafunc2.c:1988
PIXA * pixaConvertTo8(PIXA *pixas, l_int32 cmapflag)
pixaConvertTo8()
Definition pixafunc2.c:1792
Definition bmf.h:47