使用ttf字体使文本宽度灵活

时间:2017-06-08 07:39:35

标签: java graphics2d

我正在询问两件事。首先我有一个ttf文件,它位于我的macair驱动器中。我不想将该文件添加到我的项目结构中。如何从中导入True_type字体。我已尝试过各种方法将其导入我的Java程序。例如公共类TextFixer {
    private static String [] names = {" 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;                                                                                        
  }

第二部分是我想用Graphics创建一个String。首先,我需要宽度为130毫米。显示框的高度将是提供的字符串中最高的字符。字体大小在8到16之间。我有一个企业项目,它负责ttf的高度和大小。我面临的问题是:我不想使用swing / javafx库。我想使用Java的图形库,使用Graphics2D有一个矩形。如何将其宽度设置为精确130mm?然后我想根据字体使宽度灵活。我想绘制一个字符串,字符串应该在提供的宽度中调整/灵活。我能够通过g.drawString()绘制一个字符串,但我无法在控制台上看到它。因为我不想使用Jframe或任何Swing / javaFX库。 我知道这似乎有点长,但我希望我已经解释得很好。我迫切需要帮助。如果你们能在这里帮助我,请告诉我。 提前致谢

1 个答案:

答案 0 :(得分:1)

  

首先我有一个ttf文件,它位于我的macair驱动器中。我不想将该文件添加到我的项目结构中。如何从中导入True_type字体

这与“如何在文件系统中引用文件”以及“如何加载字体”有关,这是一个问题,因为如果你能解决第一个问题,你可以解决第二个问题。

File fontFile = new File("some/relative/path/to/your/Font.tff");

File fontFile = new File("/some/absolute/path/to/your/Font.tff");

就个人而言,我既不喜欢,因为它会导致太多麻烦(工作目录,其他系统等),我更喜欢尽可能使用嵌入式资源或将文件放在一个公共位置。

例如,在Windows或Mac上的{user.home}/AppData/Local/{application name},你可以使用{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"));
  

第二部分是我想用Graphics创建一个String。首先,我需要宽度为130毫米。显示框的高度将是提供的字符串中最高的字符

这要复杂得多,因为图像以像素为单位进行测量。为了知道构成给定距离的像素数,我们需要知道图像的DPI。

  

72DPI

那么,从那时起,我们可以计算出我们需要的像素数

public static double cmToPixel(double cm, double dpi) {
    return (dpi / 2.54) * cm;
}

130毫米(13厘米)出现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();

最终会输出这样的东西......

Happy, Happy, Joy, Joy

我在渲染文字之前添加了红色边框,这样我才能看出它的合适程度。

现在,这是一个非常基本的例子,这不做的是告诉你文本何时不适合(即点大小是10),你'我必须把陷阱放进去抓住你自己

而且,因为我知道你可能会把它放在一起很有趣,我的测试代码......

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;
    }

}
相关问题