fontcustom 1.2.0 → 1.3.0.beta
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/CHANGELOG.md +16 -0
- data/CONTRIBUTING.md +35 -15
- data/TODO.md +20 -0
- data/lib/fontcustom.rb +11 -24
- data/lib/fontcustom/base.rb +56 -0
- data/lib/fontcustom/cli.rb +13 -12
- data/lib/fontcustom/generator/font.rb +63 -65
- data/lib/fontcustom/generator/template.rb +81 -52
- data/lib/fontcustom/manifest.rb +42 -0
- data/lib/fontcustom/options.rb +93 -80
- data/lib/fontcustom/scripts/generate.py +116 -127
- data/lib/fontcustom/templates/_fontcustom-rails.scss +13 -18
- data/lib/fontcustom/templates/_fontcustom.scss +10 -18
- data/lib/fontcustom/templates/fontcustom-preview.html +17 -24
- data/lib/fontcustom/templates/fontcustom.css +10 -18
- data/lib/fontcustom/templates/fontcustom.yml +3 -3
- data/lib/fontcustom/utility.rb +145 -0
- data/lib/fontcustom/version.rb +1 -1
- data/lib/fontcustom/watcher.rb +1 -1
- data/spec/fixtures/generators/.fontcustom-manifest-corrupted.json +12 -5
- data/spec/fixtures/generators/.fontcustom-manifest-empty.json +0 -0
- data/spec/fixtures/generators/.fontcustom-manifest.json +49 -14
- data/spec/fixtures/generators/mixed-output/fontcustom_82a59e769bc60192484f2620570bbb59.eot +0 -0
- data/spec/fixtures/generators/mixed-output/fontcustom_82a59e769bc60192484f2620570bbb59.svg +56 -0
- data/spec/fixtures/generators/mixed-output/fontcustom_82a59e769bc60192484f2620570bbb59.ttf +0 -0
- data/spec/fixtures/generators/mixed-output/fontcustom_82a59e769bc60192484f2620570bbb59.woff +0 -0
- data/spec/fixtures/sandbox/.gitkeep +0 -0
- data/spec/fontcustom/base_spec.rb +58 -0
- data/spec/fontcustom/cli_spec.rb +15 -0
- data/spec/fontcustom/generator/font_spec.rb +50 -220
- data/spec/fontcustom/generator/template_spec.rb +30 -194
- data/spec/fontcustom/generator/template_spec.rb.off +215 -0
- data/spec/fontcustom/manifest_spec.rb +16 -0
- data/spec/fontcustom/options_spec.rb +206 -208
- data/spec/fontcustom/utility_spec.rb +163 -0
- data/spec/fontcustom/{watcher_spec.rb → watcher_spec.rb.off} +0 -0
- data/spec/spec_helper.rb +77 -19
- metadata +44 -54
- data/lib/fontcustom/templates/_fontcustom-bootstrap-ie7.scss +0 -22
- data/lib/fontcustom/templates/_fontcustom-bootstrap.scss +0 -63
- data/lib/fontcustom/templates/fontcustom-bootstrap-ie7.css +0 -22
- data/lib/fontcustom/templates/fontcustom-bootstrap.css +0 -63
- data/lib/fontcustom/util.rb +0 -62
- data/spec/fixtures/generators/mixed-output/fontcustom_cc5ce52f2ae4f9ce2e7ee8131bbfee1e.eot +0 -0
- data/spec/fixtures/generators/mixed-output/fontcustom_cc5ce52f2ae4f9ce2e7ee8131bbfee1e.svg +0 -102
- data/spec/fixtures/generators/mixed-output/fontcustom_cc5ce52f2ae4f9ce2e7ee8131bbfee1e.ttf +0 -0
- data/spec/fixtures/generators/mixed-output/fontcustom_cc5ce52f2ae4f9ce2e7ee8131bbfee1e.woff +0 -0
- data/spec/fontcustom/util_spec.rb +0 -82
@@ -1,138 +1,127 @@
|
|
1
1
|
import fontforge
|
2
2
|
import os
|
3
|
-
import md5
|
4
3
|
import subprocess
|
5
4
|
import tempfile
|
6
5
|
import json
|
7
6
|
|
7
|
+
#
|
8
|
+
# Manifest / Options
|
9
|
+
# Older Pythons don't have argparse, so we use optparse instead
|
10
|
+
#
|
11
|
+
|
8
12
|
try:
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
parser.add_argument('--autowidth', '-a', action='store_true', help='automatically size generated glyphs to their vector width')
|
14
|
-
parser.add_argument('--nohash', '-n', action='store_true', help='disable hash fingerprinting of font files')
|
15
|
-
parser.add_argument('--debug', '-d', action='store_true', help='display debug messages')
|
16
|
-
args = parser.parse_args()
|
17
|
-
indir = args.dir[0]
|
18
|
-
outdir = args.dir[1]
|
13
|
+
import argparse
|
14
|
+
parser = argparse.ArgumentParser()
|
15
|
+
parser.add_argument('manifest', help='Path to .fontcustom-manifest.json')
|
16
|
+
args = parser.parse_args()
|
19
17
|
except ImportError:
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
18
|
+
import optparse
|
19
|
+
parser = optparse.OptionParser()
|
20
|
+
parser.add_option('manifest', help='Path to .fontcustom-manifest.json')
|
21
|
+
(nothing, args) = parser.parse_args()
|
22
|
+
|
23
|
+
manifestfile = open(args.manifest, 'r+')
|
24
|
+
manifest = json.load(manifestfile)
|
25
|
+
options = manifest['options']
|
26
|
+
|
27
|
+
#
|
28
|
+
# Font
|
29
|
+
#
|
30
|
+
|
31
|
+
font = fontforge.font()
|
32
|
+
font.encoding = 'UnicodeFull'
|
33
|
+
font.design_size = 16
|
34
|
+
font.em = 512
|
35
|
+
font.ascent = 448
|
36
|
+
font.descent = 64
|
37
|
+
font.fontname = options['font_name']
|
38
|
+
font.familyname = options['font_name']
|
39
|
+
font.fullname = options['font_name']
|
40
|
+
if options['autowidth']:
|
41
|
+
font.autoWidth(0, 0, 512)
|
42
|
+
|
43
|
+
# NOTE not referenced anywhere, safe to remove?
|
42
44
|
KERNING = 15
|
43
45
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
# glyph.round()
|
84
|
-
|
85
|
-
# set glyph size explicitly or automatically depending on autowidth
|
86
|
-
if args.autowidth:
|
87
|
-
glyph.left_side_bearing = glyph.right_side_bearing = 0
|
88
|
-
glyph.round()
|
89
|
-
else:
|
90
|
-
# force a manual size when autowidth is disabled
|
91
|
-
glyph.width = 512
|
92
|
-
|
93
|
-
files.append(name)
|
94
|
-
cp += 1
|
95
|
-
|
96
|
-
# resize glyphs if autowidth is enabled
|
97
|
-
if args.autowidth:
|
98
|
-
f.autoWidth(0, 0, 512)
|
99
|
-
|
100
|
-
if args.nohash:
|
101
|
-
fontfile = outdir + '/' + args.name
|
102
|
-
else:
|
103
|
-
hashStr = m.hexdigest()
|
104
|
-
fontfile = outdir + '/' + args.name + '_' + hashStr
|
105
|
-
|
106
|
-
f.fontname = args.name
|
107
|
-
f.familyname = args.name
|
108
|
-
f.fullname = args.name
|
109
|
-
f.generate(fontfile + '.ttf')
|
110
|
-
f.generate(fontfile + '.svg')
|
111
|
-
|
112
|
-
# Fix SVG header for webkit
|
113
|
-
# from: https://github.com/fontello/font-builder/blob/master/bin/fontconvert.py
|
114
|
-
svgfile = open(fontfile + '.svg', 'r+')
|
115
|
-
svgtext = svgfile.read()
|
116
|
-
svgfile.seek(0)
|
117
|
-
svgfile.write(svgtext.replace('''<svg>''', '''<svg xmlns="http://www.w3.org/2000/svg">'''))
|
118
|
-
svgfile.close()
|
119
|
-
|
120
|
-
scriptPath = os.path.dirname(os.path.realpath(__file__))
|
46
|
+
#
|
47
|
+
# Glyphs
|
48
|
+
#
|
49
|
+
|
50
|
+
def removeSwitchFromSvg( file ):
|
51
|
+
svgfile = open(file, 'r+')
|
52
|
+
tmpsvgfile = tempfile.NamedTemporaryFile(suffix=".svg", delete=False)
|
53
|
+
svgtext = svgfile.read()
|
54
|
+
svgfile.seek(0)
|
55
|
+
svgtext = svgtext.replace('<switch>', '')
|
56
|
+
svgtext = svgtext.replace('</switch>', '')
|
57
|
+
tmpsvgfile.file.write(svgtext)
|
58
|
+
svgfile.close()
|
59
|
+
tmpsvgfile.file.close()
|
60
|
+
|
61
|
+
return tmpsvgfile.name
|
62
|
+
|
63
|
+
def createGlyph( name, source, code ):
|
64
|
+
frag, ext = os.path.splitext(source)
|
65
|
+
|
66
|
+
if ext == '.svg':
|
67
|
+
temp = removeSwitchFromSvg(source)
|
68
|
+
glyph = font.createChar(code)
|
69
|
+
glyph.importOutlines(temp)
|
70
|
+
os.unlink(temp)
|
71
|
+
|
72
|
+
if options['autowidth']:
|
73
|
+
glyph.left_side_bearing = glyph.right_side_bearing = 0
|
74
|
+
glyph.round()
|
75
|
+
else:
|
76
|
+
glyph.width = 512
|
77
|
+
|
78
|
+
for glyph, data in manifest['glyphs'].iteritems():
|
79
|
+
name = createGlyph(glyph, data['source'], data['codepoint'])
|
80
|
+
|
81
|
+
#
|
82
|
+
# Generate Files
|
83
|
+
#
|
84
|
+
|
121
85
|
try:
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
#
|
137
|
-
|
138
|
-
|
86
|
+
fontfile = options['output']['fonts'] + '/' + options['font_name']
|
87
|
+
if not options['no_hash']:
|
88
|
+
fontfile += '_' + manifest['checksum']['current'][:32]
|
89
|
+
|
90
|
+
# Generate TTF and SVG
|
91
|
+
font.generate(fontfile + '.ttf')
|
92
|
+
font.generate(fontfile + '.svg')
|
93
|
+
manifest['fonts'].append(fontfile + '.ttf')
|
94
|
+
manifest['fonts'].append(fontfile + '.svg')
|
95
|
+
|
96
|
+
# Hint the TTF file
|
97
|
+
subprocess.call('ttfautohint -s -f -n ' + fontfile + '.ttf ' + fontfile + '-hinted.ttf > /dev/null 2>&1 && mv ' + fontfile + '-hinted.ttf ' + fontfile + '.ttf', shell=True)
|
98
|
+
|
99
|
+
# Fix SVG header for webkit
|
100
|
+
# from: https://github.com/fontello/font-builder/blob/master/bin/fontconvert.py
|
101
|
+
svgfile = open(fontfile + '.svg', 'r+')
|
102
|
+
svgtext = svgfile.read()
|
103
|
+
svgfile.seek(0)
|
104
|
+
svgfile.write(svgtext.replace('''<svg>''', '''<svg xmlns="http://www.w3.org/2000/svg">'''))
|
105
|
+
svgfile.close()
|
106
|
+
|
107
|
+
# Convert WOFF
|
108
|
+
scriptPath = os.path.dirname(os.path.realpath(__file__))
|
109
|
+
try:
|
110
|
+
subprocess.Popen([scriptPath + '/sfnt2woff', fontfile + '.ttf'], stdout=subprocess.PIPE)
|
111
|
+
except OSError:
|
112
|
+
# If the local version of sfnt2woff fails (i.e., on Linux), try to use the
|
113
|
+
# global version. This allows us to avoid forcing OS X users to compile
|
114
|
+
# sfnt2woff from source, simplifying install.
|
115
|
+
subprocess.call(['sfnt2woff', fontfile + '.ttf'])
|
116
|
+
manifest['fonts'].append(fontfile + '.woff')
|
117
|
+
|
118
|
+
# Convert EOT for IE7
|
119
|
+
subprocess.call('python ' + scriptPath + '/eotlitetool.py ' + fontfile + '.ttf -o ' + fontfile + '.eot', shell=True)
|
120
|
+
subprocess.call('mv ' + fontfile + '.eotlite ' + fontfile + '.eot', shell=True)
|
121
|
+
manifest['fonts'].append(fontfile + '.eot')
|
122
|
+
|
123
|
+
finally:
|
124
|
+
manifestfile.seek(0)
|
125
|
+
manifestfile.write(json.dumps(manifest, indent=2, sort_keys=True))
|
126
|
+
manifestfile.truncate()
|
127
|
+
manifestfile.close()
|
@@ -1,28 +1,23 @@
|
|
1
1
|
//
|
2
|
-
// Icon Font: <%=
|
2
|
+
// Icon Font: <%= font_name %>
|
3
3
|
//
|
4
4
|
|
5
|
-
|
6
|
-
font-family: "<%= @opts.font_name %>";
|
7
|
-
src: font-url("<%= @font_path_alt %>.eot");
|
8
|
-
src: font-url("<%= @font_path_alt %>.eot?#iefix") format("embedded-opentype"),
|
9
|
-
font-url("<%= @font_path_alt %>.woff") format("woff"),
|
10
|
-
font-url("<%= @font_path_alt %>.ttf") format("truetype"),
|
11
|
-
font-url("<%= @font_path_alt %>.svg#<%= @opts.font_name %>") format("svg");
|
12
|
-
font-weight: normal;
|
13
|
-
font-style: normal;
|
14
|
-
}
|
5
|
+
<%= font_face(:rails) %>
|
15
6
|
|
16
|
-
|
17
|
-
|
7
|
+
[data-icon]:before { content: attr(data-icon); }
|
8
|
+
|
9
|
+
[data-icon]:before,
|
10
|
+
<%= glyph_selectors %> {
|
11
|
+
display: inline-block;
|
12
|
+
font-family: "<%= font_name %>";
|
18
13
|
font-style: normal;
|
19
14
|
font-weight: normal;
|
20
15
|
font-variant: normal;
|
21
|
-
text-transform: none;
|
22
16
|
line-height: 1;
|
23
|
-
-webkit-font-smoothing: antialiased;
|
24
|
-
display: inline-block;
|
25
17
|
text-decoration: inherit;
|
18
|
+
text-transform: none;
|
19
|
+
-moz-osx-font-smoothing: grayscale;
|
20
|
+
-webkit-font-smoothing: antialiased;
|
26
21
|
}
|
27
|
-
|
28
|
-
|
22
|
+
|
23
|
+
<%= glyphs %>
|
@@ -1,31 +1,23 @@
|
|
1
1
|
//
|
2
|
-
// Icon Font: <%=
|
2
|
+
// Icon Font: <%= font_name %>
|
3
3
|
//
|
4
4
|
|
5
|
-
|
6
|
-
font-family: "<%= @opts.font_name %>";
|
7
|
-
src: url("<%= @font_path_alt %>.eot");
|
8
|
-
src: url("<%= @font_path_alt %>.eot?#iefix") format("embedded-opentype"),
|
9
|
-
url("<%= @font_path_alt %>.woff") format("woff"),
|
10
|
-
url("<%= @font_path_alt %>.ttf") format("truetype"),
|
11
|
-
url("<%= @font_path_alt %>.svg#<%= @opts.font_name %>") format("svg");
|
12
|
-
font-weight: normal;
|
13
|
-
font-style: normal;
|
14
|
-
}
|
5
|
+
<%= font_face %>
|
15
6
|
|
16
7
|
[data-icon]:before { content: attr(data-icon); }
|
17
8
|
|
18
9
|
[data-icon]:before,
|
19
|
-
<%=
|
20
|
-
|
10
|
+
<%= glyph_selectors %> {
|
11
|
+
display: inline-block;
|
12
|
+
font-family: "<%= font_name %>";
|
21
13
|
font-style: normal;
|
22
14
|
font-weight: normal;
|
23
15
|
font-variant: normal;
|
24
|
-
text-transform: none;
|
25
16
|
line-height: 1;
|
26
|
-
-webkit-font-smoothing: antialiased;
|
27
|
-
display: inline-block;
|
28
17
|
text-decoration: inherit;
|
18
|
+
text-transform: none;
|
19
|
+
-moz-osx-font-smoothing: grayscale;
|
20
|
+
-webkit-font-smoothing: antialiased;
|
29
21
|
}
|
30
|
-
|
31
|
-
|
22
|
+
|
23
|
+
<%= glyphs %>
|
@@ -1,7 +1,7 @@
|
|
1
1
|
<% scale = %w|12 14 16 18 21 24 36 48 60 72| %><!DOCTYPE html>
|
2
2
|
<html>
|
3
3
|
<head>
|
4
|
-
<title><%=
|
4
|
+
<title><%= font_name %> glyphs preview</title>
|
5
5
|
|
6
6
|
<style>
|
7
7
|
/* Page Styles */
|
@@ -119,35 +119,27 @@
|
|
119
119
|
padding: 20px 0;
|
120
120
|
}
|
121
121
|
|
122
|
-
/* Icon Font: <%=
|
122
|
+
/* Icon Font: <%= font_name %> */
|
123
123
|
|
124
|
-
|
125
|
-
font-family: "<%= @opts.font_name %>";
|
126
|
-
src: url("<%= @font_path_preview %>.eot");
|
127
|
-
src: url("<%= @font_path_preview %>.eot?#iefix") format("embedded-opentype"),
|
128
|
-
url("<%= @font_path_preview %>.woff") format("woff"),
|
129
|
-
url("<%= @font_path_preview %>.ttf") format("truetype"),
|
130
|
-
url("<%= @font_path_preview %>.svg#<%= @opts.font_name %>") format("svg");
|
131
|
-
font-weight: normal;
|
132
|
-
font-style: normal;
|
133
|
-
}
|
124
|
+
<%= font_face(:preview) %>
|
134
125
|
|
135
126
|
[data-icon]:before { content: attr(data-icon); }
|
136
127
|
|
137
128
|
[data-icon]:before,
|
138
|
-
<%=
|
139
|
-
|
129
|
+
<%= glyph_selectors %> {
|
130
|
+
display: inline-block;
|
131
|
+
font-family: "<%= font_name %>";
|
140
132
|
font-style: normal;
|
141
133
|
font-weight: normal;
|
142
134
|
font-variant: normal;
|
143
|
-
text-transform: none;
|
144
135
|
line-height: 1;
|
145
|
-
-webkit-font-smoothing: antialiased;
|
146
|
-
display: inline-block;
|
147
136
|
text-decoration: inherit;
|
137
|
+
text-transform: none;
|
138
|
+
-moz-osx-font-smoothing: grayscale;
|
139
|
+
-webkit-font-smoothing: antialiased;
|
148
140
|
}
|
149
|
-
|
150
|
-
|
141
|
+
|
142
|
+
<%= glyphs %>
|
151
143
|
</style>
|
152
144
|
|
153
145
|
<!--[if lte IE 8]><script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script><![endif]-->
|
@@ -163,21 +155,22 @@
|
|
163
155
|
<body class="characters-off">
|
164
156
|
<div id="page" class="container">
|
165
157
|
<header>
|
166
|
-
<h1><%=
|
158
|
+
<h1><%= font_name %> contains <%= @glyphs.length %> glyphs:</h1>
|
167
159
|
<a onclick="toggleCharacters(); return false;" href="#">Toggle Preview Characters</a>
|
168
160
|
</header>
|
169
161
|
|
170
|
-
<% @glyphs.
|
162
|
+
<% @glyphs.each do |name, value|
|
163
|
+
selector = @options[:css_selector].sub('{{glyph}}', name.to_s) %>
|
171
164
|
<div class="glyph">
|
172
165
|
<div class="preview-glyphs">
|
173
|
-
<% scale.each do |n| %><span class="step size-<%= n %>"><span class="letters">Pp</span><i
|
166
|
+
<% scale.each do |n| %><span class="step size-<%= n %>"><span class="letters">Pp</span><i id="<%= selector[1..-1] %>" class="<%= selector[1..-1] %>"></i></span><% end %>
|
174
167
|
</div>
|
175
168
|
<div class="preview-scale">
|
176
169
|
<% scale.each do |n| %><span class="step"><%= n %></span><% end %>
|
177
170
|
</div>
|
178
171
|
<div class="usage">
|
179
|
-
<input class="class" type="text" readonly="readonly" onClick="this.select();" value="
|
180
|
-
<input class="point" type="text" readonly="readonly" onClick="this.select();" value="&#x<%=
|
172
|
+
<input class="class" type="text" readonly="readonly" onClick="this.select();" value="<%= selector %>" />
|
173
|
+
<input class="point" type="text" readonly="readonly" onClick="this.select();" value="&#x<%= value[:codepoint].to_s(16) %>;" />
|
181
174
|
</div>
|
182
175
|
</div>
|
183
176
|
<% end %>
|
@@ -1,31 +1,23 @@
|
|
1
1
|
/*
|
2
|
-
Icon Font: <%=
|
2
|
+
Icon Font: <%= font_name %>
|
3
3
|
*/
|
4
4
|
|
5
|
-
|
6
|
-
font-family: "<%= @opts.font_name %>";
|
7
|
-
src: url("<%= @font_path %>.eot");
|
8
|
-
src: url("<%= @font_path %>.eot?#iefix") format("embedded-opentype"),
|
9
|
-
url("<%= @font_path %>.woff") format("woff"),
|
10
|
-
url("<%= @font_path %>.ttf") format("truetype"),
|
11
|
-
url("<%= @font_path %>.svg#<%= @opts.font_name %>") format("svg");
|
12
|
-
font-weight: normal;
|
13
|
-
font-style: normal;
|
14
|
-
}
|
5
|
+
<%= font_face %>
|
15
6
|
|
16
7
|
[data-icon]:before { content: attr(data-icon); }
|
17
8
|
|
18
9
|
[data-icon]:before,
|
19
|
-
<%=
|
20
|
-
|
10
|
+
<%= glyph_selectors %> {
|
11
|
+
display: inline-block;
|
12
|
+
font-family: "<%= font_name %>";
|
21
13
|
font-style: normal;
|
22
14
|
font-weight: normal;
|
23
15
|
font-variant: normal;
|
24
|
-
text-transform: none;
|
25
16
|
line-height: 1;
|
26
|
-
-webkit-font-smoothing: antialiased;
|
27
|
-
display: inline-block;
|
28
17
|
text-decoration: inherit;
|
18
|
+
text-transform: none;
|
19
|
+
-moz-osx-font-smoothing: grayscale;
|
20
|
+
-webkit-font-smoothing: antialiased;
|
29
21
|
}
|
30
|
-
|
31
|
-
|
22
|
+
|
23
|
+
<%= glyphs %>
|