Beefy Boxes and Bandwidth Generously Provided by pair Networks
"be consistent"

How might I portably determine the TrueType Font filespecs for 'Generic' font specifications like 'sans-serif'?

by ozboomer (Pilgrim)
on Feb 14, 2017 at 00:38 UTC ( #1181943=perlquestion: print w/replies, xml ) Need Help??
ozboomer has asked for the wisdom of the Perl Monks concerning the following question:

I have a Perl program that runs under both Windows (ActiveState v5.16.3 32-bit) and Linux (Puppy Linux v5.6.4 Slacko ... but others as well) which calls the video manipulation program 'ffmpeg' to modify the content of a video file. The current issue revolves around the adding of some text to the video image.

'ffmpeg' is called via `` (backticks) and system()... and in both cases, the executed command is something like:-

ffmpeg -hide_banner -i "scats.avi" \ -vf "fps=fps=pal, \ drawtext=fontsize=10: fontcolor=yellow: \ fontfile=arial.ttf: \ text='%{pts\:hms} Fr %{n}': x=8: y=h-(2*lh), \ scale=trunc(iw/2)*2:trunc(ih/2)*2 " \ -y -codec:v libx264 -pix_fmt yuv420p \ -crf 18 -vsync cfr -r pal "new.avi"

Note that this command is fairly generic and includes some "filter clauses" that are required for .flv files, .mp4 files, etc.

With the command as it stands, the font file "arial.ttf" must reside in the current directory... but I can fix that problem by using some perl code like:-

$my_os = "$^O"; if ($my_os eq "linux") { $font_file = "/usr/share/fonts/default/TTF/DejaVuSans.ttf"; } elsif ($my_os eq "MSWin32") { $dir_marker = "\\"; # $font_file = $ENV{"SystemRoot"} . $dir_marker . "Fonts" . $dir_m +arker . "Arial.ttf"; $font_file = "c\\:\\\\windows\\\\fonts\\\\verdana.ttf"; }

...and then use '$font_file' in the 'ffmpeg' command string.

The real problem comes from the situation where the TTF files don't exist. The files I've selected are fairly common... but is there a simple, robust, *portable* way to select some 'sans serif' -style fonts (font files) in Perl?

Some of what is done in HTML markup comes to mind... where a font is often declared in HTML or CSS files as 'sans serif' and the user's browser is set-up to translate 'sans serif' into a specified *actual* font. Is something like that available in a Perl module? ... or can I call the O/S (system32.dll or Linux equivalent)? I'm looking for the simplest solution here... and modules like Font::TTF are as clear as mud to me :(

I'd appreciate any thoughts on how to deal with this...


Edit: Note the spec for $font_file under MSWin32 as shown will not work. Still trying to find a spec that will...(!)

Edit: The pathing under Windows is horrendous... the 'normal' Perl internal magic that allows us to use '/' under Windows causes grief for 'ffmpeg'... and the 'ffmpeg' filtering items use '\' and ':' in a special way. *Ugh!* Note that the MSWin32 filespec shown *now* DOES work - it's just ugly.

  • Comment on How might I portably determine the TrueType Font filespecs for 'Generic' font specifications like 'sans-serif'?
  • Select or Download Code

Replies are listed 'Best First'.
Re: How might I portably determine the TrueType Font filespecs for 'Generic' font specifications like 'sans-serif'?
by vr (Friar) on Feb 14, 2017 at 08:28 UTC
    use strict; use warnings; use feature 'say'; use File::Spec::Functions; use Font::TTF::Useall; my $dir = catdir $ENV{ SystemRoot }, 'Fonts'; say 'Looks like these our fonts are sans serif and regular:'; for my $fn ( glob( catfile $dir, '*.{ttf,otf}' )) { my $f = Font::TTF::Font-> open( $fn ); next unless $f-> { name }-> read-> find_name( 2 ) eq 'Regular'; next unless $f-> { 'OS/2' }-> read-> { sFamilyClass } >> 8 == 8; say $fn }

    If you want to further define, which kind of sans serif font you prefer, see Table 56 for subclasses (check lower byte):

    And, of course, see this distribution for details:

    Edit: From the "OS/2" table, you can also check usWeightClass and usWidthClass values, to filter out too narrow, thin, expanded, etc. fonts. See, because Apple's page linked above seems to provide incorrect constants for the usWeightClass.

    BTW, as to lower byte of sFamilyClass, I'd use it to exclude things like "Typewriter", "Matrix", etc.

    P.P.S. The "Regular" string, above, is to exclude "Bold", "Italic" (but sometimes "Oblique"), "BI" ("BO"). Yet, some vendors/authors include string "Book" rather than "Regular" (cf. "DejaVu Sans" font). Because it's correct, in their opinion. It's messy and complicated :-).

    Also, e.g. the particular version of "Arial Black" font at one computer I'm at now, has the same value of usWeightClass as "Arial Regular". A perfectionist might wish to also parse and/or hard-code some font names. I.e. many of these entries in TTF tables are just supplemental information, no obligations.

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://1181943]
Approved by beech
Front-paged by stevieb
[Corion]: Hmm. I think overnight I decided on simplifying some code. I have plugin classes that do data import (.csv, .yml, .json) and for that create objects on which then ->load() is called. But YAML::XS doesn't have an object, so I wrote my own wrapper.
[Corion]: This evening, I'll kill that wrapper again, and just call LoadFile() in the plugin class directly instead of creating a go-between object for no real gain.
[Corion]: Writing these import plugins was really nice though - in about 2 hours, I had imports for CSV, YAML and JSON, and adding XLS(X), SQLite (or DBI) data sources is also trivial. I'm idly wondering about separating the plugin into transport+parser, so ...
[Corion]: ... http:// URLs could be retrieved and then parsed, but I think that that would be overkill for a toy static site generator ;)

How do I use this? | Other CB clients
Other Users?
Others meditating upon the Monastery: (8)
As of 2018-05-22 11:04 GMT
Find Nodes?
    Voting Booth?