使用ttf字体使文本宽度灵活
Making text width flexible with ttf font
我想咨询两件事。首先,我有一个 ttf 文件,它位于我的 macair 驱动器中。我不想将该文件添加到我的项目结构中。我如何从中导入 True_type 字体。我尝试了多种方法将其导入我的 Java 程序。例如public class TextFixer {
私人静态字符串 [] 名称 = { "iksswgrg.ttf" }; //这存在于我的 macair 驱动器上,我想从中创建字体。
private static Map<String, Font> cache = new ConcurrentHashMap<String, Font>(names.length);
static {
for (String name : names) {
cache.put(name, getFont(name));
}
}
public static Font getFont(String name) {
Font font = null;
if (cache != null) {
if ((font = cache.get(name)) != null) {
return font;
}
}
String fName = "/fonts/" + name;
try {
InputStream is = TextFixer.class.getResourceAsStream(fName);
font = new Font("ttf", 0, 16);
//font = Font.createFont(Font.TRUETYPE_FONT, is);
} catch (Exception ex) {
ex.printStackTrace();
System.err.println(fName + " not loaded. Using serif font.");
font = new Font("serif", Font.PLAIN, 24);
}
return font;
}
第二部分是我想使用图形创建一个字符串。首先我需要有 130mm 的宽度。显示框的高度将是提供的字符串中最高的字符。字体大小在 8 到 16 之间。我有一个企业项目负责 ttf 的高度和大小。我面临的问题是:我不想使用 swing/javafx 库。我想使用 Java 的图形库,使用 Graphics2D 有一个矩形。我怎样才能将它的宽度设置为精确的 130mm?然后我想根据字体使宽度灵活。我想绘制一个字符串,该字符串应该在提供的宽度内变得 adjusted/being 灵活。我可以通过 g.drawString() 绘制一个字符串,但我无法在控制台上看到它。因为我不想使用 Jframe 或任何 Swing/javaFX 库。
我知道这似乎有点长,但我希望我已经解释得足够好。我迫切需要帮助。请让我知道你们是否可以在这里帮助我。
提前致谢
First I am having an ttf file and it is located in my macair drive. I do not want to add that file into my project structure. How can i import the True_type font from it
"How do you reference a file on the file system" 比 "How do I load a font" 更重要,因为如果你能解决第一个问题,你就能解决第二个问题。
File fontFile = new File("some/relative/path/to/your/Font.tff");
或
File fontFile = new File("/some/absolute/path/to/your/Font.tff");
就我个人而言,我都不喜欢,因为它会带来太多麻烦(工作目录、其他系统等),我更喜欢尽可能使用嵌入式资源或将文件放在公共位置。
例如 {user.home}/AppData/Local/{application name}
在 Windows 或 Mac 上你可以使用 {user.home}/Library/Application Support/{application name}
,那么程序从哪里执行并不重要
加载字体比较简单。对于我的示例,我将字体文件放在程序的工作目录中
System.out.println(new File("Pacifico.ttf").exists());
Font font = Font.createFont(Font.TRUETYPE_FONT, new File("Pacifico.ttf"));
2nd part is I want to create a String by using Graphics. First I need to have width that is of 130mm. The height of the displayed box will be the tallest character in the provided string
这要复杂得多,因为图像是以像素为单位测量的。为了知道给定距离有多少像素,我们需要知道图像的 DPI。
its 72DPI
好吧,据此,我们可以计算出我们需要的像素数
public static double cmToPixel(double cm, double dpi) {
return (dpi / 2.54) * cm;
}
130mm (13 cm) 结果是 368.503937007874
@ 72dpi.
据此,我们需要找到给定一段文本的字体磅值以适应此范围。
现在,有很多方法可以做到这一点,您可以简单地从点 1
开始,然后执行线性进展,直到超过您想要的范围。它不是很快,而且随着大小的增加,它可能会变得有点容易出错。
我选择了更多的分而治之的方法
protected static int widthOfText(String text, Font font, float fontSize, Graphics2D g2d) {
font = font.deriveFont(fontSize);
FontMetrics fm = g2d.getFontMetrics(font);
int textWidth = fm.stringWidth(text);
return textWidth;
}
public static Float pointToFit(double width, String text, Font font, Graphics2D g2d, float min, float max) {
float fontSize = min + ((max - min) / 2f);
font = font.deriveFont(fontSize);
FontMetrics fm = g2d.getFontMetrics(font);
int textWidth = fm.stringWidth(text);
if (fontSize == min || fontSize == max) {
return fontSize;
}
if (textWidth < width) {
return pointToFit(width, text, font, g2d, fontSize, max);
} else if (textWidth > width) {
return pointToFit(width, text, font, g2d, min, fontSize);
}
return fontSize;
}
重要的是要注意,它并不完美,但它比线性进展更好 :P
有了这个,我们就可以开始计算我们需要的属性了...
String text = "Happy, Happy, Joy, Joy";
double width = cmToPixel(13.0, 72.0);
BufferedImage img = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = img.createGraphics();
float fontSize = pointToFit(width, text, font, g2d, 0, (float)width);
font = font.deriveFont(fontSize);
FontMetrics fm = g2d.getFontMetrics(font);
int height = fm.getHeight();
g2d.dispose();
好的,这将创建一个小的 (1x1
) 临时图像。我们需要 Graphics
上下文来计算所有其他属性。然后计算字体磅值,然后可以从中计算文本高度
有了所有这些信息,我们就可以着手实际渲染文本了...
img = new BufferedImage((int) Math.round(width), height, BufferedImage.TYPE_INT_ARGB);
g2d = img.createGraphics();
g2d.setFont(font);
fm = g2d.getFontMetrics();
g2d.setColor(Color.BLACK);
g2d.drawString(text, 0, fm.getAscent());
g2d.dispose();
最终会输出这样的东西...
我在渲染文本之前添加了红色边框,这样我就可以看到它是否适合。
现在,这是一个非常基本的示例,它不会告诉您文本何时不适合(即磅值是 1
或 0
),你必须自己设置陷阱才能捕捉到它
而且,因为我知道您可能会从中获得很多乐趣,所以我的测试代码...
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.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.text.NumberFormat;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JOptionPane;
public class Test {
public static void main(String[] args) {
try {
System.out.println(new File("Pacifico.ttf").exists());
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
Font font = Font.createFont(Font.TRUETYPE_FONT, new File("Pacifico.ttf"));
String text = "Happy, Happy, Joy, Joy";
double width = cmToPixel(13.0, 72.0);
BufferedImage img = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = img.createGraphics();
float fontSize = pointToFit(width, text, font, g2d, 0, (float) width);
System.out.println(width);
System.out.println(fontSize);
font = font.deriveFont(fontSize);
FontMetrics fm = g2d.getFontMetrics(font);
int height = fm.getHeight();
g2d.dispose();
img = new BufferedImage((int) Math.round(width), height, BufferedImage.TYPE_INT_ARGB);
g2d = img.createGraphics();
g2d.setColor(Color.RED);
g2d.drawRect(0, 0, img.getWidth() - 1, img.getHeight() - 1);
g2d.setFont(font);
fm = g2d.getFontMetrics();
g2d.setColor(Color.BLACK);
g2d.drawString(text, 0, fm.getAscent());
g2d.dispose();
JOptionPane.showConfirmDialog(null, new ImageIcon(img));
} catch (IOException | FontFormatException e) {
//Handle exception
}
}
public static Float pointToFit(double width, String text, Font font, Graphics2D g2d) {
return pointToFit(width, text, font, g2d, 0f, Float.MAX_VALUE);
}
protected static int widthOfText(String text, Font font, float fontSize, Graphics2D g2d) {
font = font.deriveFont(fontSize);
FontMetrics fm = g2d.getFontMetrics(font);
int textWidth = fm.stringWidth(text);
return textWidth;
}
public static Float pointToFit(double width, String text, Font font, Graphics2D g2d, float min, float max) {
float fontSize = min + ((max - min) / 2f);
NumberFormat nf = NumberFormat.getInstance();
font = font.deriveFont(fontSize);
FontMetrics fm = g2d.getFontMetrics(font);
int textWidth = fm.stringWidth(text);
if (fontSize == min || fontSize == max) {
return fontSize;
}
if (textWidth < width) {
return pointToFit(width, text, font, g2d, fontSize, max);
} else if (textWidth > width) {
return pointToFit(width, text, font, g2d, min, fontSize);
}
return fontSize;
}
public static double cmToPixel(double cm, double dpi) {
return (dpi / 2.54) * cm;
}
}
我想咨询两件事。首先,我有一个 ttf 文件,它位于我的 macair 驱动器中。我不想将该文件添加到我的项目结构中。我如何从中导入 True_type 字体。我尝试了多种方法将其导入我的 Java 程序。例如public class TextFixer {
私人静态字符串 [] 名称 = { "iksswgrg.ttf" }; //这存在于我的 macair 驱动器上,我想从中创建字体。
private static Map<String, Font> cache = new ConcurrentHashMap<String, Font>(names.length);
static {
for (String name : names) {
cache.put(name, getFont(name));
}
}
public static Font getFont(String name) {
Font font = null;
if (cache != null) {
if ((font = cache.get(name)) != null) {
return font;
}
}
String fName = "/fonts/" + name;
try {
InputStream is = TextFixer.class.getResourceAsStream(fName);
font = new Font("ttf", 0, 16);
//font = Font.createFont(Font.TRUETYPE_FONT, is);
} catch (Exception ex) {
ex.printStackTrace();
System.err.println(fName + " not loaded. Using serif font.");
font = new Font("serif", Font.PLAIN, 24);
}
return font;
}
第二部分是我想使用图形创建一个字符串。首先我需要有 130mm 的宽度。显示框的高度将是提供的字符串中最高的字符。字体大小在 8 到 16 之间。我有一个企业项目负责 ttf 的高度和大小。我面临的问题是:我不想使用 swing/javafx 库。我想使用 Java 的图形库,使用 Graphics2D 有一个矩形。我怎样才能将它的宽度设置为精确的 130mm?然后我想根据字体使宽度灵活。我想绘制一个字符串,该字符串应该在提供的宽度内变得 adjusted/being 灵活。我可以通过 g.drawString() 绘制一个字符串,但我无法在控制台上看到它。因为我不想使用 Jframe 或任何 Swing/javaFX 库。 我知道这似乎有点长,但我希望我已经解释得足够好。我迫切需要帮助。请让我知道你们是否可以在这里帮助我。 提前致谢
First I am having an ttf file and it is located in my macair drive. I do not want to add that file into my project structure. How can i import the True_type font from it
"How do you reference a file on the file system" 比 "How do I load a font" 更重要,因为如果你能解决第一个问题,你就能解决第二个问题。
File fontFile = new File("some/relative/path/to/your/Font.tff");
或
File fontFile = new File("/some/absolute/path/to/your/Font.tff");
就我个人而言,我都不喜欢,因为它会带来太多麻烦(工作目录、其他系统等),我更喜欢尽可能使用嵌入式资源或将文件放在公共位置。
例如 {user.home}/AppData/Local/{application name}
在 Windows 或 Mac 上你可以使用 {user.home}/Library/Application Support/{application name}
,那么程序从哪里执行并不重要
加载字体比较简单。对于我的示例,我将字体文件放在程序的工作目录中
System.out.println(new File("Pacifico.ttf").exists());
Font font = Font.createFont(Font.TRUETYPE_FONT, new File("Pacifico.ttf"));
2nd part is I want to create a String by using Graphics. First I need to have width that is of 130mm. The height of the displayed box will be the tallest character in the provided string
这要复杂得多,因为图像是以像素为单位测量的。为了知道给定距离有多少像素,我们需要知道图像的 DPI。
its 72DPI
好吧,据此,我们可以计算出我们需要的像素数
public static double cmToPixel(double cm, double dpi) {
return (dpi / 2.54) * cm;
}
130mm (13 cm) 结果是 368.503937007874
@ 72dpi.
据此,我们需要找到给定一段文本的字体磅值以适应此范围。
现在,有很多方法可以做到这一点,您可以简单地从点 1
开始,然后执行线性进展,直到超过您想要的范围。它不是很快,而且随着大小的增加,它可能会变得有点容易出错。
我选择了更多的分而治之的方法
protected static int widthOfText(String text, Font font, float fontSize, Graphics2D g2d) {
font = font.deriveFont(fontSize);
FontMetrics fm = g2d.getFontMetrics(font);
int textWidth = fm.stringWidth(text);
return textWidth;
}
public static Float pointToFit(double width, String text, Font font, Graphics2D g2d, float min, float max) {
float fontSize = min + ((max - min) / 2f);
font = font.deriveFont(fontSize);
FontMetrics fm = g2d.getFontMetrics(font);
int textWidth = fm.stringWidth(text);
if (fontSize == min || fontSize == max) {
return fontSize;
}
if (textWidth < width) {
return pointToFit(width, text, font, g2d, fontSize, max);
} else if (textWidth > width) {
return pointToFit(width, text, font, g2d, min, fontSize);
}
return fontSize;
}
重要的是要注意,它并不完美,但它比线性进展更好 :P
有了这个,我们就可以开始计算我们需要的属性了...
String text = "Happy, Happy, Joy, Joy";
double width = cmToPixel(13.0, 72.0);
BufferedImage img = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = img.createGraphics();
float fontSize = pointToFit(width, text, font, g2d, 0, (float)width);
font = font.deriveFont(fontSize);
FontMetrics fm = g2d.getFontMetrics(font);
int height = fm.getHeight();
g2d.dispose();
好的,这将创建一个小的 (1x1
) 临时图像。我们需要 Graphics
上下文来计算所有其他属性。然后计算字体磅值,然后可以从中计算文本高度
有了所有这些信息,我们就可以着手实际渲染文本了...
img = new BufferedImage((int) Math.round(width), height, BufferedImage.TYPE_INT_ARGB);
g2d = img.createGraphics();
g2d.setFont(font);
fm = g2d.getFontMetrics();
g2d.setColor(Color.BLACK);
g2d.drawString(text, 0, fm.getAscent());
g2d.dispose();
最终会输出这样的东西...
我在渲染文本之前添加了红色边框,这样我就可以看到它是否适合。
现在,这是一个非常基本的示例,它不会告诉您文本何时不适合(即磅值是 1
或 0
),你必须自己设置陷阱才能捕捉到它
而且,因为我知道您可能会从中获得很多乐趣,所以我的测试代码...
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.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.text.NumberFormat;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JOptionPane;
public class Test {
public static void main(String[] args) {
try {
System.out.println(new File("Pacifico.ttf").exists());
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
Font font = Font.createFont(Font.TRUETYPE_FONT, new File("Pacifico.ttf"));
String text = "Happy, Happy, Joy, Joy";
double width = cmToPixel(13.0, 72.0);
BufferedImage img = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = img.createGraphics();
float fontSize = pointToFit(width, text, font, g2d, 0, (float) width);
System.out.println(width);
System.out.println(fontSize);
font = font.deriveFont(fontSize);
FontMetrics fm = g2d.getFontMetrics(font);
int height = fm.getHeight();
g2d.dispose();
img = new BufferedImage((int) Math.round(width), height, BufferedImage.TYPE_INT_ARGB);
g2d = img.createGraphics();
g2d.setColor(Color.RED);
g2d.drawRect(0, 0, img.getWidth() - 1, img.getHeight() - 1);
g2d.setFont(font);
fm = g2d.getFontMetrics();
g2d.setColor(Color.BLACK);
g2d.drawString(text, 0, fm.getAscent());
g2d.dispose();
JOptionPane.showConfirmDialog(null, new ImageIcon(img));
} catch (IOException | FontFormatException e) {
//Handle exception
}
}
public static Float pointToFit(double width, String text, Font font, Graphics2D g2d) {
return pointToFit(width, text, font, g2d, 0f, Float.MAX_VALUE);
}
protected static int widthOfText(String text, Font font, float fontSize, Graphics2D g2d) {
font = font.deriveFont(fontSize);
FontMetrics fm = g2d.getFontMetrics(font);
int textWidth = fm.stringWidth(text);
return textWidth;
}
public static Float pointToFit(double width, String text, Font font, Graphics2D g2d, float min, float max) {
float fontSize = min + ((max - min) / 2f);
NumberFormat nf = NumberFormat.getInstance();
font = font.deriveFont(fontSize);
FontMetrics fm = g2d.getFontMetrics(font);
int textWidth = fm.stringWidth(text);
if (fontSize == min || fontSize == max) {
return fontSize;
}
if (textWidth < width) {
return pointToFit(width, text, font, g2d, fontSize, max);
} else if (textWidth > width) {
return pointToFit(width, text, font, g2d, min, fontSize);
}
return fontSize;
}
public static double cmToPixel(double cm, double dpi) {
return (dpi / 2.54) * cm;
}
}