swdyh-quilt 0.0.2

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.
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.rdoc 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,138 @@
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
+ require 'date'
12
+ include FileUtils
13
+
14
+ NAME = "quilt"
15
+ AUTHOR = "swdyh"
16
+ EMAIL = "youhei@gmail.com"
17
+ DESCRIPTION = "a library for generating identicon."
18
+ RUBYFORGE_PROJECT = "quilt"
19
+ HOMEPATH = "http://#{RUBYFORGE_PROJECT}.rubyforge.org"
20
+ BIN_FILES = %w( )
21
+ VERS = "0.0.2"
22
+
23
+ REV = File.read(".svn/entries")[/committed-rev="(d+)"/, 1] rescue nil
24
+ CLEAN.include ['**/.*.sw?', '*.gem', '.config']
25
+ RDOC_OPTS = [
26
+ '--title', "#{NAME} documentation",
27
+ "--charset", "utf-8",
28
+ "--opname", "index.html",
29
+ "--line-numbers",
30
+ "--main", "README.rdoc",
31
+ "--inline-source",
32
+ ]
33
+
34
+ task :default => [:test]
35
+ task :package => [:clean]
36
+
37
+ Rake::TestTask.new("test") do |t|
38
+ t.libs << "test"
39
+ t.pattern = "test/**/*_test.rb"
40
+ t.verbose = true
41
+ end
42
+
43
+ spec = Gem::Specification.new do |s|
44
+ s.name = NAME
45
+ s.version = VERS
46
+ s.platform = Gem::Platform::RUBY
47
+ s.has_rdoc = true
48
+ s.extra_rdoc_files = ["README.rdoc", "ChangeLog", "MIT-LICENSE"]
49
+ s.rdoc_options += RDOC_OPTS + ['--exclude', '^(examples|extras)/']
50
+ s.summary = DESCRIPTION
51
+ s.description = DESCRIPTION
52
+ s.author = AUTHOR
53
+ s.email = EMAIL
54
+ s.homepage = HOMEPATH
55
+ s.executables = BIN_FILES
56
+ s.rubyforge_project = RUBYFORGE_PROJECT
57
+ s.bindir = "bin"
58
+ s.require_path = "lib"
59
+ # s.autorequire = ""
60
+ s.test_files = Dir["test/test_*.rb"]
61
+
62
+ #s.add_dependency('activesupport', '>=1.3.1')
63
+ #s.required_ruby_version = '>= 1.8.2'
64
+
65
+ s.files = %w(README.rdoc ChangeLog Rakefile) +
66
+ Dir.glob("{bin,doc,test,lib,templates,generator,extras,website,script}/**/*") +
67
+ Dir.glob("ext/**/*.{h,c,rb}") +
68
+ Dir.glob("examples/**/*.rb") +
69
+ Dir.glob("tools/*.rb")
70
+
71
+ s.extensions = FileList["ext/**/extconf.rb"].to_a
72
+ end
73
+
74
+ Rake::GemPackageTask.new(spec) do |p|
75
+ p.need_tar = true
76
+ p.gem_spec = spec
77
+ end
78
+
79
+ task :install do
80
+ name = "#{NAME}-#{VERS}.gem"
81
+ sh %{rake package}
82
+ sh %{sudo gem install pkg/#{name}}
83
+ end
84
+
85
+ task :uninstall => [:clean] do
86
+ sh %{sudo gem uninstall #{NAME}}
87
+ end
88
+
89
+
90
+ Rake::RDocTask.new do |rdoc|
91
+ rdoc.rdoc_dir = 'html'
92
+ rdoc.options += RDOC_OPTS
93
+ rdoc.template = "resh"
94
+ #rdoc.template = "#{ENV['template']}.rb" if ENV['template']
95
+ if ENV['DOC_FILES']
96
+ rdoc.rdoc_files.include(ENV['DOC_FILES'].split(/,\s*/))
97
+ else
98
+ rdoc.rdoc_files.include('README.rdoc', 'ChangeLog')
99
+ rdoc.rdoc_files.include('lib/**/*.rb')
100
+ rdoc.rdoc_files.include('ext/**/*.c')
101
+ end
102
+ end
103
+
104
+ desc "Publish to RubyForge"
105
+ task :rubyforge => [:rdoc, :package] do
106
+ require 'rubyforge'
107
+ Rake::RubyForgePublisher.new(RUBYFORGE_PROJECT, 'swdyh').upload
108
+ end
109
+
110
+ desc 'Package and upload the release to rubyforge.'
111
+ task :release => [:clean, :package] do |t|
112
+ v = ENV["VERSION"] or abort "Must supply VERSION=x.y.z"
113
+ abort "Versions don't match #{v} vs #{VERS}" unless v == VERS
114
+ pkg = "pkg/#{NAME}-#{VERS}"
115
+
116
+ rf = RubyForge.new
117
+ puts "Logging in"
118
+ rf.login
119
+
120
+ c = rf.userconfig
121
+ # c["release_notes"] = description if description
122
+ # c["release_changes"] = changes if changes
123
+ c["preformatted"] = true
124
+
125
+ files = [
126
+ "#{pkg}.tgz",
127
+ "#{pkg}.gem"
128
+ ].compact
129
+
130
+ puts "Releasing #{NAME} v. #{VERS}"
131
+ rf.add_release RUBYFORGE_PROJECT, NAME, VERS, *files
132
+ end
133
+
134
+ desc 'Show information about the gem.'
135
+ task :debug_gem do
136
+ puts spec.to_ruby
137
+ end
138
+
data/lib/quilt.rb ADDED
@@ -0,0 +1,265 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'rubygems'
3
+ require 'digest/sha1'
4
+
5
+ module Quilt
6
+ class ImageRmagick
7
+ def initialize width, height
8
+ require 'RMagick'
9
+ @image = Magick::Image.new width, height
10
+ @image.format = 'png'
11
+ end
12
+
13
+ def color r, g, b
14
+ sprintf('#%02x%02x%02x', r, g, b)
15
+ end
16
+
17
+ def transparent color
18
+ @image.transparent color
19
+ end
20
+
21
+ def fill_rect x, y, _x, _y, color
22
+ dr = Magick::Draw.new
23
+ dr.fill color
24
+ dr.rectangle x, y, _x, _y
25
+ dr.draw @image
26
+ end
27
+
28
+ def polygon points, color
29
+ unless points.empty?
30
+ dr = Magick::Draw.new
31
+ dr.fill color
32
+ dr.polygon *(points.flatten)
33
+ dr.draw @image
34
+ end
35
+ end
36
+
37
+ def 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
+
45
+ def resize size
46
+ @image.resize! size, size
47
+ end
48
+ end
49
+
50
+ class ImageGD
51
+ def initialize width, height
52
+ require 'GD'
53
+ @image = GD::Image.new width, height
54
+ end
55
+
56
+ def color r, g, b
57
+ @image.colorAllocate r, g, b
58
+ end
59
+
60
+ def transparent color
61
+ @image.transparent color
62
+ end
63
+
64
+ def fill_rect x, y, _x, _y, color
65
+ @image.filledRectangle x, y, _x, _y, color
66
+ end
67
+
68
+ def polygon points, color
69
+ poly = GD::Polygon.new
70
+ points.each do |i|
71
+ poly.addPt i[0], i[1]
72
+ end
73
+ @image.filledPolygon poly, color
74
+ end
75
+
76
+ def write path
77
+ File.open(path, 'w') do |f|
78
+ @image.png f
79
+ end
80
+ end
81
+
82
+ def to_blob
83
+ @image.pngStr
84
+ end
85
+
86
+ def resize size
87
+ _image = GD::Image.new size, size
88
+ # FIXME bug
89
+ @image.copyResized _image, 0, 0, 0, 0, size, size, @image.width, @image.height
90
+ @image = _image
91
+ end
92
+ end
93
+
94
+ class Identicon
95
+ PATCHES = [
96
+ [0, 4, 24, 20, 0],
97
+ [0, 4, 20, 0],
98
+ [2, 24, 20, 2],
99
+ [0, 2, 22, 20, 0],
100
+ [2, 14, 22, 10, 2],
101
+ [0, 14, 24, 22, 0],
102
+ [2, 24, 22, 13, 11, 22, 20, 2],
103
+ [0, 14, 22, 0],
104
+ [6, 8, 18, 16, 6],
105
+ [4, 20, 10, 12, 2, 4],
106
+ [0, 2, 12, 10, 0],
107
+ [10, 14, 22, 10],
108
+ [20, 12, 24, 20],
109
+ [10, 2, 12, 10],
110
+ [0, 2, 10, 0],
111
+ [],
112
+ ]
113
+ CENTER_PATCHES = [0, 4, 8, 15]
114
+ PATCH_SIZE = 5
115
+ @@image_lib = ImageRmagick
116
+ @@salt = ''
117
+ attr_reader :code
118
+
119
+ def initialize str = '', opt = {}
120
+ case opt[:type]
121
+ when :code
122
+ @code = str.to_i
123
+ when :ip
124
+ @code = Identicon.ip2code str
125
+ else
126
+ @code = Identicon.calc_code str.to_s
127
+ end
128
+ @decode = decode @code
129
+
130
+ if opt[:size]
131
+ @scale = (((opt[:size] / 3) - 1) / (PATCH_SIZE - 1)) + 1
132
+ @resize_to = opt[:size]
133
+ else
134
+ @scale = opt[:scale] || 1
135
+ end
136
+
137
+ @patch_width = (PATCH_SIZE - 1) * @scale + 1
138
+ @image = @@image_lib.new @patch_width * 3, @patch_width * 3
139
+ @back_color = @image.color 255, 255, 255
140
+ @fore_color = @image.color @decode[:red], @decode[:green], @decode[:blue]
141
+ @image.transparent @back_color
142
+ render
143
+
144
+ if @resize_to
145
+ @image.resize @resize_to
146
+ end
147
+ end
148
+
149
+ def decode code
150
+ {
151
+ :center_type => (code & 0x3),
152
+ :center_invert => (((code >> 2) & 0x01) != 0),
153
+ :corner_type => ((code >> 3) & 0x0f),
154
+ :corner_invert => (((code >> 7) & 0x01) != 0),
155
+ :corner_turn => ((code >> 8) & 0x03),
156
+ :side_type => ((code >> 10) & 0x0f),
157
+ :side_invert => (((code >> 14) & 0x01) != 0),
158
+ :side_turn => ((code >> 15) & 0x03),
159
+ :red => (((code >> 16) & 0x01f) << 3),
160
+ :green => (((code >> 21) & 0x01f) << 3),
161
+ :blue => (((code >> 27) & 0x01f) << 3),
162
+ }
163
+ end
164
+
165
+ def render
166
+ center = [[1, 1]]
167
+ side = [[1, 0], [2, 1], [1, 2], [0, 1]]
168
+ corner = [[0, 0], [2, 0], [2, 2], [0, 2]]
169
+
170
+ draw_patches(center, CENTER_PATCHES[@decode[:center_type]],
171
+ 0, @decode[:center_invert])
172
+ draw_patches(side, @decode[:side_type],
173
+ @decode[:side_turn], @decode[:side_invert])
174
+ draw_patches(corner, @decode[:corner_type],
175
+ @decode[:corner_turn], @decode[:corner_invert])
176
+ end
177
+
178
+ def draw_patches list, patch, turn, invert
179
+ list.each do |i|
180
+ draw(:x => i[0], :y => i[1], :patch => patch,
181
+ :turn => turn, :invert => invert)
182
+ turn += 1
183
+ end
184
+ end
185
+
186
+ def draw opt = {}
187
+ x = opt[:x] * @patch_width
188
+ y = opt[:y] * @patch_width
189
+ patch = opt[:patch] % PATCHES.size
190
+ turn = opt[:turn] % 4
191
+
192
+ if opt[:invert]
193
+ fore, back = @back_color, @fore_color
194
+ else
195
+ fore, back = @fore_color, @back_color
196
+ end
197
+ @image.fill_rect(x, y, x + @patch_width, y + @patch_width, back)
198
+
199
+ points = []
200
+ PATCHES[patch].each do |pt|
201
+ dx = pt % PATCH_SIZE
202
+ dy = pt / PATCH_SIZE
203
+ px = dx.to_f / (PATCH_SIZE - 1) * @patch_width
204
+ py = dy.to_f / (PATCH_SIZE - 1) * @patch_width
205
+
206
+ case turn
207
+ when 1
208
+ px, py = @patch_width - py, px
209
+ when 2
210
+ px, py = @patch_width - px, @patch_width - py
211
+ when 3
212
+ px, py = py, @patch_width - px
213
+ end
214
+ points << [x + px, y + py]
215
+ end
216
+ @image.polygon points, fore
217
+ end
218
+
219
+ def write path = "#{@code}.png"
220
+ @image.write path
221
+ end
222
+
223
+ def to_blob
224
+ @image.to_blob
225
+ end
226
+
227
+ def self.calc_code str
228
+ extract_code Identicon.digest(str)
229
+ end
230
+
231
+ def self.ip2code ip
232
+ code_ip = extract_code(ip.split('.'))
233
+ extract_code Identicon.digest(code_ip.to_s)
234
+ end
235
+
236
+ def self.digest str
237
+ Digest::SHA1.digest(str + @@salt)
238
+ end
239
+
240
+ def self.extract_code list
241
+ tmp = [list[0].to_i << 24, list[1].to_i << 16,
242
+ list[2].to_i << 8, list[3].to_i]
243
+ tmp.inject(0) do |r, i|
244
+ r | ((i[31] == 1) ? -(i & 0x7fffffff) : i)
245
+ end
246
+ end
247
+
248
+ def self.image_lib= image_lib
249
+ @@image_lib = image_lib
250
+ end
251
+
252
+ def self.image_lib
253
+ @@image_lib
254
+ end
255
+
256
+ def self.salt= salt
257
+ @@salt = salt
258
+ end
259
+
260
+ def self.salt
261
+ @@salt
262
+ end
263
+ end
264
+ end
265
+
@@ -0,0 +1,88 @@
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
+
74
+ def test_size_opt_im
75
+ size = 100
76
+ Quilt::Identicon.image_lib = Quilt::ImageRmagick
77
+ identicon = Quilt::Identicon.new 'foo', :size => size
78
+ assert_equal size, identicon.instance_variable_get(:@image).instance_variable_get(:@image).rows
79
+ assert_equal size, identicon.instance_variable_get(:@image).instance_variable_get(:@image).columns
80
+ end
81
+
82
+ def test_size_opt_gd
83
+ Quilt::Identicon.image_lib = Quilt::ImageGD
84
+ identicon = Quilt::Identicon.new 'foo', :size => size
85
+ assert_equal size, identicon.instance_variable_get(:@image).instance_variable_get(:@image).width
86
+ assert_equal size, identicon.instance_variable_get(:@image).instance_variable_get(:@image).height
87
+ end
88
+ 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: swdyh-quilt
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - swdyh
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2008-06-19 00:00:00 -07: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.rdoc
24
+ - ChangeLog
25
+ - MIT-LICENSE
26
+ files:
27
+ - README.rdoc
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.rdoc
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