quilt 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/ChangeLog ADDED
@@ -0,0 +1,4 @@
1
+ == 0.0.1 / 2008-04-12
2
+
3
+ * initial release
4
+
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2008 swdyh
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README ADDED
@@ -0,0 +1,59 @@
1
+
2
+ = quilt
3
+
4
+
5
+ == Description
6
+ a library for generating identicon.
7
+
8
+
9
+ Identicon: http://en.wikipedia.org/wiki/Identicon
10
+
11
+ == Installation
12
+ Required RMagick or ruby-gd.
13
+
14
+ === Archive Installation
15
+
16
+ rake install
17
+
18
+ === Gem Installation
19
+
20
+ gem install quilt
21
+
22
+
23
+ == Features/Problems
24
+ * Output file type is PNG only.
25
+
26
+ == Synopsis
27
+
28
+ # input: any string
29
+ # output: 15 * 15 png (default)
30
+ identicon = Quilt::Identicon.new 'sample'
31
+ identicon.write 'sample15_15.png'
32
+
33
+ # input: identicon code(32 bit integer)
34
+ # output: 15 * 15 png (default)
35
+ identicon = Quilt::Identicon.new 1, :type => :code
36
+ identicon.write 'sample15_15_code.png'
37
+
38
+ # input: ip address
39
+ identicon = Quilt::Identicon.new '100.100.100.100', :type => :ip
40
+ identicon.write 'sample15_15_ip.png'
41
+
42
+ # output: 150 * 150 png
43
+ identicon = Quilt::Identicon.new 'sample', :scale => 10
44
+ identicon.write 'sample150_150.png'
45
+
46
+ # output: blob
47
+ identicon = Quilt::Identicon.new 'sample'
48
+ print identicon.to_blob
49
+
50
+ # change image library to Rmagick to GD
51
+ Quilt::Identicon.image_lib = Quilt::ImageGD
52
+ identicon = Quilt::Identicon.new 'sample'
53
+ identicon.write 'sample15_15_gd.png'
54
+
55
+ == Copyright
56
+
57
+ Author:: swdyh <youhei@gmail.com>
58
+ Copyright:: Copyright (c) 2008 swdyh
59
+ License:: The MIT License
data/Rakefile ADDED
@@ -0,0 +1,131 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'rake/clean'
4
+ require 'rake/testtask'
5
+ require 'rake/packagetask'
6
+ require 'rake/gempackagetask'
7
+ require 'rake/rdoctask'
8
+ require 'rake/contrib/rubyforgepublisher'
9
+ require 'rake/contrib/sshpublisher'
10
+ require 'fileutils'
11
+ include FileUtils
12
+
13
+ NAME = "quilt"
14
+ AUTHOR = "swdyh"
15
+ EMAIL = "youhei@gmail.com"
16
+ DESCRIPTION = "a library for generating identicon."
17
+ RUBYFORGE_PROJECT = "quilt"
18
+ HOMEPATH = "http://#{RUBYFORGE_PROJECT}.rubyforge.org"
19
+ BIN_FILES = %w( )
20
+ VERS = "0.0.1"
21
+
22
+ REV = File.read(".svn/entries")[/committed-rev="(d+)"/, 1] rescue nil
23
+ CLEAN.include ['**/.*.sw?', '*.gem', '.config']
24
+ RDOC_OPTS = [
25
+ '--title', "#{NAME} documentation",
26
+ "--charset", "utf-8",
27
+ "--opname", "index.html",
28
+ "--line-numbers",
29
+ "--main", "README",
30
+ "--inline-source",
31
+ ]
32
+
33
+ task :default => [:test]
34
+ task :package => [:clean]
35
+
36
+ Rake::TestTask.new("test") do |t|
37
+ t.libs << "test"
38
+ t.pattern = "test/**/*_test.rb"
39
+ t.verbose = true
40
+ end
41
+
42
+ spec = Gem::Specification.new do |s|
43
+ s.name = NAME
44
+ s.version = VERS
45
+ s.platform = Gem::Platform::RUBY
46
+ s.has_rdoc = true
47
+ s.extra_rdoc_files = ["README", "ChangeLog", "MIT-LICENSE"]
48
+ s.rdoc_options += RDOC_OPTS + ['--exclude', '^(examples|extras)/']
49
+ s.summary = DESCRIPTION
50
+ s.description = DESCRIPTION
51
+ s.author = AUTHOR
52
+ s.email = EMAIL
53
+ s.homepage = HOMEPATH
54
+ s.executables = BIN_FILES
55
+ s.rubyforge_project = RUBYFORGE_PROJECT
56
+ s.bindir = "bin"
57
+ s.require_path = "lib"
58
+ # s.autorequire = ""
59
+ s.test_files = Dir["test/test_*.rb"]
60
+
61
+ #s.add_dependency('activesupport', '>=1.3.1')
62
+ #s.required_ruby_version = '>= 1.8.2'
63
+
64
+ s.files = %w(README ChangeLog Rakefile) +
65
+ Dir.glob("{bin,doc,test,lib,templates,generator,extras,website,script}/**/*") +
66
+ Dir.glob("ext/**/*.{h,c,rb}") +
67
+ Dir.glob("examples/**/*.rb") +
68
+ Dir.glob("tools/*.rb")
69
+
70
+ s.extensions = FileList["ext/**/extconf.rb"].to_a
71
+ end
72
+
73
+ Rake::GemPackageTask.new(spec) do |p|
74
+ p.need_tar = true
75
+ p.gem_spec = spec
76
+ end
77
+
78
+ task :install do
79
+ name = "#{NAME}-#{VERS}.gem"
80
+ sh %{rake package}
81
+ sh %{sudo gem install pkg/#{name}}
82
+ end
83
+
84
+ task :uninstall => [:clean] do
85
+ sh %{sudo gem uninstall #{NAME}}
86
+ end
87
+
88
+
89
+ Rake::RDocTask.new do |rdoc|
90
+ rdoc.rdoc_dir = 'html'
91
+ rdoc.options += RDOC_OPTS
92
+ rdoc.template = "resh"
93
+ #rdoc.template = "#{ENV['template']}.rb" if ENV['template']
94
+ if ENV['DOC_FILES']
95
+ rdoc.rdoc_files.include(ENV['DOC_FILES'].split(/,\s*/))
96
+ else
97
+ rdoc.rdoc_files.include('README', 'ChangeLog')
98
+ rdoc.rdoc_files.include('lib/**/*.rb')
99
+ rdoc.rdoc_files.include('ext/**/*.c')
100
+ end
101
+ end
102
+
103
+ desc "Publish to RubyForge"
104
+ task :rubyforge => [:rdoc, :package] do
105
+ require 'rubyforge'
106
+ Rake::RubyForgePublisher.new(RUBYFORGE_PROJECT, 'swdyh').upload
107
+ end
108
+
109
+ desc 'Package and upload the release to rubyforge.'
110
+ task :release => [:clean, :package] do |t|
111
+ v = ENV["VERSION"] or abort "Must supply VERSION=x.y.z"
112
+ abort "Versions don't match #{v} vs #{VERS}" unless v == VERS
113
+ pkg = "pkg/#{NAME}-#{VERS}"
114
+
115
+ rf = RubyForge.new
116
+ puts "Logging in"
117
+ rf.login
118
+
119
+ c = rf.userconfig
120
+ # c["release_notes"] = description if description
121
+ # c["release_changes"] = changes if changes
122
+ c["preformatted"] = true
123
+
124
+ files = [
125
+ "#{pkg}.tgz",
126
+ "#{pkg}.gem"
127
+ ].compact
128
+
129
+ puts "Releasing #{NAME} v. #{VERS}"
130
+ rf.add_release RUBYFORGE_PROJECT, NAME, VERS, *files
131
+ end
data/lib/quilt.rb ADDED
@@ -0,0 +1,243 @@
1
+ require 'rubygems'
2
+ require 'digest/sha1'
3
+
4
+ module Quilt
5
+ class ImageRmagick
6
+ def initialize width, height
7
+ require 'RMagick'
8
+ @image = Magick::Image.new width, height
9
+ @image.format = 'png'
10
+ end
11
+
12
+ def color r, g, b
13
+ sprintf('#%02x%02x%02x', r, g, b)
14
+ end
15
+
16
+ def transparent color
17
+ @image.transparent color
18
+ end
19
+
20
+ def fill_rect x, y, _x, _y, color
21
+ dr = Magick::Draw.new
22
+ dr.fill color
23
+ dr.rectangle x, y, _x, _y
24
+ dr.draw @image
25
+ end
26
+
27
+ def polygon points, color
28
+ unless points.empty?
29
+ dr = Magick::Draw.new
30
+ dr.fill color
31
+ dr.polygon *(points.flatten)
32
+ dr.draw @image
33
+ end
34
+ end
35
+
36
+ def write path
37
+ # @image.write path
38
+ open(path, 'w') {|f| f.puts @image.to_blob }
39
+ end
40
+
41
+ def to_blob
42
+ @image.to_blob
43
+ end
44
+ end
45
+
46
+ class ImageGD
47
+ def initialize width, height
48
+ require 'GD'
49
+ @image = GD::Image.new width, height
50
+ end
51
+
52
+ def color r, g, b
53
+ @image.colorAllocate r, g, b
54
+ end
55
+
56
+ def transparent color
57
+ @image.transparent color
58
+ end
59
+
60
+ def fill_rect x, y, _x, _y, color
61
+ @image.filledRectangle x, y, _x, _y, color
62
+ end
63
+
64
+ def polygon points, color
65
+ poly = GD::Polygon.new
66
+ points.each do |i|
67
+ poly.addPt i[0], i[1]
68
+ end
69
+ @image.filledPolygon poly, color
70
+ end
71
+
72
+ def write path
73
+ File.open(path, 'w') do |f|
74
+ @image.png f
75
+ end
76
+ end
77
+
78
+ def to_blob
79
+ @image.pngStr
80
+ end
81
+ end
82
+
83
+ class Identicon
84
+ PATCHES = [
85
+ [0, 4, 24, 20, 0],
86
+ [0, 4, 20, 0],
87
+ [2, 24, 20, 2],
88
+ [0, 2, 22, 20, 0],
89
+ [2, 14, 22, 10, 2],
90
+ [0, 14, 24, 22, 0],
91
+ [2, 24, 22, 13, 11, 22, 20, 2],
92
+ [0, 14, 22, 0],
93
+ [6, 8, 18, 16, 6],
94
+ [4, 20, 10, 12, 2, 4],
95
+ [0, 2, 12, 10, 0],
96
+ [10, 14, 22, 10],
97
+ [20, 12, 24, 20],
98
+ [10, 2, 12, 10],
99
+ [0, 2, 10, 0],
100
+ [],
101
+ ]
102
+ CENTER_PATCHES = [0, 4, 8, 15]
103
+ PATCH_SIZE = 5
104
+ @@image_lib = ImageRmagick
105
+ @@salt = ''
106
+ attr_reader :code
107
+
108
+ def initialize str = '', opt = {}
109
+ case opt[:type]
110
+ when :code
111
+ @code = str.to_i
112
+ when :ip
113
+ @code = Identicon.ip2code str
114
+ else
115
+ @code = Identicon.calc_code str.to_s
116
+ end
117
+ @decode = decode @code
118
+ @scale = opt[:scale] || 1
119
+ @patch_width = (PATCH_SIZE - 1) * @scale + 1
120
+ @image = @@image_lib.new @patch_width * 3, @patch_width * 3
121
+ @back_color = @image.color 255, 255, 255
122
+ @fore_color = @image.color @decode[:red], @decode[:green], @decode[:blue]
123
+ @image.transparent @back_color
124
+ render
125
+ end
126
+
127
+ def decode code
128
+ {
129
+ :center_type => (code & 0x3),
130
+ :center_invert => (((code >> 2) & 0x01) != 0),
131
+ :corner_type => ((code >> 3) & 0x0f),
132
+ :corner_invert => (((code >> 7) & 0x01) != 0),
133
+ :corner_turn => ((code >> 8) & 0x03),
134
+ :side_type => ((code >> 10) & 0x0f),
135
+ :side_invert => (((code >> 14) & 0x01) != 0),
136
+ :side_turn => ((code >> 15) & 0x03),
137
+ :red => (((code >> 16) & 0x01f) << 3),
138
+ :green => (((code >> 21) & 0x01f) << 3),
139
+ :blue => (((code >> 27) & 0x01f) << 3),
140
+ }
141
+ end
142
+
143
+ def render
144
+ center = [[1, 1]]
145
+ side = [[1, 0], [2, 1], [1, 2], [0, 1]]
146
+ corner = [[0, 0], [2, 0], [2, 2], [0, 2]]
147
+
148
+ draw_patches(center, CENTER_PATCHES[@decode[:center_type]],
149
+ 0, @decode[:center_invert])
150
+ draw_patches(side, @decode[:side_type],
151
+ @decode[:side_turn], @decode[:side_invert])
152
+ draw_patches(corner, @decode[:corner_type],
153
+ @decode[:corner_turn], @decode[:corner_invert])
154
+ end
155
+
156
+ def draw_patches list, patch, turn, invert
157
+ list.each do |i|
158
+ draw(:x => i[0], :y => i[1], :patch => patch,
159
+ :turn => turn, :invert => invert)
160
+ turn += 1
161
+ end
162
+ end
163
+
164
+ def draw opt = {}
165
+ x = opt[:x] * @patch_width
166
+ y = opt[:y] * @patch_width
167
+ patch = opt[:patch] % PATCHES.size
168
+ turn = opt[:turn] % 4
169
+
170
+ if opt[:invert]
171
+ fore, back = @back_color, @fore_color
172
+ else
173
+ fore, back = @fore_color, @back_color
174
+ end
175
+ @image.fill_rect(x, y, x + @patch_width, y + @patch_width, back)
176
+
177
+ points = []
178
+ PATCHES[patch].each do |pt|
179
+ dx = pt % PATCH_SIZE
180
+ dy = pt / PATCH_SIZE
181
+ px = dx.to_f / (PATCH_SIZE - 1) * @patch_width
182
+ py = dy.to_f / (PATCH_SIZE - 1) * @patch_width
183
+
184
+ case turn
185
+ when 1
186
+ px, py = @patch_width - py, px
187
+ when 2
188
+ px, py = @patch_width - px, @patch_width - py
189
+ when 3
190
+ px, py = py, @patch_width - px
191
+ end
192
+ points << [x + px, y + py]
193
+ end
194
+ @image.polygon points, fore
195
+ end
196
+
197
+ def write path = "#{@code}.png"
198
+ @image.write path
199
+ end
200
+
201
+ def to_blob
202
+ @image.to_blob
203
+ end
204
+
205
+ def self.calc_code str
206
+ extract_code Identicon.digest(str)
207
+ end
208
+
209
+ def self.ip2code ip
210
+ code_ip = extract_code(ip.split('.'))
211
+ extract_code Identicon.digest(code_ip.to_s)
212
+ end
213
+
214
+ def self.digest str
215
+ Digest::SHA1.digest(str + @@salt)
216
+ end
217
+
218
+ def self.extract_code list
219
+ tmp = [list[0].to_i << 24, list[1].to_i << 16,
220
+ list[2].to_i << 8, list[3].to_i]
221
+ tmp.inject(0) do |r, i|
222
+ r | ((i[31] == 1) ? -(i & 0x7fffffff) : i)
223
+ end
224
+ end
225
+
226
+ def self.image_lib= image_lib
227
+ @@image_lib = image_lib
228
+ end
229
+
230
+ def self.image_lib
231
+ @@image_lib
232
+ end
233
+
234
+ def self.salt= salt
235
+ @@salt = salt
236
+ end
237
+
238
+ def self.salt
239
+ @@salt
240
+ end
241
+ end
242
+ end
243
+
@@ -0,0 +1,73 @@
1
+ require File.dirname(__FILE__) + '/test_helper.rb'
2
+ require 'test/unit'
3
+ require 'digest/md5'
4
+ require 'fileutils'
5
+
6
+ class QultTest < Test::Unit::TestCase
7
+ def setup
8
+ @tmp_dir = File.join 'test', 'tmp'
9
+ unless File.exist? @tmp_dir
10
+ Dir.mkdir @tmp_dir
11
+ end
12
+ end
13
+
14
+ def teardown
15
+ if File.exist? @tmp_dir
16
+ FileUtils.rm_r @tmp_dir
17
+ end
18
+ end
19
+
20
+ def test_identicon
21
+ identicon = Quilt::Identicon.new
22
+ assert_instance_of Quilt::Identicon, identicon
23
+ path = File.join 'test', 'tmp', 'test'
24
+ identicon.write path
25
+ assert File.exist?(path)
26
+ File.unlink path
27
+ end
28
+
29
+ def test_to_blob
30
+ identicon = Quilt::Identicon.new
31
+ path_b = File.join 'test', 'tmp', 'test_to_blob.png'
32
+ path_w = File.join 'test', 'tmp', 'test_write.png'
33
+
34
+ open(path_b, 'w') {|f| f.write identicon.to_blob }
35
+ identicon.write path_w
36
+
37
+ digest = Proc.new {|path| Digest::MD5.hexdigest(IO.read(path)) }
38
+ assert_equal digest.call(path_w), digest.call(path_w)
39
+
40
+ File.unlink path_b, path_w
41
+ end
42
+
43
+ def test_digest
44
+ digest = Quilt::Identicon.digest('foo')
45
+ assert_not_nil digest
46
+ Quilt::Identicon.salt = 'foo'
47
+ assert_not_equal digest, Quilt::Identicon.digest('foo')
48
+ end
49
+
50
+ def test_image_lib
51
+ image_other = Class.new do
52
+ def initialize a, b; end
53
+ def method_missing *arg; end
54
+ def write path; open(path, 'w') {|f| f.puts 'other' }; end
55
+ end
56
+
57
+ libs = [Quilt::ImageGD, Quilt::ImageRmagick, image_other]
58
+ libs.each do |lib|
59
+ Quilt::Identicon.image_lib = lib
60
+ assert_equal lib, Quilt::Identicon.image_lib
61
+ identicon = Quilt::Identicon.new
62
+ assert_equal lib, identicon.instance_variable_get(:@image).class
63
+ end
64
+ end
65
+
66
+ def test_salt
67
+ salts = ['foo', 'bar', 'baz']
68
+ salts.each do |salt|
69
+ Quilt::Identicon.salt = salt
70
+ assert_equal salt, Quilt::Identicon.salt
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,3 @@
1
+ require 'test/unit'
2
+ require File.dirname(__FILE__) + '/../lib/quilt'
3
+
metadata ADDED
@@ -0,0 +1,72 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: quilt
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - swdyh
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2008-04-13 00:00:00 +09:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: a library for generating identicon.
17
+ email: youhei@gmail.com
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files:
23
+ - README
24
+ - ChangeLog
25
+ - MIT-LICENSE
26
+ files:
27
+ - README
28
+ - ChangeLog
29
+ - Rakefile
30
+ - test/quilt_test.rb
31
+ - test/test_helper.rb
32
+ - lib/quilt.rb
33
+ - MIT-LICENSE
34
+ has_rdoc: true
35
+ homepage: http://quilt.rubyforge.org
36
+ post_install_message:
37
+ rdoc_options:
38
+ - --title
39
+ - quilt documentation
40
+ - --charset
41
+ - utf-8
42
+ - --opname
43
+ - index.html
44
+ - --line-numbers
45
+ - --main
46
+ - README
47
+ - --inline-source
48
+ - --exclude
49
+ - ^(examples|extras)/
50
+ require_paths:
51
+ - lib
52
+ required_ruby_version: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ version: "0"
57
+ version:
58
+ required_rubygems_version: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: "0"
63
+ version:
64
+ requirements: []
65
+
66
+ rubyforge_project: quilt
67
+ rubygems_version: 1.0.1
68
+ signing_key:
69
+ specification_version: 2
70
+ summary: a library for generating identicon.
71
+ test_files:
72
+ - test/test_helper.rb