scarf 0.2.0

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
+ SHA1:
3
+ metadata.gz: 4026733a01ae99c008ae69f75a4135e8cd7826a1
4
+ data.tar.gz: 1c4f9658d3e320298f623b5448b494f878928e7f
5
+ SHA512:
6
+ metadata.gz: 27ea92c4698fc7d5bc7aa44d58027b97fd55b014c156eb50e814d2228fcf2583c13a151afa38c3359c76a25325e659396e772212d2421e21097dad1938d49a48
7
+ data.tar.gz: 2dc7c53f1c897c2a31c8aecec84a0feff774951c401b9219fe1c5a5cce68c4ea0f88c13fdb5f06dba9c8a747449aa460e8f0c65643fbfdfbee0b3dacf5655f50
@@ -0,0 +1,177 @@
1
+ module Scarf
2
+ class Identicon
3
+ PATCHES = [
4
+ [0, 4, 24, 20, 0],
5
+ [0, 4, 20, 0],
6
+ [2, 24, 20, 2],
7
+ [0, 2, 22, 20, 0],
8
+ [2, 14, 22, 10, 2],
9
+ [0, 14, 24, 22, 0],
10
+ [2, 24, 22, 13, 11, 22, 20, 2],
11
+ [0, 14, 22, 0],
12
+ [6, 8, 18, 16, 6],
13
+ [4, 20, 10, 12, 2, 4],
14
+ [0, 2, 12, 10, 0],
15
+ [10, 14, 22, 10],
16
+ [20, 12, 24, 20],
17
+ [10, 2, 12, 10],
18
+ [0, 2, 10, 0],
19
+ [],
20
+ ]
21
+
22
+ CENTER_PATCHES = [0, 4, 8, 15]
23
+ PATCH_SIZE = 5
24
+
25
+ attr_reader :code
26
+
27
+ def initialize(str = '', opt = {})
28
+ case opt[:type]
29
+ when :code
30
+ @code = str.to_i
31
+ when :ip
32
+ @code = Identicon.ip2code str
33
+ else
34
+ @code = Identicon.calc_code str.to_s
35
+ end
36
+
37
+ @decode = decode @code
38
+
39
+ if opt[:size]
40
+ @scale = opt[:size].to_f / (PATCH_SIZE * 3)
41
+ else
42
+ @scale = opt[:scale] || 1
43
+ end
44
+
45
+ @image_lib = ImageSVG
46
+
47
+ @transparent = !!opt[:transparent] &&
48
+ [ImageRmagick, ImageSVG].include?(@image_lib)
49
+ @patch_width = PATCH_SIZE * @scale
50
+ @image = @image_lib.new(@patch_width * 3, @patch_width * 3,
51
+ :transparent => @transparent)
52
+ @back_color = @image.color 255, 255, 255
53
+ @fore_color = opt[:color] || @image.color(@decode[:red], @decode[:green], @decode[:blue])
54
+ render
55
+ end
56
+
57
+ def decode(code)
58
+ {
59
+ :center_type => (code & 0x3),
60
+ :center_invert => (((code >> 2) & 0x01) != 0),
61
+ :corner_type => ((code >> 3) & 0x0f),
62
+ :corner_invert => (((code >> 7) & 0x01) != 0),
63
+ :corner_turn => ((code >> 8) & 0x03),
64
+ :side_type => ((code >> 10) & 0x0f),
65
+ :side_invert => (((code >> 14) & 0x01) != 0),
66
+ :side_turn => ((code >> 15) & 0x03),
67
+ :red => (((code >> 16) & 0x01f) << 3),
68
+ :green => (((code >> 21) & 0x01f) << 3),
69
+ :blue => (((code >> 27) & 0x01f) << 3),
70
+ }
71
+ end
72
+
73
+ def render
74
+ center = [[1, 1]]
75
+ side = [[1, 0], [2, 1], [1, 2], [0, 1]]
76
+ corner = [[0, 0], [2, 0], [2, 2], [0, 2]]
77
+
78
+ draw_patches(center, CENTER_PATCHES[@decode[:center_type]],
79
+ 0, @decode[:center_invert])
80
+ draw_patches(side, @decode[:side_type],
81
+ @decode[:side_turn], @decode[:side_invert])
82
+ draw_patches(corner, @decode[:corner_type],
83
+ @decode[:corner_turn], @decode[:corner_invert])
84
+ end
85
+
86
+ def draw_patches(list, patch, turn, invert)
87
+ list.each do |i|
88
+ draw(:x => i[0], :y => i[1], :patch => patch,
89
+ :turn => turn, :invert => invert)
90
+ turn += 1
91
+ end
92
+ end
93
+
94
+ def draw(opt = {})
95
+ x = opt[:x] * @patch_width
96
+ y = opt[:y] * @patch_width
97
+ patch = opt[:patch] % PATCHES.size
98
+ turn = opt[:turn] % 4
99
+
100
+ if opt[:invert]
101
+ fore, back = @back_color, @fore_color
102
+ else
103
+ fore, back = @fore_color, @back_color
104
+ end
105
+
106
+ offset = (@image_lib == Scarf::ImageSVG) ? 0 : 1
107
+
108
+ if !(@transparent && back == @back_color)
109
+ @image.fill_rect(x, y, x + @patch_width - offset,
110
+ y + @patch_width - offset, back)
111
+ end
112
+
113
+ points = []
114
+ PATCHES[patch].each do |pt|
115
+ dx = pt % PATCH_SIZE
116
+ dy = pt / PATCH_SIZE
117
+ len = @patch_width - offset
118
+ px = dx.to_f / (PATCH_SIZE - 1) * len
119
+ py = dy.to_f / (PATCH_SIZE - 1) * len
120
+
121
+ case turn
122
+ when 1
123
+ px, py = len - py, px
124
+ when 2
125
+ px, py = len - px, len - py
126
+ when 3
127
+ px, py = py, len - px
128
+ end
129
+ points << [x + px, y + py]
130
+ end
131
+
132
+ if @transparent
133
+ if fore == @back_color
134
+ @image.polygon_clip points
135
+ else
136
+ @image.polygon points, fore
137
+ end
138
+ else
139
+ @image.polygon points, fore
140
+ end
141
+ end
142
+
143
+ def write(path = "#{@code}.png")
144
+ @image.write(path)
145
+ end
146
+
147
+ def to_blob
148
+ @image.to_blob
149
+ end
150
+
151
+ def self.calc_code(str)
152
+ extract_code(Identicon.digest(str))
153
+ end
154
+
155
+ def self.ip2code(ip)
156
+ code_ip = extract_code(ip.split('.'))
157
+ extract_code(Identicon.digest(code_ip.to_s))
158
+ end
159
+
160
+ def self.digest(str)
161
+ Digest::SHA1.digest(str)
162
+ end
163
+
164
+ def self.extract_code(list)
165
+ if list.respond_to?(:getbyte)
166
+ tmp = [list.getbyte(0) << 24, list.getbyte(1) << 16,
167
+ list.getbyte(2) << 8, list.getbyte(3)]
168
+ else
169
+ tmp = [list[0].to_i << 24, list[1].to_i << 16,
170
+ list[2].to_i << 8, list[3].to_i]
171
+ end
172
+ tmp.inject(0) do |r, i|
173
+ r | ((i[31] == 1) ? -(i & 0x7fffffff) : i)
174
+ end
175
+ end
176
+ end
177
+ end
@@ -0,0 +1,60 @@
1
+ module Scarf
2
+ class ImageSVG
3
+ def initialize(width, height, opt = {})
4
+ @transparent = !!opt[:transparent]
5
+ @mask = @transparent ? 'mask="clip"' : ''
6
+ @masks = ''
7
+ @image = ''
8
+ @width = width
9
+ @height = height
10
+ @head = %(<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 #{width} #{height}">\n)
11
+ end
12
+
13
+ def color(r, g, b)
14
+ 'rgb(%d, %d, %d)' % [r, g, b]
15
+ end
16
+
17
+ def fill_rect(x, y, _x, _y, color)
18
+ @image << %(<rect x="#{x}" y="#{y}" width="#{_x - x}" height="#{_y - y}" fill="#{color}" stroke-width="0" stroke="white" mask="url(#clip)"/>\n)
19
+ end
20
+
21
+ def polygon(points, color)
22
+ unless points.empty?
23
+ ps = points.map { |i| i.join(',') }.join(' ')
24
+ @image << %(<polygon points="#{ps}" stroke-width="0" fill="#{color}" mask="(#clip)"/>\n)
25
+ end
26
+ end
27
+
28
+ def polygon_clip(points)
29
+ unless points.empty?
30
+ ps = points.map { |i| i.join(',') }.join(' ')
31
+ @masks << %(<polygon points="#{ps}" stroke-width="0"/>\n)
32
+ end
33
+ end
34
+
35
+ def write(path)
36
+ open(path, 'wb') { |f| f.write self.to_blob }
37
+ end
38
+
39
+ def to_blob
40
+ if @transparent
41
+ @head + build_mask + @image + "\n</svg>"
42
+ else
43
+ @head + @image + "\n</svg>"
44
+ end
45
+ end
46
+
47
+ private
48
+
49
+ def build_mask
50
+ <<~MASK
51
+ <mask id="clip" maskUnits="userSpaceOnUse" x="0" y="0" width="#{@width}" height="#{@height}">
52
+ <g fill="black" fill-rule="evenodd">
53
+ <rect x="0" y="0" width="#{@width}" height="#{@height}" fill="white"/>
54
+ #{@masks}
55
+ </g>
56
+ </mask>
57
+ MASK
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,45 @@
1
+ module Scarf
2
+ class InitialAvatar
3
+ def initialize(name, font_family: [])
4
+ @name = name
5
+ @font_family = font_family
6
+ end
7
+
8
+ BACKGROUND = %w(#ff4040 #7f2020 #cc5c33 #734939 #bf9c8f #995200 #4c2900 #f2a200 #ffd580 #332b1a #4c3d00 #ffee00 #b0b386 #64664d #6c8020 #c3d96c #143300 #19bf00 #53a669 #bfffd9 #40ffbf #1a332e #00b3a7 #165955 #00b8e6 #69818c #005ce6 #6086bf #000e66 #202440 #393973 #4700b3 #2b0d33 #aa86b3 #ee00ff #bf60b9 #4d3949 #ff00aa #7f0044 #f20061 #330007 #d96c7b).freeze
9
+
10
+ def svg
11
+ <<~WRAPPER.gsub(/$\s+/, '').strip
12
+ <svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 100 100">
13
+ <circle cx="50" cy="50" r="50" fill="#{fill}" />
14
+ <text fill="#FFFFFF" font-size="50" font-family="#{font_family}" x="50" y="50" text-anchor="middle" alignment-baseline="central">#{initials}</text>
15
+ </svg>
16
+ WRAPPER
17
+ end
18
+
19
+ private
20
+
21
+ # Default to sans-serif.
22
+ def font_family
23
+ (quoted_fonts + %w(sans-serif)).join(', ')
24
+ end
25
+
26
+ # Surround the font name with single quotes if there's a space in the name, and isn't quoted already.
27
+ def quoted_fonts
28
+ @font_family.map do |font|
29
+ return font unless font.include?(' ')
30
+ return font if font[0] == "'"
31
+ "'#{font}'"
32
+ end
33
+ end
34
+
35
+ # TODO: Need to add a hashing logic to ensure a supplied name always returns the same colour.
36
+ def fill
37
+ BACKGROUND.sample
38
+ end
39
+
40
+ # Upcase first letter of up to first two segments of the supplied name.
41
+ def initials
42
+ @name.split[0..1].map { |segment| segment[0] }.join('').upcase
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,3 @@
1
+ module Scarf
2
+ VERSION = '0.2.0'
3
+ end
data/lib/scarf.rb ADDED
@@ -0,0 +1,4 @@
1
+ require 'digest/sha1'
2
+ require_relative 'scarf/image_svg'
3
+ require_relative 'scarf/identicon'
4
+ require_relative 'scarf/initial_avatar'
@@ -0,0 +1,5 @@
1
+ require 'test/unit'
2
+ require 'digest/md5'
3
+ require 'fileutils'
4
+
5
+ require_relative '../lib/scarf'
metadata ADDED
@@ -0,0 +1,95 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: scarf
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ platform: ruby
6
+ authors:
7
+ - harigopal
8
+ - swdyh
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2017-04-20 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rake
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - "~>"
19
+ - !ruby/object:Gem::Version
20
+ version: '12.0'
21
+ type: :development
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - "~>"
26
+ - !ruby/object:Gem::Version
27
+ version: '12.0'
28
+ - !ruby/object:Gem::Dependency
29
+ name: test-unit
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - "~>"
33
+ - !ruby/object:Gem::Version
34
+ version: '3.1'
35
+ type: :development
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - "~>"
40
+ - !ruby/object:Gem::Version
41
+ version: '3.1'
42
+ - !ruby/object:Gem::Dependency
43
+ name: rspec
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - "~>"
47
+ - !ruby/object:Gem::Version
48
+ version: '3.5'
49
+ type: :development
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - "~>"
54
+ - !ruby/object:Gem::Version
55
+ version: '3.5'
56
+ description: |-
57
+ A Ruby library for generating initial avatars and identicons, forked from swdyh/quilt
58
+ https://github.com/harigopal/quilt
59
+ email: mail@harigopal.in
60
+ executables: []
61
+ extensions: []
62
+ extra_rdoc_files: []
63
+ files:
64
+ - lib/scarf.rb
65
+ - lib/scarf/identicon.rb
66
+ - lib/scarf/image_svg.rb
67
+ - lib/scarf/initial_avatar.rb
68
+ - lib/scarf/version.rb
69
+ - test/test_helper.rb
70
+ homepage: https://github.com/harigopal/scarf
71
+ licenses:
72
+ - MIT
73
+ metadata: {}
74
+ post_install_message:
75
+ rdoc_options: []
76
+ require_paths:
77
+ - lib
78
+ required_ruby_version: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: 2.3.0
83
+ required_rubygems_version: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ requirements: []
89
+ rubyforge_project:
90
+ rubygems_version: 2.6.11
91
+ signing_key:
92
+ specification_version: 4
93
+ summary: A Ruby library for generating initial avatars and identicons.
94
+ test_files:
95
+ - test/test_helper.rb