Text Rendering using TrueType Font | Java

Rendering Text

To render text, implement com.aspose.font.IGlyphOutlinePainter to collect glyph outlines in a Java 2D GeneralPath. Combine the painter and the methods below in the same class. The examples use classes from com.aspose.font, java.awt, java.awt.geom, java.awt.image, javax.imageio, java.io and java.nio.file.

  1. Create a drawText() method that draws text into a BufferedImage and saves it as a PNG file. This includes the following steps:

Auxillary steps for this strategy

The following snippets implement the outline painter and drawText() method. The 300 DPI value controls glyph scaling; it does not set PNG resolution metadata.

 1private static final class GlyphOutlinePainter implements IGlyphOutlinePainter {
 2    private final GeneralPath path;
 3
 4    private GlyphOutlinePainter(GeneralPath path) {
 5        this.path = path;
 6    }
 7
 8    @Override
 9    public void moveTo(MoveTo moveTo) {
10        path.moveTo(moveTo.getX(), moveTo.getY());
11    }
12
13    @Override
14    public void lineTo(LineTo lineTo) {
15        path.lineTo(lineTo.getX(), lineTo.getY());
16    }
17
18    @Override
19    public void curveTo(CurveTo curveTo) {
20        path.curveTo(curveTo.getX1(), curveTo.getY1(), curveTo.getX2(), curveTo.getY2(),
21                curveTo.getX3(), curveTo.getY3());
22    }
23
24    @Override
25    public void closePath() {
26        path.closePath();
27    }
28}
 1private static void drawText(String text, IFont font, double fontSize,
 2        Paint backgroundBrush, Paint textBrush, String outputFile) throws IOException {
 3    GlyphId[] glyphIds = new GlyphId[text.length()];
 4    for (int i = 0; i < text.length(); i++) {
 5        glyphIds[i] = font.getEncoding().decodeToGid(text.charAt(i));
 6    }
 7    double dpi = 300;
 8    double resolutionCorrection = dpi / 72;
 9    BufferedImage outputBitmap = new BufferedImage(960, 720, BufferedImage.TYPE_INT_RGB);
10    Graphics2D graphics = outputBitmap.createGraphics();
11    try {
12        graphics.setPaint(backgroundBrush);
13        graphics.fillRect(0, 0, outputBitmap.getWidth(), outputBitmap.getHeight());
14        graphics.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
15        GlyphId previousGlyphId = null;
16        double glyphXCoordinate = 0;
17        double glyphYCoordinate = fontSize * resolutionCorrection;
18        for (GlyphId glyphId : glyphIds) {
19            if (glyphId == null) {
20                continue;
21            }
22            Glyph glyph = font.getGlyphAccessor().getGlyphById(glyphId);
23            if (glyph == null) {
24                continue;
25            }
26            if (previousGlyphId != null) {
27                double kerning = font.getMetrics().getKerningValue(previousGlyphId, glyphId)
28                        / glyph.getSourceResolution() * fontSize * resolutionCorrection;
29                double advance = fontWidthToImageWidth(font.getMetrics().getGlyphWidth(previousGlyphId),
30                        glyph.getSourceResolution(), fontSize, dpi);
31                glyphXCoordinate += kerning + advance;
32            }
33            GeneralPath path = new GeneralPath();
34            IGlyphRenderer renderer = new GlyphOutlineRenderer(new GlyphOutlinePainter(path));
35            TransformationMatrix matrix = new TransformationMatrix(new double[] {
36                    fontSize * resolutionCorrection, 0, 0, -fontSize * resolutionCorrection,
37                    glyphXCoordinate, glyphYCoordinate
38            });
39            renderer.renderGlyph(font, glyphId, matrix);
40            path.setWindingRule(GeneralPath.WIND_NON_ZERO);
41            graphics.setPaint(textBrush);
42            graphics.fill(path);
43            previousGlyphId = glyphId;
44        }
45    } finally {
46        graphics.dispose();
47    }
48    if (!ImageIO.write(outputBitmap, "png", new File(outputFile))) {
49        throw new IOException("No PNG writer is available.");
50    }
51}
  1. create utility method to calculate font width to image width as shown in the code sample below
1private static double fontWidthToImageWidth(double width, int fontSourceResolution,
2        double fontSize, double dpi) {
3    return width / fontSourceResolution * fontSize * (dpi / 72);
4}

Calling the Rendering Text functionality

Use the following code in your application and handle or declare IOException. It loads Montserrat Bold and Lato Regular (in place of the original Lora Bold) and creates hello1_montserrat_out.png and hello2_lato_out.png. Adapt getDataDir(), getOutputDir() and the sibling TTF input paths to your application; the output directory must exist and be writable.

 1String firstFontPath = Paths.get(getDataDir(), "..", "TTF", "montserrat-bold.ttf")
 2        .normalize().toString();
 3String secondFontPath = Paths.get(getDataDir(), "..", "TTF", "LatoWeb-Regular.ttf")
 4        .normalize().toString();
 5TtfFont firstFont = (TtfFont) Font.open(new FontDefinition(FontType.TTF,
 6        new FontFileDefinition("ttf", new FileSystemStreamSource(firstFontPath))));
 7TtfFont secondFont = (TtfFont) Font.open(new FontDefinition(FontType.TTF,
 8        new FontFileDefinition("ttf", new FileSystemStreamSource(secondFontPath))));
 9
10String firstOutput = Paths.get(getOutputDir(), "hello1_montserrat_out.png").toString();
11String secondOutput = Paths.get(getOutputDir(), "hello2_lato_out.png").toString();
12drawText("Hello world", firstFont, 14, Color.WHITE, Color.BLACK, firstOutput);
13drawText("Hello world", secondFont, 14, Color.YELLOW, Color.RED, secondOutput);