dvi 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/dvi/tfm.rb ADDED
@@ -0,0 +1,68 @@
1
+ require "stringio"
2
+
3
+ module Dvi
4
+ class Tfm
5
+
6
+ class Char
7
+ # Returns the width(in design-size units) of the character index number.
8
+ attr_reader :width, :height, :depth, :italic_correction
9
+ attr_reader :kerning, :ligature
10
+ def initialize(width, height, depth, italic_correction, kerning, ligature)
11
+ @width = width
12
+ @height = height
13
+ @depth = depth
14
+ @italic_correction = italic_correction
15
+ @kerning = kerning
16
+ @ligature = ligature
17
+ end
18
+ end
19
+
20
+ class Ligature
21
+ attr_reader :a, :b, :c, :index
22
+ def initialize(a, b, c, index)
23
+ @a = a
24
+ @b = b
25
+ @c = c
26
+ @index = index
27
+ end
28
+ end
29
+
30
+ class Kerning
31
+ attr_reader :next_char, :amount
32
+ def initialize(next_char, real_amount)
33
+ @next_char = next_char
34
+ @amount = real_amount * (2**(-20.0))
35
+ end
36
+ end
37
+
38
+ class Data
39
+ attr_reader :design_size, :font_coding_scheme, :font_identifier
40
+ attr_reader :char, :param
41
+ attr_reader :slant, :space, :strech, :shrink, :xheight, :quad, :extraspace
42
+ def initialize(design_size, font_coding_scheme, font_identifier, char, param)
43
+ @design_size = design_size
44
+ @font_coding_scheme = font_coding_scheme
45
+ @font_identifier = font_identifier
46
+ @char = char
47
+ @param = param
48
+ @slant = @param[1]
49
+ @space = @param[2]
50
+ @stretch = @param[3]
51
+ @shrink = @param[4]
52
+ @xheight = @param[5]
53
+ @quad = @param[6]
54
+ @extraspace = @param[7]
55
+ end
56
+ end
57
+
58
+ # Read the TFM file.
59
+ # path:: TFM file path string
60
+ def self.read(path)
61
+ raise ArgumentError, path unless path.kind_of?(String) && File.exist?(path)
62
+ Format.new(File.open(path)).build
63
+ end
64
+
65
+ end
66
+ end
67
+
68
+ require "dvi/tfm/format"
@@ -0,0 +1,290 @@
1
+ class Dvi::Tfm::Format
2
+ class Error < StandardError; end
3
+ class NotImplemented < StandardError; end
4
+
5
+ # CharInfo is a class for char_info section.
6
+ class CharInfo
7
+ attr_reader :width_index, :height_index, :depth_index, :italic_index
8
+ attr_reader :tag, :remainder
9
+ def initialize(width_index, height_index, depth_index, italic_index,
10
+ tag, remainder)
11
+ @width_index = width_index
12
+ @height_index = height_index
13
+ @depth_index = depth_index
14
+ @italic_index = italic_index
15
+ @tag = tag
16
+ @remainder = remainder
17
+ end
18
+ end
19
+
20
+ # LigKern is a class for lig/kern section.
21
+ class LigKern
22
+ attr_reader :skip_byte, :next_char, :op_byte, :remainder
23
+ def initialize(skip_byte, next_char, op_byte, remainder)
24
+ @skip_byte = skip_byte
25
+ @next_char = next_char
26
+ @op_byte = op_byte
27
+ @remainder = remainder
28
+ end
29
+ end
30
+
31
+ # ExtensibleRecipe is a class for extensible recipe section.
32
+ class ExtensibleRecipe
33
+ attr_reader :top, :mid, :bot, :rep
34
+ def initialize(top, mid, bot, rep)
35
+ @top = top
36
+ @mid = mid
37
+ @bot = bot
38
+ @rep = rep
39
+ end
40
+ end
41
+
42
+ attr_reader :lf, :lh, :bc, :ec, :nw, :nh, :nd, :ni, :nl, :nk, :ne, :np
43
+ attr_accessor :checksum, :design_size, :font_coding_scheme, :font_identifier
44
+ attr_accessor :seven_bit_safe_flag, :face
45
+ attr_reader :charinfo, :lig_kern_table, :kern_table, :extensible_recipe, :param
46
+
47
+ def initialize(io)
48
+ raise ArgumentError unless io.kind_of?(IO)
49
+ read_tfm_header(io)
50
+ read_header_data(io)
51
+ read_char_info_table(io)
52
+ read_width_table(io)
53
+ read_height_table(io)
54
+ read_depth_table(io)
55
+ read_italic_table(io)
56
+ read_lig_kern_table(io)
57
+ read_kern_table(io)
58
+ read_extensible_recipes(io)
59
+ read_params(io)
60
+ end
61
+
62
+ def build
63
+ @chars = Array.new
64
+ @char_info_table.each_with_index do |char_info, idx|
65
+ unit = (2**(-20.0))
66
+
67
+ # sizes
68
+ w = @width_table[char_info.width_index] * unit
69
+ h = @height_table[char_info.height_index] * unit
70
+ d = @depth_table[char_info.depth_index] * unit
71
+ i = @italic_table[char_info.italic_index] * unit
72
+
73
+ # lig/kern
74
+ k = Hash.new
75
+ l = Hash.new
76
+
77
+ case char_info.tag
78
+ when 0
79
+ # do nothing
80
+ when 1
81
+ idx = char_info.remainder
82
+ next_lig_kern = true
83
+
84
+ while next_lig_kern do
85
+ lk = @lig_kern_table[idx]
86
+
87
+ if lk.op_byte >= 128
88
+ # kerning
89
+ amount = @kern_table[256*(lk.op_byte-128)+lk.remainder]
90
+ k[lk.next_char] = Dvi::Tfm::Kerning.new(lk.next_char, amount)
91
+ else
92
+ # ligature
93
+ a, b, c = case lk.op_byte
94
+ when 0; [0, 0, 0]
95
+ when 1; [0, 0, 1]
96
+ when 2; [0, 1, 0]
97
+ when 3; [0, 1, 1]
98
+ when 5; [1, 0, 0]
99
+ when 6; [1, 1, 0]
100
+ when 7; [1, 1, 1]
101
+ when 11; [2, 1, 1]
102
+ else raise Error end
103
+ l[lk.next_char] = Dvi::Tfm::Ligature.new(a, b, c, lk.remainder)
104
+ end
105
+
106
+ # next?
107
+ if lk.skip_byte >= 128
108
+ next_lig_kern = false
109
+ else
110
+ idx += (1 + lk.skip_byte)
111
+ end
112
+ end
113
+ when 2
114
+ raise NotImplemented
115
+ when 3
116
+ raise NotImplemented
117
+ else
118
+ raise Error
119
+ end
120
+
121
+ @chars << Dvi::Tfm::Char.new(w, h, d, i, k, l)
122
+ end
123
+ Dvi::Tfm::Data.new(@design_size,
124
+ @font_coding_scheme,
125
+ @font_identifier,
126
+ @chars,
127
+ @param)
128
+ end
129
+
130
+ ### PRIVATE ###
131
+
132
+ private
133
+
134
+ def read_tfm_header(io) #:nodoc:
135
+ # change the position
136
+ io.seek(0)
137
+
138
+ # section positions
139
+ @lf, @lh, @bc, @ec, @nw, @nh, @nd, @ni, @nl, @nk, @ne, @np =
140
+ io.read(24).unpack("n12")
141
+
142
+ # set positions
143
+ @pos = Hash.new
144
+ @pos[:ci] = (6 + @lh) * 4
145
+ @pos[:nw] = @pos[:ci] + (@ec - @bc + 1) * 4
146
+ @pos[:nh] = @pos[:nw] + @nw * 4
147
+ @pos[:nd] = @pos[:nh] + @nh * 4
148
+ @pos[:ni] = @pos[:nd] + @nd * 4
149
+ @pos[:nl] = @pos[:ni] + @ni * 4
150
+ @pos[:nk] = @pos[:nl] + @nl * 4
151
+ @pos[:ne] = @pos[:nk] + @nk * 4
152
+ @pos[:np] = @pos[:ne] + @ne * 4
153
+
154
+ # validation
155
+ raise Error unless @bc - 1 <= @ec and @ec <= 255 and ne <= 256
156
+ lf = 7 + @lh + @ec - @bc + @nw + @nh + @nd + @ni + @nl + @nk + @ne + @np
157
+ raise Error unless @lf == lf
158
+ end
159
+
160
+ def read_header_data(io) #:nodoc:
161
+ # change the position
162
+ io.seek(24)
163
+
164
+ # checksum
165
+ @checksum = io.read(4)
166
+
167
+ # design size
168
+ @real_design_size = io.read(4).unpack("N").first
169
+ @design_size = @real_design_size * (2**(-20.0))
170
+
171
+ # font coding scheme
172
+ if @lh > 2
173
+ size = io.read(1).unpack("C").first
174
+ @font_coding_scheme = io.read(size)
175
+ end
176
+
177
+ # font identifier / font family
178
+ if @lh > 12
179
+ io.seek(72)
180
+ size = io.read(1).unpack("C").first
181
+ @font_identifier = io.read(size)
182
+ end
183
+
184
+ # other data
185
+ if @lh > 17
186
+ io.seek(92)
187
+ byte = io.read(4).unpack("C4")
188
+ @seven_bit_safe_flag = byte[0]
189
+ @face = byte[3]
190
+ end
191
+ end
192
+
193
+ def read_char_info_table(io) #:nodoc:
194
+ # change the position
195
+ io.seek @pos[:ci]
196
+
197
+ @char_info_table = (0..(@ec - @bc)).map do
198
+ # read 4 bytes
199
+ byte = io.read(4).unpack("c4")
200
+
201
+ CharInfo.new(byte[0], # width index (8 bits)
202
+ byte[1] >> 4, # height index (4 bits)
203
+ byte[1] & 0b00001111, # depth index (4 bits)
204
+ byte[2] >> 2, # italic index (6 bits)
205
+ byte[2] & 0b00000011, # tag index (2 bits)
206
+ byte[3]) # remainder (8 bits)
207
+ end
208
+ end
209
+
210
+ def read_width_table(io)
211
+ # change the position
212
+ io.seek @pos[:nw]
213
+
214
+ # collect each word
215
+ @width_table = (1..@nw).map{ io.read(4).unpack("N").first }
216
+
217
+ # validation
218
+ raise Error unless @width_table[0] == 0
219
+ end
220
+
221
+ def read_height_table(io)
222
+ # change the position
223
+ io.seek @pos[:nh]
224
+
225
+ # collect each word
226
+ @height_table = (1..@nh).map{ io.read(4).unpack("N").first }
227
+
228
+ # validation
229
+ raise Error unless @height_table[0] == 0
230
+ end
231
+
232
+ def read_depth_table(io)
233
+ # change the position
234
+ io.seek @pos[:nd]
235
+
236
+ # collect each word
237
+ @depth_table = (1..@nd).map{ io.read(4).unpack("N").first }
238
+
239
+ # validation
240
+ raise Error unless @depth_table[0] == 0
241
+ end
242
+
243
+ def read_italic_table(io)
244
+ # change the position
245
+ io.seek @pos[:ni]
246
+
247
+ # collect each word
248
+ @italic_table = (1..@ni).map{ io.read(4).unpack("N").first }
249
+
250
+ # validation
251
+ raise Error unless @italic_table[0] == 0
252
+ end
253
+
254
+ def read_lig_kern_table(io)
255
+ # change the position
256
+ io.seek @pos[:nl]
257
+
258
+ # collect each word
259
+ @lig_kern_table = (1..@nl).map{ LigKern.new(*io.read(4).unpack("C4")) }
260
+ end
261
+
262
+ def read_kern_table(io)
263
+ # change the position
264
+ io.seek @pos[:nk]
265
+
266
+ # collect each word
267
+ @kern_table = (1..@nk).map do
268
+ # signed long little endian
269
+ io.read(4).unpack("N").pack("l").unpack("l").first
270
+ end
271
+ end
272
+
273
+ def read_extensible_recipes(io)
274
+ # change the position
275
+ io.seek @pos[:ne]
276
+
277
+ # collect each word
278
+ @extensible_recipe = (1..@ne).map do
279
+ ExtensibleRecipe.new(*io.read(1).unpack("C4"))
280
+ end
281
+ end
282
+
283
+ def read_params(io)
284
+ # change the position
285
+ io.seek @pos[:np]
286
+
287
+ # collect each word
288
+ @param = (1..@np).map{ io.read(4).unpack("N").first }
289
+ end
290
+ end
data/lib/dvi/util.rb ADDED
@@ -0,0 +1,37 @@
1
+ module Dvi::Util
2
+ def read_uint1
3
+ readchar
4
+ end
5
+
6
+ def read_uint2
7
+ (readchar << 8) | readchar
8
+ end
9
+
10
+ def read_uint3
11
+ (readchar << 16) | read_uint2
12
+ end
13
+
14
+ def read_uint4
15
+ (readchar << 24) | read_uint3
16
+ end
17
+
18
+ def read_int1
19
+ ui = read_uint1
20
+ ui & 128 != 0 ? ui - 256 : ui
21
+ end
22
+
23
+ def read_int2
24
+ ui = read_uint2
25
+ ui & 32768 != 0 ? ui - 65536 : ui
26
+ end
27
+
28
+ def read_int3
29
+ ui = read_uint3
30
+ ui & 8388608 != 0 ? ui - 16777216 : ui
31
+ end
32
+
33
+ def read_int4
34
+ ui = read_uint4
35
+ ui & 2147483648 != 0 ? ui - 4294967296 : ui
36
+ end
37
+ end
@@ -0,0 +1,9 @@
1
+ module Dvi
2
+ module VERSION #:nodoc:
3
+ MAJOR = 0
4
+ MINOR = 1
5
+ TINY = 0
6
+
7
+ STRING = [MAJOR, MINOR, TINY].join('.')
8
+ end
9
+ end
data/log/debug.log ADDED
File without changes
Binary file
@@ -0,0 +1,4 @@
1
+ \documentclass[12pt]{article}
2
+ \begin{document}
3
+ Hello, world!
4
+ \end{document}
data/script/destroy ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ APP_ROOT = File.join(File.dirname(__FILE__), '..')
3
+
4
+ begin
5
+ require 'rubigen'
6
+ rescue LoadError
7
+ require 'rubygems'
8
+ require 'rubigen'
9
+ end
10
+ require 'rubigen/scripts/destroy'
11
+
12
+ ARGV.shift if ['--help', '-h'].include?(ARGV[0])
13
+ RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
14
+ RubiGen::Scripts::Destroy.new.run(ARGV)
data/script/generate ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ APP_ROOT = File.join(File.dirname(__FILE__), '..')
3
+
4
+ begin
5
+ require 'rubigen'
6
+ rescue LoadError
7
+ require 'rubygems'
8
+ require 'rubigen'
9
+ end
10
+ require 'rubigen/scripts/generate'
11
+
12
+ ARGV.shift if ['--help', '-h'].include?(ARGV[0])
13
+ RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
14
+ RubiGen::Scripts::Generate.new.run(ARGV)