OSDN Git Service

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