Leptonica 1.68
C Image Processing Library

pixafunc2.c

Go to the documentation of this file.
00001 /*====================================================================*
00002  -  Copyright (C) 2001 Leptonica.  All rights reserved.
00003  -  This software is distributed in the hope that it will be
00004  -  useful, but with NO WARRANTY OF ANY KIND.
00005  -  No author or distributor accepts responsibility to anyone for the
00006  -  consequences of using this software, or for whether it serves any
00007  -  particular purpose or works at all, unless he or she says so in
00008  -  writing.  Everyone is granted permission to copy, modify and
00009  -  redistribute this source code, for commercial or non-commercial
00010  -  purposes, with the following restrictions: (1) the origin of this
00011  -  source code must not be misrepresented; (2) modified versions must
00012  -  be plainly marked as such; and (3) this notice may not be removed
00013  -  or altered from any source or modified source distribution.
00014  *====================================================================*/
00015 
00016 /*
00017  *   pixafunc2.c
00018  *
00019  *      Pixa Display (render into a pix)
00020  *           PIX      *pixaDisplay()
00021  *           PIX      *pixaDisplayOnColor()
00022  *           PIX      *pixaDisplayRandomCmap()
00023  *           PIX      *pixaDisplayOnLattice()
00024  *           PIX      *pixaDisplayUnsplit()
00025  *           PIX      *pixaDisplayTiled()
00026  *           PIX      *pixaDisplayTiledInRows()
00027  *           PIX      *pixaDisplayTiledAndScaled()
00028  *
00029  *      Pixaa Display (render into a pix)
00030  *           PIX      *pixaaDisplay()
00031  *           PIX      *pixaaDisplayByPixa()
00032  *           PIXA     *pixaaDisplayTiledAndScaled()
00033  *
00034  *  We give seven methods for displaying a pixa in a pix.
00035  *  Some work for 1 bpp input; others for any input depth.
00036  *  Some give an output depth that depends on the input depth;
00037  *  others give a different output depth or allow you to choose it.
00038  *  Some use a boxes to determine where each pix goes; others tile
00039  *  onto a regular lattice; yet others tile onto an irregular lattice.
00040  *
00041  *  Here is a brief description of what these functions do.
00042  *
00043  *    pixaDisplay()
00044  *        This uses the boxes to lay out each pix.  It is typically
00045  *        used to reconstruct a pix that has been broken into components.
00046  *    pixaDisplayOnColor()
00047  *        pixaDisplay() with choice of background color
00048  *    pixaDisplayRandomCmap()
00049  *        This also uses the boxes to lay out each pix.  However, it creates
00050  *        a colormapped dest, where each 1 bpp pix is given a randomly
00051  *        generated color (up to 256 are used).
00052  *    pixaDisplayOnLattice()
00053  *        This puts each pix, sequentially, onto a regular lattice,
00054  *        omitting any pix that are too big for the lattice size.
00055  *        This is useful, for example, to store bitmapped fonts,
00056  *        where all the characters are stored in a single image.
00057  *    pixaDisplayUnsplit()
00058  *        This lays out a mosaic of tiles (the pix in the pixa) that
00059  *        are all of equal size.  (Don't use this for unequal sized pix!)
00060  *        For example, it can be used to invert the action of
00061  *        pixaSplitPix().
00062  *    pixaDisplayTiled()
00063  *        Like pixaDisplayOnLattice(), this places each pix on a regular
00064  *        lattice, but here the lattice size is determined by the
00065  *        largest component, and no components are omitted.  This is
00066  *        dangerous if there are thousands of small components and
00067  *        one or more very large one, because the size of the resulting
00068  *        pix can be huge!
00069  *    pixaDisplayTiledInRows()
00070  *        This puts each pix down in a series of rows, where the upper
00071  *        edges of each pix in a row are alined and there is a uniform
00072  *        spacing between the pix.  The height of each row is determined
00073  *        by the tallest pix that was put in the row.  This function
00074  *        is a reasonably efficient way to pack the subimages.
00075  *    pixaDisplayTiledAndScaled()
00076  *        This scales each pix to a given width and output depth,
00077  *        and then tiles them in rows with a given number placed in
00078  *        each row.  This is very useful for presenting a sequence
00079  *        of images that can be at different resolutions, but which
00080  *        are derived from the same initial image.
00081  */
00082 
00083 #include <string.h>
00084 #include <math.h>   /* for sqrt() */
00085 #include "allheaders.h"
00086 
00087 
00088 /*---------------------------------------------------------------------*
00089  *                               Pixa Display                          *
00090  *---------------------------------------------------------------------*/
00091 /*!
00092  *  pixaDisplay()
00093  *
00094  *      Input:  pixa
00095  *              w, h (if set to 0, determines the size from the
00096  *                    b.b. of the components in pixa)
00097  *      Return: pix, or null on error
00098  *
00099  *  Notes:
00100  *      (1) This uses the boxes to place each pix in the rendered composite.
00101  *      (2) Set w = h = 0 to use the b.b. of the components to determine
00102  *          the size of the returned pix.
00103  *      (3) Uses the first pix in pixa to determine the depth.
00104  *      (4) The background is written "white".  On 1 bpp, each successive
00105  *          pix is "painted" (adding foreground), whereas for grayscale
00106  *          or color each successive pix is blitted with just the src.
00107  *      (5) If the pixa is empty, returns an empty 1 bpp pix.
00108  */
00109 PIX *
00110 pixaDisplay(PIXA    *pixa,
00111             l_int32  w,
00112             l_int32  h)
00113 {
00114 l_int32  i, n, d, xb, yb, wb, hb;
00115 BOXA    *boxa;
00116 PIX     *pixt, *pixd;
00117 
00118     PROCNAME("pixaDisplay");
00119 
00120     if (!pixa)
00121         return (PIX *)ERROR_PTR("pixa not defined", procName, NULL);
00122     
00123     n = pixaGetCount(pixa);
00124     if (n == 0 && w == 0 && h == 0)
00125         return (PIX *)ERROR_PTR("no components; no size", procName, NULL);
00126     if (n == 0) {
00127         L_WARNING("no components; returning empty 1 bpp pix", procName);
00128         return pixCreate(w, h, 1);
00129     }
00130 
00131         /* If w and h not input, determine the minimum size required
00132          * to contain the origin and all c.c. */
00133     if (w == 0 || h == 0) {
00134         boxa = pixaGetBoxa(pixa, L_CLONE);
00135         boxaGetExtent(boxa, &w, &h, NULL);
00136         boxaDestroy(&boxa);
00137     }
00138 
00139         /* Use the first pix in pixa to determine the depth.  */
00140     pixt = pixaGetPix(pixa, 0, L_CLONE);
00141     d = pixGetDepth(pixt);
00142     pixDestroy(&pixt);
00143 
00144     if ((pixd = pixCreate(w, h, d)) == NULL)
00145         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
00146     if (d > 1)
00147         pixSetAll(pixd);
00148     for (i = 0; i < n; i++) {
00149         if (pixaGetBoxGeometry(pixa, i, &xb, &yb, &wb, &hb)) {
00150             L_WARNING("no box found!", procName);
00151             continue;
00152         }
00153         pixt = pixaGetPix(pixa, i, L_CLONE);
00154         if (d == 1)
00155             pixRasterop(pixd, xb, yb, wb, hb, PIX_PAINT, pixt, 0, 0);
00156         else
00157             pixRasterop(pixd, xb, yb, wb, hb, PIX_SRC, pixt, 0, 0);
00158         pixDestroy(&pixt);
00159     }
00160 
00161     return pixd;
00162 }
00163 
00164 
00165 /*!
00166  *  pixaDisplayOnColor()
00167  *
00168  *      Input:  pixa
00169  *              w, h (if set to 0, determines the size from the
00170  *                    b.b. of the components in pixa)
00171  *              color (background color to use)
00172  *      Return: pix, or null on error
00173  *
00174  *  Notes:
00175  *      (1) This uses the boxes to place each pix in the rendered composite.
00176  *      (2) Set w = h = 0 to use the b.b. of the components to determine
00177  *          the size of the returned pix.
00178  *      (3) If any pix in @pixa are colormapped, or if the pix have
00179  *          different depths, it returns a 32 bpp pix.  Otherwise,
00180  *          the depth of the returned pixa equals that of the pix in @pixa.
00181  *      (4) If the pixa is empty, return null.
00182  */
00183 PIX *
00184 pixaDisplayOnColor(PIXA     *pixa,
00185                    l_int32   w,
00186                    l_int32   h,
00187                    l_uint32  bgcolor)
00188 {
00189 l_int32  i, n, xb, yb, wb, hb, hascmap, maxdepth, same;
00190 BOXA    *boxa;
00191 PIX     *pixt1, *pixt2, *pixd;
00192 PIXA    *pixat;
00193 
00194     PROCNAME("pixaDisplayOnColor");
00195 
00196     if (!pixa)
00197         return (PIX *)ERROR_PTR("pixa not defined", procName, NULL);
00198     if ((n = pixaGetCount(pixa)) == 0)
00199         return (PIX *)ERROR_PTR("no components", procName, NULL);
00200 
00201         /* If w and h are not input, determine the minimum size
00202          * required to contain the origin and all c.c. */
00203     if (w == 0 || h == 0) {
00204         boxa = pixaGetBoxa(pixa, L_CLONE);
00205         boxaGetExtent(boxa, &w, &h, NULL);
00206         boxaDestroy(&boxa);
00207     }
00208 
00209         /* If any pix have colormaps, or if they have different depths,
00210          * generate rgb */
00211     pixaAnyColormaps(pixa, &hascmap);
00212     pixaGetDepthInfo(pixa, &maxdepth, &same);
00213     if (hascmap || !same) {
00214         maxdepth = 32;
00215         pixat = pixaCreate(n);
00216         for (i = 0; i < n; i++) {
00217             pixt1 = pixaGetPix(pixa, i, L_CLONE);
00218             pixt2 = pixConvertTo32(pixt1);
00219             pixaAddPix(pixat, pixt2, L_INSERT);
00220             pixDestroy(&pixt1);
00221         }
00222     }
00223     else 
00224         pixat = pixaCopy(pixa, L_CLONE);
00225 
00226         /* Make the output pix and set the background color */
00227     if ((pixd = pixCreate(w, h, maxdepth)) == NULL)
00228         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
00229     if ((maxdepth == 1 && bgcolor > 0) ||
00230         (maxdepth == 2 && bgcolor >= 0x3) ||
00231         (maxdepth == 4 && bgcolor >= 0xf) ||
00232         (maxdepth == 8 && bgcolor >= 0xff) ||
00233         (maxdepth == 16 && bgcolor >= 0xffff) ||
00234         (maxdepth == 32 && bgcolor >= 0xffffff00)) {
00235         pixSetAll(pixd);
00236     }
00237     else if (bgcolor > 0)
00238         pixSetAllArbitrary(pixd, bgcolor);
00239 
00240         /* Blit each pix into its place */
00241     for (i = 0; i < n; i++) {
00242         if (pixaGetBoxGeometry(pixat, i, &xb, &yb, &wb, &hb)) {
00243             L_WARNING("no box found!", procName);
00244             continue;
00245         }
00246         pixt1 = pixaGetPix(pixat, i, L_CLONE);
00247         pixRasterop(pixd, xb, yb, wb, hb, PIX_SRC, pixt1, 0, 0);
00248         pixDestroy(&pixt1);
00249     }
00250 
00251     pixaDestroy(&pixat);
00252     return pixd;
00253 }
00254 
00255 
00256 /*!
00257  *  pixaDisplayRandomCmap()
00258  *
00259  *      Input:  pixa (of 1 bpp components, with boxa)
00260  *              w, h (if set to 0, determines the size from the
00261  *                    b.b. of the components in pixa)
00262  *      Return: pix (8 bpp, cmapped, with random colors on the components),
00263  *              or null on error
00264  *
00265  *  Notes:
00266  *      (1) This uses the boxes to place each pix in the rendered composite.
00267  *      (2) By default, the background color is: black, cmap index 0.
00268  *          This can be changed by pixcmapResetColor()
00269  */
00270 PIX *
00271 pixaDisplayRandomCmap(PIXA    *pixa,
00272                       l_int32  w,
00273                       l_int32  h)
00274 {
00275 l_int32   i, n, d, index, xb, yb, wb, hb;
00276 BOXA     *boxa;
00277 PIX      *pixs, *pixt, *pixd;
00278 PIXCMAP  *cmap;
00279 
00280     PROCNAME("pixaDisplayRandomCmap");
00281 
00282     if (!pixa)
00283         return (PIX *)ERROR_PTR("pixa not defined", procName, NULL);
00284     
00285     n = pixaGetCount(pixa);
00286     if (n == 0)
00287         return (PIX *)ERROR_PTR("no components", procName, NULL);
00288 
00289         /* Use the first pix in pixa to verify depth is 1 bpp  */
00290     pixs = pixaGetPix(pixa, 0, L_CLONE);
00291     d = pixGetDepth(pixs);
00292     pixDestroy(&pixs);
00293     if (d != 1)
00294         return (PIX *)ERROR_PTR("components not 1 bpp", procName, NULL);
00295 
00296         /* If w and h not input, determine the minimum size required
00297          * to contain the origin and all c.c. */
00298     if (w == 0 || h == 0) {
00299         boxa = pixaGetBoxa(pixa, L_CLONE);
00300         boxaGetExtent(boxa, &w, &h, NULL);
00301         boxaDestroy(&boxa);
00302     }
00303 
00304         /* Set up an 8 bpp dest pix, with a colormap with 254 random colors */
00305     if ((pixd = pixCreate(w, h, 8)) == NULL)
00306         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
00307     cmap = pixcmapCreateRandom(8, 1, 1);
00308     pixSetColormap(pixd, cmap);
00309 
00310         /* Color each component and blit it in */
00311     for (i = 0; i < n; i++) {
00312         index = 1 + (i % 254);
00313         pixaGetBoxGeometry(pixa, i, &xb, &yb, &wb, &hb);
00314         pixs = pixaGetPix(pixa, i, L_CLONE);
00315         pixt = pixConvert1To8(NULL, pixs, 0, index);
00316         pixRasterop(pixd, xb, yb, wb, hb, PIX_PAINT, pixt, 0, 0);
00317         pixDestroy(&pixs);
00318         pixDestroy(&pixt);
00319     }
00320 
00321     return pixd;
00322 }
00323 
00324 
00325 /*!
00326  *  pixaDisplayOnLattice()
00327  *
00328  *      Input:  pixa
00329  *              xspace
00330  *              yspace
00331  *      Return: pix of composite images, or null on error
00332  *
00333  *  Notes:
00334  *      (1) This places each pix on sequentially on a regular lattice
00335  *          in the rendered composite.  If a pix is too large to fit in the
00336  *          allocated lattice space, it is not rendered.
00337  *      (2) If any pix has a colormap, all pix are rendered in rgb.
00338  *      (3) This is useful when putting bitmaps of components,
00339  *          such as characters, into a single image.
00340  */
00341 PIX *
00342 pixaDisplayOnLattice(PIXA    *pixa,
00343                      l_int32  xspace,
00344                      l_int32  yspace)
00345 {
00346 l_int32  n, nw, nh, w, h, d, wt, ht;
00347 l_int32  index, i, j, hascmap;
00348 PIX     *pix, *pixt, *pixd;
00349 PIXA    *pixat;
00350 
00351     PROCNAME("pixaDisplayOnLattice");
00352 
00353     if (!pixa)
00354         return (PIX *)ERROR_PTR("pixa not defined", procName, NULL);
00355     
00356         /* If any pix have colormaps, generate rgb */
00357     if ((n = pixaGetCount(pixa)) == 0)
00358         return (PIX *)ERROR_PTR("no components", procName, NULL);
00359     pixaAnyColormaps(pixa, &hascmap);
00360     if (hascmap) {
00361         pixat = pixaCreate(n);
00362         for (i = 0; i < n; i++) {
00363             pixt = pixaGetPix(pixa, i, L_CLONE);
00364             pix = pixConvertTo32(pixt);
00365             pixaAddPix(pixat, pix, L_INSERT);
00366             pixDestroy(&pixt);
00367         }
00368     }
00369     else
00370         pixat = pixaCopy(pixa, L_CLONE);
00371 
00372     nw = (l_int32)sqrt((l_float64)n);
00373     nh = (n + nw - 1) / nw;
00374     w = xspace * nw;
00375     h = yspace * nh;
00376 
00377         /* Use the first pix in pixa to determine the depth.  */
00378     pixaGetPixDimensions(pixat, 0, NULL, NULL, &d);
00379 
00380     if ((pixd = pixCreate(w, h, d)) == NULL) {
00381         pixaDestroy(&pixat);
00382         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
00383     }
00384     
00385     index = 0;
00386     for (i = 0; i < nh; i++) {
00387         for (j = 0; j < nw && index < n; j++, index++) {
00388             pixt = pixaGetPix(pixat, index, L_CLONE);
00389             pixGetDimensions(pixt, &wt, &ht, NULL);
00390             if (wt > xspace || ht > yspace) {
00391                 fprintf(stderr, "pix(%d) omitted; size %dx%d\n", index, wt, ht);
00392                 pixDestroy(&pixt);
00393                 continue;
00394             }
00395             pixRasterop(pixd, j * xspace, i * yspace, wt, ht, 
00396                         PIX_PAINT, pixt, 0, 0);
00397             pixDestroy(&pixt);
00398         }
00399     }
00400 
00401     pixaDestroy(&pixat);
00402     return pixd;
00403 }
00404 
00405 
00406 /*!
00407  *  pixaDisplayUnsplit()
00408  *
00409  *      Input:  pixa
00410  *              nx   (number of mosaic cells horizontally)
00411  *              ny   (number of mosaic cells vertically)
00412  *              borderwidth  (of added border on all sides)
00413  *              bordercolor  (in our RGBA format: 0xrrggbbaa)
00414  *      Return: pix of tiled images, or null on error
00415  *
00416  *  Notes:
00417  *      (1) This is a logical inverse of pixaSplitPix().  It
00418  *          constructs a pix from a mosaic of tiles, all of equal size.
00419  *      (2) For added generality, a border of arbitrary color can
00420  *          be added to each of the tiles.
00421  *      (3) In use, pixa will typically have either been generated
00422  *          from pixaSplitPix() or will derived from a pixa that
00423  *          was so generated.
00424  *      (4) All pix in the pixa must be of equal depth, and, if
00425  *          colormapped, have the same colormap.
00426  */
00427 PIX *
00428 pixaDisplayUnsplit(PIXA     *pixa,
00429                    l_int32   nx,
00430                    l_int32   ny,
00431                    l_int32   borderwidth,
00432                    l_uint32  bordercolor)
00433 {
00434 l_int32  w, h, d, wt, ht;
00435 l_int32  i, j, k, x, y, n;
00436 PIX     *pixt, *pixd;
00437 
00438     PROCNAME("pixaDisplayUnsplit");
00439 
00440     if (!pixa)
00441         return (PIX *)ERROR_PTR("pixa not defined", procName, NULL);
00442     if (nx <= 0 || ny <= 0)
00443         return (PIX *)ERROR_PTR("nx and ny must be > 0", procName, NULL);
00444     if ((n = pixaGetCount(pixa)) == 0)
00445         return (PIX *)ERROR_PTR("no components", procName, NULL);
00446     if (n != nx * ny)
00447         return (PIX *)ERROR_PTR("n != nx * ny", procName, NULL);
00448     borderwidth = L_MAX(0, borderwidth);
00449 
00450     pixaGetPixDimensions(pixa, 0, &wt, &ht, &d);
00451     w = nx * (wt + 2 * borderwidth);
00452     h = ny * (ht + 2 * borderwidth);
00453 
00454     if ((pixd = pixCreate(w, h, d)) == NULL)
00455         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
00456     pixt = pixaGetPix(pixa, 0, L_CLONE);
00457     pixCopyColormap(pixd, pixt);
00458     pixDestroy(&pixt);
00459     if (borderwidth > 0)
00460         pixSetAllArbitrary(pixd, bordercolor);
00461 
00462     y = borderwidth;
00463     for (i = 0, k = 0; i < ny; i++) {
00464         x = borderwidth;
00465         for (j = 0; j < nx; j++, k++) {
00466             pixt = pixaGetPix(pixa, k, L_CLONE);
00467             pixRasterop(pixd, x, y, wt, ht, PIX_SRC, pixt, 0, 0);
00468             pixDestroy(&pixt);
00469             x += wt + 2 * borderwidth;
00470         }
00471         y += ht + 2 * borderwidth;
00472     }
00473 
00474     return pixd;
00475 }
00476 
00477 
00478 /*!
00479  *  pixaDisplayTiled()
00480  *
00481  *      Input:  pixa
00482  *              maxwidth (of output image)
00483  *              background (0 for white, 1 for black)
00484  *              spacing
00485  *      Return: pix of tiled images, or null on error
00486  *
00487  *  Notes:
00488  *      (1) This saves a pixa to a single image file of width not to
00489  *          exceed maxwidth, with background color either white or black,
00490  *          and with each subimage spaced on a regular lattice.
00491  *      (2) The lattice size is determined from the largest width and height,
00492  *          separately, of all pix in the pixa.
00493  *      (3) All pix in the pixa must be of equal depth.
00494  *      (4) If any pix has a colormap, all pix are rendered in rgb.
00495  *      (5) Careful: because no components are omitted, this is
00496  *          dangerous if there are thousands of small components and
00497  *          one or more very large one, because the size of the
00498  *          resulting pix can be huge!
00499  */
00500 PIX *
00501 pixaDisplayTiled(PIXA    *pixa,
00502                  l_int32  maxwidth,
00503                  l_int32  background,
00504                  l_int32  spacing)
00505 {
00506 l_int32  w, h, wmax, hmax, wd, hd, d, hascmap;
00507 l_int32  i, j, n, ni, ncols, nrows;
00508 l_int32  ystart, xstart, wt, ht;
00509 PIX     *pix, *pixt, *pixd;
00510 PIXA    *pixat;
00511 
00512     PROCNAME("pixaDisplayTiled");
00513 
00514     if (!pixa)
00515         return (PIX *)ERROR_PTR("pixa not defined", procName, NULL);
00516 
00517         /* If any pix have colormaps, generate rgb */
00518     if ((n = pixaGetCount(pixa)) == 0)
00519         return (PIX *)ERROR_PTR("no components", procName, NULL);
00520     pixaAnyColormaps(pixa, &hascmap);
00521     if (hascmap) {
00522         pixat = pixaCreate(n);
00523         for (i = 0; i < n; i++) {
00524             pixt = pixaGetPix(pixa, i, L_CLONE);
00525             pix = pixConvertTo32(pixt);
00526             pixaAddPix(pixat, pix, L_INSERT);
00527             pixDestroy(&pixt);
00528         }
00529     }
00530     else
00531         pixat = pixaCopy(pixa, L_CLONE);
00532 
00533         /* Find the largest width and height of the subimages */
00534     wmax = hmax = 0;
00535     for (i = 0; i < n; i++) {
00536         pix = pixaGetPix(pixat, i, L_CLONE);
00537         pixGetDimensions(pix, &w, &h, NULL);
00538         if (i == 0)
00539             d = pixGetDepth(pix);
00540         else if (d != pixGetDepth(pix)) {
00541             pixDestroy(&pix);
00542             pixaDestroy(&pixat);
00543             return (PIX *)ERROR_PTR("depths not equal", procName, NULL);
00544         }
00545         if (w > wmax)
00546             wmax = w;
00547         if (h > hmax)
00548             hmax = h;
00549         pixDestroy(&pix);
00550     }
00551 
00552         /* Get the number of rows and columns and the output image size */
00553     spacing = L_MAX(spacing, 0);
00554     ncols = (l_int32)((l_float32)(maxwidth - spacing) /
00555                       (l_float32)(wmax + spacing));
00556     nrows = (n + ncols - 1) / ncols;
00557     wd = wmax * ncols + spacing * (ncols + 1);
00558     hd = hmax * nrows + spacing * (nrows + 1);
00559     if ((pixd = pixCreate(wd, hd, d)) == NULL) {
00560         pixaDestroy(&pixat);
00561         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
00562     }
00563 
00564 #if 0
00565     fprintf(stderr, " nrows = %d, ncols = %d, wmax = %d, hmax = %d\n",
00566             nrows, ncols, wmax, hmax);
00567     fprintf(stderr, " space = %d, wd = %d, hd = %d, n = %d\n",
00568             space, wd, hd, n);
00569 #endif
00570 
00571         /* Reset the background color if necessary */
00572     if ((background == 1 && d == 1) || (background == 0 && d != 1))
00573         pixSetAll(pixd);
00574 
00575         /* Blit the images to the dest */
00576     for (i = 0, ni = 0; i < nrows; i++) {
00577         ystart = spacing + i * (hmax + spacing);
00578         for (j = 0; j < ncols && ni < n; j++, ni++) {
00579             xstart = spacing + j * (wmax + spacing);
00580             pix = pixaGetPix(pixat, ni, L_CLONE);
00581             wt = pixGetWidth(pix);
00582             ht = pixGetHeight(pix);
00583             pixRasterop(pixd, xstart, ystart, wt, ht, PIX_SRC, pix, 0, 0);
00584             pixDestroy(&pix);
00585         }
00586     }
00587 
00588     pixaDestroy(&pixat);
00589     return pixd;
00590 }
00591 
00592 
00593 /*!
00594  *  pixaDisplayTiledInRows()
00595  *
00596  *      Input:  pixa
00597  *              outdepth (output depth: 1, 8 or 32 bpp)
00598  *              maxwidth (of output image)
00599  *              scalefactor (applied to every pix; use 1.0 for no scaling)
00600  *              background (0 for white, 1 for black; this is the color
00601  *                 of the spacing between the images)
00602  *              spacing  (between images, and on outside)
00603  *              border (width of black border added to each image;
00604  *                      use 0 for no border)
00605  *      Return: pixd (of tiled images), or null on error
00606  *
00607  *  Notes:
00608  *      (1) This saves a pixa to a single image file of width not to
00609  *          exceed maxwidth, with background color either white or black,
00610  *          and with each row tiled such that the top of each pix is
00611  *          aligned and separated by 'spacing' from the next one.
00612  *          A black border can be added to each pix.
00613  *      (2) All pix are converted to outdepth; existing colormaps are removed.
00614  *      (3) This does a reasonably spacewise-efficient job of laying
00615  *          out the individual pix images into a tiled composite.
00616  */
00617 PIX *
00618 pixaDisplayTiledInRows(PIXA      *pixa,
00619                        l_int32    outdepth,
00620                        l_int32    maxwidth,
00621                        l_float32  scalefactor,
00622                        l_int32    background,
00623                        l_int32    spacing,
00624                        l_int32    border)
00625 {
00626 l_int32  h;  /* cumulative height over all the rows */
00627 l_int32  w;  /* cumulative height in the current row */
00628 l_int32  bordval, wtry, wt, ht;
00629 l_int32  irow;  /* index of current pix in current row */
00630 l_int32  wmaxrow;  /* width of the largest row */
00631 l_int32  maxh;  /* max height in row */
00632 l_int32  i, j, index, n, x, y, nrows, ninrow;
00633 NUMA    *nainrow;  /* number of pix in the row */
00634 NUMA    *namaxh;  /* height of max pix in the row */
00635 PIX     *pix, *pixn, *pixt, *pixd;
00636 PIXA    *pixan;
00637 
00638     PROCNAME("pixaDisplayTiledInRows");
00639 
00640     if (!pixa)
00641         return (PIX *)ERROR_PTR("pixa not defined", procName, NULL);
00642     if (outdepth != 1 && outdepth != 8 && outdepth != 32)
00643         return (PIX *)ERROR_PTR("outdepth not in {1, 8, 32}", procName, NULL);
00644     if (border < 0)
00645         border = 0;
00646     if (scalefactor <= 0.0) scalefactor = 1.0;
00647     
00648     if ((n = pixaGetCount(pixa)) == 0)
00649         return (PIX *)ERROR_PTR("no components", procName, NULL);
00650 
00651         /* Normalize depths, scale, remove colormaps; optionally add border */
00652     pixan = pixaCreate(n);
00653     bordval = (outdepth == 1) ? 1 : 0;
00654     for (i = 0; i < n; i++) {
00655         if ((pix = pixaGetPix(pixa, i, L_CLONE)) == NULL)
00656             continue;
00657 
00658         if (outdepth == 1)
00659             pixn = pixConvertTo1(pix, 128);
00660         else if (outdepth == 8)
00661             pixn = pixConvertTo8(pix, FALSE);
00662         else  /* outdepth == 32 */
00663             pixn = pixConvertTo32(pix);
00664         pixDestroy(&pix);
00665 
00666         if (scalefactor != 1.0)
00667             pixt = pixScale(pixn, scalefactor, scalefactor);
00668         else
00669             pixt = pixClone(pixn);
00670         if (border)
00671             pixd = pixAddBorder(pixt, border, bordval);
00672         else
00673             pixd = pixClone(pixt);
00674         pixDestroy(&pixn);
00675         pixDestroy(&pixt);
00676 
00677         pixaAddPix(pixan, pixd, L_INSERT);
00678     }
00679     if (pixaGetCount(pixan) != n) {
00680         n = pixaGetCount(pixan);
00681         L_WARNING_INT("only got %d components", procName, n);
00682         if (n == 0) {
00683             pixaDestroy(&pixan);
00684             return (PIX *)ERROR_PTR("no components", procName, NULL);
00685         }
00686     }
00687 
00688         /* Compute parameters for layout */
00689     nainrow = numaCreate(0);
00690     namaxh = numaCreate(0);
00691     wmaxrow = 0;
00692     w = h = spacing;
00693     maxh = 0;  /* max height in row */
00694     for (i = 0, irow = 0; i < n; i++, irow++) {
00695         pixaGetPixDimensions(pixan, i, &wt, &ht, NULL);
00696         wtry = w + wt + spacing;
00697         if (wtry > maxwidth) {  /* end the current row and start next one */
00698             numaAddNumber(nainrow, irow); 
00699             numaAddNumber(namaxh, maxh); 
00700             wmaxrow = L_MAX(wmaxrow, w);
00701             h += maxh + spacing;
00702             irow = 0;
00703             w = wt + 2 * spacing;
00704             maxh = ht;
00705         } else {
00706             w = wtry;
00707             maxh = L_MAX(maxh, ht);
00708         }
00709     }
00710 
00711         /* Enter the parameters for the last row */
00712     numaAddNumber(nainrow, irow); 
00713     numaAddNumber(namaxh, maxh); 
00714     wmaxrow = L_MAX(wmaxrow, w);
00715     h += maxh + spacing;
00716             
00717     if ((pixd = pixCreate(wmaxrow, h, outdepth)) == NULL) {
00718         numaDestroy(&nainrow);
00719         numaDestroy(&namaxh);
00720         pixaDestroy(&pixan);
00721         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
00722     }
00723 
00724         /* Reset the background color if necessary */
00725     if ((background == 1 && outdepth == 1) ||
00726         (background == 0 && outdepth != 1))
00727         pixSetAll(pixd);
00728 
00729         /* Blit the images to the dest */
00730     nrows = numaGetCount(nainrow);
00731     y = spacing;
00732     for (i = 0, index = 0; i < nrows; i++) {  /* over rows */
00733         numaGetIValue(nainrow, i, &ninrow);
00734         numaGetIValue(namaxh, i, &maxh);
00735         x = spacing;
00736         for (j = 0; j < ninrow; j++, index++) {   /* over pix in row */
00737             pix = pixaGetPix(pixan, index, L_CLONE);
00738             pixGetDimensions(pix, &wt, &ht, NULL);
00739             pixRasterop(pixd, x, y, wt, ht, PIX_SRC, pix, 0, 0);
00740             pixDestroy(&pix);
00741             x += wt + spacing;
00742         }
00743         y += maxh + spacing;
00744     }
00745 
00746     numaDestroy(&nainrow);
00747     numaDestroy(&namaxh);
00748     pixaDestroy(&pixan);
00749     return pixd;
00750 }
00751 
00752 
00753 /*!
00754  *  pixaDisplayTiledAndScaled()
00755  *
00756  *      Input:  pixa
00757  *              outdepth (output depth: 1, 8 or 32 bpp)
00758  *              tilewidth (each pix is scaled to this width)
00759  *              ncols (number of tiles in each row)
00760  *              background (0 for white, 1 for black; this is the color
00761  *                 of the spacing between the images)
00762  *              spacing  (between images, and on outside)
00763  *              border (width of additional black border on each image;
00764  *                      use 0 for no border)
00765  *      Return: pix of tiled images, or null on error
00766  *
00767  *  Notes:
00768  *      (1) This can be used to tile a number of renderings of
00769  *          an image that are at different scales and depths.
00770  *      (2) Each image, after scaling and optionally adding the
00771  *          black border, has width 'tilewidth'.  Thus, the border does
00772  *          not affect the spacing between the image tiles.  The
00773  *          maximum allowed border width is tilewidth / 5.
00774  */
00775 PIX *
00776 pixaDisplayTiledAndScaled(PIXA    *pixa,
00777                           l_int32  outdepth,
00778                           l_int32  tilewidth,
00779                           l_int32  ncols,
00780                           l_int32  background,
00781                           l_int32  spacing,
00782                           l_int32  border)
00783 {
00784 l_int32    x, y, w, h, wd, hd, d;
00785 l_int32    i, n, nrows, maxht, ninrow, irow, bordval;
00786 l_int32   *rowht;
00787 l_float32  scalefact;
00788 PIX       *pix, *pixn, *pixt, *pixb, *pixd;
00789 PIXA      *pixan;
00790 
00791     PROCNAME("pixaDisplayTiledAndScaled");
00792 
00793     if (!pixa)
00794         return (PIX *)ERROR_PTR("pixa not defined", procName, NULL);
00795     if (outdepth != 1 && outdepth != 8 && outdepth != 32)
00796         return (PIX *)ERROR_PTR("outdepth not in {1, 8, 32}", procName, NULL);
00797     if (border < 0 || border > tilewidth / 5)
00798         border = 0;
00799     
00800     if ((n = pixaGetCount(pixa)) == 0)
00801         return (PIX *)ERROR_PTR("no components", procName, NULL);
00802 
00803         /* Normalize scale and depth for each pix; optionally add border */
00804     pixan = pixaCreate(n);
00805     bordval = (outdepth == 1) ? 1 : 0;
00806     for (i = 0; i < n; i++) {
00807         if ((pix = pixaGetPix(pixa, i, L_CLONE)) == NULL)
00808             continue;
00809 
00810         pixGetDimensions(pix, &w, &h, &d);
00811         scalefact = (l_float32)(tilewidth - 2 * border) / (l_float32)w;
00812         if (d == 1 && outdepth > 1 && scalefact < 1.0)
00813             pixt = pixScaleToGray(pix, scalefact);
00814         else
00815             pixt = pixScale(pix, scalefact, scalefact);
00816 
00817         if (outdepth == 1)
00818             pixn = pixConvertTo1(pixt, 128);
00819         else if (outdepth == 8)
00820             pixn = pixConvertTo8(pixt, FALSE);
00821         else  /* outdepth == 32 */
00822             pixn = pixConvertTo32(pixt);
00823         pixDestroy(&pixt);
00824 
00825         if (border)
00826             pixb = pixAddBorder(pixn, border, bordval);
00827         else
00828             pixb = pixClone(pixn);
00829 
00830         pixaAddPix(pixan, pixb, L_INSERT);
00831         pixDestroy(&pix);
00832         pixDestroy(&pixn);
00833     }
00834     if ((n = pixaGetCount(pixan)) == 0) { /* should not have changed! */
00835         pixaDestroy(&pixan);
00836         return (PIX *)ERROR_PTR("no components", procName, NULL);
00837     }
00838 
00839         /* Determine the size of each row and of pixd */
00840     wd = tilewidth * ncols + spacing * (ncols + 1);
00841     nrows = (n + ncols - 1) / ncols;
00842     if ((rowht = (l_int32 *)CALLOC(nrows, sizeof(l_int32))) == NULL)
00843         return (PIX *)ERROR_PTR("rowht array not made", procName, NULL);
00844     maxht = 0;
00845     ninrow = 0;
00846     irow = 0;
00847     for (i = 0; i < n; i++) {
00848         pix = pixaGetPix(pixan, i, L_CLONE);
00849         ninrow++;
00850         pixGetDimensions(pix, &w, &h, NULL);
00851         maxht = L_MAX(h, maxht);
00852         if (ninrow == ncols) {
00853             rowht[irow] = maxht;
00854             maxht = ninrow = 0;  /* reset */
00855             irow++;
00856         }
00857         pixDestroy(&pix);
00858     }
00859     if (ninrow > 0) {   /* last fencepost */
00860         rowht[irow] = maxht;
00861         irow++;  /* total number of rows */
00862     }
00863     nrows = irow;
00864     hd = spacing * (nrows + 1);
00865     for (i = 0; i < nrows; i++)
00866         hd += rowht[i];
00867 
00868     pixd = pixCreate(wd, hd, outdepth);
00869     if ((background == 1 && outdepth == 1) ||
00870         (background == 0 && outdepth != 1))
00871         pixSetAll(pixd);
00872 
00873         /* Now blit images to pixd */
00874     x = y = spacing;
00875     irow = 0;
00876     for (i = 0; i < n; i++) {
00877         pix = pixaGetPix(pixan, i, L_CLONE);
00878         pixGetDimensions(pix, &w, &h, NULL);
00879         if (i && ((i % ncols) == 0)) {  /* start new row */
00880             x = spacing;
00881             y += spacing + rowht[irow];
00882             irow++;
00883         }
00884         pixRasterop(pixd, x, y, w, h, PIX_SRC, pix, 0, 0);
00885         x += tilewidth + spacing;
00886         pixDestroy(&pix);
00887     }
00888 
00889     pixaDestroy(&pixan);
00890     FREE(rowht);
00891     return pixd;
00892 }
00893 
00894 
00895 /*---------------------------------------------------------------------*
00896  *                              Pixaa Display                          *
00897  *---------------------------------------------------------------------*/
00898 /*!
00899  *  pixaaDisplay()
00900  *
00901  *      Input:  pixaa
00902  *              w, h (if set to 0, determines the size from the
00903  *                    b.b. of the components in pixaa)
00904  *      Return: pix, or null on error
00905  *
00906  *  Notes:
00907  *      (1) Each pix of the pixaa is displayed at the location given by
00908  *          its box, translated by the box of the containing pixa
00909  *          if it exists.
00910  */
00911 PIX *
00912 pixaaDisplay(PIXAA   *pixaa,
00913              l_int32  w,
00914              l_int32  h)
00915 {
00916 l_int32  i, j, n, nbox, na, d, wmax, hmax, x, y, xb, yb, wb, hb;
00917 BOXA    *boxa1;  /* top-level boxa */
00918 BOXA    *boxa;
00919 PIX     *pixt, *pixd;
00920 PIXA    *pixa;
00921 
00922     PROCNAME("pixaaDisplay");
00923 
00924     if (!pixaa)
00925         return (PIX *)ERROR_PTR("pixaa not defined", procName, NULL);
00926     
00927     n = pixaaGetCount(pixaa);
00928     if (n == 0)
00929         return (PIX *)ERROR_PTR("no components", procName, NULL);
00930 
00931         /* If w and h not input, determine the minimum size required
00932          * to contain the origin and all c.c. */
00933     boxa1 = pixaaGetBoxa(pixaa, L_CLONE);
00934     nbox = boxaGetCount(boxa1);
00935     if (w == 0 || h == 0) {
00936         if (nbox == n)
00937             boxaGetExtent(boxa1, &w, &h, NULL);
00938         else {  /* have to use the lower-level boxa for each pixa */
00939             wmax = hmax = 0;
00940             for (i = 0; i < n; i++) {
00941                 pixa = pixaaGetPixa(pixaa, i, L_CLONE);
00942                 boxa = pixaGetBoxa(pixa, L_CLONE);
00943                 boxaGetExtent(boxa, &w, &h, NULL);
00944                 wmax = L_MAX(wmax, w);
00945                 hmax = L_MAX(hmax, h);
00946                 pixaDestroy(&pixa);
00947                 boxaDestroy(&boxa);
00948             }
00949             w = wmax;
00950             h = hmax;
00951         }
00952     }
00953 
00954         /* Get depth from first pix */
00955     pixa = pixaaGetPixa(pixaa, 0, L_CLONE);
00956     pixt = pixaGetPix(pixa, 0, L_CLONE);
00957     d = pixGetDepth(pixt);
00958     pixaDestroy(&pixa);
00959     pixDestroy(&pixt);
00960 
00961     if ((pixd = pixCreate(w, h, d)) == NULL)
00962         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
00963     
00964     x = y = 0;
00965     for (i = 0; i < n; i++) {
00966         pixa = pixaaGetPixa(pixaa, i, L_CLONE);
00967         if (nbox == n)
00968             boxaGetBoxGeometry(boxa1, i, &x, &y, NULL, NULL);
00969         na = pixaGetCount(pixa);
00970         for (j = 0; j < na; j++) {
00971             pixaGetBoxGeometry(pixa, j, &xb, &yb, &wb, &hb);
00972             pixt = pixaGetPix(pixa, j, L_CLONE);
00973             pixRasterop(pixd, x + xb, y + yb, wb, hb, PIX_PAINT, pixt, 0, 0);
00974             pixDestroy(&pixt);
00975         }
00976         pixaDestroy(&pixa);
00977     }
00978     boxaDestroy(&boxa1);
00979 
00980     return pixd;
00981 }
00982 
00983 
00984 /*!
00985  *  pixaaDisplayByPixa()
00986  *
00987  *      Input:  pixaa
00988  *              xspace between pix in pixa
00989  *              yspace between pixa
00990  *              max width of output pix
00991  *      Return: pix, or null on error
00992  *
00993  *  Notes:
00994  *      (1) Displays each pixa on a line (or set of lines),
00995  *          in order from top to bottom.  Within each pixa,
00996  *          the pix are displayed in order from left to right.
00997  *      (2) The size of each pix in each pixa is assumed to be
00998  *          approximately equal to the size of the first pix in
00999  *          the pixa.  If this assumption is not correct, this
01000  *          function will not work properly.
01001  *      (3) This ignores the boxa of the pixaa.
01002  */
01003 PIX *
01004 pixaaDisplayByPixa(PIXAA   *pixaa,
01005                    l_int32  xspace,
01006                    l_int32  yspace,
01007                    l_int32  maxw)
01008 {
01009 l_int32  i, j, npixa, npix;
01010 l_int32  width, height, depth, nlines, lwidth;
01011 l_int32  x, y, w, h, w0, h0;
01012 PIX     *pixt, *pixd;
01013 PIXA    *pixa;
01014 
01015     PROCNAME("pixaaDisplayByPixa");
01016 
01017     if (!pixaa)
01018         return (PIX *)ERROR_PTR("pixaa not defined", procName, NULL);
01019     
01020     if ((npixa = pixaaGetCount(pixaa)) == 0)
01021         return (PIX *)ERROR_PTR("no components", procName, NULL);
01022 
01023         /* Get size of output pix.  The width is the minimum of the
01024          * maxw and the largest pixa line width.  The height is whatever
01025          * it needs to be to accommodate all pixa. */
01026     height = 2 * yspace;
01027     width = 0;
01028     for (i = 0; i < npixa; i++) {
01029         pixa = pixaaGetPixa(pixaa, i, L_CLONE);
01030         npix = pixaGetCount(pixa);
01031         pixt = pixaGetPix(pixa, 0, L_CLONE);
01032         if (i == 0)
01033             depth = pixGetDepth(pixt);
01034         w = pixGetWidth(pixt);
01035         lwidth = npix * (w + xspace);
01036         nlines = (lwidth + maxw - 1) / maxw;
01037         if (nlines > 1)
01038             width = maxw;
01039         else
01040             width = L_MAX(lwidth, width);
01041         height += nlines * (pixGetHeight(pixt) + yspace);
01042         pixDestroy(&pixt);
01043         pixaDestroy(&pixa);
01044     }
01045 
01046     if ((pixd = pixCreate(width, height, depth)) == NULL)
01047         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
01048 
01049         /* Now layout the pix by pixa */
01050     y = yspace;
01051     for (i = 0; i < npixa; i++) {
01052         x = 0;
01053         pixa = pixaaGetPixa(pixaa, i, L_CLONE);
01054         npix = pixaGetCount(pixa);
01055         for (j = 0; j < npix; j++) {
01056             pixt = pixaGetPix(pixa, j, L_CLONE);
01057             if (j == 0) {
01058                 w0 = pixGetWidth(pixt);
01059                 h0 = pixGetHeight(pixt);
01060             }
01061             w = pixGetWidth(pixt);
01062             if (width == maxw && x + w >= maxw) {
01063                 x = 0;
01064                 y += h0 + yspace;
01065             }
01066             h = pixGetHeight(pixt);
01067             pixRasterop(pixd, x, y, w, h, PIX_PAINT, pixt, 0, 0);
01068             pixDestroy(&pixt);
01069             x += w0 + xspace;
01070         }
01071         y += h0 + yspace;
01072         pixaDestroy(&pixa);
01073     }
01074 
01075     return pixd;
01076 }
01077 
01078 
01079 /*!
01080  *  pixaaDisplayTiledAndScaled()
01081  *
01082  *      Input:  pixaa
01083  *              outdepth (output depth: 1, 8 or 32 bpp)
01084  *              tilewidth (each pix is scaled to this width)
01085  *              ncols (number of tiles in each row)
01086  *              background (0 for white, 1 for black; this is the color
01087  *                 of the spacing between the images)
01088  *              spacing  (between images, and on outside)
01089  *              border (width of additional black border on each image;
01090  *                      use 0 for no border)
01091  *      Return: pixa (of tiled images, one image for each pixa in
01092  *                    the pixaa), or null on error
01093  *
01094  *  Notes:
01095  *      (1) For each pixa, this generates from all the pix a
01096  *          tiled/scaled output pix, and puts it in the output pixa.
01097  *      (2) See comments in pixaDisplayTiledAndScaled().
01098  */
01099 PIXA *
01100 pixaaDisplayTiledAndScaled(PIXAA   *pixaa,
01101                            l_int32  outdepth,
01102                            l_int32  tilewidth,
01103                            l_int32  ncols,
01104                            l_int32  background,
01105                            l_int32  spacing,
01106                            l_int32  border)
01107 {
01108 l_int32  i, n;
01109 PIX     *pix;
01110 PIXA    *pixa, *pixad;
01111 
01112     PROCNAME("pixaaDisplayTiledAndScaled");
01113 
01114     if (!pixaa)
01115         return (PIXA *)ERROR_PTR("pixaa not defined", procName, NULL);
01116     if (outdepth != 1 && outdepth != 8 && outdepth != 32)
01117         return (PIXA *)ERROR_PTR("outdepth not in {1, 8, 32}", procName, NULL);
01118     if (border < 0 || border > tilewidth / 5)
01119         border = 0;
01120     
01121     if ((n = pixaaGetCount(pixaa)) == 0)
01122         return (PIXA *)ERROR_PTR("no components", procName, NULL);
01123 
01124     pixad = pixaCreate(n);
01125     for (i = 0; i < n; i++) {
01126         pixa = pixaaGetPixa(pixaa, i, L_CLONE);
01127         pix = pixaDisplayTiledAndScaled(pixa, outdepth, tilewidth, ncols,
01128                                         background, spacing, border);
01129         pixaAddPix(pixad, pix, L_INSERT);
01130         pixaDestroy(&pixa);
01131     }
01132 
01133     return pixad;
01134 }
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines