Leptonica 1.68
C Image Processing Library
|
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 }