java - 以编程方式获取字体轮廓

标签 java android

是否可以通过某种方式在 Android 上将字体 (ttf/otf) 轮廓检索为一条曲线/一系列点?例如,如果我想将具有特定字体的单词转换为 vector 格式?

最佳答案

因为我从来没有为 Android 设备开发过,所以我会告诉你这样做的方法,但是在 Java .

这是几个不错的库,但我不知道您是否可以使用它 (C/C++),所以我将向您解释如何自己使用它。

您应该首先使用 TextLayout 将您的单词转换为形状(您可以绘制的样式字符数据的不可变图形表示)在 FontRenderContext 中.

根据 John J Smith 的回答:https://stackoverflow.com/a/6864113/837765 , 应该可以使用类似于 TextLayout 的东西在安卓系统上。但是,没有 FontRenderContext 的等价物。 .正如我所说,我从未为 Android 设备开发过,但可能(我希望如此)有一种将字符转换为形状的解决方法。

在 Java 中这样的东西应该可以工作(将文本转换为形状):

public Shape getShape(String text, Font font, Point from) {
    FontRenderContext context = new FontRenderContext(null, false, false);

    GeneralPath shape = new GeneralPath();
    TextLayout layout = new TextLayout(text, font, context);

    Shape outline = layout.getOutline(null);
    shape.append(outline, true);

    return shape;
}

然后,您应该找到形状边界。这里并不难,因为你的形状可以直接给你路径迭代器 shape.getPathIterator(null)

在每次迭代中,您可以获得当前段,its type和坐标。:

  1. SEG_QUADTO:二次参数曲线;
  2. SEG_CUBICTO:三次参数曲线;
  3. SEG_LINETO : 指定直线的终点;
  4. SEG_MOVETO :指定新子路径起始位置的点。

此时,您应该阅读贝塞尔曲线 herehere .

您将了解到:

Any quadratic spline can be expressed as a cubic (where the cubic term is zero). The end points of the cubic will be the same as the quadratic's.

CP0 = QP0 CP3 = QP2

The two control points for the cubic are:

CP1 = QP0 + 2/3 *(QP1-QP0) CP2 = CP1 + 1/3 *(QP2-QP0)

因此从 TrueType 转换为 PostScript 是微不足道的。

在 Java 中这样的东西应该可以工作:

public List<Point> getPoints(Shape shape) {
    List<Point> out = new ArrayList<Point>();
    PathIterator iterator = shape.getPathIterator(null);

    double[] coordinates = new double[6];
    double x = 0, y = 0;

    while (!iterator.isDone()) {

        double x1 = coordinates[0];
        double y1 = coordinates[1];

        double x2 = coordinates[2];
        double y2 = coordinates[3];

        double x3 = coordinates[4];
        double y3 = coordinates[5];

        switch (iterator.currentSegment(coordinates)) {
        case PathIterator.SEG_QUADTO:
            x3 = x2;
            y3 = y2;

            x2 = x1 + 1 / 3f * (x2 - x1);
            y2 = y1 + 1 / 3f * (y2 - y1);

            x1 = x + 2 / 3f * (x1 - x);
            y1 = y + 2 / 3f * (y1 - y);

            out.add(new Point(x3, y3));

            x = x3;
            y = y3;
            break;

        case PathIterator.SEG_CUBICTO:
            out.add(new Point(x3, y3));
            x = x3;
            y = y3;
            break;
        case PathIterator.SEG_LINETO:
            out.add(new Point(x1, y1));
            x = x1;
            y = y1;
            break;
        case PathIterator.SEG_MOVETO:
            out.add(new Point(x1, y1));
            x = x1;
            y = y1;
            break;
        }
        iterator.next();
    }

    return out;
}

我在 Bitbucket 上创建了一个演示项目,也许它可以帮助你。 https://bitbucket.org/pieralexandre/fontshape

初始形状文本(轮廓变换后):

enter image description here

形状上的点:

enter image description here

只有点:

enter image description here

以及所有点的输出:

(0.0,0.0)
(9.326171875,200.0)
(9.326171875,127.734375)
(0.0,0.0)
(50.7080078125,130.126953125)
(62.158203125,138.232421875)
(69.82421875,162.158203125)
(60.302734375,190.087890625)
(50.78125,200.0)
//...

我知道你不能使用 Graphics2D (我将它用于 UI)在 Android 中,但您应该能够将我的解决方案用于 Android 项目(我希望)。

之后,您可以(在贝塞尔曲线的帮助下)重新创建曲线。

此外,这里还有一些其他的好工具。看看这个:

http://nodebox.github.io/opentype.js/

它是用 Javascript 编写的,但也许它可以为您提供更多帮助。

关于java - 以编程方式获取字体轮廓,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26563073/

相关文章:

java - MouseListener 在 JLabel 中不起作用

java - 在 fxml 中定义您的自定义类

java - 为什么我的数组出现 ArrayIndexOutOfBoundsException?

android - 如何计算android中每个应用程序的移动和wifi数据使用量?

java - 从 Java 程序启动外部 Java 程序

java - 使用整数表示货币

java - Android - 使用 jQuery Mobile 将简单的用户输入表单 web View 发送到后端 java

android服务监听特定端口

Android:如何导入我创建的类?

java - Android查询关于onClick和android控制流程