How to programmatically detect whether a font renders characters as squares?

23 hours ago 1
ARTICLE AD BOX

GraphicsEnvironment.getAvailableFontFamilyNames() gives us an array of all installed fonts. At my site, however, not all fonts render text properly; instead some fonts show squares only. Run the code below to see whether you also have "useless" fonts.

Now I would like to sift out these fonts. But how to detect them? Font.canDisplay('A') finds 6 fonts at my site, Font.canDisplayUpTo("zÀÿĀ") finds 2 reaching beyond ASCII (no squares). But altogether I have got 36 undisplayable fonts. Any idea how to get the rest?

import java.awt.*; import java.awt.event.*; import java.awt.font.*; import java.awt.image.*; import javax.swing.*; public class FontsMany extends JFrame { boolean first= true; GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); Insets insets; JScrollPane scroll; String fontList[] = ge.getAvailableFontFamilyNames(); int count= fontList.length; public FontsMany() { setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); setSize(640, 700); setTitle(String.valueOf(fontList.length)+" installierte Fonts"); MyPanel mp= new MyPanel(); scroll = new JScrollPane(mp); ScrollBarListener sbl= new ScrollBarListener(); scroll.getHorizontalScrollBar().addAdjustmentListener(sbl); scroll.getVerticalScrollBar().addAdjustmentListener(sbl); add(scroll, BorderLayout.CENTER); setVisible(true); } // With "void main(String args[])" the frame was displayed twice. public static void main(String args[]) { EventQueue.invokeLater(FontsMany::new); } class ScrollBarListener implements AdjustmentListener { public void adjustmentValueChanged(AdjustmentEvent evt) { scroll.repaint(); } } class MyPanel extends JPanel { MyPanel() { setPreferredSize(new Dimension(600, count/3*14)); } public void paintComponent(Graphics g) { if (insets == null) insets = getInsets(); g.translate(insets.left, insets.top); Font theFont; FontMetrics fm; int fontHeight = 0; int[] arr= new int[count]; int iend= count/3; if (count%3 >0) iend++; int idif= iend*2; if (count%3 == 1) idif--; int iUndisplayable= 0; for (int i= 0; i<iend; i++) { theFont = new Font(fontList[i], Font.PLAIN, 11); g.setFont(theFont); fm = g.getFontMetrics(theFont); fontHeight += fm.getHeight(); g.drawString(fontList[i], 10, fontHeight); arr[i]= fm.getHeight(); if (i+iend != count) { theFont = new Font(fontList[i+iend], Font.PLAIN, 11); if (theFont.canDisplay('A')) { int ind= theFont.canDisplayUpTo("zÀÿĀ"); if (ind>0 && ind<3) { // 'z' is recognized. System.console().printf("%s%s %s%n", "UpTo: ", ind, theFont.getName()); } } else if (!theFont.canDisplay('A')) { System.out.println(theFont.getName()); iUndisplayable++; } else if (hasMissingGlyphs(theFont, "zÀÿ")) { System.out.println("Missing glyph: " +theFont.getName()); iUndisplayable++; } g.setFont(theFont); g.drawString(fontList[i+iend], 200, fontHeight); arr[i+iend]= g.getFontMetrics(theFont).getHeight(); } if (i+idif < count) { theFont = new Font(fontList[i+idif], Font.PLAIN, 11); g.setFont(theFont); g.drawString(fontList[i+idif], 400, fontHeight); arr[i+idif]= g.getFontMetrics(theFont).getHeight(); } } // End for. if (first) { first= false; System.out.println("Total: "+iUndisplayable); } } } }

EDIT

I just asked Stackoverflow's AI and was recommended to "inspect glyph codes via GlyphVector". So I implemented the given method:

public boolean hasMissingGlyphs(Font font, String text) { // Create a FontRenderContext. Using a buffered image avoids needing a visible // component. FontRenderContext frc = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB) .createGraphics().getFontRenderContext(); GlyphVector gv = font.createGlyphVector(frc, text); for (int i = 0; i < gv.getNumGlyphs(); i++) { int glyphCode = gv.getGlyphCode(i); if (glyphCode == 0) { // glyph code 0 is usually the ".notdef" / missing glyph return true; } } return false; }

Unfortunately it didn't find more. I updated my original code.

Read Entire Article