freetype 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +8 -18
- data/lib/freetype/api.rb +31 -118
- data/lib/freetype/api_test.rb +53 -76
- data/lib/freetype/c.rb +3 -0
- data/lib/freetype/c_test.rb +47 -16
- data/lib/freetype/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c36f62b7c9de44960d5c1610bdad80291833313e
|
4
|
+
data.tar.gz: 46b17c2d49414d9fdad8b8ea6072b342286aab00
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 372d0d55f362b88693b72d12e17336319afea3b75a2a67d1eaedaaa235c02e775f86652e71764a4f5644b3451c98a3e23bced0ff7f31e4819866546877c936a3
|
7
|
+
data.tar.gz: 55ac0bd04129157365706a0a91ffe5aceea88e3c5f4108ffd0563a40e0e589bb8dd972c33ba0167540228c4962e66ec184eefc88b949543a1add02bacc5285b8
|
data/README.md
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# FreeType
|
2
2
|
|
3
|
+
[![Build Status](https://travis-ci.org/ksss/freetype.svg?branch=master)](https://travis-ci.org/ksss/freetype)
|
4
|
+
|
3
5
|
FreeType is freetype wrapper using by ffi
|
4
6
|
|
5
7
|
## Installation
|
@@ -78,27 +80,15 @@ raise FreeType::Error.find(err) unless err == 0
|
|
78
80
|
|
79
81
|
```ruby
|
80
82
|
require 'freetype/api'
|
83
|
+
# or require 'freetype'
|
81
84
|
|
82
85
|
include FreeType::API
|
83
86
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
p face.kerning_unfitted('A', 'W') #=> #<FreeType::API::Vector x=-10 y=0>
|
90
|
-
end
|
91
|
-
end
|
92
|
-
```
|
93
|
-
|
94
|
-
### Use All
|
95
|
-
|
96
|
-
```ruby
|
97
|
-
require 'freetype'
|
98
|
-
|
99
|
-
FreeType::API::Library.open do |lib|
|
100
|
-
face = FFI::MemoryPointer.new(:pointer)
|
101
|
-
FreeType::C::FT_New_Face(lib.pointer, 'font.otf', 0, face)
|
87
|
+
Font.open('font.ttf') do |font|
|
88
|
+
font.set_char_size(0, 32 * 32, 300, 300)
|
89
|
+
outline = font.glyph('a').outline
|
90
|
+
p outline.points #=> [#<FreeType::API::Outline tag=-1 x= 10 y=24>, ...]
|
91
|
+
p font.kerning_unfitted('A', 'W') #=> #<FreeType::API::Vector x=-10 y=0>
|
102
92
|
end
|
103
93
|
```
|
104
94
|
|
data/lib/freetype/api.rb
CHANGED
@@ -4,6 +4,22 @@ require 'freetype/error'
|
|
4
4
|
module FreeType
|
5
5
|
# high level API for freetype wrapping by FFI
|
6
6
|
module API
|
7
|
+
def library_version
|
8
|
+
library = ::FFI::MemoryPointer.new(:pointer)
|
9
|
+
err = FreeType::C::FT_Init_FreeType(library)
|
10
|
+
raise FreeType::Error.find(err) unless err == 0
|
11
|
+
|
12
|
+
amajor = ::FFI::MemoryPointer.new(:int)
|
13
|
+
aminor = ::FFI::MemoryPointer.new(:int)
|
14
|
+
apatch = ::FFI::MemoryPointer.new(:int)
|
15
|
+
FreeType::C::FT_Library_Version(library.get_pointer(0), amajor, aminor, apatch)
|
16
|
+
"#{amajor.get_int(0)}.#{aminor.get_int(0)}.#{apatch.get_int(0)}"
|
17
|
+
ensure
|
18
|
+
err = FreeType::C::FT_Done_Library(library.get_pointer(0))
|
19
|
+
raise FreeType::Error.find(err) unless err == 0
|
20
|
+
end
|
21
|
+
module_function :library_version
|
22
|
+
|
7
23
|
module IOInterface
|
8
24
|
def open(*args)
|
9
25
|
i = new(*args)
|
@@ -19,58 +35,30 @@ module FreeType
|
|
19
35
|
end
|
20
36
|
end
|
21
37
|
|
22
|
-
class
|
38
|
+
class Font
|
23
39
|
extend IOInterface
|
24
40
|
include C
|
25
41
|
|
26
|
-
|
42
|
+
attr_reader :face
|
43
|
+
def initialize(font_path)
|
27
44
|
@library = ::FFI::MemoryPointer.new(:pointer)
|
28
45
|
err = FT_Init_FreeType(@library)
|
29
46
|
raise FreeType::Error.find(err) unless err == 0
|
30
|
-
end
|
31
|
-
|
32
|
-
def face_open(font)
|
33
|
-
Face.open(pointer, font) do |f|
|
34
|
-
yield f
|
35
|
-
end
|
36
|
-
end
|
37
47
|
|
38
|
-
|
39
|
-
@library.get_pointer(0)
|
40
|
-
end
|
48
|
+
@font_path = font_path
|
41
49
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
FT_Library_Version(@library.get_pointer(0), amajor, aminor, apatch)
|
47
|
-
"#{amajor.get_int(0)}.#{aminor.get_int(0)}.#{apatch.get_int(0)}"
|
50
|
+
f = ::FFI::MemoryPointer.new(:pointer)
|
51
|
+
err = FT_New_Face(@library.get_pointer(0), @font_path, 0, f)
|
52
|
+
raise FreeType::Error.find(err) unless err == 0
|
53
|
+
@face = FT_FaceRec.new(f.get_pointer(0))
|
48
54
|
end
|
49
55
|
|
50
56
|
def close
|
51
|
-
err =
|
57
|
+
err = FT_Done_Face(@face)
|
52
58
|
raise FreeType::Error.find(err) unless err == 0
|
53
|
-
@library.free
|
54
|
-
end
|
55
|
-
end
|
56
59
|
|
57
|
-
|
58
|
-
extend IOInterface
|
59
|
-
include C
|
60
|
-
|
61
|
-
attr_reader :font_path
|
62
|
-
def initialize(library, font_path)
|
63
|
-
@library = library
|
64
|
-
@font_path = font_path
|
65
|
-
@outline = nil
|
66
|
-
f = ::FFI::MemoryPointer.new(:pointer)
|
67
|
-
err = FT_New_Face(@library, @font_path, 0, f)
|
60
|
+
err = FT_Done_Library(@library.get_pointer(0))
|
68
61
|
raise FreeType::Error.find(err) unless err == 0
|
69
|
-
@face = FT_FaceRec.new(f.get_pointer(0))
|
70
|
-
end
|
71
|
-
|
72
|
-
def raw
|
73
|
-
@face
|
74
62
|
end
|
75
63
|
|
76
64
|
def select_charmap(enc_code)
|
@@ -122,11 +110,6 @@ module FreeType
|
|
122
110
|
get_kerning(before_char, after_char, :FT_KERNING_UNSCALED)
|
123
111
|
end
|
124
112
|
|
125
|
-
def close
|
126
|
-
err = FT_Done_Face(@face)
|
127
|
-
raise FreeType::Error.find(err) unless err == 0
|
128
|
-
end
|
129
|
-
|
130
113
|
private
|
131
114
|
|
132
115
|
def get_kerning(before_char, after_char, kerning_mode)
|
@@ -164,8 +147,8 @@ module FreeType
|
|
164
147
|
@glyph = glyph
|
165
148
|
end
|
166
149
|
|
167
|
-
def
|
168
|
-
@glyph
|
150
|
+
def [](key)
|
151
|
+
@glyph[key]
|
169
152
|
end
|
170
153
|
|
171
154
|
def metrics
|
@@ -176,7 +159,7 @@ module FreeType
|
|
176
159
|
Outline.new(@glyph[:outline])
|
177
160
|
end
|
178
161
|
|
179
|
-
def
|
162
|
+
def char_width
|
180
163
|
@glyph[:metrics][:horiAdvance]
|
181
164
|
end
|
182
165
|
end
|
@@ -188,8 +171,8 @@ module FreeType
|
|
188
171
|
@outline = outline
|
189
172
|
end
|
190
173
|
|
191
|
-
def
|
192
|
-
@outline
|
174
|
+
def [](key)
|
175
|
+
@outline[key]
|
193
176
|
end
|
194
177
|
|
195
178
|
def points
|
@@ -212,76 +195,6 @@ module FreeType
|
|
212
195
|
return [] if @outline[:n_points] == 0
|
213
196
|
@outline[:tags].get_array_of_char(0, @outline[:n_points])
|
214
197
|
end
|
215
|
-
|
216
|
-
def to_svg_path
|
217
|
-
end_ptd_of_counts = contours
|
218
|
-
contours = []
|
219
|
-
contour = []
|
220
|
-
points.each.with_index do |point, index|
|
221
|
-
contour << point
|
222
|
-
if index == end_ptd_of_counts.first
|
223
|
-
end_ptd_of_counts.shift
|
224
|
-
contours << contour
|
225
|
-
contour = []
|
226
|
-
end
|
227
|
-
end
|
228
|
-
|
229
|
-
path = []
|
230
|
-
contours.each do |contour|
|
231
|
-
first_pt = contour.first
|
232
|
-
last_pt = contour.last
|
233
|
-
curve_pt = nil
|
234
|
-
start = 0
|
235
|
-
if first_pt.on_curve?
|
236
|
-
curve_pt = nil
|
237
|
-
start = 1
|
238
|
-
else
|
239
|
-
if last_pt.on_curve?
|
240
|
-
first_pt = last_pt
|
241
|
-
else
|
242
|
-
first_pt = Point.new(0, (first_pt.x + last_pt.x) / 2, (first_pt.y + last_pt.y) / 2)
|
243
|
-
end
|
244
|
-
curve_pt = first_pt
|
245
|
-
end
|
246
|
-
path << ['M', first_pt.x, -first_pt.y]
|
247
|
-
|
248
|
-
prev_pt = nil
|
249
|
-
(start...contour.length).each do |j|
|
250
|
-
pt = contour[j]
|
251
|
-
prev_pt = if j == 0
|
252
|
-
first_pt
|
253
|
-
else
|
254
|
-
contour[j - 1]
|
255
|
-
end
|
256
|
-
|
257
|
-
if prev_pt.on_curve? && pt.on_curve?
|
258
|
-
path << ['L', pt.x, -pt.y]
|
259
|
-
elsif prev_pt.on_curve? && !pt.on_curve?
|
260
|
-
curve_pt = pt
|
261
|
-
elsif !prev_pt.on_curve? && !pt.on_curve?
|
262
|
-
path << ['Q', prev_pt.x, -prev_pt.y, (prev_pt.x + pt.x) / 2, -((prev_pt.y + pt.y) / 2)]
|
263
|
-
curve_pt = pt
|
264
|
-
elsif !prev_pt.on_curve? && pt.on_curve?
|
265
|
-
path << ['Q', curve_pt.x, -curve_pt.y, pt.x, -pt.y]
|
266
|
-
curve_pt = nil
|
267
|
-
else
|
268
|
-
raise
|
269
|
-
end
|
270
|
-
end
|
271
|
-
|
272
|
-
next unless first_pt != last_pt
|
273
|
-
if curve_pt
|
274
|
-
path << ['Q', curve_pt.x, -curve_pt.y, first_pt.x, -first_pt.y]
|
275
|
-
else
|
276
|
-
path << ['L', first_pt.x, -first_pt.y]
|
277
|
-
end
|
278
|
-
end
|
279
|
-
path << ['z'] if 0 < path.length
|
280
|
-
|
281
|
-
path.map { |(command, *args)|
|
282
|
-
"#{command}#{args.join(' ')}"
|
283
|
-
}.join('')
|
284
|
-
end
|
285
198
|
end
|
286
199
|
|
287
200
|
Point = Struct.new(:tag, :x, :y) do
|
data/lib/freetype/api_test.rb
CHANGED
@@ -3,98 +3,74 @@ require 'freetype/api'
|
|
3
3
|
module FreeTypeApiTest
|
4
4
|
include FreeType::API
|
5
5
|
|
6
|
-
def
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
f.set_char_size(0, 0, 300, 300)
|
11
|
-
yield f
|
12
|
-
end
|
6
|
+
def font_open
|
7
|
+
['data/Prida01.otf', 'data/Starjedi.ttf'].each do |font|
|
8
|
+
Font.open(font) do |f|
|
9
|
+
yield f, font
|
13
10
|
end
|
14
11
|
end
|
15
12
|
end
|
16
13
|
|
17
|
-
def
|
18
|
-
|
19
|
-
|
20
|
-
|
14
|
+
def test_library_version(t)
|
15
|
+
v = FreeType::API.library_version
|
16
|
+
unless String === v
|
17
|
+
t.error 'return value was break'
|
18
|
+
end
|
19
|
+
unless /\A\d+.\d+.\d+\z/ =~ v
|
20
|
+
t.error "version format was break got #{v}"
|
21
|
+
end
|
22
|
+
end
|
21
23
|
|
22
|
-
|
23
|
-
|
24
|
-
|
24
|
+
def test_Font(t)
|
25
|
+
font = nil
|
26
|
+
ret = Font.open('data/Prida01.otf') do |f|
|
27
|
+
font = f
|
25
28
|
|
26
29
|
:abc
|
27
30
|
end
|
28
|
-
if
|
31
|
+
if font.nil?
|
29
32
|
t.error('cannot get FT_Library in `open` with block')
|
30
33
|
end
|
31
34
|
if ret != :abc
|
32
35
|
t.error 'want to return last value in block'
|
33
36
|
end
|
34
|
-
end
|
35
37
|
|
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
|
-
t.error('recommend warn miss?')
|
66
|
-
end
|
67
|
-
else
|
68
|
-
t.error('check freetype spec')
|
69
|
-
ensure
|
70
|
-
$stderr = origerr
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
f.set_char_size(0, 0, 300, 300)
|
75
|
-
|
76
|
-
bbox = f.bbox
|
77
|
-
unless BBox === bbox
|
78
|
-
t.error('FreeType::API::Face#bbox return value was break')
|
79
|
-
end
|
80
|
-
|
81
|
-
unless Glyph === f.glyph('a')
|
82
|
-
t.error 'return value was break'
|
83
|
-
end
|
84
|
-
|
85
|
-
# unless Glyph === f.notdef
|
86
|
-
# t.error 'return value was break'
|
87
|
-
# end
|
88
|
-
end
|
38
|
+
font_open do |f, _font|
|
39
|
+
if f.char_index('a') == 0
|
40
|
+
t.error('ascii char not defined this font')
|
41
|
+
end
|
42
|
+
if f.char_index('㍿') != 0
|
43
|
+
t.error("I don't know why set character was defined in font")
|
44
|
+
end
|
45
|
+
|
46
|
+
v = f.kerning('A', 'W')
|
47
|
+
unless v
|
48
|
+
t.error('#kerning return object was changed')
|
49
|
+
end
|
50
|
+
unless Fixnum === v.x && Fixnum === v.y
|
51
|
+
t.error('Not vector object. Check spec for FT_Get_Kerning()')
|
52
|
+
end
|
53
|
+
|
54
|
+
f.set_char_size(0, 0, 300, 300)
|
55
|
+
|
56
|
+
bbox = f.bbox
|
57
|
+
unless BBox === bbox
|
58
|
+
t.error('FreeType::API::Face#bbox return value was break')
|
59
|
+
end
|
60
|
+
|
61
|
+
unless Glyph === f.glyph('a')
|
62
|
+
t.error 'return value was break'
|
63
|
+
end
|
64
|
+
|
65
|
+
unless Glyph === f.notdef
|
66
|
+
t.error 'return value was break'
|
89
67
|
end
|
90
|
-
end
|
91
|
-
if face.nil?
|
92
|
-
t.error('cannot get FT_Face in `open` with block')
|
93
68
|
end
|
94
69
|
end
|
95
70
|
|
96
71
|
def test_glyph(t)
|
97
|
-
|
72
|
+
font_open do |f|
|
73
|
+
f.set_char_size(0, 0, 300, 300)
|
98
74
|
table = { 'a' => nil, 'b' => nil, 'c' => nil, 'd' => nil }
|
99
75
|
table.each do |char, _|
|
100
76
|
glyph = f.glyph(char)
|
@@ -104,8 +80,8 @@ module FreeTypeApiTest
|
|
104
80
|
t.error 'return value was break'
|
105
81
|
end
|
106
82
|
|
107
|
-
|
108
|
-
unless Fixnum ===
|
83
|
+
char_width = glyph.char_width
|
84
|
+
unless Fixnum === char_width
|
109
85
|
t.error 'return value was break'
|
110
86
|
end
|
111
87
|
|
@@ -118,7 +94,8 @@ module FreeTypeApiTest
|
|
118
94
|
end
|
119
95
|
|
120
96
|
def test_outline(t)
|
121
|
-
|
97
|
+
font_open do |f|
|
98
|
+
f.set_char_size(0, 0, 300, 300)
|
122
99
|
table = { 'a' => nil, 'b' => nil, 'c' => nil, 'd' => nil }
|
123
100
|
table.each do |char, _|
|
124
101
|
outline = f.glyph(char).outline
|
data/lib/freetype/c.rb
CHANGED
@@ -235,6 +235,9 @@ module FreeType
|
|
235
235
|
# id = FT_Get_Char_Index(face, 'A'.ord) -> glyph id or 0 (undefined)
|
236
236
|
attach_function :FT_Get_Char_Index, [:pointer, :ulong], :uint
|
237
237
|
|
238
|
+
# err = FT_Get_Glyph_Name(face, 0, buff, 32)
|
239
|
+
attach_function :FT_Get_Glyph_Name, [:pointer, :uint, :pointer, :uint], :FT_Error
|
240
|
+
|
238
241
|
# v = FT_Vector.new
|
239
242
|
# err = FT_Get_Kerning(face, before_id, id, :FT_KERNING_DEFAULT, v)
|
240
243
|
# p v
|
data/lib/freetype/c_test.rb
CHANGED
@@ -12,11 +12,19 @@ module FFITest
|
|
12
12
|
|
13
13
|
FONTS.each do |font|
|
14
14
|
face = ::FFI::MemoryPointer.new(:pointer)
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
15
|
+
begin
|
16
|
+
err = FT_New_Face(library.get_pointer(0), font, 0, face)
|
17
|
+
raise FreeType::Error.find(err) unless err == 0
|
18
|
+
|
19
|
+
yield FT_FaceRec.new(face.get_pointer(0)), font
|
20
|
+
ensure
|
21
|
+
err = FT_Done_Face(face.get_pointer(0))
|
22
|
+
raise FreeType::Error.find(err) unless err == 0
|
23
|
+
end
|
19
24
|
end
|
25
|
+
ensure
|
26
|
+
err = FT_Done_Library(library.get_pointer(0))
|
27
|
+
raise FreeType::Error.find(err) unless err == 0
|
20
28
|
end
|
21
29
|
|
22
30
|
def test_Library(t)
|
@@ -38,6 +46,12 @@ module FFITest
|
|
38
46
|
unless a.all? { |i| Fixnum === i }
|
39
47
|
t.error 'miss get values from FT_Library_Version()'
|
40
48
|
end
|
49
|
+
t.log "freetype version: #{a.join('.')}"
|
50
|
+
ensure
|
51
|
+
err = FT_Done_Library(library.get_pointer(0))
|
52
|
+
if err != 0
|
53
|
+
t.error FreeType::Error.find(err).message
|
54
|
+
end
|
41
55
|
end
|
42
56
|
|
43
57
|
def test_Face(t)
|
@@ -53,24 +67,28 @@ module FFITest
|
|
53
67
|
t.fatal FreeType::Error.find(err).message
|
54
68
|
end
|
55
69
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
70
|
+
begin
|
71
|
+
face = FT_FaceRec.new(face.get_pointer(0))
|
72
|
+
err = FT_Select_Charmap(face, :FT_ENCODING_UNICODE)
|
73
|
+
if err != 0
|
74
|
+
t.error FreeType::Error.find(err).message
|
75
|
+
end
|
76
|
+
ensure
|
77
|
+
err = FT_Done_Face(face)
|
78
|
+
if err != 0
|
79
|
+
t.error FreeType::Error.find(err).message
|
80
|
+
end
|
60
81
|
end
|
61
82
|
end
|
83
|
+
ensure
|
84
|
+
err = FT_Done_Library(library.get_pointer(0))
|
85
|
+
if err != 0
|
86
|
+
t.error FreeType::Error.find(err).message
|
87
|
+
end
|
62
88
|
end
|
63
89
|
|
64
90
|
def test_FT_Set_Char_Size(t)
|
65
91
|
libopen do |face|
|
66
|
-
if /darwin/ =~ RUBY_PLATFORM
|
67
|
-
err = FT_Load_Char(face, 'a'.ord, FreeType::C::FT_LOAD_DEFAULT)
|
68
|
-
e = FreeType::Error.find(err)
|
69
|
-
unless FreeType::Error::Invalid_Size_Handle === e
|
70
|
-
t.fatal 'check freetype spec'
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
92
|
err = FT_Set_Char_Size(face, 0, 32, 300, 300)
|
75
93
|
if err != 0
|
76
94
|
t.error FreeType::Error.find(err).message
|
@@ -83,6 +101,19 @@ module FFITest
|
|
83
101
|
end
|
84
102
|
end
|
85
103
|
|
104
|
+
def test_FT_Get_Glyph_Name(t)
|
105
|
+
libopen do |face|
|
106
|
+
buff = FFI::MemoryPointer.new(:pointer)
|
107
|
+
err = FT_Get_Glyph_Name(face, 0, buff, 32)
|
108
|
+
if err != 0
|
109
|
+
t.error FreeType::Error.find(err).message
|
110
|
+
end
|
111
|
+
unless String === buff.get_string(0)
|
112
|
+
t.error 'May buffering miss?'
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
86
117
|
def test_char(t)
|
87
118
|
libopen do |face, _font|
|
88
119
|
err = FT_Set_Char_Size(face, 0, 32, 300, 300)
|
data/lib/freetype/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: freetype
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- ksss
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-12-
|
11
|
+
date: 2015-12-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ffi
|