/*! * pixaGenerateFont() * * Input: pix (of 95 characters in 3 rows) * fontsize (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 * * Notes: * (1) This does all the work. See pixaGenerateFontFromFile() * for an overview. * (2) The pix is for one of the 9 fonts. @fontsize is only * used here for debugging. */ PIXA * pixaGenerateFont(PIX *pixs, l_int32 fontsize, l_int32 *pbl0, l_int32 *pbl1, l_int32 *pbl2) { l_int32 i, j, nrows, nrowchars, nchars, h, yval; l_int32 width, height; l_int32 baseline[3]; l_int32 *tab = NULL; BOX *box, *box1, *box2; BOXA *boxar, *boxac, *boxacs; PIX *pix1, *pix2, *pixr, *pixrc, *pixc; PIXA *pixa; l_int32 n, w, inrow, top; l_int32 *ia; NUMA *na; PROCNAME("pixaGenerateFont"); if (!pbl0 || !pbl1 || !pbl2) return (PIXA *)ERROR_PTR("&bl not all defined", procName, NULL); *pbl0 = *pbl1 = *pbl2 = 0; if (!pixs) return (PIXA *)ERROR_PTR("pixs not defined", procName, NULL); /* Locate the 3 rows of characters */ w = pixGetWidth(pixs); na = pixCountPixelsByRow(pixs, NULL); boxar = boxaCreate(0); n = numaGetCount(na); ia = numaGetIArray(na); inrow = 0; for (i = 0; i < n; i++) { if (!inrow && ia[i] > 0) { inrow = 1; top = i; } else if (inrow && ia[i] == 0) { inrow = 0; box = boxCreate(0, top, w, i - top); boxaAddBox(boxar, box, L_INSERT); } } FREE(ia); numaDestroy(&na); nrows = boxaGetCount(boxar); #if DEBUG_FONT_GEN L_INFO("For fontsize %s, have %d rows\n", procName, fontsize, nrows); #endif /* DEBUG_FONT_GEN */ if (nrows != 3) { L_INFO("nrows = %d; skipping fontsize %d\n", procName, nrows, fontsize); return (PIXA *)ERROR_PTR("3 rows not generated", procName, NULL); } /* Grab the character images and baseline data */ #if DEBUG_BASELINE lept_rmdir("baseline"); lept_mkdir("baseline"); #endif /* DEBUG_BASELINE */ tab = makePixelSumTab8(); pixa = pixaCreate(95); 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 L_INFO("Baseline info: row %d, yval = %d, h = %d\n", procName, i, yval, pixGetHeight(pixr)); pix1 = pixCopy(NULL, pixr); pixRenderLine(pix1, 0, yval, pixGetWidth(pix1), yval, 1, L_FLIP_PIXELS); if (i == 0 ) pixWrite("/tmp/baseline/row0.png", pix1, IFF_PNG); else if (i == 1) pixWrite("/tmp/baseline/row1.png", pix1, IFF_PNG); else pixWrite("/tmp/baseline/row2.png", pix1, IFF_PNG); pixDestroy(&pix1); #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); } FREE(tab); 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. */ pix1 = pixaGetPix(pixa, 0, L_CLONE); width = 2 * pixGetWidth(pix1); height = pixGetHeight(pix1); pixDestroy(&pix1); pix1 = pixCreate(width, height, 1); pixaReplacePix(pixa, 0, pix1, NULL); /* Fix up the '\' character; use a LR flip of the '/' char */ pix1 = pixaGetPix(pixa, 15, L_CLONE); pix2 = pixFlipLR(NULL, pix1); pixDestroy(&pix1); pixaReplacePix(pixa, 60, pix2, NULL); #if DEBUG_CHARS pix1 = pixaDisplayTiled(pixa, 1500, 0, 10); pixDisplay(pix1, 100 * i, 200); pixDestroy(&pix1); #endif /* DEBUG_CHARS */ boxaDestroy(&boxar); 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. */ 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; }