sprite-factory 1.0.0 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +10 -0
- data/README.md +39 -31
- data/Rakefile +2 -0
- data/bin/sf +3 -2
- data/lib/sprite_factory.rb +25 -3
- data/lib/sprite_factory/layout/horizontal.rb +42 -0
- data/lib/sprite_factory/layout/packed.rb +107 -0
- data/lib/sprite_factory/layout/vertical.rb +42 -0
- data/lib/sprite_factory/runner.rb +20 -1
- data/sprite_factory.gemspec +5 -1
- data/test/images/reference/index.html +16 -0
- data/test/images/reference/irregular.packed.css +24 -0
- data/test/images/reference/irregular.packed.png +0 -0
- data/test/images/reference/regular.packed.css +24 -0
- data/test/images/reference/regular.packed.png +0 -0
- data/test/integration_test.rb +12 -0
- data/test/layout/horizontal_test.rb +100 -0
- data/test/layout/packed_test.rb +221 -0
- data/test/layout/test_case.rb +56 -0
- data/test/layout/vertical_test.rb +100 -0
- data/test/test_case.rb +7 -0
- metadata +19 -9
- data/lib/sprite_factory/layout.rb +0 -89
- data/test/layout_test.rb +0 -228
data/.gitignore
ADDED
data/README.md
CHANGED
@@ -12,6 +12,7 @@ The library provides:
|
|
12
12
|
* many customizable options
|
13
13
|
* support for any stylesheet syntax, including [CSS](http://www.w3.org/Style/CSS/) and [Sass](http://sass-lang.com/).
|
14
14
|
* support for any image library, including [RMagick](http://rmagick.rubyforge.org/) and [ChunkyPNG](https://github.com/wvanbergen/chunky_png).
|
15
|
+
* support for pngcrush'n the generated image file
|
15
16
|
|
16
17
|
|
17
18
|
Installation
|
@@ -20,11 +21,18 @@ Installation
|
|
20
21
|
$ gem install sprite-factory
|
21
22
|
|
22
23
|
An image library is also required. SpriteFactory comes with built in support for
|
23
|
-
[RMagick](http://rmagick.rubyforge.org/) or
|
24
|
-
[ChunkyPng](https://github.com/wvanbergen/chunky_png) and is easily extensible to
|
25
|
-
use any image library of your choice.
|
24
|
+
[RMagick](http://rmagick.rubyforge.org/) or [ChunkyPng](https://github.com/wvanbergen/chunky_png).
|
26
25
|
|
27
|
-
|
26
|
+
RMagick is the most common image libary to use, installation instructions for ubuntu:
|
27
|
+
|
28
|
+
$ sudo aptitude install imageMagick libMagickWand-dev
|
29
|
+
$ sudo gem install rmagick
|
30
|
+
|
31
|
+
ChunkyPng is lighter weight but only supports .png format:
|
32
|
+
|
33
|
+
$ gem install chunky_png
|
34
|
+
|
35
|
+
SpriteFactory can also be easily extended to use the image library of your choice.
|
28
36
|
|
29
37
|
Usage
|
30
38
|
=====
|
@@ -62,7 +70,7 @@ Customization
|
|
62
70
|
Much of the behavior can be customized by overriding the following options:
|
63
71
|
|
64
72
|
- `:output` - specify output location for generated files
|
65
|
-
- `:layout` - specify layout algorithm (horizontal or
|
73
|
+
- `:layout` - specify layout algorithm (horizontal, vertical or packed)
|
66
74
|
- `:style` - specify output style (css or sass)
|
67
75
|
- `:library` - specify image library to use (rmagick or chunkypng)
|
68
76
|
- `:selector` - specify custom css selector (see below)
|
@@ -70,18 +78,32 @@ Much of the behavior can be customized by overriding the following options:
|
|
70
78
|
- `:padding` - add padding to each sprite
|
71
79
|
- `:width` - fix width of each sprite to a specific size
|
72
80
|
- `:height` - fix height of each sprite to a specific size
|
81
|
+
- `:pngcrush` - pngcrush the generated output image (if pngcrush is available)
|
73
82
|
|
74
83
|
Options can be passed as command line arguments to the `sf` script:
|
75
84
|
|
76
|
-
$ sf images/icons --style sass --layout
|
85
|
+
$ sf images/icons --style sass --layout packed
|
77
86
|
|
78
87
|
Options can also be passed as the 2nd argument to the `#run!` method:
|
79
88
|
|
80
|
-
SpriteFactory.run!('images/icons', :style => :sass, :layout => :
|
89
|
+
SpriteFactory.run!('images/icons', :style => :sass, :layout => :packed)
|
81
90
|
|
82
91
|
You can see the results of many of these options by viewing the sample page that
|
83
92
|
comes with the gem in `test/images/reference/index.html`.
|
84
93
|
|
94
|
+
Layout
|
95
|
+
======
|
96
|
+
|
97
|
+
The generated image can be laid out in a horizontal or a vertical strip by
|
98
|
+
providing a `:layout` option (defaults to horizontal). A **new option in v1.2.0** is
|
99
|
+
to use a **:packed** layout which will attempt to generate an optimized packed
|
100
|
+
square-ish layout.
|
101
|
+
|
102
|
+
For more details on the bin-packing algorithm used:
|
103
|
+
|
104
|
+
* You can find a [description here](http://codeincomplete.com/posts/2011/5/7/bin_packing/)
|
105
|
+
* You can find a [demo here](http://codeincomplete.com/posts/2011/5/7/bin_packing/example/)
|
106
|
+
|
85
107
|
Customizing the CSS Selector
|
86
108
|
============================
|
87
109
|
|
@@ -113,7 +135,7 @@ building a Ruby on Rails application you might need to generate URL's using the
|
|
113
135
|
helper method to ensure it gets the appopriate cache-busting query parameter.
|
114
136
|
|
115
137
|
By default, the SpriteFactory generates simple url's that contain only the basename of the
|
116
|
-
unified sprite image, but you can control the generation of these url's using the
|
138
|
+
unified sprite image, but you can control the generation of these url's using the `:csspath`
|
117
139
|
option:
|
118
140
|
|
119
141
|
For most CDN's, you can prepend a simple string to the image name:
|
@@ -171,37 +193,23 @@ The sprite factory library can also be extended in a number of other ways.
|
|
171
193
|
|
172
194
|
_(see existing code for examples of each)._
|
173
195
|
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
SpriteFactory comes with built in support for
|
178
|
-
[RMagick](http://rmagick.rubyforge.org/) or
|
179
|
-
[ChunkyPng](https://github.com/wvanbergen/chunky_png)
|
180
|
-
|
181
|
-
RMagick is the most flexible image libary to use, but requires ImageMagick
|
182
|
-
binaries, installation instructions for ubuntu:
|
183
|
-
|
184
|
-
$ sudo aptitude install imageMagick libMagickWand-dev
|
185
|
-
$ sudo gem install rmagick
|
186
|
-
|
187
|
-
ChunkyPng is lighter weight and has no binary requirements, but only supports
|
188
|
-
.png format. Installation is a simple gem install:
|
189
|
-
|
190
|
-
$ gem install chunky_png
|
196
|
+
License
|
197
|
+
=======
|
191
198
|
|
192
|
-
|
199
|
+
See [LICENSE](https://github.com/jakesgordon/sprite-factory/blob/master/LICENSE) file.
|
193
200
|
|
194
|
-
|
201
|
+
Credits
|
195
202
|
=======
|
196
203
|
|
197
|
-
|
204
|
+
Thanks to my employer, [LiquidPlanner](http://liquidplanner.com) for allowing me to take this idea from our
|
205
|
+
online project management web application and release it into the wild.
|
198
206
|
|
199
207
|
Contact
|
200
208
|
=======
|
201
209
|
|
202
|
-
|
203
|
-
|
204
|
-
|
210
|
+
If you have any ideas, feedback, requests or bug reports, you can reach me at
|
211
|
+
[jake@codeincomplete.com](mailto:jake@codeincomplete.com), or via
|
212
|
+
my website: [Code inComplete](http://codeincomplete.com/posts/2011/4/29/sprite_factory/).
|
205
213
|
|
206
214
|
|
207
215
|
|
data/Rakefile
CHANGED
@@ -31,6 +31,7 @@ task :reference do
|
|
31
31
|
regenerate.call('test/images/regular')
|
32
32
|
regenerate.call('test/images/regular', :output => 'test/images/regular.horizontal', :selector => 'img.horizontal_', :layout => :horizontal)
|
33
33
|
regenerate.call('test/images/regular', :output => 'test/images/regular.vertical', :selector => 'img.vertical_', :layout => :vertical)
|
34
|
+
regenerate.call('test/images/regular', :output => 'test/images/regular.packed', :selector => 'img.packed_', :layout => :packed)
|
34
35
|
regenerate.call('test/images/regular', :output => 'test/images/regular.padded', :selector => 'img.padded_', :padding => 10)
|
35
36
|
regenerate.call('test/images/regular', :output => 'test/images/regular.fixed', :selector => 'img.fixed_', :width => 100, :height => 100)
|
36
37
|
regenerate.call('test/images/regular', :output => 'test/images/regular.sassy', :selector => 'img.sassy_', :style => :sass)
|
@@ -38,6 +39,7 @@ task :reference do
|
|
38
39
|
regenerate.call('test/images/irregular')
|
39
40
|
regenerate.call('test/images/irregular', :output => 'test/images/irregular.horizontal', :selector => 'img.horizontal_', :layout => :horizontal)
|
40
41
|
regenerate.call('test/images/irregular', :output => 'test/images/irregular.vertical', :selector => 'img.vertical_', :layout => :vertical)
|
42
|
+
regenerate.call('test/images/irregular', :output => 'test/images/irregular.packed', :selector => 'img.packed_', :layout => :packed)
|
41
43
|
regenerate.call('test/images/irregular', :output => 'test/images/irregular.padded', :selector => 'img.padded_', :padding => 10)
|
42
44
|
regenerate.call('test/images/irregular', :output => 'test/images/irregular.fixed', :selector => 'img.fixed_', :width => 100, :height => 100)
|
43
45
|
regenerate.call('test/images/irregular', :output => 'test/images/irregular.sassy', :selector => 'img.sassy_', :style => :sass)
|
data/bin/sf
CHANGED
@@ -20,11 +20,12 @@ op.on("-v", "--version") do
|
|
20
20
|
end
|
21
21
|
|
22
22
|
output_help = "specify output location, without any extension"
|
23
|
-
layout_help = "specify layout orientation ( horizontal, vertical )"
|
23
|
+
layout_help = "specify layout orientation ( horizontal, vertical, packed )"
|
24
24
|
style_help = "specify output style format ( css, sass )"
|
25
25
|
library_help = "specify image library to use ( rmagic, chunkypng )"
|
26
26
|
selector_help = "specify custom selector to use for each css rule ( default: 'img.' )"
|
27
27
|
csspath_help = "specify custom path to use for css image urls ( default: output file's basename )"
|
28
|
+
pngcrush_help = "use pngcrush to optimize generated image"
|
28
29
|
|
29
30
|
op.on("--output [PATH]", output_help) {|value| options[:output] = value }
|
30
31
|
op.on("--layout [ORIENTATION]", layout_help) {|value| options[:layout] = value }
|
@@ -32,6 +33,7 @@ op.on("--style [STYLE]", style_help) {|value| options[:style] = v
|
|
32
33
|
op.on("--library [LIBRARY]", library_help) {|value| options[:library] = value }
|
33
34
|
op.on("--selector [SELECTOR]", selector_help) {|value| options[:selector] = value }
|
34
35
|
op.on("--csspath [CSSPATH]", csspath_help) {|value| options[:csspath] = value }
|
36
|
+
op.on("--pngcrush", pngcrush_help) {|value| options[:pngcrush] = value }
|
35
37
|
|
36
38
|
begin
|
37
39
|
op.parse!(ARGV)
|
@@ -39,7 +41,6 @@ begin
|
|
39
41
|
SpriteFactory.run!(ARGV[0], options)
|
40
42
|
rescue Exception => ex
|
41
43
|
puts ex.message
|
42
|
-
puts op.to_s
|
43
44
|
exit
|
44
45
|
end
|
45
46
|
|
data/lib/sprite_factory.rb
CHANGED
@@ -2,14 +2,13 @@ module SpriteFactory
|
|
2
2
|
|
3
3
|
#----------------------------------------------------------------------------
|
4
4
|
|
5
|
-
VERSION = "1.
|
5
|
+
VERSION = "1.2.0"
|
6
6
|
SUMMARY = "Automatic CSS sprite generator"
|
7
7
|
DESCRIPTION = "Combines individual images from a directory into a single sprite image file and creates an appropriate CSS stylesheet"
|
8
8
|
LIB = File.dirname(__FILE__)
|
9
9
|
|
10
10
|
autoload :Runner, File.join(LIB, 'sprite_factory/runner') # controller that glues everything together
|
11
|
-
autoload :
|
12
|
-
autoload :Style, File.join(LIB, 'sprite_factory/style') # style generators
|
11
|
+
autoload :Style, File.join(LIB, 'sprite_factory/style') # style generators all live in a single module (for now)
|
13
12
|
|
14
13
|
def self.run!(input, config = {}, &block)
|
15
14
|
Runner.new(input, config).run!(&block)
|
@@ -26,6 +25,29 @@ module SpriteFactory
|
|
26
25
|
attr_accessor :library
|
27
26
|
attr_accessor :selector
|
28
27
|
attr_accessor :csspath
|
28
|
+
attr_accessor :pngcrush
|
29
|
+
end
|
30
|
+
|
31
|
+
#----------------------------------------------------------------------------
|
32
|
+
|
33
|
+
module Layout # abstract module for various layout strategies
|
34
|
+
|
35
|
+
autoload :Horizontal, File.join(LIB, 'sprite_factory/layout/horizontal') # concrete module for layout in a single horizontal strip
|
36
|
+
autoload :Vertical, File.join(LIB, 'sprite_factory/layout/vertical') # concrete module for layout in a single vertical strip
|
37
|
+
autoload :Packed, File.join(LIB, 'sprite_factory/layout/packed') # concrete module for layout in a bin-packed square
|
38
|
+
|
39
|
+
def self.horizontal
|
40
|
+
Horizontal
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.vertical
|
44
|
+
Vertical
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.packed
|
48
|
+
Packed
|
49
|
+
end
|
50
|
+
|
29
51
|
end
|
30
52
|
|
31
53
|
#----------------------------------------------------------------------------
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module SpriteFactory
|
2
|
+
module Layout
|
3
|
+
module Horizontal
|
4
|
+
|
5
|
+
def self.layout(images, options = {})
|
6
|
+
width = options[:width]
|
7
|
+
height = options[:height]
|
8
|
+
hpadding = options[:hpadding] || 0
|
9
|
+
vpadding = options[:vpadding] || 0
|
10
|
+
max_height = height || ((2 * vpadding) + images.map{|i| i[:height]}.max)
|
11
|
+
x = 0
|
12
|
+
images.each do |i|
|
13
|
+
|
14
|
+
if width
|
15
|
+
i[:cssw] = width
|
16
|
+
i[:cssx] = x
|
17
|
+
i[:x] = x + (width - i[:width]) / 2
|
18
|
+
else
|
19
|
+
i[:cssw] = i[:width] + (2 * hpadding) # image width plus padding
|
20
|
+
i[:cssx] = x # anchored at x
|
21
|
+
i[:x] = i[:cssx] + hpadding # image drawn offset to account for padding
|
22
|
+
end
|
23
|
+
|
24
|
+
if height
|
25
|
+
i[:cssh] = height
|
26
|
+
i[:cssy] = 0
|
27
|
+
i[:y] = 0 + (height - i[:height]) / 2
|
28
|
+
else
|
29
|
+
i[:cssh] = i[:height] + (2 * vpadding) # image height plus padding
|
30
|
+
i[:cssy] = (max_height - i[:cssh]) / 2 # centered vertically
|
31
|
+
i[:y] = i[:cssy] + vpadding # image drawn offset to account for padding
|
32
|
+
end
|
33
|
+
|
34
|
+
x = x + i[:cssw]
|
35
|
+
|
36
|
+
end
|
37
|
+
{ :width => x, :height => max_height }
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
module SpriteFactory
|
2
|
+
module Layout
|
3
|
+
module Packed
|
4
|
+
|
5
|
+
#------------------------------------------------------------------------
|
6
|
+
|
7
|
+
def self.layout(images, options = {})
|
8
|
+
|
9
|
+
raise NotImplementedError, ":packed layout does not support the :padding option" if (options[:padding].to_i > 0) || (options[:hpadding].to_i > 0) || (options[:vpadding].to_i > 0)
|
10
|
+
raise NotImplementedError, ":packed layout does not support fixed :width/:height option" if options[:width] || options[:height]
|
11
|
+
|
12
|
+
return { :width => 0, :height => 0 } if images.empty?
|
13
|
+
|
14
|
+
images.sort! do |a,b|
|
15
|
+
diff = [b[:width], b[:height]].max <=> [a[:width], a[:height]].max
|
16
|
+
diff = [b[:width], b[:height]].min <=> [a[:width], a[:height]].min if diff.zero?
|
17
|
+
diff = b[:height] <=> a[:height] if diff.zero?
|
18
|
+
diff = b[:width] <=> a[:width] if diff.zero?
|
19
|
+
diff
|
20
|
+
end
|
21
|
+
|
22
|
+
root = { :x => 0, :y => 0, :w => images[0][:width], :h => images[0][:height] }
|
23
|
+
|
24
|
+
images.each do |i|
|
25
|
+
if (node = findNode(root, i[:width], i[:height]))
|
26
|
+
placeImage(i, node)
|
27
|
+
splitNode(node, i[:width], i[:height])
|
28
|
+
else
|
29
|
+
root = grow(root, i[:width], i[:height])
|
30
|
+
redo
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
{ :width => root[:w], :height => root[:h] }
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.placeImage(image, node)
|
39
|
+
image[:cssx] = image[:x] = node[:x] # TODO
|
40
|
+
image[:cssy] = image[:y] = node[:y] # * support for :padding option
|
41
|
+
image[:cssw] = image[:width] # * support for fixed :width/:height option
|
42
|
+
image[:cssh] = image[:height]
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.findNode(root, w, h)
|
46
|
+
if root[:used]
|
47
|
+
findNode(root[:right], w, h) || findNode(root[:down], w, h)
|
48
|
+
elsif (w <= root[:w]) && (h <= root[:h])
|
49
|
+
root
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.splitNode(node, w, h)
|
54
|
+
node[:used] = true
|
55
|
+
node[:down] = { :x => node[:x], :y => node[:y] + h, :w => node[:w], :h => node[:h] - h }
|
56
|
+
node[:right] = { :x => node[:x] + w, :y => node[:y], :w => node[:w] - w, :h => h }
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.grow(root, w, h)
|
60
|
+
|
61
|
+
canGrowDown = (w <= root[:w])
|
62
|
+
canGrowRight = (h <= root[:h])
|
63
|
+
|
64
|
+
shouldGrowRight = canGrowRight && (root[:h] >= (root[:w] + w))
|
65
|
+
shouldGrowDown = canGrowDown && (root[:w] >= (root[:h] + h))
|
66
|
+
|
67
|
+
if shouldGrowRight
|
68
|
+
growRight(root, w, h)
|
69
|
+
elsif shouldGrowDown
|
70
|
+
growDown(root, w, h)
|
71
|
+
elsif canGrowRight
|
72
|
+
growRight(root, w, h)
|
73
|
+
elsif canGrowDown
|
74
|
+
growDown(root, w, h)
|
75
|
+
else
|
76
|
+
raise RuntimeError, "can't fit #{w}x#{h} block into root #{root[:w]}x#{root[:h]} - this should not happen if images are pre-sorted correctly"
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
|
81
|
+
def self.growRight(root, w, h)
|
82
|
+
return {
|
83
|
+
:used => true,
|
84
|
+
:x => 0,
|
85
|
+
:y => 0,
|
86
|
+
:w => root[:w] + w,
|
87
|
+
:h => root[:h],
|
88
|
+
:down => root,
|
89
|
+
:right => { :x => root[:w], :y => 0, :w => w, :h => root[:h] }
|
90
|
+
}
|
91
|
+
end
|
92
|
+
|
93
|
+
def self.growDown(root, w, h)
|
94
|
+
return {
|
95
|
+
:used => true,
|
96
|
+
:x => 0,
|
97
|
+
:y => 0,
|
98
|
+
:w => root[:w],
|
99
|
+
:h => root[:h] + h,
|
100
|
+
:down => { :x => 0, :y => root[:h], :w => root[:w], :h => h },
|
101
|
+
:right => root
|
102
|
+
}
|
103
|
+
end
|
104
|
+
|
105
|
+
end # module Packed
|
106
|
+
end # module Layout
|
107
|
+
end # module SpriteFactory
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module SpriteFactory
|
2
|
+
module Layout
|
3
|
+
module Vertical
|
4
|
+
|
5
|
+
def self.layout(images, options = {})
|
6
|
+
width = options[:width]
|
7
|
+
height = options[:height]
|
8
|
+
hpadding = options[:hpadding] || 0
|
9
|
+
vpadding = options[:vpadding] || 0
|
10
|
+
max_width = width || ((2 * hpadding) + images.map{|i| i[:width]}.max)
|
11
|
+
y = 0
|
12
|
+
images.each do |i|
|
13
|
+
|
14
|
+
if width
|
15
|
+
i[:cssw] = width
|
16
|
+
i[:cssx] = 0
|
17
|
+
i[:x] = 0 + (width - i[:width]) / 2
|
18
|
+
else
|
19
|
+
i[:cssw] = i[:width] + (2 * hpadding) # image width plus padding
|
20
|
+
i[:cssx] = (max_width - i[:cssw]) / 2 # centered horizontally
|
21
|
+
i[:x] = i[:cssx] + hpadding # image drawn offset to account for padding
|
22
|
+
end
|
23
|
+
|
24
|
+
if height
|
25
|
+
i[:cssh] = height
|
26
|
+
i[:cssy] = y
|
27
|
+
i[:y] = y + (height - i[:height]) / 2
|
28
|
+
else
|
29
|
+
i[:cssh] = i[:height] + (2 * vpadding) # image height plus padding
|
30
|
+
i[:cssy] = y # anchored at y
|
31
|
+
i[:y] = i[:cssy] + vpadding # image drawn offset to account for padding
|
32
|
+
end
|
33
|
+
|
34
|
+
y = y + i[:cssh]
|
35
|
+
|
36
|
+
end
|
37
|
+
{ :width => max_width, :height => y }
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'pathname'
|
2
|
+
require 'fileutils'
|
2
3
|
|
3
4
|
module SpriteFactory
|
4
5
|
class Runner
|
@@ -17,6 +18,7 @@ module SpriteFactory
|
|
17
18
|
@config[:selector] ||= SpriteFactory.selector || 'img.'
|
18
19
|
@config[:csspath] ||= SpriteFactory.csspath
|
19
20
|
@config[:report] ||= SpriteFactory.report
|
21
|
+
@config[:pngcrush] ||= SpriteFactory.pngcrush
|
20
22
|
end
|
21
23
|
|
22
24
|
#----------------------------------------------------------------------------
|
@@ -146,12 +148,17 @@ module SpriteFactory
|
|
146
148
|
|
147
149
|
def create_sprite(images, width, height)
|
148
150
|
library.create(output_image_file, images, width, height)
|
151
|
+
pngcrush(output_image_file)
|
149
152
|
end
|
150
153
|
|
151
154
|
#----------------------------------------------------------------------------
|
152
155
|
|
156
|
+
def layout_strategy
|
157
|
+
@layout_strategy ||= Layout.send(layout_name)
|
158
|
+
end
|
159
|
+
|
153
160
|
def layout_images(images)
|
154
|
-
|
161
|
+
layout_strategy.layout(images, :width => width, :height => height, :hpadding => hpadding, :vpadding => vpadding)
|
155
162
|
end
|
156
163
|
|
157
164
|
#----------------------------------------------------------------------------
|
@@ -171,6 +178,18 @@ module SpriteFactory
|
|
171
178
|
|
172
179
|
#----------------------------------------------------------------------------
|
173
180
|
|
181
|
+
SUPPORTS_PNGCRUSH = !`which pngcrush`.empty?
|
182
|
+
|
183
|
+
def pngcrush(image)
|
184
|
+
if SUPPORTS_PNGCRUSH && config[:pngcrush]
|
185
|
+
crushed = "#{image}.crushed"
|
186
|
+
`pngcrush -rem alla -reduce -brute #{image} #{crushed}`
|
187
|
+
FileUtils.mv(crushed, image)
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
#----------------------------------------------------------------------------
|
192
|
+
|
174
193
|
def summary(images, max)
|
175
194
|
return <<-EOF
|
176
195
|
|