以编程方式获取字体轮廓

Axa*_*dax 7 java android

是否有可能在Android上检索字体(ttf/otf)轮廓作为曲线/系列点?例如,如果我想将具有特定字体的单词转换为矢量格式?

Pie*_*ard 6

由于我从来没有为Android设备开发,我会给你这样做的方法,但在Java.

这是一些很好的库,但我不知道你是否可以使用它(C/C++)所以我会解释你如何自己做.

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

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

在Java中这样的东西应该工作(转换Shape中的文本):

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;
}
Run Code Online (Sandbox Code Playgroud)

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

在每次迭代中,您可以获得当前段,其类型和坐标:

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

此时,您应该在这里这里阅读Bézier曲线.

你会了解到:

任何二次样条可以表示为立方(其中立方项为零).立方体的终点与二次方的终点相同.

CP0 = QP0 CP3 = QP2

立方体的两个控制点是:

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;
}
Run Code Online (Sandbox Code Playgroud)

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

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

在此输入图像描述

形状上的点:

在此输入图像描述

只有要点:

在此输入图像描述

以及所有要点的输出:

(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)
//...
Run Code Online (Sandbox Code Playgroud)

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

之后,您可以(在Bézier曲线的帮助下)重新创建曲线.

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

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

它是在Javascript中,但也许它可以帮助你更多.