letter_avatar_simple 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: eac1036d24e2ef091716b9c981800abf0e3e1175dd2ef724b49946f2f182e730
4
+ data.tar.gz: e24eb2f56ab42e46cce77a076555248bc6bbfae55f8ec9b853473bcdc9b8fa21
5
+ SHA512:
6
+ metadata.gz: 98f2beed0d5932e6b6fef70b9c4b6aa01d211655a9550942a28c15020c08a5a11e954dc66b8411b1903c87cbd815c33a736a683c316e2834525a1e4b5fd9a341
7
+ data.tar.gz: 31fc21b791a0ef895dca8236af35176b3b9062ce21e5dd58c8a12fb80be7167dc3ea34d6e1c125c3bcb9118132f079aac142de3021192c8d1c6948c01d14e000
@@ -0,0 +1,11 @@
1
+ 0.9.1
2
+ -----
3
+
4
+ - Add keyword argument support to generate method
5
+ - Simplify custom palette specification
6
+ - Improve documentation
7
+
8
+ 0.9.0
9
+ -----
10
+
11
+ - Initial release
@@ -0,0 +1,327 @@
1
+ # LetterAvatarSimple
2
+
3
+ Generate letter image avatars based on user initials.
4
+
5
+ ## Usage
6
+
7
+ ```ruby
8
+ LetterAvatarSimple.generate("foobar")
9
+ # => #<StringIO:0x000055b3804948a8>
10
+ ```
11
+
12
+ <img src="./examples/readme/F.png" alt='Image of letter "F"' width="64" height="64" />
13
+
14
+ ------------
15
+
16
+ We can do multiple letters:
17
+
18
+ ```ruby
19
+ LetterAvatarSimple.generate("Dallas Smith")
20
+ # => #<StringIO:0x000055b380e6a058>
21
+ ```
22
+
23
+ <img src="./examples/readme/DS.png" alt='Image of letters "DS"' width="64" height="64" />
24
+
25
+ ------------
26
+
27
+ We can save to a file:
28
+
29
+ ```ruby
30
+ LetterAvatarSimple.generate_file("Dallas Smith")
31
+ # => #<File:/tmp/x20190527-19344-79m629.png>
32
+
33
+ LetterAvatarSimple.generate_file("Dallas Smith", filename: "/tmp/dallas.png")
34
+ # => #<File:/tmp/dallas.png>
35
+ ```
36
+
37
+ ------------
38
+
39
+ We can specify the initials using `LetterAvatarSimple::Identity`:
40
+
41
+ ```ruby
42
+ i = LetterAvatarSimple::Identity.new("ZZ", "Dallas Smith")
43
+ LetterAvatarSimple.generate(i)
44
+ ```
45
+
46
+ <img src="./examples/readme/ZZ-1.png" alt='Image of letters "ZZ" in green' width="64" height="64" />
47
+
48
+ ------------
49
+
50
+ Image color is chosen from a palette based on username, so the same initials
51
+ will (most likely) not share the same color:
52
+
53
+ ```ruby
54
+ i = LetterAvatarSimple::Identity.new("ZZ", "foobar")
55
+ LetterAvatarSimple.generate(i)
56
+ ```
57
+
58
+ <img src="./examples/readme/ZZ-2.png" alt='Image of letters "ZZ" in pink' width="64" height="64" />
59
+
60
+ ------------
61
+
62
+ The default palette is based on Google Inbox. You can change palettes:
63
+
64
+ ```ruby
65
+ LetterAvatarSimple.generate("foobar", palette: :i_want_hue)
66
+ ```
67
+
68
+ <img src="./examples/readme/F-i_want_hue.png" alt='Image of letter "F"' width="64" height="64" />
69
+
70
+ ------------
71
+
72
+ Or skip the palette feature and provide the desired color directly, in RGB tuple format:
73
+
74
+ ```ruby
75
+ LetterAvatarSimple.generate("foobar", color: [255,0,0])
76
+ ```
77
+
78
+ <img src="./examples/readme/F-red.png" alt='Image of letter "F"' width="64" height="64" />
79
+
80
+ ------------
81
+
82
+ Other options that can be provided to customize image generation:
83
+
84
+ ```ruby
85
+ LetterAvatarSimple.generate(
86
+ "foobar",
87
+ size: 256, # => default 1024
88
+ palette: :i_want_hue, # => default :google
89
+ # warning: this bypasses the palette's color selection
90
+ color: [255, 0, 0] # => default nil
91
+ pointsize: 150, # => default 600
92
+ font: "/tmp/path/to/font/file", # => default is path to included Roboto font
93
+ weight: 500, # => default 300
94
+ fill_color: "rgba(255, 255, 255, 1)", # => default "rgba(255, 255, 255, 0.65)"
95
+ annotate_position: "-0+10", # => default "-0+5"
96
+ filename: "/tmp/foo.png", # => default is randomly generated tempfile path
97
+ )
98
+ ```
99
+
100
+ ## About
101
+
102
+ Forked from [letter_avatar][], which was in turn extracted from [Discourse][].
103
+
104
+ Compared to [letter_avatar][], this gem:
105
+ * Outputs `StringIO` binary data by default (but can write to files too!)
106
+ instead of always writing files to the `public` directory. This way you can
107
+ use image upload gems like [shrine][] much easier
108
+ * Supports keyword arguments for generating each image (don't need to edit
109
+ global config or constants)
110
+ * Simplifies custom palette loading and supports multiple custom palettes
111
+ * Uses [minimagick][] instead of homegrown ImageMagick shell execution
112
+ * Does **not** come with model, view, or controller helpers (you should
113
+ be using [shrine][])
114
+ * Does **not** do caching (you should be using [shrine][])
115
+
116
+ ## Installation
117
+
118
+ ```ruby
119
+ gem "letter_avatar_simple"
120
+ ```
121
+
122
+ ## System requirements
123
+
124
+ ImageMagick or GraphicsMagick - see
125
+ [MiniMagick requirements](https://github.com/minimagick/minimagick#requirements)
126
+
127
+ ## Color palettes
128
+
129
+ Two color palettes are provided by default: `:google` and `:i_want_hue`
130
+
131
+ Both palettes use an MD5 digest of the username to select the color, so it's
132
+ likely that two different usernames that share the same initial(s) will render
133
+ with different colors.
134
+
135
+ If you need the same initials to always render with the same color, simply
136
+ provide a custom palette using a customized `letter_color` method. See below
137
+ for an example.
138
+
139
+ ### `:google` - Google Inbox palette
140
+
141
+ <!--
142
+ alphabet = ("A".."Z").cycle
143
+
144
+ pairs = LetterAvatarSimple::Palettes::Google::PALETTE.zip(alphabet)
145
+
146
+ pairs.each do |color,letter|
147
+ filename = "./examples/readme/google-palette/#{letter}.png"
148
+ LetterAvatarSimple.generate_file(
149
+ letter,
150
+ color: color,
151
+ filename: filename,
152
+ size: 64,
153
+ pointsize: 37.5,
154
+ annotate_position: "-0+0"
155
+ )
156
+ end
157
+ -->
158
+
159
+ <div>
160
+ <img src="./examples/readme/google-palette/A.png" alt='Image of letter "A"' width="64" height="64" />
161
+ <img src="./examples/readme/google-palette/B.png" alt='Image of letter "B"' width="64" height="64" />
162
+ <img src="./examples/readme/google-palette/C.png" alt='Image of letter "C"' width="64" height="64" />
163
+ <img src="./examples/readme/google-palette/D.png" alt='Image of letter "D"' width="64" height="64" />
164
+ <img src="./examples/readme/google-palette/E.png" alt='Image of letter "E"' width="64" height="64" />
165
+ <img src="./examples/readme/google-palette/F.png" alt='Image of letter "F"' width="64" height="64" />
166
+ <img src="./examples/readme/google-palette/G.png" alt='Image of letter "G"' width="64" height="64" />
167
+ <img src="./examples/readme/google-palette/H.png" alt='Image of letter "H"' width="64" height="64" />
168
+ <img src="./examples/readme/google-palette/I.png" alt='Image of letter "I"' width="64" height="64" />
169
+ <img src="./examples/readme/google-palette/J.png" alt='Image of letter "J"' width="64" height="64" />
170
+ <img src="./examples/readme/google-palette/K.png" alt='Image of letter "K"' width="64" height="64" />
171
+ <img src="./examples/readme/google-palette/L.png" alt='Image of letter "L"' width="64" height="64" />
172
+ <img src="./examples/readme/google-palette/M.png" alt='Image of letter "M"' width="64" height="64" />
173
+ <img src="./examples/readme/google-palette/N.png" alt='Image of letter "N"' width="64" height="64" />
174
+ <img src="./examples/readme/google-palette/O.png" alt='Image of letter "O"' width="64" height="64" />
175
+ <img src="./examples/readme/google-palette/P.png" alt='Image of letter "P"' width="64" height="64" />
176
+ <img src="./examples/readme/google-palette/Q.png" alt='Image of letter "Q"' width="64" height="64" />
177
+ <img src="./examples/readme/google-palette/R.png" alt='Image of letter "R"' width="64" height="64" />
178
+ <img src="./examples/readme/google-palette/S.png" alt='Image of letter "S"' width="64" height="64" />
179
+ <img src="./examples/readme/google-palette/T.png" alt='Image of letter "T"' width="64" height="64" />
180
+ <img src="./examples/readme/google-palette/U.png" alt='Image of letter "U"' width="64" height="64" />
181
+ <img src="./examples/readme/google-palette/V.png" alt='Image of letter "V"' width="64" height="64" />
182
+ <img src="./examples/readme/google-palette/W.png" alt='Image of letter "W"' width="64" height="64" />
183
+ <img src="./examples/readme/google-palette/X.png" alt='Image of letter "X"' width="64" height="64" />
184
+ <img src="./examples/readme/google-palette/Y.png" alt='Image of letter "Y"' width="64" height="64" />
185
+ <img src="./examples/readme/google-palette/Z.png" alt='Image of letter "Z"' width="64" height="64" />
186
+ </div>
187
+
188
+ ### `:i_want_hue` - [iWantHue][] palette
189
+
190
+ <!--
191
+ alphabet = ("A".."Z").cycle
192
+
193
+ pairs = LetterAvatarSimple::Palettes::IWantHue::PALETTE.zip(alphabet)
194
+
195
+ f = File.open("/tmp/i_want_hue.txt", "w")
196
+ pairs.each_with_index do |(color,letter),i|
197
+ filename = "./examples/readme/i_want_hue-palette/#{i}-#{letter}.png"
198
+ LetterAvatarSimple.generate_file(
199
+ letter,
200
+ color: color,
201
+ filename: filename,
202
+ size: 64,
203
+ pointsize: 37.5,
204
+ annotate_position: "-0+0"
205
+ )
206
+ f.puts <<~HTML
207
+ <img src="#{filename}" alt='Image of letter "#{letter}"' width="64" height="64" />
208
+ HTML
209
+ end
210
+ f.close
211
+ -->
212
+
213
+ <div>
214
+ <img src="./examples/readme/i_want_hue-palette/0-A.png" alt='Image of letter "A"' width="64" height="64" />
215
+ <img src="./examples/readme/i_want_hue-palette/1-B.png" alt='Image of letter "B"' width="64" height="64" />
216
+ <img src="./examples/readme/i_want_hue-palette/2-C.png" alt='Image of letter "C"' width="64" height="64" />
217
+ <img src="./examples/readme/i_want_hue-palette/3-D.png" alt='Image of letter "D"' width="64" height="64" />
218
+ <img src="./examples/readme/i_want_hue-palette/4-E.png" alt='Image of letter "E"' width="64" height="64" />
219
+ <img src="./examples/readme/i_want_hue-palette/5-F.png" alt='Image of letter "F"' width="64" height="64" />
220
+ <img src="./examples/readme/i_want_hue-palette/6-G.png" alt='Image of letter "G"' width="64" height="64" />
221
+ <img src="./examples/readme/i_want_hue-palette/7-H.png" alt='Image of letter "H"' width="64" height="64" />
222
+ <img src="./examples/readme/i_want_hue-palette/8-I.png" alt='Image of letter "I"' width="64" height="64" />
223
+ <img src="./examples/readme/i_want_hue-palette/9-J.png" alt='Image of letter "J"' width="64" height="64" />
224
+ <img src="./examples/readme/i_want_hue-palette/10-K.png" alt='Image of letter "K"' width="64" height="64" />
225
+ <img src="./examples/readme/i_want_hue-palette/11-L.png" alt='Image of letter "L"' width="64" height="64" />
226
+ <img src="./examples/readme/i_want_hue-palette/12-M.png" alt='Image of letter "M"' width="64" height="64" />
227
+ <img src="./examples/readme/i_want_hue-palette/13-N.png" alt='Image of letter "N"' width="64" height="64" />
228
+ <img src="./examples/readme/i_want_hue-palette/14-O.png" alt='Image of letter "O"' width="64" height="64" />
229
+ <img src="./examples/readme/i_want_hue-palette/15-P.png" alt='Image of letter "P"' width="64" height="64" />
230
+ <img src="./examples/readme/i_want_hue-palette/16-Q.png" alt='Image of letter "Q"' width="64" height="64" />
231
+ <img src="./examples/readme/i_want_hue-palette/17-R.png" alt='Image of letter "R"' width="64" height="64" />
232
+ <img src="./examples/readme/i_want_hue-palette/18-S.png" alt='Image of letter "S"' width="64" height="64" />
233
+ <img src="./examples/readme/i_want_hue-palette/19-T.png" alt='Image of letter "T"' width="64" height="64" />
234
+ <img src="./examples/readme/i_want_hue-palette/20-U.png" alt='Image of letter "U"' width="64" height="64" />
235
+ <img src="./examples/readme/i_want_hue-palette/21-V.png" alt='Image of letter "V"' width="64" height="64" />
236
+ <img src="./examples/readme/i_want_hue-palette/22-W.png" alt='Image of letter "W"' width="64" height="64" />
237
+ <img src="./examples/readme/i_want_hue-palette/23-X.png" alt='Image of letter "X"' width="64" height="64" />
238
+ <img src="./examples/readme/i_want_hue-palette/24-Y.png" alt='Image of letter "Y"' width="64" height="64" />
239
+ <img src="./examples/readme/i_want_hue-palette/25-Z.png" alt='Image of letter "Z"' width="64" height="64" />
240
+ <img src="./examples/readme/i_want_hue-palette/26-A.png" alt='Image of letter "A"' width="64" height="64" />
241
+ <img src="./examples/readme/i_want_hue-palette/27-B.png" alt='Image of letter "B"' width="64" height="64" />
242
+ <img src="./examples/readme/i_want_hue-palette/28-C.png" alt='Image of letter "C"' width="64" height="64" />
243
+ <img src="./examples/readme/i_want_hue-palette/29-D.png" alt='Image of letter "D"' width="64" height="64" />
244
+ <img src="./examples/readme/i_want_hue-palette/30-E.png" alt='Image of letter "E"' width="64" height="64" />
245
+ <img src="./examples/readme/i_want_hue-palette/31-F.png" alt='Image of letter "F"' width="64" height="64" />
246
+ <img src="./examples/readme/i_want_hue-palette/32-G.png" alt='Image of letter "G"' width="64" height="64" />
247
+ <img src="./examples/readme/i_want_hue-palette/33-H.png" alt='Image of letter "H"' width="64" height="64" />
248
+ <img src="./examples/readme/i_want_hue-palette/34-I.png" alt='Image of letter "I"' width="64" height="64" />
249
+ <img src="./examples/readme/i_want_hue-palette/35-J.png" alt='Image of letter "J"' width="64" height="64" />
250
+ <img src="./examples/readme/i_want_hue-palette/36-K.png" alt='Image of letter "K"' width="64" height="64" />
251
+ <img src="./examples/readme/i_want_hue-palette/37-L.png" alt='Image of letter "L"' width="64" height="64" />
252
+ <img src="./examples/readme/i_want_hue-palette/38-M.png" alt='Image of letter "M"' width="64" height="64" />
253
+ <img src="./examples/readme/i_want_hue-palette/39-N.png" alt='Image of letter "N"' width="64" height="64" />
254
+ <img src="./examples/readme/i_want_hue-palette/40-O.png" alt='Image of letter "O"' width="64" height="64" />
255
+ <img src="./examples/readme/i_want_hue-palette/41-P.png" alt='Image of letter "P"' width="64" height="64" />
256
+ <img src="./examples/readme/i_want_hue-palette/42-Q.png" alt='Image of letter "Q"' width="64" height="64" />
257
+ <img src="./examples/readme/i_want_hue-palette/43-R.png" alt='Image of letter "R"' width="64" height="64" />
258
+ <img src="./examples/readme/i_want_hue-palette/44-S.png" alt='Image of letter "S"' width="64" height="64" />
259
+ <img src="./examples/readme/i_want_hue-palette/45-T.png" alt='Image of letter "T"' width="64" height="64" />
260
+ <img src="./examples/readme/i_want_hue-palette/46-U.png" alt='Image of letter "U"' width="64" height="64" />
261
+ <img src="./examples/readme/i_want_hue-palette/47-V.png" alt='Image of letter "V"' width="64" height="64" />
262
+ <img src="./examples/readme/i_want_hue-palette/48-W.png" alt='Image of letter "W"' width="64" height="64" />
263
+ <img src="./examples/readme/i_want_hue-palette/49-X.png" alt='Image of letter "X"' width="64" height="64" />
264
+ <img src="./examples/readme/i_want_hue-palette/50-Y.png" alt='Image of letter "Y"' width="64" height="64" />
265
+ <img src="./examples/readme/i_want_hue-palette/51-Z.png" alt='Image of letter "Z"' width="64" height="64" />
266
+ <img src="./examples/readme/i_want_hue-palette/52-A.png" alt='Image of letter "A"' width="64" height="64" />
267
+ <img src="./examples/readme/i_want_hue-palette/53-B.png" alt='Image of letter "B"' width="64" height="64" />
268
+ <img src="./examples/readme/i_want_hue-palette/54-C.png" alt='Image of letter "C"' width="64" height="64" />
269
+ <img src="./examples/readme/i_want_hue-palette/55-D.png" alt='Image of letter "D"' width="64" height="64" />
270
+ <img src="./examples/readme/i_want_hue-palette/56-E.png" alt='Image of letter "E"' width="64" height="64" />
271
+ <img src="./examples/readme/i_want_hue-palette/57-F.png" alt='Image of letter "F"' width="64" height="64" />
272
+ <img src="./examples/readme/i_want_hue-palette/58-G.png" alt='Image of letter "G"' width="64" height="64" />
273
+ ... <a href="./examples/readme/i_want_hue-palette">and 157 more!</a>
274
+ </div>
275
+
276
+ ### Custom palettes
277
+
278
+ You can add your own custom palette:
279
+
280
+ ```ruby
281
+ LetterAvatarSimple.palettes[:my_palette] = LetterAvatarSimple::Palette.new([
282
+ [120, 132, 205],
283
+ [91, 149, 249],
284
+ [72, 194, 249],
285
+ [69, 208, 226],
286
+ ])
287
+ # The default method of selecting the color is by MD5 digest of the username. You
288
+ # can change this behavior by providing a letter_color method.
289
+ LetterAvatarSimple.palettes[:my_palette].tap do |p|
290
+ def p.letter_color(identity)
291
+ if identity.id == "admin"
292
+ [255, 0, 0] # red
293
+ elsif identity.id == "bozo"
294
+ @palette.sample # random
295
+ else
296
+ # same initials = same color
297
+ digest = Digest::MD5.hexdigest(identity.letters.to_s)
298
+ @palette[digest[0...15].to_i(16) % @palette.length]
299
+ end
300
+ end
301
+ end
302
+
303
+ LetterAvatarSimple.generate_file("foobar", palette: :my_palette)
304
+ ```
305
+
306
+ ## Configuration
307
+
308
+ The same options that can be passed to `generate` can be set as global defaults:
309
+
310
+ ```ruby
311
+ LetterAvatarSimple.config do |config|
312
+ config.size = 256
313
+ config.palette = :i_want_hue
314
+ config.color = [255, 0, 0]
315
+ config.pointsize = 150
316
+ config.font = "/tmp/path/to/font/file"
317
+ config.weight = 500
318
+ config.fill_color = "rgba(255, 255, 255, 1)"
319
+ config.annotate_position = "-0+10"
320
+ end
321
+ ```
322
+
323
+ [letter_avatar]: https://github.com/ksz2k/letter_avatar
324
+ [minimagick]: https://github.com/minimagick/minimagick
325
+ [shrine]: https://github.com/shrinerb/shrine
326
+ [Discourse]: https://www.discourse.org/
327
+ [iWantHue]: http://tools.medialab.sciences-po.fr/iwanthue/index.php
Binary file
@@ -0,0 +1,90 @@
1
+ # frozen_string_literal: true
2
+ require "letter_avatar_simple/configuration"
3
+ require "letter_avatar_simple/identity"
4
+ require "letter_avatar_simple/palette"
5
+ require "letter_avatar_simple/version"
6
+ require "fileutils"
7
+ require "mini_magick"
8
+ require "tmpdir"
9
+
10
+ class LetterAvatarSimple
11
+ extend Configuration
12
+
13
+ def self.config(&blk)
14
+ yield(self)
15
+ end
16
+
17
+ def self.palettes
18
+ @palettes
19
+ end
20
+
21
+ def self.palettes=(h)
22
+ @palettes = h
23
+ end
24
+
25
+ def self.generate(identity, output: :string, **kwargs)
26
+ if identity.is_a?(String)
27
+ identity = Identity.from_username(identity)
28
+ end
29
+
30
+ opts = {
31
+ palette: kwargs[:palette] || LetterAvatarSimple.palette,
32
+ color: kwargs[:color] || LetterAvatarSimple.color,
33
+ size: kwargs[:size] || LetterAvatarSimple.size,
34
+ pointsize: kwargs[:pointsize] || LetterAvatarSimple.pointsize,
35
+ font: kwargs[:font] || LetterAvatarSimple.font,
36
+ weight: kwargs[:weight] || LetterAvatarSimple.weight,
37
+ fill_color: kwargs[:fill_color] || LetterAvatarSimple.fill_color,
38
+ annotate_position: kwargs[:annotate_position] || LetterAvatarSimple.annotate_position,
39
+ }
40
+
41
+ filename = kwargs[:filename] || generate_temp_filename
42
+ color = opts[:color] || LetterAvatarSimple.palettes.fetch(opts.fetch(:palette)).letter_color(identity)
43
+ MiniMagick::Tool::Convert.new do |x|
44
+ x.size "#{opts.fetch(:size)}x#{opts.fetch(:size)}"
45
+ x << "xc:#{to_rgb(color)}"
46
+ x.pointsize opts.fetch(:pointsize)
47
+ x.font opts.fetch(:font)
48
+ x.weight opts.fetch(:weight)
49
+ x.fill opts.fetch(:fill_color)
50
+ x.gravity "Center"
51
+ x.annotate(opts.fetch(:annotate_position), identity.letters)
52
+ x << filename
53
+ end
54
+
55
+ if output == :file
56
+ File.open(filename, "rb")
57
+ else
58
+ StringIO.new(File.binread(filename), "rb").tap do
59
+ FileUtils.rm_f(filename)
60
+ end
61
+ end
62
+ end
63
+
64
+ def self.generate_file(*args, **kwargs)
65
+ kwargs[:output] = :file
66
+ self.generate(*args, **kwargs)
67
+ end
68
+
69
+ def self.to_rgb(color)
70
+ r, g, b = color
71
+ "rgb(#{r},#{g},#{b})"
72
+ end
73
+
74
+ def self.generate_temp_filename(ext=".png")
75
+ filename = begin
76
+ Dir::Tmpname.make_tmpname(["x", ext], nil)
77
+ rescue NoMethodError
78
+ require "securerandom"
79
+ "#{SecureRandom.urlsafe_base64}#{ext}"
80
+ end
81
+ File.join(Dir.tmpdir, filename)
82
+ end
83
+ end
84
+
85
+ require "letter_avatar_simple/palettes/google"
86
+ require "letter_avatar_simple/palettes/i_want_hue"
87
+ LetterAvatarSimple.palettes = {
88
+ google: LetterAvatarSimple::Palettes::Google.new,
89
+ i_want_hue: LetterAvatarSimple::Palettes::IWantHue.new,
90
+ }
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+ class LetterAvatarSimple
3
+ module Configuration
4
+ attr_accessor :color
5
+ attr_writer :size, :fill_color, :font, :palette, :weight,
6
+ :annotate_position, :pointsize
7
+
8
+ def size
9
+ @size || 1024
10
+ end
11
+
12
+ def fill_color
13
+ @fill_color || "rgba(255, 255, 255, 0.65)"
14
+ end
15
+
16
+ def font
17
+ @font || File.join(File.expand_path("../../", File.dirname(__FILE__)), "Roboto-Medium")
18
+ end
19
+
20
+ def palette
21
+ @palette || :google
22
+ end
23
+
24
+ def weight
25
+ @weight ||= 300
26
+ end
27
+
28
+ def annotate_position
29
+ @annotate_position ||= "-0+5"
30
+ end
31
+
32
+ def pointsize
33
+ @pointsize ||= 600
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+ class LetterAvatarSimple
3
+ class Identity
4
+ attr_accessor :letters, :id
5
+
6
+ def initialize(letters, id)
7
+ @letters = letters
8
+ @id = id
9
+ end
10
+
11
+ def self.from_username(username)
12
+ # "john smith" => "JS"
13
+ letters = username.split(/\s+/).map{|word| word[0].upcase}.join('')
14
+ new(letters, username)
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+ require "digest"
3
+
4
+ class LetterAvatarSimple
5
+ class Palette
6
+ def initialize(palette)
7
+ @palette = palette
8
+ end
9
+
10
+ def letter_color(identity)
11
+ digest = Digest::MD5.hexdigest(identity.id.to_s)
12
+ @palette[digest[0...15].to_i(16) % @palette.length]
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+ class LetterAvatarSimple
3
+ class Palettes
4
+ class Google < LetterAvatarSimple::Palette
5
+ # Colors from Google Inbox
6
+ # https://inbox.google.com
7
+ PALETTE = [
8
+ [226, 95, 81], # A
9
+ [242, 96, 145], # B
10
+ [187, 101, 202], # C
11
+ [149, 114, 207], # D
12
+ [120, 132, 205], # E
13
+ [91, 149, 249], # F
14
+ [72, 194, 249], # G
15
+ [69, 208, 226], # H
16
+ [72, 182, 172], # I
17
+ [82, 188, 137], # J
18
+ [155, 206, 95], # K
19
+ [212, 227, 74], # L
20
+ [254, 218, 16], # M
21
+ [247, 192, 0], # N
22
+ [255, 168, 0], # O
23
+ [255, 138, 96], # P
24
+ [194, 194, 194], # Q
25
+ [143, 164, 175], # R
26
+ [162, 136, 126], # S
27
+ [163, 163, 163], # T
28
+ [175, 181, 226], # U
29
+ [179, 155, 221], # V
30
+ [194, 194, 194], # W
31
+ [124, 222, 235], # X
32
+ [188, 170, 164], # Y
33
+ [173, 214, 125] # Z
34
+ ].freeze
35
+
36
+ def initialize
37
+ @palette = PALETTE
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,235 @@
1
+ # frozen_string_literal: true
2
+ class LetterAvatarSimple
3
+ class Palettes
4
+ class IWantHue < LetterAvatarSimple::Palette
5
+ # palette of optimally disctinct colors
6
+ # cf. http://tools.medialab.sciences-po.fr/iwanthue/index.php
7
+ # parameters used:
8
+ # - H: 0 - 360
9
+ # - C: 0 - 2
10
+ # - L: 0.75 - 1.5
11
+ PALETTE = [
12
+ [198, 125, 40],
13
+ [61, 155, 243],
14
+ [74, 243, 75],
15
+ [238, 89, 166],
16
+ [52, 240, 224],
17
+ [177, 156, 155],
18
+ [240, 120, 145],
19
+ [111, 154, 78],
20
+ [237, 179, 245],
21
+ [237, 101, 95],
22
+ [89, 239, 155],
23
+ [43, 254, 70],
24
+ [163, 212, 245],
25
+ [65, 152, 142],
26
+ [165, 135, 246],
27
+ [181, 166, 38],
28
+ [187, 229, 206],
29
+ [77, 164, 25],
30
+ [179, 246, 101],
31
+ [234, 93, 37],
32
+ [225, 155, 115],
33
+ [142, 140, 188],
34
+ [223, 120, 140],
35
+ [249, 174, 27],
36
+ [244, 117, 225],
37
+ [137, 141, 102],
38
+ [75, 191, 146],
39
+ [188, 239, 142],
40
+ [164, 199, 145],
41
+ [173, 120, 149],
42
+ [59, 195, 89],
43
+ [222, 198, 220],
44
+ [68, 145, 187],
45
+ [236, 204, 179],
46
+ [159, 195, 72],
47
+ [188, 121, 189],
48
+ [166, 160, 85],
49
+ [181, 233, 37],
50
+ [236, 177, 85],
51
+ [121, 147, 160],
52
+ [234, 218, 110],
53
+ [241, 157, 191],
54
+ [62, 200, 234],
55
+ [133, 243, 34],
56
+ [88, 149, 110],
57
+ [59, 228, 248],
58
+ [183, 119, 118],
59
+ [251, 195, 45],
60
+ [113, 196, 122],
61
+ [197, 115, 70],
62
+ [80, 175, 187],
63
+ [103, 231, 238],
64
+ [240, 72, 133],
65
+ [228, 149, 241],
66
+ [180, 188, 159],
67
+ [172, 132, 85],
68
+ [180, 135, 251],
69
+ [236, 194, 58],
70
+ [217, 176, 109],
71
+ [88, 244, 199],
72
+ [186, 157, 239],
73
+ [113, 230, 96],
74
+ [206, 115, 165],
75
+ [244, 178, 163],
76
+ [230, 139, 26],
77
+ [241, 125, 89],
78
+ [83, 160, 66],
79
+ [107, 190, 166],
80
+ [197, 161, 210],
81
+ [198, 203, 245],
82
+ [238, 117, 19],
83
+ [228, 119, 116],
84
+ [131, 156, 41],
85
+ [145, 178, 168],
86
+ [139, 170, 220],
87
+ [233, 95, 125],
88
+ [87, 178, 230],
89
+ [157, 200, 119],
90
+ [237, 140, 76],
91
+ [229, 185, 186],
92
+ [144, 206, 212],
93
+ [236, 209, 158],
94
+ [185, 189, 79],
95
+ [34, 208, 66],
96
+ [84, 238, 129],
97
+ [133, 140, 134],
98
+ [67, 157, 94],
99
+ [168, 179, 25],
100
+ [140, 145, 240],
101
+ [151, 241, 125],
102
+ [67, 162, 107],
103
+ [200, 156, 21],
104
+ [169, 173, 189],
105
+ [226, 116, 189],
106
+ [133, 231, 191],
107
+ [194, 161, 63],
108
+ [241, 77, 99],
109
+ [241, 217, 53],
110
+ [123, 204, 105],
111
+ [210, 201, 119],
112
+ [229, 108, 155],
113
+ [240, 91, 72],
114
+ [187, 115, 210],
115
+ [240, 163, 100],
116
+ [178, 217, 57],
117
+ [179, 135, 116],
118
+ [204, 211, 24],
119
+ [186, 135, 57],
120
+ [223, 176, 135],
121
+ [204, 148, 151],
122
+ [116, 223, 50],
123
+ [95, 195, 46],
124
+ [123, 160, 236],
125
+ [181, 172, 131],
126
+ [142, 220, 202],
127
+ [240, 140, 112],
128
+ [172, 145, 164],
129
+ [228, 124, 45],
130
+ [135, 151, 243],
131
+ [42, 205, 125],
132
+ [192, 233, 116],
133
+ [119, 170, 114],
134
+ [158, 138, 26],
135
+ [73, 190, 183],
136
+ [185, 229, 243],
137
+ [227, 107, 55],
138
+ [196, 205, 202],
139
+ [132, 143, 60],
140
+ [233, 192, 237],
141
+ [62, 150, 220],
142
+ [205, 201, 141],
143
+ [106, 140, 190],
144
+ [161, 131, 205],
145
+ [135, 134, 158],
146
+ [198, 139, 81],
147
+ [115, 171, 32],
148
+ [101, 181, 67],
149
+ [149, 137, 119],
150
+ [37, 142, 183],
151
+ [183, 130, 175],
152
+ [168, 125, 133],
153
+ [124, 142, 87],
154
+ [236, 156, 171],
155
+ [232, 194, 91],
156
+ [219, 200, 69],
157
+ [144, 219, 34],
158
+ [219, 95, 187],
159
+ [145, 154, 217],
160
+ [165, 185, 100],
161
+ [127, 238, 163],
162
+ [224, 178, 198],
163
+ [119, 153, 120],
164
+ [124, 212, 92],
165
+ [172, 161, 105],
166
+ [231, 155, 135],
167
+ [157, 132, 101],
168
+ [122, 185, 146],
169
+ [53, 166, 51],
170
+ [70, 163, 90],
171
+ [150, 190, 213],
172
+ [210, 107, 60],
173
+ [166, 152, 185],
174
+ [159, 194, 159],
175
+ [39, 141, 222],
176
+ [202, 176, 161],
177
+ [95, 140, 229],
178
+ [168, 142, 87],
179
+ [93, 170, 203],
180
+ [159, 142, 54],
181
+ [14, 168, 39],
182
+ [94, 150, 149],
183
+ [187, 206, 136],
184
+ [157, 224, 166],
185
+ [235, 158, 208],
186
+ [109, 232, 216],
187
+ [141, 201, 87],
188
+ [208, 124, 118],
189
+ [142, 125, 214],
190
+ [19, 237, 174],
191
+ [72, 219, 41],
192
+ [234, 102, 111],
193
+ [168, 142, 79],
194
+ [188, 135, 35],
195
+ [95, 155, 143],
196
+ [148, 173, 116],
197
+ [223, 112, 95],
198
+ [228, 128, 236],
199
+ [206, 114, 54],
200
+ [195, 119, 88],
201
+ [235, 140, 94],
202
+ [235, 202, 125],
203
+ [233, 155, 153],
204
+ [214, 214, 238],
205
+ [246, 200, 35],
206
+ [151, 125, 171],
207
+ [132, 145, 172],
208
+ [131, 142, 118],
209
+ [199, 126, 150],
210
+ [61, 162, 123],
211
+ [58, 176, 151],
212
+ [215, 141, 69],
213
+ [225, 154, 220],
214
+ [220, 77, 167],
215
+ [233, 161, 64],
216
+ [130, 221, 137],
217
+ [81, 191, 129],
218
+ [169, 162, 140],
219
+ [174, 177, 222],
220
+ [236, 174, 47],
221
+ [233, 188, 180],
222
+ [69, 222, 172],
223
+ [71, 232, 93],
224
+ [118, 211, 238],
225
+ [157, 224, 83],
226
+ [218, 105, 73],
227
+ [126, 169, 36]
228
+ ].freeze
229
+
230
+ def initialize
231
+ @palette = PALETTE
232
+ end
233
+ end
234
+ end
235
+ end
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+ class LetterAvatarSimple
3
+ VERSION = "1.0.0"
4
+ end
metadata ADDED
@@ -0,0 +1,71 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: letter_avatar_simple
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Discourse Developers
8
+ - Krzysiek Szczuka
9
+ - Mateusz Mróz
10
+ - Jason Lee
11
+ - Abe Voelker
12
+ autorequire:
13
+ bindir: bin
14
+ cert_chain: []
15
+ date: 2019-05-28 00:00:00.000000000 Z
16
+ dependencies:
17
+ - !ruby/object:Gem::Dependency
18
+ name: mini_magick
19
+ requirement: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - "~>"
22
+ - !ruby/object:Gem::Version
23
+ version: '4.0'
24
+ type: :runtime
25
+ prerelease: false
26
+ version_requirements: !ruby/object:Gem::Requirement
27
+ requirements:
28
+ - - "~>"
29
+ - !ruby/object:Gem::Version
30
+ version: '4.0'
31
+ description:
32
+ email:
33
+ - abe@abevoelker.com
34
+ executables: []
35
+ extensions: []
36
+ extra_rdoc_files: []
37
+ files:
38
+ - CHANGELOG.md
39
+ - README.md
40
+ - Roboto-Medium
41
+ - lib/letter_avatar_simple.rb
42
+ - lib/letter_avatar_simple/configuration.rb
43
+ - lib/letter_avatar_simple/identity.rb
44
+ - lib/letter_avatar_simple/palette.rb
45
+ - lib/letter_avatar_simple/palettes/google.rb
46
+ - lib/letter_avatar_simple/palettes/i_want_hue.rb
47
+ - lib/letter_avatar_simple/version.rb
48
+ homepage: https://github.com/abevoelker/letter_avatar_simple
49
+ licenses:
50
+ - GPL-2.0
51
+ metadata: {}
52
+ post_install_message:
53
+ rdoc_options: []
54
+ require_paths:
55
+ - lib
56
+ required_ruby_version: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ required_rubygems_version: !ruby/object:Gem::Requirement
62
+ requirements:
63
+ - - ">="
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ requirements: []
67
+ rubygems_version: 3.0.3
68
+ signing_key:
69
+ specification_version: 4
70
+ summary: Generate letter image avatars based on user initials
71
+ test_files: []