css-spriter 0.9.2 → 1.0.1

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.
@@ -1,39 +1,47 @@
1
- class Sprite
2
- class ImageFormatException < Exception; end
3
- attr_reader :images, :max_height
1
+ module CssSpriter
2
+ class Sprite
3
+ attr_reader :images, :max_height
4
4
 
5
- def initialize
6
- @images = []
7
- @locations = {}
8
- end
5
+ def initialize
6
+ @images = []
7
+ @locations = {}
8
+ end
9
9
 
10
- def append( image )
11
- @images.each do |i|
12
- unless i.compatible? image
13
- raise ImageFormatException.new("Image #{i} not compatible with #{image}")
14
- end
10
+ def append( image )
11
+ @images << image
12
+ @max_height = @images.map{ |i| i.height }.max
15
13
  end
16
14
 
17
- @images << image
18
- @max_height = @images.map{ |i| i.height }.max
19
- end
15
+ def append_file( filename )
16
+ append( CssSpriter::Image.from_file( filename ))
17
+ end
20
18
 
21
- def locations
22
- @images.inject(0) do |x, image|
23
- @locations[image.name.to_sym] = { :x => -(x),
24
- :width => image.width,
25
- :height => image.height}
26
- image.width + x
19
+ def locations
20
+ @images.inject(0) do |x, image|
21
+ @locations[image.name.to_sym] = { :x => -(x),
22
+ :width => image.width,
23
+ :height => image.height}
24
+ image.width + x
25
+ end
26
+ @locations
27
27
  end
28
- @locations
29
- end
30
28
 
31
- def write( output_filename )
32
- return if @images.empty?
33
- right_sized = @images.map{|i| i.fill_to_height(@max_height)}
34
- # head is the last image, then we merge left
35
- head, *tail = right_sized.reverse
36
- result = tail.inject( head ){ |head, image| head.merge_left( image ) }
37
- PNG::Image.write( output_filename, result )
29
+ def write( output_filename )
30
+ return if @images.empty?
31
+
32
+ sprite_height = @images.map{ |i| i.height }.max
33
+ sprite_width = @images.inject(0){|sum, image| sum + image.width }
34
+
35
+ sprite = ChunkyPNG::Image.new(sprite_width, sprite_height)
36
+
37
+ current_x = 0
38
+
39
+ images.each do |image|
40
+ sprite = sprite.replace(image, current_x, 0)
41
+ current_x += image.width
42
+ end
43
+
44
+ sprite.save( output_filename, :best_compression )
45
+ end
38
46
  end
39
- end
47
+ end
@@ -1,22 +1,24 @@
1
- class StylesheetBuilder
2
- def initialize(dir)
3
- @dir = dir
4
- @output_file = @dir + "/sprite.css"
5
- end
1
+ module CssSpriter
2
+ class StylesheetBuilder
3
+ def initialize(dir)
4
+ @dir = dir
5
+ @output_file = @dir + "/sprite.css"
6
+ end
6
7
 
7
- def output_file(file)
8
- @output_file = file
9
- end
8
+ def output_file(file)
9
+ @output_file = file
10
+ end
10
11
 
11
- def css
12
- @css ||= Dir.glob(@dir + "/**/fragment.css").inject("") {|acc, f| acc + File.read(f)}
13
- end
12
+ def css
13
+ @css ||= Dir.glob(@dir + "/**/fragment.css").inject("") {|acc, f| acc + File.read(f)}
14
+ end
14
15
 
15
- def write
16
- File.open(@output_file, 'w') {|f| f.write(css)}
17
- end
16
+ def write
17
+ File.open(@output_file, 'w') {|f| f.write(css)}
18
+ end
18
19
 
19
- def cleanup
20
- File.delete(@output_file) rescue nil
20
+ def cleanup
21
+ File.delete(@output_file) rescue nil
22
+ end
21
23
  end
22
- end
24
+ end
@@ -8,16 +8,11 @@ class ImageBuilder
8
8
  @general_options = default_options.merge general_options
9
9
  end
10
10
 
11
- def data(width, height)
12
- Array.new((width * height * 3) + height).fill(0)
13
- end
14
-
15
11
  def build( specific_options={} )
16
12
  args = @general_options.merge specific_options
17
-
18
- ihdr = PNG::IHDR.new( args[:width], args[:height] )
19
- idat = PNG::IDAT.new( args[:data] || data(args[:width], args[:height]) )
20
13
 
21
- PNG::Image.new( ihdr, idat, args[:name] )
14
+ image = CssSpriter::Image.new( args[:width], args[:height], ChunkyPNG::Color::TRANSPARENT )
15
+ image.name = args[:name]
16
+ image
22
17
  end
23
18
  end
@@ -1,81 +1,58 @@
1
- require 'benchmark'
2
1
  require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
3
2
 
4
- describe 'PNG' do
5
- before do
6
- @img_dir = File.dirname(__FILE__) + '/images'
7
- @expected_dir = File.dirname(__FILE__) + '/expected_output'
8
- @tmp_dir = File.dirname(__FILE__) + '/tmp'
9
- end
10
-
11
- it 'can read and write a PNG' do
12
- img = PNG::Image.open("#{@img_dir}/lightening.png")
13
- img.write("#{@tmp_dir}/write_test.png", :filter_type => 0)
14
- read("#{@expected_dir}/write_test.png").should == read("#{@tmp_dir}/write_test.png")
15
- end
16
-
17
- it 'can merge one PNG on the left of another' do
18
- one = PNG::Image.image_data("#{@img_dir}/lightening.png", :rgba => false)
19
- two = PNG::Image.image_data("#{@img_dir}/lightening.png", :rgba => false)
20
- merged = one.merge_left two
21
- PNG::Image.write("#{@tmp_dir}/merge_right_test.png", merged, :filter_type => 0)
22
- read("#{@expected_dir}/merge_right_test.png").should == read("#{@tmp_dir}/merge_right_test.png")
23
- end
24
- end
25
-
26
3
  describe "Dir sprite" do
27
4
  before :all do
28
5
  @dir = File.dirname(__FILE__) + "/sprite_dirs/words"
29
- @spriter = DirectoryProcessor.new(@dir)
6
+ @spriter = CssSpriter::DirectoryProcessor.new(@dir)
30
7
  @sprite_file = @dir + "/sprite.png"
31
8
  @css_file = @dir + "/fragment.css"
32
9
  @spriter.write
33
10
  end
34
11
 
35
- after :all do
12
+ after :all do
36
13
  @spriter.cleanup
37
14
  end
38
15
 
39
- describe "Sprite generation" do
40
- it "provides the correct dir name" do
16
+ describe "Sprite generation" do
17
+ it "provides the correct dir name" do
41
18
  @spriter.dir_name.should == 'words'
42
19
  end
43
20
 
44
- it "find all the pngs in a directory" do
21
+ it "find all the pngs in a directory" do
45
22
  expected = ['latitude.png', 'of.png', 'set.png', 'specified.png']
46
23
  images = @spriter.images
47
24
  images.map{|f| f.split('/').last}.should == expected
48
25
  end
49
26
 
50
- it "sprites all the images in a directory" do
27
+ it "sprites all the images in a directory" do
51
28
  File.exists?(@sprite_file).should be_true
52
29
  end
53
30
  end
54
31
 
55
- describe "CSS fragments" do
56
- before :all do
32
+ describe "CSS fragments" do
33
+ before :all do
57
34
  @template = @dir + "/template.css"
58
35
  @css = @spriter.css
59
36
  end
60
37
 
61
- after do
38
+ after do
62
39
  File.delete(@template) rescue nil
63
40
  end
64
41
 
65
- it "should compose class names" do
42
+ it "should compose class names" do
66
43
  @css.should include( ".words_latitude")
67
44
  @css.should include( ".words_of" )
68
45
  end
69
46
 
70
- it "has the correct image path" do
47
+ it "has the correct image path" do
71
48
  @css.should include( "/sprite_dirs/words/sprite.png" )
72
49
  end
73
50
 
74
- it "should write css fragments for a sprite" do
51
+ it "should write css fragments for a sprite" do
75
52
  File.exists?(@css_file).should be_true
76
53
  end
77
54
 
78
- it "can be overidden by including a template.css in the sprite directory" do
55
+ it "can be overidden by including a template.css in the sprite directory" do
79
56
  File.open(@template, 'w'){|f| f.write("override")}
80
57
  @spriter.write
81
58
  @spriter.css.should include("override")
@@ -83,63 +60,63 @@ describe "Dir sprite" do
83
60
  end
84
61
  end
85
62
 
86
- describe 'Stylesheet generator' do
87
- before :all do
63
+ describe 'Stylesheet generator' do
64
+ before :all do
88
65
  @dir = File.dirname(__FILE__) + "/css_fragments"
89
66
  @out = @dir + "/complete.css"
90
- @builder = StylesheetBuilder.new(@dir)
67
+ @builder = CssSpriter::StylesheetBuilder.new(@dir)
91
68
  @builder.output_file(@out)
92
69
  @css = @builder.css
93
70
  end
94
71
 
95
- after :all do
72
+ after :all do
96
73
  @builder.cleanup
97
74
  end
98
75
 
99
- it "takes the css fragments and concatonates them into a single stylesheet" do
76
+ it "takes the css fragments and concatonates them into a single stylesheet" do
100
77
  @css.should include( ".some_style" )
101
78
  end
102
79
 
103
- it "can handle nested folder structures" do
80
+ it "can handle nested folder structures" do
104
81
  @css.should include( ".deep" )
105
82
  end
106
83
 
107
- it "writes the css file to the specified location" do
84
+ it "writes the css file to the specified location" do
108
85
  @builder.write
109
86
  File.exists?(@out).should be_true
110
87
  end
111
88
  end
112
89
 
113
- describe "Complete spriting process" do
114
- before :all do
90
+ describe "Complete spriting process" do
91
+ before :all do
115
92
  @dir = File.dirname(__FILE__) + "/sprite_dirs"
116
93
  @css_file = @dir + "/sprite.css"
117
94
  @spriter = CssSpriter::Processor.new(:path_prefix => "/images", :source => @dir, :css_file => @css_file)
118
95
  @spriter.write
119
96
  end
120
97
 
121
- after :all do
98
+ after :all do
122
99
  @spriter.cleanup
123
100
  #making sure it cleans things up - shitty place for these
124
101
  File.exists?(@css_file).should be_false
125
102
  File.exists?(@dir + "/words/sprite.png").should be_false
126
103
  end
127
104
 
128
- it "prepends a path prefix to all sprites in the css file" do
105
+ it "prepends a path prefix to all sprites in the css file" do
129
106
  file = read(@css_file)
130
107
  file.should include("/images/sprite_dirs/words")
131
108
  end
132
109
 
133
- it "can find all the sprite directories" do
110
+ it "can find all the sprite directories" do
134
111
  dirs = @spriter.directories.map{|d| d.split('/').last}
135
112
  dirs.should include( "words" )
136
113
  end
137
114
 
138
- it "generates the css file at the appropriate location" do
115
+ it "generates the css file at the appropriate location" do
139
116
  File.exists?(@css_file).should be_true
140
117
  end
141
118
 
142
- it "creates sprites/css for all subfolders" do
119
+ it "creates sprites/css for all subfolders" do
143
120
  File.exists?(@dir + "/words/sprite.png").should be_true
144
121
  File.exists?(@dir + "/words/fragment.css").should be_true
145
122
  end
@@ -0,0 +1,8 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe CssSpriter::Image do
4
+ it "sets the name with the filename of the image" do
5
+ image = CssSpriter::Image.from_file( File.dirname(__FILE__) + '/../images/lightening.png')
6
+ image.name.should == 'lightening'
7
+ end
8
+ end
@@ -1,13 +1,12 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
2
 
3
- describe Sprite do
3
+ describe CssSpriter::Sprite do
4
4
  before :each do
5
- @sprite = Sprite.new
5
+ @sprite = CssSpriter::Sprite.new
6
6
  @builder = ImageBuilder.new
7
7
 
8
- #TODO - We should just create ImageData objects here
9
- @image1 = @builder.build( :width => 50, :height => 50, :name => "image1").to_image
10
- @image2 = @builder.build( :width => 50, :height => 50, :name => "image2").to_image
8
+ @image1 = @builder.build( :width => 50, :height => 50, :name => "image1")
9
+ @image2 = @builder.build( :width => 50, :height => 50, :name => "image2")
11
10
  end
12
11
 
13
12
  it "can merge an image to the right" do
@@ -35,5 +34,4 @@ describe Sprite do
35
34
 
36
35
  @sprite.max_height.should == max_height
37
36
  end
38
-
39
37
  end
@@ -2,65 +2,79 @@ require 'benchmark'
2
2
  require 'fileutils'
3
3
  require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
4
4
 
5
- describe MtimeTracker do
6
- describe "on a new directory" do
7
- before do
5
+ describe CssSpriter::MtimeTracker do
6
+ describe "on a new directory" do
7
+ before do
8
8
  @img_dir = File.dirname(__FILE__) + '/images'
9
- @tracker = MtimeTracker.new(@img_dir)
9
+ @tracker = CssSpriter::MtimeTracker.new(@img_dir)
10
10
  end
11
11
 
12
12
  after do
13
13
  File.delete(@img_dir + "/.mtimes") rescue nil
14
14
  end
15
15
 
16
- it "tells me there are changes" do
16
+ it "tells me there are changes" do
17
17
  @tracker.has_changes?.should be_true
18
18
  end
19
19
 
20
- it "tells me things have not changed after I update the tracking" do
20
+ it "tells me things have not changed after I update the tracking" do
21
21
  @tracker.update
22
22
  @tracker.has_changes?.should be_false
23
23
  end
24
24
  end
25
25
 
26
- describe "on an existing directory" do
27
- before do
26
+ describe "on an existing directory" do
27
+ before do
28
28
  @img_dir = File.dirname(__FILE__) + '/images'
29
- MtimeTracker.new(@img_dir).update
30
- @tracker = MtimeTracker.new(@img_dir)
29
+ CssSpriter::MtimeTracker.new(@img_dir).update
30
+ @tracker = CssSpriter::MtimeTracker.new(@img_dir)
31
31
  end
32
32
 
33
33
  after do
34
34
  File.delete(@img_dir + "/.mtimes") rescue nil
35
35
  end
36
36
 
37
- it "tells me nothing has changed" do
37
+ it "tells me nothing has changed" do
38
38
  @tracker.has_changes?.should be_false
39
39
  end
40
40
 
41
- describe "when a file has changed" do
42
- before do
41
+ describe "when a file has changed" do
42
+ before do
43
43
  FileUtils.touch(@img_dir + "/lightening.png")
44
44
  @tracker.reset
45
45
  end
46
46
 
47
- it "returns true from has_changes" do
47
+ it "returns true from has_changes" do
48
48
  @tracker.has_changes?.should be_true
49
49
  @tracker.changeset.first.should include("/spec/images/lightening.png")
50
50
  end
51
51
  end
52
52
 
53
- describe "file exclustions" do
54
- before do
53
+ describe "when a file is deleted" do
54
+ before do
55
+ FileUtils.touch(@img_dir + "/a_test.png")
56
+ File.exists?(@img_dir + "/a_test.png").should be_true
57
+ @tracker.update
58
+ File.delete(@img_dir + "/a_test.png")
59
+ end
60
+
61
+ it "returns true from has_changes" do
62
+ @tracker.has_changes?.should be_true
63
+ @tracker.changeset.first.should include("/spec/images/a_test.png")
64
+ end
65
+ end
66
+
67
+ describe "file exclustions" do
68
+ before do
55
69
  @img_dir = File.dirname(__FILE__) + '/images'
56
- @tracker = MtimeTracker.new(@img_dir, :exclude => [/lightening/, "tacos"])
70
+ @tracker = CssSpriter::MtimeTracker.new(@img_dir, :exclude => [/lightening/, "tacos"])
57
71
  end
58
72
 
59
- after do
73
+ after do
60
74
  File.delete(@img_dir + "/.mtimes") rescue nil
61
75
  end
62
76
 
63
- it "does not report excluded files as changed" do
77
+ it "does not report excluded files as changed" do
64
78
  FileUtils.touch(@img_dir + "/lightening.png")
65
79
  @tracker.has_changes?.should be_false
66
80
  end
@@ -1,13 +1,13 @@
1
- # $LOAD_PATH.unshift(File.dirname(__FILE__))
2
- # $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
- require 'spec'
4
- require 'spec/autorun'
1
+ require 'rspec'
2
+ require 'rspec/autorun'
5
3
 
4
+ require 'chunky_png'
6
5
  require 'css-spriter'
7
6
 
7
+
8
8
  require 'builders/image_builder'
9
9
 
10
- Spec::Runner.configure do |config|
10
+ RSpec.configure do |config|
11
11
 
12
12
  end
13
13