Added more accurate font height utility methods. Moved font utility
methods into FontUtil class.
This commit is contained in:
parent
61f4f5a4de
commit
01e5eab0ca
|
@ -0,0 +1,279 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2014 dorkbox, llc
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package dorkbox.util;
|
||||||
|
|
||||||
|
import java.awt.Color;
|
||||||
|
import java.awt.Font;
|
||||||
|
import java.awt.FontFormatException;
|
||||||
|
import java.awt.FontMetrics;
|
||||||
|
import java.awt.Graphics2D;
|
||||||
|
import java.awt.GraphicsEnvironment;
|
||||||
|
import java.awt.RenderingHints;
|
||||||
|
import java.awt.font.FontRenderContext;
|
||||||
|
import java.awt.font.GlyphVector;
|
||||||
|
import java.awt.geom.Rectangle2D;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.Enumeration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Java Font utilities
|
||||||
|
*/
|
||||||
|
public
|
||||||
|
class FontUtil {
|
||||||
|
/** Default location where all the fonts are stored */
|
||||||
|
@Property
|
||||||
|
public static String FONTS_LOCATION = "resources/fonts";
|
||||||
|
|
||||||
|
|
||||||
|
/** All of the fonts in the {@link #FONTS_LOCATION} will be loaded by the Font manager */
|
||||||
|
public static
|
||||||
|
void loadAllFonts() {
|
||||||
|
boolean isJava6 = OS.javaVersion == 6;
|
||||||
|
|
||||||
|
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
|
||||||
|
Enumeration<URL> fonts = LocationResolver.getResources(FONTS_LOCATION);
|
||||||
|
|
||||||
|
if (fonts.hasMoreElements()) {
|
||||||
|
// skip the FIRST one, since we always know that the first one is the directory we asked for
|
||||||
|
fonts.nextElement();
|
||||||
|
|
||||||
|
while (fonts.hasMoreElements()) {
|
||||||
|
URL url = fonts.nextElement();
|
||||||
|
InputStream is = null;
|
||||||
|
|
||||||
|
//noinspection TryWithIdenticalCatches
|
||||||
|
try {
|
||||||
|
String path = url.toURI()
|
||||||
|
.getPath();
|
||||||
|
|
||||||
|
// only support TTF fonts (java6) and OTF fonts (7+).
|
||||||
|
if (path.endsWith(".ttf") || (!isJava6 && path.endsWith(".otf"))) {
|
||||||
|
is = url.openStream();
|
||||||
|
|
||||||
|
Font newFont = Font.createFont(Font.TRUETYPE_FONT, is);
|
||||||
|
// fonts that ALREADY exist are not re-registered
|
||||||
|
ge.registerFont(newFont);
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (URISyntaxException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (FontFormatException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} finally {
|
||||||
|
if (is != null) {
|
||||||
|
try {
|
||||||
|
is.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets (or creates) a Font based on a specific system property. Remember: the FontManager caches system/loaded fonts, so we don't need
|
||||||
|
* to ALSO cache them as well. see: https://stackoverflow.com/questions/6102602/java-awt-is-font-a-lightweight-object
|
||||||
|
* <p>
|
||||||
|
* Also remember that if requesting a BOLD hint for a font, the system will look for a font that is BOLD. If none are found, it
|
||||||
|
* will then apply transforms to the specified font to create a font that is bold. Specifying a bold name AND a bold hint will not
|
||||||
|
* "double bold" the font
|
||||||
|
* <p></p>
|
||||||
|
* For example:
|
||||||
|
* <p>
|
||||||
|
*
|
||||||
|
* Font titleTextFont = SwingUtil.parseFont("Source Code Pro Bold 16");
|
||||||
|
*
|
||||||
|
* @param fontInfo This is the font "name style size", as a string. For example "Source Code Pro Bold BOLD 16"
|
||||||
|
*
|
||||||
|
* @return the specified font
|
||||||
|
*/
|
||||||
|
public static
|
||||||
|
Font parseFont(final String fontInfo) {
|
||||||
|
try {
|
||||||
|
final int sizeIndex = fontInfo.lastIndexOf(" ");
|
||||||
|
|
||||||
|
String size = fontInfo.substring(sizeIndex + 1);
|
||||||
|
|
||||||
|
// hint is at most 6 (ITALIC) before sizeIndex - we can use this to our benefit.
|
||||||
|
int styleIndex = fontInfo.indexOf(" ", sizeIndex - 7);
|
||||||
|
String styleString = fontInfo.substring(styleIndex + 1, sizeIndex);
|
||||||
|
int style = Font.PLAIN;
|
||||||
|
|
||||||
|
if (styleString.equalsIgnoreCase("bold")) {
|
||||||
|
style = Font.BOLD;
|
||||||
|
}
|
||||||
|
else if (styleString.equalsIgnoreCase("italic")) {
|
||||||
|
style = Font.ITALIC;
|
||||||
|
}
|
||||||
|
|
||||||
|
String fontName = fontInfo.substring(0, styleIndex);
|
||||||
|
|
||||||
|
// this can be WRONG, in which case it will just error out
|
||||||
|
//noinspection MagicConstant
|
||||||
|
return new Font(fontName, style, Integer.parseInt(size));
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("Unable to load font info from '" + fontInfo + "'", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the correct font (in GENERAL) for a specified pixel height.
|
||||||
|
*
|
||||||
|
* @param font the font we are checking
|
||||||
|
* @param height the height in pixels we want to get as close as possible to
|
||||||
|
*
|
||||||
|
* @return the font (derived from the specified font) that is as close as possible to the requested height. If our font-size is less
|
||||||
|
* than the height, then the approach is from the low size (so the returned font will always fit inside the box)
|
||||||
|
*/
|
||||||
|
public static
|
||||||
|
Font getFontForSpecificHeight(final Font font, final int height) {
|
||||||
|
int size = font.getSize();
|
||||||
|
Boolean lastAction = null;
|
||||||
|
BufferedImage image = new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB);
|
||||||
|
Graphics2D g = image.createGraphics();
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
Font fontCheck = new Font(font.getName(), Font.PLAIN, size);
|
||||||
|
|
||||||
|
FontMetrics metrics = g.getFontMetrics(fontCheck);
|
||||||
|
Rectangle2D rect = metrics.getStringBounds("`Tj|┃", g); // `Tj|┃ are glyphs that are at the top/bottom of the fontset (usually)
|
||||||
|
double testHeight = rect.getHeight();
|
||||||
|
|
||||||
|
if (testHeight < height && lastAction != Boolean.FALSE) {
|
||||||
|
size++;
|
||||||
|
lastAction = Boolean.TRUE;
|
||||||
|
} else if (testHeight > height && lastAction != Boolean.TRUE) {
|
||||||
|
size--;
|
||||||
|
lastAction = Boolean.FALSE;
|
||||||
|
} else {
|
||||||
|
// either we are the exact size, or we are ONE font size to big/small (depending on what our initial guess was)
|
||||||
|
g.dispose();
|
||||||
|
return fontCheck;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the specified font height for a specific string
|
||||||
|
*
|
||||||
|
* @param font the font to use
|
||||||
|
* @param string the string to get the size of
|
||||||
|
*
|
||||||
|
* @return the height of the string
|
||||||
|
*/
|
||||||
|
public static
|
||||||
|
int getFontHeight(final Font font, final String string) {
|
||||||
|
BufferedImage image = new BufferedImage(1, 1, 1);
|
||||||
|
Graphics2D g = image.createGraphics();
|
||||||
|
FontRenderContext frc = g.getFontRenderContext();
|
||||||
|
GlyphVector gv = font.createGlyphVector(frc, string);
|
||||||
|
int height = gv.getPixelBounds(null, 0, 0).height;
|
||||||
|
g.dispose();
|
||||||
|
|
||||||
|
return height;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the maximum font height used by alpha-numeric characters ONLY
|
||||||
|
*/
|
||||||
|
public static
|
||||||
|
int getAlphaNumbericFontHeight(final Font font) {
|
||||||
|
// Because font metrics is based on a graphics context, we need to create a small, temporary image to determine the width and height
|
||||||
|
BufferedImage image = new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB);
|
||||||
|
Graphics2D g = image.createGraphics();
|
||||||
|
|
||||||
|
FontMetrics metrics = g.getFontMetrics(font);
|
||||||
|
int height = metrics.getAscent() + metrics.getDescent();
|
||||||
|
g.dispose();
|
||||||
|
|
||||||
|
return height;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the maximum font height used by of ALL characters.
|
||||||
|
*/
|
||||||
|
public static
|
||||||
|
int getFontHeight(final Font font) {
|
||||||
|
// Because font metrics is based on a graphics context, we need to create a small, temporary image to determine the width and height
|
||||||
|
BufferedImage image = new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB);
|
||||||
|
Graphics2D g = image.createGraphics();
|
||||||
|
|
||||||
|
FontMetrics metrics = g.getFontMetrics(font);
|
||||||
|
int height = metrics.getMaxAscent() + metrics.getMaxDescent();
|
||||||
|
|
||||||
|
g.dispose();
|
||||||
|
|
||||||
|
return height;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the specified text (with a font) and as an image
|
||||||
|
*
|
||||||
|
* @param font the specified font to render the image
|
||||||
|
* @return a BufferedImage of the specified text, font, and color
|
||||||
|
*/
|
||||||
|
public static
|
||||||
|
BufferedImage getFontAsImage(final Font font, String text, Color foregroundColor) {
|
||||||
|
// Because font metrics is based on a graphics context, we need to create a small, temporary image to determine the width and height
|
||||||
|
BufferedImage img = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);
|
||||||
|
Graphics2D g2d = img.createGraphics();
|
||||||
|
g2d.setFont(font);
|
||||||
|
|
||||||
|
FontMetrics fm = g2d.getFontMetrics();
|
||||||
|
int width = fm.stringWidth(text);
|
||||||
|
int height = fm.getHeight();
|
||||||
|
g2d.dispose();
|
||||||
|
|
||||||
|
// make it square
|
||||||
|
if (width > height) {
|
||||||
|
height = width;
|
||||||
|
} else {
|
||||||
|
width = height;
|
||||||
|
}
|
||||||
|
|
||||||
|
img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
|
||||||
|
g2d = img.createGraphics();
|
||||||
|
|
||||||
|
g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
|
||||||
|
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||||
|
g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
|
||||||
|
g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
|
||||||
|
g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
|
||||||
|
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
|
||||||
|
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
|
||||||
|
g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
|
||||||
|
|
||||||
|
g2d.setFont(font);
|
||||||
|
fm = g2d.getFontMetrics();
|
||||||
|
|
||||||
|
g2d.setColor(foregroundColor);
|
||||||
|
|
||||||
|
// width/4 centers the text in the image
|
||||||
|
g2d.drawString(text, width/4.0f, fm.getAscent());
|
||||||
|
g2d.dispose();
|
||||||
|
|
||||||
|
return img;
|
||||||
|
}
|
||||||
|
}
|
|
@ -15,38 +15,27 @@
|
||||||
*/
|
*/
|
||||||
package dorkbox.util;
|
package dorkbox.util;
|
||||||
|
|
||||||
import java.awt.Color;
|
|
||||||
import java.awt.Component;
|
import java.awt.Component;
|
||||||
import java.awt.Container;
|
import java.awt.Container;
|
||||||
import java.awt.Desktop;
|
import java.awt.Desktop;
|
||||||
import java.awt.Dimension;
|
import java.awt.Dimension;
|
||||||
import java.awt.EventQueue;
|
import java.awt.EventQueue;
|
||||||
import java.awt.Font;
|
|
||||||
import java.awt.FontFormatException;
|
|
||||||
import java.awt.FontMetrics;
|
|
||||||
import java.awt.Graphics2D;
|
|
||||||
import java.awt.GraphicsDevice;
|
import java.awt.GraphicsDevice;
|
||||||
import java.awt.GraphicsEnvironment;
|
|
||||||
import java.awt.Image;
|
import java.awt.Image;
|
||||||
import java.awt.MouseInfo;
|
import java.awt.MouseInfo;
|
||||||
import java.awt.Point;
|
import java.awt.Point;
|
||||||
import java.awt.Rectangle;
|
import java.awt.Rectangle;
|
||||||
import java.awt.RenderingHints;
|
|
||||||
import java.awt.Toolkit;
|
import java.awt.Toolkit;
|
||||||
import java.awt.Window;
|
import java.awt.Window;
|
||||||
import java.awt.event.HierarchyEvent;
|
import java.awt.event.HierarchyEvent;
|
||||||
import java.awt.event.HierarchyListener;
|
import java.awt.event.HierarchyListener;
|
||||||
import java.awt.event.KeyEvent;
|
import java.awt.event.KeyEvent;
|
||||||
import java.awt.event.WindowListener;
|
import java.awt.event.WindowListener;
|
||||||
import java.awt.geom.Rectangle2D;
|
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
import java.net.URL;
|
|
||||||
import java.util.Enumeration;
|
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
import javax.swing.AbstractButton;
|
import javax.swing.AbstractButton;
|
||||||
|
@ -57,19 +46,11 @@ import javax.swing.UIManager;
|
||||||
|
|
||||||
public
|
public
|
||||||
class SwingUtil {
|
class SwingUtil {
|
||||||
|
|
||||||
/** Default location where all the fonts are stored */
|
|
||||||
@Property
|
|
||||||
public static String FONTS_LOCATION = "resources/fonts";
|
|
||||||
|
|
||||||
static {
|
static {
|
||||||
/*
|
/*
|
||||||
* hack workaround for starting the Toolkit thread before any Timer stuff
|
* hack workaround for starting the Toolkit thread before any Timer stuff javax.swing.Timer uses the Event Dispatch Thread, which is not
|
||||||
* javax.swing.Timer uses the Event Dispatch Thread, which is not
|
* created until the Toolkit thread starts up. Using the Swing Timer before starting this stuff starts up may get unexpected
|
||||||
* created until the Toolkit thread starts up. Using the Swing
|
* results (such as taking a long time before the first timer event).
|
||||||
* Timer before starting this stuff starts up may get unexpected
|
|
||||||
* results (such as taking a long time before the first timer
|
|
||||||
* event).
|
|
||||||
*/
|
*/
|
||||||
Toolkit.getDefaultToolkit();
|
Toolkit.getDefaultToolkit();
|
||||||
}
|
}
|
||||||
|
@ -173,100 +154,6 @@ class SwingUtil {
|
||||||
new Exception("Could not load " + lookAndFeel + ", it was not available.").printStackTrace();
|
new Exception("Could not load " + lookAndFeel + ", it was not available.").printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** All of the fonts in the {@link #FONTS_LOCATION} will be loaded by the Font manager */
|
|
||||||
public static
|
|
||||||
void loadAllFonts() {
|
|
||||||
boolean isJava6 = OS.javaVersion == 6;
|
|
||||||
|
|
||||||
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
|
|
||||||
Enumeration<URL> fonts = LocationResolver.getResources(FONTS_LOCATION);
|
|
||||||
|
|
||||||
if (fonts.hasMoreElements()) {
|
|
||||||
// skip the FIRST one, since we always know that the first one is the directory we asked for
|
|
||||||
fonts.nextElement();
|
|
||||||
|
|
||||||
while (fonts.hasMoreElements()) {
|
|
||||||
URL url = fonts.nextElement();
|
|
||||||
InputStream is = null;
|
|
||||||
|
|
||||||
//noinspection TryWithIdenticalCatches
|
|
||||||
try {
|
|
||||||
String path = url.toURI()
|
|
||||||
.getPath();
|
|
||||||
|
|
||||||
// only support TTF fonts (java6) and OTF fonts (7+).
|
|
||||||
if (path.endsWith(".ttf") || (!isJava6 && path.endsWith(".otf"))) {
|
|
||||||
is = url.openStream();
|
|
||||||
|
|
||||||
Font newFont = Font.createFont(Font.TRUETYPE_FONT, is);
|
|
||||||
// fonts that ALREADY exist are not re-registered
|
|
||||||
ge.registerFont(newFont);
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
} catch (URISyntaxException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
} catch (FontFormatException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
} finally {
|
|
||||||
if (is != null) {
|
|
||||||
try {
|
|
||||||
is.close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets (or creates) a Font based on a specific system property. Remember: the FontManager caches system/loaded fonts, so we don't need
|
|
||||||
* to ALSO cache them as well. see: https://stackoverflow.com/questions/6102602/java-awt-is-font-a-lightweight-object
|
|
||||||
* <p>
|
|
||||||
* Also remember that if requesting a BOLD hint for a font, the system will look for a font that is BOLD. If none are found, it
|
|
||||||
* will then apply transforms to the specified font to create a font that is bold. Specifying a bold name AND a bold hint will not
|
|
||||||
* "double bold" the font
|
|
||||||
* <p></p>
|
|
||||||
* For example:
|
|
||||||
* <p>
|
|
||||||
*
|
|
||||||
* Font titleTextFont = SwingUtil.parseFont("Source Code Pro Bold 16");
|
|
||||||
*
|
|
||||||
* @param fontInfo This is the font "name style size", as a string. For example "Source Code Pro Bold BOLD 16"
|
|
||||||
*
|
|
||||||
* @return the specified font
|
|
||||||
*/
|
|
||||||
public static
|
|
||||||
Font parseFont(final String fontInfo) {
|
|
||||||
try {
|
|
||||||
final int sizeIndex = fontInfo.lastIndexOf(" ");
|
|
||||||
|
|
||||||
String size = fontInfo.substring(sizeIndex + 1);
|
|
||||||
|
|
||||||
// hint is at most 6 (ITALIC) before sizeIndex - we can use this to our benefit.
|
|
||||||
int styleIndex = fontInfo.indexOf(" ", sizeIndex - 7);
|
|
||||||
String styleString = fontInfo.substring(styleIndex + 1, sizeIndex);
|
|
||||||
int style = Font.PLAIN;
|
|
||||||
|
|
||||||
if (styleString.equalsIgnoreCase("bold")) {
|
|
||||||
style = Font.BOLD;
|
|
||||||
}
|
|
||||||
else if (styleString.equalsIgnoreCase("italic")) {
|
|
||||||
style = Font.ITALIC;
|
|
||||||
}
|
|
||||||
|
|
||||||
String fontName = fontInfo.substring(0, styleIndex);
|
|
||||||
|
|
||||||
// this can be WRONG, in which case it will just error out
|
|
||||||
//noinspection MagicConstant
|
|
||||||
return new Font(fontName, style, Integer.parseInt(size));
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new RuntimeException("Unable to load font info from '" + fontInfo + "'", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** used when setting various icon components in the GUI to "nothing", since null doesn't work */
|
/** used when setting various icon components in the GUI to "nothing", since null doesn't work */
|
||||||
public static final Image BLANK_ICON = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB_PRE);
|
public static final Image BLANK_ICON = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB_PRE);
|
||||||
|
|
||||||
|
@ -318,113 +205,6 @@ class SwingUtil {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the correct font (in GENERAL) for a specified pixel height.
|
|
||||||
*
|
|
||||||
* @param font the font we are checking
|
|
||||||
* @param height the height in pixels we want to get as close as possible to
|
|
||||||
*
|
|
||||||
* @return the font (derived from the specified font) that is as close as possible to the requested height. If our font-size is less
|
|
||||||
* than the height, then the approach is from the low size (so the returned font will always fit inside the box)
|
|
||||||
*/
|
|
||||||
public static
|
|
||||||
Font getFontForSpecificHeight(final Font font, final int height) {
|
|
||||||
int size = font.getSize();
|
|
||||||
Boolean lastAction = null;
|
|
||||||
BufferedImage image = new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB);
|
|
||||||
Graphics2D g = image.createGraphics();
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
Font fontCheck = new Font(font.getName(), Font.PLAIN, size);
|
|
||||||
|
|
||||||
FontMetrics metrics = g.getFontMetrics(fontCheck);
|
|
||||||
Rectangle2D rect = metrics.getStringBounds("`Tj|┃", g); // `Tj|┃ are glyphs that are at the top/bottom of the fontset (usually)
|
|
||||||
double testHeight = rect.getHeight();
|
|
||||||
|
|
||||||
if (testHeight < height && lastAction != Boolean.FALSE) {
|
|
||||||
size++;
|
|
||||||
lastAction = Boolean.TRUE;
|
|
||||||
} else if (testHeight > height && lastAction != Boolean.TRUE) {
|
|
||||||
size--;
|
|
||||||
lastAction = Boolean.FALSE;
|
|
||||||
} else {
|
|
||||||
// either we are the exact size, or we are ONE font size to big/small (depending on what our initial guess was)
|
|
||||||
g.dispose();
|
|
||||||
return fontCheck;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the specified font height
|
|
||||||
* @param font
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public static
|
|
||||||
int getFontHeight(final Font font) {
|
|
||||||
// Because font metrics is based on a graphics context, we need to create a small, temporary image to determine the width and height
|
|
||||||
BufferedImage image = new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB);
|
|
||||||
Graphics2D g = image.createGraphics();
|
|
||||||
|
|
||||||
FontMetrics metrics = g.getFontMetrics(font);
|
|
||||||
Rectangle2D rect = metrics.getStringBounds("`Tj|┃", g); // `Tj|┃ are glyphs that are at the top/bottom of the fontset (usually)
|
|
||||||
int testHeight = (int) rect.getHeight();
|
|
||||||
|
|
||||||
g.dispose();
|
|
||||||
|
|
||||||
return testHeight;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the specified text (with a font) and as an image
|
|
||||||
*
|
|
||||||
* @param font the specified font to render the image
|
|
||||||
* @return a BufferedImage of the specified text, font, and color
|
|
||||||
*/
|
|
||||||
public static
|
|
||||||
BufferedImage getFontAsImage(final Font font, String text, Color foregroundColor) {
|
|
||||||
// Because font metrics is based on a graphics context, we need to create a small, temporary image to determine the width and height
|
|
||||||
BufferedImage img = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);
|
|
||||||
Graphics2D g2d = img.createGraphics();
|
|
||||||
g2d.setFont(font);
|
|
||||||
|
|
||||||
FontMetrics fm = g2d.getFontMetrics();
|
|
||||||
int width = fm.stringWidth(text);
|
|
||||||
int height = fm.getHeight();
|
|
||||||
g2d.dispose();
|
|
||||||
|
|
||||||
// make it square
|
|
||||||
if (width > height) {
|
|
||||||
height = width;
|
|
||||||
} else {
|
|
||||||
width = height;
|
|
||||||
}
|
|
||||||
|
|
||||||
img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
|
|
||||||
g2d = img.createGraphics();
|
|
||||||
|
|
||||||
g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
|
|
||||||
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
|
||||||
g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
|
|
||||||
g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
|
|
||||||
g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
|
|
||||||
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
|
|
||||||
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
|
|
||||||
g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
|
|
||||||
|
|
||||||
g2d.setFont(font);
|
|
||||||
fm = g2d.getFontMetrics();
|
|
||||||
|
|
||||||
g2d.setColor(foregroundColor);
|
|
||||||
|
|
||||||
// width/4 centers the text in the image
|
|
||||||
g2d.drawString(text, width/4.0f, fm.getAscent());
|
|
||||||
g2d.dispose();
|
|
||||||
|
|
||||||
return img;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the largest icon/image for a button (or other JComponent that has .setIcon(image) method) without affecting the size of the
|
* Gets the largest icon/image for a button (or other JComponent that has .setIcon(image) method) without affecting the size of the
|
||||||
* button. An image that is any larger will require that the button increases it's height or width.
|
* button. An image that is any larger will require that the button increases it's height or width.
|
||||||
|
|
Loading…
Reference in New Issue