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

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

Solutions Collecting From Web of "检查自定义字体是否可以显示字符"

更新:如果您编码的API级别为23或更高,请使用Paint.hasGlyph(),如Orson Baines的回答中所述。 否则,请参阅下面的原始答案。


正如你在自己的答案中提到的,没有内置的方法可用于检查。 但是,如果您对要查看的string/字符有一定的控制权,实际上可以采用更具创造性的方法来实现。

你可以画一个你知道在你想检查的字体中缺less的字符,然后绘制一个你想知道它是否存在的字符,然后最后比较它们,看看它们看起来是否相同。

这里是一个代码示例,说明了我如何实现这个检查:

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()来检测)。 在某些字体中,缺less的字符呈现为空格,所以如果您要比较存在的空白字符,则会错误地将其报告为像这样的字体中的缺失字符。
  • missingCharacter成员必须是已知在字体中缺less要检查的字符。 我使用的代码点U + 0978是在梵文Unicode块中间的一个保留代码点,所以它在所有的Unicode兼容字体中应该是缺less的,但是将来当新字符被添加到Unicode时,这个代码点可能会被分配给一个真正的人物。 所以这种方法不是未来的certificate,但是如果您自己提供字体,则可以确保在更改应用程序的字体时使用缺less的字符。
  • 由于此检查是通过绘制位图并比较它们来完成的,因此它不是非常有效,因此它只应用于检查应用程序中的几个字符而不是所有string。

更新:

看看U + 0978的解决scheme并没有像其他人指出的那样长久。 该字符在2014年6月的Unicode 7.0版本中添加。 另一种select是使用unicode中存在的字形,但不太可能以正常字体使用。

早期王朝楔形文字块中的U + 124AB可能是许多字体中不存在的东西。

从Android版本23开始,您可以像这样testing它:

 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); 

@nibarius的答案效果很好,虽然具有不同的性格:“\ u2936”。

但是,这个解决scheme在内存,CPU和时间上都很重。 我需要一个解决scheme为数很less的字符,所以我通过只检查边界来实现“快速和肮脏”的解决scheme。 它的工作速度快了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准确,并且有一些错误的消极和误报,但是如果你只需要testing几个字符就可以回退到其他字符 – 这个解决scheme非常棒。

请查看Googles Mozc项目的源代码。 EmojiRenderableChecker类似乎工作得很好!

它就像一个Paint.hasGlypgh (添加在棉花糖)compat版本。

对于那些仍然希望您的应用程序兼容小于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中,您的应用可能会显示空白符号。 但至less在API23 +你的应用程序将是完美的。

要检查音乐符号♫是否显示在一个string中(如果它没有显示在某些设备上),您可以尝试测量string的宽度; if width == 0那么符号不存在。

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