face-no-more 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 124bf237d91787cc4cfd04d77c117f0aff8069eeae6382707d1669566d4e25a7
4
+ data.tar.gz: 3c0b4aa07cf08603f80ef380b113a9e8ac6ee7c297dbe6ac84ed87a4df778091
5
+ SHA512:
6
+ metadata.gz: bd9bd3f7bb2f9818c2524f39268516645abc6830a86d83ff6ae94b6a5d9303c8933f941b08b0ed6259e80f6fb91c342ebdeffeed156d227e53379c1d6348d019
7
+ data.tar.gz: 2bf2b7276b1489d924aaf1fb2d09d79a74bc2b9ee9db87a7548420942099b5f8a2038d1daf4e7b7b4a150bd3942a3f80ed77812e1bb1229ba3f6726d43258663
data/README.md ADDED
@@ -0,0 +1,37 @@
1
+ Description
2
+ ===========
3
+
4
+ Allow generating avatar pictures from ruby.
5
+
6
+ The supported avatar type are: `cat`, `bird`, `abstract`, `mobilizon`,
7
+ `8bit-female` and `8bit-male`.
8
+
9
+
10
+ Examples
11
+ ========
12
+
13
+ ~~~ruby
14
+ require 'face-no-more'
15
+
16
+ # Number of possible avatars
17
+ count = FaceNoMore.possibilities(:mobilizon)
18
+
19
+ # Generate avatar picture
20
+ jpg = FaceNoMore.generate(:cat, "foo@example.com", format: :jpg, size: 256)
21
+ png = FaceNoMore.generate(:bird, 12345678910)
22
+ ~~~
23
+
24
+
25
+
26
+ Artworks
27
+ ========
28
+ * `cat`, `bird`, `abstract` and `mobilizon` are from [David Revoy][2]
29
+ licensed under [CC-By 4.0][4]
30
+ * `8bit-female` and `8bit-male` are from [matveyco][3]
31
+
32
+
33
+
34
+ [2]: http://www.peppercarrot.com
35
+ [3]: https://github.com/matveyco/8biticon
36
+ [4]: http://creativecommons.org/licenses/by/4.0/
37
+
@@ -0,0 +1,26 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require_relative 'lib/face-no-more/version'
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = 'face-no-more'
7
+ s.version = FaceNoMore::VERSION
8
+ s.summary = "Generate avatars"
9
+ s.description = <<~EOF
10
+ Generate avatars from artwork assets.
11
+ Included 5 different types of artwork: cat, bird, abstract, mobilizon, and 8bit.
12
+ EOF
13
+
14
+ s.homepage = 'https://gitlab.com/sdalu/face-no-more'
15
+ s.license = 'MIT'
16
+
17
+ s.authors = [ "Stéphane D'Alu" ]
18
+ s.email = [ 'stephane.dalu@insa-lyon.fr' ]
19
+
20
+ s.files = %w[ README.md face-no-more.gemspec ] +
21
+ Dir['lib/**/*.rb'] + Dir['data/**']
22
+
23
+ s.add_dependency 'rmagick'
24
+ s.add_development_dependency 'yard', '~>0'
25
+ s.add_development_dependency 'rake', '~>13'
26
+ end
@@ -0,0 +1,4 @@
1
+ module FaceNoMore
2
+ # Version string
3
+ VERSION = '0.1.1'
4
+ end
@@ -0,0 +1,168 @@
1
+ # coding: utf-8
2
+ require 'securerandom'
3
+ require 'digest'
4
+ require 'rmagick'
5
+
6
+
7
+ # Generate avatar
8
+ #
9
+ # ~~~ruby
10
+ # require 'face-no-more'
11
+ #
12
+ # FaceNoMore.generate(:cat, "foo@example.com", format: :jpg, size: 256)
13
+ # FaceNoMore.generate(:bird, 12345678910)
14
+ # ~~~
15
+
16
+
17
+ module FaceNoMore
18
+ # @!visibility private
19
+ IMAGES_DIR = File.join(__dir__, '..', 'data', 'images')
20
+
21
+ # @!visibility private
22
+ # NOTE: - Limited to 16 parts
23
+ # - Keep sizes sorted from small to big
24
+ DESCRIPTIONS = {
25
+ :cat => {
26
+ :author => 'David Revoy',
27
+ :license => 'CC-BY',
28
+ :src => 'https://www.peppercarrot.com/extras/html/2016_cat-generator/',
29
+ :sizes => [ 256 ],
30
+ :partname => "%<part>s_%<id>d.png",
31
+ :parts => { :body => 1..15,
32
+ :fur => 1..10,
33
+ :eyes => 1..15,
34
+ :mouth => 1..10,
35
+ :accessorie => 1..20 },
36
+
37
+ },
38
+ :bird => {
39
+ :author => 'David Revoy',
40
+ :license => 'CC-BY',
41
+ :src => 'https://www.peppercarrot.com/extras/html/2019_bird-generator/',
42
+ :sizes => [ 256 ],
43
+ :partname => "%<part>s_%<id>d.png",
44
+ :parts => { :tail => 1..9,
45
+ :hoop => 1..10,
46
+ :body => 1..9,
47
+ :wing => 1..9,
48
+ :eyes => 1..9,
49
+ :bec => 1..9,
50
+ :accessorie => 1..20, },
51
+ },
52
+ :abstract => {
53
+ :author => 'David Revoy',
54
+ :license => 'CC-BY',
55
+ :src => 'https://www.peppercarrot.com/extras/html/2017_abstract-generator/',
56
+ :sizes => [ 256 ],
57
+ :partname => "%<part>s_%<id>d.png",
58
+ :parts => { :body => 1..15,
59
+ :fur => 1..10,
60
+ :eyes => 1..15,
61
+ :mouth => 1..10, },
62
+ },
63
+ :mobilizon => {
64
+ :author => 'David Revoy',
65
+ :license => 'CC-BY',
66
+ :src => 'https://www.peppercarrot.com/extras/html/2020_mobilizon-generator/',
67
+ :sizes => [ 256, 1024 ],
68
+ :partname => "%<part>s_%<id>02d.png",
69
+ :parts => { :body => 1..25,
70
+ :nose => 1..10,
71
+ :tail => 1..5,
72
+ :eyes => 1..10,
73
+ :mouth => 1..10,
74
+ :accessories => 1..20,
75
+ :misc => 1..20,
76
+ :hat => 1..20, },
77
+ },
78
+ :'8bit-female' => {
79
+ :author => 'matveyco',
80
+ :src => 'https://github.com/matveyco/8biticon',
81
+ :path => '8bit/female',
82
+ :sizes => [ 400 ],
83
+ :partname => "%<part>s%<id>d.png",
84
+ :parts => { :face => 1..4,
85
+ :clothes => 1..59,
86
+ :mouth => 1..17,
87
+ :head => 1..33,
88
+ :eye => 1..53, },
89
+ },
90
+ :'8bit-male' => {
91
+ :author => 'matveyco',
92
+ :src => 'https://github.com/matveyco/8biticon',
93
+ :path => '8bit/male',
94
+ :sizes => [ 400 ],
95
+ :partname => "%<part>s%<id>d.png",
96
+ :parts => { :face => 1..4,
97
+ :clothes => 1..65,
98
+ :mouth => 1..26,
99
+ :hair => 1..36,
100
+ :eye => 1..32, },
101
+ },
102
+ }
103
+
104
+
105
+ # List of supported avatar types
106
+ TYPES = DESCRIPTIONS.keys.freeze
107
+
108
+
109
+ # Return the number of different avatar possible
110
+ #
111
+ # @param type type of avatar
112
+ #
113
+ # @return [Integer]
114
+ #
115
+ def self.possibilities(type)
116
+ DESCRIPTIONS.fetch(type) {
117
+ raise ArgumentError, "unsupported type (#{type})"
118
+ }[:parts].map {|part, range| range.last - range.first }
119
+ .reduce(:*)
120
+ end
121
+
122
+
123
+ # Generate an avatar
124
+ #
125
+ # @param type [Symbol] type of avatar
126
+ # @param seed [String,Array<Integer>,Integer,nil] seed
127
+ # @param format [:Symbol] picture format (as defined in ImageMagick)
128
+ # @param quality [Integer] picture quality (1..100)
129
+ # @param size [Integer] picture size
130
+ #
131
+ # @return [String]
132
+ #
133
+ def self.generate(type, seed = nil, format: :png, quality: 90, size: 256)
134
+ desc = DESCRIPTIONS.fetch(type) {
135
+ raise ArgumentError, "unsupported type (#{type})" }
136
+ parts = desc[:parts]
137
+ sizes = desc[:sizes]
138
+ path = File.join(IMAGES_DIR, desc[:path] || type.to_s)
139
+ partsize = sizes.find {|s| size > s } || sizes.last
140
+ seedbytes = case seed
141
+ when nil then SecureRandom.random_bytes(16).bytes
142
+ when String then Digest::MD5.digest(seed).bytes
143
+ when Array then seed
144
+ when Integer then parts.map {|_, r|
145
+ count = r.end - r.begin + 1
146
+ seed, val = seed.divmod(count)
147
+ val }
148
+ end
149
+
150
+ if parts.size > seedbytes.size
151
+ raise ArgumentError, "seed doesn't hold enough elements"
152
+ end
153
+
154
+
155
+ files = parts.each_with_index.map {|(part, range), index|
156
+ mod = (range.end - range.begin) + 1
157
+ id = range.first + seedbytes[index] % mod
158
+ File.join(path, partsize.to_s,
159
+ desc[:partname] % { :part => part, :id => id })
160
+ }
161
+
162
+ Magick::ImageList.new(*files).flatten_images
163
+ .change_geometry!("#{size}x#{size}") { |cols, rows, me|
164
+ me.thumbnail!(cols, rows)
165
+ }.to_blob {|me| me.format = format.to_s
166
+ me.quality = quality }
167
+ end
168
+ end
metadata ADDED
@@ -0,0 +1,91 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: face-no-more
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ platform: ruby
6
+ authors:
7
+ - Stéphane D'Alu
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2021-05-21 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rmagick
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: yard
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '13'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '13'
55
+ description: |
56
+ Generate avatars from artwork assets.
57
+ Included 5 different types of artwork: cat, bird, abstract, mobilizon, and 8bit.
58
+ email:
59
+ - stephane.dalu@insa-lyon.fr
60
+ executables: []
61
+ extensions: []
62
+ extra_rdoc_files: []
63
+ files:
64
+ - README.md
65
+ - face-no-more.gemspec
66
+ - lib/face-no-more.rb
67
+ - lib/face-no-more/version.rb
68
+ homepage: https://gitlab.com/sdalu/face-no-more
69
+ licenses:
70
+ - MIT
71
+ metadata: {}
72
+ post_install_message:
73
+ rdoc_options: []
74
+ require_paths:
75
+ - lib
76
+ required_ruby_version: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - ">="
79
+ - !ruby/object:Gem::Version
80
+ version: '0'
81
+ required_rubygems_version: !ruby/object:Gem::Requirement
82
+ requirements:
83
+ - - ">="
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ requirements: []
87
+ rubygems_version: 3.0.8
88
+ signing_key:
89
+ specification_version: 4
90
+ summary: Generate avatars
91
+ test_files: []