当使用imagemagick对文字进行操作的时候需要注意字体路径的配置,并且需要修改
convert -debug configure -background none label:Kane a.png
2015-09-23T17:06:02+08:00 0:00.000 0.000u 6.9.1 Configure convert[13059]: utility.c/ExpandFilenames/936/Configure
Command line: ./bin_for_fopd/convert {-debug} {configure} {-background} {none} {label:Landy} {wtexthlVwhBgr_ATrCgya.png}
2015-09-23T17:06:02+08:00 0:00.000 0.000u 6.9.1 Configure convert[13059]: configure.c/GetConfigureOptions/679/Configure
Searching for configure file: "/usr/local/share/ImageMagick-6/colors.xml"
省略多个路径的寻找
2015-09-23T17:06:02+08:00 0:00.000 0.000u 6.9.1 Configure convert[13059]: delegate.c/LoadDelegateCache/1494/Configure
Loading delegate configuration file "built-in" ...
convert: UnableToOpenConfigureFile `type.xml' @ warning/configure.c/GetConfigureOptions/706.
convert: UnableToReadFont `(null)' @ error/annotate.c/RenderFreetype/1153.
convert: UnableToOpenConfigureFile `delegates.xml' @ warning/configure.c/GetConfigureOptions/706.
convert: UnableToReadFont `(null)' @ error/annotate.c/RenderFreetype/1153.
convert: UnableToOpenConfigureFile `colors.xml' @ warning/configure.c/GetConfigureOptions/706.
Command line: ./bin_for_fopd/convert {-debug} {configure} {-background} {none} {label:Landy} {wtexthlVwhBgr_ATrCgya.png}
2015-09-23T17:06:02+08:00 0:00.000 0.000u 6.9.1 Configure convert[13059]: configure.c/GetConfigureOptions/679/Configure
Searching for configure file: "/usr/local/share/ImageMagick-6/colors.xml"
省略多个路径的寻找
2015-09-23T17:06:02+08:00 0:00.000 0.000u 6.9.1 Configure convert[13059]: delegate.c/LoadDelegateCache/1494/Configure
Loading delegate configuration file "built-in" ...
convert: UnableToOpenConfigureFile `type.xml' @ warning/configure.c/GetConfigureOptions/706.
convert: UnableToReadFont `(null)' @ error/annotate.c/RenderFreetype/1153.
convert: UnableToOpenConfigureFile `delegates.xml' @ warning/configure.c/GetConfigureOptions/706.
convert: UnableToReadFont `(null)' @ error/annotate.c/RenderFreetype/1153.
convert: UnableToOpenConfigureFile `colors.xml' @ warning/configure.c/GetConfigureOptions/706.
convert: NoImagesDefined `a.png' @ error/convert.c/ConvertImageCommand/3212.
这里一直在找默认路径,先找系统默认路径,再找当前用户默认路径,即.magick,这里可以加文件夹,也可以重新指定该文件夹路径
$MAGICK_CONFIGURE_PATH
配置这个环境变量是用于寻找type.xml 、colors.xml等文件,可以吧这些文件放在一个文件夹下,然后路径指到这个文件夹
有了这些配置文件还有问题,需要修改type.xml
cat .magick/type.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE typemap [
<!ELEMENT typemap (type)+>
<!ELEMENT type (#PCDATA)>
<!ELEMENT include (#PCDATA)>
<!ATTLIST type name CDATA #REQUIRED>
<!ATTLIST type fullname CDATA #IMPLIED>
<!ATTLIST type family CDATA #IMPLIED>
<!ATTLIST type foundry CDATA #IMPLIED>
<!ATTLIST type weight CDATA #IMPLIED>
<!ATTLIST type style CDATA #IMPLIED>
<!ATTLIST type stretch CDATA #IMPLIED>
<!ATTLIST type format CDATA #IMPLIED>
<!ATTLIST type metrics CDATA #IMPLIED>
<!ATTLIST type glyphs CDATA #REQUIRED>
<!ATTLIST type version CDATA #IMPLIED>
<!ATTLIST include file CDATA #REQUIRED>
]>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE typemap [
<!ELEMENT typemap (type)+>
<!ELEMENT type (#PCDATA)>
<!ELEMENT include (#PCDATA)>
<!ATTLIST type name CDATA #REQUIRED>
<!ATTLIST type fullname CDATA #IMPLIED>
<!ATTLIST type family CDATA #IMPLIED>
<!ATTLIST type foundry CDATA #IMPLIED>
<!ATTLIST type weight CDATA #IMPLIED>
<!ATTLIST type style CDATA #IMPLIED>
<!ATTLIST type stretch CDATA #IMPLIED>
<!ATTLIST type format CDATA #IMPLIED>
<!ATTLIST type metrics CDATA #IMPLIED>
<!ATTLIST type glyphs CDATA #REQUIRED>
<!ATTLIST type version CDATA #IMPLIED>
<!ATTLIST include file CDATA #REQUIRED>
]>
<typemap>
<include file="type-ghostscript.xml" /> //这是新加的,指向字体识别路径
</typemap>
我们看下这个配置文件
qboxserver@bc25:~$ cat .magick/type-ghostscript.xml |head -20
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE typemap [
<!ELEMENT typemap (type)+>
<!ELEMENT type (#PCDATA)>
<!ELEMENT include (#PCDATA)>
<!ATTLIST type name CDATA #REQUIRED>
<!ATTLIST type fullname CDATA #IMPLIED>
<!ATTLIST type family CDATA #IMPLIED>
<!ATTLIST type foundry CDATA #IMPLIED>
<!ATTLIST type weight CDATA #IMPLIED>
<!ATTLIST type style CDATA #IMPLIED>
<!ATTLIST type stretch CDATA #IMPLIED>
<!ATTLIST type format CDATA #IMPLIED>
<!ATTLIST type metrics CDATA #IMPLIED>
<!ATTLIST type glyphs CDATA #REQUIRED>
<!ATTLIST type version CDATA #IMPLIED>
<!ATTLIST include file CDATA #REQUIRED>
]>
<typemap>
<type name="AvantGarde-Book" fullname="AvantGarde Book" family="AvantGarde" foundry="URW" weight="400" style="normal" stretch="normal" format="type1" metrics="系统路径/gsfonts/a010013l.afm" glyphs="系统路径/gsfonts/a010013l.pfb"/>
<type name="AvantGarde-BookOblique" fullname="AvantGarde Book Oblique" family="AvantGarde" foundry="URW" weight="400" style="oblique" stretch="normal" format="type1" metrics="系统路径/gsfonts/a010033l.afm" glyphs="系统路径/gsfonts/a010033l.pfb"/>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE typemap [
<!ELEMENT typemap (type)+>
<!ELEMENT type (#PCDATA)>
<!ELEMENT include (#PCDATA)>
<!ATTLIST type name CDATA #REQUIRED>
<!ATTLIST type fullname CDATA #IMPLIED>
<!ATTLIST type family CDATA #IMPLIED>
<!ATTLIST type foundry CDATA #IMPLIED>
<!ATTLIST type weight CDATA #IMPLIED>
<!ATTLIST type style CDATA #IMPLIED>
<!ATTLIST type stretch CDATA #IMPLIED>
<!ATTLIST type format CDATA #IMPLIED>
<!ATTLIST type metrics CDATA #IMPLIED>
<!ATTLIST type glyphs CDATA #REQUIRED>
<!ATTLIST type version CDATA #IMPLIED>
<!ATTLIST include file CDATA #REQUIRED>
]>
<typemap>
<type name="AvantGarde-Book" fullname="AvantGarde Book" family="AvantGarde" foundry="URW" weight="400" style="normal" stretch="normal" format="type1" metrics="系统路径/gsfonts/a010013l.afm" glyphs="系统路径/gsfonts/a010013l.pfb"/>
<type name="AvantGarde-BookOblique" fullname="AvantGarde Book Oblique" family="AvantGarde" foundry="URW" weight="400" style="oblique" stretch="normal" format="type1" metrics="系统路径/gsfonts/a010033l.afm" glyphs="系统路径/gsfonts/a010033l.pfb"/>
这里系统路径一般是/usr/share/fonts下面的某个字体库,如
里面都是些系统默认字体库
ls系统路径/gsfonts/
a010013l.afm a010033l.pfm b018015l.pfb c059013l.afm c059033l.pfm n019003l.pfb n019024l.afm n019044l.pfm n021003l.pfb n021024l.afm n022004l.pfm p052003l.pfb p052024l.afm z003034l.pfm
a010013l.pfb a010035l.afm b018015l.pfm c059013l.pfb c059036l.afm n019003l.pfm n019024l.pfb n019063l.afm n021003l.pfm n021024l.pfb n022023l.afm p052003l.pfm p052024l.pfb
a010013l.pfm a010035l.pfb b018032l.afm c059013l.pfm c059036l.pfb n019004l.afm n019024l.pfm n019063l.pfb n021004l.afm n021024l.pfm n022023l.pfb p052004l.afm p052024l.pfm
a010015l.afm a010035l.pfm b018032l.pfb c059016l.afm c059036l.pfm n019004l.pfb n019043l.afm n019063l.pfm n021004l.pfb n022003l.afm n022023l.pfm p052004l.pfb s050000l.afm
a010013l.afm a010033l.pfm b018015l.pfb c059013l.afm c059033l.pfm n019003l.pfb n019024l.afm n019044l.pfm n021003l.pfb n021024l.afm n022004l.pfm p052003l.pfb p052024l.afm z003034l.pfm
a010013l.pfb a010035l.afm b018015l.pfm c059013l.pfb c059036l.afm n019003l.pfm n019024l.pfb n019063l.afm n021003l.pfm n021024l.pfb n022023l.afm p052003l.pfm p052024l.pfb
a010013l.pfm a010035l.pfb b018032l.afm c059013l.pfm c059036l.pfb n019004l.afm n019024l.pfm n019063l.pfb n021004l.afm n021024l.pfm n022023l.pfb p052004l.afm p052024l.pfm
a010015l.afm a010035l.pfm b018032l.pfb c059016l.afm c059036l.pfm n019004l.pfb n019043l.afm n019063l.pfm n021004l.pfb n022003l.afm n022023l.pfm p052004l.pfb s050000l.afm
a010015l.pfb b018012l.afm b018032l.pfm c059016l.pfb d050000l.afm n019004l.pfm n019043l.pfb n019064l.a
同时存在一个问题,不是所有操作系统版本都是这个路径
另一种方案直接生成含ttf的xml,命令
find fonts -name '*.ttf' | ./imagick_type_gen -f - > ~/magick/type-ghostscript.xml //fonts是存放所有ttf文件的文件夹
结果如下
cat magick/type-ghostscript.xml |head -30
<?xml version="1.0"?>
<typemap>
<type
format="ttf"
name="FranklinGothicMI"
fullname="Franklin Gothic Medium Italic"
family="Franklin Gothic Medium"
glyphs="fonts/framdit.ttf"
/>
<type
format="ttf"
name="JasmineUPC"
fullname="JasmineUPC"
family="JasmineUPC"
glyphs="fonts/upcjl.ttf"
/>
<?xml version="1.0"?>
<typemap>
<type
format="ttf"
name="FranklinGothicMI"
fullname="Franklin Gothic Medium Italic"
family="Franklin Gothic Medium"
glyphs="fonts/framdit.ttf"
/>
<type
format="ttf"
name="JasmineUPC"
fullname="JasmineUPC"
family="JasmineUPC"
glyphs="fonts/upcjl.ttf"
/>
#!/usr/bin/perl -w
#
(my $prog = $0) =~ s/^.*\///;
sub Usage {
die @_, &herefile( qq{
| Usage: $prog > ~/.magick/type.xml
| $prog [-d] font1.ttf font2.ttf ... > type.xml
| $prog -f ttf_font_file_list > type.xml
|
| Generate an ImageMagick font list "type.xml" file for ALL fonts
| currently on the local linux system. This includes
| True Type Fonts (ttf)
| Ghostscript Fonts (afm)
| Open Type Fonts (otf)
|
| The output can be saved into files in the ".magick" sub-directory of
| your home, to be referenced by, or replacing the "type.xml" file.
|
| This file informs ImageMagick of the fonts location, font type, name and
| family. It also trys its best to clean up the name to provide a 'nicer'
| one for you to identify the various fonts.
|
| By default the fonts are found using the linux "locate" command, so run
| "updatedb" if you only just added new fonts to your computer.
|
| However you can use a "-f" option to read the font filenames from a
| file, or from STANDARD INPUT (using a "-" for a file name).
| For example...
|
| find /home/user/my/font/dir/ -name '*.ttf' | \
| imagick_type_gen -f - > ~/.magick/type-myfonts.xml
|
| You can then include that into your own personal "~/.magick/type.xml"
| file or the system-wide "type.xml" which has a form like...
| <typemap>
| <include file="type-system.xml" />
| <include file="type-myfonts.xml" />
| </typemap>
|
| Note that later defintions will override earlier ones. As such "myfonts"
| will override any "system" font. However any fonts that the IM system
| configures in /usr/lib/ImageMagick-*/config/type*.xml will override the
| both the above definitions, if the same font name is used (unlikely).
|
| When the "type.xml" font definitions file has been generated and
| installed, should then see a list of the fonts found with...
| convert -list font
|
| And can use the fonts, by name, with commands like...
| convert -font Candice -pointsize 72 label:Anthony x:
|
| Instead of having to specifying TTF font file directly...
| convert -font ~/lib/font/truetype/favoriate/candice.ttf \
| -pointsize 72 label:Anthony x:
|
| NOTE before IM v6.1.2-3 the font list file was called "type.mgk" and
| not "type.xml". And you would use "-list type" instead of "-list font"
|
| Also see the script "show_fonts" which displays a sample image either
| a IM defined font, or the given font files. The "graphics_utf" script
| may also be useful to look at specific UTF character sections of a
| specific font, such as Math symbols.
|
| Anthony Thyssen May 2003 Updated January 2009
});
}
# Internal working notes...
#
# Originally the script used an external tool to read TTF fonts, but now
# that is built-in thanks to Peter N Lewis < peter@stairways.com.au>
#
# WARNING: Input arguments are NOT tested for correctness.
# This script represents a security risk if used ONLINE.
# I accept no responsiblity for misuse. Use at own risk.
#
# The original version of this script was found on
# http://studio.imagemagick.org/pipermail/magick-users/2003-March/001703.html
# by raptor < raptor@unacs.bg>, presumaibly around March 2002
#
# Re-Write by Anthony Thyssen < anthony@cit.griffith.edu.au>, August 2002
# May 2003 Update with TTF family names
# Oct 2005 Update to use "getttinfo" if available
#
use strict;
use Fcntl qw( O_RDONLY SEEK_SET );
binmode(STDOUT, ":utf8");
binmode(STDERR, ":utf8");
my $VERBOSE = 0; # verbose output of fonts found
my $DEBUG = 0; # debug TTF file decoding
# ======================================================================
# Subroutines...
# ======================================================================
#
# True Type fonts Handling
#
my $ttf_template = herefile( q{
| <type
| format="ttf"
| name="%s"
| glyphs="%s"
| />
});
my $ttf_template_full = herefile( q{
| <type
| format="ttf"
| name="%s"
| fullname="%s"
| family="%s"
| glyphs="%s"
| />
});
sub ttf_file_parse {
#
# Method for Parsing TTF files curtesy of
# Peter N Lewis < peter@stairways.com.au>
#
my $file = $_[0];
my ( $font_family, $font_fullname, $font_psname ) = ( '','','','' );
my ( $fh, $len );
unless ( sysopen( $fh, $file, O_RDONLY ) ) {
warn "Cannot open $file: $!\n";
return;
}
my $header;
unless ( sysread( $fh, $header, 12 ) ) {
warn "Cant read header: $file";
close($fh);
return;
}
my ( $sfnt_version, $numTables, $searchRange, $entrySelector, $rangeShift
) = unpack( 'Nnnnn', $header );
my $sfnt_version_code = unpack( 'A4', $header );
unless ( $sfnt_version == 0x00010000
|| $sfnt_version_code eq 'true'
|| $sfnt_version_code eq 'typ1' ) {
warn "TTF Version mismatch, not a basic TrueType font file: $file";
close($fh);
return;
}
print STDERR "TTF Table count: $numTables\n" if $DEBUG>=2;
foreach ( 1..$numTables ) {
my $table_entry;
unless ( sysread( $fh, $table_entry, 16 ) ) {
warn "Cant read master table $_ from $file";
last;
}
my ( $table_tag, $table_checkSum, $table_offset, $table_length
) = unpack( 'A4NNN', $table_entry );
print STDERR "Table: $table_tag\n" if $DEBUG>=2;
$table_tag eq 'name' or next;
my $table_header;
sysseek( $fh, $table_offset, SEEK_SET ) or die "Can't seek: $file";
sysread( $fh, $table_header, 6 );
my ( $table_format, $table_count, $table_stringOffset
) = unpack( 'nnn', $table_header );
print STDERR "Name Table Entries: $table_count\n" if $DEBUG>=2;
my $table_base = $table_offset + 6;
my $storage_base = $table_base + $table_count * 12;
foreach my $index ( 1..$table_count ) {
my $entry;
sysseek( $fh, $table_base + ($index-1)*12, SEEK_SET )
or die "Cant seek: $file";
sysread( $fh, $entry, 12 );
my ( $name_platformID, $name_encodingID, $name_languageID,
$name_id, $name_length, $name_offset
) = unpack( 'nnnnnn', $entry );
print STDERR "Index[$index]: ", join ( ", ",
$name_platformID, $name_encodingID, $name_languageID,
$name_id, $name_length, $name_offset ), "\n" if $DEBUG>=2;
#
# ID meanings : figured out from getttinfo
#
# Platform: 0=Apple 1=macintosh 3=microsoft
# Encoding: 0=unicode(8) 1=unicode(16)
# Language: 0=english 1033=English-US 1041=Japanese 2052=Chinese
#
next unless $name_languageID == 0
|| $name_languageID == 1033
;
my $name;
sysseek( $fh, $storage_base + $name_offset, SEEK_SET )
or die "Cant seek: $file";
sysread( $fh, $name, $name_length );
# Decode UTF-16 to UTF-8 if nessary
$name = pack("U*",unpack("n*", $name)) if $name_encodingID == 1;
$name =~ s/\0//g; # clean fonts use UTF-16 when it should be UTF-8
print STDERR "$name\n" if $DEBUG>=2;
$font_family = $name if $name_id == 1;
#font_subfamily = $name if $name_id == 2; # (EG: Regular)
#font_identifier = $name if $name_id == 3; # Unique Name
$font_fullname = $name if $name_id == 4;
#font_version = $name if $name_id == 5;
$font_psname = $name if $name_id == 6; # Postscipt Name
#font_trademark = $name if $name_id == 7;
#font_manufacturer = $name if $name_id == 8;
#font_designer = $name if $name_id == 9;
}
last; # found "name" table -- skip any other tables as irrelevent
}
close( $fh );
return ( $font_family, $font_fullname, $font_psname );
}
sub ttf_name {
my $file = shift;
my ( $family, $fullname, $psname ) = &ttf_file_parse( $file );
print STDERR "$file\n\t==> $family -- $fullname -- $psname\n" if $DEBUG;
$fullname =~ s/[^\s\w-]//g; # Check: Pepsi.ttf
$fullname =~ s/^\s+//;
$fullname =~ s/\s+$//;
$fullname =~ s/(^|\s)-/$1/g;
$fullname =~ s/-(\s|$)/$1/g;
$family =~ s/[^\s\w-]//g; # Check: Pepsi.ttf
$family =~ s/^\s*//;
$family =~ s/\s*$//;
$family =~ s/\s*(MS|ITC)$//; # font factory ititials
$family =~ s/^(MS|ITC)\s*//;
$family =~ s/\s*(FB|MT)\s*/ /; # Check: MaturaScriptCapitals
$family =~ s/^Monotype\s*//; # Check: Corsiva
$family =~ s/^AR PL\s*//; # Check: gkai00mp.ttf
$family =~ s/\sBV$//; # Check: CandyStore.ttf
# Determine simple font name
# Junk/abbr decriptive strings, foundaries, etc
# Test with the fonts given
my $name = ($fullname);
$name =~ s/-/ /g;
$name =~ s/\s*(MS|ITC)$//; # font factory ititials
$name =~ s/^(MS|ITC)\s*//;
$name =~ s/\s*(FB|MT)\s*/ /; # Check: MaturaScriptCapitals
$name =~ s/^Monotype\s*//; # Check: Corsiva
$name =~ s/^AR PL\s*//; # Check: gkai00mp.ttf
$name =~ s/^TTF_//; # Check: TattoEF.tff
$name =~ s/^HE_//; # Check: Terminal.tff
$name =~ s/^KR\s//; # Check: SimpleFleur*.ttf
$name =~ s/\sBT$//; # Check: Amazone.ttf
$name =~ s/\sBV$//; # Check: CandyStore.ttf
$name =~ s/\sFM$//; # Check: CactusSandwich.ttf
$name =~ s/\sNFI$//; # Check: Zreaks.ttf
$name =~ s/SSK$//; # Check: BravoScript.ttf
$name =~ s/Regular//g; # Check: Gecko
$name =~ s/\bPlain\b//g; # Check: LittleGidding
$name =~ s/\bReg\b//g; # Check: agencyr.ttf
$name =~ s/\bNormal\b//g;
#$name =~ s/\bSans\b//g;
$name =~ s/\bDemi\s*[Bb]old\b/Db/g;
$name =~ s/\bCondensed\b/C/g;
$name =~ s/\bBold\b/B/g;
$name =~ s/\bItalic\b/I/g;
$name =~ s/\bExtra[Bb]old\b/Xb/g;
$name =~ s/\bBlack\b/Bk/g;
$name =~ s/\bHeavy\b/H/g;
$name =~ s/\bMedium\b/M/g; # Check: gkai00mp.ttf
$name =~ s/\bLight\b/L/g;
$name =~ s/\bOblique\b/Ob/g;
$name =~ s/\bUnregistered\b//g; # Check: CandyCane.ttf
$name =~ s/\s+//g; # Remove all spaces
# Special Case Renaming
$name = "Dot" if $name eq "NationalFirstFontDotted";
$fullname =~ s/\s+/ /g;
$fullname =~ s/\s$//;
$fullname =~ s/^\s//;
# Failed to parse TTF file?
return( ( $file =~ m/^.*\/(.*?).ttf$/ )[0] ) unless $name;
return ($name, $fullname, $family); # return the name if found!
}
sub do_ttf_font {
my $file = shift;
my (@ttf) = ttf_name($file);
print STDERR join( ' - ', @ttf), "\n" if $VERBOSE;
printf $ttf_template, @ttf, $file if @ttf == 1;
printf $ttf_template_full, @ttf, $file if @ttf == 3;
}
sub do_ttf_fonts {
for ( locate('ttf') ) {
do_ttf_font($_);
}
}
#---------------------------
#
# Open Type fonts
#
# I do not know how to parse OTF files (yet)
# so we are stuck with just the filebame
#
my $otf_template = herefile( q{
| <type
| format="otf"
| name="%s"
| glyphs="%s"
| />
});
sub do_otf_font {
my $file = shift;
my $name = $file;
$name =~ s/^.*\///;
$name =~ s/\.otf$//;
$name =~ s/-?Regular//g;
$name =~ s/-?Bold?/B/g;
$name =~ s/-?Italic/I/g;
$name =~ s/-?Ita?/I/g;
$name =~ s/-?Oblique/Ob/g;
print STDERR join( ' - ', $name ), "\n" if $VERBOSE;
printf $otf_template, $name, $file;
}
sub do_otf_fonts {
for ( locate('otf') ) {
do_otf_font($_);
}
}
#---------------------------
#
# Adobe Type fonts
#
# Get font name from the AFM file
my $afm_template_full = herefile( q{
| <type
| format="type1"
| name="%s"
| fullname="%s"
| family="%s"
| glyphs="%s"
| metrics="%s"
| />
});
sub afm_name {
my $file = shift;
my( $name, $fullname, $family ) = ('','','');
if ( open AFM, $file ) {
while( <AFM> ) {
chop; last if /^StartCharMetrics/;
#$name = $1 if /^FontName (.*)/;
$fullname = $1 if /^FullName (.*)/;
$family = $1 if /^FamilyName (.*)/;
}
close AFM;
$family =~ s/\s*L$//; # just the stupid 'L'
$fullname =~ s/\bL\b//;
$name = $fullname;
$name =~ s/\bRegular\b//; # Junk/abbr decriptive strings
$name =~ s/\bDemi\s*[Bb]old\b/Db/g;
$name =~ s/\bCondensed\b/C/g;
$name =~ s/\bBold\b/B/g;
$name =~ s/\bItalic\b/I/g;
$name =~ s/\bExtra[Bb]old\b/Xb/g;
$name =~ s/\bBlack\b/Bk/g;
$name =~ s/\bHeavy\b/H/g;
$name =~ s/\bLight\b/L/g;
$name =~ s/[-\s]+//g;
$fullname =~ s/\s+/ /g;
$fullname =~ s/\s$//g;
$fullname =~ s/^\s//g;
} else {
warn "Cannot open $file";
}
return ($name, $fullname, $family ) if $name && $fullname && $family;
}
sub do_afm_fonts {
my %atf;
# locate abode font files
map { my ($k) = m/^(.*?).pfb*$/i; $atf{lc($k)}{pfb} = $_ } locate('pfb');
map { my ($k) = m/^(.*?).afm*$/i; $atf{lc($k)}{afm} = $_ } locate('afm');
# for each Abode font where BOTH files were found.
for my $key (keys %atf) {
next unless $atf{$key}{pfb} && $atf{$key}{afm};
my (@afm) = afm_name($atf{$key}{afm});
#print STDERR join( ' - ', @afm), "\n" if $VERBOSE;
printf $afm_template_full, @afm, $atf{$key}{pfb}, $atf{$key}{afm}
if @afm == 3;
}
}
# -----------------------------
#
# Miscellanous functions
#
sub locate {
# This fails under MacOSX
#return split('\0', `locate -0ier '\\.$_[0]\$'`);
# Use perl to 'glob' expand '?' in locate output on MacOSX
return grep { /\.$_[0]$/i && -f $_ }
map { glob "$_" }
split "\n", `locate -i '.$_[0]'`;
}
sub herefile { # Handle a multi-line quoted indented string
my $string = shift;
$string =~ s/^\s*//; # remove start spaces
$string =~ s/^\s*\| ?//gm; # remove line starts
$string =~ s/\s*$/\n/g; # remove end spaces
return $string;
}
sub do_font {
local $_ = shift;
if ( /\.ttf$/i ) {
do_ttf_font($_)
}
elsif ( $_ =~ /\.otf$/i ) {
do_otf_font($_)
}
else {
print STDERR "$prog: \"$_\" skipped, unknown suffix\n";
}
}
# ======================================================================
# Main Function
# ======================================================================
print herefile( q{
| <?xml version="1.0"?>
| <typemap>
});
# Read TTF font filenames from a file or stdin
$DEBUG=1,shift if @ARGV && $ARGV[0] eq '-d';
if ( @ARGV ) {
if ( $ARGV[0] eq '-?' || $ARGV[0] eq '-h' || $ARGV[0] eq '--help' ) {
Usage;
}
if ( $ARGV[0] eq '-f' ) {
shift;
while( <> ) {
s/#.*$//; # ignore comments
s/\s+$//; # remove end of line spaces
next if /^$/; # skip blank lines
do_font($_);
}
}
else {
# TTF font filenames as arguments
for ( @ARGV ) {
do_font($_);
}
}
} else {
# Generate the "type.xml" file using "locate"
print STDERR "Doing TTF fonts\n" if $VERBOSE;
do_ttf_fonts();
print STDERR "Doing OTF fonts\n" if $VERBOSE;
do_otf_fonts($_);
print STDERR "Doing ATM fonts\n" if $VERBOSE;
do_afm_fonts();
}
print "</typemap>\n";
#
(my $prog = $0) =~ s/^.*\///;
sub Usage {
die @_, &herefile( qq{
| Usage: $prog > ~/.magick/type.xml
| $prog [-d] font1.ttf font2.ttf ... > type.xml
| $prog -f ttf_font_file_list > type.xml
|
| Generate an ImageMagick font list "type.xml" file for ALL fonts
| currently on the local linux system. This includes
| True Type Fonts (ttf)
| Ghostscript Fonts (afm)
| Open Type Fonts (otf)
|
| The output can be saved into files in the ".magick" sub-directory of
| your home, to be referenced by, or replacing the "type.xml" file.
|
| This file informs ImageMagick of the fonts location, font type, name and
| family. It also trys its best to clean up the name to provide a 'nicer'
| one for you to identify the various fonts.
|
| By default the fonts are found using the linux "locate" command, so run
| "updatedb" if you only just added new fonts to your computer.
|
| However you can use a "-f" option to read the font filenames from a
| file, or from STANDARD INPUT (using a "-" for a file name).
| For example...
|
| find /home/user/my/font/dir/ -name '*.ttf' | \
| imagick_type_gen -f - > ~/.magick/type-myfonts.xml
|
| You can then include that into your own personal "~/.magick/type.xml"
| file or the system-wide "type.xml" which has a form like...
| <typemap>
| <include file="type-system.xml" />
| <include file="type-myfonts.xml" />
| </typemap>
|
| Note that later defintions will override earlier ones. As such "myfonts"
| will override any "system" font. However any fonts that the IM system
| configures in /usr/lib/ImageMagick-*/config/type*.xml will override the
| both the above definitions, if the same font name is used (unlikely).
|
| When the "type.xml" font definitions file has been generated and
| installed, should then see a list of the fonts found with...
| convert -list font
|
| And can use the fonts, by name, with commands like...
| convert -font Candice -pointsize 72 label:Anthony x:
|
| Instead of having to specifying TTF font file directly...
| convert -font ~/lib/font/truetype/favoriate/candice.ttf \
| -pointsize 72 label:Anthony x:
|
| NOTE before IM v6.1.2-3 the font list file was called "type.mgk" and
| not "type.xml". And you would use "-list type" instead of "-list font"
|
| Also see the script "show_fonts" which displays a sample image either
| a IM defined font, or the given font files. The "graphics_utf" script
| may also be useful to look at specific UTF character sections of a
| specific font, such as Math symbols.
|
| Anthony Thyssen May 2003 Updated January 2009
});
}
# Internal working notes...
#
# Originally the script used an external tool to read TTF fonts, but now
# that is built-in thanks to Peter N Lewis < peter@stairways.com.au>
#
# WARNING: Input arguments are NOT tested for correctness.
# This script represents a security risk if used ONLINE.
# I accept no responsiblity for misuse. Use at own risk.
#
# The original version of this script was found on
# http://studio.imagemagick.org/pipermail/magick-users/2003-March/001703.html
# by raptor < raptor@unacs.bg>, presumaibly around March 2002
#
# Re-Write by Anthony Thyssen < anthony@cit.griffith.edu.au>, August 2002
# May 2003 Update with TTF family names
# Oct 2005 Update to use "getttinfo" if available
#
use strict;
use Fcntl qw( O_RDONLY SEEK_SET );
binmode(STDOUT, ":utf8");
binmode(STDERR, ":utf8");
my $VERBOSE = 0; # verbose output of fonts found
my $DEBUG = 0; # debug TTF file decoding
# ======================================================================
# Subroutines...
# ======================================================================
#
# True Type fonts Handling
#
my $ttf_template = herefile( q{
| <type
| format="ttf"
| name="%s"
| glyphs="%s"
| />
});
my $ttf_template_full = herefile( q{
| <type
| format="ttf"
| name="%s"
| fullname="%s"
| family="%s"
| glyphs="%s"
| />
});
sub ttf_file_parse {
#
# Method for Parsing TTF files curtesy of
# Peter N Lewis < peter@stairways.com.au>
#
my $file = $_[0];
my ( $font_family, $font_fullname, $font_psname ) = ( '','','','' );
my ( $fh, $len );
unless ( sysopen( $fh, $file, O_RDONLY ) ) {
warn "Cannot open $file: $!\n";
return;
}
my $header;
unless ( sysread( $fh, $header, 12 ) ) {
warn "Cant read header: $file";
close($fh);
return;
}
my ( $sfnt_version, $numTables, $searchRange, $entrySelector, $rangeShift
) = unpack( 'Nnnnn', $header );
my $sfnt_version_code = unpack( 'A4', $header );
unless ( $sfnt_version == 0x00010000
|| $sfnt_version_code eq 'true'
|| $sfnt_version_code eq 'typ1' ) {
warn "TTF Version mismatch, not a basic TrueType font file: $file";
close($fh);
return;
}
print STDERR "TTF Table count: $numTables\n" if $DEBUG>=2;
foreach ( 1..$numTables ) {
my $table_entry;
unless ( sysread( $fh, $table_entry, 16 ) ) {
warn "Cant read master table $_ from $file";
last;
}
my ( $table_tag, $table_checkSum, $table_offset, $table_length
) = unpack( 'A4NNN', $table_entry );
print STDERR "Table: $table_tag\n" if $DEBUG>=2;
$table_tag eq 'name' or next;
my $table_header;
sysseek( $fh, $table_offset, SEEK_SET ) or die "Can't seek: $file";
sysread( $fh, $table_header, 6 );
my ( $table_format, $table_count, $table_stringOffset
) = unpack( 'nnn', $table_header );
print STDERR "Name Table Entries: $table_count\n" if $DEBUG>=2;
my $table_base = $table_offset + 6;
my $storage_base = $table_base + $table_count * 12;
foreach my $index ( 1..$table_count ) {
my $entry;
sysseek( $fh, $table_base + ($index-1)*12, SEEK_SET )
or die "Cant seek: $file";
sysread( $fh, $entry, 12 );
my ( $name_platformID, $name_encodingID, $name_languageID,
$name_id, $name_length, $name_offset
) = unpack( 'nnnnnn', $entry );
print STDERR "Index[$index]: ", join ( ", ",
$name_platformID, $name_encodingID, $name_languageID,
$name_id, $name_length, $name_offset ), "\n" if $DEBUG>=2;
#
# ID meanings : figured out from getttinfo
#
# Platform: 0=Apple 1=macintosh 3=microsoft
# Encoding: 0=unicode(8) 1=unicode(16)
# Language: 0=english 1033=English-US 1041=Japanese 2052=Chinese
#
next unless $name_languageID == 0
|| $name_languageID == 1033
;
my $name;
sysseek( $fh, $storage_base + $name_offset, SEEK_SET )
or die "Cant seek: $file";
sysread( $fh, $name, $name_length );
# Decode UTF-16 to UTF-8 if nessary
$name = pack("U*",unpack("n*", $name)) if $name_encodingID == 1;
$name =~ s/\0//g; # clean fonts use UTF-16 when it should be UTF-8
print STDERR "$name\n" if $DEBUG>=2;
$font_family = $name if $name_id == 1;
#font_subfamily = $name if $name_id == 2; # (EG: Regular)
#font_identifier = $name if $name_id == 3; # Unique Name
$font_fullname = $name if $name_id == 4;
#font_version = $name if $name_id == 5;
$font_psname = $name if $name_id == 6; # Postscipt Name
#font_trademark = $name if $name_id == 7;
#font_manufacturer = $name if $name_id == 8;
#font_designer = $name if $name_id == 9;
}
last; # found "name" table -- skip any other tables as irrelevent
}
close( $fh );
return ( $font_family, $font_fullname, $font_psname );
}
sub ttf_name {
my $file = shift;
my ( $family, $fullname, $psname ) = &ttf_file_parse( $file );
print STDERR "$file\n\t==> $family -- $fullname -- $psname\n" if $DEBUG;
$fullname =~ s/[^\s\w-]//g; # Check: Pepsi.ttf
$fullname =~ s/^\s+//;
$fullname =~ s/\s+$//;
$fullname =~ s/(^|\s)-/$1/g;
$fullname =~ s/-(\s|$)/$1/g;
$family =~ s/[^\s\w-]//g; # Check: Pepsi.ttf
$family =~ s/^\s*//;
$family =~ s/\s*$//;
$family =~ s/\s*(MS|ITC)$//; # font factory ititials
$family =~ s/^(MS|ITC)\s*//;
$family =~ s/\s*(FB|MT)\s*/ /; # Check: MaturaScriptCapitals
$family =~ s/^Monotype\s*//; # Check: Corsiva
$family =~ s/^AR PL\s*//; # Check: gkai00mp.ttf
$family =~ s/\sBV$//; # Check: CandyStore.ttf
# Determine simple font name
# Junk/abbr decriptive strings, foundaries, etc
# Test with the fonts given
my $name = ($fullname);
$name =~ s/-/ /g;
$name =~ s/\s*(MS|ITC)$//; # font factory ititials
$name =~ s/^(MS|ITC)\s*//;
$name =~ s/\s*(FB|MT)\s*/ /; # Check: MaturaScriptCapitals
$name =~ s/^Monotype\s*//; # Check: Corsiva
$name =~ s/^AR PL\s*//; # Check: gkai00mp.ttf
$name =~ s/^TTF_//; # Check: TattoEF.tff
$name =~ s/^HE_//; # Check: Terminal.tff
$name =~ s/^KR\s//; # Check: SimpleFleur*.ttf
$name =~ s/\sBT$//; # Check: Amazone.ttf
$name =~ s/\sBV$//; # Check: CandyStore.ttf
$name =~ s/\sFM$//; # Check: CactusSandwich.ttf
$name =~ s/\sNFI$//; # Check: Zreaks.ttf
$name =~ s/SSK$//; # Check: BravoScript.ttf
$name =~ s/Regular//g; # Check: Gecko
$name =~ s/\bPlain\b//g; # Check: LittleGidding
$name =~ s/\bReg\b//g; # Check: agencyr.ttf
$name =~ s/\bNormal\b//g;
#$name =~ s/\bSans\b//g;
$name =~ s/\bDemi\s*[Bb]old\b/Db/g;
$name =~ s/\bCondensed\b/C/g;
$name =~ s/\bBold\b/B/g;
$name =~ s/\bItalic\b/I/g;
$name =~ s/\bExtra[Bb]old\b/Xb/g;
$name =~ s/\bBlack\b/Bk/g;
$name =~ s/\bHeavy\b/H/g;
$name =~ s/\bMedium\b/M/g; # Check: gkai00mp.ttf
$name =~ s/\bLight\b/L/g;
$name =~ s/\bOblique\b/Ob/g;
$name =~ s/\bUnregistered\b//g; # Check: CandyCane.ttf
$name =~ s/\s+//g; # Remove all spaces
# Special Case Renaming
$name = "Dot" if $name eq "NationalFirstFontDotted";
$fullname =~ s/\s+/ /g;
$fullname =~ s/\s$//;
$fullname =~ s/^\s//;
# Failed to parse TTF file?
return( ( $file =~ m/^.*\/(.*?).ttf$/ )[0] ) unless $name;
return ($name, $fullname, $family); # return the name if found!
}
sub do_ttf_font {
my $file = shift;
my (@ttf) = ttf_name($file);
print STDERR join( ' - ', @ttf), "\n" if $VERBOSE;
printf $ttf_template, @ttf, $file if @ttf == 1;
printf $ttf_template_full, @ttf, $file if @ttf == 3;
}
sub do_ttf_fonts {
for ( locate('ttf') ) {
do_ttf_font($_);
}
}
#---------------------------
#
# Open Type fonts
#
# I do not know how to parse OTF files (yet)
# so we are stuck with just the filebame
#
my $otf_template = herefile( q{
| <type
| format="otf"
| name="%s"
| glyphs="%s"
| />
});
sub do_otf_font {
my $file = shift;
my $name = $file;
$name =~ s/^.*\///;
$name =~ s/\.otf$//;
$name =~ s/-?Regular//g;
$name =~ s/-?Bold?/B/g;
$name =~ s/-?Italic/I/g;
$name =~ s/-?Ita?/I/g;
$name =~ s/-?Oblique/Ob/g;
print STDERR join( ' - ', $name ), "\n" if $VERBOSE;
printf $otf_template, $name, $file;
}
sub do_otf_fonts {
for ( locate('otf') ) {
do_otf_font($_);
}
}
#---------------------------
#
# Adobe Type fonts
#
# Get font name from the AFM file
my $afm_template_full = herefile( q{
| <type
| format="type1"
| name="%s"
| fullname="%s"
| family="%s"
| glyphs="%s"
| metrics="%s"
| />
});
sub afm_name {
my $file = shift;
my( $name, $fullname, $family ) = ('','','');
if ( open AFM, $file ) {
while( <AFM> ) {
chop; last if /^StartCharMetrics/;
#$name = $1 if /^FontName (.*)/;
$fullname = $1 if /^FullName (.*)/;
$family = $1 if /^FamilyName (.*)/;
}
close AFM;
$family =~ s/\s*L$//; # just the stupid 'L'
$fullname =~ s/\bL\b//;
$name = $fullname;
$name =~ s/\bRegular\b//; # Junk/abbr decriptive strings
$name =~ s/\bDemi\s*[Bb]old\b/Db/g;
$name =~ s/\bCondensed\b/C/g;
$name =~ s/\bBold\b/B/g;
$name =~ s/\bItalic\b/I/g;
$name =~ s/\bExtra[Bb]old\b/Xb/g;
$name =~ s/\bBlack\b/Bk/g;
$name =~ s/\bHeavy\b/H/g;
$name =~ s/\bLight\b/L/g;
$name =~ s/[-\s]+//g;
$fullname =~ s/\s+/ /g;
$fullname =~ s/\s$//g;
$fullname =~ s/^\s//g;
} else {
warn "Cannot open $file";
}
return ($name, $fullname, $family ) if $name && $fullname && $family;
}
sub do_afm_fonts {
my %atf;
# locate abode font files
map { my ($k) = m/^(.*?).pfb*$/i; $atf{lc($k)}{pfb} = $_ } locate('pfb');
map { my ($k) = m/^(.*?).afm*$/i; $atf{lc($k)}{afm} = $_ } locate('afm');
# for each Abode font where BOTH files were found.
for my $key (keys %atf) {
next unless $atf{$key}{pfb} && $atf{$key}{afm};
my (@afm) = afm_name($atf{$key}{afm});
#print STDERR join( ' - ', @afm), "\n" if $VERBOSE;
printf $afm_template_full, @afm, $atf{$key}{pfb}, $atf{$key}{afm}
if @afm == 3;
}
}
# -----------------------------
#
# Miscellanous functions
#
sub locate {
# This fails under MacOSX
#return split('\0', `locate -0ier '\\.$_[0]\$'`);
# Use perl to 'glob' expand '?' in locate output on MacOSX
return grep { /\.$_[0]$/i && -f $_ }
map { glob "$_" }
split "\n", `locate -i '.$_[0]'`;
}
sub herefile { # Handle a multi-line quoted indented string
my $string = shift;
$string =~ s/^\s*//; # remove start spaces
$string =~ s/^\s*\| ?//gm; # remove line starts
$string =~ s/\s*$/\n/g; # remove end spaces
return $string;
}
sub do_font {
local $_ = shift;
if ( /\.ttf$/i ) {
do_ttf_font($_)
}
elsif ( $_ =~ /\.otf$/i ) {
do_otf_font($_)
}
else {
print STDERR "$prog: \"$_\" skipped, unknown suffix\n";
}
}
# ======================================================================
# Main Function
# ======================================================================
print herefile( q{
| <?xml version="1.0"?>
| <typemap>
});
# Read TTF font filenames from a file or stdin
$DEBUG=1,shift if @ARGV && $ARGV[0] eq '-d';
if ( @ARGV ) {
if ( $ARGV[0] eq '-?' || $ARGV[0] eq '-h' || $ARGV[0] eq '--help' ) {
Usage;
}
if ( $ARGV[0] eq '-f' ) {
shift;
while( <> ) {
s/#.*$//; # ignore comments
s/\s+$//; # remove end of line spaces
next if /^$/; # skip blank lines
do_font($_);
}
}
else {
# TTF font filenames as arguments
for ( @ARGV ) {
do_font($_);
}
}
} else {
# Generate the "type.xml" file using "locate"
print STDERR "Doing TTF fonts\n" if $VERBOSE;
do_ttf_fonts();
print STDERR "Doing OTF fonts\n" if $VERBOSE;
do_otf_fonts($_);
print STDERR "Doing ATM fonts\n" if $VERBOSE;
do_afm_fonts();
}
print "</typemap>\n";