profilepic 0.1.4 → 0.1.5

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.
@@ -1,499 +1,286 @@
1
-
2
1
  ###
3
- # helpers
4
- # to generate
5
-
6
- def radio_options_w_sprites( options,
7
- name:,
8
- legend: )
2
+ # serve-up built-in spritesheet(s) and metadata
3
+ FILES = {
4
+ # doge
5
+ 'doge-24x24.png' => "#{Shibainus.root}/config/spritesheet.png",
6
+ 'doge-24x24.csv' => "#{Shibainus.root}/config/spritesheet.csv",
7
+ # marcs
8
+ 'marcs-24x24.png' => "#{Pixelart::Module::Punks.root}/config/marcs-24x24.png",
9
+ 'marcs-24x24.csv' => "#{Pixelart::Module::Punks.root}/config/marcs-24x24.csv",
10
+ # saudis
11
+ 'saudis-24x24.png' => "#{Pixelart::Module::Punks.root}/config/saudis-24x24.png",
12
+ 'saudis-24x24.csv' => "#{Pixelart::Module::Punks.root}/config/saudis-24x24.csv",
13
+ # yeoldepunks
14
+ 'yeoldepunks-24x24.png' => "#{Pixelart::Module::Punks.root}/config/yeoldepunks-24x24.png",
15
+ 'yeoldepunks-24x24.csv' => "#{Pixelart::Module::Punks.root}/config/yeoldepunks-24x24.csv",
16
+ }
17
+
18
+ SPRITESHEETS = {
19
+ doge: ['doge-24x24.png', 'doge-24x24.csv'],
20
+ marcs: ['marcs-24x24.png', 'marcs-24x24.csv'],
21
+ saudis: ['saudis-24x24.png', 'saudis-24x24.csv'],
22
+ yeoldepunks: ['yeoldepunks-24x24.png', 'yeoldepunks-24x24.csv'],
23
+ }
24
+
25
+
26
+
27
+ def render_spritesheet( type, image_path, meta_path, zoom: 2 )
28
+ buf = String.new('')
29
+ buf += <<TXT
9
30
 
10
- buf = <<TXT
11
- <fieldset>
12
- <legend>#{legend}:</legend>
31
+ <h1> #{type} Spritesheet </h1>
13
32
  TXT
14
33
 
15
- options.each_with_index do |option,i|
34
+ ## note: map "virtual" to real path
35
+ path = FILES[ meta_path ]
36
+ recs = read_csv( path )
16
37
 
17
- value = option.downcase
38
+ recs.each do |rec|
39
+ id = rec['id']
40
+ name = rec['name']
41
+ more_names = (rec['more_names'] || '').split( '|' )
18
42
 
19
- ## auto-extract qualifiers e.g. (m)ale/(f)emale
20
- qualifiers = if value.index( '(m)' ) then ['m']
21
- elsif value.index( '(f)' ) then ['f']
22
- elsif value.index( '(m/f)' ) then ['m', 'f']
23
- else []
24
- end
43
+ names = [name]
44
+ names += more_names
25
45
 
26
- value = value.sub( '(m)', '' ).sub( '(f)', '' ).sub( '(m/f)', '' ).sub( '¹', '' )
27
- value = value.strip
46
+ key = name
47
+ if rec.has_key?( 'gender' )
48
+ archetype = (rec['type'] || rec['category'] || '').downcase.strip == 'archetype'
49
+ if archetype
50
+ ## do nothing for base archetype (e.g. male 1, alien, etc.)
51
+ else
52
+ ## auto-add qualifer e.g. (m) or (f) via gender
53
+ gender = (rec['gender'] || 'm').downcase.strip
54
+ key = "#{name} (#{gender})"
55
+ names = names.map { |name| "#{name} (#{gender})"}
56
+ end
57
+ end
28
58
 
29
59
 
60
+ buf << "#{id} "
61
+ buf << "<span class='sprite' data-name='#{key}'></span>"
62
+ buf << " "
63
+ buf << names.join( ' | ' )
64
+ buf << "<br>\n"
65
+ end
30
66
 
31
- label = option
32
67
 
33
68
  buf += <<TXT
34
- <div>
35
- <input type="radio" id="#{name}#{i}" name="#{name}" value="#{value}"
36
- #{ i==0 ? 'checked' : '' }>
69
+ <script>
70
+ var sheet = Spritesheet.read( '#{image_path}',
71
+ `#{spritesheet( meta_path )}` );
72
+ sheet.draw();
73
+ </script>
37
74
  TXT
38
75
 
39
- if ['none'].include?( value )
40
- ## do nothing - no sprite(s) - for none & friends
41
- elsif qualifiers.empty?
42
- buf += %Q[ <span class="sprite" data-name="#{value}"></span>\n]
43
- else
44
- qualifiers.each do |qualifier|
45
- buf += %Q[ <span class="sprite" data-name="#{value} (#{qualifier})"></span>\n]
46
- end
47
- end
76
+ buf
48
77
 
49
- buf += <<TXT
50
- <label for="#{name}#{i}">#{label}</label>
51
- </div>
52
- TXT
53
78
  end
54
79
 
55
80
 
56
- buf += "</fieldset>\n"
57
- buf
58
81
 
59
- end
82
+ class ProfilepicService < Sinatra::Base
60
83
 
61
84
 
62
- def radio_options( options,
63
- name:,
64
- legend: )
85
+ get '/' do
86
+ erb :index
87
+ end
65
88
 
66
- buf = <<TXT
67
- <fieldset>
68
- <legend>#{legend}:</legend>
69
- TXT
89
+ get '/marcs' do
90
+ erb :marcs
91
+ end
70
92
 
71
- options.each_with_index do |option,i|
93
+ get '/saudis' do
94
+ erb :saudis
95
+ end
72
96
 
73
- value = option.downcase
74
- value = value.sub( '(m)', '' ).sub( '(f)', '' ).sub( '(m/f)', '' ).sub( '¹', '' )
75
- value = value.strip
97
+ get '/doge' do
98
+ erb :doge
99
+ end
76
100
 
77
- label = option
101
+ get '/yeoldepunks' do
102
+ erb :yeoldepunks
103
+ end
78
104
 
79
- buf += <<TXT
80
- <div>
81
- <input type="radio" id="#{name}#{i}" name="#{name}" value="#{value}"
82
- #{ i==0 ? 'checked' : '' }>
83
- <label for="#{name}#{i}">#{label}</label>
84
- </div>
85
- TXT
86
- end
87
105
 
88
- buf += "</fieldset>\n"
89
- buf
90
- end
91
106
 
107
+ get '/spritesheets' do
92
108
 
93
- YEOLDEPUNK_ARCHETYPE = [
94
- 'Male 1',
95
- 'Male 2',
96
- 'Male 3',
97
- 'Male 4',
98
- 'Female 1',
99
- 'Female 2',
100
- 'Female 3',
101
- 'Female 4',
102
- 'Zombie',
103
- 'Ape',
104
- 'Alien',
105
- ]
106
-
107
-
108
- YEOLDEPUNK_HAIR = [
109
- 'Shaved Head (m)',
110
- 'Peak Spike (m)',
111
- 'Vampire Hair (m)',
112
- 'Purple Hair (m)',
113
-
114
- 'Mohawk (m/f)',
115
- 'Mohawk Dark (m/f)',
116
- 'Mohawk Thin (m/f)',
117
- 'Wild Hair (m/f)',
118
- 'Crazy Hair (m/f)',
119
- 'Messy Hair (m/f)',
120
- 'Frumpy Hair (m/f)',
121
- 'Stringy Hair (m/f)',
122
- 'Clown Hair Green (m/f)',
123
-
124
- 'Straight Hair (f)',
125
- 'Straight Hair Dark (f)',
126
- 'Straight Hair Blonde (f)',
127
- 'Blonde Short (f)',
128
- 'Blonde Bob (f)',
129
- 'Wild Blonde (f)',
130
- 'Wild White Hair (f)',
131
- 'Orange Side (f)',
132
- 'Dark Hair (f)',
133
- 'Pigtails (f)',
134
- 'Pink With Hat¹ (f)',
135
- 'Half Shaved (f)',
136
- 'Red Mohawk (f)',
137
- ]
138
-
139
- YEOLDEPUNK_BEARD = [
140
- 'Shadow Beard (m)',
141
- 'Normal Beard (m)',
142
- 'Normal Beard Black (m)',
143
- 'Big Beard (m)',
144
- 'Luxurious Beard (m)',
145
- 'Mustache (m)',
146
- 'Goat (m)',
147
- 'Handlebars (m)',
148
- 'Front Beard (m)',
149
- 'Front Beard Dark (m)',
150
- 'Chinstrap (m)',
151
- 'Muttonchops (m)',
152
- ]
153
-
154
- YEOLDEPUNK_EYEWEAR = [
155
- 'Small Shades (m)',
156
- 'Regular Shades (m/f)',
157
- 'Classic Shades (m/f)',
158
- 'Big Shades (m/f)',
159
- 'Nerd Glasses (m/f)',
160
- 'Horned Rim Glasses (m/f)',
161
- '3D Glasses (m/f)',
162
- 'VR (m/f)',
163
- 'Eye Mask (m/f)',
164
- 'Eye Patch (m/f)',
165
- 'Welding Goggles (f)',
166
- ]
167
-
168
- YEOLDEPUNK_EARRING = [
169
- 'Earring (m/f)'
170
- ]
171
-
172
-
173
- YEOLDEPUNK_HEADWEAR = [
174
- 'Cowboy Hat (m)',
175
- 'Fedora (m)',
176
- 'Hoodie (m)',
177
- 'Beanie (m)',
178
- 'Top Hat (m)',
179
- 'Do-rag (m)',
180
- 'Police Cap (m)',
181
- 'Cap Forward (m)',
182
- 'Cap (m/f)',
183
- 'Knitted Cap (m/f)',
184
- 'Bandana (m/f)',
185
- 'Headband¹ (m/f)',
186
- 'Pilot Helmet (f)',
187
- 'Tassle Hat (f)',
188
- 'Tiara (f)',
189
- ]
190
-
191
- YEOLDEPUNK_EYES = [
192
- 'Clown Eyes Green (m/f)',
193
- 'Clown Eyes Blue (m/f)',
194
- 'Green Eye Shadow (f)',
195
- 'Blue Eye Shadow (f)',
196
- 'Purple Eye Shadow (f)',
197
- ]
198
-
199
- YEOLDEPUNK_MOUTH = [
200
- 'Smile (m)',
201
- 'Frown (m)',
202
- 'Buck Teeth (m)',
203
- 'Hot Lipstick (f)',
204
- 'Black Lipstick (f)',
205
- 'Purple Lipstick (f)',
206
- ]
207
-
208
-
209
- YEOLDEPUNK_MOUTH_PROP = [
210
- 'Cigarette (m/f)',
211
- 'Vape (m/f)',
212
- 'Pipe (m/f)',
213
- 'Medical Mask (m/f)',
214
- ]
215
-
216
- YEOLDEPUNK_NECK = [
217
- 'Silver Chain (m/f)',
218
- 'Gold Chain (m/f)',
219
- 'Choker (f)',
220
- ]
221
-
222
- YEOLDEPUNK_BLEMISH = [
223
- 'Mole (m/f)',
224
- 'Spots (m/f)',
225
- 'Rosy Cheeks (m/f)',
226
- ]
227
-
228
- YEOLDEPUNK_NOSE = [
229
- 'Clown Nose (m/f)',
230
- ]
231
-
232
-
233
-
234
-
235
- DOGE_ARCHETYPE = [
236
- 'Classic',
237
- 'Dark',
238
- 'Zombie',
239
- 'Alien',
240
- ]
241
-
242
- DOGE_HAIR = [
243
- 'Crazy Hair',
244
- ]
245
-
246
- DOGE_HEADWEAR = [
247
- 'Beanie',
248
- 'Cap',
249
- 'Cap Forward',
250
- 'Cowboy Hat',
251
- 'Fedora',
252
- 'Knitted Cap',
253
- 'Top Hat',
254
- 'Bandana',
255
- 'Headband',
256
- 'Tiara',
257
- ]
258
-
259
- DOGE_EYEWEAR = [
260
- '3D Glasses',
261
- 'Big Shades',
262
- 'Classic Shades',
263
- 'Regular Shades',
264
- 'Small Shades',
265
- 'Nerd Glasses',
266
- 'Eye Patch',
267
- ]
268
-
269
-
270
-
271
- MARC_ARCHETYPE = [
272
- 'Marc',
273
- 'Marc Mid',
274
- 'Marc Dark',
275
- 'Marc Albino',
276
- 'Marc Golden',
277
- 'Mad Lad',
278
- 'Zombie',
279
- 'Ape',
280
- 'Ape Golden',
281
- 'Ape Pink',
282
- 'Alien',
283
- 'Alien Green',
284
- 'Devil',
285
- 'Orc',
286
- 'Skeleton',
287
- 'Bot']
288
-
289
-
290
- MARC_EYES = [
291
- 'Blue Eyes',
292
- 'Green Eyes',
293
- ]
294
-
295
- MARC_FACE = [
296
- 'Blue Eye Shadow',
297
- 'Green Eye Shadow',
298
- 'Purple Eye Shadow',
299
- 'Clown Eyes Blue',
300
- 'Clown Eyes Green',
301
- 'Bagner',
302
- 'Marc Tyson',
303
- 'Tears',
304
- ]
305
-
306
- MARC_BEARD = [
307
- 'Big Beard White',
308
- 'Big Beard',
309
- 'Chinstrap',
310
- 'Front Beard',
311
- 'Front Beard Dark',
312
- 'Full Mustache',
313
- 'Full Mustache Dark',
314
- 'Goat',
315
- 'Goat Dark',
316
- 'Handlebar',
317
- 'Luxurious Beard',
318
- 'Mustache',
319
- 'Mutton Chop',
320
- 'Normal Beard',
321
- 'Normal Beard Black',
322
- 'Shadow Beard',
323
- 'Soul Patch',
324
- ]
325
-
326
- MARC_HAIR = [
327
- 'Blonde Bob',
328
- 'Chad',
329
- 'Clown Hair',
330
- 'Crazy White Hair',
331
- 'Crazy Hair',
332
- 'Frumpy Hair',
333
- 'Marc Three',
334
- 'Purple Hair',
335
- 'Stringy Hair',
336
- 'Vampire Hair',
337
- 'Wild Blonde Hair',
338
- 'Wild Hair',
339
- ]
340
-
341
- MARC_HEADWEAR = [
342
- 'Bandana',
343
- 'Beanie',
344
- 'Bunny Ears',
345
- 'Cap',
346
- 'Skull Cap',
347
- 'Cap Forward',
348
- 'Police Cap',
349
- 'Cowboy Hat',
350
- 'Do Rag',
351
- 'Fast Food',
352
- 'Marcdonalds',
353
- 'Fedora',
354
- 'Headband',
355
- 'Roaring Headband',
356
- 'Hoodie',
357
- 'Purple Hoodie',
358
- 'Knitted Cap',
359
- 'Laurels',
360
- 'Shemagh',
361
- 'Tassle Hat',
362
- 'Tiarra',
363
- 'Top Hat',
364
- 'Uncle Sam',
365
- 'Viking',
366
- 'Welding Goggles',
367
- ]
368
-
369
-
370
- MARC_EYEWEAR = [
371
- '3D Glasses',
372
- 'Aviators',
373
- 'Big Shades',
374
- 'Classic Shades',
375
- 'Deal With It',
376
- 'Glasses',
377
- 'Gold Glasses',
378
- 'Horned-Rim Glasses',
379
- 'Monocle',
380
- 'Nerd Glasses',
381
- 'Pink Shades',
382
- 'Polarized',
383
- 'Polarized White',
384
- 'Regular Shades',
385
- 'Small Shades',
386
- 'VR Headset',
387
- 'Eye Mask',
388
- 'Eye Patch',
389
- 'Lasers']
390
-
391
- MARC_MOUTH_PROP = [
392
- 'Cigar',
393
- 'Cigarette',
394
- 'Hookah',
395
- 'Pipe',
396
- 'Vape',
397
- 'Medical Mask',
398
- 'Bubble Gum' ]
109
+ erb <<TXT
399
110
 
111
+ <p style="font-size: 80%;">
112
+ <a href="/">« Profile Pic(ture) As A Service</a>
113
+ </p>
400
114
 
115
+ <h1>Spritesheets</h1>
401
116
 
402
117
 
403
- class ProfilepicService < Sinatra::Base
118
+ <% SPRITESHEETS.each do |type, files| %>
119
+ <p>
120
+ <b><a href="/<%= type %>_spritesheet"> <%= type %> Attribute Quick Reference</b></a>
404
121
 
405
- get '/cache' do
406
122
 
407
- html =<<HTML
408
- <pre>
409
- #{IMAGES.size} image(s) in cache:
123
+ <span style="font-size: 80%;">
124
+ (Source:
125
+ <% files.each_with_index do |name, i| %>
126
+ <%= i > 0 ? ' · ' : '' %>
127
+ <a href="/<%= name %>"><%= name %></a>
128
+ <% end %>
129
+ )
130
+ </span>
131
+ </p>
132
+ <% end %>
133
+ TXT
134
+ end
410
135
 
411
136
 
412
- </pre>
413
- HTML
414
- html
415
- end
416
137
 
138
+ FILES.each do |name, real_path|
417
139
 
140
+ basename = File.basename( name )
141
+ extname = File.extname( name )
142
+ pp [basename, extname]
418
143
 
419
- get '/' do
420
- erb :index
421
- end
144
+ puts "adding get route >/#{name}< serving >#{real_path}<"
422
145
 
423
- get '/marcs' do
424
- erb :marcs
146
+ get "/#{name}" do
147
+ puts " serving >#{name}<..."
148
+ if extname == '.csv'
149
+ ## headers( 'Content-Type' => 'text/plain; charset=utf-8' )
150
+ headers( 'Content-Type' => 'text/plain; charset=utf-8' )
151
+ headers( 'Content-Disposition' => 'inline' )
152
+ ## note - do NOT use content type for now
153
+ ## chrome will DOWNLOAD the file and not display inline
154
+ read_text( real_path )
155
+ else ## assume png - image/png
156
+ headers( 'Content-Type' => 'image/png' )
157
+ ## todo/fix. change to read_blob/bin/binary( real_path )
158
+ Pixelart::Image.read( real_path ).to_blob
159
+ end
425
160
  end
161
+ end
426
162
 
427
- get '/doge' do
428
- erb :doge
429
- end
430
163
 
431
- get '/yeoldepunks' do
432
- erb :yeoldepunks
164
+ SPRITESHEETS.each do |type, files|
165
+ get "/#{type}_spritesheet" do
166
+ erb render_spritesheet( type, files[0], files[1], zoom: 2 )
433
167
  end
168
+ end
434
169
 
435
170
 
436
171
 
437
-
172
+ ##
173
+ # generators
438
174
  get '/generate_marcs' do
439
-
440
175
  r = ImageReq.build_marc( params )
441
176
 
442
- img = r.image
177
+ IMAGES[ r.image_key ] = r.image_blob
178
+ redirect "/more?key=#{r.image_key}"
179
+ end
180
+
181
+ get '/generate_saudis' do
182
+ r = ImageReq.build_saudi( params )
443
183
 
444
- blob = img.image.to_blob
445
- IMAGES[ r.image_key ] = blob
446
- redirect "/#{r.image_key}.png"
447
- end
184
+ IMAGES[ r.image_key ] = r.image_blob
185
+ redirect "/more?key=#{r.image_key}"
186
+ end
448
187
 
449
188
  get '/generate_yeoldepunks' do
189
+ r = ImageReq.build_yeoldepunk( params )
450
190
 
451
- r = ImageReq.build_yeoldepunk( params )
191
+ IMAGES[ r.image_key ] = r.image_blob
192
+ redirect "/more?key=#{r.image_key}"
193
+ end
452
194
 
453
- img = r.image
195
+ get '/generate_doge' do
196
+ r = ImageReq.build_doge( params )
454
197
 
455
- blob = img.image.to_blob
456
- IMAGES[ r.image_key ] = blob
457
- redirect "/#{r.image_key}.png"
458
- end
198
+ IMAGES[ r.image_key ] = r.image_blob
199
+ redirect "/more?key=#{r.image_key}"
200
+ end
459
201
 
460
202
 
461
- get '/generate_doge' do
203
+ get '/generate' do
204
+ r = ImageReq.build( params )
205
+
206
+ IMAGES[ r.image_key ] = r.image_blob
207
+ # redirect "/#{r.image_key}.png"
208
+ redirect "/more?key=#{r.image_key}"
209
+ end
462
210
 
463
- r = ImageReq.build_doge( params )
464
211
 
465
- img = r.image
466
212
 
467
- blob = img.image.to_blob
468
- IMAGES[ r.image_key ] = blob
469
- redirect "/#{r.image_key}.png"
470
- end
471
213
 
214
+ get '/more' do
472
215
 
473
- get '/generate' do
216
+ zoom = (params[:z] || '1').strip.to_i( 10 )
474
217
 
475
- r = ImageReq.build( params )
218
+ key = params[:key]
219
+ ## split key in name and id e.g.
220
+ ## moonbird1660753325 => moonbird / 1660753325
221
+ name, id = if m = key.match( /^(?<name>[a-z_-]+)
222
+ (?<id>[0-9]+)$
223
+ /ix )
224
+ [m[:name],m[:id]]
225
+ else
226
+ ['?','?']
227
+ end
228
+
229
+ ## change/rename pic to src (or image_src or such - why? why not?)
230
+ pic = "#{key}"
231
+ pic += "@#{zoom}x" if [2,3,4,5,6,7,8,9,10,20].include?( zoom )
232
+ pic += ".png"
233
+
234
+ bg = (params[:bg] || 'none').strip.downcase
476
235
 
477
- img = r.image
236
+ pic += "?bg=#{bg}" if bg != 'none'
478
237
 
479
- blob = img.image.to_blob
480
- IMAGES[ r.image_key ] = blob
481
- redirect "/#{r.image_key}.png"
238
+
239
+ erb :more, locals: { pic: pic,
240
+ zoom: zoom,
241
+ bg: bg,
242
+ key: key,
243
+ name: name,
244
+ id: id }
482
245
  end
483
246
 
484
247
 
485
- get '/:key.png' do
248
+ get %r{/(?<key>[a-z0-9]+)
249
+ (@(?<zoom>[0-9]+)x)?
250
+ \.png}xi do
251
+
252
+ # get '/:key(@:zoom)?.png' do
486
253
  puts " .png image request for key: >#{params[:key]}<"
254
+ puts " with zoom: >#{params[:zoom]}< : #{params[:zoom].class.name}"
487
255
 
488
256
  blob = IMAGES[ params[:key] ]
489
257
 
258
+
490
259
  if blob
260
+ img = Pixelart::Image.blob( blob )
261
+
262
+ bg = (params[:bg] || 'none').strip.downcase
263
+ img = img.background( bg ) if bg != 'none'
264
+
265
+ zoom = (params[:zoom] || '1').strip.to_i( 10 )
266
+ img = img.zoom( zoom ) if [2,3,4,5,6,7,8,9,10,20].include?( zoom )
267
+
491
268
  headers( 'Content-Type' => "image/png" )
492
- blob
269
+ img.to_blob
493
270
  else
494
271
  "404 not found; sorry no generated .png image found for key >#{params[:key]}<"
495
272
  end
496
273
  end
497
- end
498
274
 
275
+ get '/cache' do
276
+
277
+ html =<<HTML
278
+ <pre>
279
+ #{IMAGES.size} image(s) in cache:
499
280
 
281
+
282
+ </pre>
283
+ HTML
284
+ html
285
+ end
286
+ end # class ProfilepicService
@@ -3,7 +3,7 @@
3
3
  module Profilepic
4
4
  MAJOR = 0
5
5
  MINOR = 1
6
- PATCH = 4
6
+ PATCH = 5
7
7
  VERSION = [MAJOR,MINOR,PATCH].join('.')
8
8
 
9
9
  def self.version