2012-08-05 35 views
8

Tôi có phông chữ tùy chỉnh hiển thị ký tự hộp hay không. Phông chữ tôi đang sử dụng không hỗ trợ tất cả các ngôn ngữ. Tôi muốn kiểm tra xem chuỗi Tôi sắp hiển thị có thể được hiển thị bằng phông chữ tùy chỉnh của tôi không. Nếu không thì tôi muốn sử dụng phông chữ chuẩn của Android (mà tôi biết có thể hiển thị các ký tự). Tôi không thể tìm thấy một phương pháp để kiểm tra xem Typeface của tôi có thể hiển thị một Chuỗi cụ thể hay không. Tôi chắc chắn tôi đã nhìn thấy một phương pháp xung quanh mà không điều này một nơi nào đó. Có ai biết không?Kiểm tra xem phông chữ tùy chỉnh có thể hiển thị ký tự

+0

Hmmmm ... Tôi không nghĩ rằng chúng tôi có đủ quyền truy cập phông chữ cấp thấp để xác định liệu một hình tượng cụ thể có tồn tại trong một tệp phông chữ cụ thể từ trong Android hay không. – CommonsWare

+0

Câu trả lời của bahpo đã làm điều đó cho tôi: http://stackoverflow.com/a/41100873/5285687 – YellowJ

Trả lời

6

Cập nhật: Nếu bạn đang mã hóa cho cấp API 23 hoặc cao hơn xin vui lòng sử dụng Paint.hasGlyph() như đã đề cập trong answer by Orson Baines. Nếu không, hãy xem câu trả lời ban đầu của tôi bên dưới.


Như bạn đã đề cập trong câu trả lời của riêng bạn, không có phương pháp tích hợp sẵn để kiểm tra điều này. Tuy nhiên, nếu bạn có một số kiểm soát đối với chuỗi ký tự/ký tự bạn muốn kiểm tra, thì thực sự có thể thực hiện điều này với cách tiếp cận sáng tạo hơn một chút.

Bạn có thể vẽ một ký tự mà bạn biết bị thiếu trong phông chữ bạn muốn kiểm tra và sau đó vẽ một ký tự mà bạn muốn biết nếu nó tồn tại, rồi cuối cùng so sánh chúng và xem chúng có giống nhau hay không.

Đây là một mẫu mã mà minh họa làm thế nào tôi thực hiện việc kiểm tra này:

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

Có một số hạn chế quan trọng cần lưu ý với phương pháp này:

  • Nhân vật bạn kiểm tra (tham số để isCharacterMissing) phải là khoảng trắng (có thể được phát hiện bằng cách sử dụng Character.isWhitespace()). Trong một số phông chữ, các ký tự bị thiếu được hiển thị dưới dạng khoảng trắng, vì vậy nếu bạn so sánh một ký tự khoảng trống tồn tại, nó sẽ được báo cáo không chính xác như một ký tự bị thiếu trong các phông chữ như thế này.
  • Thành viên missingCharacter phải là ký tự được biết là bị thiếu trong phông chữ cần kiểm tra. Điểm mã U+0978 mà tôi đang sử dụng là điểm mã được đặt ở giữa khối Unicode Devanagari vì vậy hiện tại nó sẽ bị thiếu trong tất cả các phông chữ tương thích với Unicode, tuy nhiên trong tương lai khi các ký tự mới được thêm vào Unicode, điểm mã này có thể được gán với một nhân vật thực sự. Vì vậy, cách tiếp cận này không phải là bằng chứng trong tương lai, nhưng nếu bạn tự cung cấp phông chữ, bạn có thể đảm bảo rằng bạn đang sử dụng ký tự bị thiếu bất cứ khi nào bạn thay đổi phông chữ của ứng dụng.
  • Vì việc kiểm tra này được thực hiện bằng cách vẽ bitmap và so sánh chúng không hiệu quả nên chỉ nên sử dụng để kiểm tra một vài ký tự chứ không phải tất cả các chuỗi trong ứng dụng của bạn.

Cập nhật:

Các giải pháp để nhìn vào U + 0978 đã không làm việc miễn là chỉ ra bởi những người khác. Nhân vật đó đã được thêm vào trong bản phát hành Unicode 7.0 trong June 2014. Một lựa chọn khác là sử dụng một glyph tồn tại trong unicode nhưng điều đó rất khó được sử dụng trong một phông chữ bình thường.

U+124AB trong khối Early Dynastic Cuneiform có lẽ là thứ không tồn tại trong nhiều phông chữ.

+2

cổ phiếu Nexus 4 có hình tượng cho "\ u0978". Thay vào đó, "\ u2936" dường như vẫn bị thiếu. – auval

+0

Tôi nên sử dụng gì cho 'BITMAP_WIDTH'? –

+0

Bất cứ điều gì đủ lớn mà mỗi nhân vật được vẽ khác nhau. Ví dụ: nếu bạn cố gắng vẽ các chữ cái khác nhau bằng cách sử dụng chỉ 2x2 pixel, nhiều chữ cái khác nhau có thể trông giống nhau. Tôi nghĩ rằng tôi có thể đã sử dụng một cái gì đó như 16 hoặc 20. – nibarius

2

@nibarius câu trả lời hoạt động tốt, mặc dù có một ký tự khác: "\ u2936".

Tuy nhiên, giải pháp đó nặng về bộ nhớ, CPU và thời gian. Tôi cần giải pháp cho số lượng ký tự rất nhỏ nên tôi đã triển khai giải pháp "nhanh chóng và bẩn" bằng cách chỉ kiểm tra các giới hạn. Nó hoạt động về 50x lần nhanh hơn, vì vậy nó là phù hợp hơn cho trường hợp của tôi:

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

tôi nên cảnh báo rằng phương pháp này là kém chính xác hơn @nibarius, và có một số âm tính giả và dương tính giả, nhưng nếu bạn chỉ cần phải kiểm tra một vài ký tự để có thể dự phòng với các nhân vật khác - giải pháp này rất tuyệt.

5

Tính đến Android phiên bản 23, Bạn có thể kiểm tra nó như thế này:

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

Đây là câu trả lời đúng cho API 23 trở lên, IMO. – CrazyIvan1974

+1

Từ JavaDoc: "Việc kiểm tra được thực hiện trên toàn bộ chuỗi dự phòng, không chỉ là phông chữ ngay lập tức được tham chiếu." Vì vậy, nếu bạn chỉ muốn biết nếu nó trong Typeface bạn chỉ định, điều này sẽ không hoạt động. – ashughes

1

xin vui lòng kiểm tra mã nguồn từ dự án Googles Mozc. Lớp EmojiRenderableChecker dường như hoạt động khá tốt!

nó giống như phiên bản tương thích cho Paint.hasGlypgh (được thêm vào trong Marshmallow).

0

Để kiểm tra xem biểu tượng âm nhạc ♫ có đang được hiển thị trong chuỗi không (nếu nó không được hiển thị trên một số thiết bị), bạn có thể thử chiều rộng chuỗi measuring; if width == 0 thì biểu tượng không có.

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

Đối với những người bạn của những người vẫn muốn ứng dụng của bạn để tương thích với các API ít hơn 23 và vẫn sử dụng chức năng hasGlyph trong mã của bạn, bạn có thể sử dụng @TargetApi (23) theo cách sau:

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

Và sau đó trong mã của bạn:

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

vấn đề duy nhất là trong API thấp hơn 23 ứng dụng của bạn có thể hiển thị những biểu tượng trống. Nhưng ít nhất trong API23 + ứng dụng của bạn sẽ hoàn hảo.

Các vấn đề liên quan