Java hosting clients happen to require custom font for their dynamically generated images or reports. Basically, there are 2 methods of making new TTF fonts available to your servlets or JSP - installing in JDK directory tree or outside of it. The methods and their variants will be described below in more details with examples.
Installation outside of JDK tree
This is preferred method as you can embed the font files inside your application (.war or .jar) and do not depend on what fonts are provided by the JVM your application is running in or underlying OS. You can also place fonts in a subdirectory of your home directory. The fonts can be loaded on the fly.
Optionally - when you request the install on our side - we can choose to install the font system-wide so that any JDK can see it. Example of a font already installed this way on our shared Java hosting servers is Bitstream Vera that can be used (in a slanted variant in this example) simply by calling its name:
Font font = new Font("Bitstream Vera Sans Mono Oblique",Font.PLAIN,32);
Bitstream Vera Sans Bold from OS (seen by JVM) | Verdana Bold from WEB-INF/lib of a web application |
Installation in JDK tree
Open support ticket and ask for installaton of your font for given JDK. If approved, it will be installed in /opt/YOURJDKVERSION/jre/lib/fonts
directory e.g. /opt/jdk1.6.0_25/jre/lib/fonts
. You should be aware that if you change JDK version your font will no longer be accessible unless it is also installed in the current JDK directory tree. Note: there is no need for fonts.dir and fonts.scale update with mkfontscale/mkfontdir commands by support.
As a last resort you can install your own JDK in your home directory, overwrite JAVA_HOME
in ~/.bashrc
and copy the fonts to $JAVA_HOME/jre/lib/fonts
directory. This approach is not recommended in our environment as .bashrc
can be overwritten by JCP control panel though.
By default, JVM will see fonts provided by host OS e.g. from /usr/share/fonts
and the ones placed in $JAVA_HOME/jre/lib/fonts
. To start with, you can check fonts availability with the following JSP code:
<%@page pageEncoding="UTF-8" language="java" import="java.awt.*"%>
<%@page contentType="text/html;charset=UTF-8"%>
<html><head><META http-equiv="Content-Type" content="text/html;charset=UTF-8"></head>
<body>
<% GraphicsEnvironment e = GraphicsEnvironment.getLocalGraphicsEnvironment();
Font[] fonts = e.getAllFonts(); // Get the fonts
for (Font f : fonts) {
out.println(f.getFontName());
out.println("<br/>");
}
%>
</body></html>
In the next code snippet we generate an image with text written using our TTF font placed in WEB-INF/lib
.
<%@page import="java.awt.*,java.io.*,java.awt.image.*,java.awt.font.*,java.awt.geom.*,javax.imageio.*"%>
<% String text = "Custom font test";
String font_file = "verdana.ttf";
font_file = request.getRealPath("WEB-INF/lib/" + font_file);
Font font = Font.createFont(Font.TRUETYPE_FONT, new FileInputStream(font_file));
font = font.deriveFont(25.0f);
// create temporary 1x1 image to get FontRenderingContext needed to calculate image size
BufferedImage buffer = new BufferedImage(1,1,BufferedImage.TYPE_INT_RGB);
Graphics2D g2 = buffer.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
FontRenderContext fc = g2.getFontRenderContext();
Rectangle2D bounds = font.getStringBounds(text,fc);
// calculate the size of the text
int width = (int) bounds.getWidth();
int height = (int) bounds.getHeight();
// prepare final image with proper dimensions
buffer = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
g2 = buffer.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setFont(font);
// actually do the drawing
g2.setColor(Color.white);
g2.fillRect(0,0,width,height);
g2.setColor(Color.blue);
g2.drawString(text,0,(int)-bounds.getY());
// set the content type, get the output stream and print image as PNG
response.setContentType("image/png");
OutputStream os = response.getOutputStream();
ImageIO.write(buffer, "png", os);
os.close();
%>
As the above image generation script outputs data directly to browser, it can be included in another page with:
<img src="/pathto/font.jsp">
In the same easy way we can use custom fonts in our dynamically generated PDF documents. We need to download a PDF library for example iText and place the included jar (e.g. itextpdf-5.1.3.jar
) in WEB-INF/lib
directory of our web application.
<%@page import="java.io.*,java.awt.Color,java.io.ByteArrayOutputStream,"%>
<%@page import="com.itextpdf.text.*,com.itextpdf.text.pdf.*"%>
<% FontFactory.register(request.getRealPath("verdana.ttf"), "my_font_alias");
Document document = new Document();
PdfWriter.getInstance(document, new FileOutputStream(request.getRealPath("hello.pdf")));
document.open();
Paragraph p = new Paragraph("This is a PDF paragraph written with custom font", FontFactory.getFont("my_font_alias", 18.0f, Font.BOLDITALIC, new BaseColor(0, 0, 255)));
document.add(p);
document.close();
%>
And if we decide to send the PDF directly to the browser it may look like below.
<%@page import="java.io.*,java.awt.Color,java.io.ByteArrayOutputStream"%>
<%@page import="com.itextpdf.text.*,com.itextpdf.text.pdf.*"%>
<% FontFactory.register(request.getRealPath("verdana.ttf"), "my_font_alias");
ByteArrayOutputStream baos = new ByteArrayOutputStream();
Document document = new Document();
PdfWriter.getInstance(document, baos);
document.open();
Paragraph p = new Paragraph("This is a PDF paragraph written with custom font", FontFactory.getFont("my_font_alias", 18.0f, Font.BOLDITALIC, new BaseColor(0, 0, 255)));
document.add(p);
document.close();
response.setHeader("Expires", "0");
response.setHeader("Cache-Control", "must-revalidate, post-check=0, pre-check=0");
response.setHeader("Pragma", "public");
// setting the content type
response.setContentType("application/pdf");
// the contentlength is needed for MSIE!!!
response.setContentLength(baos.size());
// write ByteArrayOutputStream to the ServletOutputStream
ServletOutputStream os = response.getOutputStream();
baos.writeTo(os);
os.flush();
%>
To sum up, JDK offers quite simple custom TTF font support and leaves the decision on where to keep the font to the developer.