dragonfly_fonts 0.0.3
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.
- 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
|