dragonfly_fonts 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +23 -0
- data/Dockerfile +15 -0
- data/Gemfile +4 -0
- data/Guardfile +8 -0
- data/LICENSE.txt +22 -0
- data/README.md +196 -0
- data/Rakefile +9 -0
- data/circle.yml +23 -0
- data/docker-compose.yml +15 -0
- data/dragonfly_fonts.gemspec +28 -0
- data/lib/dragonfly_fonts.rb +8 -0
- data/lib/dragonfly_fonts/analysers/bbox.rb +35 -0
- data/lib/dragonfly_fonts/analysers/font_info.rb +15 -0
- data/lib/dragonfly_fonts/analysers/glyphs.rb +14 -0
- data/lib/dragonfly_fonts/analysers/gsub_tables.rb +14 -0
- data/lib/dragonfly_fonts/plugin.rb +43 -0
- data/lib/dragonfly_fonts/processors/correct_metrics.rb +21 -0
- data/lib/dragonfly_fonts/processors/encode.rb +57 -0
- data/lib/dragonfly_fonts/processors/extract_glyph.rb +19 -0
- data/lib/dragonfly_fonts/processors/normalize_names.rb +17 -0
- data/lib/dragonfly_fonts/processors/set_dimensions.rb +24 -0
- data/lib/dragonfly_fonts/processors/set_ttf_names.rb +52 -0
- data/lib/dragonfly_fonts/processors/set_underline.rb +26 -0
- data/lib/dragonfly_fonts/processors/set_width.rb +25 -0
- data/lib/dragonfly_fonts/processors/set_woff_metadata.rb +23 -0
- data/lib/dragonfly_fonts/processors/ttf_autohint.rb +21 -0
- data/lib/dragonfly_fonts/processors/web_friendly.rb +17 -0
- data/lib/dragonfly_fonts/unicode_ranges.rb +89 -0
- data/lib/dragonfly_fonts/version.rb +3 -0
- data/samples/Arial.ttf +0 -0
- data/samples/Inconsolata.otf +0 -0
- data/script/dimensions.py +28 -0
- data/script/font_info.py +49 -0
- data/script/glyphs.py +25 -0
- data/script/gsub_tables.py +43 -0
- data/script/normalize_names.sh +13 -0
- data/script/underline.py +20 -0
- data/script/webfonts.pe +49 -0
- data/script/woff_meta.py +81 -0
- data/test/dragonfly_fonts/analysers/bbox_test.rb +48 -0
- data/test/dragonfly_fonts/analysers/font_info_test.rb +65 -0
- data/test/dragonfly_fonts/analysers/glyphs_test.rb +27 -0
- data/test/dragonfly_fonts/analysers/gsub_tables_test.rb +42 -0
- data/test/dragonfly_fonts/plugin_test.rb +76 -0
- data/test/dragonfly_fonts/processors/correct_metrics_test.rb +22 -0
- data/test/dragonfly_fonts/processors/encode_test.rb +36 -0
- data/test/dragonfly_fonts/processors/extract_glyph_test.rb +22 -0
- data/test/dragonfly_fonts/processors/normalize_names_test.rb +18 -0
- data/test/dragonfly_fonts/processors/set_dimensions_test.rb +26 -0
- data/test/dragonfly_fonts/processors/set_ttf_names_test.rb +23 -0
- data/test/dragonfly_fonts/processors/set_underline_test.rb +22 -0
- data/test/dragonfly_fonts/processors/set_width_test.rb +48 -0
- data/test/dragonfly_fonts/processors/set_woff_metadata_test.rb +28 -0
- data/test/dragonfly_fonts/processors/ttf_autohint_test.rb +18 -0
- data/test/dragonfly_fonts/processors/web_friendly_test.rb +18 -0
- data/test/test_helper.rb +21 -0
- metadata +215 -0
data/samples/Arial.ttf
ADDED
Binary file
|
Binary file
|
@@ -0,0 +1,28 @@
|
|
1
|
+
#!/usr/bin/env python
|
2
|
+
|
3
|
+
import fontforge, sys
|
4
|
+
|
5
|
+
__version__ = '0.1'
|
6
|
+
|
7
|
+
def main():
|
8
|
+
font = fontforge.open(sys.argv[1])
|
9
|
+
output_file_name = sys.argv[2]
|
10
|
+
|
11
|
+
if sys.argv[3]:
|
12
|
+
ascent = float(sys.argv[3])
|
13
|
+
font.ascent += ascent
|
14
|
+
font.hhea_ascent += ascent
|
15
|
+
font.os2_typoascent += ascent
|
16
|
+
font.os2_winascent += ascent
|
17
|
+
|
18
|
+
if sys.argv[4]:
|
19
|
+
descent = float(sys.argv[4])
|
20
|
+
font.descent += descent
|
21
|
+
font.hhea_descent += descent
|
22
|
+
font.os2_typodescent += descent
|
23
|
+
font.os2_windescent += descent
|
24
|
+
|
25
|
+
font.generate(output_file_name)
|
26
|
+
|
27
|
+
if __name__ == '__main__':
|
28
|
+
main()
|
data/script/font_info.py
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
#!/usr/bin/env python
|
2
|
+
|
3
|
+
import fontforge, json, sys
|
4
|
+
|
5
|
+
def main():
|
6
|
+
for f in sys.argv[1:] :
|
7
|
+
font = fontforge.open(f)
|
8
|
+
|
9
|
+
names = {}
|
10
|
+
for n in font.sfnt_names :
|
11
|
+
if n[0] == "English (US)" :
|
12
|
+
names[n[1]] = n[2]
|
13
|
+
|
14
|
+
font_info = {
|
15
|
+
'ascent': font.ascent,
|
16
|
+
'cap_height': font.capHeight,
|
17
|
+
'comment': font.comment,
|
18
|
+
'copyright': font.copyright,
|
19
|
+
'default_base_filename': font.default_base_filename,
|
20
|
+
'descent': font.descent,
|
21
|
+
'descriptor': names.get('Descriptor'),
|
22
|
+
'designer': names.get('Designer'),
|
23
|
+
'designer_url': names.get('Designer URL'),
|
24
|
+
'em': font.em,
|
25
|
+
'embedding_restrictions': font.os2_fstype,
|
26
|
+
'encoding': font.encoding,
|
27
|
+
'familyname': font.familyname,
|
28
|
+
'fontlog': font.fontlog,
|
29
|
+
'fontname': font.fontname,
|
30
|
+
'fullname': font.fullname,
|
31
|
+
'license': names.get('License'),
|
32
|
+
'license_url': names.get('License URL'),
|
33
|
+
'path': font.path,
|
34
|
+
'sfnt_revision': font.sfntRevision,
|
35
|
+
'trademark': names.get('Trademark'),
|
36
|
+
'upos': font.upos,
|
37
|
+
'uwidth': font.uwidth,
|
38
|
+
'vendor_url': names.get('Vendor URL'),
|
39
|
+
'version': font.version,
|
40
|
+
'weight': font.weight,
|
41
|
+
'woff_metadata': font.woffMetadata,
|
42
|
+
'woff_revision': [font.woffMajor, font.woffMinor],
|
43
|
+
'x_height': font.xHeight
|
44
|
+
}
|
45
|
+
|
46
|
+
print json.dumps(font_info)
|
47
|
+
|
48
|
+
if __name__ == '__main__':
|
49
|
+
main()
|
data/script/glyphs.py
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
#!/usr/bin/env python
|
2
|
+
|
3
|
+
import array, fontforge, json, sys
|
4
|
+
|
5
|
+
def main():
|
6
|
+
for f in sys.argv[1:] :
|
7
|
+
font = fontforge.open(f)
|
8
|
+
|
9
|
+
glyphs = []
|
10
|
+
|
11
|
+
for (i,g) in enumerate(font.glyphs()):
|
12
|
+
glyphs.append({
|
13
|
+
'glyphname': g.glyphname,
|
14
|
+
'glyphclass': g.glyphclass,
|
15
|
+
'script': g.script,
|
16
|
+
'encoding': g.encoding,
|
17
|
+
'unicode': g.unicode,
|
18
|
+
'width': g.width
|
19
|
+
})
|
20
|
+
|
21
|
+
print json.dumps(glyphs)
|
22
|
+
|
23
|
+
|
24
|
+
if __name__ == '__main__':
|
25
|
+
main()
|
@@ -0,0 +1,43 @@
|
|
1
|
+
#!/usr/bin/env python
|
2
|
+
|
3
|
+
import fontforge, json, sys
|
4
|
+
|
5
|
+
def main():
|
6
|
+
for f in sys.argv[1:] :
|
7
|
+
font = fontforge.open(f)
|
8
|
+
|
9
|
+
gsub_tables = []
|
10
|
+
|
11
|
+
for gsub in font.gsub_lookups:
|
12
|
+
|
13
|
+
subtables = []
|
14
|
+
for sub in font.getLookupSubtables(gsub):
|
15
|
+
|
16
|
+
glyphs = []
|
17
|
+
for g in font.glyphs():
|
18
|
+
pos = g.getPosSub(sub)
|
19
|
+
if pos:
|
20
|
+
glyphs.append({
|
21
|
+
'name': g.glyphname,
|
22
|
+
'glyphclass': g.glyphclass,
|
23
|
+
'script': g.script,
|
24
|
+
'encoding': g.encoding,
|
25
|
+
'unicode': g.unicode,
|
26
|
+
'pos': pos
|
27
|
+
})
|
28
|
+
|
29
|
+
subtables.append({
|
30
|
+
'name': sub,
|
31
|
+
'glyphs': glyphs
|
32
|
+
})
|
33
|
+
|
34
|
+
gsub_tables.append({
|
35
|
+
'name': gsub,
|
36
|
+
'info': font.getLookupInfo(gsub),
|
37
|
+
'subtables': subtables
|
38
|
+
})
|
39
|
+
|
40
|
+
print json.dumps(gsub_tables)
|
41
|
+
|
42
|
+
if __name__ == '__main__':
|
43
|
+
main()
|
@@ -0,0 +1,13 @@
|
|
1
|
+
|
2
|
+
Open($1)
|
3
|
+
|
4
|
+
fontname = $fontname
|
5
|
+
version = $fontversion
|
6
|
+
|
7
|
+
# Fix for rejected EOT's in IE8:
|
8
|
+
# http://stackoverflow.com/questions/12449512/why-does-one-of-these-font-face-render-in-ie8-but-the-others-dont/12459447#12459447
|
9
|
+
# http://fontforge.org/scripting-alpha.html#SetFontNames
|
10
|
+
SetFontNames($fontname,$fontname,$fontname,"","",version)
|
11
|
+
|
12
|
+
# Save.
|
13
|
+
Generate($2)
|
data/script/underline.py
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
#!/usr/bin/env python
|
2
|
+
|
3
|
+
import fontforge, sys
|
4
|
+
|
5
|
+
__version__ = '0.1'
|
6
|
+
|
7
|
+
def main():
|
8
|
+
font = fontforge.open(sys.argv[1])
|
9
|
+
output_file_name = sys.argv[2]
|
10
|
+
|
11
|
+
if sys.argv[3]:
|
12
|
+
font.upos = float(sys.argv[3])
|
13
|
+
|
14
|
+
if sys.argv[4]:
|
15
|
+
font.uwidth = float(sys.argv[4])
|
16
|
+
|
17
|
+
font.generate(output_file_name)
|
18
|
+
|
19
|
+
if __name__ == '__main__':
|
20
|
+
main()
|
data/script/webfonts.pe
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
# webfonts.pe font-in.ttf font-out.ttf
|
2
|
+
|
3
|
+
# Generates webfont-ready files as per http://goo.gl/0qowi
|
4
|
+
# Author: Brian Zick <http://21326.info>
|
5
|
+
# Version: 1
|
6
|
+
# Date: 27 September 2011
|
7
|
+
|
8
|
+
|
9
|
+
# DESCRIPTION
|
10
|
+
# webfonts.pe saves a source file, cleans glyph outlines, coverts to tt outlines,
|
11
|
+
# and hints fonts before saving hinted and unhinted variants in both .sfd and .ttf.
|
12
|
+
# You may need to change the path variable in this script for your project;
|
13
|
+
# by default it is set to ../Release.
|
14
|
+
#
|
15
|
+
# BUGS
|
16
|
+
# Some functions are used twice in a row. This is because they
|
17
|
+
# (for some reason) did not work properly when used once.
|
18
|
+
#
|
19
|
+
# On my system, the generated *-TTF-hints.ttf has no hints? I don't know why.
|
20
|
+
# *-TTF-hints.sfd does, however, have hints. A workaround was found by
|
21
|
+
# Alexei Vanyashin <alexei.vanyashin@gmail.com>: split the script into two
|
22
|
+
# parts - one with hints, one without.
|
23
|
+
#
|
24
|
+
# I have not found a way to set "Really use Typo Metrics", and reportedly,
|
25
|
+
# fontforge doesn't export it to the TTF files anyway.
|
26
|
+
#
|
27
|
+
# It would be nice if fontforge could create a sub-folder for each version.
|
28
|
+
#
|
29
|
+
# TODO
|
30
|
+
# Options to enable or disable hinted/not hinted versions.
|
31
|
+
|
32
|
+
Open($1)
|
33
|
+
|
34
|
+
# Glyph cleanup
|
35
|
+
SelectAll()
|
36
|
+
UnlinkReference()
|
37
|
+
RemoveOverlap()
|
38
|
+
CorrectDirection()
|
39
|
+
ScaleToEm(2048)
|
40
|
+
|
41
|
+
# Convert splines to quadratic
|
42
|
+
SetFontOrder(2)
|
43
|
+
Simplify(128,2.05)
|
44
|
+
Simplify(128,2.05)
|
45
|
+
RoundToInt()
|
46
|
+
RoundToInt()
|
47
|
+
|
48
|
+
# Save.
|
49
|
+
Generate($2)
|
data/script/woff_meta.py
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
#!/usr/bin/env python
|
2
|
+
|
3
|
+
import array, fontforge, json, sys
|
4
|
+
|
5
|
+
__version__ = '0.1'
|
6
|
+
|
7
|
+
def main():
|
8
|
+
font = fontforge.open(sys.argv[1])
|
9
|
+
output_file_name = sys.argv[2]
|
10
|
+
uniqueid = sys.argv[3]
|
11
|
+
licensee_name = sys.argv[4]
|
12
|
+
|
13
|
+
names = {}
|
14
|
+
for n in font.sfnt_names :
|
15
|
+
if n[0] == "English (US)" :
|
16
|
+
names[n[1]] = n[2]
|
17
|
+
|
18
|
+
metadata = [
|
19
|
+
'<?xml version="1.0" encoding="UTF-8"?>',
|
20
|
+
'<metadata version="1.0">',
|
21
|
+
' <uniqueid id="{}.{}.{}.{}"/>'.format(uniqueid, __version__, font.fontname, font.version),
|
22
|
+
]
|
23
|
+
|
24
|
+
if names.get('Vendor URL'):
|
25
|
+
metadata.extend([
|
26
|
+
' <vendor name="{}" url="{}" />'.format(names.get('Manufacturer'), names.get('Vendor URL')),
|
27
|
+
])
|
28
|
+
|
29
|
+
if names.get('Designer'):
|
30
|
+
if names.get('Designer URL'):
|
31
|
+
metadata.extend([
|
32
|
+
' <credits>',
|
33
|
+
' <credit name="{}" url="{}" role="Designer" />'.format(names.get('Designer'), names.get('Designer URL')),
|
34
|
+
' </credits>',
|
35
|
+
])
|
36
|
+
|
37
|
+
if font.fontlog:
|
38
|
+
metadata.extend([
|
39
|
+
' <description>',
|
40
|
+
' <text lang="en"><![CDATA[{}]]></text>'.format(font.fontlog),
|
41
|
+
' </description>',
|
42
|
+
])
|
43
|
+
|
44
|
+
if names.get('License'):
|
45
|
+
if names.get('License URL'):
|
46
|
+
metadata.extend([
|
47
|
+
' <license url="{}">'.format(names.get('License URL')),
|
48
|
+
' <text xml:lang="en"><![CDATA[{}]]></text>'.format(names.get('License')),
|
49
|
+
' </license>',
|
50
|
+
])
|
51
|
+
|
52
|
+
if font.copyright:
|
53
|
+
metadata.extend([
|
54
|
+
' <copyright>',
|
55
|
+
' <text lang="en"><![CDATA[{}]]></text>'.format(font.copyright),
|
56
|
+
' </copyright>',
|
57
|
+
])
|
58
|
+
|
59
|
+
if names.get('Trademark'):
|
60
|
+
metadata.extend([
|
61
|
+
' <trademark>',
|
62
|
+
' <text lang="en"><![CDATA[{}]]></text>'.format(names.get('Trademark')),
|
63
|
+
' </trademark>',
|
64
|
+
])
|
65
|
+
|
66
|
+
if licensee_name:
|
67
|
+
metadata.extend([
|
68
|
+
' <licensee name="{}" />'.format(licensee_name),
|
69
|
+
])
|
70
|
+
|
71
|
+
metadata.extend([
|
72
|
+
'</metadata>',
|
73
|
+
'', # for trailing endline
|
74
|
+
])
|
75
|
+
|
76
|
+
font.woffMetadata = '\n'.join(metadata)
|
77
|
+
|
78
|
+
font.generate(output_file_name)
|
79
|
+
|
80
|
+
if __name__ == '__main__':
|
81
|
+
main()
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module DragonflyFonts
|
4
|
+
module Analysers
|
5
|
+
describe Bbox do
|
6
|
+
let(:app) { test_app.configure_with(:fonts) }
|
7
|
+
let(:asset) { app.fetch_file SAMPLES_DIR.join('Inconsolata.otf') }
|
8
|
+
|
9
|
+
let(:analyser) { DragonflyFonts::Analysers::Bbox.new }
|
10
|
+
|
11
|
+
describe 'call' do
|
12
|
+
let(:bbox) { analyser.call(asset, 'A') }
|
13
|
+
|
14
|
+
it 'returns Hash' do
|
15
|
+
bbox.must_be_kind_of Struct
|
16
|
+
end
|
17
|
+
|
18
|
+
it '#glyph' do
|
19
|
+
bbox.glyph.must_equal 'A'
|
20
|
+
end
|
21
|
+
|
22
|
+
it '#min_x' do
|
23
|
+
bbox.min_x.must_equal 14.6709
|
24
|
+
end
|
25
|
+
|
26
|
+
it '#min_y' do
|
27
|
+
bbox.min_y.must_equal(-0.863281)
|
28
|
+
end
|
29
|
+
|
30
|
+
it '#max_x' do
|
31
|
+
bbox.max_x.must_equal 483.28
|
32
|
+
end
|
33
|
+
|
34
|
+
it '#max_y' do
|
35
|
+
bbox.max_y.must_equal 634.305
|
36
|
+
end
|
37
|
+
|
38
|
+
it '#width' do
|
39
|
+
bbox.width.must_equal 468.60909999999996
|
40
|
+
end
|
41
|
+
|
42
|
+
it '#height' do
|
43
|
+
bbox.height.must_equal 635.168281
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module DragonflyFonts
|
4
|
+
module Analysers
|
5
|
+
describe FontInfo do
|
6
|
+
let(:app) { test_app.configure_with(:fonts) }
|
7
|
+
let(:analyser) { DragonflyFonts::Analysers::FontInfo.new }
|
8
|
+
let(:font) { app.fetch_file(SAMPLES_DIR.join('Inconsolata.otf')) }
|
9
|
+
|
10
|
+
describe 'call' do
|
11
|
+
it 'returns Hash' do
|
12
|
+
analyser.call(font).must_be_kind_of Hash
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'includes keys' do
|
16
|
+
%w(
|
17
|
+
ascent
|
18
|
+
cap_height
|
19
|
+
comment
|
20
|
+
copyright
|
21
|
+
default_base_filename
|
22
|
+
descent
|
23
|
+
descriptor
|
24
|
+
designer
|
25
|
+
designer_url
|
26
|
+
em
|
27
|
+
embedding_restrictions
|
28
|
+
encoding
|
29
|
+
familyname
|
30
|
+
fontlog
|
31
|
+
fontname
|
32
|
+
fullname
|
33
|
+
license
|
34
|
+
license_url
|
35
|
+
path
|
36
|
+
sfnt_revision
|
37
|
+
trademark
|
38
|
+
upos
|
39
|
+
uwidth
|
40
|
+
vendor_url
|
41
|
+
version
|
42
|
+
weight
|
43
|
+
woff_metadata
|
44
|
+
woff_revision
|
45
|
+
x_height
|
46
|
+
).each do |key|
|
47
|
+
analyser.call(font).keys.must_include key
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'includes familyname' do
|
52
|
+
analyser.call(font)['familyname'].must_equal 'Inconsolata'
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'includes fullname' do
|
56
|
+
analyser.call(font)['fullname'].must_equal 'Inconsolata'
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'includes weight' do
|
60
|
+
analyser.call(font)['weight'].must_equal 'Medium'
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module DragonflyFonts
|
4
|
+
module Analysers
|
5
|
+
describe Glyphs do
|
6
|
+
let(:app) { test_app.configure_with(:fonts) }
|
7
|
+
let(:asset) { app.fetch_file SAMPLES_DIR.join('Inconsolata.otf') }
|
8
|
+
|
9
|
+
let(:glyph_A) { asset.glyphs.find{ |g| g['glyphname'] == 'A' } }
|
10
|
+
|
11
|
+
describe 'call' do
|
12
|
+
it 'returns Array' do
|
13
|
+
asset.glyphs.must_be_kind_of Array
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'returns properties per each glyph' do
|
17
|
+
glyph_A['glyphclass'].wont_be_nil
|
18
|
+
glyph_A['glyphname'].wont_be_nil
|
19
|
+
glyph_A['encoding'].wont_be_nil
|
20
|
+
glyph_A['script'].wont_be_nil
|
21
|
+
glyph_A['width'].wont_be_nil
|
22
|
+
glyph_A['unicode'].wont_be_nil
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|