2012-08-05 25 views
8

Tengo una fuente personalizada que muestra el carácter del cuadro. La fuente que estoy usando no es compatible con todos los idiomas, aparentemente. Quiero verificar si la Cadena que estoy a punto de mostrar puede mostrarse con mi fuente personalizada. Si no puede, entonces quiero usar la fuente estándar de Android (que sé que puede mostrar los caracteres). No obstante, no puedo encontrar un método para verificar si My Typeface puede mostrar una Cadena en particular. Estoy seguro de que he visto un método que hace esto en alguna parte. ¿Nadie sabe?Compruebe si la fuente personalizada puede mostrar el carácter

+0

Hmmmm ... No creo que tengamos suficiente acceso a fuentes de bajo nivel para determinar si un glifo en particular existe en un archivo de fuente particular desde dentro de Android. – CommonsWare

+0

La respuesta de bahpo lo hizo por mí: http://stackoverflow.com/a/41100873/5285687 – YellowJ

Respuesta

6

Actualización: Si se codifica la API de nivel 23 o superior por favor utilice Paint.hasGlyph() como se menciona en el answer by Orson Baines. De lo contrario, ver mi respuesta original a continuación.


Como mencionó en su propia respuesta, no hay métodos integrados disponibles para verificar esto. Sin embargo, si usted tiene cierto control sobre qué cadena/caracteres desea verificar, en realidad es posible hacerlo con un enfoque un poco más creativo.

Puede dibujar un personaje que sabe que falta en la fuente que desea verificar y luego dibujar un personaje que desea saber si existe, y finalmente compararlos y ver si se ven iguales.

Aquí es un ejemplo de código que ilustra cómo he implementado esta comprobación:

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

Hay algunas limitaciones importantes a tener en cuenta con este método:

  • El carácter de comprobar (argumento para isCharacterMissing) no debe ser un espacio en blanco (se puede detectar usando Character.isWhitespace()). En algunas fuentes, los caracteres faltantes se representan como espacios en blanco, por lo que si comparas un carácter de espacio en blanco que existe, se informará incorrectamente como un carácter faltante en fuentes como estas.
  • El miembro missingCharacter debe ser un carácter que se sabe que falta en la fuente que se va a comprobar. El punto de código U+0978 que estoy usando es un punto de código reservado en el medio del bloque Devanagari Unicode, por lo que actualmente falta en todas las fuentes compatibles con Unicode, sin embargo, en el futuro, cuando se agreguen nuevos caracteres a Unicode, este punto de código podría asignarse a un personaje real. Por lo tanto, este enfoque no es a prueba de futuro, pero si usted mismo suministra la fuente, puede asegurarse de que esté utilizando un carácter que falta cada vez que cambie la fuente de su aplicación.
  • Dado que esta comprobación se realiza dibujando mapas de bits y comparándolos no es muy eficiente, por lo que solo se debe utilizar para verificar algunos caracteres y no todas las cadenas en su aplicación.

Actualización:

La solución a la vista U + 0978 no funcionó mucho como se ha señalado por otros. Ese carácter se agregó en la versión Unicode 7.0 en June 2014. Otra opción es usar un glifo que existe en Unicode pero que es muy poco probable que se use en una fuente normal.

U+124AB en el bloque Early Dynastic Cuneiform es probablemente algo que no existe en muchas fuentes.

+2

stock Nexus 4 tiene un glifo para "\ u0978". En cambio, "\ u2936" parece que aún falta. – auval

+0

¿Qué debo usar para 'BITMAP_WIDTH'? –

+0

Cualquier cosa lo suficientemente grande como para que cada personaje se dibuje de manera diferente. Por ejemplo, si tratas de dibujar diferentes letras con solo 2x2 píxeles, muchas letras diferentes probablemente se vean iguales. Creo que podría haber usado algo así como 16 o 20. – nibarius

2

@nibarius answer funciona bien, aunque con un carácter diferente: "\ u2936".

Sin embargo, esa solución es pesada en memoria, CPU y tiempo. Necesitaba una solución para un número muy reducido de caracteres, así que implementé como una solución "rápida y sucia" al marcar solo los límites. Funciona sobre 50x veces más rápido, por lo que es más adecuado para mi caso:

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

debo advertir que este método es menos preciso que @nibarius, y hay algunos falsos negativos y falsos positivos, pero si sólo necesita probar algunos caracteres para poder recurrir a otros personajes; esta solución es genial.

5

A partir de la versión Android 23, puede probar de esta manera:

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

Esta es la respuesta correcta para API 23 en adelante, IMO. – CrazyIvan1974

+1

Desde JavaDoc: "La comprobación se realiza en toda la cadena alternativa, no solo en la fuente inmediata a la que se hace referencia". Entonces, si solo quiere saber si está en la Tipografía especificada, esto no funcionará. – ashughes

1

favor compruebe el código fuente de la Googles Mozc proyecto. ¡La clase EmojiRenderableChecker parece funcionar bastante bien!

es como una versión compatible para Paint.hasGlypgh (agregada en Marshmallow).

0

Para comprobar si el símbolo de música ♫ se muestra en una cadena (si no se muestra en algunos dispositivos), puede probar measuring el ancho de la cadena; if width == 0, entonces el símbolo está ausente.

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

Para aquellos de ustedes que todavía le gustaría que su aplicación sea compatible con las API de menos de 23 y seguir utilizando la función hasGlyph en su código, se puede utilizar el @TargetApi (23) de la siguiente manera:

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

Y luego en el código:

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

El único problema es que en las API inferiores a 23, su aplicación puede mostrar símbolos en blanco. Pero al menos en API23 + tu aplicación será perfecta.

Cuestiones relacionadas