fontcustom 1.2.0 → 1.3.0.beta
Sign up to get free protection for your applications and to get access to all the features.
- 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 %>
|