/** Get the outline of a character given the glyph id */ protected synchronized GeneralPath getOutline(int glyphId, float width) { // find the glyph itself GlyfTable glyf = (GlyfTable) this.font.getTable("glyf"); Glyf g = glyf.getGlyph(glyphId); GeneralPath gp = null; if (g instanceof GlyfSimple) { gp = renderSimpleGlyph((GlyfSimple) g); } else if (g instanceof GlyfCompound) { gp = renderCompoundGlyph(glyf, (GlyfCompound) g); } else { gp = new GeneralPath(); } // calculate the advance HmtxTable hmtx = (HmtxTable) this.font.getTable("hmtx"); float advance = hmtx.getAdvance(glyphId) / this.unitsPerEm; // scale the glyph to match the desired advance float widthfactor = width / advance; // the base transform scales the glyph to 1x1 AffineTransform at = AffineTransform.getScaleInstance(1 / this.unitsPerEm, 1 / this.unitsPerEm); at.concatenate(AffineTransform.getScaleInstance(widthfactor, 1)); gp.transform(at); return gp; }
/** Render a compound glyf */ protected GeneralPath renderCompoundGlyph(GlyfTable glyf, GlyfCompound g) { GeneralPath gp = new GeneralPath(); for (int i = 0; i < g.getNumComponents(); i++) { // find and render the component glyf Glyf gl = glyf.getGlyph(g.getGlyphIndex(i)); GeneralPath path = null; if (gl instanceof GlyfSimple) { path = renderSimpleGlyph((GlyfSimple) gl); } else if (gl instanceof GlyfCompound) { path = renderCompoundGlyph(glyf, (GlyfCompound) gl); } else { throw new RuntimeException("Unsupported glyph type " + gl.getClass().getCanonicalName()); } // multiply the translations by units per em double[] matrix = g.getTransform(i); // transform the path path.transform(new AffineTransform(matrix)); // add it to the global path gp.append(path, false); } return gp; }