summaryrefslogtreecommitdiff
path: root/support/rfil/examples
diff options
context:
space:
mode:
Diffstat (limited to 'support/rfil/examples')
-rwxr-xr-xsupport/rfil/examples/afm2tfm.rb204
-rwxr-xr-xsupport/rfil/examples/afminfo249
-rwxr-xr-xsupport/rfil/examples/encodingtable67
-rwxr-xr-xsupport/rfil/examples/pldiff297
-rwxr-xr-xsupport/rfil/examples/plinfo109
-rwxr-xr-xsupport/rfil/examples/rfii257
-rwxr-xr-xsupport/rfil/examples/rfont185
7 files changed, 1368 insertions, 0 deletions
diff --git a/support/rfil/examples/afm2tfm.rb b/support/rfil/examples/afm2tfm.rb
new file mode 100755
index 0000000000..8bdc654548
--- /dev/null
+++ b/support/rfil/examples/afm2tfm.rb
@@ -0,0 +1,204 @@
+#!/usr/bin/env ruby
+#--
+# Last Change: Tue May 16 18:10:52 2006
+#++
+=begin rdoc
+== afm2tfm using the ruby font installer library
+This is a re-implementation of afm2tfm that is part of dvips. This
+does not aim for a 100% compatible output. There are some differences
+in the calculation of the font metrics, which, in my opinion, are
+reasonable. The -u and -o switch are missing from this implementation.
+
+ Usage: afm2tfm.rb [options] FILE[.afm,.ttf] ... [FILE[.tfm]]
+ -c REAL use REAL for height of small caps made with -V [0.8]
+ -d DIRNAME Set the base output directory to DIRNAME
+ -e REAL widen (extend) characters by a factor of REAL
+ -l Include ligature and kerning information in tfm file
+ -p ENCFILE read/download ENCFILE for the PostScript encoding
+ -s REAL oblique (slant) characters by REAL, generally <<1
+ -t ENCFILE read ENCFILE for the encoding of the vf file
+ -T ENCFILE equivalent to -p ENCFILE -t ENCFILE
+ -v [FILE] make a VF file with filename FILE
+ -V [SCFILE] like -v, but synthesize smallcaps as lowercase
+ --help print this message and exit.
+ --version print version number and exit.
+
+= Usage
+See the documentation of the original afm2tfm for an explanation of
+the parameters -c, -e, -s, -p, -t, -T, -v and -V.
+
+afm2tfm.rb creates a tfm (tex font metric) file from the font given as
+the first argument. This font can be a Postscript Type 1 font metric
+file (afm) or a TrueType font. (So the name of the program is a bit
+misleading, it is not restricted to Type 1 font metric files.) The tfm
+file is written assuming that the underlying TeX text is encoded in
+the encoding given with the -p parameter.
+
+[<tt>-d</tt> DIRNAME] Set the base directory to DIRNAME. All files are written to the base directory. If unset, use the current directory.
+[<tt>-l</tt>] Don't discard the ligature and kerning information when writing the tfm file.
+[<tt>-v</tt>, <tt>-V</tt> FILE] The filename of the virtual fonts is optional. When unset, construct a name such as <tt>ec-savorg__-capitalized-800</tt>.
+---
+Remark: this is not the reimplementation I mentioned at the 35th NTG meeting.
+
+Author:: Patrick Gundlach <patrick@gundla.ch>
+License:: Copyright (c) 2005 Patrick Gundlach.
+ Released under the terms of the GNU General Public License
+=end
+
+
+# :enddoc:
+
+# font metric differences between afm2tfm and afm2tfm.rb
+# tfm: fix_height is applied before writing out the tfm file, so the height
+# of the glpyphs are different.
+# slant: charic calculation in the vpl file is not affected by the
+# texheight in afm2tfm.c, but in afm2tfm.rb the height is changed
+# before cahric calculation
+# other:
+# in my testfont, the hyphen has a different height in the tfm
+# file: 732 (afm2tfm.c) vs. 240 (afm2tfm.rb)
+
+require 'optparse'
+require 'ostruct'
+require 'rfil/font'
+
+include RFIL
+options=OpenStruct.new
+
+ARGV.options { |opt|
+ opt.banner = "Usage: #{File.basename($0)} [options] FILE[.afm] ... [FILE[.tfm]]"
+ opt.on("-c REAL", Float,
+ "use REAL for height of small caps made with -V [0.8]") {|c|
+ if c and c >= 0.01
+ options.capheight=c
+ else
+ puts "! Bad small caps height"
+ exit -1
+ end
+ }
+ opt.on("-d DIRNAME", String, "Set the base output directory to DIRNAME") {|d|
+ if File.exists?(d) and File.directory?(d)
+ options.dirname=d
+ else
+ puts "! #{d} does not exist or is not a directory"
+ exit -1
+ end
+ }
+ opt.on("-e REAL", Float, "widen (extend) characters by a factor of REAL") {|e|
+ # this test should be in class AFM
+ if e and e >= 0.01
+ options.efactor=e
+ else
+ puts "! Bad extension factor"
+ exit -1
+ end
+ }
+
+ opt.on("-l", "Include ligature and kerning information in tfm file") {
+ options.ligkern=true
+ }
+
+ opt.on("-p ENCFILE", "read/download ENCFILE for the PostScript encoding") {|e|
+ options.mapenc = e
+ }
+ opt.on("-s REAL",Float,"oblique (slant) characters by REAL, generally <<1") {|s|
+ if s
+ options.slant=s
+ else
+ puts "! Bad slant parameter"
+ exit -1
+ end
+ }
+
+ opt.on("-t ENCFILE", "read ENCFILE for the encoding of the vf file") {|e|
+ options.texenc = e
+ }
+ opt.on("-T ENCFILE",String,"equivalent to -p ENCFILE -t ENCFILE") {|e|
+ options.mapenc = e
+ options.texenc = e
+ }
+ opt.on("-v [FILE]", String, "make a VF file with filename FILE") { |v|
+ options.write_vf=true
+ options.vffile=v
+ }
+ opt.on("-V [SCFILE]","like -v, but synthesize smallcaps as lowercase") { |v|
+ options.vffile=v
+ options.write_vf=true
+ options.fakecaps=true
+ }
+ opt.on("--help","print this message and exit.") { puts opt; exit 0 }
+ opt.on("--version","print version number and exit.") {
+ puts "#{File.basename($0)}: Version 0.9"
+ puts "Uses RFI Library (https://foundry.supelec.fr/projects/rfil)"
+ puts "[Based on afm2tfm(k) (dvips(k) 5.95a) 8.1 (C) 2005 Radical Eye Software.]"
+ exit
+ }
+ opt.parse!
+}
+
+if ARGV.size == 0
+ puts "#{File.basename($0)}: Need at least one file argument."
+ puts "Try `#{File.basename($0)} --help' for more information."
+ exit 0
+end
+
+inputfile=ARGV.shift
+
+if ARGV.size >0
+ options.outputfilename=ARGV.shift
+end
+
+font = RFI::Font.new
+font.write_vf = options.write_vf
+
+if options.dirname
+ font.set_dirs(options.dirname)
+end
+
+begin
+ font.load_variant(inputfile)
+rescue Errno::ENOENT
+ puts "! Cannot find file #{inputfile}"
+ exit -1
+end
+
+
+font.texenc=options.texenc || "8a.enc"
+font.mapenc=options.mapenc || "8a.enc"
+
+font.apply_ligkern_instructions(RFI::STDLIGKERN)
+
+font.efactor=options.efactor || 1.0
+font.slant =options.slant || 0.0
+
+ploptions=options.ligkern==true ? {:noligs=>false} : {:noligs=>true}
+
+fn=font.map_fontname(font.mapenc) + ".tfm"
+f=font.to_tfm(font.mapenc,ploptions)
+f.tfmpathname=File.join(font.get_dir(:tfm),fn)
+f.save(true)
+
+if options.fakecaps
+ fc = font.load_variant(inputfile)
+ font.fake_caps(fc,options.capheight || 0.8)
+ font.copy(fc,:lowercase,:ligkern=>true)
+end
+
+if options.write_vf
+ vffilename=if options.vffile
+ options.vffile
+ else
+ font.tex_fontname(font.texenc[0])
+ end
+ vf= File.join(font.get_dir(:vf) ,vffilename+".vf")
+ tfm=File.join(font.get_dir(:tfm),vffilename+ ".tfm")
+ vpl=font.to_vf(font.mapenc,font.texenc[0])
+ vpl.tfmpathname=File.join(font.get_dir(:tfm) ,vffilename + ".tfm")
+ vpl.vfpathname=File.join(font.get_dir(:vpl) ,vffilename + ".vf")
+ vpl.save(true)
+ # vplfile= File.join(font.get_dir(:vpl) ,vffilename + ".vpl")
+ # vpl.write_vpl(vplfile)
+ # vpl.write_vf(vf,tfm)
+end
+puts font.maplines
+
diff --git a/support/rfil/examples/afminfo b/support/rfil/examples/afminfo
new file mode 100755
index 0000000000..b0f279a3ac
--- /dev/null
+++ b/support/rfil/examples/afminfo
@@ -0,0 +1,249 @@
+#!/usr/bin/env ruby
+#--
+# Last Change: Tue May 16 18:09:09 2006
+#++
+=begin rdoc
+
+== afminfo - print out information about an afm or truetype font file
+
+ Usage: afminfo [options] afm-file.afm | truetypefont.ttf
+ -m, --metrics show global metrics information
+ -v, --verbose verbose output
+ --[no-]info list general information (default)
+ -l, --list-glyphs list all available glyphs
+ -g, --glyphinfo g information about a specific glyph
+ -h, --help Show this help
+
+---
+Author:: Patrick Gundlach <patrick@gundla.ch>
+License:: Copyright (c) 2005 Patrick Gundlach.
+ Released under the terms of the GNU General Public License
+=end
+
+# :enddoc:
+
+require 'optparse'
+require 'ostruct'
+require 'rfil/font/afm'
+
+
+# sorry for german - one day I'll change that into engish. --pg
+class TextTable # :nodoc:
+ def initialize (data,maxchars=80)
+ raise "Data must be an array of strings" unless data.kind_of? Array
+ @data = data
+
+ @maxchars = 90
+ @maxwidth = 0
+ @data.each { |elt|
+ @maxwidth = @maxwidth > elt.length ? @maxwidth : elt.length
+ }
+ @spalten = (@maxchars/(@maxwidth + 1)).floor
+ end
+
+ def zeilenweise
+ (0...@data.size).each { |x|
+ print sprintf("%-" + @maxwidth.to_s + "s",@data[x]) +
+ if (x+1) % @spalten == 0
+ "\n"
+ else
+ " "
+ end
+ }
+ puts
+ end
+
+ def spaltenweise
+ zeilenmin = (@data.size * 1.0 / @spalten).floor
+ zeilenmax = (@data.size * 1.0 / @spalten).ceil
+ anz_volle_spalten = @data.size % @spalten
+
+ verteilung=Array.new()
+ verteilung[0]=0
+ count = 0
+ (0...@spalten).each { |col|
+ if col < anz_volle_spalten
+ count += zeilenmax
+ else
+ count += zeilenmin
+ end
+ verteilung[col]= count
+ }
+ verteilung.unshift 0
+ (0...zeilenmax).each { |zeile|
+ puts((0...@spalten).collect { |spalte|
+ w = @data[verteilung[spalte] + zeile]
+ if (spalte >= anz_volle_spalten) and (zeile >= zeilenmin)
+ w = ""
+ end
+ sprintf("%-" + @maxwidth.to_s + "s",w)
+ }.join(' '))
+ }
+ end
+end
+
+class AFMinfo # :nodoc:
+ def initialize (afm)
+ @afm = afm
+ @uppercase_letters = ('A'..'Z').collect { |l| l }
+ @lowercase_letters = ('a'..'z').collect { |l| l }
+ @digits = %w(one two three four five six seven eight nine zero)
+ end
+ def stdformat
+ "%-18s "
+ end
+ def printout (str,value)
+ puts sprintf(stdformat + "%s", str + ":" ,value.to_s)
+ end
+
+ def num_to_string (num,reservespace=true)
+ formatstring = "%"
+ formatstring << " " if reservespace
+ formatstring << (num.to_i == num ? "d" : "f")
+ # output "integer" if value after decimal point is 0
+ sprintf(formatstring,num)
+ end
+
+ def dump_maininfo
+ puts "General font information:"
+ puts "========================="
+ printout("Filename",@afm.filename)
+ [
+ ["Fontname",:fontname],
+ ["FullName",:fullname],
+ ["Family name",:familyname],
+ ["Weight",:weight],
+ ["EncodingScheme",:encodingscheme],
+# ["·","·"],
+ ].each { |s,m|
+ printout(s,@afm.send(m))
+ }
+ puts sprintf(stdformat,'Number of gylphs:') + @afm.count_charmetrics.to_s +
+ " (encoded: " + @afm.count_charmetrics_encoded.to_s + ", unencoded: " + @afm.count_charmetrics_unencoded.to_s + ")"
+
+ end
+ def dump_metrics
+ puts "\n\nGlobal metrics information:"
+ puts "=========================="
+ puts sprintf(stdformat,"FontBBox:") + @afm.fontbbox.collect { |f|
+ num_to_string(f)
+ }.join(' ') + ' (llx,lly,urx,ury)'
+ printout('IsFixedPitch',@afm.isfixedpitch)
+
+ [
+ ["ItalicAngle", :italicangle],
+ ["UnderlinePosition", :underlineposition],
+ ["UnderlineThickness", :underlinethickness],
+ ["CapHeight", :capheight],
+ ["XHeight", :xheight],
+ ["Ascender", :ascender],
+ ["Descender", :descender]
+ ].each { |s,m|
+ puts sprintf(stdformat,s) + num_to_string(@afm.send(m))
+ }
+ end
+ def dump_glyphinfo (glyph)
+ chars=@afm.chars[glyph]
+ puts "\n\nGlyph information (" + glyph + ")"
+ puts "===================="
+ puts sprintf(stdformat,"Encoding pos:") +
+ if chars.c == -1
+ "--"
+ else
+ sprintf("%d (dec), %x (hex), %o (oct)",chars.c,chars.c,chars.c)
+ end
+ puts sprintf(stdformat,"Width x (wx)") + chars.wx.to_s
+ puts sprintf(stdformat,"Bounding box") + chars.b.collect { |f|
+ num_to_string(f,false)
+ }.join(' ') + ' (llx,lly,urx,ury)'
+ puts "Kerning pairs: (x,y)"
+ puts "--------------------"
+ chars.kern_data.each { |k,v|
+ puts sprintf(stdformat," " + k) + num_to_string(v[0]) + "," +
+ num_to_string(v[1])
+ }
+ end
+ def dump_glyphs
+ chars=@afm.chars
+ puts "\n\nList of glyphs"
+ puts "================"
+ removefromlist=[]
+ if @uppercase_letters.all? { |glyph|
+ chars[glyph]
+ }
+ puts sprintf(stdformat,"A-Z") + "available"
+ removefromlist += @uppercase_letters
+ else
+ puts sprintf(stdformat,"A-Z") + "some missing"
+ end
+ if @lowercase_letters.all? { |glyph|
+ chars[glyph]
+ }
+ puts sprintf(stdformat,"a-z") + "available"
+ removefromlist += @lowercase_letters
+ else
+ puts sprintf(stdformat,"a-z") + "some missing"
+ end
+ if @digits.all? { |glyph|
+ chars[glyph]
+ }
+ puts sprintf(stdformat,"one, two, .., zero") + "available"
+ removefromlist += @digits
+ else
+ puts sprintf(stdformat,"one, two, .., zero") + "some missing"
+ end
+ puts
+ glyphlist=[]
+ chars.each { |glyph,h|
+ glyphlist.push(glyph + (h.c == -1 ? "*" : ""))
+ }
+ glyphlist = glyphlist - removefromlist
+ glyphlist.sort! { |a,b|
+ a.casecmp b
+ }
+ t = TextTable.new(glyphlist - removefromlist)
+ t.spaltenweise
+ puts "\n* = unencoded - only glyphs not mentioned above listed"
+ end
+
+end
+
+options=OpenStruct.new
+options.verbose = false
+options.metrics = false
+options.glyph = nil
+options.listglyphs = false
+options.generalinfo = true
+
+ARGV.options { |opt|
+ opt.banner = "Usage: #{File.basename($0)} [options] afm-file[.afm]"
+ opt.on("--metrics", "-m", "show global metrics information") { options.metrics=true}
+ opt.on("--verbose", "-v", "verbose output") { options.verbose=true }
+ opt.on("--[no-]info", "list general information (default)") { |x|
+ options.generalinfo=x }
+ opt.on("--list-glyphs", "-l", "list all available glyphs") { options.listglyphs=true }
+ opt.on("--glyphinfo g" , "-g",
+ "information about a specific glyph") { |arg|
+ options.glyph = arg
+ }
+
+ opt.on("--help", "-h", "Show this help") { puts opt; exit 0 }
+ opt.separator ""
+ opt.separator "Copyright (c) 2005 Patrick Gundlach"
+ opt.parse!
+}
+
+unless ARGV.size==1
+ puts "Please specify one afm-file to read" if ARGV
+ exit 1
+end
+
+
+# afm=Font::AFM.new(:verbose => options.verbose)
+afm=RFIL::Font::Metric.read(ARGV[0],:verbose => options.verbose)
+
+ai = AFMinfo.new(afm)
+ai.dump_maininfo if options.generalinfo
+ai.dump_metrics if options.metrics
+options.glyph && ai.dump_glyphinfo(options.glyph)
+ai.dump_glyphs if options.listglyphs
diff --git a/support/rfil/examples/encodingtable b/support/rfil/examples/encodingtable
new file mode 100755
index 0000000000..59c12d459d
--- /dev/null
+++ b/support/rfil/examples/encodingtable
@@ -0,0 +1,67 @@
+#!/usr/bin/env ruby -w
+#--
+# Last Change: Tue May 16 18:11:49 2006
+#++
+=begin rdoc
+= encodingtable -- print out a table with different encodings in colums
+
+This is mainly an example how to use the ENC and Kpathsea class.
+
+== Usage
+ encodingtable encoding[.enc] [encoding[.enc] ...]
+
+
+== Example
+
+ $ ./encodingtable ec texnansi 8r 8a
+
+ dec | oct |hex | ECEncoding | TeXnANSIEncoding | TeXBase1Encoding | StandardEncoding |
+ --------------------------------------------------------------------------------------------
+ 0 | 0 | 0 | grave | --- | --- | --- |
+ 1 | 1 | 1 | acute | Euro | dotaccent | --- |
+ 2 | 2 | 2 | circumflex | --- | fi | --- |
+ 3 | 3 | 3 | tilde | --- | fl | --- |
+ 4 | 4 | 4 | dieresis | fraction | fraction | --- |
+ 5 | 5 | 5 | hungarumlaut | dotaccent | hungarumlaut | --- |
+ ...
+---
+Author:: Patrick Gundlach <patrick@gundla.ch>
+=end
+
+# :enddoc:
+
+require 'rfil/tex/enc'
+require 'rfil/tex/kpathsea'
+
+include RFIL
+include TeX
+
+unless ARGV.size > 0
+ puts "Usage: #{File.basename($0)} encoding[.enc] ..."
+ exit
+end
+
+fmt=" %-16.16s |"
+
+encodings=[]
+kpse=Kpathsea.new
+ARGV.each { |e|
+ kpse.open_file(e.chomp('.enc')+'.enc','enc') { |f|
+ encodings.push(ENC.new(f))
+ }
+}
+
+
+print "dec | oct |hex |"
+encodings.each { |e| print sprintf(fmt,e.encname) }
+
+
+0.upto(255) { |slot|
+ print "\n"+"-"*(16 + encodings.size * 19 ) if slot % 32 == 0
+
+ print sprintf("\n%3d | %3o | %2x |", slot,slot,slot)
+ encodings.each { |e|
+ print sprintf(fmt, e[slot]==".notdef" ? "---" : e[slot])
+ }
+}
+puts
diff --git a/support/rfil/examples/pldiff b/support/rfil/examples/pldiff
new file mode 100755
index 0000000000..0cad686667
--- /dev/null
+++ b/support/rfil/examples/pldiff
@@ -0,0 +1,297 @@
+#!/usr/bin/env ruby
+#--
+# Last Change: Tue May 16 18:13:36 2006
+#++
+=begin rdoc
+
+== pldiff -- show the differences between two (v)pl files.
+
+ Usage: pldiff [options] file file
+ file can be tfm, pl, vpl or vf files.
+ -d, --delta DELTA Don't report differences whithin +/- DELTA percent
+ -c, --ignore-comments ignore comments
+ -k, --ignore-kern ignore difference in kerning information
+ -m, --mapenc ENC assume encoding ENC for destination encoding
+ -t, --texenc ENC assume encoding ENC for source encoding (TeX side)
+ -e, --encoding ENC assume encoding ENC for both in and out
+ -s, --skip-characters only look at fontdimen and main data
+
+ -h, --help Show this help
+
+
+---
+Author:: Patrick Gundlach <patrick@gundla.ch>
+License:: Copyright (c) 2005 Patrick Gundlach.
+ Released under the terms of the GNU General Public License
+
+=end
+
+# :enddoc:
+
+require 'optparse'
+require 'ostruct'
+
+require 'rfil/tex/kpathsea'
+require 'rfil/tex/enc'
+require 'rfil/tex/tfm'
+require 'rfil/tex/vf'
+
+include RFIL
+
+
+def showmap(mapary)
+ str = ""
+ if mapary
+ mapary.each { |entry|
+ str << " | " << entry.join(" ") << "\n"
+ }
+ end
+ str
+end
+
+def plopen(filename)
+ case filename
+ when /\.tfm$/
+ return TFM.new.read_tfm(filename)
+ when /\.vf$/
+ # change to that dir first
+ currentdir=Dir.getwd
+ dirname=File.dirname(filename)
+ Dir.chdir(dirname)
+ fn=File.basename(filename)
+ vf=VF.new.read_vf(filename)
+ Dir.chdir(currentdir)
+ return vf
+ when /\.pl$/
+ return TFM.new.read_pl(filename)
+ when /\.vpl$/
+ return TFM.new.read_pl(filename)
+ else
+ puts "Unknown format: #{filename}"
+ exit 1
+ end
+end
+
+include TeX
+options=OpenStruct.new
+kpse=Kpathsea.new
+
+ARGV.options { |opts|
+ opts.banner = "Usage: #{File.basename($0)} [options] file file"
+ opts.separator "file can be tfm, pl, vpl or vf files."
+
+ opts.on("--delta","-d DELTA", Float,
+ "Don't report differences whithin +/- DELTA percent") { |d|
+ options.delta=d
+ }
+ opts.on("--ignore-comments", "-c", "ignore comments") { |i|
+ options.ignore_comments=true
+ }
+ opts.on("--ignore-kern", "-k", "ignore difference in kerning information") { |k|
+ options.ignore_kern=true
+ }
+
+ opts.on("--mapenc", "-m ENC",
+ "assume encoding ENC for destination encoding") {|e|
+ options.mapencoding=e
+ }
+
+ opts.on("--texenc", "-t ENC",
+ "assume encoding ENC for source encoding (TeX side)") {|e|
+ options.texencoding=e
+ }
+
+ opts.on("--encoding", "-e ENC",
+ "assume encoding ENC for both in and out") {|e|
+ options.encoding=e
+ }
+ opts.on("--skip-characters", "-s", "only look at fontdimen and main data") {|s|
+ options.skip=true
+ }
+ opts.on_tail("--help", "-h", "Show this help") { puts opts; exit 0 }
+ opts.separator ""
+ opts.parse!
+}
+
+# untested:
+if options.encoding
+ kpse.open_file(options.encoding,"enc") { |f|
+ options.encoding = ENC.new(f)
+ }
+ options.mapencoding=options.encoding
+ options.texencoding=options.encoding
+end
+
+if options.mapencoding.instance_of?(String)
+ kpse.open_file(options.mapencoding,"enc") { |f|
+ options.mapencoding = ENC.new(f)
+ }
+end
+
+if options.texencoding.instance_of?(String)
+ kpse.open_file(options.texencoding,"enc") { |f|
+ options.texencoding = ENC.new(f)
+ }
+end
+
+if ARGV.size != 2
+ puts "#{File.basename($0)}: Need exactly two file arguments."
+ puts "Try `#{File.basename($0)} --help' for more information."
+ exit 0
+end
+
+
+p1 = plopen(ARGV[0])
+p2 = plopen(ARGV[1])
+
+percent = options.delta ? options.delta/50.0 : 0
+
+[:fontfamily,:codingscheme,:designsize].each { |sym|
+ if p1.send(sym) != p2.send(sym)
+ puts "#{sym} differ: #{p1.send(sym)} vs #{p2.send(sym)}"
+ end
+}
+
+
+fd1 = p1.params
+fd2 = p2.params
+str = ""
+if fd1.size != fd2.size
+ str << "Difference in number of parameters (fontdimen)"
+end
+
+paramname=%w( X SLANT SPACE STRETCH SHRINK XHEIGHT QUAD EXTRASPACE )
+if p1.codingscheme=="TeX math symbols"
+ paramname += %w(NUM1 NUM2 NUM3 DENOM1 DENOM2 SUP1 SUP2 SUP3
+ SUB1 SUB2 SUPDROP)
+elsif p1.codingscheme=="TeX math extension"
+ paramname += %w(DEFAULT_RULE_THICKNESS BIG_OP_SPACING1
+ BIG_OP_SPACING2 BIG_OP_SPACING3 BIG_OP_SPACING4 BIG_OP_SPACING5)
+end
+
+for i in 1..fd1.size
+ next if fd1[i] == fd2[i]
+ if fd1[i]==nil
+ str << "Difference in #{paramname[i]}: nil vs. #{fd2[i]}" << "\n"
+ elsif
+ fd2[i]==nil
+ str << "Difference in #{paramname[i]}: #{fd1[i]} vs. nil" << "\n"
+ elsif (fd1[i] - fd2[i] ).abs > fd1[i] * percent
+ str << "Difference in #{paramname[i]}: #{fd1[i]} vs. #{fd2[i]}" << "\n"
+ end
+end
+
+if str.size > 0
+ puts "--------------------"
+ puts "fondimen difference:"
+ puts str
+ puts "--------------------"
+end
+
+exit if options.skip==true
+str= ""
+0.upto(255) do |i|
+ a=p1.chars[i]
+ b=p2.chars[i]
+ next unless a and b
+ l1=a[:lig_kern] ? p1.lig_kern[a[:lig_kern]] : nil
+ l2=b[:lig_kern] ? p2.lig_kern[b[:lig_kern]] : nil
+
+ next if a==b and l1==l2
+
+ if a==nil
+ str << "#{i}: no character at this slot in font 1" << "\n"
+ elsif b==nil
+ str << "#{i}: no character at this slot in font 2" << "\n"
+ else
+ chr=""
+ [:charwd, :charht, :chardp, :charic].each { |dim|
+ next if a[dim].to_f==b[dim].to_f
+ if a[dim]==nil
+ chr << " Difference in #{dim}: nil vs. #{b[dim]}" << "\n"
+ elsif b[dim]==nil
+ chr << " Difference in #{dim}: #{b[dim]} vs. nil" << "\n"
+ elsif (a[dim] - b[dim]).abs > a[dim] * percent
+ chr << " Difference in #{dim}: #{a[dim]} vs. #{b[dim]}" << "\n"
+ end
+ }
+ if l1 != l2 and options.ignore_kern != true
+ chr << " Difference in kern information" << "\n"
+ if l1==nil
+ str << " no lig/kern information for first font \n"
+ elsif l2==nil
+ str << " no lig/kern information for second font \n"
+ else
+ chr << " in font1 but not in font 2:" << (l1 - l2).join(" ").to_s << "\n"
+ chr << " in font2 but not in font 1:" << (l2 - l1).join(" ").to_s << "\n"
+ end
+ end
+
+# if a[:ligkern] and b[:ligkern]
+# if a[:ligkern][:lig] != b[:ligkern][:lig]
+# chr << " Difference in lig information" << "\n"
+# if a[:ligkern][:lig]
+# a[:ligkern][:lig].each { |lig|
+# chr << " | " << lig.inspect << "\n"
+# }
+# else
+# chr << "nil"
+# end
+# chr << " vs.\n"
+# if b[:ligkern][:lig]
+# b[:ligkern][:lig].each { |lig|
+# chr << " | " << lig.inspect << "\n"
+# }
+# else
+# chr << "nil"
+# end
+# end
+# if a[:ligkern][:krn]
+# (a[:ligkern][:krn] - b[:ligkern][:krn]).each { |lig|
+# if options.mapencoding
+# chr << " | [#{options.mapencoding[lig[0]]} #{lig[1]}]\n"
+# else
+# chr << " | " << lig.inspect << "\n"
+# end
+# }
+# else
+# chr << "nil"
+# end
+# chr << " vs.\n"
+# if b[:ligkern][:krn]
+# (b[:ligkern][:krn] - a[:ligkern][:krn]).each { |lig|
+# if options.mapencoding
+# chr << " | [#{options.mapencoding[lig[0]]} #{lig[1]}]\n"
+# else
+# chr << " | " << lig.inspect << "\n"
+# end
+# }
+# else
+# chr << "nil"
+# end
+ #end
+# end
+ if a[:dvi] != b[:dvi]
+ chr << " Difference in map\n"
+ chr << showmap(a[:map])
+ chr << " vs.\n"
+ chr << showmap(b[:map])
+ end
+
+ if chr.length > 0
+ str << "#{i}: "
+ if options.texencoding
+ str << options.texencoding[i]
+ end
+ str << "\n"
+ str << chr
+ end
+ end
+end
+if str.length > 0
+ puts "Character entries:"
+ puts "------------------"
+ puts str
+end
+
+
diff --git a/support/rfil/examples/plinfo b/support/rfil/examples/plinfo
new file mode 100755
index 0000000000..1ceda6c5cb
--- /dev/null
+++ b/support/rfil/examples/plinfo
@@ -0,0 +1,109 @@
+#!/usr/bin/env ruby
+#--
+# Last Change: Tue May 16 18:14:38 2006
+#++
+=begin rdoc
+== plinfo -- output information about a pl file.
+
+ Usage: plinfo [options] tfmfile.pl [file...]
+ -e, --encoding enc set the encoding for the file
+ -l, --list-chars list all available characters
+ -h, --help Show this help
+
+
+---
+Author:: Patrick Gundlach <patrick@gundla.ch>
+License:: Copyright (c) 2005 Patrick Gundlach.
+ Released under the terms of the GNU General Public License
+=end
+
+
+# :enddoc:
+
+require 'optparse'
+require 'ostruct'
+
+require 'rfil/tex/tfm'
+require 'rfil/tex/kpathsea'
+require 'rfil/tex/enc'
+
+include RFIL
+include TeX
+
+kpse=Kpathsea.new
+
+@options=OpenStruct.new
+
+ARGV.options { |opt|
+ opt.banner = "Usage: #{File.basename($0)} [options] tfmfile.pl [file...]"
+ opt.on("--encoding enc", "-e", "set the encoding for the file") { |e|
+ kpse.open_file(e,"enc") { |f|
+ @options.encoding = ENC.new(f)
+ }
+ }
+ opt.on("--list-chars", "-l", "list all available characters") {
+ @options.listchars=true }
+ opt.on("--help", "-h", "Show this help") { puts opt; exit 0 }
+ opt.separator ""
+ opt.parse!
+}
+
+if ARGV.size < 1
+ puts "#{File.basename($0)}: Need at least one file argument."
+ puts "Try `#{File.basename($0)} --help' for more information."
+ exit 0
+end
+
+
+def dump_maininfo(filename)
+ puts "General font information:"
+ puts "========================="
+ print "filename=#{File.basename(filename)} "
+ # puts @isvpl ? "(vpl)" : "(pl)"
+ puts "Family: #{@tfm.fontfamily}"
+ puts "Designsize: #{@tfm.designsize}"
+ puts "Codingscheme: #{@tfm.codingscheme}"
+ puts "Fontdimen:"
+ paramname=%w( SLANT SPACE STRETCH SHRINK XHEIGHT QUAD EXTRASPACE )
+ if @tfm.codingscheme=="TeX math symbols"
+ paramname += %w(NUM1 NUM2 NUM3 DENOM1 DENOM2 SUP1 SUP2 SUP3
+ SUB1 SUB2 SUPDROP)
+ elsif @tfm.codingscheme=="TeX math extension"
+ paramname += %w(DEFAULT_RULE_THICKNESS BIG_OP_SPACING1
+ BIG_OP_SPACING2 BIG_OP_SPACING3 BIG_OP_SPACING4 BIG_OP_SPACING5)
+ end
+
+ (1..@tfm.params.size-1).each {|i|
+ puts " #{paramname[i-1]} = #{@tfm.params[i]}"
+ }
+end
+
+def dump_charsinfo
+ stdformat="%9s|"
+ count=0
+ 0.upto(255) { |i|
+ if c=@tfm.chars[i]
+ if count % 32 == 0
+ puts "\n slot| width | height | depth | ic |lig/kern?| extra | char"
+ puts "-----|---------|---------|---------|---------|---------|---------|-------"
+ end
+
+ has_krn= c[:lig_kern] ? "yes" : ""
+ extra = ""
+ char = @options.encoding ? @options.encoding[i] : ""
+ puts sprintf("%5s|"+stdformat*6+" %s", "#{i}","#{c[:charwd]}","#{c[:charht]}","#{c[:chardp]}","#{c[:charic]}", has_krn,"",char)
+ count += 1
+
+ end
+
+ }
+end
+
+ARGV.each { |plfilename|
+ @tfm=TFM.new()
+ @tfm.read_pl(plfilename)
+ dump_maininfo(plfilename)
+ if @options.listchars
+ dump_charsinfo
+ end
+}
diff --git a/support/rfil/examples/rfii b/support/rfil/examples/rfii
new file mode 100755
index 0000000000..2e80a2ef86
--- /dev/null
+++ b/support/rfil/examples/rfii
@@ -0,0 +1,257 @@
+#!/usr/bin/env ruby
+
+# :enddoc:
+
+require 'pp'
+require 'ostruct'
+require 'fileutils'
+
+
+require 'rfil/fontcollection'
+require 'rfil/tex/kpathsea'
+
+$:.unshift File.dirname($0)
+require 'rfii.tab'
+
+
+class RFII # :nodoc:
+ include RFIL
+ include TeX
+
+ def initialize
+ @instructions=[]
+ @known_encodings=Hash.new
+ @fontset=nil
+ @kpse=Kpathsea.new
+ @known_outputfiles=[:vf,:sty,:tfm,:typescript,:fd,:map]
+ @fontfiles_copied=nil
+ @vendor=nil
+ @texencodings=[]
+ @psencoding=[]
+ @fontroot=File.expand_path(Dir.pwd)
+ @options=OpenStruct.new
+ @options.verbose=false
+ @options.dryrun=false
+ @options.tds=true
+ @fc=nil
+ end
+
+ def parse_file(filename)
+ f=File.open(filename)
+ @s=StringScanner.new(f.read)
+ f.close
+ @mode=:normal
+ @line=1
+ yyparse(self,:scan)
+ end
+
+ def on_error(error_token_id,error_value,value_stack)
+ # puts "error"
+ error=token_to_str(error_token_id)
+ p error_value,value_stack
+ puts "parse error near line #@line, exiting, next string: '#{error_value}#{@s.rest[0..20]}...'"
+ exit 1
+ # the default action would be:
+ # raise ParseError
+ end
+
+ def ensure_encoding(enc)
+ unless @known_encodings.has_key?(enc)
+ puts "Unknown encoding #{enc} in line #{@line}"
+ exit 1
+ end
+ end
+
+ def get_encodings(symbols)
+ symbols.collect { |encoding|
+ ensure_encoding(encoding)
+ @known_encodings[encoding]
+ }
+ end
+ def get_encoding(symbol)
+ return :none if symbol==:none or symbol==:same_as_texencoding
+ ensure_encoding(symbol)
+ @known_encodings[symbol]
+ end
+
+ def get_fonts(ident)
+ towrite=[]
+ case ident
+ when [:all],nil
+ towrite=@fontset.keys
+ else
+ towrite=ident
+ end
+ fontlist=[]
+ towrite.each{ |font|
+ if @fontset.has_key?(font)
+ fontlist << @fontset[font]
+ else
+ puts "Font for #{ident} in line #{@line} unknown, ignoring"
+ end
+ }
+ fontlist
+ end
+ def run_instructions
+ @instructions.each { |line,i|
+ @line=line
+ instr,*rest=i
+ case instr
+ when :useencoding
+ # this should be in parser:
+ if rest[1]==:none or rest[1]==:same_as_texencoding
+ puts "invalid encoding name"
+ exit 1
+ end
+ @kpse.open_file(rest[0],"enc") { |encfile|
+ @known_encodings[rest[1]]=ENC.new(encfile)
+ }
+ when :psencoding
+ @psencoding=get_encoding(rest[0])
+ when :texencoding
+ @texencodings=get_encodings(rest[0])
+ when :fontroot
+ @fontroot=File.expand_path(rest[0])
+ unless File.exists?(@fontroot) and File.directory?(@fontroot)
+ puts "fontroot (#{@fontroot})is not a valid directory"
+ exit 1
+ end
+ when :fontsource
+ @fontsource=File.expand_path(rest[0])
+ unless File.exists?(@fontsource) and File.directory?(@fontsource)
+ puts "fontsource (#{@fontsource})is not a valid directory"
+ exit 1
+ end
+ when :newfont
+ @fontset={}
+ @fontfiles_copied={}
+ @fc=RFI::FontCollection.new
+ @fc.options[:dryrun]=@options.dryrun
+ @fc.options[:verbose]=@options.verbose
+ @fc.vendor=@vendor
+ @fc.name=rest[0]
+ @fc.set_dirs({:base=>@fontroot, :tds=>@options.tds})
+ @fc.mapenc=@psencoding
+ @fc.texenc=@texencodings
+ @fc.style=rest[1]
+ when :useafm
+ fontfilename=rest[0]
+ ident=rest[1]
+ srcpath=File.join(@fontsource,fontfilename)
+ unless @fontfiles_copied.has_key?(fontfilename) and @options.copyfonts
+ @fontfiles_copied[fontfilename]=true # dummy value, used as Set
+
+ if @options.verbose
+ puts "copy #{srcpath} to #{@fc.dirs[:afm]}"
+ end
+ unless @options.dryrun
+ @fc.ensure_dir(@fc.dirs[:afm])
+ FileUtils.cp(srcpath,@fc.dirs[:afm])
+ end
+ if @options.verbose
+ puts "copy #{srcpath.chomp(".afm")}.pfb to #{@fc.dirs[:type1]}"
+ end
+ unless @options.dryrun
+ @fc.ensure_dir(@fc.dirs[:type1])
+ FileUtils.cp(srcpath.chomp(".afm")+".pfb",@fc.dirs[:type1])
+ end
+ end
+ f=RFI::Font.new(@fc)
+ i=f.load_variant(File.join(@fontsource,fontfilename))
+ @fontset[ident]=f
+ case ident
+ when :italic
+ f.variant=:italic
+ when :slanted
+ f.variant=:slanted
+ when :bold
+ f.weight=:bold
+ when :bolditalic
+ f.variant=:italic
+ f.weight=:bold
+ when :boldslanted
+ f.variant=:slanted
+ f.weight=:bold
+ when :smallcaps
+ f.variant=:smallcaps
+ end
+ when :write
+ # p rest
+ texencodings = if rest[2]
+ get_encodings(rest[2])
+ else
+ @texencodings
+ end
+
+ psencoding = rest[3] ? get_encoding(rest[3]) : @psencoding
+ rest[0].each { |filetype|
+ case filetype
+ when :vf
+ get_fonts(rest[1]).each { |font|
+ font.texenc=texencodings
+ font.mapenc=psencoding
+ font.write_files({:mapfile=>false})
+ }
+ when :map
+ m = get_fonts(rest[1]).collect { |font|
+ font.texenc=texencodings
+ font.mapenc=psencoding
+ font.maplines
+ }
+ mapdir=@fc.get_dir(:map); @fc.ensure_dir(mapdir)
+ mapfilename=File.join(mapdir,@fc.name+".map")
+ if @options.verbose
+ puts "writing mapfile to #{mapfilename}"
+ end
+ unless @options.dryrun
+ File.open(mapfilename, "w") {|file|
+ file.puts m
+ }
+ end
+ when :fd
+ @fc.run_temps(:latex)
+ when :typescript
+ @fc.run_temps(:context)
+ else
+ puts "unknown filetype: #{filetype}, ignoring"
+ end
+ }
+ when :vendor
+ @vendor=rest[0]
+ if @fc and @fc.respond_to?(:vendor=)
+ @fc.vendor=@vendor
+ end
+ when :set
+ kw,values=rest
+ case kw
+ when :verbose,:dryrun,:tds,:copyfonts
+ if [:true,:false].member?(values)
+ @options.send(kw.to_s+"=",values==:true)
+ else
+ puts "Warning: unkown value for '#{kw}' in line #{@line}, must be one of 'true' or 'false'"
+ end
+ end
+ when :apply
+ instr=rest[0]
+ case instr
+ when :slant
+ font=rest[1]
+ # p @fontset.has_key?(font)
+ @fontset[font].slant=0.167
+ else
+ puts "Unknown instruction (#{instr}) for apply in line #{@line}. Exiting."
+ end
+ else
+ puts "Unknown instruction (#{instr}) in line #{@line}. Exiting."
+ exit 1
+ end
+ }
+ # p @psencoding
+ # p @texencodings
+ # pp @fc
+ end
+end
+
+parser = RFII.new
+parser.parse_file("test/inputfile")
+parser.run_instructions
diff --git a/support/rfil/examples/rfont b/support/rfil/examples/rfont
new file mode 100755
index 0000000000..a49b667053
--- /dev/null
+++ b/support/rfil/examples/rfont
@@ -0,0 +1,185 @@
+#!/usr/bin/env ruby
+#--
+# Last Change: Tue May 16 21:01:40 2006
+#++
+=begin rdoc
+= rfont -- An example font installer
+
+rfont uses the RFI Library for installing a family of fonts.
+
+== Command line parameters
+Usage: rfont [options] vendor/fontname FILE1 FILE2 ...
+ -c, --copy-fonts Also copy the font outlines
+ -d, --directory DIR Set base directory to DIR
+ --dry-run dry run, don't create any files
+ -m, --list-plugin list available macro support methods
+ -p ENCFILE read/download ENCFILE for the PostScript encoding
+ -s, --style STYLE Style of the font, eg. sans, roman, typewriter
+ --tds Put files in a TDS compliant directory hierarchy
+ -t ENCFILE read ENCFILE for the encoding of the vf file
+ multiple encodings can be given (seperated by ',')
+ -T ENCFILE equivalent to -p ENCFILE -t ENCFILE
+ -u, --use-plugin PLUGIN use plugin files PLUGIN, multiple files seperated by ','
+ -v, --no-vf Do not create virtual fonts for reencoding
+ --verbose Print more then needed on stdout
+ --help print this message and exit.
+ --version print version number and exit.
+
+== Example usage
+This is the command line I used to install the Bitstream variant of the font 'Syntax' (from the Corel Draw CD)
+
+ ./rfont bitstream/syntax ../corel/hum531*afm -t ec,ts1 -p 8r -d ~/rfitexmf/ -u latex -s sans --verbose --tds -c
+
+It works, but the <tt>.fd</tt>-file is not perfect yet.
+---
+Author:: Patrick Gundlach <patrick@gundla.ch>
+License:: Copyright (c) 2005 Patrick Gundlach.
+ Released under the terms of the GNU General Public License
+
+=end
+
+# :enddoc:
+
+require 'optparse'
+require 'ostruct'
+require 'fileutils'
+
+require 'rfil/fontcollection'
+
+include RFIL
+
+options=OpenStruct.new
+optionswritevf=true
+fc=RFI::FontCollection.new
+
+ret= ARGV.options { |opts|
+ opts.banner = "Usage: #{File.basename($0)} [options] vendor/fontname FILE1 FILE2 ..."
+ opts.on("-c", "--copy-fonts", "Also copy the font outlines") {
+ options.copyfonts=true
+ }
+
+ opts.on("-d DIR", "--directory", "Set base directory to DIR") { |d|
+ fc.set_dirs(d)
+ }
+ opts.on("--dry-run", "dry run, don't create any files") {
+ fc.options[:dryrun]=true
+ options.dryrun=true
+ }
+ opts.on("-m", "--list-plugin", "list available plugins") {
+ puts "The following plugins are known:"
+ puts fc.plugins
+ exit 0;
+ }
+ opts.on("-p ENCFILE", String,
+ "read/download ENCFILE for the PostScript encoding") {|e|
+ fc.mapenc = e
+ }
+ opts.on("-s STYLE", "--style", String, "Style of the font, eg. sans, roman, typewriter") { |s|
+ fc.style=s.to_sym
+ }
+ opts.on("--tds", "Put files in a TDS compliant directory hierarchy") {
+ options.tds=true
+ }
+ opts.on("-t ENCFILE",Array, "read ENCFILE for the encoding of the vf file",
+ "multiple encodings can be given (seperated by ',')") {|e|
+ fc.texenc = e
+ }
+ opts.on("-T ENCFILE",String,"equivalent to -p ENCFILE -t ENCFILE") {|e|
+ fc.mapenc = e
+ fc.texenc = e
+ }
+ opts.on("-u PLUGIN","--use-plugin",Array, "use plugin PLUGIN, multiple files seperated by ','") { |m|
+ options.plugin=m
+ }
+ opts.on("-v", "--no-vf", "Do not create virtual fonts for reencoding") {
+ fc.write_vf=false
+ }
+ opts.on("--verbose","Print more then needed on stdout") {
+ options.verbose=true
+ fc.options[:verbose]=true
+ }
+ opts.on_tail("--help","print this message and exit.") { puts opts; exit 0 }
+ opts.on_tail("--version","print version number and exit.") {
+ puts "#{File.basename($0)}: Version 0.1"
+ exit 0
+ }
+ opts.parse!
+}
+unless ret
+ puts "See --help for usage information"
+ exit(-1)
+end
+
+
+vendor_fontname=ARGV.shift
+
+if vendor_fontname
+ options.vendor,options.fontname=vendor_fontname.split('/')
+end
+if options.vendor==nil or options.fontname==nil
+ puts "You must name vendor and fontname this way: vendor/fontname"
+ puts "See --help for usage information"
+ exit(-1)
+end
+
+
+
+fc.name=options.fontname
+fc.vendor=options.vendor
+
+fc.set_dirs(:tds=>true) if options.tds
+
+fonts=[]
+maplines=""
+
+
+fontoutlinedir=File.dirname(ARGV[0])
+
+ARGV.each { |fontname|
+ # puts "reading font #{File.basename(fontname)}"
+ f=RFI::Font.new(fc)
+ f.load_variant(fontname)
+ fonts.push f
+}
+
+fc.fonts.each { |font|
+ puts "Processing font #{font.defaultfm.fontname}"
+ font.guess_weight_variant
+ font.apply_ligkern_instructions(RFI::STDLIGKERN)
+ font.write_files(:dryrun=>options.dryrun==true,
+ :verbose=>false, :mapfile=>false
+ )
+ maplines << font.maplines.to_s
+}
+
+
+if options.copyfonts
+ fc.fonts.each { |font|
+ font.find_used_fonts.each {|varnumber|
+ fontmetric=font.variants[varnumber]
+ destdir=font.get_dir(fontmetric.outlinetype)
+ sourcefile=File.join(fontoutlinedir,fontmetric.fontfilename)
+ destfile=File.join(destdir,fontmetric.fontfilename)
+ puts "Copying #{sourcefile} to #{destfile}" if options.verbose
+ fc.ensure_dir(destdir)
+ unless options.dryrun
+ FileUtils.cp(sourcefile,destfile)
+ end
+ }
+ }
+end
+
+mapdir=fc.get_dir(:map)
+mapfile=File.join(mapdir,options.fontname)
+puts "Writing mapfile #{mapfile}" if options.verbose
+unless fc.options[:dryrun]
+ fc.ensure_dir(mapdir)
+ File.open(mapfile + ".map", "w") { |f|
+ f << maplines
+ }
+end
+
+if options.plugin
+ options.plugin.each { |m| fc.run_plugin(m.to_sym) }
+end
+