/
font-say
95 lines (87 loc) · 2.62 KB
/
font-say
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# prints an ascii banner, using the supplied font
use Font::FreeType;
use Font::FreeType::Native::Types;
enum Mode «
:normal(0)
:light(1)
:mono(2)
:lcd(3)
:lcd-v(4)
»;
sub MAIN(Str $font-file,
Str $text is copy,
Int :$resolution=60,
Bool :$kern = True,
Bool :$hint,
UInt :$ascend,
UInt :$descend,
UInt :$char-spacing is copy,
UInt :$word-spacing is copy,
UInt :$bold = 0,
Mode :$mode = normal,
Bool :$verbose,
) {
if $text eq '' {
# handle empty string as a zero width space
$text = ' ';
$word-spacing //= 0;
}
my $load-flags = $hint
?? FT_LOAD_DEFAULT
!! FT_LOAD_NO_HINTING;
my $face = Font::FreeType.new.face($font-file, :$load-flags);
try $face.set-char-size(24, 0, $resolution, $resolution);
$char-spacing //= $resolution > 40
?? ($resolution + 20) div 40
!! 1;
$word-spacing //= $char-spacing * 4;
my @bitmaps = $face.glyph-images($text).map: {
.bold($bold) if $bold;
my $bitmap = .bitmap(:render-mode($mode));
note "{.char-code.chr} U+{.char-code.fmt('%06X')} [{.index}]: {$bitmap.width} X {$bitmap.rows}"
if $verbose;
$bitmap;
}
my @pix-bufs = @bitmaps.map: { .defined && .width ?? .pixels !! Any };
my $top = $ascend // @bitmaps.map({.defined ?? .top !! 0}).max;
my $bottom = - ($descend // @bitmaps.map({.defined ?? .rows - .top !! 0}).max);
for $top ...^ $bottom -> $row {
my Str @line;
my int16 $pos = 0;
for 0 ..^ +@bitmaps -> $col {
with @bitmaps[$col] {
$pos += do-horiz-kern($face, @bitmaps[$col-1], $_, $mode)
if $col && $kern && $face.has-kerning;
for scan-line($_, @pix-bufs[$col], $row) -> $pix {
@line[$pos] = '#' if $pix;
$pos++;
}
$pos += $char-spacing;
}
else {
$pos += $word-spacing;
}
}
$_ //= ' ' for @line;
say @line.join;
}
}
sub scan-line($bitmap, $pix-buf, $row) {
my uint8 @pix[$bitmap.width];
my int $y = $bitmap.top - $row;
if $bitmap.rows > $y >= 0 {
my int $i = 0;
for ^$bitmap.width -> int $x {
@pix[$i] = 1
if $pix-buf[$y;$x];
$i++;
}
}
@pix;
}
sub do-horiz-kern($face, $bm1, $bm2, $mode ) {
my $vec = $face.kerning($bm1.char-code.chr, $bm2.char-code.chr);
my $x = $vec.x;
$x *= 3 if $mode == lcd;
round($x).Int;
}