the-architect-sprite_generator 0.1.12 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -39,29 +39,24 @@ class SpriteGenerator
39
39
  def initialize(files_or_paths, output, root, options = {})
40
40
  @files = find_files(files_or_paths)
41
41
  return if @files.nil? || @files.empty?
42
- @root = root || ''
43
- @output = output
44
- @delimiter = options[:delimiter] || '-'
45
- @analyzed = analyze_filenames(@files, @delimiter)
46
- @template = Liquid::Template.parse(options[:template] || '')
47
-
48
- @sprite_location = options[:sprite_location] || @output
49
- @background = options[:background] || '#FFFFFF00'
50
- @tile_size = options[:tile]
51
- @alignment = options[:alignment] ? Magick.const_get("#{camelize(options[:alignment])}Gravity") : Magick::CenterGravity
42
+ @root = root || ''
43
+ @output = output
44
+ @delimiter = options[:delimiter] || '-'
45
+ @analyzed = find_files_for_mode(options[:distribution] || :smart)
46
+ @template = Liquid::Template.parse(options[:template] || '')
47
+ @sprite_location = options[:sprite_location] || @output
48
+ @background = options[:background] || '#FFFFFF00'
49
+ @tile_size = options[:tile]
50
+ @alignment = options[:alignment] ? Magick.const_get("#{camelize(options[:alignment])}Gravity") : Magick::CenterGravity
52
51
  end
53
52
 
54
53
 
55
54
  def create
56
55
  raise 'No files found.' if @files.nil? || @files.empty?
57
- background = @background
58
- unless @tile_size.nil?
59
- size_x, size_y = @tile_size.split('x').first(2).map{|dim| dim.to_i}
60
- tile = Magick::Image.new(size_x, size_y){ self.background_color = background }
61
- tile.format = "PNG"
62
- end
56
+ build_tile
63
57
  destination = @root.nil? || @root.empty? ? @output : File.join(@root, @output)
64
- image, css = build(tile)
58
+ image, css = build_sprite_and_css
59
+ background = @background
65
60
  image.write(destination){ self.background_color = background }
66
61
  css
67
62
  end
@@ -69,66 +64,99 @@ class SpriteGenerator
69
64
 
70
65
  protected
71
66
 
72
- # simplyfied version of active_supports camelize version
73
- def camelize(lower_case_and_underscored_word)
74
- lower_case_and_underscored_word.to_s.gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase }
75
- end
76
-
77
- def build(tile = nil)
78
- background = @background
79
- images = ImageList.new{ self.background_color = background }
80
- context = { 'sprite_location' => @sprite_location, 'tile' => tile }
81
- css = []
67
+ def build_sprite_and_css
68
+ background = @background
69
+ @images = ImageList.new{ self.background_color = background }
70
+ context = { 'sprite_location' => @sprite_location }
71
+ @css = []
82
72
 
83
- @analyzed.each do |key, value|
84
- if tile
85
- context['left'] = images.length > 0 ? tile.columns : 0
73
+ @analyzed.keys.sort.each do |key|
74
+ value = @analyzed[key]
75
+ if @tile
76
+ context['left'] = @images.length > 0 ? @tile.columns : 0
86
77
  else
87
- context['left'] = images.length > 0 ? images.append(false).columns : 0
78
+ context['left'] = @images.length > 0 ? @images.append(false).columns : 0
88
79
  end
89
- context['top'] = 0
80
+ context['top'] = 0
90
81
  context['basename'] = key
91
- context['overall'] = images.length
82
+ context['overall'] = @images.length
92
83
 
93
- if value.size > 1
94
- image_list = ImageList.new(*value){ self.background_color = background }
95
- if tile
96
- tiles = ImageList.new{ self.background_color = background }
97
- image_list.each do |image|
98
- tiles << tile.composite(image, @alignment, Magick::OverCompositeOp)
99
- end
100
- images.from_blob(tiles.append(true).to_blob){ self.background_color = background }
101
- else
102
- images.from_blob(image_list.append(true).to_blob){ self.background_color = background }
103
- end
104
- context['variations'] = image_list.length
105
- context['type'] = :list
106
- context['images'] = image_list
107
- context['filenames'] = value
108
- else
109
-
110
- filename = value.flatten.first
111
- image = Image.read(filename){ self.background_color = background }
112
-
113
- context['variations'] = 0
114
- context['variation_name'] = ''
115
- context['variation_number'] = 0
116
- context['full_filename'] = filename
117
- context['file_basename'] = File.basename(filename, '.*')
118
- context['variation_name'] = context['file_basename'].gsub(/^#{context['basename']}#{@delimiter}/, '')
119
-
120
- context['type'] = :image
121
-
122
- if tile
123
- images.from_blob(tile.composite(image.first, @alignment, Magick::OverCompositeOp).to_blob){ self.background_color = background }
124
- else
125
- images.from_blob(image.first.to_blob){ self.background_color = background }
126
- end
127
- end
128
- css << build_css(context)
84
+ value.size > 1 ? build_image_list(context, value.sort) : build_single_image(context, value.flatten.first)
85
+ @css << build_css(context)
129
86
  end
130
87
 
131
- [images.append(false), css.join("\n")]
88
+ [@images.append(false), @css.join("\n")]
89
+ end
90
+
91
+
92
+ def build_single_image(context, filename)
93
+ background = @background
94
+ image = Image.read(filename){ self.background_color = background }.flatten.first
95
+
96
+ context.merge!(build_context_for_single_image(image, filename, context['basename']))
97
+
98
+ if @tile
99
+ @images.from_blob(@tile.composite(image, @alignment, Magick::OverCompositeOp).to_blob){ self.background_color = background }
100
+ else
101
+ @images.from_blob(image.to_blob){ self.background_color = background }
102
+ end
103
+ end
104
+
105
+
106
+ def build_context_for_single_image(image, filename, basename)
107
+ file_basename = File.basename(filename, '.*')
108
+ {
109
+ 'variations' => 0,
110
+ 'variation_name' => '',
111
+ 'variation_number' => 0,
112
+ 'full_filename' => filename,
113
+ 'file_basename' => file_basename,
114
+ 'variation_name' => file_basename.gsub(/^#{basename}#{@delimiter}/, ''),
115
+ 'width' => @tile ? tile.columns : image.columns,
116
+ 'height' => @tile ? tile.rows : image.rows,
117
+ 'type' => :image
118
+ }
119
+ end
120
+
121
+
122
+ def build_image_list(context, image_filenames)
123
+ background = @background
124
+ image_list = ImageList.new(*image_filenames){ self.background_color = background }
125
+ if @tile
126
+ tiles = ImageList.new{ self.background_color = background }
127
+ image_list.each do |image|
128
+ tiles << @tile.composite(image, @alignment, Magick::OverCompositeOp)
129
+ end
130
+ append_to_sprite(tiles)
131
+ else
132
+ append_to_sprite(image_list)
133
+ end
134
+ context.merge!(build_context_for_image_list(image_list, image_filenames))
135
+ end
136
+
137
+
138
+ def append_to_sprite(images)
139
+ background = @background
140
+ @images.from_blob(images.append(true).to_blob){ self.background_color = background }
141
+ end
142
+
143
+
144
+ def build_context_for_image_list(image_list, image_filenames)
145
+ {
146
+ 'variations' => image_list.length,
147
+ 'type' => :list,
148
+ 'images' => image_list,
149
+ 'filenames' => image_filenames
150
+ }
151
+ end
152
+
153
+
154
+ def build_tile
155
+ return if @tile_size.nil?
156
+ background = @background
157
+ size_x, size_y = @tile_size.split('x').first(2).map{|dim| dim.to_i}
158
+ @tile = Magick::Image.new(size_x, size_y){ self.background_color = background }
159
+ @tile.format = "PNG"
132
160
  end
133
161
 
134
162
 
@@ -147,21 +175,19 @@ protected
147
175
 
148
176
  def build_css_for_list(context)
149
177
  new_context = context.dup
150
- tile = new_context.delete('tile')
151
- image_list = context.delete('images')
178
+ image_list = context.delete('images')
152
179
  new_context['type'] = :image
153
180
  css = image_list.inject([]) do |css, image|
154
- new_context['width'] = tile ? tile.columns : image.columns
155
- new_context['height'] = tile ? tile.rows : image.rows
181
+ new_context['width'] = @tile ? @tile.columns : image.columns
182
+ new_context['height'] = @tile ? @tile.rows : image.rows
156
183
  new_context['variation_number'] = css.size
157
-
158
- new_context['full_filename'] = context['filenames'].shift
159
- new_context['filename'] = File.basename(new_context['full_filename'])
160
- new_context['file_basename'] = File.basename(new_context['full_filename'], '.*')
161
- new_context['variation_name'] = new_context['file_basename'].gsub(/^#{new_context['basename']}#{@delimiter}/, '')
184
+ new_context['full_filename'] = context['filenames'].shift
185
+ new_context['filename'] = File.basename(new_context['full_filename'])
186
+ new_context['file_basename'] = File.basename(new_context['full_filename'], '.*')
187
+ new_context['variation_name'] = new_context['file_basename'].gsub(/^#{new_context['basename']}#{@delimiter}/, '')
162
188
 
163
189
  css << build_css(new_context.dup)
164
- new_context['top'] += tile ? tile.columns : new_context['height']
190
+ new_context['top'] += @tile ? @tile.columns : new_context['height']
165
191
  css
166
192
  end.join("\n")
167
193
  end
@@ -181,17 +207,53 @@ protected
181
207
  end
182
208
 
183
209
 
210
+ # put filenames in format for each mode
211
+ def find_files_for_mode(mode)
212
+ case mode
213
+ when :smart
214
+ smart_distribution
215
+ when :horizontal
216
+ horizontal_distribution
217
+ when :vertical
218
+ vertical_distribution
219
+ end
220
+ end
221
+
222
+
184
223
  # gather information about the selected files
185
224
  # check for variations by using a delimiter as an indicator
186
- def analyze_filenames(file_names, delimiter = '_')
187
- file_names.inject(Hash.new{|hash, key| hash[key] = Array.new;}) do |h, file|
188
- basename = File.basename(file).split('.').first
189
- without_variation = basename.split(delimiter)[0..-2].join(delimiter)
190
- basename = without_variation.nil? || without_variation == '' ? basename : without_variation
225
+ def smart_distribution
226
+ @files.inject(Hash.new{|hash, key| hash[key] = Array.new;}) do |h, file|
227
+ basename = File.basename(file, '.*')
228
+ without_variation = basename.split(@delimiter)[0..-2].join(@delimiter)
229
+ basename = without_variation.nil? || without_variation == '' ? basename : without_variation
191
230
  h[basename] << file
192
231
  h
193
232
  end
194
233
  end
195
234
 
196
235
 
236
+ def horizontal_distribution
237
+ @files.inject(Hash.new{|hash, key| hash[key] = Array.new;}) do |h, file|
238
+ basename = File.basename(file)
239
+ h[basename] << file
240
+ h
241
+ end
242
+ end
243
+
244
+
245
+ def vertical_distribution
246
+ @files.inject(Hash.new{|hash, key| hash[key] = Array.new;}) do |h, file|
247
+ basename = File.basename(file)
248
+ h['all'] << file
249
+ h
250
+ end
251
+ end
252
+
253
+
254
+ # simplyfied version of active_support's camelize version
255
+ def camelize(lower_case_and_underscored_word)
256
+ lower_case_and_underscored_word.to_s.gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase }
257
+ end
258
+
197
259
  end
@@ -18,13 +18,42 @@ class SpriteGeneratorTest < Test::Unit::TestCase
18
18
  Dir.glob('test/output/*').each{|f| File.delete f }
19
19
  end
20
20
 
21
- def test_should_set_correct_context_for_images_without_variations
21
+ def test_should_user_horizontal_distribution
22
+ template = %q{ {{left}} }
23
+ generator = SpriteGenerator.new(@all_images_path, @output, nil, { :template => template, :distribution => :horizontal })
24
+ css = generator.create
25
+ assert css.include?('240')
26
+ end
27
+
28
+ def test_should_user_vertical_distribution
29
+ template = %q{ {{top}} }
30
+ generator = SpriteGenerator.new(@all_images_path, @output, nil, { :template => template, :distribution => :vertical })
31
+ css = generator.create
32
+ `open #{@output}`
33
+ sleep 1
34
+ assert css.include?('240')
35
+ end
36
+
37
+ def test_should_set_correct_context_filebasename_for_images_without_variations
22
38
  template = %q{ {{file_basename}} }
23
39
  generator = SpriteGenerator.new(@all_images_path, @output, nil, { :template => template, :delimiter => '_' })
24
40
  css = generator.create
25
41
  assert css.include?('emoticon-evilgrin')
26
42
  end
27
43
 
44
+ def test_should_set_correct_context_width_for_images_without_variations
45
+ template = %q{ {{width}} }
46
+ generator = SpriteGenerator.new(@all_images_path, @output, nil, { :template => template, :delimiter => '_' })
47
+ css = generator.create
48
+ assert css.include?('16')
49
+ end
50
+
51
+ def test_should_set_correct_context_top_for_images_without_variations
52
+ template = %q{ {{top}} }
53
+ generator = SpriteGenerator.new(@all_images_path, @output, nil, { :template => template, :delimiter => '_' })
54
+ css = generator.create
55
+ assert !css.include?('-16')
56
+ end
28
57
 
29
58
  def test_should_create_correct_context
30
59
  template = %q{
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: the-architect-sprite_generator
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.12
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Marcel Scherf