hjw3001-waldo 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (7) hide show
  1. data/Manifest +5 -0
  2. data/README.rdoc +36 -0
  3. data/Rakefile +14 -0
  4. data/init.rb +1 -0
  5. data/lib/waldo.rb +193 -0
  6. data/waldo.gemspec +29 -0
  7. metadata +64 -0
@@ -0,0 +1,5 @@
1
+ init.rb
2
+ lib/waldo.rb
3
+ Rakefile
4
+ README.rdoc
5
+ Manifest
@@ -0,0 +1,36 @@
1
+ = Uniquify
2
+
3
+ Ruby gem to create a mosaic image from a series of smaller images.
4
+
5
+
6
+ == Install
7
+
8
+ gem install hjw3001-waldo --source http://gems.github.com
9
+
10
+
11
+ == Usage
12
+
13
+ TBD
14
+
15
+ == License
16
+
17
+ Copyright (c) 2009 Henry Wagner
18
+
19
+ Permission is hereby granted, free of charge, to any person obtaining
20
+ a copy of this software and associated documentation files (the
21
+ "Software"), to deal in the Software without restriction, including
22
+ without limitation the rights to use, copy, modify, merge, publish,
23
+ distribute, sublicense, and/or sell copies of the Software, and to
24
+ permit persons to whom the Software is furnished to do so, subject to
25
+ the following conditions:
26
+
27
+ The above copyright notice and this permission notice shall be
28
+ included in all copies or substantial portions of the Software.
29
+
30
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
31
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
32
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
33
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
34
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
35
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
36
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,14 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'echoe'
4
+
5
+ Echoe.new('waldo', '0.1.0') do |p|
6
+ p.description = "Ruby gem to create a mosaic image from a series of smaller images."
7
+ p.url = "http://github.com/hjw3001/waldo"
8
+ p.author = "Henry Wagner"
9
+ p.email = "hjw3001@gmail.com"
10
+ p.ignore_pattern = ["tmp/*", "script/*"]
11
+ p.development_dependencies = []
12
+ end
13
+
14
+ Dir["#{File.dirname(__FILE__)}/tasks/*.rake"].sort.each { |ext| load ext }
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ require 'waldo'
@@ -0,0 +1,193 @@
1
+ require 'rmagick'
2
+ require 'fileutils'
3
+ require 'erb'
4
+ require 'rexml/document'
5
+ require 'yaml'
6
+
7
+ class Waldo
8
+
9
+ @@template = <<EOF
10
+ # .waldo
11
+ #
12
+ # Please fill in fields like this:
13
+ #
14
+ # cache: c:/waldo/cache
15
+ # thumb: c:/waldo/thumb
16
+ # waldoized: c:/waldo/waldoized
17
+ #
18
+ cache:
19
+ thumb:
20
+ waldoized:
21
+ EOF
22
+
23
+ attr_reader :photos, :config
24
+
25
+ def initialize
26
+ @config = create_or_find_config
27
+ @photos = Array.new
28
+ load_photo_data
29
+ end
30
+
31
+ # Move these to waldo gem
32
+ def waldoize(photo_id,size)
33
+ amount = config['colorize_percentage']
34
+ file = Magick::Image.read("#{config['thumb']}/#{photo_id}.jpg").first
35
+ mosaic = Magick::Image.new(file.columns * size, file.rows * size)
36
+
37
+ file.rows.times {|y|
38
+ file.columns.times {|x|
39
+ pixel_color = file.pixel_color(x,y)
40
+ color = Pixel.as_int(pixel_color)
41
+ match = find_closest_photo(photos, color)
42
+ # Load the matching 75x75 version of the photo
43
+ thumb = Magick::Image.read("#{config['cache']}/#{match.external_id}.jpg").first
44
+ # Delete the thumbnail from the list once it has been used
45
+ delete_from_photos(match)
46
+ # Convert it to gray
47
+ gray = thumb.quantize(256, Magick::GRAYColorspace)
48
+ # Colorize the gray version to match the current pixel color
49
+ colorized = gray.colorize(amount, amount, amount, '#' + to_hex(pixel_color.red, pixel_color.green, pixel_color.blue))
50
+ # Add the colorized version of the photo to the final image
51
+ colorized.rows.times {|ty|
52
+ colorized.columns.times {|tx|
53
+ mosaic.pixel_color((x*size) + tx, (y*size) + ty, Magick::Pixel.new(colorized.pixel_color(tx,ty).red, colorized.pixel_color(tx,ty).green, colorized.pixel_color(tx,ty).blue, 0))
54
+ }
55
+ }
56
+ }
57
+ }
58
+ mosaic.write("waldo_#{photo_id}.jpg")
59
+ end
60
+
61
+ def build_xml_cache
62
+ photos = loadCache
63
+ xml_data = Array.new
64
+ for photo in photos
65
+ photo_median_data = Array.new
66
+ file = Magick::Image.read("#{photo}").first
67
+ file.rows.times {|y|
68
+ file.columns.times {|x|
69
+ pixel_color = file.pixel_color(x,y)
70
+ color = Pixel.as_int(pixel_color)
71
+ photo_median_data << color
72
+ }
73
+ }
74
+ photo_median_data.sort!
75
+ xml_data << PhotoXML.new(photo, photo_median_data[photo_median_data.size / 2])
76
+ end
77
+ # xml = REXML::Document.new(File.open("#{@config['xml']}"))
78
+ File.open("#{@config['xml']}", 'wb') do |dest|
79
+ dest.write ERB.new(File.open('cache.xml').read, nil, '-').result(binding)
80
+ end
81
+ end
82
+
83
+ def loadCache
84
+ jpgfiles = File.join(config['cache'], "*.jpg")
85
+ Dir.glob(jpgfiles)
86
+ end
87
+
88
+ protected
89
+
90
+ def find_closest_photo(photos, color)
91
+ if (photos.size == 1)
92
+ photos[0]
93
+ elsif photos[photos.size/2].median_int > color
94
+ find_closest_photo(photos.values_at(0...((photos.size/2))), color)
95
+ else
96
+ find_closest_photo(photos.values_at(photos.size/2...photos.size), color)
97
+ end
98
+ end
99
+
100
+ def to_hex(red, green, blue)
101
+ base = 16
102
+ "#{red.to_s(base=base).rjust(2, '0')}#{green.to_s(base=base).rjust(2, '0')}#{blue.to_s(base=base).rjust(2, '0')}"
103
+ end
104
+
105
+ def create_grey(photo, size)
106
+ if (!File.exists?("public/images/#{size}/#{photo.external_id}.jpg"))
107
+ image = Magick::Image.read("public/images/cache/#{photo.external_id}.jpg").first
108
+ image.resize!(size,size)
109
+ grey = image.quantize(256, Magick::GRAYColorspace)
110
+ grey.write("public/images/#{size}/#{photo.external_id}.jpg")
111
+ end
112
+ end
113
+
114
+ def create_or_find_config
115
+ home = ENV['HOME'] || ENV['USERPROFILE'] || ENV['HOMEPATH']
116
+ begin
117
+ config = YAML::load open(home + "/.waldo")
118
+ rescue
119
+ open(home + '/.waldo','w').write(@@template)
120
+ config = YAML::load open(home + "/.waldo")
121
+ end
122
+
123
+ if config['cache'] == nil or config['thumb'] == nil
124
+ puts "Please edit ~/.waldo to include your flickr api_key and secret\nTextmate users: mate ~/.waldo"
125
+ exit(0)
126
+ end
127
+
128
+ config
129
+ end
130
+
131
+ private
132
+
133
+ def load_photo_data
134
+ xml = REXML::Document.new(File.open("#{@config['xml']}"))
135
+ xml.elements.each("//photo") {|photo| photos << Photo.new(photo) }
136
+ # Sort photos by median_int
137
+ photos.sort!{|x,y| x.median_int <=> y.median_int}
138
+ end
139
+
140
+ def delete_from_photos(photo)
141
+ photos.delete(photo)
142
+ if (photos.size == 0)
143
+ load_photo_data
144
+ end
145
+ end
146
+
147
+ end
148
+
149
+ class Pixel
150
+ def self.as_int(pixel)
151
+ base = 16
152
+ "#{pixel.red.to_s(base=base).rjust(2, '0')}#{pixel.green.to_s(base=base).rjust(2, '0')}#{pixel.blue.to_s(base=base).rjust(2, '0')}".to_i(16)
153
+ end
154
+ end
155
+
156
+ # xml.elements.each("//photo") {|photo| Photo.create(:external_id => photo.attributes['id'].split('.').first,
157
+ # :mean => photo.attributes['a'],
158
+ # :median => photo.attributes['m'],
159
+ # :mean_red => photo.attributes['ar'],
160
+ # :mean_green => photo.attributes['ag'],
161
+ # :mean_blue => photo.attributes['ab'],
162
+ # :median_red => photo.attributes['mr'],
163
+ # :median_green => photo.attributes['mg'],
164
+ # :median_blue => photo.attributes['mb'])}
165
+ class Photo
166
+ attr_reader :external_id, :mean, :median, :mean_red, :mean_green, :mean_blue, :median_red, :median_green, :median_blue
167
+
168
+ def initialize(photo)
169
+ @external_id = photo.attributes['id'].split('.').first
170
+ @mean = photo.attributes['a']
171
+ @median = photo.attributes['m']
172
+ @mean_red = photo.attributes['ar']
173
+ @mean_green = photo.attributes['ag']
174
+ @mean_blue = photo.attributes['ab']
175
+ @median_red = photo.attributes['mr']
176
+ @median_green = photo.attributes['mg']
177
+ @median_blue = photo.attributes['mb']
178
+ end
179
+
180
+ def median_int
181
+ median.to_i(16)
182
+ end
183
+ end
184
+
185
+ class PhotoXML
186
+ attr_reader :external_id, :median
187
+
188
+ def initialize(photo, median)
189
+ @external_id = photo.slice(photo.rindex('/') + 1, photo.size)
190
+ @median = median
191
+ end
192
+
193
+ end
@@ -0,0 +1,29 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = %q{waldo}
3
+ s.version = "0.1.0"
4
+
5
+ s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
6
+ s.authors = ["Henry Wagner"]
7
+ s.date = %q{2009-02-12}
8
+ s.description = %q{Ruby gem to create a mosaic image from a series of smaller images.}
9
+ s.email = %q{hjw3001@gmail.com}
10
+ s.extra_rdoc_files = ["lib/waldo.rb", "README.rdoc"]
11
+ s.files = ["init.rb", "lib/waldo.rb", "Rakefile", "README.rdoc", "Manifest", "waldo.gemspec"]
12
+ s.has_rdoc = true
13
+ s.homepage = %q{http://github.com/hjw3001/waldo}
14
+ s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Waldo", "--main", "README.rdoc"]
15
+ s.require_paths = ["lib"]
16
+ s.rubyforge_project = %q{waldo}
17
+ s.rubygems_version = %q{1.2.0}
18
+ s.summary = %q{Ruby gem to create a mosaic image from a series of smaller images.}
19
+
20
+ if s.respond_to? :specification_version then
21
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
22
+ s.specification_version = 2
23
+
24
+ if current_version >= 3 then
25
+ else
26
+ end
27
+ else
28
+ end
29
+ end
metadata ADDED
@@ -0,0 +1,64 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: hjw3001-waldo
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Henry Wagner
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-02-12 00:00:00 -08:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: Ruby gem to create a mosaic image from a series of smaller images.
17
+ email: hjw3001@gmail.com
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files:
23
+ - lib/waldo.rb
24
+ - README.rdoc
25
+ files:
26
+ - init.rb
27
+ - lib/waldo.rb
28
+ - Rakefile
29
+ - README.rdoc
30
+ - Manifest
31
+ - waldo.gemspec
32
+ has_rdoc: true
33
+ homepage: http://github.com/hjw3001/waldo
34
+ post_install_message:
35
+ rdoc_options:
36
+ - --line-numbers
37
+ - --inline-source
38
+ - --title
39
+ - Waldo
40
+ - --main
41
+ - README.rdoc
42
+ require_paths:
43
+ - lib
44
+ required_ruby_version: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: "0"
49
+ version:
50
+ required_rubygems_version: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: "1.2"
55
+ version:
56
+ requirements: []
57
+
58
+ rubyforge_project: waldo
59
+ rubygems_version: 1.2.0
60
+ signing_key:
61
+ specification_version: 2
62
+ summary: Ruby gem to create a mosaic image from a series of smaller images.
63
+ test_files: []
64
+