hjw3001-waldo 0.1.0

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.
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
+