add hex2bin filter for easy diff
[terpinus.git] / bdf.rb
blob9115e5470fb80c8cf53d48a834b1283d00b4d76e
1 def open_bdf(file)
2   f = File.open(file,'r')
3   buf = f.readlines.map {|x| x.chomp}
4   f.close
5   class << buf
6     def init
7       @line = 0
8     end
9   
10     def line
11       self[@line]
12     end
13   
14     def swallow
15       @line += 1
16     end
17   
18     def empty
19       @line == self.length
20     end
21   end
22   buf.init
23   buf
24 end
26 class BDF
27   attr_reader :glyphs, :header, :glyph_ref
28   def initialize(filename)
29     buf = open_bdf(filename)
30     @glyphs = []
31     @glyph_ref = {}
32     @header = []
33     @footer = []
34     glyph_processing = false
35     while (!buf.empty) do
36       items = buf.line.split(/ /)
37       if items[0] == 'STARTCHAR'
38         glyph_processing = true
39         g = Glyph.new(buf)
40         @glyphs << g
41         @glyph_ref[g.name] = g
42       else
43         glyph_processing ? @footer << buf.line : @header << buf.line
44         buf.swallow
45       end
46     end
47     self
48   end
50   def write(io)
51     if io.is_a? String
52       f = File.open(io,'w')
53       ret = self.write(f)
54       f.close
55       return ret
56     end
57     glyphs = @glyph_ref.values.sort {|x,y| x.encoding <=> y.encoding}
58     @header.each {|h| io.puts h =~ /^CHARS / ? "CHARS #{glyphs.length}" : h}
59     glyphs.each {|g| g.write(io) }
60     @footer.each {|h| io.puts h}
61     true
62   end
64   NAMES = {
65     0x01A0 => 'Ohorn',
66     0x01A1 => 'ohorn',
67     0x01AF => 'Uhorn',
68     0x01B0 => 'uhorn',
69     0x1EF2 => 'Ygrave',
70     0x1EF3 => 'ygrave',
71   }
72   REFS = {
73     0x01A0 => 'O',
74     0x01A1 => 'o',
75     0x01AF => 'U',
76     0x01B0 => 'u',
77   
78     0x1EA0 => 'A',
79     0x1EA1 => 'a',
80     0x1EA2 => 'A',
81     0x1EA3 => 'a',
82     
83     0x1EA4 => 'Acircumflex',
84     0x1EA5 => 'acircumflex',
85     0x1EA6 => 'Acircumflex',
86     0x1EA7 => 'acircumflex',
87     0x1EA8 => 'Acircumflex',
88     0x1EA9 => 'acircumflex',
89     0x1EAA => 'Acircumflex',
90     0x1EAB => 'acircumflex',
91     0x1EAC => 'Acircumflex',
92     0x1EAD => 'acircumflex',
93     
94     0x1EAE => 'Abreve',
95     0x1EAF => 'abreve',
96     0x1EB0 => 'Abreve',
97     0x1EB1 => 'abreve',
98     0x1EB2 => 'Abreve',
99     0x1EB3 => 'abreve',
100     0x1EB4 => 'Abreve',
101     0x1EB5 => 'abreve',
102     0x1EB6 => 'Abreve',
103     0x1EB7 => 'abreve',
104     
105     0x1EBA => 'E',
106     0x1EBB => 'e',
107     
108     0x1EBE => 'Ecircumflex',
109     0x1EBF => 'ecircumflex',
110     0x1EC0 => 'Ecircumflex',
111     0x1EC1 => 'ecircumflex',
112     0x1EC2 => 'Ecircumflex',
113     0x1EC3 => 'ecircumflex',
114     0x1EC4 => 'Ecircumflex',
115     0x1EC5 => 'ecircumflex',
116     0x1EC6 => 'Ecircumflex',
117     0x1EC7 => 'ecircumflex',
118     
119     0x1EC8 => 'I',
120     0x1EC9 => 'i',
121     0x1ECA => 'I',
122     0x1ECB => 'i',
123     
124     0x1ECE => 'O',
125     0x1ECF => 'o',
126     
127     0x1ED0 => 'Ocircumflex',
128     0x1ED1 => 'ocircumflex',
129     0x1ED2 => 'Ocircumflex',
130     0x1ED3 => 'ocircumflex',
131     0x1ED4 => 'Ocircumflex',
132     0x1ED5 => 'ocircumflex',
133     0x1ED6 => 'Ocircumflex',
134     0x1ED7 => 'ocircumflex',
135     0x1ED8 => 'Ocircumflex',
136     0x1ED9 => 'ocircumflex',
137     
138     0x1EDA => 'O',
139     0x1EDB => 'o',
140     0x1EDC => 'O',
141     0x1EDD => 'o',
142     0x1EDE => 'O',
143     0x1EDF => 'o',
144     0x1EE0 => 'O',
145     0x1EE1 => 'o',
146     0x1EE2 => 'O',
147     0x1EE3 => 'o',
148     
149     0x1EE4 => 'U',
150     0x1EE5 => 'u',
151     0x1EE6 => 'U',
152     0x1EE7 => 'u',
153     
154     0x1EE8 => 'U',
155     0x1EE9 => 'u',
156     0x1EEA => 'U',
157     0x1EEB => 'u',
158     0x1EEC => 'U',
159     0x1EED => 'u',
160     0x1EEE => 'U',
161     0x1EEF => 'u',
162     0x1EF0 => 'U',
163     0x1EF1 => 'u',
164     
165     0x1EF2 => 'Y',
166     0x1EF3 => 'y',
168     0x1EF4 => 'Y',
169     0x1EF5 => 'y',
170     0x1EF6 => 'Y',
171     0x1EF7 => 'y',
172   }
174   def copy_glyph(name,bdf)
175     g = bdf.glyph_ref[name].dup
176     @glyph_ref[g.name] = g
177   end
179   def copy_glyph_by_id(name,bdf)
180     if name.is_a? String
181       self.copy_glyph(name,bdf)
182     end
183     if name.is_a? Array
184       name.each {|x| self.copy_glyph_by_id(x,bdf) }
185     end
186     nil
187   end
189   def dup_glyph(name,newname,newencoding,bdf = nil)
190     g = bdf.nil? ? @glyph_ref[name].dup : bdf.glyph_ref[name].dup
191     g.name = newname
192     g.encoding = newencoding
193     @glyph_ref[g.name] = g
194   end
196   def dup_glyph_by_id(id,bdf = nil)
197     if id.is_a? Fixnum
198       return unless REFS.key? id
199       name = NAMES[id] || "uni#{id.to_s(16).upcase}"
200       self.dup_glyph(REFS[id],name,id,bdf)
201     end
202     if id.is_a? Array
203       id.each {|x| self.dup_glyph_by_id(x,bdf) }
204     end
205     nil
206   end
208   def copy_all(bdf)
209     self.copy_glyph_by_id(REFS.keys.map {|x| NAMES[x] || "uni#{x.to_s(16).upcase}"} ,bdf)
210   end
212   def dup_all(bdf = nil)
213     #$bdf.dup_glyph_by_id([416, 417, 431, 432, 7922, 7923,
214     #0x1EA0, 0x1EA1, 0x1EA2, 0x1EA3,
215     #0x1EA4, 0x1EA5, 0x1EA6, 0x1EA7, 0x1EA8, 0x1EA9, 0x1EAA, 0x1EAB, 0x1EAC, 0x1EAD,
216     #0x1EAE, 0x1EAF, 0x1EB0, 0x1EB1, 0x1EB2, 0x1EB3, 0x1EB4, 0x1EB5, 0x1EB6, 0x1EB7,
217     #0x1EBA, 0x1EBB,
218     #0x1EBE, 0x1EBF, 0x1EC0, 0x1EC1, 0x1EC2, 0x1EC3, 0x1EC4, 0x1EC5, 0x1EC6, 0x1EC7,
219     #0x1EC8, 0x1EC9, 0x1ECA, 0x1ECB, 
220     #0x1ECE, 0x1ECF,
221     #0x1ED0, 0x1ED1, 0x1ED2, 0x1ED3, 0x1ED4, 0x1ED5, 0x1ED6, 0x1ED7, 0x1ED8, 0x1ED9,
222     #0x1EDA, 0x1EDB, 0x1EDC, 0x1EDD, 0x1EDE, 0x1EDF, 0x1EE0, 0x1EE1, 0x1EE2, 0x1EE3,
223     #0x1EE4, 0x1EE5, 0x1EE6, 0x1EE7,
224     #0x1EE8, 0x1EE9, 0x1EEA, 0x1EEB, 0x1EEC, 0x1EED, 0x1EEE, 0x1EEF, 0x1EF0, 0x1EF1,
225     #0x1EF4, 0x1EF5, 0x1EF6, 0x1EF7])
226     self.dup_glyph_by_id(REFS.keys,bdf)
227   end
230 class Glyph
231   attr_reader :swidth, :dwidth, :bbx, :bitmap
232   attr_accessor :encoding, :name
233   def initialize(buf)
234     done = false
235     bitmap_phase = false
236     @bitmap = []
237     while (!buf.empty && !done) do
238       items = buf.line.split(/ /)
239       if bitmap_phase
240         if items[0] == 'ENDCHAR'
241           done = true
242         else
243           @bitmap << buf.line
244         end
245       else
246         @name = items[1].dup if items[0] == 'STARTCHAR'
247         @encoding = items[1].to_i if items[0] == 'ENCODING'
248         @swidth = items.dup if items[0] == 'SWIDTH'
249         @dwidth = items.dup if items[0] == 'DWIDTH'
250         @bbx = items.dup if items[0] == 'BBX'
251         bitmap_phase = true if buf.line == 'BITMAP'
252       end 
253       buf.swallow
254     end
255     self
256   end
258   def write(io)
259     io.puts "STARTCHAR #@name"
260     io.puts "ENCODING #@encoding"
261     io.puts @swidth.join(' ')
262     io.puts @dwidth.join(' ')
263     io.puts @bbx.join(' ')
264     io.puts "BITMAP"
265     @bitmap.each {|b| io.puts b}
266     io.puts "ENDCHAR"
267   end
270 #$buf = open_bdf('ter-u16n.bdf')
271 #$bdf = BDF.new($buf)
272 #require 'pp'
273 #$bdf.write(STDOUT)
274 #a = BDF.new('zz')
275 #b = BDF.new('ter-u12n.bdf')
276 #a.copy_all(b)
277 #c = File.open('zzo','w')
278 #a.write(c)
279 #c.close