rfil 0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/COPYING +340 -0
- data/README +77 -0
- data/examples/afm2tfm.rb +204 -0
- data/examples/afminfo +305 -0
- data/examples/encodingtable +65 -0
- data/examples/pldiff +295 -0
- data/examples/plinfo +108 -0
- data/examples/rfii +257 -0
- data/examples/rfont +188 -0
- data/lib/rfil/font.rb +722 -0
- data/lib/rfil/font/afm.rb +414 -0
- data/lib/rfil/font/glyph.rb +198 -0
- data/lib/rfil/font/metric.rb +135 -0
- data/lib/rfil/font/truetype.rb +35 -0
- data/lib/rfil/fontcollection.rb +182 -0
- data/lib/rfil/helper.rb +155 -0
- data/lib/rfil/rfi.rb +472 -0
- data/lib/rfil/rfi_plugin_context.rb +90 -0
- data/lib/rfil/rfi_plugin_latex.rb +95 -0
- data/lib/rfil/version.rb +3 -0
- data/lib/tex/enc.rb +223 -0
- data/lib/tex/kpathsea.rb +63 -0
- data/lib/tex/tfm.rb +1198 -0
- data/lib/tex/vf.rb +846 -0
- metadata +86 -0
@@ -0,0 +1,135 @@
|
|
1
|
+
# font/metric.rb - superclass for different font metric formats
|
2
|
+
# Last Change: Mi 24 Mai 2006 16:13:14 CEST
|
3
|
+
|
4
|
+
require 'rfil/font/glyph'
|
5
|
+
#require 'font/afm'
|
6
|
+
#require 'font/truetype'
|
7
|
+
|
8
|
+
module RFIL
|
9
|
+
module Font
|
10
|
+
# FontMetric is the superclass for font metrics. All information that
|
11
|
+
# is not specific to a certain kind of file format is accessible via
|
12
|
+
# this class.
|
13
|
+
|
14
|
+
class Metric
|
15
|
+
# to make Rdoc and Ruby happy: [ruby-talk:147778]
|
16
|
+
def self.documented_as_accessor(*args) # :nodoc:
|
17
|
+
end
|
18
|
+
def self.documented_as_reader(*args) # :nodoc:
|
19
|
+
end
|
20
|
+
|
21
|
+
# :type1, :truetype
|
22
|
+
attr_accessor :outlinetype
|
23
|
+
|
24
|
+
# Hash of glyphs in the font.
|
25
|
+
attr_accessor :chars
|
26
|
+
|
27
|
+
# The filename of the just read metric file. Does not contain the
|
28
|
+
# path. To set, change the pathname
|
29
|
+
documented_as_reader :filename
|
30
|
+
|
31
|
+
# Absolute pathname of the metric file. Not checked when set.
|
32
|
+
attr_accessor :pathname
|
33
|
+
|
34
|
+
# File name of the font containing the outlines (the file that needs
|
35
|
+
# to be put into the pdf-file). The .tt or the .pfb file. If unset
|
36
|
+
# use the value of filename, but changed to the correct extension in
|
37
|
+
# case of Type 1 fonts.
|
38
|
+
documented_as_accessor :fontfilename
|
39
|
+
|
40
|
+
# Some unique name of the font. Use the filename of the font or a
|
41
|
+
# name after the KB naming schema. Do not add an extension such as
|
42
|
+
# afm or tt.
|
43
|
+
attr_accessor :name
|
44
|
+
|
45
|
+
# family name of the font
|
46
|
+
attr_accessor :familyname
|
47
|
+
|
48
|
+
# xheight in 1/1000 of an em
|
49
|
+
attr_accessor :xheight
|
50
|
+
|
51
|
+
attr_accessor :weight
|
52
|
+
|
53
|
+
# natural width of a space
|
54
|
+
documented_as_reader :space
|
55
|
+
|
56
|
+
attr_accessor :italicangle
|
57
|
+
|
58
|
+
# True if the font is a monospaced font (courier for example).
|
59
|
+
attr_accessor :isfixedpitch
|
60
|
+
|
61
|
+
# The official name of the font as supplied by the vendor. Written
|
62
|
+
# as FontName in the afm file.
|
63
|
+
attr_accessor :fontname
|
64
|
+
|
65
|
+
# The full name of the font, whatever this means. Written as
|
66
|
+
# FullName in the afm file.
|
67
|
+
attr_accessor :fullname
|
68
|
+
|
69
|
+
# Class for new glyphs. Default is Glyph
|
70
|
+
attr_accessor :glyph_class
|
71
|
+
|
72
|
+
def Metric.read(filename,options={})
|
73
|
+
case File.extname(filename)
|
74
|
+
when ".afm"
|
75
|
+
require 'rfil/font/afm'
|
76
|
+
return AFM.new(options).read(filename)
|
77
|
+
when ".ttf"
|
78
|
+
require 'rfil/font/truetype'
|
79
|
+
return TrueType.new(options).read(filename)
|
80
|
+
else
|
81
|
+
raise ArgumentError, "Unknown filetype: #{File.basename(filename)}"
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def initialize
|
86
|
+
@chars=Hash.new
|
87
|
+
@xheight=nil
|
88
|
+
@glyph_class=Glyph
|
89
|
+
@outlinetype=nil
|
90
|
+
@info={}
|
91
|
+
@fontfilename=nil
|
92
|
+
@efactor=1.0
|
93
|
+
@slantfactor=0.0
|
94
|
+
@pathname=nil
|
95
|
+
end
|
96
|
+
|
97
|
+
# Factory for new glyphs. Return new instance of glyph_class (see
|
98
|
+
# Attributes).
|
99
|
+
def new_glyph
|
100
|
+
@glyph_class.new
|
101
|
+
end
|
102
|
+
|
103
|
+
|
104
|
+
def space # :nodoc:
|
105
|
+
chars['space'].wx
|
106
|
+
end
|
107
|
+
|
108
|
+
def filename # :nodoc:
|
109
|
+
File.basename(@pathname)
|
110
|
+
end
|
111
|
+
|
112
|
+
def fontfilename= (obj) # :nodoc:
|
113
|
+
@fontfilename=obj
|
114
|
+
end
|
115
|
+
|
116
|
+
# This one is documented in the 'attributes' section. If the global
|
117
|
+
# variable is unset, just use @filename, perhaps change afm to pfb
|
118
|
+
def fontfilename # :nodoc:
|
119
|
+
return @fontfilename if @fontfilename
|
120
|
+
case filename
|
121
|
+
when /\.afm$/
|
122
|
+
return filename.chomp(".afm") + ".pfb"
|
123
|
+
when /\.tt$/
|
124
|
+
return filename
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
# Return all relevant part of pyhsical font. May be used for
|
129
|
+
# copying all files.
|
130
|
+
def fontfilenames
|
131
|
+
raise ScriptError, "not implemented"
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# truetype.rb -- read truetype font metrics
|
2
|
+
#--
|
3
|
+
# Last Change: Mi 24 Mai 2006 16:42:47 CEST
|
4
|
+
#++
|
5
|
+
|
6
|
+
require 'rfil/font/afm'
|
7
|
+
|
8
|
+
module RFIL
|
9
|
+
module Font
|
10
|
+
# Read TrueType fonts. Use like the AFM class.
|
11
|
+
class TrueType < AFM
|
12
|
+
def initialize(options={})
|
13
|
+
super
|
14
|
+
@outlinetype=:truetype
|
15
|
+
end
|
16
|
+
|
17
|
+
# all relevant filenames of the font
|
18
|
+
def fontfilenames
|
19
|
+
return {:truetype => File.basename( @fontfilename || filename) }
|
20
|
+
end
|
21
|
+
|
22
|
+
def read(filename)
|
23
|
+
@filename=File.basename(filename)
|
24
|
+
@fontfilename=filename
|
25
|
+
@name=@filename.chomp(".ttf")
|
26
|
+
self.pathname=Pathname.new(filename).realpath.to_s
|
27
|
+
a=`ttf2afm #{@fontfilename}`
|
28
|
+
parse(a)
|
29
|
+
# ttf2afm does not give an xheight!?
|
30
|
+
@xheight=@chars['x'].ury unless @xheight
|
31
|
+
self
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,182 @@
|
|
1
|
+
#--
|
2
|
+
# fontcollection.rb
|
3
|
+
# Last Change: Tue May 16 19:02:11 2006
|
4
|
+
#++
|
5
|
+
|
6
|
+
require 'rfil/rfi'
|
7
|
+
require 'rfil/font'
|
8
|
+
require 'rfil/helper'
|
9
|
+
|
10
|
+
module RFIL # :nodoc:
|
11
|
+
class RFI
|
12
|
+
# A set of fonts (regular,bold,italic). Used to write an fd-file for
|
13
|
+
# LaTeX or a typescript for ConTeXt. Register different fonts and set
|
14
|
+
# encodings, so you dont't have to specify them in each font.
|
15
|
+
|
16
|
+
class FontCollection
|
17
|
+
include Helper
|
18
|
+
def self.documented_as_accessor(*args) # :nodoc:
|
19
|
+
end
|
20
|
+
def self.documented_as_reader(*args) # :nodoc:
|
21
|
+
end
|
22
|
+
|
23
|
+
attr_accessor :vendor
|
24
|
+
|
25
|
+
# attr_accessor :fontname
|
26
|
+
|
27
|
+
# Name of the font (collection)
|
28
|
+
attr_accessor :name
|
29
|
+
|
30
|
+
# One object or one or more objects in an array that describe the
|
31
|
+
# encoding of the postscript font. Object can either be a string
|
32
|
+
# that represents the filename of the encoding ("8r.enc", "8r") or
|
33
|
+
# an ENC object that already contains the encoding
|
34
|
+
documented_as_accessor :mapenc
|
35
|
+
|
36
|
+
# One object or one ore more objects in an array that describe the
|
37
|
+
# encoding of the font TeX expects. Object can either be a string
|
38
|
+
# that represents the filename of the encoding ("8r.enc", "8r") or
|
39
|
+
# an ENC object that already contains the encoding
|
40
|
+
documented_as_accessor :texenc
|
41
|
+
|
42
|
+
# hash of directories for writing files. Default to current working
|
43
|
+
# directory. The setting in the Font object overrides the setting here.
|
44
|
+
attr_accessor :dirs
|
45
|
+
|
46
|
+
attr_accessor :fonts
|
47
|
+
|
48
|
+
# sans, roman, typewriter
|
49
|
+
attr_accessor :style
|
50
|
+
|
51
|
+
attr_accessor :write_vf
|
52
|
+
|
53
|
+
attr_accessor :options
|
54
|
+
|
55
|
+
# list of temps
|
56
|
+
documented_as_reader :plugins
|
57
|
+
|
58
|
+
def initialize()
|
59
|
+
@kpse=Kpathsea.new
|
60
|
+
@basedir=nil
|
61
|
+
@name=nil
|
62
|
+
@texenc=nil
|
63
|
+
@mapenc=nil
|
64
|
+
@write_vf=true
|
65
|
+
@fonts=[]
|
66
|
+
@options={:verbose=>false,:dryrun=>false}
|
67
|
+
@style=nil
|
68
|
+
@dirs={}
|
69
|
+
@vendor=nil
|
70
|
+
@fontname=nil
|
71
|
+
set_dirs(Dir.getwd)
|
72
|
+
@plugins={}
|
73
|
+
# find temps-plugins
|
74
|
+
$:.each{ |d|
|
75
|
+
a=Dir.glob(d+"/rfil/rfi_plugin_*.rb")
|
76
|
+
a.each{ |f|
|
77
|
+
require f
|
78
|
+
}
|
79
|
+
}
|
80
|
+
ObjectSpace.each_object(Class){ |x|
|
81
|
+
if Plugin > x
|
82
|
+
t = x.new(self)
|
83
|
+
n = t.name
|
84
|
+
if @plugins.has_key?(n)
|
85
|
+
raise "Name already registered"
|
86
|
+
end
|
87
|
+
@plugins[n]=t
|
88
|
+
end
|
89
|
+
}
|
90
|
+
# done initializing plugins
|
91
|
+
end
|
92
|
+
|
93
|
+
# Add a font to the collection. Return the number of the font.
|
94
|
+
def register_font (font)
|
95
|
+
unless font.respond_to?(:maplines)
|
96
|
+
raise ArgumentError, "parameter does not look like a font"
|
97
|
+
end
|
98
|
+
fontnumber=@fonts.size
|
99
|
+
@fonts << font
|
100
|
+
return fontnumber
|
101
|
+
end
|
102
|
+
|
103
|
+
def run_plugin(name)
|
104
|
+
|
105
|
+
raise "don't know plugin #{name}" unless @plugins.has_key?(name)
|
106
|
+
|
107
|
+
# doc for run_plugin
|
108
|
+
# Return the contents of the file that should be used by the TeX
|
109
|
+
# macro package, i.e a typescript for ConTeXt or an fd-file for
|
110
|
+
# Context. Return value is an Array of Hashes. The Hash has three
|
111
|
+
# different keys:
|
112
|
+
# [<tt>:type</tt>] The type of the file, should be either <tt>:fd</tt> or <tt>:typescript</tt>.
|
113
|
+
# [<tt>:filename</tt>] the filename (without a path) of the file
|
114
|
+
# [<tt>:contents</tt>] the contents of the file.
|
115
|
+
|
116
|
+
files=@plugins[name].run_plugin
|
117
|
+
if files.respond_to?(:each)
|
118
|
+
files.each { |fh|
|
119
|
+
dir=get_dir(fh[:type])
|
120
|
+
filename=File.join(dir,fh[:filename])
|
121
|
+
puts "writing file #{filename}" if @options[:verbose]
|
122
|
+
|
123
|
+
unless @options[:dryrun]
|
124
|
+
ensure_dir(dir)
|
125
|
+
File.open(filename,"w") { |f| f << fh[:contents] }
|
126
|
+
end
|
127
|
+
}
|
128
|
+
end
|
129
|
+
end
|
130
|
+
def plugins #:nodoc:
|
131
|
+
@plugins.keys
|
132
|
+
end
|
133
|
+
def mapfile
|
134
|
+
mapfile=[]
|
135
|
+
@fonts.each {|font|
|
136
|
+
mapfile << font.maplines
|
137
|
+
}
|
138
|
+
mapfile.flatten
|
139
|
+
end
|
140
|
+
def mapenc # :nodoc:
|
141
|
+
return nil if @mapenc==:none
|
142
|
+
@mapenc
|
143
|
+
end
|
144
|
+
def mapenc= (enc) # :nodoc:
|
145
|
+
set_mapenc(enc)
|
146
|
+
end
|
147
|
+
def texenc # :nodoc:
|
148
|
+
if @texenc
|
149
|
+
@texenc
|
150
|
+
else
|
151
|
+
# @texenc not set
|
152
|
+
ret=nil
|
153
|
+
@kpse.open_file("8a.enc","enc") { |f|
|
154
|
+
ret = [ENC.new(f)]
|
155
|
+
}
|
156
|
+
return ret
|
157
|
+
end
|
158
|
+
end
|
159
|
+
def texenc= (enc) # :nodoc:
|
160
|
+
@texenc=[]
|
161
|
+
set_encarray(enc,@texenc)
|
162
|
+
end
|
163
|
+
def get_dir(type)
|
164
|
+
@dirs[type]
|
165
|
+
end
|
166
|
+
def write_files(options={})
|
167
|
+
mapdir=get_dir(:map); ensure_dir(mapdir)
|
168
|
+
|
169
|
+
@fonts.each {|font|
|
170
|
+
font.write_files(:mapfile => false)
|
171
|
+
mapfile << font.maplines
|
172
|
+
}
|
173
|
+
mapfilename=File.join(mapdir,@name+".map")
|
174
|
+
unless options[:dryrun]==true
|
175
|
+
File.open(mapfilename, "w") {|file|
|
176
|
+
file << mapfile.to_s
|
177
|
+
}
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end # class RFI
|
182
|
+
end # module RFIL
|
data/lib/rfil/helper.rb
ADDED
@@ -0,0 +1,155 @@
|
|
1
|
+
#--
|
2
|
+
# helper.rb Last Change: Fri Jul 1 14:29:09 2005
|
3
|
+
#++
|
4
|
+
# Helper module for Font and FontCollection.
|
5
|
+
|
6
|
+
# Here we define methods that are used in Font and FontCollection.
|
7
|
+
|
8
|
+
require 'fileutils'
|
9
|
+
require 'tex/kpathsea'
|
10
|
+
|
11
|
+
module RFIL # :nodoc:
|
12
|
+
class RFI
|
13
|
+
module Helper
|
14
|
+
include TeX
|
15
|
+
def set_encarray(enc,where) #:nodoc:
|
16
|
+
if enc.instance_of?(TeX::ENC)
|
17
|
+
where.push(enc)
|
18
|
+
else
|
19
|
+
enc.each { |e|
|
20
|
+
if e.instance_of?(String)
|
21
|
+
e = e.chomp(".enc") + ".enc"
|
22
|
+
f=@kpse.open_file(e,"enc")
|
23
|
+
where.push(TeX::ENC.new(f))
|
24
|
+
f.close
|
25
|
+
elsif e.instance_of?(TeX::ENC)
|
26
|
+
where.push(e)
|
27
|
+
end
|
28
|
+
}
|
29
|
+
end
|
30
|
+
end
|
31
|
+
def set_mapenc(enc) # :nodoc:
|
32
|
+
@mapenc=enc
|
33
|
+
|
34
|
+
# nil/:none is perfectly valid
|
35
|
+
return if enc==nil or enc==:none
|
36
|
+
|
37
|
+
if enc.instance_of?(TeX::ENC)
|
38
|
+
@mapenc = enc
|
39
|
+
else
|
40
|
+
enc.find { |e|
|
41
|
+
if e.instance_of?(String)
|
42
|
+
e = e.chomp(".enc") + ".enc"
|
43
|
+
@kpse.open_file(e,"enc") { |f|
|
44
|
+
@mapenc = TeX::ENC.new(f)
|
45
|
+
}
|
46
|
+
elsif e.instance_of?(TeX::ENC)
|
47
|
+
@mapenc = e
|
48
|
+
end
|
49
|
+
}
|
50
|
+
end
|
51
|
+
end
|
52
|
+
# call-seq:
|
53
|
+
# set_dirs(string)
|
54
|
+
# set_dirs(hash)
|
55
|
+
#
|
56
|
+
# Set the base dir of all font related files. Acts only as a storage
|
57
|
+
# for the information. The automatic font installation method in
|
58
|
+
# Font#write_files uses this information. When a _string_ is passed,
|
59
|
+
# use this as the base dir for all files, when a hash is given, the
|
60
|
+
# keys must be one of <tt>:afm</tt>, <tt>:tfm</tt>,
|
61
|
+
# <tt>:vf</tt>,<tt>:map</tt>, <tt>:pfb</tt>, <tt>:tt</tt>, <tt>:tds</tt>.
|
62
|
+
def set_dirs(arg)
|
63
|
+
# tds needs testing! set vendor/fonname before/after set_dirs
|
64
|
+
types=[:afm, :tfm, :vpl, :vf, :pl, :map, :type1,:truetype, :fd, :typescript]
|
65
|
+
if arg.instance_of? String
|
66
|
+
@basedir=arg
|
67
|
+
types.each { |sym|
|
68
|
+
@dirs[sym]=arg
|
69
|
+
}
|
70
|
+
elsif arg.instance_of? Hash
|
71
|
+
if arg[:base]
|
72
|
+
@basedir=arg[:base]
|
73
|
+
end
|
74
|
+
if arg[:tds]==true
|
75
|
+
suffix = if @vendor and @name
|
76
|
+
File.join(@vendor,@name)
|
77
|
+
else
|
78
|
+
""
|
79
|
+
end
|
80
|
+
types.each { |t|
|
81
|
+
subdir= case t
|
82
|
+
when :afm
|
83
|
+
File.join("fonts/afm",suffix)
|
84
|
+
when :tfm
|
85
|
+
File.join("fonts/tfm",suffix)
|
86
|
+
when :vpl
|
87
|
+
File.join("fonts/source/vpl",suffix)
|
88
|
+
when :vf
|
89
|
+
File.join("fonts/vf",suffix)
|
90
|
+
when :pl
|
91
|
+
File.join("fonts/source/pl",suffix)
|
92
|
+
when :map
|
93
|
+
"fonts/map/dvips"
|
94
|
+
when :type1
|
95
|
+
File.join("fonts/type1",suffix)
|
96
|
+
when :truetype
|
97
|
+
File.join("fonts/truetype",suffix)
|
98
|
+
when :fd
|
99
|
+
File.join("tex/latex",suffix)
|
100
|
+
when :typescript
|
101
|
+
File.join("tex/context",suffix)
|
102
|
+
else
|
103
|
+
raise "unknown type"
|
104
|
+
end
|
105
|
+
@dirs[t] = File.join(@basedir,subdir)
|
106
|
+
}
|
107
|
+
else
|
108
|
+
arg.each { |key,value|
|
109
|
+
@dirs[key] = value
|
110
|
+
}
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
def ensure_dir(dirname) # :nodoc:
|
115
|
+
if File.exists?(dirname)
|
116
|
+
if File.directory?(dirname)
|
117
|
+
# nothing to do
|
118
|
+
else
|
119
|
+
# exists, but not dir
|
120
|
+
raise "File exists, but is not a directory: #{dirname}"
|
121
|
+
end
|
122
|
+
else
|
123
|
+
# file does not exist, we can create a directory (hopefully)
|
124
|
+
|
125
|
+
puts "Creating directory hierarchy #{dirname}" if @options[:verbose]
|
126
|
+
|
127
|
+
unless @options[:dryrun]
|
128
|
+
FileUtils.mkdir_p(dirname)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end #ensure_dir
|
132
|
+
end # helper
|
133
|
+
# options is a hash, but with lookup to a fontcollection
|
134
|
+
class Options # :nodoc:
|
135
|
+
def initialize(fontcollection)
|
136
|
+
@fc=fontcollection
|
137
|
+
@options={}
|
138
|
+
end
|
139
|
+
def [](idx)
|
140
|
+
if @options[idx]
|
141
|
+
return @options[idx]
|
142
|
+
end
|
143
|
+
if @fc
|
144
|
+
@fc.options[idx]
|
145
|
+
else
|
146
|
+
nil
|
147
|
+
end
|
148
|
+
end
|
149
|
+
def []=(idx,obj)
|
150
|
+
@options[idx]=obj
|
151
|
+
end
|
152
|
+
|
153
|
+
end
|
154
|
+
end # RFI
|
155
|
+
end
|