forked from numixproject/numix-tools
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathnumix-helper.rb
executable file
·251 lines (216 loc) · 7.16 KB
/
numix-helper.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
#!/usr/bin/env ruby
# Dependencies:
# - json
# - color
# - commander
require 'json'
require 'color'
require 'commander/import'
SHAPES = %w(circle square)
def notify_send message
`notify-send -i numix '#{message}'`
end
program :name, 'Numix Helper'
program :version, '0.0.1'
program :description, 'Helper scripts for Numix icon development'
program :help, 'Author', 'Mészáros Máté Róbert <[email protected]>'
global_option('-n', '--notify', 'Send OS notification when the command finished')
global_option('-V', '--verbose', 'Show detailed command output')
default_command :help
def git_current_branch_name
branch_name = `git rev-parse --abbrev-ref HEAD`.strip
if branch_name == 'HEAD'
raise 'Currently not on a branch! Please specify the icon name'
else
branch_name
end
end
def puts_color color, fmt
puts fmt % {rgb: color.to_rgb.hex, hsl: color.css_hsl}
end
def calc_value base, change
if change =~ /^[+-]/
base + change.to_f
else
change.to_f
end
end
command :color do |c|
c.syntax = 'numix color HEX_COLORS...'
c.option '-H', '--hue=H', String, 'Rotate the hue by the given amount (0-360)'
c.option '-S', '--saturation=S', String, 'Change the saturation by the given amount (0-100)'
c.option '-L', '--luminosity=L', String, 'Change the luminosity by the given amount (0-100)'
c.option '-f', '--format=FORMAT', String, 'Format the output with the given ruby format string'
c.action do |args, options|
options.default :format => '| #%{rgb} | %{hsl} |'
args.each do |color|
hsl = Color::RGB.by_hex(color).to_hsl
puts_color hsl, options.format
hsl.hue = calc_value(hsl.hue, options.hue) if options.hue
hsl.saturation = calc_value(hsl.saturation, options.saturation) if options.saturation
hsl.luminosity = calc_value(hsl.luminosity, options.luminosity) if options.luminosity
puts_color hsl, options.format
end
end
end
command :blend do |c|
c.syntax = 'numix blend COLOR1 COLOR2 [options]'
c.option '-f', '--format=FORMAT', String, 'Format the output with the given ruby format string'
c.option '-r', '--ratio=RATIO', Array, 'Use given ratios to blend the colors'
c.action do |args, options|
options.default :format => '| %{r} | %{rgb} | %{hsl} |', :ratio => [0.5]
if args.size != 2
puts "[ERROR]: The blend command expects exactly 2 arguments!"
else
c1 = Color::RGB.by_hex(args[0]).to_hsl
c2 = Color::RGB.by_hex(args[1]).to_hsl
options.ratio.each do |r|
mixture = c1.mix_with(c2, r.to_f)
puts options.format % {r: r, rgb: mixture.to_rgb.hex, hsl: mixture.css_hsl}
end
end
end
end
command :setup do |c|
c.syntax = 'numix setup ICON_NAME [options]'
c.description = 'Set up links for a new icon'
c.option '-r', '--rename LINK_NAME', String, 'Rename the link (Defaults to ICON_NAME)'
c.option '-b', '--branch', 'Create git branch named LINK_NAME if not yet created'
c.action do |args, options|
if args.size < 1
puts 'Argument ICON_NAME missing. See command syntax:'
puts c.syntax
exit
end
icon_name = args.first
link_name = options.rename || icon_name
`git checkout -b #{link_name}` if options.branch && `git branch --list #{link_name}`.empty?
Dir.mkdir('ln') unless File.directory?('ln')
SHAPES.each do |shape|
target = "icons/#{shape}/48/#{icon_name}.svg"
`cp templates/#{shape}/48.svg #{target}` unless File.file? target
`ln -s ../#{target} ln/#{link_name}.#{shape}.svg`
end
notify_send 'Setup finished!' if options.notify
end
end
DATA_JSON = 'data.json'
class Hash
def sorted!
self.keys.sort_by{ |k| k.downcase }.each { |k| self[k] = self.delete k }
end
end
class Array
def insert_sorted item
idx = (0...self.size).bsearch{ |i| item.downcase < self[i].downcase } || self.size
self.insert idx, item
end
end
class IconEntry
def initialize entry
@hash = entry
end
def linux icon
unless @hash.include? 'linux'
@hash['linux'] = { 'root' => icon }
@hash.sorted!
else
@hash['linux']['symlinks'] = [] unless @hash['linux'].include? 'symlinks'
@hash['linux']['symlinks'].insert_sorted icon
end
end
def android icon
unless @hash.include? 'android'
@hash['android'] = []
@hash.sorted!
end
@hash['android'].insert_sorted icon
end
end
class IconData
def initialize file
@file = file
@data = JSON[File.read file]
end
def [] icon
@data[icon] = {} unless @data.include? icon
IconEntry.new @data[icon]
end
def rename old_name, new_name
@data[new_name] = @data.delete old_name
end
def save!
@data = @data.sort_by{ |k,v| k.downcase }.to_h
json = JSON.pretty_generate @data, indent: " "
File.open(@file, 'w') { |file| file.write(json + "\n") }
end
end
command :data do |c|
c.syntax = 'numix data ICON_NAME [options]'
c.description = 'Add data entry for the icon'
c.option '-l', '--linux=ENTRY', String, 'Add linux entry (root or symlink)'
c.option '-a', '--android=ENTRY', String, 'Add android entry (root or symlink)'
c.option '-r', '--rename=ICON_NAME', String, 'Rename the data entry base name'
c.action do |args, options|
icon_name = args.first || git_current_branch_name
if options.linux or options.android or options.rename
data = IconData.new DATA_JSON
data[icon_name].linux options.linux if options.linux
data[icon_name].android options.android if options.android
data.rename icon_name, options.rename if options.rename
data.save!
end
end
end
command :render do |c|
c.syntax = 'numix render ICON_NAME... [options]'
c.description = 'Render svg icons to raster images (png)'
c.option '-s', '--size SIZES', Array, 'Specify the resolution of the raster.'
c.option '-S', '--shapes SHAPES', Array, 'Specify the shapes for which to render.'
c.option '-b', '--bundle', 'Create bundle images with all the shapes'
c.option '-q', '--quiet', 'Diable all unnecessary program output'
c.action do |icon_names, options|
options.default :size => [48], :shapes => SHAPES
sizes = options.size.map(&:to_i).sort.reverse
icon_names = [git_current_branch_name] if icon_names.size < 1
icon_names.each do |icon_name|
puts "Rendering '#{icon_name}' ..." unless options.quiet
pngs = sizes.map{ |s| [s, []] }.to_h
sizes.each do |size|
options.shapes.each do |shape|
svg = "icons/#{shape}/48/#{icon_name}.svg"
png = "#{icon_name}.#{shape}.#{size}.png"
if File.file? svg
inkscape_output = `inkscape #{svg} -o #{png} -w #{size} 2>&1`
if options.verbose
puts inkscape_output
end
puts "... [DONE] #{png}" unless options.quiet
pngs[size].push png
else
puts "... [MISS] #{svg}" unless options.quiet
end
end
end
if options.bundle
parts = []
sizes.each do |size|
source = pngs[size].join(' ')
target = "#{icon_name}.#{size}.png"
padding = (sizes.max - size) / 2.0
`convert #{source} -bordercolor none -border #{padding}x4 -rotate 90 -append -rotate -90 #{target}`
puts "... [BUNDLE] #{target}" unless options.quiet
parts.push target
end
if 1 < sizes.size
source = parts.join(' ')
target = "#{icon_name}.#{sizes.join('-')}.png"
`convert #{source} -append #{target}`
puts "... [BUNDLE] #{target}" unless options.quiet
`rm #{source}` if options
end
end
end
notify_send 'Rendering finished!' if options.notify
end
end