lash-sprites 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +2 -0
- data/Gemfile +4 -0
- data/LICENSE +165 -0
- data/README +38 -0
- data/Rakefile +38 -0
- data/examples/css/css.rb +17 -0
- data/examples/css/css_cli.rb +29 -0
- data/examples/example_imgs/1.png +0 -0
- data/examples/example_imgs/10.png +0 -0
- data/examples/example_imgs/11.png +0 -0
- data/examples/example_imgs/12.png +0 -0
- data/examples/example_imgs/13.png +0 -0
- data/examples/example_imgs/14.png +0 -0
- data/examples/example_imgs/15.png +0 -0
- data/examples/example_imgs/16.png +0 -0
- data/examples/example_imgs/17.png +0 -0
- data/examples/example_imgs/18.png +0 -0
- data/examples/example_imgs/19.png +0 -0
- data/examples/example_imgs/2.png +0 -0
- data/examples/example_imgs/20.png +0 -0
- data/examples/example_imgs/21.png +0 -0
- data/examples/example_imgs/22.png +0 -0
- data/examples/example_imgs/23.png +0 -0
- data/examples/example_imgs/24.png +0 -0
- data/examples/example_imgs/25.png +0 -0
- data/examples/example_imgs/26.png +0 -0
- data/examples/example_imgs/27.png +0 -0
- data/examples/example_imgs/28.png +0 -0
- data/examples/example_imgs/29.png +0 -0
- data/examples/example_imgs/3.png +0 -0
- data/examples/example_imgs/30.png +0 -0
- data/examples/example_imgs/31.png +0 -0
- data/examples/example_imgs/32.png +0 -0
- data/examples/example_imgs/33.png +0 -0
- data/examples/example_imgs/34.png +0 -0
- data/examples/example_imgs/35.png +0 -0
- data/examples/example_imgs/36.png +0 -0
- data/examples/example_imgs/37.png +0 -0
- data/examples/example_imgs/38.png +0 -0
- data/examples/example_imgs/39.png +0 -0
- data/examples/example_imgs/4.png +0 -0
- data/examples/example_imgs/40.png +0 -0
- data/examples/example_imgs/41.png +0 -0
- data/examples/example_imgs/42.png +0 -0
- data/examples/example_imgs/43.png +0 -0
- data/examples/example_imgs/44.png +0 -0
- data/examples/example_imgs/45.png +0 -0
- data/examples/example_imgs/46.png +0 -0
- data/examples/example_imgs/47.png +0 -0
- data/examples/example_imgs/48.png +0 -0
- data/examples/example_imgs/49.png +0 -0
- data/examples/example_imgs/5.png +0 -0
- data/examples/example_imgs/50.png +0 -0
- data/examples/example_imgs/51.png +0 -0
- data/examples/example_imgs/52.png +0 -0
- data/examples/example_imgs/53.png +0 -0
- data/examples/example_imgs/54.png +0 -0
- data/examples/example_imgs/55.png +0 -0
- data/examples/example_imgs/56.png +0 -0
- data/examples/example_imgs/57.png +0 -0
- data/examples/example_imgs/58.png +0 -0
- data/examples/example_imgs/59.png +0 -0
- data/examples/example_imgs/6.png +0 -0
- data/examples/example_imgs/60.png +0 -0
- data/examples/example_imgs/7.png +0 -0
- data/examples/example_imgs/8.png +0 -0
- data/examples/example_imgs/9.png +0 -0
- data/examples/packing/packing.rb +19 -0
- data/lash-sprites.gemspec +21 -0
- data/lib/.DS_Store +0 -0
- data/lib/lash-sprites/.DS_Store +0 -0
- data/lib/lash-sprites/block.rb +34 -0
- data/lib/lash-sprites/css.rb +27 -0
- data/lib/lash-sprites/graphics_manager/gd2.rb +43 -0
- data/lib/lash-sprites/graphics_manager/graphics_manager.rb +22 -0
- data/lib/lash-sprites/graphics_manager/rmagick.rb +45 -0
- data/lib/lash-sprites/image.rb +46 -0
- data/lib/lash-sprites/packer/both_smart.rb +90 -0
- data/lib/lash-sprites/packer/both_split.rb +171 -0
- data/lib/lash-sprites/packer/even.rb +78 -0
- data/lib/lash-sprites/packer/horizontal_smart.rb +72 -0
- data/lib/lash-sprites/packer/horizontal_split.rb +156 -0
- data/lib/lash-sprites/packer/horizontal_stack.rb +22 -0
- data/lib/lash-sprites/packer/ratio.rb +94 -0
- data/lib/lash-sprites/packer/vertical_smart.rb +72 -0
- data/lib/lash-sprites/packer/vertical_split.rb +164 -0
- data/lib/lash-sprites/packer/vertical_stack.rb +23 -0
- data/lib/lash-sprites/sprite.rb +272 -0
- data/lib/lash-sprites/version.rb +5 -0
- data/test/b_graphics.rb +37 -0
- data/test/b_packers.rb +53 -0
- data/test/imgs/1.png +0 -0
- data/test/imgs/10.png +0 -0
- data/test/imgs/11.png +0 -0
- data/test/imgs/12.png +0 -0
- data/test/imgs/13.png +0 -0
- data/test/imgs/14.png +0 -0
- data/test/imgs/15.png +0 -0
- data/test/imgs/16.png +0 -0
- data/test/imgs/17.png +0 -0
- data/test/imgs/18.png +0 -0
- data/test/imgs/19.png +0 -0
- data/test/imgs/2.png +0 -0
- data/test/imgs/20.png +0 -0
- data/test/imgs/21.png +0 -0
- data/test/imgs/22.png +0 -0
- data/test/imgs/23.png +0 -0
- data/test/imgs/24.png +0 -0
- data/test/imgs/25.png +0 -0
- data/test/imgs/26.png +0 -0
- data/test/imgs/27.png +0 -0
- data/test/imgs/28.png +0 -0
- data/test/imgs/29.png +0 -0
- data/test/imgs/3.png +0 -0
- data/test/imgs/30.png +0 -0
- data/test/imgs/31.png +0 -0
- data/test/imgs/32.png +0 -0
- data/test/imgs/33.png +0 -0
- data/test/imgs/34.png +0 -0
- data/test/imgs/35.png +0 -0
- data/test/imgs/36.png +0 -0
- data/test/imgs/37.png +0 -0
- data/test/imgs/38.png +0 -0
- data/test/imgs/39.png +0 -0
- data/test/imgs/4.png +0 -0
- data/test/imgs/40.png +0 -0
- data/test/imgs/41.png +0 -0
- data/test/imgs/42.png +0 -0
- data/test/imgs/43.png +0 -0
- data/test/imgs/44.png +0 -0
- data/test/imgs/45.png +0 -0
- data/test/imgs/46.png +0 -0
- data/test/imgs/47.png +0 -0
- data/test/imgs/48.png +0 -0
- data/test/imgs/49.png +0 -0
- data/test/imgs/5.png +0 -0
- data/test/imgs/50.png +0 -0
- data/test/imgs/51.png +0 -0
- data/test/imgs/52.png +0 -0
- data/test/imgs/53.png +0 -0
- data/test/imgs/54.png +0 -0
- data/test/imgs/55.png +0 -0
- data/test/imgs/56.png +0 -0
- data/test/imgs/57.png +0 -0
- data/test/imgs/58.png +0 -0
- data/test/imgs/59.png +0 -0
- data/test/imgs/6.png +0 -0
- data/test/imgs/60.png +0 -0
- data/test/imgs/7.png +0 -0
- data/test/imgs/8.png +0 -0
- data/test/imgs/9.png +0 -0
- data/test/t_gd2.rb +28 -0
- data/test/t_generic.rb +183 -0
- data/test/t_rmagick.rb +29 -0
- metadata +269 -0
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'ruby_sprites/graphics_manager/graphics_manager'
|
2
|
+
|
3
|
+
module RubySprites
|
4
|
+
module GraphicsManager
|
5
|
+
class Rmagick < GraphicsManager
|
6
|
+
|
7
|
+
DESCRIPTION = 'RMagick'
|
8
|
+
|
9
|
+
def self.availible?
|
10
|
+
begin
|
11
|
+
require 'rubygems'
|
12
|
+
require 'RMagick'
|
13
|
+
rescue LoadError
|
14
|
+
return false
|
15
|
+
end
|
16
|
+
|
17
|
+
return Magick::Version.match(/^RMagick 2/)
|
18
|
+
end
|
19
|
+
|
20
|
+
def combine(images, width, height)
|
21
|
+
image = Magick::Image.new(width, height) { self.background_color = '#0000' }
|
22
|
+
images.each do |path, img|
|
23
|
+
next unless img.exists?
|
24
|
+
i = Magick::Image.read(@sprite.file_root + path).first
|
25
|
+
drawer = Magick::Draw.new
|
26
|
+
w = width - img.x
|
27
|
+
w = img.width if img.width < w
|
28
|
+
h = height - img.y
|
29
|
+
h = img.height if img.height < h
|
30
|
+
drawer.composite(img.x, img.y, w, h, i)
|
31
|
+
drawer.draw(image)
|
32
|
+
i.destroy!
|
33
|
+
end
|
34
|
+
image.write(@sprite.image_file)
|
35
|
+
end
|
36
|
+
|
37
|
+
def get_info(path)
|
38
|
+
img = Magick::Image.read(@sprite.file_root + path).first
|
39
|
+
info = {:width => img.columns, :height => img.rows}
|
40
|
+
img.destroy!
|
41
|
+
return info
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module RubySprites
|
2
|
+
class Image
|
3
|
+
|
4
|
+
attr_accessor :x, :y
|
5
|
+
attr_reader :path, :width, :height
|
6
|
+
|
7
|
+
def initialize(path, sprite, x = 0, y = 0, width = nil, height = nil)
|
8
|
+
@path = path
|
9
|
+
@sprite = sprite
|
10
|
+
@x = x
|
11
|
+
@y = y
|
12
|
+
|
13
|
+
@width = nil
|
14
|
+
@height = nil
|
15
|
+
|
16
|
+
if exists?
|
17
|
+
|
18
|
+
if !sprite.mtime.nil? && mtime < sprite.mtime
|
19
|
+
@width = width
|
20
|
+
@height = height
|
21
|
+
end
|
22
|
+
|
23
|
+
if @width.nil? || @height.nil?
|
24
|
+
info = @sprite.graphics_manager.get_info(path)
|
25
|
+
@width = info[:width]
|
26
|
+
@height = info[:height]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def exists?
|
32
|
+
return File.exists?(@sprite.file_root + @path)
|
33
|
+
end
|
34
|
+
|
35
|
+
def area
|
36
|
+
return nil if @width.nil?
|
37
|
+
@area = @width * @height if @area.nil?
|
38
|
+
return @area
|
39
|
+
end
|
40
|
+
|
41
|
+
def mtime
|
42
|
+
return File.mtime(@sprite.file_root + @path) if exists?
|
43
|
+
return nil
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'ruby_sprites/image'
|
2
|
+
require 'ruby_sprites/block'
|
3
|
+
|
4
|
+
module RubySprites
|
5
|
+
module Packer
|
6
|
+
module BothSmart
|
7
|
+
|
8
|
+
def self.pack(images, options = {})
|
9
|
+
width = 0
|
10
|
+
height = 0
|
11
|
+
|
12
|
+
images.sort! do |a, b|
|
13
|
+
b.area <=> a.area
|
14
|
+
end
|
15
|
+
|
16
|
+
blocks = []
|
17
|
+
|
18
|
+
images.each do |img|
|
19
|
+
next unless img.exists?
|
20
|
+
smallest = nil
|
21
|
+
exact = nil
|
22
|
+
blocks.each do |block|
|
23
|
+
next unless block.fits?(img)
|
24
|
+
|
25
|
+
exact = block if (img.width == block.width || img.height == block.height) && (exact.nil? || block.area < exact.area)
|
26
|
+
smallest = block if smallest.nil? || block.area < smallest.area
|
27
|
+
|
28
|
+
break if smallest.area == img.area
|
29
|
+
end
|
30
|
+
|
31
|
+
if smallest
|
32
|
+
if exact
|
33
|
+
img.x = exact.x
|
34
|
+
img.y = exact.y
|
35
|
+
blocks.concat(blocks.delete(exact).split(img))
|
36
|
+
else
|
37
|
+
img.x = smallest.x
|
38
|
+
img.y = smallest.y
|
39
|
+
blocks.concat(blocks.delete(smallest).split(img))
|
40
|
+
end
|
41
|
+
else
|
42
|
+
if width == 0 && height == 0
|
43
|
+
b = Block.new(0, 0, img.width, img.height)
|
44
|
+
width = img.width
|
45
|
+
height = img.height
|
46
|
+
blocks.concat(b.split(img))
|
47
|
+
else
|
48
|
+
if img.height > height
|
49
|
+
new_area_right = width * (img.height - height)
|
50
|
+
else
|
51
|
+
new_area_right = img.width * (height - img.height)
|
52
|
+
end
|
53
|
+
|
54
|
+
if img.width > width
|
55
|
+
new_area_below = height * (img.width - width)
|
56
|
+
else
|
57
|
+
new_area_below = img.height * (width - img.width)
|
58
|
+
end
|
59
|
+
|
60
|
+
if new_area_below > new_area_right
|
61
|
+
if img.height > height
|
62
|
+
blocks.push(Block.new(0, height, width, img.height - height))
|
63
|
+
height = img.height
|
64
|
+
elsif img.height < height
|
65
|
+
blocks.push(Block.new(width, img.height, img.width, height - img.height))
|
66
|
+
end
|
67
|
+
img.x = width
|
68
|
+
img.y = 0
|
69
|
+
width += img.width
|
70
|
+
else
|
71
|
+
if img.width > width
|
72
|
+
blocks.push(Block.new(width, 0, img.width - width, height))
|
73
|
+
width = img.width
|
74
|
+
elsif img.width < width
|
75
|
+
blocks.push(Block.new(img.width, height, width - img.width, img.height))
|
76
|
+
end
|
77
|
+
img.x = 0
|
78
|
+
img.y = height
|
79
|
+
height += img.height
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
return {:width => width, :height => height}
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,171 @@
|
|
1
|
+
require 'ruby_sprites/image'
|
2
|
+
require 'ruby_sprites/block'
|
3
|
+
|
4
|
+
module RubySprites
|
5
|
+
module Packer
|
6
|
+
module BothSplit
|
7
|
+
|
8
|
+
def self.pack(images, options = {})
|
9
|
+
width = 0
|
10
|
+
height = 0
|
11
|
+
|
12
|
+
images = images.dup
|
13
|
+
|
14
|
+
images.sort! do |a, b|
|
15
|
+
a.area <=> b.area
|
16
|
+
end
|
17
|
+
|
18
|
+
block_heap = Heap.new {|a,b| b.area <=> a.area}
|
19
|
+
|
20
|
+
while !images.empty?
|
21
|
+
if block_heap.empty?
|
22
|
+
img = images.pop
|
23
|
+
if width == 0 && height == 0
|
24
|
+
img.x = 0
|
25
|
+
img.y = 0
|
26
|
+
width = img.width
|
27
|
+
height = img.height
|
28
|
+
else
|
29
|
+
if img.height > height
|
30
|
+
new_area_right = width * (img.height - height)
|
31
|
+
else
|
32
|
+
new_area_right = img.width * (height - img.height)
|
33
|
+
end
|
34
|
+
|
35
|
+
if img.width > width
|
36
|
+
new_area_below = height * (img.width - width)
|
37
|
+
else
|
38
|
+
new_area_below = img.height * (width - img.width)
|
39
|
+
end
|
40
|
+
|
41
|
+
if new_area_below > new_area_right
|
42
|
+
if img.height > height
|
43
|
+
block_heap.insert(Block.new(0, height, width, img.height - height))
|
44
|
+
height = img.height
|
45
|
+
elsif img.height < height
|
46
|
+
block_heap.insert(Block.new(width, img.height, img.width, height - img.height))
|
47
|
+
end
|
48
|
+
img.x = width
|
49
|
+
img.y = 0
|
50
|
+
width += img.width
|
51
|
+
else
|
52
|
+
if img.width > width
|
53
|
+
block_heap.insert(Block.new(width, 0, img.width - width, height))
|
54
|
+
width = img.width
|
55
|
+
elsif img.width < width
|
56
|
+
block_heap.insert(Block.new(img.width, height, width - img.width, img.height))
|
57
|
+
end
|
58
|
+
img.x = 0
|
59
|
+
img.y = height
|
60
|
+
height += img.height
|
61
|
+
end
|
62
|
+
end
|
63
|
+
else
|
64
|
+
while !block_heap.empty? && !images.empty?
|
65
|
+
block = block_heap.remove
|
66
|
+
cur_img = nil
|
67
|
+
cur_exact = nil
|
68
|
+
images.each_index do |i|
|
69
|
+
break if images[i].area > block.area
|
70
|
+
cur_img = i if block.fits?(images[i])
|
71
|
+
cur_exact = i if block.fits?(images[i]) && (block.width == images[i].width || block.height == images[i].height)
|
72
|
+
end
|
73
|
+
if !cur_exact.nil?
|
74
|
+
img = images.delete_at(cur_exact)
|
75
|
+
img.x = block.x
|
76
|
+
img.y = block.y
|
77
|
+
split_block(block, img).each do |b|
|
78
|
+
block_heap.insert(b)
|
79
|
+
end
|
80
|
+
elsif !cur_img.nil?
|
81
|
+
img = images.delete_at(cur_img)
|
82
|
+
img.x = block.x
|
83
|
+
img.y = block.y
|
84
|
+
split_block(block, img).each do |b|
|
85
|
+
block_heap.insert(b)
|
86
|
+
end
|
87
|
+
else
|
88
|
+
# Nothing will fit in this block, we are throwing it out
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
return {:width => width, :height => height}
|
95
|
+
end
|
96
|
+
|
97
|
+
def self.split_block(block, img)
|
98
|
+
blocks = []
|
99
|
+
img.x = block.x
|
100
|
+
img.y = block.y
|
101
|
+
if (block.width - img.width) * img.height > (block.height - img.height) * img.width
|
102
|
+
blocks.push Block.new(block.x + img.width, block.y, block.width - img.width, block.height) if block.width != img.width
|
103
|
+
blocks.push Block.new(block.x, block.y + img.height, img.width, block.height - img.height) if block.height != img.height
|
104
|
+
else
|
105
|
+
blocks.push Block.new(block.x + img.width, block.y, block.width - img.width, img.height) if block.width != img.width
|
106
|
+
blocks.push Block.new(block.x, block.y + img.height, block.width, block.height - img.height) if block.height != img.height
|
107
|
+
end
|
108
|
+
return blocks
|
109
|
+
end
|
110
|
+
|
111
|
+
protected
|
112
|
+
|
113
|
+
class Heap
|
114
|
+
def initialize(&comparer)
|
115
|
+
@comparer = comparer
|
116
|
+
@heap = [0]
|
117
|
+
end
|
118
|
+
|
119
|
+
def insert(el)
|
120
|
+
pos = @heap.length
|
121
|
+
@heap.push(el)
|
122
|
+
new_pos = pos
|
123
|
+
while new_pos != 1 && @comparer.call(el, @heap[new_pos / 2]) < 0
|
124
|
+
new_pos /= 2
|
125
|
+
end
|
126
|
+
|
127
|
+
while(pos > new_pos)
|
128
|
+
@heap[pos] = @heap[pos / 2]
|
129
|
+
pos /= 2
|
130
|
+
end
|
131
|
+
@heap[pos] = el
|
132
|
+
end
|
133
|
+
|
134
|
+
def remove
|
135
|
+
return nil if @heap.length == 1
|
136
|
+
el = @heap[1]
|
137
|
+
shifter = @heap.pop
|
138
|
+
if @heap.length != 1
|
139
|
+
pos = 1
|
140
|
+
while(!@heap[pos * 2].nil?)
|
141
|
+
lesser_pos = pos * 2
|
142
|
+
lesser_pos += 1 if !@heap[pos * 2 + 1].nil? && @comparer.call(@heap[pos * 2 + 1], @heap[pos * 2]) < 0
|
143
|
+
if(@comparer.call(@heap[lesser_pos], shifter) < 0)
|
144
|
+
@heap[pos] = @heap[lesser_pos]
|
145
|
+
pos = lesser_pos
|
146
|
+
else
|
147
|
+
break
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
@heap[pos] = shifter
|
152
|
+
end
|
153
|
+
return el
|
154
|
+
end
|
155
|
+
|
156
|
+
def peek
|
157
|
+
return nil if @heap.length == 1
|
158
|
+
return @heap[1]
|
159
|
+
end
|
160
|
+
|
161
|
+
def empty?
|
162
|
+
return @heap.length == 1
|
163
|
+
end
|
164
|
+
|
165
|
+
def inspect
|
166
|
+
return @heap.to_s
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'ruby_sprites/image'
|
2
|
+
require 'ruby_sprites/block'
|
3
|
+
|
4
|
+
module RubySprites
|
5
|
+
module Packer
|
6
|
+
module Even
|
7
|
+
|
8
|
+
def self.pack(images, options = {})
|
9
|
+
width = 0
|
10
|
+
height = 0
|
11
|
+
|
12
|
+
images.sort! do |a, b|
|
13
|
+
b.area <=> a.area
|
14
|
+
end
|
15
|
+
|
16
|
+
blocks = []
|
17
|
+
|
18
|
+
images.each do |img|
|
19
|
+
next unless img.exists?
|
20
|
+
smallest = nil
|
21
|
+
exact = nil
|
22
|
+
blocks.each do |block|
|
23
|
+
next unless block.fits?(img)
|
24
|
+
|
25
|
+
exact = block if (img.width == block.width || img.height == block.height) && (exact.nil? || block.area < exact.area)
|
26
|
+
smallest = block if smallest.nil? || block.area < smallest.area
|
27
|
+
|
28
|
+
break if smallest.area == img.area
|
29
|
+
end
|
30
|
+
|
31
|
+
if smallest
|
32
|
+
if exact
|
33
|
+
img.x = exact.x
|
34
|
+
img.y = exact.y
|
35
|
+
blocks.concat(blocks.delete(exact).split(img))
|
36
|
+
else
|
37
|
+
img.x = smallest.x
|
38
|
+
img.y = smallest.y
|
39
|
+
blocks.concat(blocks.delete(smallest).split(img))
|
40
|
+
end
|
41
|
+
else
|
42
|
+
if width == 0 && height == 0
|
43
|
+
b = Block.new(0, 0, img.width, img.height)
|
44
|
+
width = img.width
|
45
|
+
height = img.height
|
46
|
+
blocks.concat(b.split(img))
|
47
|
+
else
|
48
|
+
if height > width
|
49
|
+
if img.height > height
|
50
|
+
blocks.push(Block.new(0, height, width, img.height - height))
|
51
|
+
height = img.height
|
52
|
+
elsif img.height < height
|
53
|
+
blocks.push(Block.new(width, img.height, img.width, height - img.height))
|
54
|
+
end
|
55
|
+
img.x = width
|
56
|
+
img.y = 0
|
57
|
+
width += img.width
|
58
|
+
else
|
59
|
+
if img.width > width
|
60
|
+
blocks.push(Block.new(width, 0, img.width - width, height))
|
61
|
+
width = img.width
|
62
|
+
elsif img.width < width
|
63
|
+
blocks.push(Block.new(img.width, height, width - img.width, img.height))
|
64
|
+
end
|
65
|
+
img.x = 0
|
66
|
+
img.y = height
|
67
|
+
height += img.height
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
return {:width => width, :height => height}
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'ruby_sprites/image'
|
2
|
+
require 'ruby_sprites/block'
|
3
|
+
|
4
|
+
module RubySprites
|
5
|
+
module Packer
|
6
|
+
module HorizontalSmart
|
7
|
+
|
8
|
+
def self.pack(images, options = {})
|
9
|
+
width = 0
|
10
|
+
height = 0
|
11
|
+
|
12
|
+
images.sort! do |a, b|
|
13
|
+
if a.height == b.height
|
14
|
+
b.width <=> a.width
|
15
|
+
else
|
16
|
+
b.height <=> a.height
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
blocks = []
|
21
|
+
|
22
|
+
images.each do |img|
|
23
|
+
next unless img.exists?
|
24
|
+
smallest = nil
|
25
|
+
exact = nil
|
26
|
+
blocks.each do |block|
|
27
|
+
next unless block.fits?(img)
|
28
|
+
|
29
|
+
exact = block if (img.width == block.width || img.height == block.height) && (exact.nil? || block.area < exact.area)
|
30
|
+
smallest = block if smallest.nil? || block.area < smallest.area
|
31
|
+
|
32
|
+
break if smallest.area == img.area
|
33
|
+
end
|
34
|
+
|
35
|
+
if smallest
|
36
|
+
if exact
|
37
|
+
blocks.concat(split_block(blocks.delete(exact), img))
|
38
|
+
else
|
39
|
+
blocks.concat(split_block(blocks.delete(smallest), img))
|
40
|
+
end
|
41
|
+
else
|
42
|
+
if width == 0 && height == 0
|
43
|
+
b = Block.new(0, 0, img.width, img.height)
|
44
|
+
width = img.width
|
45
|
+
height = img.height
|
46
|
+
else
|
47
|
+
b = Block.new(width, 0, img.width, height)
|
48
|
+
width += img.width
|
49
|
+
end
|
50
|
+
blocks.concat(split_block(b, img))
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
return {:width => width, :height => height}
|
55
|
+
end
|
56
|
+
|
57
|
+
def self.split_block(block, img)
|
58
|
+
blocks = []
|
59
|
+
img.x = block.x
|
60
|
+
img.y = block.y
|
61
|
+
if (block.width - img.width) * img.height > (block.height - img.height) * img.width
|
62
|
+
blocks.push Block.new(block.x + img.width, block.y, block.width - img.width, block.height) if block.width != img.width
|
63
|
+
blocks.push Block.new(block.x, block.y + img.height, img.width, block.height - img.height) if block.height != img.height
|
64
|
+
else
|
65
|
+
blocks.push Block.new(block.x + img.width, block.y, block.width - img.width, img.height) if block.width != img.width
|
66
|
+
blocks.push Block.new(block.x, block.y + img.height, block.width, block.height - img.height) if block.height != img.height
|
67
|
+
end
|
68
|
+
return blocks
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,156 @@
|
|
1
|
+
require 'ruby_sprites/image'
|
2
|
+
require 'ruby_sprites/block'
|
3
|
+
|
4
|
+
module RubySprites
|
5
|
+
module Packer
|
6
|
+
module HorizontalSplit
|
7
|
+
|
8
|
+
def self.pack(images, options = {})
|
9
|
+
width = 0
|
10
|
+
height = 0
|
11
|
+
|
12
|
+
images = images.dup
|
13
|
+
|
14
|
+
images.sort! do |a, b|
|
15
|
+
a.height <=> b.height
|
16
|
+
end
|
17
|
+
|
18
|
+
i = images.pop
|
19
|
+
width = i.width
|
20
|
+
height = i.height
|
21
|
+
i.x = 0
|
22
|
+
i.y = 0
|
23
|
+
|
24
|
+
images.sort! do |a, b|
|
25
|
+
a.area <=> b.area
|
26
|
+
end
|
27
|
+
|
28
|
+
block_heap = Heap.new {|a,b| b.area <=> a.area}
|
29
|
+
|
30
|
+
while !images.empty?
|
31
|
+
if block_heap.empty?
|
32
|
+
img = images.pop
|
33
|
+
if width == 0 && height == 0
|
34
|
+
img.x = 0
|
35
|
+
img.y = 0
|
36
|
+
width = img.width
|
37
|
+
height = img.height
|
38
|
+
else
|
39
|
+
if img.height > height
|
40
|
+
block_heap.insert(Block.new(0, height, width, img.height - height))
|
41
|
+
height = img.height
|
42
|
+
elsif img.height < height
|
43
|
+
block_heap.insert(Block.new(width, img.height, img.width, height - img.height))
|
44
|
+
end
|
45
|
+
img.x = width
|
46
|
+
img.y = 0
|
47
|
+
width += img.width
|
48
|
+
end
|
49
|
+
else
|
50
|
+
while !block_heap.empty? && !images.empty?
|
51
|
+
block = block_heap.remove
|
52
|
+
cur_img = nil
|
53
|
+
cur_exact = nil
|
54
|
+
images.each_index do |i|
|
55
|
+
cur_img = i if block.fits?(images[i])
|
56
|
+
cur_exact = i if block.fits?(images[i]) && (block.width == images[i].width || block.height == images[i].height)
|
57
|
+
end
|
58
|
+
if !cur_exact.nil?
|
59
|
+
img = images.delete_at(cur_exact)
|
60
|
+
img.x = block.x
|
61
|
+
img.y = block.y
|
62
|
+
split_block(block, img).each do |b|
|
63
|
+
block_heap.insert(b)
|
64
|
+
end
|
65
|
+
elsif !cur_img.nil?
|
66
|
+
img = images.delete_at(cur_img)
|
67
|
+
img.x = block.x
|
68
|
+
img.y = block.y
|
69
|
+
split_block(block, img).each do |b|
|
70
|
+
block_heap.insert(b)
|
71
|
+
end
|
72
|
+
else
|
73
|
+
# Nothing will fit in this block, we are throwing it out
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
return {:width => width, :height => height}
|
80
|
+
end
|
81
|
+
|
82
|
+
def self.split_block(block, img)
|
83
|
+
blocks = []
|
84
|
+
img.x = block.x
|
85
|
+
img.y = block.y
|
86
|
+
if (block.width - img.width) * img.height > (block.height - img.height) * img.width
|
87
|
+
blocks.push Block.new(block.x + img.width, block.y, block.width - img.width, block.height) if block.width != img.width
|
88
|
+
blocks.push Block.new(block.x, block.y + img.height, img.width, block.height - img.height) if block.height != img.height
|
89
|
+
else
|
90
|
+
blocks.push Block.new(block.x + img.width, block.y, block.width - img.width, img.height) if block.width != img.width
|
91
|
+
blocks.push Block.new(block.x, block.y + img.height, block.width, block.height - img.height) if block.height != img.height
|
92
|
+
end
|
93
|
+
return blocks
|
94
|
+
end
|
95
|
+
|
96
|
+
protected
|
97
|
+
|
98
|
+
class Heap
|
99
|
+
def initialize(&comparer)
|
100
|
+
@comparer = comparer
|
101
|
+
@heap = [0]
|
102
|
+
end
|
103
|
+
|
104
|
+
def insert(el)
|
105
|
+
pos = @heap.length
|
106
|
+
@heap.push(el)
|
107
|
+
new_pos = pos
|
108
|
+
while new_pos != 1 && @comparer.call(el, @heap[new_pos / 2]) < 0
|
109
|
+
new_pos /= 2
|
110
|
+
end
|
111
|
+
|
112
|
+
while(pos > new_pos)
|
113
|
+
@heap[pos] = @heap[pos / 2]
|
114
|
+
pos /= 2
|
115
|
+
end
|
116
|
+
@heap[pos] = el
|
117
|
+
end
|
118
|
+
|
119
|
+
def remove
|
120
|
+
return nil if @heap.length == 1
|
121
|
+
el = @heap[1]
|
122
|
+
shifter = @heap.pop
|
123
|
+
if @heap.length != 1
|
124
|
+
pos = 1
|
125
|
+
while(!@heap[pos * 2].nil?)
|
126
|
+
lesser_pos = pos * 2
|
127
|
+
lesser_pos += 1 if !@heap[pos * 2 + 1].nil? && @comparer.call(@heap[pos * 2 + 1], @heap[pos * 2]) < 0
|
128
|
+
if(@comparer.call(@heap[lesser_pos], shifter) < 0)
|
129
|
+
@heap[pos] = @heap[lesser_pos]
|
130
|
+
pos = lesser_pos
|
131
|
+
else
|
132
|
+
break
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
@heap[pos] = shifter
|
137
|
+
end
|
138
|
+
return el
|
139
|
+
end
|
140
|
+
|
141
|
+
def peek
|
142
|
+
return nil if @heap.length == 1
|
143
|
+
return @heap[1]
|
144
|
+
end
|
145
|
+
|
146
|
+
def empty?
|
147
|
+
return @heap.length == 1
|
148
|
+
end
|
149
|
+
|
150
|
+
def inspect
|
151
|
+
return @heap.to_s
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'ruby_sprites/image'
|
2
|
+
|
3
|
+
module RubySprites
|
4
|
+
module Packer
|
5
|
+
module HorizontalStack
|
6
|
+
|
7
|
+
def self.pack(images, options = {})
|
8
|
+
width = 0
|
9
|
+
height = 0
|
10
|
+
images.each do |img|
|
11
|
+
next unless img.exists?
|
12
|
+
img.x = width
|
13
|
+
img.y = 0
|
14
|
+
height = img.height if img.height > height
|
15
|
+
width += img.width
|
16
|
+
end
|
17
|
+
return {:width => width, :height => height}
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|