这种方法的不利之处在于不得不在改变剪辑区前记住现存的剪辑区,以使能够返回到 Graphics 创建时的状态。每一次调用绘制方法之前都要存储剪辑区,显著的代价是:每次必须进行 4 次调用并分配 4 个 int。
我们陷入常见的时间-空间的权衡问题中:为节省内存,CustomFont 占用了更多的处理器时间,使用剪辑来取代对每一个字符分配单个图像实例。在内存小的设备上,运行慢总不根本不能运行要强得多。
初始化时,有一项小任务 CustomFont 必须完成,这就是计算字体的基线。在字体渲染中,与字体的高度和宽度一样,字体的基线也是另一个重要的决定因素,因为它定义了一个字体的字符位于一个文本行的哪个位置。如果一个文本行有不同的字体,需要将其基线对齐,以使其出现在同一个水平线上。

我们可以改变 CustomFont.getFont() 来要求调用者指定所选字体的基线,但有一种更好的方法。MIDP 2.0 使我们能够动态检测基线。getRGB() 方法使我们可直接访问一个图像的单个像素,并且一个简单的探试就能确定哪行像素就是基线。
...
// determine background color: assume it's at 0, 0
image.getRGB( row, 0, 1, 0, 0, 1, 1 );
background = row[0];
// here's the heuristic: find the row on the bottom
// half of the image with the most non-background pixels
for ( int y = height/2; y < height; y++ )
{
total = 0;
image.getRGB( row, 0, imageWidth, 0, y, imageWidth, 1 );
for ( int x = 0; x < imageWidth; x++ )
{
if ( row[x] != background ) total++;
}
if ( total > max )
{
max = total;
result = y;
}
}
...
|
CustomFont 假定图像中左上角像素为背景颜色。CustomFont 计算图像的下半部分中的每一行的非背景像素,并且判断具有最多前景像素的那一行作为基线。在运行时确定基线,使您在创建自定义字体位图时无需为此事担忧。
动态样式设置
Font.getFont() and CustomFont.getFont() 的签名的第一个参数有所不同:标准的方法采用字体类型,而这里的方法采用的是图像文件的名称;但是二者都接受大小和样式参数。CustomFont 忽略了所要求的字体大小,因为如果对每一个字体大小都在内存中提供一个独立的图像的话,代价太高,并且如果试图在运行时缩放位图,就可能造成最终结果难以辨识。但是,自定义字体类确实试图尊重所要求的样式,途径是采用了一些简单而高效的技术,这些技术改变了它在运行时绘制字符图像的方式。
最简单的是下划线。就是在基线下两个像素的位置,在字符下画一条线。
...
if ( ( style & Font.STYLE_UNDERLINED ) != 0 )
{
g.drawLine(
x, y + baseline + 2, x + width, y + baseline + 2 );
}
...
|
+加粗只是稍微复杂了一点。为了加粗字符,CustomFont 多绘制了一次字符,在右侧加一列像素。因为背景是透明的,因此两行像素重叠使字符加黑。
...
if ( ( style & Font.STYLE_BOLD ) != 0 )
{
// draw an additional time, one pixel to the right
g.drawImage(
image, x - width*character + 1, y, anchor );
}
...
|
做斜体字时,CustomFont 使用剪辑来将字符的上半部分绘制得向右移动一个像素。效果出人意料地好。
...
if ( ( style & Font.STYLE_ITALIC ) != 0 )
{
g.setClip( x + 1, y, width, height/2 );
g.drawImage(
image, x - width*character + 1, y, anchor );
g.setClip( x, y+height/2, width, height/2 );
g.drawImage(
image, x - width*character, y, anchor );
}
...
|
下面是实际中的样式:
STYLE_PLAIN | STYLE_UNDERLINED |
![]() | ![]() |
STYLE_BOLD | STYLE_ITALIC |
![]() | ![]() |
在绘制特定颜色的字符时会稍难一些。当 Graphics 用当前颜色渲染字体时,CustomFont 只能把像素拷贝到整个的字体图像中,因此字符以原始图像的采用的非透明的颜色出现。
MIDP 2.0 提供了一种从 getRGB() 返回的像素创建新图像的方法。您可以复制一个字符的像素,扫描并修改每一个非背景像素的颜色,建立新的图像,并将该图像绘制屏幕上;但这种方法要占用大量的处理器资源而明显地很慢。如果事先知道需要哪种颜色,在创建字体时可以在前景中使用该颜色。MIDTerm 采用是黑色背景,因此整个字体图像含有白色字符,背景则是透明的。
使自定义的字体工作起来
因为 CustomFont 与 MIDP 的 Font 类非常接近于一致,MIDTerm 的 TelnetCanvas 类仅需要很少的改动就可以实现自定义字体的优势。
| Using MIDP Fonts | Using Custom Font |
font = Font.getFont(
Font.FACE_MONOSPACE,
Font.STYLE_SMALL,
Font.SIZE_PLAIN ); | font = CustomFont.getFont(
"/mono.png", // the font bitmap file
Font.SIZE_SMALL, // ignored
Font.STYLE_PLAIN ); // no styling |
g.setFont( font );
g.drawChar( (char) b,
insetX + x*fontWidth,
insetY + y*fontHeight,
g.TOP | g.LEFT ); |
font.drawChar( g, (char) b,
insetX + x*fontWidth,
insetY + y*fontHeight,
g.TOP | g.LEFT );
|



