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 /* 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