-
Notifications
You must be signed in to change notification settings - Fork 3
/
luametalatex-font-pk.lua
200 lines (199 loc) · 5.82 KB
/
luametalatex-font-pk.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
local function decode_char(buf)
local flag = buf:byte(1)
local form = flag & 0x07
local tfm, dx, dy, w, h, hoff, voff, off
if form < 4 then
tfm, dx, w, h, hoff, voff, off = string.unpack(">I3BBBbb", buf, 4)
dx, dy = dx * 2^16, 0
elseif form < 7 then
tfm, dx, w, h, hoff, voff, off = string.unpack(">I3HHHhh", buf, 5)
dx, dy = dx * 2^16, 0
else
tfm, dx, dy, w, h, hoff, voff, off = string.unpack(">I4I4I4I4I4i4i4", buf, 10)
end
local dyn_f, state = flag >> 4, flag & 8 == 8
local data
local stride = w+7>>3
if dyn_f == 14 then
print(state)
-- assert(not state)
data = lua.newtable(stride*h, 0)
local bit_offset, saved = 0
local delta_bit_offset = 8 - w%8
delta_bit_offset = delta_bit_offset == 8 and 0 or delta_bit_offset
for y=0,h-1 do
for x=1,stride do
if bit_offset == 0 then
saved = buf:byte(off)
data[y*stride+x] = saved
else
local saved_mask = (1<<bit_offset)-1
local current = (saved&saved_mask) << 8-bit_offset
saved = buf:byte(off)
data[y*stride+x] = current | (saved & ~saved_mask) >> bit_offset
end
off = off+1
end
if delta_bit_offset then
data[(y+1)*stride] = data[(y+1)*stride] & (0x100 - (1<<delta_bit_offset))
end
bit_offset = bit_offset + delta_bit_offset
if bit_offset >= 8 then
bit_offset = bit_offset-8
off = off-1
saved = buf:byte(off)
end
end
else
data = {string.rep('\0', stride*h):byte(1,-1)} -- FIXME: This is probably really slow
local nibble, repeat_row = nil, 0
local function get_nibble()
if nibble then
local cur = nibble
nibble = nil
off = off+1
return cur
else
local cur = buf:byte(off)
nibble = cur&0xF
return cur >> 4
end
end
local function get_packed()
local cur = get_nibble()
if cur == 0 then
local i = 0
repeat
cur = get_nibble()
i = i+1
until cur ~= 0
for _=1,i do
cur = (cur<<4) + get_nibble()
end
return cur - 0xF + (13-dyn_f << 4) + dyn_f
elseif cur <= dyn_f then
return cur
elseif cur < 14 then
return (cur-dyn_f-1 << 4) + get_nibble() + dyn_f + 1
else
repeat_row = cur == 14 and get_packed() or 1
return get_packed()
end
end
local cur_x, cur_y = 0, 0
while cur_y < h do
local count = get_packed()
repeat
local this_line = math.min(w - cur_x, count)
count = count - this_line
if state then
local cur_bit_offset = cur_x % 8
if cur_bit_offset ~= 0 then -- We are in the middle of a byte
cur_bit_offset = 8-cur_bit_offset -- The remaining bits in the byte
local off = cur_y*stride+(cur_x>>3)+1
if this_line > cur_bit_offset then -- Fill byte with ones
data[off] = data[off] + (1<<cur_bit_offset)-1
this_line, cur_x = this_line-cur_bit_offset, cur_x+cur_bit_offset
else
data[off] = data[off] + (1<<cur_bit_offset)-(1<<cur_bit_offset-this_line)
this_line, cur_x = 0, cur_x+this_line
end
end
while this_line >= 8 do
data[cur_y*stride+(cur_x>>3)+1] = 0xFF
this_line, cur_x = this_line-8, cur_x+8
end
if this_line ~= 0 then
data[cur_y*stride+(cur_x>>3)+1] = 0x100-(1<<8-this_line)
end
end
cur_x = cur_x + this_line
if cur_x == w then
for i = 1, repeat_row do
table.move(data, cur_y*stride+1, (cur_y+1)*stride, (cur_y+i)*stride+1) -- TODO
end
cur_y, cur_x, repeat_row = cur_y + 1 + repeat_row, 0, 0
end
until count == 0
state = not state
end
end
data = string.char(table.unpack(data))
return {
data = data,
tfm = tfm,
dx = dx,
dy = dy,
hoff = hoff,
voff = voff,
w = w,
h = h,
}
end
local commands = {
[240] = function(buf, off, t)
local xxx xxx, off = string.unpack(">xs1", buf, off)
return off
end,
[241] = function(buf, off, t)
local xxx xxx, off = string.unpack(">xs2", buf, off)
return off
end,
[242] = function(buf, off, t)
local xxx xxx, off = string.unpack(">xs3", buf, off)
return off
end,
[243] = function(buf, off, t)
local xxx xxx, off = string.unpack(">xs4", buf, off)
return off
end,
[244] = function(buf, off, t)
local yyy yyy, off = string.unpack(">xI4", buf, off)
return off
end,
[247] = function(buf, off, t)
local ident
ident, t.comment, t.designsize, t.checksum, t.hppp, t.vppp, off = string.unpack(">xBs1I4I4I4I4", buf, off)
if ident ~= 89 then
error[[Not a PK file]]
end
return off
end,
}
local function parse_commands(buf, off, t)
local cmd = buf:byte(off)
assert(cmd == 247)
repeat
if cmd < 240 then
local form = cmd & 0x07
local chr, newoff, length
if form < 4 then
length, chr, newoff = string.unpack(">xBB", buf, off)
length = length + ((form & 3)<<8)
elseif form < 7 then
length, chr, newoff = string.unpack(">xHB", buf, off)
length = length + ((form & 3)<<16)
else
length, chr, newoff = string.unpack(">xI4I4", buf, off)
end
newoff = newoff + length
t[chr] = decode_char(buf:sub(off, newoff))
off = newoff
else
local handler = commands[cmd]
if not handler then
print([[Unknown command ]] .. cmd)
return off-1
end
off = handler(buf, off, t)
end
cmd = buf:byte(off)
until cmd == 245
return off
end
return function(data)
local res = {}
local off = parse_commands(data, 1, res)
-- assert(off == #pk+1) -- TODO: Check that only fillup bytes follow
return res
end