OSDN Git Service

more unicode library -> utf
[luatex-ja/luatexja.git] / tool / jfm-convert.lua
1 #!/usr/bin/env texlua
2
3 local stderr = io.stderr
4 local function show_usage(s)
5   stderr:write('Error: ' .. s .. '\n'); 
6   stderr:write('Usage: texlua jfm-convert [-J|-U] <ptex_jfm>\n'); 
7   stderr:write('-J: JIS mode, -U: UCS mode \n'); 
8   stderr:write(' * The output will be written to stdout.\n'); 
9   stderr:write(' * I do not read  virtual fonts which corresponded to <ptex_jfm>.\n'); 
10   stderr:write("   You will need to adjust 'align', 'left', 'down' entries by hand.\n");
11   stderr:write(" * In JIS mode, characters which are not included in JIS X 0208\n");
12   stderr:write("   (e.g., 0x2257) are written as 0x202577.\n");
13   os.exit(1)
14 end
15
16 kpse.set_program_name('luatex')
17 require('lualibs'); local uchar = utf.char
18 jisx0208 = require('ltj-jisx0208.lua').table_jisx0208_uptex
19 local function pass_ucs(s)
20    return  "'" .. uchar(s) .. "'" 
21 end
22 local function jis_to_ucs(s)
23    local i = s - 0x2020
24    local a = jisx0208[math.floor(i/256)*94+(i%256)-94] or 0
25    return a and pass_ucs(a) or string.format('0x%X',s+0x200000)
26 end
27
28 -------- 引数解釈 --------
29
30
31 local filename
32 local mode
33
34 for i=1,#arg do
35    if arg[i]=='-u' or arg[i]=='-U' then
36       mode = pass_ucs
37    elseif arg[i]=='-j' or arg[i]=='-J' then
38       mode = jis_to_ucs
39    elseif filename then
40       show_usage('Multiple JFM files.')
41    else
42       filename = arg[i]
43    end
44 end
45
46 if not filename then show_usage('Missing JFM file argument.') end
47 kpse.set_program_name('ptex')
48 local nf = kpse.find_file(filename, 'tfm')
49 if not nf then show_usage("JFM file can't be opened: " .. filename) end
50
51 -------- OPEN --------
52
53 local jfm_ptex = io.open(nf, 'rb')
54 local function get_word()
55    local d = table.pack(string.byte(jfm_ptex:read(4),1,4))
56    return d[1]*16777216+d[2]*65536+d[3]*256+d[4]
57 end
58 local function get_signed_word()
59    local d = get_word()
60    return  (d>=2147483648) and -(4294967296-d) or d
61 end
62 local extract = bit32.extract
63 local function get_two()
64    local d = get_word()
65    return extract(d,16,16), extract(d,0,16)
66 end
67 local function get_four()
68    local d = get_word()
69    return extract(d,24,8), extract(d,16,8), extract(d,8,8), extract(d,0,8)
70 end
71
72 local id, nt = get_two()
73 local lf, lh = get_two()
74 local bc, ec = get_two()
75 local nw, nh = get_two()
76 local nd, ni = get_two()
77 local nl, nk = get_two()
78 local ng, np = get_two()
79
80 if bc~=0 or
81    lf~= 7 + lh + nt + (ec - bc + 1) + nw + nh + nd + ni + nl + nk + ng + np or
82    (id~=11 and id~=9) then
83       stderr:write('Bad JFM "' .. filename .. '".\n'); jfm_ptex:close(); os.exit(1)
84 end
85
86 local result = {}
87 result.dir = (id==11) and 'yoko' or 'tate'
88
89 -------- HEADER --------
90
91 _ = get_word() -- checksum, unused
92 local designsize = get_word()/1048576 -- ignored
93
94 local encoding
95 if lh>=3 then
96    encoding   = ''
97    for i=1,math.min(10,lh-2) do encoding = encoding .. jfm_ptex:read(4) end
98    encoding = encoding:sub(2, 1+string.byte(encoding))
99 end
100 if not encoding then encoding = 'UNSPECIFIED' end
101
102 local family = ''
103 if lh>=13 then
104    for i=1,math.min(5,lh-12) do family = family .. jfm_ptex:read(4) end
105    family = family:sub(2, 1+string.byte(family))
106 end
107
108 local face = 0
109 if lh>=18 then
110    _, _, _, face = get_four()
111    for i=1,lh-19 do jfm_ptex:read(4) end -- ignored
112 end
113
114 -------- CHAR_TYPE --------
115 result[0] = {}
116 local all_ctype = {}
117 for i=1,nt do
118    local ccode, ctype = get_two()
119    if ccode~=0 then 
120       all_ctype[#all_ctype+1] = ccode
121    end
122    if ctype~=0 then
123       if not result[ctype] then result[ctype] = {} end
124       if not result[ctype].chars then result[ctype].chars = {} end
125       local t = result[ctype].chars
126       t[#t+1] = ccode
127    end
128 end
129
130 -------- CHAR_INFO --------
131 for i=0,ec do
132    if not result[i] then result[i] = {} end
133    local t, info = result[i], get_word()
134    t.align, t.left, t.down  = 'left', 0, 0
135    t.width  = extract(info, 24, 8)
136    t.height = extract(info, 20, 4)
137    t.depth  = extract(info, 16, 4)
138    t.italic = extract(info, 10, 6)
139    t.tag = extract(info, 8, 2)
140    t.rem = extract(info, 0, 8)
141 end
142
143 local wi, hi, di, ii = {}, {}, {}, {}
144 for i=0,nw-1 do wi[i] = get_signed_word() end
145 for i=0,nh-1 do hi[i] = get_signed_word() end
146 for i=0,nd-1 do di[i] = get_signed_word() end
147 for i=0,ni-1 do ii[i] = get_signed_word() end
148
149
150 -------- GLUE/KERN --------
151
152 local gk_table = {}
153 for i=0,nl-1 do  gk_table[i] = table.pack(get_four()) end
154
155 local kerns = {}
156 for i=0,nk-1 do kerns[i] = get_signed_word() end
157
158 local glues = {}
159 for i=0,ng/3-1 do glues[i] = { get_signed_word(), get_signed_word(), get_signed_word() } end
160
161
162 -------- PARAM --------
163 local param = {}
164 for i=1,math.min(9, np) do param[i] = get_word() end
165 local zw = param[6]
166 result.kanjiskip = {
167    param[2]/zw, param[3]/zw, param[4]/zw
168 }
169 result.xkanjiskip = {
170    param[7]/zw, param[8]/zw, param[9]/zw
171 }
172 result.zw, result.zh = 1.0, param[5]/zw
173
174
175
176 -------- 各種 index の解決 --------
177 for i=0,ec do
178    local t = result[i]
179    t.width  = wi[t.width]/zw
180    t.height = hi[t.height]/zw
181    t.depth  = di[t.depth]/zw
182    t.italic = ii[t.italic]/zw
183    if t.tag==1 then
184       local j = t.rem
185       while j do
186          local gkp = gk_table[j]
187          j = (gkp[1]<128) and j+gkp[1]+1 or nil
188          if gkp[3]<128 then
189             if not t.glue then t.glue = {} end
190             t.glue[gkp[2]] = {
191                glues[gkp[4]][1]/zw, 
192                glues[gkp[4]][2]/zw, 
193                glues[gkp[4]][3]/zw, 
194             }
195          else
196             if not t.kern then t.kern = {} end
197             t.kern[gkp[2]] = kerns[gkp[4]]/zw
198          end
199       end
200    end
201    t.tag, t.rem  = nil, nil
202 end
203
204 jfm_ptex:close()
205
206
207 -------- モード判定 --------
208 if not mode then
209    mode = jis_to_ucs
210    for i=1, #all_ctype do
211       local i = all_ctype[i]-0x2020
212       if not jisx0208[math.floor(i/256)*94+(i%256)-94] then
213          mode = pass_ucs; break
214       end
215    end
216 end
217
218 -------- 出力 --------
219 local function S(a)
220    if type(a)=='number' then
221       return tostring(math.floor(a*1000000+0.5)/1000000)
222    elseif type(a)=='table' then -- glue
223       return '{ ' .. S(a[1]) .. ', ' .. S(a[2]) .. ', ' .. S(a[3]) .. '},'
224    elseif type(a)=='string' then
225       return "'" .. a .. "'"
226    else
227       tostring(a)
228    end
229 end
230
231 print('-- -*- coding: utf-8 -*-')
232 print('-- converted from ' .. filename .. ' by jfm_convert.lua')
233 print('-- assumed encoding:  ' .. (mode==jis_to_ucs and 'JIS' or 'UCS') .. '\n')
234 print('luatexja.jfont.define_jfm {')
235 print('   -- original design size = ' .. S(designsize))
236 print('   -- original encoding    = (' .. encoding .. ')')
237 print('   -- original family      = (' .. family .. ')')
238 print("   dir = " .. S(result.dir) .. ",")
239 print('   zw = ' .. S(result.zw) .. ', zh = ' .. S(result.zh) .. ', ')
240 print('   kanjiskip = ' .. S(result.kanjiskip))
241 print('   xkanjiskip = ' .. S(result.xkanjiskip))
242 for i=0, ec do
243    local t = result[i]
244    print('   [' .. tostring(i) .. '] = {')
245    if t.chars then
246       print('      chars = {')
247       local d = '         '
248       for j=1,#(t.chars) do
249          d = d ..  mode(t.chars[j]) .. ', '
250          if j%8==0 and j<#(t.chars) then
251             d = d .. '\n         '
252          end
253       end
254       print(d)
255       print('      },')
256    end
257    print('      align = ' .. S(t.align) .. ', left = ' .. S(0.0) 
258             .. ', down = ' .. S(0.0) .. ', ')
259    print('      width = ' .. S(t.width) .. ', height = ' .. S(t.height) 
260             .. ', depth = ' .. S(t.depth) .. ', italic = ' .. S(t.italic) .. ',')
261    if t.glue then
262       print('      glue = {')
263       local gi = {}
264       for m,_ in pairs(t.glue) do gi[#gi+1]=m end
265       table.sort(gi)
266       for _,m in ipairs(gi) do
267          print('         [' .. tostring(m) .. '] = ' .. S(t.glue[m]))
268       end
269       print('      },')
270    end
271    if t.kern then
272       print('      kern = {')
273       local gi = {}
274       for m,_ in pairs(t.kern) do gi[#gi+1]=m end
275       table.sort(gi)
276       for _,m in ipairs(gi) do
277          print('         [' .. tostring(m) .. '] = ' .. S(t.kern[m]) .. ',')
278       end
279       print('      },')
280    end
281    print('   },')
282 end
283 print('}')