face-no-more 0.1.1

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.
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: []