检查自定义字体是否可以显示字符

时间:2012-08-05 09:49:49

标签: android typeface custom-font

我有一个显示框字符的自定义字体。我使用的字体显然不支持所有语言。我想检查我要显示的字符串是否可以通过我的自定义字体显示。如果它不能,那么我想使用标准的Android字体(我知道可以显示字符)。我找不到一种方法来检查我的Typeface是否可以显示特定的字符串。我相信我已经看到了一种方法可以解决这个问题。有人知道吗?

6 个答案:

答案 0 :(得分:7)

<强>更新 如果您要编写API级别23或更高级别,请使用Paint.hasGlyph()中提到的answer by Orson Baines。否则请参阅下面的原始答案。


正如您在自己的回答中所提到的,没有可用于检查此内容的内置方法。但是,如果您可以控制要检查的字符串/字符,实际上可以通过稍微创新的方法来实现此目的。

您可以在要检查的字体中绘制一个您知道缺少的字符,然后绘制一个您想知道的字符(如果存在),然后最终比较它们并查看它们是否相同。

以下是一个代码示例,说明了我如何实施此检查:

public Bitmap drawBitmap(String text){
    Bitmap b = Bitmap.createBitmap(BITMAP_WIDTH, BITMAP_HEIGHT, Bitmap.Config.ALPHA_8);
    Canvas c = new Canvas(b);
    c.drawText(text, 0, BITMAP_HEIGHT / 2, paint);
    return b;
}

public byte[] getPixels(Bitmap b) {
    ByteBuffer buffer = ByteBuffer.allocate(b.getByteCount());
    b.copyPixelsToBuffer(buffer);
    return buffer.array();
}
public boolean isCharacterMissingInFont(String ch) {
    String missingCharacter = "\u0978"; // reserved code point in the devanagari block (should not exist).
    byte[] b1 = getPixels(drawBitmap(ch));
    byte[] b2 = getPixels(drawBitmap(missingCharacter));
    return Arrays.equals(b1, b2);
}

使用此方法时要记住一些重要的限制:

  • 您检查的字符(isCharacterMissing的参数)必须是非空格(可以使用Character.isWhitespace()检测到)。在某些字体中,缺少的字符会呈现为空格,因此如果您要比较存在的空白字符,则会错误地将其报告为这些字体中的缺失字符。
  • missingCharacter成员必须是要检查的字体中已知缺少的字符。我正在使用的代码点U+0978是Devanagari Unicode块中间的保留代码点,因此当前在所有Unicode兼容字体中都应该丢失它,但将来当新的字符添加到Unicode时此代码点可能被分配给真实角色。因此,这种方法不是未来的证明,但如果您自己提供字体,则可以确保在更改应用程序的字体时使用缺少的字符。
  • 由于此检查是通过绘制位图并进行比较来完成的,因此它不是非常有效,因此它只应用于检查应用程序中的几个字符而不是所有字符串。

<强>更新

看待U + 0978的解决方案没有其他人指出的那么长。该字符已添加到Unicode 7.0June 2014版本中。另一种选择是使用unicode中存在的字形,但不太可能以普通字体使用。

U+124AB块中的

Early Dynastic Cuneiform可能根本不存在于许多字体中。

答案 1 :(得分:6)

从Android版本23开始,您可以像这样测试:

Typeface typeface;
//initialize the custom font here

//enter the character to test
String charToTest="\u0978";
Paint paint=new Paint();
paint.setTypeface(typeface);
boolean hasGlyph=paint.hasGlyph(charToTest);

答案 2 :(得分:2)

@nibarius答案效果很好,但有不同的角色:&#34; \ u2936&#34;。

然而,该解决方案在内存,CPU和时间上都很重要。 我需要一个极少数字符的解决方案,所以我实现了 a&#34;快速而肮脏&#34;通过仅检查边界来解决问题。它的工作速度提高了约50倍,因此更适合我的情况:

public boolean isCharGlyphAvailable(char... c) {
      Rect missingCharBounds = new Rect();
      char missingCharacter = '\u2936';
      paint.getTextBounds(c, 0, 1, missingCharBounds); // takes array as argument, but I need only one char.
      Rect testCharsBounds = new Rect();
      paint.getTextBounds(c, 0, 1, testCharsBounds);
      return !testCharsBounds.equals(missingCharBounds);
}

我应该警告这种方法不如@nibarius准确,并且有一些误报和误报,但是如果你只需要测试几个字符以便能够回退到其他字符 - 这个解决方案是大。

答案 3 :(得分:2)

请检查Googles Mozc项目的源代码。 EmojiRenderableChecker类看起来效果很好!

它就像Paint.hasGlypgh的compat版本(在Marshmallow中添加)。

答案 4 :(得分:2)

对于那些仍然希望你的应用程序与少于23的API兼容并仍在代码中使用hasGlyph函数的人,可以通过以下方式使用@TargetApi(23):

@TargetApi(23)
public boolean isPrintable( String c ) {
    Paint paint=new Paint();
    boolean hasGlyph=true;
    hasGlyph=paint.hasGlyph(c);
    return hasGlyph;
}

然后在你的代码中:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
    if(isPrintable(yourString)) {
        //Do Something
    }
}

唯一的问题是,在低于23的API中,您的应用可能会显示空白符号。但至少在API23 +中你的应用程序将是完美的。

答案 5 :(得分:1)

要检查音乐符号♫是否以字符串形式显示(如果某些设备上没有显示),您可以尝试measuring字符串宽度; if width == 0然后符号不存在。

Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
Rect rtt = new Rect();
paint.getTextBounds( "♫", 0, 1, rtt );
    if( rtt.width() == 0 ){
}