static UnderlineMetrics deriveUnderlineMetrics(FreeTypeFontGenerator generator, int size) { try { // Size metrics aren't publicly accessible (as of 1.9.3). (Ab)use reflection to gain access. Field faceField = FreeTypeFontGenerator.class.getDeclaredField("face"); faceField.setAccessible(true); Face face = (Face)faceField.get(generator); SizeMetrics sizeMetrics = face.getSize().getMetrics(); int yScale = sizeMetrics.getYscale(); // 16.16 fixed point float position = FreeType.toInt(face.getUnderlinePosition() * yScale >> 16); float thickness = FreeType.toInt(face.getUnderlineThickness() * yScale >> 16); return new UnderlineMetrics(position, thickness); } catch (Exception e) { LOG.error("Error fetching FreeType underline metrics", e); } // Return a reasonable default return UnderlineMetrics.defaultInstance(size); }
/** Uses ascender and descender of font to calculate real height that makes all glyphs to fit in given pixel size. Source: * http://nothings.org/stb/stb_truetype.h / stbtt_ScaleForPixelHeight */ public int scaleForPixelHeight (int height) { setPixelSizes(0, height); SizeMetrics fontMetrics = face.getSize().getMetrics(); int ascent = FreeType.toInt(fontMetrics.getAscender()); int descent = FreeType.toInt(fontMetrics.getDescender()); return height * height / (ascent - descent); }
/** Uses max advance, ascender and descender of font to calculate real height that makes any n glyphs to fit in given pixel * width. * @param width the max width to fit (in pixels) * @param numChars max number of characters that to fill width */ public int scaleForPixelWidth (int width, int numChars) { SizeMetrics fontMetrics = face.getSize().getMetrics(); int advance = FreeType.toInt(fontMetrics.getMaxAdvance()); int ascent = FreeType.toInt(fontMetrics.getAscender()); int descent = FreeType.toInt(fontMetrics.getDescender()); int unscaledHeight = ascent - descent; int height = unscaledHeight * width / (advance * numChars); setPixelSizes(0, height); return height; }
/** Uses ascender and descender of font to calculate real height that makes all glyphs to fit in given pixel size. Source: * http://nothings.org/stb/stb_truetype.h / stbtt_ScaleForPixelHeight */ public int scaleForPixelHeight (int height) { if (!bitmapped && !FreeType.setPixelSizes(face, 0, height)) throw new GdxRuntimeException("Couldn't set size for font"); SizeMetrics fontMetrics = face.getSize().getMetrics(); int ascent = FreeType.toInt(fontMetrics.getAscender()); int descent = FreeType.toInt(fontMetrics.getDescender()); return height * height / (ascent - descent); }
/** Uses max advance, ascender and descender of font to calculate real height that makes any n glyphs to fit in given pixel width. * @param width the max width to fit (in pixels) * @param numChars max number of characters that to fill width */ public int scaleForPixelWidth(int width, int numChars) { SizeMetrics fontMetrics = face.getSize().getMetrics(); int advance = FreeType.toInt(fontMetrics.getMaxAdvance()); int ascent = FreeType.toInt(fontMetrics.getAscender()); int descent = FreeType.toInt(fontMetrics.getDescender()); int unscaledHeight = ascent - descent; int height = unscaledHeight * width / (advance * numChars); if (!bitmapped && !FreeType.setPixelSizes(face, 0, height)) throw new GdxRuntimeException("Couldn't set size for font"); return height; }
/** Returns null if glyph was not found. If there is nothing to render, for example with various space characters, then bitmap * is null. */ public GlyphAndBitmap generateGlyphAndBitmap (int c, int size, boolean flip) { setPixelSizes(0, size); SizeMetrics fontMetrics = face.getSize().getMetrics(); int baseline = FreeType.toInt(fontMetrics.getAscender()); // Check if character exists in this font. // 0 means 'undefined character code' if (face.getCharIndex(c) == 0) { return null; } // Try to load character if (!loadChar(c)) { throw new GdxRuntimeException("Unable to load character!"); } GlyphSlot slot = face.getGlyph(); // Try to render to bitmap Bitmap bitmap; if (bitmapped) { bitmap = slot.getBitmap(); } else if (!slot.renderGlyph(FreeType.FT_RENDER_MODE_NORMAL)) { bitmap = null; } else { bitmap = slot.getBitmap(); } GlyphMetrics metrics = slot.getMetrics(); Glyph glyph = new Glyph(); if (bitmap != null) { glyph.width = bitmap.getWidth(); glyph.height = bitmap.getRows(); } else { glyph.width = 0; glyph.height = 0; } glyph.xoffset = slot.getBitmapLeft(); glyph.yoffset = flip ? -slot.getBitmapTop() + baseline : -(glyph.height - slot.getBitmapTop()) - baseline; glyph.xadvance = FreeType.toInt(metrics.getHoriAdvance()); glyph.srcX = 0; glyph.srcY = 0; glyph.id = c; GlyphAndBitmap result = new GlyphAndBitmap(); result.glyph = glyph; result.bitmap = bitmap; return result; }
/** Returns null if glyph was not found. If there is nothing to render, for example with various space characters, then bitmap * is null. */ public GlyphAndBitmap generateGlyphAndBitmap (int c, int size, boolean flip) { if (!bitmapped && !FreeType.setPixelSizes(face, 0, size)) throw new GdxRuntimeException("Couldn't set size for font"); SizeMetrics fontMetrics = face.getSize().getMetrics(); int baseline = FreeType.toInt(fontMetrics.getAscender()); // Check if character exists in this font. // 0 means 'undefined character code' if (FreeType.getCharIndex(face, c) == 0) { return null; } // Try to load character if (!FreeType.loadChar(face, c, FreeType.FT_LOAD_DEFAULT)) { throw new GdxRuntimeException("Unable to load character!"); } GlyphSlot slot = face.getGlyph(); // Try to render to bitmap Bitmap bitmap; if (bitmapped) { bitmap = slot.getBitmap(); } else if (!FreeType.renderGlyph(slot, FreeType.FT_RENDER_MODE_LIGHT)) { bitmap = null; } else { bitmap = slot.getBitmap(); } GlyphMetrics metrics = slot.getMetrics(); Glyph glyph = new Glyph(); if (bitmap != null) { glyph.width = bitmap.getWidth(); glyph.height = bitmap.getRows(); } else { glyph.width = 0; glyph.height = 0; } glyph.xoffset = slot.getBitmapLeft(); glyph.yoffset = flip ? -slot.getBitmapTop() + baseline : -(glyph.height - slot.getBitmapTop()) - baseline; glyph.xadvance = FreeType.toInt(metrics.getHoriAdvance()); glyph.srcX = 0; glyph.srcY = 0; glyph.id = c; GlyphAndBitmap result = new GlyphAndBitmap(); result.glyph = glyph; result.bitmap = bitmap; return result; }