dvi 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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)