Commit c3af0e64cc4c248d7e88d4241a0f5dfb1b43bf2d
1 parent
1ada3506
Exists in
master
init
Showing
9 changed files
with
476 additions
and
0 deletions
Show diff stats
... | ... | @@ -0,0 +1,31 @@ |
1 | +*.rbc | |
2 | +capybara-*.html | |
3 | +.rspec | |
4 | +/log | |
5 | +/tmp | |
6 | +/db/*.sqlite3 | |
7 | +/public/system | |
8 | +/coverage/ | |
9 | +/spec/tmp | |
10 | +**.orig | |
11 | +rerun.txt | |
12 | +pickle-email-*.html | |
13 | + | |
14 | +# TODO Comment out these rules if you are OK with secrets being uploaded to the repo | |
15 | +config/initializers/secret_token.rb | |
16 | +config/secrets.yml | |
17 | + | |
18 | +## Environment normalisation: | |
19 | +/.bundle | |
20 | +/vendor/bundle | |
21 | + | |
22 | +# these should all be checked in to normalise the environment: | |
23 | +# Gemfile.lock, .ruby-version, .ruby-gemset | |
24 | + | |
25 | +# unless supporting rvm < 1.11.0 or doing something fancy, ignore this: | |
26 | +.rvmrc | |
27 | + | |
28 | +# if using bower-rails ignore default bower_components path bower.json files | |
29 | +/vendor/assets/bower_components | |
30 | +*.bowerrc | |
31 | +bower.json | ... | ... |
... | ... | @@ -0,0 +1,22 @@ |
1 | +Copyright (c) 2014 Krzysiek Szczuka | |
2 | + | |
3 | +MIT License | |
4 | + | |
5 | +Permission is hereby granted, free of charge, to any person obtaining | |
6 | +a copy of this software and associated documentation files (the | |
7 | +"Software"), to deal in the Software without restriction, including | |
8 | +without limitation the rights to use, copy, modify, merge, publish, | |
9 | +distribute, sublicense, and/or sell copies of the Software, and to | |
10 | +permit persons to whom the Software is furnished to do so, subject to | |
11 | +the following conditions: | |
12 | + | |
13 | +The above copyright notice and this permission notice shall be | |
14 | +included in all copies or substantial portions of the Software. | |
15 | + | |
16 | +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |
17 | +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |
18 | +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | |
19 | +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE | |
20 | +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION | |
21 | +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION | |
22 | +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ... | ... |
... | ... | @@ -0,0 +1,29 @@ |
1 | +# LetterAvatar | |
2 | + | |
3 | +TODO: Write a gem description | |
4 | + | |
5 | +## Installation | |
6 | + | |
7 | +Add this line to your application's Gemfile: | |
8 | + | |
9 | + gem 'letter_avatar' | |
10 | + | |
11 | +And then execute: | |
12 | + | |
13 | + $ bundle | |
14 | + | |
15 | +Or install it yourself as: | |
16 | + | |
17 | + $ gem install letter_avatar | |
18 | + | |
19 | +## Usage | |
20 | + | |
21 | +TODO: Write usage instructions here | |
22 | + | |
23 | +## Contributing | |
24 | + | |
25 | +1. Fork it | |
26 | +2. Create your feature branch (`git checkout -b my-new-feature`) | |
27 | +3. Commit your changes (`git commit -am 'Add some feature'`) | |
28 | +4. Push to the branch (`git push origin my-new-feature`) | |
29 | +5. Create new Pull Request | ... | ... |
... | ... | @@ -0,0 +1 @@ |
1 | +require "bundler/gem_tasks" | ... | ... |
... | ... | @@ -0,0 +1,26 @@ |
1 | +# coding: utf-8 | |
2 | +lib = File.expand_path('../lib', __FILE__) | |
3 | +$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) | |
4 | +require 'letter_avatar/version' | |
5 | + | |
6 | +Gem::Specification.new do |spec| | |
7 | + spec.name = "letter_avatar" | |
8 | + spec.version = LetterAvatar::VERSION | |
9 | + spec.authors = ["Krzysiek Szczuka"] | |
10 | + spec.email = ["kszczuka@gmail.com"] | |
11 | + spec.description = %q{TODO: Write a gem description} | |
12 | + spec.summary = %q{TODO: Write a gem summary} | |
13 | + spec.homepage = "" | |
14 | + spec.license = "MIT" | |
15 | + | |
16 | + spec.rubyforge_project = "letter_avatar" | |
17 | + | |
18 | + spec.files = `git ls-files`.split($/) | |
19 | + spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) } | |
20 | + spec.test_files = spec.files.grep(%r{^(test|spec|features)/}) | |
21 | + spec.require_paths = ["lib"] | |
22 | + | |
23 | + spec.add_development_dependency "bundler", "~> 1.3" | |
24 | + spec.add_development_dependency "rake" | |
25 | + spec.add_development_dependency "image_optim" | |
26 | +end | ... | ... |
... | ... | @@ -0,0 +1,260 @@ |
1 | +require "letter_avatar/version" | |
2 | +require "letter_avatar/avatar" | |
3 | + | |
4 | +module LetterAvatar | |
5 | + | |
6 | + mattr_accessor :cache_path | |
7 | + @@cache_path = '' | |
8 | + | |
9 | + def self.setup(&block) | |
10 | + yield(self) | |
11 | + end | |
12 | + | |
13 | + def self.resize(from, to, width, height) | |
14 | + # NOTE: ORDER is important! | |
15 | + instructions = %W{ | |
16 | + #{from} | |
17 | + -background transparent | |
18 | + -gravity center | |
19 | + -thumbnail #{width}x#{height}^ | |
20 | + -extent #{width}x#{height} | |
21 | + -interpolate bicubic | |
22 | + -unsharp 2x0.5+0.7+0 | |
23 | + -quality 98 | |
24 | + #{to} | |
25 | + }.join(" ") | |
26 | + | |
27 | + `convert #{instructions}` | |
28 | + | |
29 | + if $?.exitstatus == 0 | |
30 | + ImageOptim.new.optimize_image(to) rescue nil | |
31 | + true | |
32 | + else | |
33 | + false | |
34 | + end | |
35 | + end | |
36 | + | |
37 | + # palette of optimally disctinct colors | |
38 | + # cf. http://tools.medialab.sciences-po.fr/iwanthue/index.php | |
39 | + # parameters used: | |
40 | + # - H: 0 - 360 | |
41 | + # - C: 0 - 2 | |
42 | + # - L: 0.75 - 1.5 | |
43 | + COLORS = [[198,125,40], | |
44 | + [61,155,243], | |
45 | + [74,243,75], | |
46 | + [238,89,166], | |
47 | + [52,240,224], | |
48 | + [177,156,155], | |
49 | + [240,120,145], | |
50 | + [111,154,78], | |
51 | + [237,179,245], | |
52 | + [237,101,95], | |
53 | + [89,239,155], | |
54 | + [43,254,70], | |
55 | + [163,212,245], | |
56 | + [65,152,142], | |
57 | + [165,135,246], | |
58 | + [181,166,38], | |
59 | + [187,229,206], | |
60 | + [77,164,25], | |
61 | + [179,246,101], | |
62 | + [234,93,37], | |
63 | + [225,155,115], | |
64 | + [142,140,188], | |
65 | + [223,120,140], | |
66 | + [249,174,27], | |
67 | + [244,117,225], | |
68 | + [137,141,102], | |
69 | + [75,191,146], | |
70 | + [188,239,142], | |
71 | + [164,199,145], | |
72 | + [173,120,149], | |
73 | + [59,195,89], | |
74 | + [222,198,220], | |
75 | + [68,145,187], | |
76 | + [236,204,179], | |
77 | + [159,195,72], | |
78 | + [188,121,189], | |
79 | + [166,160,85], | |
80 | + [181,233,37], | |
81 | + [236,177,85], | |
82 | + [121,147,160], | |
83 | + [234,218,110], | |
84 | + [241,157,191], | |
85 | + [62,200,234], | |
86 | + [133,243,34], | |
87 | + [88,149,110], | |
88 | + [59,228,248], | |
89 | + [183,119,118], | |
90 | + [251,195,45], | |
91 | + [113,196,122], | |
92 | + [197,115,70], | |
93 | + [80,175,187], | |
94 | + [103,231,238], | |
95 | + [240,72,133], | |
96 | + [228,149,241], | |
97 | + [180,188,159], | |
98 | + [172,132,85], | |
99 | + [180,135,251], | |
100 | + [236,194,58], | |
101 | + [217,176,109], | |
102 | + [88,244,199], | |
103 | + [186,157,239], | |
104 | + [113,230,96], | |
105 | + [206,115,165], | |
106 | + [244,178,163], | |
107 | + [230,139,26], | |
108 | + [241,125,89], | |
109 | + [83,160,66], | |
110 | + [107,190,166], | |
111 | + [197,161,210], | |
112 | + [198,203,245], | |
113 | + [238,117,19], | |
114 | + [228,119,116], | |
115 | + [131,156,41], | |
116 | + [145,178,168], | |
117 | + [139,170,220], | |
118 | + [233,95,125], | |
119 | + [87,178,230], | |
120 | + [157,200,119], | |
121 | + [237,140,76], | |
122 | + [229,185,186], | |
123 | + [144,206,212], | |
124 | + [236,209,158], | |
125 | + [185,189,79], | |
126 | + [34,208,66], | |
127 | + [84,238,129], | |
128 | + [133,140,134], | |
129 | + [67,157,94], | |
130 | + [168,179,25], | |
131 | + [140,145,240], | |
132 | + [151,241,125], | |
133 | + [67,162,107], | |
134 | + [200,156,21], | |
135 | + [169,173,189], | |
136 | + [226,116,189], | |
137 | + [133,231,191], | |
138 | + [194,161,63], | |
139 | + [241,77,99], | |
140 | + [241,217,53], | |
141 | + [123,204,105], | |
142 | + [210,201,119], | |
143 | + [229,108,155], | |
144 | + [240,91,72], | |
145 | + [187,115,210], | |
146 | + [240,163,100], | |
147 | + [178,217,57], | |
148 | + [179,135,116], | |
149 | + [204,211,24], | |
150 | + [186,135,57], | |
151 | + [223,176,135], | |
152 | + [204,148,151], | |
153 | + [116,223,50], | |
154 | + [95,195,46], | |
155 | + [123,160,236], | |
156 | + [181,172,131], | |
157 | + [142,220,202], | |
158 | + [240,140,112], | |
159 | + [172,145,164], | |
160 | + [228,124,45], | |
161 | + [135,151,243], | |
162 | + [42,205,125], | |
163 | + [192,233,116], | |
164 | + [119,170,114], | |
165 | + [158,138,26], | |
166 | + [73,190,183], | |
167 | + [185,229,243], | |
168 | + [227,107,55], | |
169 | + [196,205,202], | |
170 | + [132,143,60], | |
171 | + [233,192,237], | |
172 | + [62,150,220], | |
173 | + [205,201,141], | |
174 | + [106,140,190], | |
175 | + [161,131,205], | |
176 | + [135,134,158], | |
177 | + [198,139,81], | |
178 | + [115,171,32], | |
179 | + [101,181,67], | |
180 | + [149,137,119], | |
181 | + [37,142,183], | |
182 | + [183,130,175], | |
183 | + [168,125,133], | |
184 | + [124,142,87], | |
185 | + [236,156,171], | |
186 | + [232,194,91], | |
187 | + [219,200,69], | |
188 | + [144,219,34], | |
189 | + [219,95,187], | |
190 | + [145,154,217], | |
191 | + [165,185,100], | |
192 | + [127,238,163], | |
193 | + [224,178,198], | |
194 | + [119,153,120], | |
195 | + [124,212,92], | |
196 | + [172,161,105], | |
197 | + [231,155,135], | |
198 | + [157,132,101], | |
199 | + [122,185,146], | |
200 | + [53,166,51], | |
201 | + [70,163,90], | |
202 | + [150,190,213], | |
203 | + [210,107,60], | |
204 | + [166,152,185], | |
205 | + [159,194,159], | |
206 | + [39,141,222], | |
207 | + [202,176,161], | |
208 | + [95,140,229], | |
209 | + [168,142,87], | |
210 | + [93,170,203], | |
211 | + [159,142,54], | |
212 | + [14,168,39], | |
213 | + [94,150,149], | |
214 | + [187,206,136], | |
215 | + [157,224,166], | |
216 | + [235,158,208], | |
217 | + [109,232,216], | |
218 | + [141,201,87], | |
219 | + [208,124,118], | |
220 | + [142,125,214], | |
221 | + [19,237,174], | |
222 | + [72,219,41], | |
223 | + [234,102,111], | |
224 | + [168,142,79], | |
225 | + [188,135,35], | |
226 | + [95,155,143], | |
227 | + [148,173,116], | |
228 | + [223,112,95], | |
229 | + [228,128,236], | |
230 | + [206,114,54], | |
231 | + [195,119,88], | |
232 | + [235,140,94], | |
233 | + [235,202,125], | |
234 | + [233,155,153], | |
235 | + [214,214,238], | |
236 | + [246,200,35], | |
237 | + [151,125,171], | |
238 | + [132,145,172], | |
239 | + [131,142,118], | |
240 | + [199,126,150], | |
241 | + [61,162,123], | |
242 | + [58,176,151], | |
243 | + [215,141,69], | |
244 | + [225,154,220], | |
245 | + [220,77,167], | |
246 | + [233,161,64], | |
247 | + [130,221,137], | |
248 | + [81,191,129], | |
249 | + [169,162,140], | |
250 | + [174,177,222], | |
251 | + [236,174,47], | |
252 | + [233,188,180], | |
253 | + [69,222,172], | |
254 | + [71,232,93], | |
255 | + [118,211,238], | |
256 | + [157,224,83], | |
257 | + [218,105,73], | |
258 | + [126,169,36]] | |
259 | + | |
260 | +end | ... | ... |
... | ... | @@ -0,0 +1,100 @@ |
1 | +module LetterAvatar | |
2 | + class Avatar | |
3 | + | |
4 | + # BUMP UP if avatar algorithm changes | |
5 | + VERSION = 2 | |
6 | + | |
7 | + # Largest avatar generated, one day when pixel ratio hit 3 | |
8 | + # we will need to change this | |
9 | + FULLSIZE = 240 | |
10 | + | |
11 | + class<<self | |
12 | + | |
13 | + class Identity | |
14 | + attr_accessor :color, :letter | |
15 | + | |
16 | + def self.from_username(username) | |
17 | + identity = new | |
18 | + identity.color = LetterAvatar::COLORS[ | |
19 | + Digest::MD5.hexdigest(username)[0...15].to_i(16) % LetterAvatar::COLORS.length | |
20 | + ] | |
21 | + identity.letter = username[0].upcase | |
22 | + | |
23 | + identity | |
24 | + end | |
25 | + end | |
26 | + | |
27 | + | |
28 | + def cache_path | |
29 | + LetterAvatar.cache_path || "public/system/letter_avatars/#{VERSION}" | |
30 | + end | |
31 | + | |
32 | + def generate(username, size, opts = nil) | |
33 | + identity = Identity.from_username(username) | |
34 | + | |
35 | + cache = true | |
36 | + cache = false if opts && opts[:cache] == false | |
37 | + | |
38 | + size = FULLSIZE if size > FULLSIZE | |
39 | + filename = cached_path(identity, size) | |
40 | + | |
41 | + return filename if cache && File.exists?(filename) | |
42 | + | |
43 | + fullsize = fullsize_path(identity) | |
44 | + generate_fullsize(identity) if !cache || !File.exists?(fullsize) | |
45 | + | |
46 | + OptimizedImage.resize(fullsize, filename, size, size) | |
47 | + filename | |
48 | + end | |
49 | + | |
50 | + def cached_path(identity, size) | |
51 | + dir = "#{cache_path}/#{identity.letter}/#{identity.color.join("_")}" | |
52 | + FileUtils.mkdir_p(dir) | |
53 | + | |
54 | + "#{dir}/#{size}.png" | |
55 | + end | |
56 | + | |
57 | + def fullsize_path(identity) | |
58 | + cached_path(identity, FULLSIZE) | |
59 | + end | |
60 | + | |
61 | + def generate_fullsize(identity) | |
62 | + color = identity.color | |
63 | + letter = identity.letter | |
64 | + | |
65 | + filename = fullsize_path(identity) | |
66 | + stroke = darken(color, 0.8) | |
67 | + | |
68 | + instructions = %W{ | |
69 | + -size 240x240 | |
70 | + xc:#{to_rgb(color)} | |
71 | + -pointsize 200 | |
72 | + -fill white | |
73 | + -gravity Center | |
74 | + -font 'Helvetica' | |
75 | + -stroke #{to_rgb(stroke)} | |
76 | + -strokewidth 2 | |
77 | + -annotate -5+25 '#{letter}' | |
78 | + '#{filename}' | |
79 | + } | |
80 | + | |
81 | + `convert #{instructions.join(" ")}` | |
82 | + | |
83 | + ImageOptim.new.optimize_image(filename) rescue nil | |
84 | + | |
85 | + filename | |
86 | + end | |
87 | + | |
88 | + def darken(color,pct) | |
89 | + color.map do |n| | |
90 | + (n.to_f * pct).to_i | |
91 | + end | |
92 | + end | |
93 | + | |
94 | + def to_rgb(color) | |
95 | + r,g,b = color | |
96 | + "'rgb(#{r},#{g},#{b})'" | |
97 | + end | |
98 | + end | |
99 | + end | |
100 | +end | ... | ... |