I am tackling the same problem and copied java.awt.Font.canDisplayUpTo()
method while adapting it to use PDFont instead. Thanks to @jmc34 and their sanitization method for the font.encode()
example and the inspiration!
private static int canDisplayUpTo(String text, PDFont font) {
int len = text.length();
for (int i = 0; i < len; i++) {
try {
font.encode(text.substring(i, i + 1));
} catch (IOException | IllegalArgumentException e) {
return i;
}
}
return -1;
}
Because I had already written these methods using Font.canDisplayUpTo()
and it was working beautifully until I had to use PDFont.
public static String getFontSupportedString(String text) {
try {
Font font = Font.createFont(Font.TRUETYPE_FONT, getBoldFontStream());
return replaceUnsupportedGlyphs(text, font);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private static String replaceUnsupportedGlyphs(String text, Font font) {
int failIndex = font.canDisplayUpTo(text);
if (failIndex == -1) {
return text;
} else if (failIndex < text.length()) {
return text.substring(0, failIndex)
+ REPLACEMENT_CHARACTER
+ replaceUnsupportedGlyphs(text.substring(failIndex + 1), font);
} else {
return text + REPLACEMENT_CHARACTER;
}
}
The only change was to replace font.canDisplayUpTo(text)
with my canDisplayUpTo(text, font)
method, and we were back in business.
Final Code:
public static String getFontSupportedString(String text) {
try {
PDFont font = PDType0Font.load(new PDDocument(), getBoldFontStream());
return replaceUnsupportedGlyphs(text, font);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private static String replaceUnsupportedGlyphs(String text, PDFont font) {
int failIndex = canDisplayUpTo(text, font);
if (failIndex == -1) {
return text;
} else if (failIndex < text.length()) {
return text.substring(0, failIndex)
+ REPLACEMENT_CHARACTER
+ replaceUnsupportedGlyphs(text.substring(failIndex + 1), font);
} else {
return text + REPLACEMENT_CHARACTER;
}
}
private static int canDisplayUpTo(String text, PDFont font) {
int len = text.length();
for (int i = 0; i < len; i++) {
try {
font.encode(text.substring(i, i + 1));
} catch (IOException | IllegalArgumentException e) {
return i;
}
}
return -1;
}
I have not done efficiency testing, and so make no claims in that regard.
Cheers!