Leptonica 1.68
C Image Processing Library

bmf.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 /*
00018  *  bmf.c
00019  *
00020  *   Acquisition and generation of bitmap fonts.
00021  *
00022  *       L_BMF           *bmfCreate()
00023  *       L_BMF           *bmfDestroy()
00024  *
00025  *       PIX             *bmfGetPix()
00026  *       l_int32          bmfGetWidth()
00027  *       l_int32          bmfGetBaseline()
00028  *
00029  *       PIXA            *pixaGetFont()
00030  *       l_int32          pixaSaveFont()
00031  *       PIXA            *pixaGenerateFont()
00032  *       static l_int32   pixGetTextBaseline()
00033  *       static l_int32   bmfMakeAsciiTables()
00034  *
00035  *   This is not a very general utility, because it only uses bitmap
00036  *   representations of a single font, Palatino-Roman, with the
00037  *   normal style.  It uses bitmaps generated for nine sizes, from
00038  *   4 to 20 pts, rendered at 300 ppi.  Generalization to different
00039  *   fonts, styles and sizes is straightforward.
00040  *
00041  *   I chose Palatino-Roman is because I like it.
00042  *   The input font images were generated from a set of small
00043  *   PostScript files, such as chars-12.ps, which were rendered
00044  *   into the inputfont[] bitmap files using GhostScript.  See, for
00045  *   example, the bash script prog/ps2tiff, which will "rip" a
00046  *   PostScript file into a set of ccitt-g4 compressed tiff files.
00047  *
00048  *   The set of ascii characters from 32 through 126 are the 95
00049  *   printable ascii chars.  Palatino-Roman is missing char 92, '\'.
00050  *   I have substituted '/', char 47, for 92, so that there will be
00051  *   no missing printable chars in this set.  The space is char 32,
00052  *   and I have given it a width equal to twice the width of '!'.
00053  */
00054 
00055 #include "allheaders.h"
00056 
00057 #define  NFONTS  9
00058 static const char  *inputfonts[] = {"chars-4.tif", "chars-6.tif",
00059                                     "chars-8.tif", "chars-10.tif",
00060                                     "chars-12.tif", "chars-14.tif",
00061                                     "chars-16.tif", "chars-18.tif",
00062                                     "chars-20.tif"};
00063 static const char  *outputfonts[] = {"chars-4.pixa", "chars-6.pixa",
00064                                      "chars-8.pixa", "chars-10.pixa",
00065                                      "chars-12.pixa", "chars-14.pixa",
00066                                      "chars-16.pixa", "chars-18.pixa",
00067                                      "chars-20.pixa"};
00068 static const l_int32 baselines[NFONTS][3] = {{11, 12, 12}, {18, 18, 18},
00069                                              {24, 24, 24}, {30, 30, 30},
00070                                              {36, 36, 36}, {42, 42, 42},
00071                                              {48, 48, 48}, {54, 54, 54},
00072                                              {60, 60, 60}};
00073 static const l_float32  VERT_FRACT_SEP = 0.3;
00074 
00075 #ifndef  NO_CONSOLE_IO
00076 #define  DEBUG_BASELINE     0
00077 #define  DEBUG_CHARS        0
00078 #define  DEBUG_FONT_GEN     0
00079 #endif  /* ~NO_CONSOLE_IO */
00080 
00081 static l_int32 pixGetTextBaseline(PIX *pixs, l_int32 *tab8, l_int32 *py);
00082 static l_int32 bmfMakeAsciiTables(L_BMF *bmf);
00083 
00084 
00085 /*---------------------------------------------------------------------*/
00086 /*                           Bmf create/destroy                        */
00087 /*---------------------------------------------------------------------*/
00088 /*!
00089  *  bmfCreate()
00090  *
00091  *      Input:  dir (directory holding pixa of character set)
00092  *              size (4, 6, 8, ... , 20)
00093  *      Return: bmf (holding the bitmap font and associated information)
00094  *
00095  *  Notes:
00096  *      (1) This first tries to read a pre-computed pixa file with the
00097  *          95 ascii chars in it.  If the file is not found, it
00098  *          creates the pixa from the raw image.  It then generates all 
00099  *          associated data required to use the bmf.
00100  */
00101 L_BMF *
00102 bmfCreate(const char  *dir,
00103           l_int32      size)
00104 {
00105 L_BMF   *bmf;
00106 PIXA  *pixa;
00107 
00108     PROCNAME("bmfCreate");
00109 
00110     if ((bmf = (L_BMF *)CALLOC(1, sizeof(L_BMF))) == NULL)
00111         return (L_BMF *)ERROR_PTR("bmf not made", procName, NULL);
00112 
00113         /* Look for the pixa */
00114     pixa = pixaGetFont(dir, size, &bmf->baseline1, &bmf->baseline2,
00115                        &bmf->baseline3);
00116 
00117         /* If not found, make it */
00118     if (!pixa) {
00119         L_INFO("Generating pixa of bitmap fonts", procName);
00120         pixa = pixaGenerateFont(dir, size, &bmf->baseline1, &bmf->baseline2,
00121                                 &bmf->baseline3);
00122         if (!pixa) {
00123             bmfDestroy(&bmf);
00124             return (L_BMF *)ERROR_PTR("font pixa not made", procName, NULL);
00125         }
00126     }
00127 
00128     bmf->pixa = pixa;
00129     bmf->size = size;
00130     bmf->directory = stringNew(dir);
00131     bmfMakeAsciiTables(bmf);
00132     return bmf;
00133 }
00134 
00135 
00136 /*!
00137  *  bmfDestroy()
00138  *
00139  *      Input:  &bmf (<set to null>)
00140  *      Return: void
00141  */
00142 void
00143 bmfDestroy(L_BMF  **pbmf)
00144 {
00145 L_BMF  *bmf;
00146 
00147     PROCNAME("bmfDestroy");
00148 
00149     if (pbmf == NULL) {
00150         L_WARNING("ptr address is null!", procName);
00151         return;
00152     }
00153 
00154     if ((bmf = *pbmf) == NULL)
00155         return;
00156 
00157     pixaDestroy(&bmf->pixa);
00158     FREE(bmf->directory);
00159     FREE(bmf->fonttab);
00160     FREE(bmf->baselinetab);
00161     FREE(bmf->widthtab);
00162     FREE(bmf);
00163     *pbmf = NULL;
00164     return;
00165 }
00166 
00167 
00168 /*---------------------------------------------------------------------*/
00169 /*                             Bmf accessors                           */
00170 /*---------------------------------------------------------------------*/
00171 /*!
00172  *  bmfGetPix()
00173  *
00174  *      Input:  bmf
00175  *              chr (should be one of the 95 supported printable bitmaps)
00176  *      Return: pix (clone of pix in bmf), or null on error
00177  */
00178 PIX *
00179 bmfGetPix(L_BMF  *bmf,
00180           char    chr)
00181 {
00182 l_int32  i, index;
00183 PIXA    *pixa;
00184 
00185     PROCNAME("bmfGetPix");
00186 
00187     if ((index = (l_int32)chr) == 10)  /* NL */
00188         return NULL;
00189     if (!bmf)
00190         return (PIX *)ERROR_PTR("bmf not defined", procName, NULL);
00191 
00192     i = bmf->fonttab[index];
00193     if (i == UNDEF) {
00194         L_ERROR_INT("no bitmap representation for %d", procName, index);
00195         return NULL;
00196     }
00197 
00198     if ((pixa = bmf->pixa) == NULL)
00199         return (PIX *)ERROR_PTR("pixa not found", procName, NULL);
00200     return pixaGetPix(pixa, i, L_CLONE);
00201 }
00202 
00203 
00204 /*!
00205  *  bmfGetWidth()
00206  *
00207  *      Input:  bmf
00208  *              chr (should be one of the 95 supported bitmaps)
00209  *              &w (<return> character width; -1 if not printable)
00210  *      Return: 0 if OK, 1 on error
00211  */
00212 l_int32
00213 bmfGetWidth(L_BMF    *bmf,
00214             char      chr,
00215             l_int32  *pw)
00216 {
00217 l_int32  i, index;
00218 PIX     *pix;
00219 PIXA    *pixa;
00220 
00221     PROCNAME("bmfGetWidth");
00222 
00223     if (!pw)
00224         return ERROR_INT("&w not defined", procName, 1);
00225     *pw = -1;
00226     if (!bmf)
00227         return ERROR_INT("bmf not defined", procName, 1);
00228     if ((index = (l_int32)chr) == 10)  /* NL */
00229         return 0;
00230 
00231     i = bmf->fonttab[index];
00232     if (i == UNDEF) {
00233         L_ERROR_INT("no bitmap representation for %d", procName, index);
00234         return 1;
00235     }
00236 
00237     if ((pixa = bmf->pixa) == NULL)
00238         return ERROR_INT("pixa not found", procName, 1);
00239     if ((pix = pixaGetPix(pixa, i, L_CLONE)) == NULL)
00240         return ERROR_INT("pix not found", procName, 1);
00241     *pw = pixGetWidth(pix);
00242     pixDestroy(&pix);
00243 
00244     return 0;
00245 }
00246 
00247 
00248 /*!
00249  *  bmfGetBaseline()
00250  *
00251  *      Input:  bmf
00252  *              chr (should be one of the 95 supported bitmaps)
00253  *              &baseline (<return>; distance below UL corner of bitmap char)
00254  *      Return: 0 if OK, 1 on error
00255  */
00256 l_int32
00257 bmfGetBaseline(L_BMF    *bmf,
00258                char      chr,
00259                l_int32  *pbaseline)
00260 {
00261 l_int32  bl, index;
00262 
00263     PROCNAME("bmfGetBaseline");
00264 
00265     if (!pbaseline)
00266         return ERROR_INT("&baseline not defined", procName, 1);
00267     *pbaseline = 0;
00268     if (!bmf)
00269         return ERROR_INT("bmf not defined", procName, 1);
00270     if ((index = (l_int32)chr) == 10)  /* NL */
00271         return 0;
00272 
00273     bl = bmf->baselinetab[index];
00274     if (bl == UNDEF) {
00275         L_ERROR_INT("no bitmap representation for %d", procName, index);
00276         return 1;
00277     }
00278 
00279     *pbaseline = bl;
00280     return 0;
00281 }
00282 
00283 
00284 /*---------------------------------------------------------------------*/
00285 /*               Font bitmap acquisition and generation                */
00286 /*---------------------------------------------------------------------*/
00287 /*!
00288  *  pixaGetFont()
00289  *
00290  *      Input:  dir (directory holding pixa of character set)
00291  *              size (4, 6, 8, ... , 20)
00292  *              &bl1 (<return> baseline of row 1)
00293  *              &bl2 (<return> baseline of row 2)
00294  *              &bl3 (<return> baseline of row 3)
00295  *      Return: pixa of font bitmaps for 95 characters, or null on error
00296  *
00297  *  Notes:
00298  *      (1) This reads a pre-computed pixa file with the 95 ascii chars.
00299  */
00300 PIXA *
00301 pixaGetFont(const char  *dir,
00302             l_int32      size,
00303             l_int32     *pbl0,
00304             l_int32     *pbl1,
00305             l_int32     *pbl2)
00306 {
00307 char     *pathname;
00308 l_int32   fileno;
00309 PIXA     *pixa;
00310 
00311     PROCNAME("pixaGetFont");
00312 
00313     fileno = (size / 2) - 2;
00314     if (fileno < 0 || fileno > NFONTS)
00315         return (PIXA *)ERROR_PTR("font size invalid", procName, NULL);
00316     if (!pbl0 || !pbl1 || !pbl2)
00317         return (PIXA *)ERROR_PTR("&bl not all defined", procName, NULL);
00318     *pbl0 = baselines[fileno][0];
00319     *pbl1 = baselines[fileno][1];
00320     *pbl2 = baselines[fileno][2];
00321 
00322     pathname = genPathname(dir, outputfonts[fileno]);
00323     pixa = pixaRead(pathname);
00324     FREE(pathname);
00325 
00326     if (!pixa)
00327         L_WARNING("pixa of char bitmaps not found", procName);
00328     return pixa;
00329 }
00330 
00331 
00332 /*!
00333  *  pixaSaveFont()
00334  *
00335  *      Input:  indir (directory holding image of character set)
00336  *              outdir (directory into which the output pixa file
00337  *                      will be written)
00338  *              size (in pts, at 300 ppi)
00339  *      Return: 0 if OK, 1 on error
00340  *
00341  *  Notes:
00342  *      (1) This saves a font of a particular size.
00343  *      (2) prog/genfonts calls this function for each of the
00344  *          nine font sizes, to generate all the font pixa files.
00345  */
00346 l_int32
00347 pixaSaveFont(const char  *indir,
00348              const char  *outdir,
00349              l_int32      size)
00350 {
00351 char    *pathname;
00352 l_int32  bl1, bl2, bl3;
00353 PIXA    *pixa;
00354 
00355     PROCNAME("pixaSaveFont");
00356 
00357     if (size < 4 || size > 20 || (size % 2))
00358         return ERROR_INT("size must be in {4, 6, ..., 20}", procName, 1);
00359 
00360     if ((pixa = pixaGenerateFont(indir, size, &bl1, &bl2, &bl3)) == NULL)
00361         return ERROR_INT("pixa not made", procName, 1);
00362     pathname = genPathname(outdir, outputfonts[(size - 4) / 2]);
00363     pixaWrite(pathname, pixa);
00364 
00365 #if  DEBUG_FONT_GEN
00366     fprintf(stderr, "Found %d chars in font size %d\n",
00367             pixaGetCount(pixa), size);
00368     fprintf(stderr, "Baselines are at: %d, %d, %d\n", bl1, bl2, bl3);
00369 #endif  /* DEBUG_FONT_GEN */
00370 
00371     FREE(pathname);
00372     pixaDestroy(&pixa);
00373     return 0;
00374 }
00375 
00376 
00377 /*!
00378  *  pixaGenerateFont()
00379  *
00380  *      Input:  dir (directory holding image of character set)
00381  *              size (4, 6, 8, ... , 20, in pts at 300 ppi)
00382  *              &bl1 (<return> baseline of row 1)
00383  *              &bl2 (<return> baseline of row 2)
00384  *              &bl3 (<return> baseline of row 3)
00385  *      Return: pixa of font bitmaps for 95 characters, or null on error
00386  *
00387  *  These font generation functions use 9 sets, each with bitmaps
00388  *  of 94 ascii characters, all in Palatino-Roman font.
00389  *  Each input bitmap has 3 rows of characters.  The range of
00390  *  ascii values in each row is as follows:
00391  *    row 0:  32-57   (32 is a space)
00392  *    row 1:  58-91   (92, '\', is not represented in this font)
00393  *    row 2:  93-126 
00394  *  We LR flip the '/' char to generate a bitmap for the missing
00395  *  '\' character, so that we have representations of all 95
00396  *  printable chars.
00397  *
00398  *  Computation of the bitmaps and baselines for a single
00399  *  font takes from 40 to 200 msec on a 2 GHz processor,
00400  *  depending on the size.  Use pixaGetFont() to read the
00401  *  generated character set directly from files that were
00402  *  produced in prog/genfonts.c using this function.
00403  */
00404 PIXA *
00405 pixaGenerateFont(const char  *dir,
00406                  l_int32      size,
00407                  l_int32     *pbl0,
00408                  l_int32     *pbl1,
00409                  l_int32     *pbl2)
00410 {
00411 char     *pathname;
00412 l_int32   fileno;
00413 l_int32   i, j, nrows, nrowchars, nchars, h, yval;
00414 l_int32   width, height;
00415 l_int32   baseline[3];
00416 l_int32  *tab;
00417 BOX      *box, *box1, *box2;
00418 BOXA     *boxar, *boxac, *boxacs;
00419 PIX      *pixs, *pixt1, *pixt2, *pixt3;
00420 PIX      *pixr, *pixrc, *pixc;
00421 PIXA     *pixa;
00422 
00423     PROCNAME("pixaGenerateFont");
00424 
00425     if (!pbl0 || !pbl1 || !pbl2)
00426         return (PIXA *)ERROR_PTR("&bl not all defined", procName, NULL);
00427     *pbl0 = *pbl1 = *pbl2 = 0;
00428 
00429     fileno = (size / 2) - 2;
00430     if (fileno < 0 || fileno > NFONTS)
00431         return (PIXA *)ERROR_PTR("font size invalid", procName, NULL);
00432     tab = makePixelSumTab8();
00433     pathname = genPathname(dir, inputfonts[fileno]);
00434     if ((pixs = pixRead(pathname)) == NULL)
00435         return (PIXA *)ERROR_PTR("pixs not all defined", procName, NULL);
00436     FREE(pathname);
00437 
00438     pixa = pixaCreate(95);
00439     pixt1 = pixMorphSequence(pixs, "c1.35 + c101.1", 0);
00440     boxar = pixConnComp(pixt1, NULL, 8);  /* one box for each row */
00441     pixDestroy(&pixt1);
00442     nrows = boxaGetCount(boxar);
00443 #if  DEBUG_FONT_GEN
00444     fprintf(stderr, "For font %s, number of rows is %d\n",
00445             inputfonts[fileno], nrows);
00446 #endif  /* DEBUG_FONT_GEN */
00447     if (nrows != 3) {
00448         L_INFO_INT2("nrows = %d; skipping font %d", procName, nrows, fileno);
00449         return (PIXA *)ERROR_PTR("3 rows not generated", procName, NULL);
00450     }
00451     for (i = 0; i < nrows; i++) {
00452         box = boxaGetBox(boxar, i, L_CLONE);
00453         pixr = pixClipRectangle(pixs, box, NULL);  /* row of chars */
00454         pixGetTextBaseline(pixr, tab, &yval);
00455         baseline[i] = yval;
00456 
00457 #if DEBUG_BASELINE
00458       { PIX *pixbl;
00459         fprintf(stderr, "row %d, yval = %d, h = %d\n",
00460                 i, yval, pixGetHeight(pixr));
00461         pixbl = pixCopy(NULL, pixr);
00462         pixRenderLine(pixbl, 0, yval, pixGetWidth(pixbl), yval, 1,
00463                       L_FLIP_PIXELS);
00464         if (i == 0 )
00465             pixWrite("junktl0", pixbl, IFF_PNG);
00466         else if (i == 1)
00467             pixWrite("junktl1", pixbl, IFF_PNG);
00468         else
00469             pixWrite("junktl2", pixbl, IFF_PNG);
00470         pixDestroy(&pixbl);
00471       }
00472 #endif  /* DEBUG_BASELINE */
00473 
00474         boxDestroy(&box);
00475         pixrc = pixCloseSafeBrick(NULL, pixr, 1, 35);
00476         boxac = pixConnComp(pixrc, NULL, 8);
00477         boxacs = boxaSort(boxac, L_SORT_BY_X, L_SORT_INCREASING, NULL);
00478         if (i == 0) {  /* consolidate the two components of '"' */
00479             box1 = boxaGetBox(boxacs, 1, L_CLONE);
00480             box2 = boxaGetBox(boxacs, 2, L_CLONE);
00481             box1->w = box2->x + box2->w - box1->x;  /* increase width */
00482             boxDestroy(&box1);
00483             boxDestroy(&box2);
00484             boxaRemoveBox(boxacs, 2);
00485         }
00486         h = pixGetHeight(pixr);
00487         nrowchars = boxaGetCount(boxacs);
00488         for (j = 0; j < nrowchars; j++) {
00489             box = boxaGetBox(boxacs, j, L_COPY);
00490             if (box->w <= 2 && box->h == 1) {  /* skip 1x1, 2x1 components */
00491                 boxDestroy(&box);
00492                 continue;
00493             }
00494             box->y = 0;
00495             box->h = h - 1;
00496             pixc = pixClipRectangle(pixr, box, NULL);
00497             boxDestroy(&box);
00498             if (i == 0 && j == 0)  /* add a pix for the space; change later */
00499                 pixaAddPix(pixa, pixc, L_COPY);
00500             if (i == 2 && j == 0)  /* add a pix for the '\'; change later */
00501                 pixaAddPix(pixa, pixc, L_COPY);
00502             pixaAddPix(pixa, pixc, L_INSERT);
00503         }
00504         pixDestroy(&pixr);
00505         pixDestroy(&pixrc);
00506         boxaDestroy(&boxac);
00507         boxaDestroy(&boxacs);
00508     }
00509 
00510     nchars = pixaGetCount(pixa);
00511     if (nchars != 95)
00512         return (PIXA *)ERROR_PTR("95 chars not generated", procName, NULL);
00513 
00514     *pbl0 = baseline[0];
00515     *pbl1 = baseline[1];
00516     *pbl2 = baseline[2];
00517         
00518         /* Fix the space character up; it should have no ON pixels,
00519          * and be about twice as wide as the '!' character.    */
00520     pixt2 = pixaGetPix(pixa, 0, L_CLONE);
00521     width = 2 * pixGetWidth(pixt2);
00522     height = pixGetHeight(pixt2);
00523     pixDestroy(&pixt2);
00524     pixt2 = pixCreate(width, height, 1);
00525     pixaReplacePix(pixa, 0, pixt2, NULL);
00526 
00527         /* Fix up the '\' character; use a LR flip of the '/' char */
00528     pixt2 = pixaGetPix(pixa, 15, L_CLONE);
00529     pixt3 = pixFlipLR(NULL, pixt2);
00530     pixDestroy(&pixt2);
00531     pixaReplacePix(pixa, 60, pixt3, NULL);
00532     
00533 #if DEBUG_CHARS
00534   { PIX *pixd;
00535     pixd = pixaDisplayTiled(pixa, 1500, 0, 10);
00536     pixDisplay(pixd, 100 * i, 200);
00537     pixDestroy(&pixd);
00538   }
00539 #endif  /* DEBUG_CHARS */
00540 
00541     pixDestroy(&pixs);
00542     boxaDestroy(&boxar);
00543     FREE(tab);
00544 
00545     return pixa;
00546 }
00547 
00548 
00549 /*!
00550  *  pixGetTextBaseline()
00551  *
00552  *      Input:  pixs (1 bpp, one textline character set)
00553  *              tab8 (<optional> pixel sum table)
00554  *              &y   (<return> baseline value)
00555  *      Return: 0 if OK, 1 on error
00556  *
00557  *  Notes:
00558  *      (1) Method: find the largest difference in pixel sums from one
00559  *          raster line to the next one below it.  The baseline is the
00560  *          upper raster line for the pair of raster lines that
00561  *          maximizes this function.
00562  */
00563 static l_int32
00564 pixGetTextBaseline(PIX      *pixs,
00565                    l_int32  *tab8,
00566                    l_int32  *py)
00567 {
00568 l_int32   i, h, val1, val2, diff, diffmax, ymax;
00569 l_int32  *tab;
00570 NUMA     *na;
00571 
00572     PROCNAME("pixGetTextBaseline");
00573 
00574     if (!pixs)
00575         return ERROR_INT("pixs not defined", procName, 1);
00576     if (!py)
00577         return ERROR_INT("&y not defined", procName, 1);
00578     *py = 0;
00579     if (!tab8)
00580         tab = makePixelSumTab8();
00581     else
00582         tab = tab8;
00583 
00584     na = pixCountPixelsByRow(pixs, tab);
00585     h = numaGetCount(na);
00586     diffmax = 0;
00587     ymax = 0;
00588     for (i = 1; i < h; i++) {
00589         numaGetIValue(na, i - 1, &val1);
00590         numaGetIValue(na, i, &val2);
00591         diff = L_MAX(0, val1 - val2);
00592         if (diff > diffmax) {
00593             diffmax = diff;
00594             ymax = i - 1;  /* upper raster line */
00595         }
00596     }
00597     *py = ymax;
00598 
00599     if (!tab8)
00600         FREE(tab);
00601     numaDestroy(&na);
00602     return 0;
00603 }
00604 
00605 
00606 /*!
00607  *  bmfMakeAsciiTables
00608  *
00609  *      Input:  bmf
00610  *      Return: 0 if OK, 1 on error
00611  *
00612  *  Notes:
00613  *      (1) This makes three tables, each of size 128, as follows:
00614  *          - fonttab is a table containing the index of the Pix
00615  *            that corresponds to each input ascii character;
00616  *            it maps (ascii-index) --> Pixa index
00617  *          - baselinetab is a table containing the baseline offset
00618  *            for the Pix that corresponds to each input ascii character;
00619  *            it maps (ascii-index) --> baseline offset
00620  *          - widthtab is a table containing the character width in
00621  *            pixels for the Pix that corresponds to that character;
00622  *            it maps (ascii-index) --> bitmap width
00623  *     (2) This also computes
00624  *          - lineheight (sum of maximum character extensions above and
00625  *                        below the baseline)
00626  *          - kernwidth (spacing between characters within a word)
00627  *          - spacewidth (space between words)
00628  *          - vertlinesep (extra vertical spacing between textlines)
00629  *     (3) The baselines apply as follows:
00630  *          baseline1   (ascii 32 - 57), ascii 92
00631  *          baseline2   (ascii 58 - 91)
00632  *          baseline3   (ascii 93 - 126)
00633  *     (4) The only array in bmf that is not ascii-based is the
00634  *         array of bitmaps in the pixa, which starts at ascii 32.
00635  */
00636 static l_int32
00637 bmfMakeAsciiTables(L_BMF  *bmf)
00638 {
00639 l_int32   i, maxh, height, charwidth, xwidth, kernwidth;
00640 l_int32  *fonttab, *baselinetab, *widthtab;
00641 PIX      *pix;
00642 
00643     PROCNAME("bmfMakeAsciiTables");
00644 
00645     if (!bmf)
00646         return ERROR_INT("bmf not defined", procName, 1);
00647 
00648         /* First get the fonttab; we use this later for the char widths */
00649     if ((fonttab = (l_int32 *)CALLOC(128, sizeof(l_int32))) == NULL)
00650         return ERROR_INT("fonttab not made", procName, 1);
00651     bmf->fonttab = fonttab;        
00652     for (i = 0; i < 128; i++)
00653         fonttab[i] = UNDEF;
00654     for (i = 32; i < 127; i++)
00655         fonttab[i] = i - 32;
00656 
00657     if ((baselinetab = (l_int32 *)CALLOC(128, sizeof(l_int32))) == NULL)
00658         return ERROR_INT("baselinetab not made", procName, 1);
00659     bmf->baselinetab = baselinetab;        
00660     for (i = 0; i < 128; i++)
00661         baselinetab[i] = UNDEF;
00662     for (i = 32; i <= 57; i++)
00663         baselinetab[i] = bmf->baseline1;
00664     for (i = 58; i <= 91; i++)
00665         baselinetab[i] = bmf->baseline2;
00666     baselinetab[92] = bmf->baseline1;  /* the '\' char */
00667     for (i = 93; i < 127; i++)
00668         baselinetab[i] = bmf->baseline3;
00669 
00670         /* Generate array of character widths; req's fonttab to exist */
00671     if ((widthtab = (l_int32 *)CALLOC(128, sizeof(l_int32))) == NULL)
00672         return ERROR_INT("widthtab not made", procName, 1);
00673     bmf->widthtab = widthtab;        
00674     for (i = 0; i < 128; i++)
00675         widthtab[i] = UNDEF;
00676     for (i = 32; i < 127; i++) {
00677         bmfGetWidth(bmf, i, &charwidth);
00678         widthtab[i] = charwidth;
00679     }
00680 
00681         /* Get the line height of text characters, from the highest
00682          * ascender to the lowest descender; req's fonttab to exist. */
00683     pix =  bmfGetPix(bmf, 32);
00684     maxh =  pixGetHeight(pix);
00685     pixDestroy(&pix);
00686     pix =  bmfGetPix(bmf, 58);
00687     height =  pixGetHeight(pix);
00688     pixDestroy(&pix);
00689     maxh = L_MAX(maxh, height);
00690     pix =  bmfGetPix(bmf, 93);
00691     height =  pixGetHeight(pix);
00692     pixDestroy(&pix);
00693     maxh = L_MAX(maxh, height);
00694     bmf->lineheight = maxh;
00695 
00696         /* Get the kern width (distance between characters).
00697          * We let it be the same for all characters in a given
00698          * font size, and scale it linearly with the size; 
00699          * req's fonttab to be built first. */
00700     bmfGetWidth(bmf, 120, &xwidth);
00701     kernwidth = (l_int32)(0.08 * (l_float32)xwidth + 0.5);
00702     bmf->kernwidth = L_MAX(1, kernwidth);
00703 
00704         /* Save the space width (between words) */
00705     bmfGetWidth(bmf, 32, &charwidth);
00706     bmf->spacewidth = charwidth;
00707 
00708         /* Save the extra vertical space between lines */
00709     bmf->vertlinesep = (l_int32)(VERT_FRACT_SEP * bmf->lineheight + 0.5);
00710 
00711     return 0;
00712 }
00713 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines