以编程方式获取字体轮廓

时间:2014-10-25 13:45:46

标签: java android

在某种程度上可以将字体(ttf / otf)轮廓检索为Android上的曲线/一系列点吗?例如,如果我想将具有特定字体的单词转换为矢量格式?

1 个答案:

答案 0 :(得分:6)

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

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

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

根据John J Smith的回答:https://stackoverflow.com/a/6864113/837765,应该可以在Android上使用与TextLayout类似的内容。但是,没有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;
}

然后,你应该找到形状边界。这里不是很难,因为你的形状可以直接通过shape.getPathIterator(null)

为你提供路径迭代器

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

  1. SEG_QUADTO :二次参数曲线;
  2. SEG_CUBICTO :立方参数曲线;
  3. SEG_LINETO :指定一条线的终点;
  4. SEG_MOVETO :指定新子路径的起始位置的点。
  5. 此时,您应该阅读Bézier曲线herehere

    您将了解到:

      

    任何二次样条都可以表示为立方(其中立方项   是零)。立方体的终点将与   二次的。

         

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

    我在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)
    //...
    

    我知道您无法在Android中使用Graphics2D(我在UI中使用它),但您应该可以将我的解决方案用于Android项目(我希望)。

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

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

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

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