1

I would like to draw text as polygons and get an array of line segments with (x1,y1)-(x2,y2) pairs that I could scale and use in my vector drawing application. One application might be for writing text with a CNC.

So, for example:

$f = PolyFont->new("Hello World");
@lines = $f->get_lines();

This might provide a list of @lines = ([x1,y1],[x2,y2]) values or something like that.

The font doesn't have to be particularly beautiful, it doesn't even need to support curves if it will approximate with line segments.

If it will take in a TTF then that is even better!

Ideas?

KJ7LNW
  • 1,437
  • 5
  • 11
  • Related, but looking for this in perl: https://stackoverflow.com/questions/13797787/outline-of-a-text-as-single-line-vector-path – KJ7LNW Oct 22 '21 at 03:43
  • 1
    Might SVG help? There are various image modules that can produce SVG images. I don't know about your exact use case, but you could build on top of SVG and parse the output of that, which should be fairly trivial XML consumption, to convert to a set of instructions. Sounds like a fun problem to solve, and you could release it to cpan after. There are a few results for _CNC_ on cpan too, but none of them seem like they are text related. – simbabque Oct 22 '21 at 07:26
  • Maybe the [FreeType library](https://www.freetype.org/) can do this? See [Draw text outline with Freetype](https://stackoverflow.com/questions/20874056/draw-text-outline-with-freetype). There are also various Perl modules that interface with the FreeType library – Håkon Hægland Oct 22 '21 at 10:09

1 Answers1

4

You can use the Font::FreeType module to get the outline of a glyph as a series of line segments and Bézier arcs. Here is an example, where I save the outline to a new .png file using Image::Magick:

use feature qw(say);
use strict;
use warnings;
use Font::FreeType;
use Image::Magick;

my $size = 72;
my $dpi = 600;
my $font_filename = 'Vera.ttf';
my $char = 'A';
my $output_filename = $char . '-outline.png';
my $face = Font::FreeType->new->face($font_filename);
$face->set_char_size($size, $size, $dpi, $dpi);
my $glyph = $face->glyph_from_char($char);
my $width = $glyph->horizontal_advance;
my $height = $glyph->vertical_advance;
my $img = Image::Magick->new(size => "${width}x$height");
$img->Read('xc:#ffffff');
$img->Set(stroke => '#8888ff');

my $curr_pos;
$glyph->outline_decompose(
    move_to => sub {
        my ($x, $y) = @_;
        $y = $height - $y;
        $curr_pos = "$x,$y";
    },
    line_to => sub {
        my ($x, $y) = @_;
        $y = $height - $y;
        $img->Draw(primitive => 'line', linewidth => 5, points => "$curr_pos $x,$y");
        $curr_pos = "$x,$y";
    },
    cubic_to => sub {
        my ($x, $y, $cx1, $cy1, $cx2, $cy2) = @_;
        $y = $height - $y;
        $cy1 = $height - $cy1;
        $cy2 = $height - $cy2;
        $img->Draw(primitive => 'bezier',
                   points => "$curr_pos $cx1,$cy1 $cx2,$cy2 $x,$y");
        $curr_pos = "$x,$y";
    },
);

$img->Write($output_filename);

Output:

enter image description here

Notes:

Håkon Hægland
  • 39,012
  • 21
  • 81
  • 174