src/bmf.c
PIXA *
pixaGenerateFont(const char  *dir,
                 l_int32      size,
                 l_int32     *pbl0,
                 l_int32     *pbl1,
                 l_int32     *pbl2)
{
char     *pathname;
l_int32   fileno;
l_int32   i, j, nrows, nrowchars, nchars, h, yval;
l_int32   width, height;
l_int32   baseline[3];
l_int32  *tab;
BOX      *box, *box1, *box2;
BOXA     *boxar, *boxac, *boxacs;
PIX      *pixs, *pixt1, *pixt2, *pixt3;
PIX      *pixr, *pixrc, *pixc;
PIXA     *pixa;

    PROCNAME("pixaGenerateFont");

    if (!pbl0 || !pbl1 || !pbl2)
        return (PIXA *)ERROR_PTR("&bl not all defined", procName, NULL);
    *pbl0 = *pbl1 = *pbl2 = 0;

    fileno = (size / 2) - 2;
    if (fileno < 0 || fileno > NFONTS)
        return (PIXA *)ERROR_PTR("font size invalid", procName, NULL);
    tab = makePixelSumTab8();
    pathname = genPathname(dir, inputfonts[fileno]);
    if ((pixs = pixRead(pathname)) == NULL)
        return (PIXA *)ERROR_PTR("pixs not all defined", procName, NULL);
    FREE(pathname);

    pixa = pixaCreate(95);
    pixt1 = pixMorphSequence(pixs, "c1.35 + c101.1", 0);
    boxar = pixConnComp(pixt1, NULL, 8);  /* one box for each row */
    pixDestroy(&pixt1);
    nrows = boxaGetCount(boxar);
#if  DEBUG_FONT_GEN
    fprintf(stderr, "For font %s, number of rows is %d\n",
            inputfonts[fileno], nrows);
#endif  /* DEBUG_FONT_GEN */
    if (nrows != 3) {
        L_INFO_INT2("nrows = %d; skipping font %d", procName, nrows, fileno);
        return (PIXA *)ERROR_PTR("3 rows not generated", procName, NULL);
    }
    for (i = 0; i < nrows; i++) {
        box = boxaGetBox(boxar, i, L_CLONE);
        pixr = pixClipRectangle(pixs, box, NULL);  /* row of chars */
        pixGetTextBaseline(pixr, tab, &yval);
        baseline[i] = yval;

#if DEBUG_BASELINE
      { PIX *pixbl;
        fprintf(stderr, "row %d, yval = %d, h = %d\n",
                i, yval, pixGetHeight(pixr));
        pixbl = pixCopy(NULL, pixr);
        pixRenderLine(pixbl, 0, yval, pixGetWidth(pixbl), yval, 1,
                      L_FLIP_PIXELS);
        if (i == 0 )
            pixWrite("junktl0", pixbl, IFF_PNG);
        else if (i == 1)
            pixWrite("junktl1", pixbl, IFF_PNG);
        else
            pixWrite("junktl2", pixbl, IFF_PNG);
        pixDestroy(&pixbl);
      }
#endif  /* DEBUG_BASELINE */

        boxDestroy(&box);
        pixrc = pixCloseSafeBrick(NULL, pixr, 1, 35);
        boxac = pixConnComp(pixrc, NULL, 8);
        boxacs = boxaSort(boxac, L_SORT_BY_X, L_SORT_INCREASING, NULL);
        if (i == 0) {  /* consolidate the two components of '"' */
            box1 = boxaGetBox(boxacs, 1, L_CLONE);
            box2 = boxaGetBox(boxacs, 2, L_CLONE);
            box1->w = box2->x + box2->w - box1->x;  /* increase width */
            boxDestroy(&box1);
            boxDestroy(&box2);
            boxaRemoveBox(boxacs, 2);
        }
        h = pixGetHeight(pixr);
        nrowchars = boxaGetCount(boxacs);
        for (j = 0; j < nrowchars; j++) {
            box = boxaGetBox(boxacs, j, L_COPY);
            if (box->w <= 2 && box->h == 1) {  /* skip 1x1, 2x1 components */
                boxDestroy(&box);
                continue;
            }
            box->y = 0;
            box->h = h - 1;
            pixc = pixClipRectangle(pixr, box, NULL);
            boxDestroy(&box);
            if (i == 0 && j == 0)  /* add a pix for the space; change later */
                pixaAddPix(pixa, pixc, L_COPY);
            if (i == 2 && j == 0)  /* add a pix for the '\'; change later */
                pixaAddPix(pixa, pixc, L_COPY);
            pixaAddPix(pixa, pixc, L_INSERT);
        }
        pixDestroy(&pixr);
        pixDestroy(&pixrc);
        boxaDestroy(&boxac);
        boxaDestroy(&boxacs);
    }

    nchars = pixaGetCount(pixa);
    if (nchars != 95)
        return (PIXA *)ERROR_PTR("95 chars not generated", procName, NULL);

    *pbl0 = baseline[0];
    *pbl1 = baseline[1];
    *pbl2 = baseline[2];
        
        /* Fix the space character up; it should have no ON pixels,
         * and be about twice as wide as the '!' character.    */
    pixt2 = pixaGetPix(pixa, 0, L_CLONE);
    width = 2 * pixGetWidth(pixt2);
    height = pixGetHeight(pixt2);
    pixDestroy(&pixt2);
    pixt2 = pixCreate(width, height, 1);
    pixaReplacePix(pixa, 0, pixt2, NULL);

        /* Fix up the '\' character; use a LR flip of the '/' char */
    pixt2 = pixaGetPix(pixa, 15, L_CLONE);
    pixt3 = pixFlipLR(NULL, pixt2);
    pixDestroy(&pixt2);
    pixaReplacePix(pixa, 60, pixt3, NULL);
    
#if DEBUG_CHARS
  { PIX *pixd;
    pixd = pixaDisplayTiled(pixa, 1500, 0, 10);
    pixDisplay(pixd, 100 * i, 200);
    pixDestroy(&pixd);
  }
#endif  /* DEBUG_CHARS */

    pixDestroy(&pixs);
    boxaDestroy(&boxar);
    FREE(tab);

    return pixa;
}
/*!
 *  pixaGenerateFont()
 *
 *      Input:  dir (directory holding image of character set)
 *              size (4, 6, 8, ... , 20, in pts at 300 ppi)
 *              &bl1 (<return> baseline of row 1)
 *              &bl2 (<return> baseline of row 2)
 *              &bl3 (<return> baseline of row 3)
 *      Return: pixa of font bitmaps for 95 characters, or null on error
 *
 *  These font generation functions use 9 sets, each with bitmaps
 *  of 94 ascii characters, all in Palatino-Roman font.
 *  Each input bitmap has 3 rows of characters.  The range of
 *  ascii values in each row is as follows:
 *    row 0:  32-57   (32 is a space)
 *    row 1:  58-91   (92, '\', is not represented in this font)
 *    row 2:  93-126 
 *  We LR flip the '/' char to generate a bitmap for the missing
 *  '\' character, so that we have representations of all 95
 *  printable chars.
 *
 *  Computation of the bitmaps and baselines for a single
 *  font takes from 40 to 200 msec on a 2 GHz processor,
 *  depending on the size.  Use pixaGetFont() to read the
 *  generated character set directly from files that were
 *  produced in prog/genfonts.c using this function.
 */
pixaGenerateFont()
Input:  dir (directory holding image of character set)
size (4, 6, 8, ... , 20, in pts at 300 ppi)
&bl1 ( baseline of row 1)
&bl2 ( baseline of row 2)
&bl3 ( baseline of row 3)
Return: pixa of font bitmaps for 95 characters, or null on error

These font generation functions use 9 sets, each with bitmaps
of 94 ascii characters, all in Palatino-Roman font.
Each input bitmap has 3 rows of characters.

Computation of the bitmaps and baselines for a single
font takes from 40 to 200 msec on a 2 GHz processor,
depending on the size.  Use pixaGetFont() to read the
generated character set directly from files that were
produced in prog/genfonts.c using this function.
pixaGenerateFont () Input : dir ( directory holding image of character set ) size ( 4 6 8 ... 20 in pts at 300 ppi ) &bl1 ( baseline of row 1 ) &bl2 ( baseline of row 2 ) &bl3 ( baseline of row 3 ) Return : pixa of font bitmaps for 95 characters or null on error These font generation functions use 9 sets each with bitmaps of 94 ascii characters all in Palatino - Roman font . Each input bitmap has 3 rows of characters . Computation of the bitmaps and baselines for a single font takes from 40 to 200 msec on a 2 GHz processor depending on the size . Use pixaGetFont () to read the generated character set directly from files that were produced in prog / genfonts . c using this function .
PIXA *
pixaGenerateFont(const char  *dir,
                 l_int32      size,
                 l_int32     *pbl0,
                 l_int32     *pbl1,
                 l_int32     *pbl2)
{
char     *pathname;
l_int32   fileno;
l_int32   i, j, nrows, nrowchars, nchars, h, yval;
l_int32   width, height;
l_int32   baseline[3];
l_int32  *tab;
BOX      *box, *box1, *box2;
BOXA     *boxar, *boxac, *boxacs;
PIX      *pixs, *pixt1, *pixt2, *pixt3;
PIX      *pixr, *pixrc, *pixc;
PIXA     *pixa;
    PROCNAME("pixaGenerateFont");
    if (!pbl0 || !pbl1 || !pbl2)
        return (PIXA *)ERROR_PTR("&bl not all defined", procName, NULL);
    *pbl0 = *pbl1 = *pbl2 = 0;
    fileno = (size / 2) - 2;
    if (fileno < 0 || fileno > NFONTS)
        return (PIXA *)ERROR_PTR("font size invalid", procName, NULL);
    tab = makePixelSumTab8();
    pathname = genPathname(dir, inputfonts[fileno]);
    if ((pixs = pixRead(pathname)) == NULL)
        return (PIXA *)ERROR_PTR("pixs not all defined", procName, NULL);
    FREE(pathname);
    pixa = pixaCreate(95);
    pixt1 = pixMorphSequence(pixs, "c1.35 + c101.1", 0);
    boxar = pixConnComp(pixt1, NULL, 8);  
    pixDestroy(&pixt1);
    nrows = boxaGetCount(boxar);
#if  DEBUG_FONT_GEN
    fprintf(stderr, "For font %s, number of rows is %d\n",
            inputfonts[fileno], nrows);
#endif  
    if (nrows != 3) {
        L_INFO_INT2("nrows = %d; skipping font %d", procName, nrows, fileno);
        return (PIXA *)ERROR_PTR("3 rows not generated", procName, NULL);
    }
    for (i = 0; i < nrows; i++) {
        box = boxaGetBox(boxar, i, L_CLONE);
        pixr = pixClipRectangle(pixs, box, NULL);  
        pixGetTextBaseline(pixr, tab, &yval);
        baseline[i] = yval;
#if DEBUG_BASELINE
      { PIX *pixbl;
        fprintf(stderr, "row %d, yval = %d, h = %d\n",
                i, yval, pixGetHeight(pixr));
        pixbl = pixCopy(NULL, pixr);
        pixRenderLine(pixbl, 0, yval, pixGetWidth(pixbl), yval, 1,
                      L_FLIP_PIXELS);
        if (i == 0 )
            pixWrite("junktl0", pixbl, IFF_PNG);
        else if (i == 1)
            pixWrite("junktl1", pixbl, IFF_PNG);
        else
            pixWrite("junktl2", pixbl, IFF_PNG);
        pixDestroy(&pixbl);
      }
#endif  
        boxDestroy(&box);
        pixrc = pixCloseSafeBrick(NULL, pixr, 1, 35);
        boxac = pixConnComp(pixrc, NULL, 8);
        boxacs = boxaSort(boxac, L_SORT_BY_X, L_SORT_INCREASING, NULL);
        if (i == 0) {  
            box1 = boxaGetBox(boxacs, 1, L_CLONE);
            box2 = boxaGetBox(boxacs, 2, L_CLONE);
            box1->w = box2->x + box2->w - box1->x;  
            boxDestroy(&box1);
            boxDestroy(&box2);
            boxaRemoveBox(boxacs, 2);
        }
        h = pixGetHeight(pixr);
        nrowchars = boxaGetCount(boxacs);
        for (j = 0; j < nrowchars; j++) {
            box = boxaGetBox(boxacs, j, L_COPY);
            if (box->w <= 2 && box->h == 1) {  
                boxDestroy(&box);
                continue;
            }
            box->y = 0;
            box->h = h - 1;
            pixc = pixClipRectangle(pixr, box, NULL);
            boxDestroy(&box);
            if (i == 0 && j == 0)  
                pixaAddPix(pixa, pixc, L_COPY);
            if (i == 2 && j == 0)  
                pixaAddPix(pixa, pixc, L_COPY);
            pixaAddPix(pixa, pixc, L_INSERT);
        }
        pixDestroy(&pixr);
        pixDestroy(&pixrc);
        boxaDestroy(&boxac);
        boxaDestroy(&boxacs);
    }
    nchars = pixaGetCount(pixa);
    if (nchars != 95)
        return (PIXA *)ERROR_PTR("95 chars not generated", procName, NULL);
    *pbl0 = baseline[0];
    *pbl1 = baseline[1];
    *pbl2 = baseline[2];
    pixt2 = pixaGetPix(pixa, 0, L_CLONE);
    width = 2 * pixGetWidth(pixt2);
    height = pixGetHeight(pixt2);
    pixDestroy(&pixt2);
    pixt2 = pixCreate(width, height, 1);
    pixaReplacePix(pixa, 0, pixt2, NULL);
    pixt2 = pixaGetPix(pixa, 15, L_CLONE);
    pixt3 = pixFlipLR(NULL, pixt2);
    pixDestroy(&pixt2);
    pixaReplacePix(pixa, 60, pixt3, NULL);
#if DEBUG_CHARS
  { PIX *pixd;
    pixd = pixaDisplayTiled(pixa, 1500, 0, 10);
    pixDisplay(pixd, 100 * i, 200);
    pixDestroy(&pixd);
  }
#endif  
    pixDestroy(&pixs);
    boxaDestroy(&boxar);
    FREE(tab);
    return pixa;
}
PIXA * pixaGenerateFont ( const char * dir , l_int32 size , l_int32 * pbl0 , l_int32 * pbl1 , l_int32 * pbl2 ) { char * pathname ; l_int32 fileno ; l_int32 i , j , nrows , nrowchars , nchars , h , yval ; l_int32 width , height ; l_int32 baseline [ 3 ] ; l_int32 * tab ; BOX * box , * box1 , * box2 ; BOXA * boxar , * boxac , * boxacs ; PIX * pixs , * pixt1 , * pixt2 , * pixt3 ; PIX * pixr , * pixrc , * pixc ; PIXA * pixa ; PROCNAME ( " " ) ; if ( ! pbl0 || ! pbl1 || ! pbl2 ) return ( PIXA * ) ERROR_PTR ( " " , procName , NULL ) ; * pbl0 = * pbl1 = * pbl2 = 0 ; fileno = ( size / 2 ) - 2 ; if ( fileno < 0 || fileno > NFONTS ) return ( PIXA * ) ERROR_PTR ( " " , procName , NULL ) ; tab = makePixelSumTab8 ( ) ; pathname = genPathname ( dir , inputfonts [ fileno ] ) ; if ( ( pixs = pixRead ( pathname ) ) == NULL ) return ( PIXA * ) ERROR_PTR ( " " , procName , NULL ) ; FREE ( pathname ) ; pixa = pixaCreate ( 95 ) ; pixt1 = pixMorphSequence ( pixs , " " , 0 ) ; boxar = pixConnComp ( pixt1 , NULL , 8 ) ; pixDestroy ( & pixt1 ) ; nrows = boxaGetCount ( boxar ) ; #if DEBUG_FONT_GEN fprintf ( stderr , " \n " , inputfonts [ fileno ] , nrows ) ; #endif if ( nrows != 3 ) { L_INFO_INT2 ( " " , procName , nrows , fileno ) ; return ( PIXA * ) ERROR_PTR ( " " , procName , NULL ) ; } for ( i = 0 ; i < nrows ; i ++ ) { box = boxaGetBox ( boxar , i , L_CLONE ) ; pixr = pixClipRectangle ( pixs , box , NULL ) ; pixGetTextBaseline ( pixr , tab , & yval ) ; baseline [ i ] = yval ; #if DEBUG_BASELINE { PIX * pixbl ; fprintf ( stderr , " \n " , i , yval , pixGetHeight ( pixr ) ) ; pixbl = pixCopy ( NULL , pixr ) ; pixRenderLine ( pixbl , 0 , yval , pixGetWidth ( pixbl ) , yval , 1 , L_FLIP_PIXELS ) ; if ( i == 0 ) pixWrite ( " " , pixbl , IFF_PNG ) ; else if ( i == 1 ) pixWrite ( " " , pixbl , IFF_PNG ) ; else pixWrite ( " " , pixbl , IFF_PNG ) ; pixDestroy ( & pixbl ) ; } #endif boxDestroy ( & box ) ; pixrc = pixCloseSafeBrick ( NULL , pixr , 1 , 35 ) ; boxac = pixConnComp ( pixrc , NULL , 8 ) ; boxacs = boxaSort ( boxac , L_SORT_BY_X , L_SORT_INCREASING , NULL ) ; if ( i == 0 ) { box1 = boxaGetBox ( boxacs , 1 , L_CLONE ) ; box2 = boxaGetBox ( boxacs , 2 , L_CLONE ) ; box1 -> w = box2 -> x + box2 -> w - box1 -> x ; boxDestroy ( & box1 ) ; boxDestroy ( & box2 ) ; boxaRemoveBox ( boxacs , 2 ) ; } h = pixGetHeight ( pixr ) ; nrowchars = boxaGetCount ( boxacs ) ; for ( j = 0 ; j < nrowchars ; j ++ ) { box = boxaGetBox ( boxacs , j , L_COPY ) ; if ( box -> w <= 2 && box -> h == 1 ) { boxDestroy ( & box ) ; continue ; } box -> y = 0 ; box -> h = h - 1 ; pixc = pixClipRectangle ( pixr , box , NULL ) ; boxDestroy ( & box ) ; if ( i == 0 && j == 0 ) pixaAddPix ( pixa , pixc , L_COPY ) ; if ( i == 2 && j == 0 ) pixaAddPix ( pixa , pixc , L_COPY ) ; pixaAddPix ( pixa , pixc , L_INSERT ) ; } pixDestroy ( & pixr ) ; pixDestroy ( & pixrc ) ; boxaDestroy ( & boxac ) ; boxaDestroy ( & boxacs ) ; } nchars = pixaGetCount ( pixa ) ; if ( nchars != 95 ) return ( PIXA * ) ERROR_PTR ( " " , procName , NULL ) ; * pbl0 = baseline [ 0 ] ; * pbl1 = baseline [ 1 ] ; * pbl2 = baseline [ 2 ] ; pixt2 = pixaGetPix ( pixa , 0 , L_CLONE ) ; width = 2 * pixGetWidth ( pixt2 ) ; height = pixGetHeight ( pixt2 ) ; pixDestroy ( & pixt2 ) ; pixt2 = pixCreate ( width , height , 1 ) ; pixaReplacePix ( pixa , 0 , pixt2 , NULL ) ; pixt2 = pixaGetPix ( pixa , 15 , L_CLONE ) ; pixt3 = pixFlipLR ( NULL , pixt2 ) ; pixDestroy ( & pixt2 ) ; pixaReplacePix ( pixa , 60 , pixt3 , NULL ) ; #if DEBUG_CHARS { PIX * pixd ; pixd = pixaDisplayTiled ( pixa , 1500 , 0 , 10 ) ; pixDisplay ( pixd , 100 * i , 200 ) ; pixDestroy ( & pixd ) ; } #endif pixDestroy ( & pixs ) ; boxaDestroy ( & boxar ) ; FREE ( tab ) ; return pixa ; }
pixaGenerateFont()
      Input:  dir (directory holding image of character set)
              size (4, 6, 8, ... , 20, in pts at 300 ppi)
              &bl1 (<return> baseline of row 1)
              &bl2 (<return> baseline of row 2)
              &bl3 (<return> baseline of row 3)
      Return: pixa of font bitmaps for 95 characters, or null on error
pixaGenerateFont () Input : dir ( directory holding image of character set ) size ( 4 6 8 ... 20 in pts at 300 ppi ) &bl1 ( <return > baseline of row 1 ) &bl2 ( <return > baseline of row 2 ) &bl3 ( <return > baseline of row 3 ) Return : pixa of font bitmaps for 95 characters or null on error
/* one box for each row */ /* DEBUG_FONT_GEN */ /* row of chars */ /* DEBUG_BASELINE */ /* consolidate the two components of '"' */ /* increase width */ /* skip 1x1, 2x1 components */ /* add a pix for the space; change later */ /* add a pix for the '\'; change later */ /* Fix the space character up; it should have no ON pixels,
         * and be about twice as wide as the '!' character.    */ /* Fix up the '\' character; use a LR flip of the '/' char */ /* DEBUG_CHARS */