css-spriter 0.9.2 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -15,6 +15,10 @@ It takes your PNG's, chews them up and spits out sprites!
15
15
 
16
16
  point bin/css-spriter at a directory, and watch it sprite away!
17
17
 
18
+ CSS-Spriter uses Chunky PNG for it's PNG manipulation. Not only is it super fast, but the library is a great example of fast, efficient ruby programming.
19
+
20
+ Chunky PNG is written in pure ruby, this means you can sprite up anything using MRI, JRuby, or Rubinius.
21
+
18
22
  == Installation - standalone
19
23
 
20
24
  sudo gem install css-spriter
@@ -35,7 +39,7 @@ For a full list of options:
35
39
 
36
40
  === Usage - Rails plugin
37
41
 
38
- Spittle assumes all of your sprites are located in the directory public/images/sprites. This directory should contain sub-directories for each sprite you wish to create. The css class names for an image in a sprite will take the form <directory_name>_<image_name>. Here is an example:
42
+ CSS-Spriter assumes all of your sprites are located in the directory public/images/sprites. This directory should contain sub-directories for each sprite you wish to create. The css class names for an image in a sprite will take the form <directory_name>_<image_name>. Here is an example:
39
43
 
40
44
  sprites /
41
45
  cars /
@@ -45,14 +49,10 @@ Spittle assumes all of your sprites are located in the directory public/images/s
45
49
  boeing.png
46
50
  cesna.png
47
51
 
48
- Running sprite:generate does all the work. Each sprite directory (cars, planes) will now contain a sprite.png. Spittle will also generate a sprites.css stylesheet in public/stylesheets/ that you should include in your layout. If you wished to use the ford image from the cars sprite you would give the 'cars_ford' class to the desired element in the view. That's it!
49
-
50
- Check out examples/sprites if you want to see what spriter can do without doing any work.
52
+ Running the sprite:generate task does all the work. Each sprite directory (cars, planes) will now contain a sprite.png. Spittle will also generate a sprites.css stylesheet in public/stylesheets/ that you should include in your layout. If you wished to use the ford image from the cars sprite you would give the 'cars_ford' class to the desired element in the view. That's it!
51
53
 
52
- == Limitations
54
+ Check out examples/sprites if you want to see what CSS-Spriter can do without doing any work.
53
55
 
54
- - does not support color profiles (can cause a slight change in color from the source image)
55
- - does not support reading interlaced PNGs.
56
56
 
57
57
  == Features
58
58
 
@@ -62,12 +62,10 @@ Check out examples/sprites if you want to see what spriter can do without doing
62
62
  - Rails plugin & rake tasks (sprite:generate & sprite:cleanup)
63
63
  - Supports varying dimensions in source images
64
64
  - Does not regenerate sprites that have not changed
65
- - Supports all PNG filter types to improve image compression
66
65
  - supports mixing RGB and RGBA color types
67
66
 
68
67
  == Roadmap - by priority
69
68
 
70
- - Reading interlaced images
71
69
  - allow a global css template override
72
70
  - allow per-sprite and global configuration
73
71
 
data/Rakefile CHANGED
@@ -6,11 +6,12 @@ begin
6
6
  Jeweler::Tasks.new do |gem|
7
7
  gem.name = "css-spriter"
8
8
  gem.summary = %Q{pure ruby PNG spriting library}
9
- gem.description = %Q{Css Spriter is a pure ruby PNG spriting library. It can be used standalone or as a Rails plugin, see the readme for details.}
9
+ gem.description = %Q{CSS-Spriter is a pure ruby PNG spriting library. It can be used standalone or as a Rails plugin, see the readme for details.}
10
10
  gem.email = ["qzzzq1@gmail.com", "tyler.jennings@gmail.com"]
11
11
  gem.homepage = "http://github.com/aberant/css-spriter"
12
12
  gem.authors = ["aberant", "tjennings"]
13
13
  gem.add_development_dependency "rspec" #, ">= 1.2.9"
14
+ gem.add_dependency "chunky_png", "~> 1.1.0"
14
15
  # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
15
16
  end
16
17
  Jeweler::GemcutterTasks.new
@@ -18,14 +19,12 @@ rescue LoadError
18
19
  puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
19
20
  end
20
21
 
21
- require 'spec/rake/spectask'
22
- Spec::Rake::SpecTask.new(:spec) do |spec|
23
- spec.libs << 'lib' << 'spec'
24
- spec.spec_files = FileList['spec/**/*_spec.rb']
22
+ require 'rspec/core/rake_task'
23
+ RSpec::Core::RakeTask.new do |task|
24
+ task.pattern = 'spec/**/*_spec.rb'
25
25
  end
26
26
 
27
- Spec::Rake::SpecTask.new(:rcov) do |spec|
28
- spec.libs << 'lib' << 'spec'
27
+ RSpec::Core::RakeTask.new(:rcov) do |spec|
29
28
  spec.pattern = 'spec/**/*_spec.rb'
30
29
  spec.rcov = true
31
30
  end
@@ -39,7 +38,7 @@ Rake::RDocTask.new do |rdoc|
39
38
  version = File.exist?('VERSION') ? File.read('VERSION') : ""
40
39
 
41
40
  rdoc.rdoc_dir = 'rdoc'
42
- rdoc.title = "spittle #{version}"
41
+ rdoc.title = "css-spriter #{version}"
43
42
  rdoc.rdoc_files.include('README*')
44
43
  rdoc.rdoc_files.include('lib/**/*.rb')
45
44
  end
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.9.2
1
+ 1.0.1
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  require 'optparse'
4
- require File.dirname(__FILE__) + "/../lib/css-spriter.rb"
4
+ require File.dirname(__FILE__) + "/../lib/css-spriter"
5
5
 
6
6
 
7
7
  options = {}
@@ -0,0 +1,106 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{css-spriter}
8
+ s.version = "1.0.1"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["aberant", "tjennings"]
12
+ s.date = %q{2011-03-23}
13
+ s.default_executable = %q{css-spriter}
14
+ s.description = %q{CSS-Spriter is a pure ruby PNG spriting library. It can be used standalone or as a Rails plugin, see the readme for details.}
15
+ s.email = ["qzzzq1@gmail.com", "tyler.jennings@gmail.com"]
16
+ s.executables = ["css-spriter"]
17
+ s.extra_rdoc_files = [
18
+ "README.rdoc"
19
+ ]
20
+ s.files = [
21
+ "MIT-LICENSE",
22
+ "README.rdoc",
23
+ "Rakefile",
24
+ "VERSION",
25
+ "bin/css-spriter",
26
+ "css-spriter.gemspec",
27
+ "examples/sprites/.mtimes",
28
+ "examples/sprites/README",
29
+ "examples/sprites/fragment.css",
30
+ "examples/sprites/index.html",
31
+ "examples/sprites/many_sized_cats/.mtimes",
32
+ "examples/sprites/many_sized_cats/cat-on-keyboard.png",
33
+ "examples/sprites/many_sized_cats/darth_cat.png",
34
+ "examples/sprites/many_sized_cats/fragment.css",
35
+ "examples/sprites/many_sized_cats/music-keyboard-cat.png",
36
+ "examples/sprites/many_sized_cats/sprite.css",
37
+ "examples/sprites/many_sized_cats/sprite.png",
38
+ "examples/sprites/server.rb",
39
+ "examples/sprites/sprite.css",
40
+ "examples/sprites/words/.mtimes",
41
+ "examples/sprites/words/fragment.css",
42
+ "examples/sprites/words/latitude.png",
43
+ "examples/sprites/words/of.png",
44
+ "examples/sprites/words/set.png",
45
+ "examples/sprites/words/specified.png",
46
+ "examples/sprites/words/sprite.css",
47
+ "examples/sprites/words/sprite.png",
48
+ "init.rb",
49
+ "lib/css-spriter.rb",
50
+ "lib/css-spriter/directory_processor.rb",
51
+ "lib/css-spriter/image.rb",
52
+ "lib/css-spriter/mtime_tracker.rb",
53
+ "lib/css-spriter/processor.rb",
54
+ "lib/css-spriter/sprite.rb",
55
+ "lib/css-spriter/stylesheet_builder.rb",
56
+ "spec/builders/image_builder.rb",
57
+ "spec/css_fragments/deep/style/fragment.css",
58
+ "spec/css_fragments/some/fragment.css",
59
+ "spec/expected_output/merge_right_test.png",
60
+ "spec/expected_output/write_test.png",
61
+ "spec/images/lightening.png",
62
+ "spec/integration_spec.rb",
63
+ "spec/lib/css_spriter_image_spec.rb",
64
+ "spec/lib/sprite_spec.rb",
65
+ "spec/mtime_tracking_spec.rb",
66
+ "spec/spec.opts",
67
+ "spec/spec_helper.rb",
68
+ "spec/sprite_dirs/words/latitude.png",
69
+ "spec/sprite_dirs/words/of.png",
70
+ "spec/sprite_dirs/words/set.png",
71
+ "spec/sprite_dirs/words/specified.png",
72
+ "spec/tmp/merge_right_test.png",
73
+ "spec/tmp/write_test.png",
74
+ "tasks/spriter_tasks.rake"
75
+ ]
76
+ s.homepage = %q{http://github.com/aberant/css-spriter}
77
+ s.require_paths = ["lib"]
78
+ s.rubygems_version = %q{1.3.7}
79
+ s.summary = %q{pure ruby PNG spriting library}
80
+ s.test_files = [
81
+ "examples/sprites/server.rb",
82
+ "spec/builders/image_builder.rb",
83
+ "spec/integration_spec.rb",
84
+ "spec/lib/css_spriter_image_spec.rb",
85
+ "spec/lib/sprite_spec.rb",
86
+ "spec/mtime_tracking_spec.rb",
87
+ "spec/spec_helper.rb"
88
+ ]
89
+
90
+ if s.respond_to? :specification_version then
91
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
92
+ s.specification_version = 3
93
+
94
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
95
+ s.add_development_dependency(%q<rspec>, [">= 0"])
96
+ s.add_runtime_dependency(%q<chunky_png>, ["~> 1.1.0"])
97
+ else
98
+ s.add_dependency(%q<rspec>, [">= 0"])
99
+ s.add_dependency(%q<chunky_png>, ["~> 1.1.0"])
100
+ end
101
+ else
102
+ s.add_dependency(%q<rspec>, [">= 0"])
103
+ s.add_dependency(%q<chunky_png>, ["~> 1.1.0"])
104
+ end
105
+ end
106
+
@@ -1,16 +1,7 @@
1
- require 'zlib'
2
-
3
- require 'css-spriter/png/file_header'
4
- require 'css-spriter/png/parser'
5
- require 'css-spriter/png/filters'
6
- require 'css-spriter/png/chunk'
7
- require 'css-spriter/png/ihdr'
8
- require 'css-spriter/png/idat'
9
- require 'css-spriter/png/iend'
10
- require 'css-spriter/png/image'
1
+ require 'chunky_png'
11
2
  require 'css-spriter/sprite'
3
+ require 'css-spriter/image'
12
4
  require 'css-spriter/directory_processor'
13
5
  require 'css-spriter/stylesheet_builder'
14
6
  require 'css-spriter/processor'
15
7
  require 'css-spriter/mtime_tracker'
16
- require 'css-spriter/image_data'
@@ -1,94 +1,98 @@
1
- class DirectoryProcessor
2
-
3
- DEFAULT_TEMPLATE = <<-EOF
4
- .<name>_<image_name> {
5
- background: transparent url(<image_loc>) <offset>px 0px no-repeat;
6
- width:<width>;
7
- height:<height>;
8
- text-indent:-5000px;
9
- }
10
-
11
- EOF
12
-
13
- def initialize(dir, options = {})
14
- @options = options
15
- @dir = dir
16
- @sprite = Sprite.new
17
- @tracker = MtimeTracker.new(@dir,
18
- :exclude => ['sprite.css', 'fragment.css', 'sprite.png'])
19
- end
1
+ module CssSpriter
2
+ class DirectoryProcessor
20
3
 
21
- def images
22
- Dir.glob(@dir + "/*.png").reject{|i| i.match /sprite\.png/}
23
- end
4
+ DEFAULT_TEMPLATE = <<-EOF
5
+ .<name>_<image_name> {
6
+ background: transparent url(<image_loc>) <offset>px 0px no-repeat;
7
+ width:<width>;
8
+ height:<height>;
9
+ text-indent:-5000px;
10
+ }
24
11
 
25
- def write
26
- return unless @tracker.has_changes?
27
- images.each {|f| @sprite.append(PNG::Image.image_data(f))}
28
- @sprite.write(sprite_file)
29
- File.open(css_file, 'w') do |f|
30
- f.write(css)
12
+ EOF
13
+
14
+ def initialize(dir, options = {})
15
+ @options = options
16
+ @dir = dir
17
+ @sprite = Sprite.new
18
+ @tracker = MtimeTracker.new(@dir,
19
+ :exclude => ['sprite.css', 'fragment.css', 'sprite.png'])
31
20
  end
32
- @tracker.update
33
- end
34
21
 
35
- def cleanup
36
- File.delete(sprite_file) rescue nil
37
- File.delete(css_file) rescue nil
38
- @tracker.cleanup
39
- end
22
+ def images
23
+ Dir.glob(@dir + "/*.png").reject{|i| i.match /sprite\.png/}
24
+ end
40
25
 
41
- def sprite_file
42
- @dir + "/sprite.png"
43
- end
26
+ def write
27
+ return unless @tracker.has_changes?
28
+ images.each {|f| @sprite.append_file(f)}
44
29
 
45
- def css_file
46
- @dir + "/fragment.css"
47
- end
30
+ @sprite.write(sprite_file)
48
31
 
49
- def dir_name
50
- @dir.split('/').last
51
- end
32
+ File.open(css_file, 'w') do |f|
33
+ f.write(css)
34
+ end
35
+ @tracker.update
36
+ end
52
37
 
53
- def image_loc
54
- #TODO: Lame!
38
+ def cleanup
39
+ File.delete(sprite_file) rescue nil
40
+ File.delete(css_file) rescue nil
41
+ @tracker.cleanup
42
+ end
55
43
 
56
- dir = truncate_abs_path
57
- base = ("/" + dir + "/sprite.png").gsub(/^\/.\//, "/").gsub("//", "/")
58
- source = @options[:source]
59
- base = base.gsub(source, "") if source && source != "."
60
- base = @options[:path_prefix] + base if @options[:path_prefix]
61
- base
62
- end
44
+ def sprite_file
45
+ @dir + "/sprite.png"
46
+ end
63
47
 
64
- def truncate_abs_path
65
- return @dir unless @options[:source]
66
- path_elements = @options[:source].split('/')
67
- path_elements.pop #we want to remove everything above the root
68
- to_truncate = path_elements.join("/")
69
- @dir.gsub(to_truncate, "")
70
- end
48
+ def css_file
49
+ @dir + "/fragment.css"
50
+ end
71
51
 
72
- def template_file
73
- @dir + "/template.css"
74
- end
52
+ def dir_name
53
+ @dir.split('/').last
54
+ end
55
+
56
+ def image_loc
57
+ #TODO: Lame!
75
58
 
76
- def template
77
- if File.exists?(template_file)
78
- return File.read(template_file)
59
+ dir = truncate_abs_path
60
+ base = ("/" + dir + "/sprite.png").gsub(/^\/.\//, "/").gsub("//", "/")
61
+ source = @options[:source]
62
+ base = base.gsub(source, "") if source && source != "."
63
+ base = @options[:path_prefix] + base if @options[:path_prefix]
64
+ base
65
+ end
66
+
67
+ def truncate_abs_path
68
+ return @dir unless @options[:source]
69
+ path_elements = @options[:source].split('/')
70
+ path_elements.pop #we want to remove everything above the root
71
+ to_truncate = path_elements.join("/")
72
+ @dir.gsub(to_truncate, "")
73
+ end
74
+
75
+ def template_file
76
+ @dir + "/template.css"
77
+ end
78
+
79
+ def template
80
+ if File.exists?(template_file)
81
+ return File.read(template_file)
82
+ end
83
+ return DEFAULT_TEMPLATE
79
84
  end
80
- return DEFAULT_TEMPLATE
81
- end
82
85
 
83
- def css
84
- @sprite.locations.inject("") do |out, image|
85
- image_name, properties = image
86
- out << template.gsub("<name>", dir_name).
87
- gsub("<image_name>", image_name.to_s).
88
- gsub("<width>", properties[:width].to_s).
89
- gsub("<height>", properties[:height].to_s).
90
- gsub("<offset>", properties[:x].to_s).
91
- gsub("<image_loc>", image_loc)
86
+ def css
87
+ @sprite.locations.inject("") do |out, image|
88
+ image_name, properties = image
89
+ out << template.gsub("<name>", dir_name).
90
+ gsub("<image_name>", image_name.to_s).
91
+ gsub("<width>", properties[:width].to_s).
92
+ gsub("<height>", properties[:height].to_s).
93
+ gsub("<offset>", properties[:x].to_s).
94
+ gsub("<image_loc>", image_loc)
95
+ end
92
96
  end
93
97
  end
94
- end
98
+ end
@@ -0,0 +1,13 @@
1
+ module CssSpriter
2
+ class Image < ::ChunkyPNG::Image
3
+ attr_accessor :name
4
+
5
+ def self.from_file( filename )
6
+ name = File.basename( filename, ".png" )
7
+
8
+ image = super
9
+ image.name = name
10
+ image
11
+ end
12
+ end
13
+ end
@@ -1,79 +1,82 @@
1
- class MtimeTracker
2
- def initialize(dir, options = {})
3
- @dir = dir
4
- @options = options
5
- end
1
+ module CssSpriter
2
+ class MtimeTracker
3
+ def initialize(dir, options = {})
4
+ @dir = dir
5
+ @options = options
6
+ end
6
7
 
7
- def cleanup
8
- File.delete(mtime_file) rescue nil
9
- end
8
+ def cleanup
9
+ File.delete(mtime_file) rescue nil
10
+ end
10
11
 
11
- def fresh?
12
- not File.exists?(mtime_file)
13
- end
12
+ def fresh?
13
+ not File.exists?(mtime_file)
14
+ end
14
15
 
15
- def files
16
- return @files if @files
17
- @files = without_exclusions(Dir.glob(@dir + "/**/*"))
18
- end
16
+ def files
17
+ @files = without_exclusions(Dir.glob(@dir + "/**/*"))
18
+ end
19
19
 
20
- def without_exclusions(files)
21
- return files unless @options[:exclude]
22
- exclusions = [@options[:exclude]].flatten
23
- files.select{|f| not exclusions.any?{|e| f.match e}}
24
- end
20
+ def without_exclusions(files)
21
+ return files unless @options[:exclude]
22
+ exclusions = [@options[:exclude]].flatten
23
+ files.select{|f| not exclusions.any?{|e| f.match e}}
24
+ end
25
25
 
26
- def current_mtimes
27
- @current ||= files.inject({}) do |map, f|
28
- map[f] = File.mtime(f).to_i; map
26
+ def current_mtimes
27
+ @current ||= files.inject({}) do |map, f|
28
+ map[f] = File.mtime(f).to_i; map
29
+ end
29
30
  end
30
- end
31
31
 
32
- def file_changed?(file)
33
- mtimes[file] != current_mtimes[file]
34
- end
32
+ def file_changed?(file)
33
+ mtimes[file] != current_mtimes[file]
34
+ end
35
35
 
36
- def mtimes
37
- return @mtimes if @mtimes
38
- return {} unless File.exists?(mtime_file)
39
- @mtimes = read_mtimes
40
- end
36
+ def mtimes
37
+ return @mtimes if @mtimes
38
+ return {} unless File.exists?(mtime_file)
39
+ @mtimes = read_mtimes
40
+ end
41
41
 
42
- def read_mtimes
43
- mtimes = {}
44
- File.open(mtime_file) do |f|
45
- f.each do |line|
46
- name, time = line.split("\t")
47
- mtimes[name] = time.to_i
42
+ def read_mtimes
43
+ mtimes = {}
44
+ File.open(mtime_file) do |f|
45
+ f.each do |line|
46
+ name, time = line.split("\t")
47
+ mtimes[name] = time.to_i
48
+ end
48
49
  end
50
+ mtimes
49
51
  end
50
- mtimes
51
- end
52
52
 
53
- def changeset
54
- files.select{|f| file_changed?(f)}
55
- end
53
+ def changeset
54
+ changed = files.select{|f| file_changed?(f)}
55
+ deleted = without_exclusions(mtimes.keys) - current_mtimes.keys
56
+ changed + deleted
57
+ end
56
58
 
57
- def has_changes?
58
- not changeset.empty?
59
- end
59
+ def has_changes?
60
+ not changeset.empty?
61
+ end
60
62
 
61
- def mtime_file
62
- @dir + "/.mtimes"
63
- end
63
+ def mtime_file
64
+ @dir + "/.mtimes"
65
+ end
64
66
 
65
- def update
66
- File.open(mtime_file, 'w') do |f|
67
- current = current_mtimes
68
- flat = current.map{|k, v| "#{k}\t#{v}\n"}.join
69
- f.write flat
67
+ def update
68
+ File.open(mtime_file, 'w') do |f|
69
+ current = current_mtimes
70
+ flat = current.map{|k, v| "#{k}\t#{v}\n"}.join
71
+ f.write flat
72
+ end
73
+ reset
70
74
  end
71
- reset
72
- end
73
75
 
74
- def reset
75
- @mtimes = nil
76
- @current = nil
77
- @files = nil
76
+ def reset
77
+ @mtimes = nil
78
+ @current = nil
79
+ @files = nil
80
+ end
78
81
  end
79
- end
82
+ end