mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-05-17 22:03:07 -06:00
700 lines
22 KiB
C
700 lines
22 KiB
C
/*====================================================================*
|
|
- Copyright (C) 2001 Leptonica. All rights reserved.
|
|
- This software is distributed in the hope that it will be
|
|
- useful, but with NO WARRANTY OF ANY KIND.
|
|
- No author or distributor accepts responsibility to anyone for the
|
|
- consequences of using this software, or for whether it serves any
|
|
- particular purpose or works at all, unless he or she says so in
|
|
- writing. Everyone is granted permission to copy, modify and
|
|
- redistribute this source code, for commercial or non-commercial
|
|
- purposes, with the following restrictions: (1) the origin of this
|
|
- source code must not be misrepresented; (2) modified versions must
|
|
- be plainly marked as such; and (3) this notice may not be removed
|
|
- or altered from any source or modified source distribution.
|
|
*====================================================================*/
|
|
|
|
|
|
/*
|
|
* bmf.c
|
|
*
|
|
* Acquisition and generation of bitmap fonts.
|
|
*
|
|
* L_BMF *bmfCreate()
|
|
* L_BMF *bmfDestroy()
|
|
*
|
|
* PIX *bmfGetPix()
|
|
* l_int32 bmfGetWidth()
|
|
* l_int32 bmfGetBaseline()
|
|
*
|
|
* PIXA *pixaGetFont()
|
|
* l_int32 pixaSaveFont()
|
|
* PIXA *pixaGenerateFont()
|
|
* static l_int32 pixGetTextBaseline()
|
|
* static l_int32 bmfMakeAsciiTables()
|
|
*
|
|
* This is not a very general utility, because it only uses bitmap
|
|
* representations of a single font, Palatino-Roman, with the
|
|
* normal style. It uses bitmaps generated for nine sizes, from
|
|
* 4 to 20 pts, rendered at 300 ppi. Generalization to different
|
|
* fonts, styles and sizes is straightforward.
|
|
*
|
|
* I chose Palatino-Roman is because I like it.
|
|
* The input font images were generated from a set of small
|
|
* PostScript files, such as chars-12.ps, which were rendered
|
|
* into the inputfont[] bitmap files using GhostScript. See, for
|
|
* example, the bash script prog/ps2tiff, which will "rip" a
|
|
* PostScript file into a set of ccitt-g4 compressed tiff files.
|
|
*
|
|
* The set of ascii characters from 32 through 126 are the 95
|
|
* printable ascii chars. Palatino-Roman is missing char 92, '\'.
|
|
* I have substituted '/', char 47, for 92, so that there will be
|
|
* no missing printable chars in this set. The space is char 32,
|
|
* and I have given it a width equal to twice the width of '!'.
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include "allheaders.h"
|
|
|
|
#define NFONTS 9
|
|
static const char *inputfonts[] = {"chars-4.tif", "chars-6.tif",
|
|
"chars-8.tif", "chars-10.tif",
|
|
"chars-12.tif", "chars-14.tif",
|
|
"chars-16.tif", "chars-18.tif",
|
|
"chars-20.tif"};
|
|
static const char *outputfonts[] = {"chars-4.pixa", "chars-6.pixa",
|
|
"chars-8.pixa", "chars-10.pixa",
|
|
"chars-12.pixa", "chars-14.pixa",
|
|
"chars-16.pixa", "chars-18.pixa",
|
|
"chars-20.pixa"};
|
|
static const l_int32 baselines[NFONTS][3] = {{11, 12, 12}, {18, 18, 18},
|
|
{24, 24, 24}, {30, 30, 30},
|
|
{36, 36, 36}, {42, 42, 42},
|
|
{48, 48, 48}, {54, 54, 54},
|
|
{60, 60, 60}};
|
|
static const l_float32 VERT_FRACT_SEP = 0.3;
|
|
|
|
#ifndef NO_CONSOLE_IO
|
|
#define DEBUG_BASELINE 0
|
|
#define DEBUG_CHARS 0
|
|
#define DEBUG_FONT_GEN 0
|
|
#endif /* ~NO_CONSOLE_IO */
|
|
|
|
static l_int32 pixGetTextBaseline(PIX *pixs, l_int32 *tab8, l_int32 *py);
|
|
static l_int32 bmfMakeAsciiTables(L_BMF *bmf);
|
|
|
|
|
|
/*---------------------------------------------------------------------*/
|
|
/* Bmf create/destroy */
|
|
/*---------------------------------------------------------------------*/
|
|
/*!
|
|
* bmfCreate()
|
|
*
|
|
* Input: dir (directory holding pixa of character set)
|
|
* size (4, 6, 8, ... , 20)
|
|
* Return: bmf (holding the bitmap font and associated information)
|
|
*
|
|
* Notes:
|
|
* (1) This first tries to read a pre-computed pixa file with the
|
|
* 95 ascii chars in it. If the file is not found, it
|
|
* creates the pixa from the raw image. It then generates all
|
|
* associated data required to use the bmf.
|
|
*/
|
|
L_BMF *
|
|
bmfCreate(const char *dir,
|
|
l_int32 size)
|
|
{
|
|
L_BMF *bmf;
|
|
PIXA *pixa;
|
|
|
|
PROCNAME("bmfCreate");
|
|
|
|
if ((bmf = (L_BMF *)CALLOC(1, sizeof(L_BMF))) == NULL)
|
|
return (L_BMF *)ERROR_PTR("bmf not made", procName, NULL);
|
|
|
|
/* Look for the pixa */
|
|
pixa = pixaGetFont(dir, size, &bmf->baseline1, &bmf->baseline2,
|
|
&bmf->baseline3);
|
|
|
|
/* If not found, make it */
|
|
if (!pixa) {
|
|
L_INFO("Generating pixa of bitmap fonts", procName);
|
|
pixa = pixaGenerateFont(dir, size, &bmf->baseline1, &bmf->baseline2,
|
|
&bmf->baseline3);
|
|
if (!pixa) {
|
|
bmfDestroy(&bmf);
|
|
return (L_BMF *)ERROR_PTR("font pixa not made", procName, NULL);
|
|
}
|
|
}
|
|
|
|
bmf->pixa = pixa;
|
|
bmf->size = size;
|
|
bmf->directory = stringNew(dir);
|
|
bmfMakeAsciiTables(bmf);
|
|
return bmf;
|
|
}
|
|
|
|
|
|
/*!
|
|
* bmfDestroy()
|
|
*
|
|
* Input: &bmf (<set to null>)
|
|
* Return: void
|
|
*/
|
|
void
|
|
bmfDestroy(L_BMF **pbmf)
|
|
{
|
|
L_BMF *bmf;
|
|
|
|
PROCNAME("bmfDestroy");
|
|
|
|
if (pbmf == NULL) {
|
|
L_WARNING("ptr address is null!", procName);
|
|
return;
|
|
}
|
|
|
|
if ((bmf = *pbmf) == NULL)
|
|
return;
|
|
|
|
pixaDestroy(&bmf->pixa);
|
|
FREE(bmf->directory);
|
|
FREE(bmf->fonttab);
|
|
FREE(bmf->baselinetab);
|
|
FREE(bmf->widthtab);
|
|
FREE(bmf);
|
|
*pbmf = NULL;
|
|
return;
|
|
}
|
|
|
|
|
|
/*---------------------------------------------------------------------*/
|
|
/* Bmf accessors */
|
|
/*---------------------------------------------------------------------*/
|
|
/*!
|
|
* bmfGetPix()
|
|
*
|
|
* Input: bmf
|
|
* chr (should be one of the 95 supported printable bitmaps)
|
|
* Return: pix (clone of pix in bmf), or null on error
|
|
*/
|
|
PIX *
|
|
bmfGetPix(L_BMF *bmf,
|
|
char chr)
|
|
{
|
|
l_int32 i;
|
|
PIXA *pixa;
|
|
|
|
PROCNAME("bmfGetPix");
|
|
|
|
if (!bmf)
|
|
return (PIX *)ERROR_PTR("bmf not defined", procName, NULL);
|
|
|
|
i = bmf->fonttab[(l_int32)chr];
|
|
if (i == UNDEF)
|
|
return (PIX *)ERROR_PTR("no bitmap representation", procName, NULL);
|
|
if ((pixa = bmf->pixa) == NULL)
|
|
return (PIX *)ERROR_PTR("pixa not found", procName, NULL);
|
|
|
|
return pixaGetPix(pixa, i, L_CLONE);
|
|
}
|
|
|
|
|
|
/*!
|
|
* bmfGetWidth()
|
|
*
|
|
* Input: bmf
|
|
* chr (should be one of the 95 supported bitmaps)
|
|
* &w (<return> character width; -1 if not printable)
|
|
* Return: 0 if OK, 1 on error
|
|
*/
|
|
l_int32
|
|
bmfGetWidth(L_BMF *bmf,
|
|
char chr,
|
|
l_int32 *pw)
|
|
{
|
|
l_int32 i;
|
|
PIX *pix;
|
|
PIXA *pixa;
|
|
|
|
PROCNAME("bmfGetWidth");
|
|
|
|
if (!bmf)
|
|
return ERROR_INT("bmf not defined", procName, 1);
|
|
if (!pw)
|
|
return ERROR_INT("&w not defined", procName, 1);
|
|
*pw = -1;
|
|
i = bmf->fonttab[(l_int32)chr];
|
|
if (i == UNDEF)
|
|
return ERROR_INT("no bitmap representation", procName, 1);
|
|
if ((pixa = bmf->pixa) == NULL)
|
|
return ERROR_INT("pixa not found", procName, 1);
|
|
if ((pix = pixaGetPix(pixa, i, L_CLONE)) == NULL)
|
|
return ERROR_INT("pix not found", procName, 1);
|
|
*pw = pixGetWidth(pix);
|
|
pixDestroy(&pix);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*!
|
|
* bmfGetBaseline()
|
|
*
|
|
* Input: bmf
|
|
* chr (should be one of the 95 supported bitmaps)
|
|
* &baseline (<return>; distance below UL corner of bitmap char)
|
|
* Return: 0 if OK, 1 on error
|
|
*/
|
|
l_int32
|
|
bmfGetBaseline(L_BMF *bmf,
|
|
char chr,
|
|
l_int32 *pbaseline)
|
|
{
|
|
l_int32 bl;
|
|
|
|
PROCNAME("bmfGetBaseline");
|
|
|
|
if (!pbaseline)
|
|
return ERROR_INT("&baseline not defined", procName, 1);
|
|
*pbaseline = 0;
|
|
if (!bmf)
|
|
return ERROR_INT("bmf not defined", procName, 1);
|
|
bl = bmf->baselinetab[(l_int32)chr];
|
|
if (bl == UNDEF)
|
|
return ERROR_INT("no bitmap representation", procName, 1);
|
|
|
|
*pbaseline = bl;
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*---------------------------------------------------------------------*/
|
|
/* Font bitmap acquisition and generation */
|
|
/*---------------------------------------------------------------------*/
|
|
/*!
|
|
* pixaGetFont()
|
|
*
|
|
* Input: dir (directory holding pixa of character set)
|
|
* size (4, 6, 8, ... , 20)
|
|
* &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 reads a pre-computed pixa file with the 95 ascii chars.
|
|
*/
|
|
PIXA *
|
|
pixaGetFont(const char *dir,
|
|
l_int32 size,
|
|
l_int32 *pbl0,
|
|
l_int32 *pbl1,
|
|
l_int32 *pbl2)
|
|
{
|
|
char *pathname;
|
|
l_int32 fileno;
|
|
PIXA *pixa;
|
|
|
|
PROCNAME("pixaGetFont");
|
|
|
|
fileno = (size / 2) - 2;
|
|
if (fileno < 0 || fileno > NFONTS)
|
|
return (PIXA *)ERROR_PTR("font size invalid", procName, NULL);
|
|
if (!pbl0 || !pbl1 || !pbl2)
|
|
return (PIXA *)ERROR_PTR("&bl not all defined", procName, NULL);
|
|
*pbl0 = baselines[fileno][0];
|
|
*pbl1 = baselines[fileno][1];
|
|
*pbl2 = baselines[fileno][2];
|
|
|
|
pathname = genPathname(dir, outputfonts[fileno]);
|
|
pixa = pixaRead(pathname);
|
|
FREE(pathname);
|
|
|
|
if (!pixa)
|
|
L_WARNING("pixa of char bitmaps not found", procName);
|
|
return pixa;
|
|
}
|
|
|
|
|
|
/*!
|
|
* pixaSaveFont()
|
|
*
|
|
* Input: indir (directory holding image of character set)
|
|
* outdir (directory into which the output pixa file
|
|
* will be written)
|
|
* size (in pts, at 300 ppi)
|
|
* Return: 0 if OK, 1 on error
|
|
*
|
|
* Notes:
|
|
* (1) This saves a font of a particular size.
|
|
* (2) prog/genfonts calls this function for each of the
|
|
* nine font sizes, to generate all the font pixa files.
|
|
*/
|
|
l_int32
|
|
pixaSaveFont(const char *indir,
|
|
const char *outdir,
|
|
l_int32 size)
|
|
{
|
|
char *pathname;
|
|
l_int32 bl1, bl2, bl3;
|
|
PIXA *pixa;
|
|
|
|
PROCNAME("pixaSaveFont");
|
|
|
|
if (size < 4 || size > 20 || (size % 2))
|
|
return ERROR_INT("size must be in {4, 6, ..., 20}", procName, 1);
|
|
|
|
if ((pixa = pixaGenerateFont(indir, size, &bl1, &bl2, &bl3)) == NULL)
|
|
return ERROR_INT("pixa not made", procName, 1);
|
|
pathname = genPathname(outdir, outputfonts[(size - 4) / 2]);
|
|
pixaWrite(pathname, pixa);
|
|
|
|
#if DEBUG_FONT_GEN
|
|
fprintf(stderr, "Found %d chars in font size %d\n",
|
|
pixaGetCount(pixa), size);
|
|
fprintf(stderr, "Baselines are at: %d, %d, %d\n", bl1, bl2, bl3);
|
|
#endif /* DEBUG_FONT_GEN */
|
|
|
|
FREE(pathname);
|
|
pixaDestroy(&pixa);
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*!
|
|
* 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;
|
|
}
|
|
|
|
|
|
/*!
|
|
* pixGetTextBaseline()
|
|
*
|
|
* Input: pixs (1 bpp, one textline character set)
|
|
* tab8 (<optional> pixel sum table)
|
|
* &y (<return> baseline value)
|
|
* Return: 0 if OK, 1 on error
|
|
*
|
|
* Notes:
|
|
* (1) Method: find the largest difference in pixel sums from one
|
|
* raster line to the next one below it. The baseline is the
|
|
* upper raster line for the pair of raster lines that
|
|
* maximizes this function.
|
|
*/
|
|
static l_int32
|
|
pixGetTextBaseline(PIX *pixs,
|
|
l_int32 *tab8,
|
|
l_int32 *py)
|
|
{
|
|
l_int32 i, h, val1, val2, diff, diffmax, ymax;
|
|
l_int32 *tab;
|
|
NUMA *na;
|
|
|
|
PROCNAME("pixGetTextBaseline");
|
|
|
|
if (!pixs)
|
|
return ERROR_INT("pixs not defined", procName, 1);
|
|
if (!py)
|
|
return ERROR_INT("&y not defined", procName, 1);
|
|
*py = 0;
|
|
if (!tab8)
|
|
tab = makePixelSumTab8();
|
|
else
|
|
tab = tab8;
|
|
|
|
na = pixCountPixelsByRow(pixs, tab);
|
|
h = numaGetCount(na);
|
|
diffmax = 0;
|
|
ymax = 0;
|
|
for (i = 1; i < h; i++) {
|
|
numaGetIValue(na, i - 1, &val1);
|
|
numaGetIValue(na, i, &val2);
|
|
diff = L_MAX(0, val1 - val2);
|
|
if (diff > diffmax) {
|
|
diffmax = diff;
|
|
ymax = i - 1; /* upper raster line */
|
|
}
|
|
}
|
|
*py = ymax;
|
|
|
|
if (!tab8)
|
|
FREE(tab);
|
|
numaDestroy(&na);
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*!
|
|
* bmfMakeAsciiTables
|
|
*
|
|
* Input: bmf
|
|
* Return: 0 if OK, 1 on error
|
|
*
|
|
* Notes:
|
|
* (1) This makes three tables, each of size 128, as follows:
|
|
* - fonttab is a table containing the index of the Pix
|
|
* that corresponds to each input ascii character;
|
|
* it maps (ascii-index) --> Pixa index
|
|
* - baselinetab is a table containing the baseline offset
|
|
* for the Pix that corresponds to each input ascii character;
|
|
* it maps (ascii-index) --> baseline offset
|
|
* - widthtab is a table containing the character width in
|
|
* pixels for the Pix that corresponds to that character;
|
|
* it maps (ascii-index) --> bitmap width
|
|
* (2) This also computes
|
|
* - lineheight (sum of maximum character extensions above and
|
|
* below the baseline)
|
|
* - kernwidth (spacing between characters within a word)
|
|
* - spacewidth (space between words)
|
|
* - vertlinesep (extra vertical spacing between textlines)
|
|
* (3) The baselines apply as follows:
|
|
* baseline1 (ascii 32 - 57), ascii 92
|
|
* baseline2 (ascii 58 - 91)
|
|
* baseline3 (ascii 93 - 126)
|
|
* (4) The only array in bmf that is not ascii-based is the
|
|
* array of bitmaps in the pixa, which starts at ascii 32.
|
|
*/
|
|
static l_int32
|
|
bmfMakeAsciiTables(L_BMF *bmf)
|
|
{
|
|
l_int32 i, maxh, height, charwidth, xwidth, kernwidth;
|
|
l_int32 *fonttab, *baselinetab, *widthtab;
|
|
PIX *pix;
|
|
|
|
PROCNAME("bmfMakeAsciiTables");
|
|
|
|
if (!bmf)
|
|
return ERROR_INT("bmf not defined", procName, 1);
|
|
|
|
/* First get the fonttab; we use this later for the char widths */
|
|
if ((fonttab = (l_int32 *)CALLOC(128, sizeof(l_int32))) == NULL)
|
|
return ERROR_INT("fonttab not made", procName, 1);
|
|
bmf->fonttab = fonttab;
|
|
for (i = 0; i < 128; i++)
|
|
fonttab[i] = UNDEF;
|
|
for (i = 32; i < 127; i++)
|
|
fonttab[i] = i - 32;
|
|
|
|
if ((baselinetab = (l_int32 *)CALLOC(128, sizeof(l_int32))) == NULL)
|
|
return ERROR_INT("baselinetab not made", procName, 1);
|
|
bmf->baselinetab = baselinetab;
|
|
for (i = 0; i < 128; i++)
|
|
baselinetab[i] = UNDEF;
|
|
for (i = 32; i <= 57; i++)
|
|
baselinetab[i] = bmf->baseline1;
|
|
for (i = 58; i <= 91; i++)
|
|
baselinetab[i] = bmf->baseline2;
|
|
baselinetab[92] = bmf->baseline1; /* the '\' char */
|
|
for (i = 93; i < 127; i++)
|
|
baselinetab[i] = bmf->baseline3;
|
|
|
|
/* Generate array of character widths; req's fonttab to exist */
|
|
if ((widthtab = (l_int32 *)CALLOC(128, sizeof(l_int32))) == NULL)
|
|
return ERROR_INT("widthtab not made", procName, 1);
|
|
bmf->widthtab = widthtab;
|
|
for (i = 0; i < 128; i++)
|
|
widthtab[i] = UNDEF;
|
|
for (i = 32; i < 127; i++) {
|
|
bmfGetWidth(bmf, i, &charwidth);
|
|
widthtab[i] = charwidth;
|
|
}
|
|
|
|
/* Get the line height of text characters, from the highest
|
|
* ascender to the lowest descender; req's fonttab to exist. */
|
|
pix = bmfGetPix(bmf, 32);
|
|
maxh = pixGetHeight(pix);
|
|
pixDestroy(&pix);
|
|
pix = bmfGetPix(bmf, 58);
|
|
height = pixGetHeight(pix);
|
|
pixDestroy(&pix);
|
|
maxh = L_MAX(maxh, height);
|
|
pix = bmfGetPix(bmf, 93);
|
|
height = pixGetHeight(pix);
|
|
pixDestroy(&pix);
|
|
maxh = L_MAX(maxh, height);
|
|
bmf->lineheight = maxh;
|
|
|
|
/* Get the kern width (distance between characters).
|
|
* We let it be the same for all characters in a given
|
|
* font size, and scale it linearly with the size;
|
|
* req's fonttab to be built first. */
|
|
bmfGetWidth(bmf, 120, &xwidth);
|
|
kernwidth = (l_int32)(0.08 * (l_float32)xwidth + 0.5);
|
|
bmf->kernwidth = L_MAX(1, kernwidth);
|
|
|
|
/* Save the space width (between words) */
|
|
bmfGetWidth(bmf, 32, &charwidth);
|
|
bmf->spacewidth = charwidth;
|
|
|
|
/* Save the extra vertical space between lines */
|
|
bmf->vertlinesep = (l_int32)(VERT_FRACT_SEP * bmf->lineheight + 0.5);
|
|
|
|
return 0;
|
|
}
|
|
|