sprite-generator 0.1.7
Sign up to get free protection for your applications and to get access to all the features.
- data/MIT-LICENSE +20 -0
- data/README.md +184 -0
- data/Rakefile +27 -0
- data/VERSION +1 -0
- data/bin/sprite +8 -0
- data/lib/sprite.rb +23 -0
- data/lib/sprite/builder.rb +198 -0
- data/lib/sprite/image_combiner.rb +33 -0
- data/lib/sprite/runner.rb +30 -0
- data/lib/sprite/sass_extensions.rb +57 -0
- data/lib/sprite/styles.rb +20 -0
- data/lib/sprite/styles/css_generator.rb +33 -0
- data/lib/sprite/styles/sass_generator.rb +43 -0
- data/lib/sprite/styles/sass_mixin_generator.rb +46 -0
- data/lib/sprite/styles/sass_yml_generator.rb +54 -0
- data/rails/init.rb +2 -0
- data/sprite-generator.gemspec +56 -0
- data/tasks/sprite_tasks.rake +13 -0
- metadata +73 -0
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 [Richard Huang (flyerhzm@gmail.com)]
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,184 @@
|
|
1
|
+
# sprite-generator #
|
2
|
+
|
3
|
+
`sprite-generator` is a gem that helps generate css sprite images automagically. It's aim is to support all web frameworks (Merb/Rails/Sinatra), and have extensible output generator. By default, it supports CSS and SASS output (via mixins).
|
4
|
+
|
5
|
+
## INSTALL ##
|
6
|
+
|
7
|
+
### Install the `rmagick` gem ###
|
8
|
+
|
9
|
+
`sprite-generator` currently requires the rmagick gem. to install it, use
|
10
|
+
|
11
|
+
gem install rmagick
|
12
|
+
|
13
|
+
### Install the `sprite-generator` gem ###
|
14
|
+
|
15
|
+
Install the `sprite-generator` gem from gemcutter
|
16
|
+
|
17
|
+
gem sources -a http://gemcutter.org
|
18
|
+
gem install sprite-generator
|
19
|
+
|
20
|
+
## USAGE ##
|
21
|
+
|
22
|
+
if installed as a gem, at your root project folder you can just run
|
23
|
+
|
24
|
+
sprite
|
25
|
+
|
26
|
+
### Intelligent Defaults ###
|
27
|
+
|
28
|
+
Without having to configure anything, `sprite-generator` will allow you to easily generate sprites based on a couple default folder settings we give you right off the bat.
|
29
|
+
|
30
|
+
For example, given you have the following setup:
|
31
|
+
|
32
|
+
public/
|
33
|
+
images/
|
34
|
+
sprites/
|
35
|
+
black-icons/
|
36
|
+
stop.png
|
37
|
+
go.png
|
38
|
+
back.png
|
39
|
+
forward.png
|
40
|
+
|
41
|
+
weather/
|
42
|
+
sunny.gif
|
43
|
+
rainy.gif
|
44
|
+
cloudy.gif
|
45
|
+
|
46
|
+
Running `sprite-generator` with no configuration file will generate the following new files:
|
47
|
+
|
48
|
+
public/
|
49
|
+
stylesheets/
|
50
|
+
sprites.css
|
51
|
+
images/
|
52
|
+
sprites/
|
53
|
+
black-icons.png
|
54
|
+
weather.png
|
55
|
+
|
56
|
+
Any folders within `public/images/sprites/` will get compressed into a merged image file at the same
|
57
|
+
location. Then `sprites.css` will get generated in the stylesheets folder with all the class definitions for
|
58
|
+
these files. Just add a link to `sprites.css` into your html <head> and you're ready to go!
|
59
|
+
|
60
|
+
|
61
|
+
## CONFIGURATION ##
|
62
|
+
|
63
|
+
Configuration of `sprite-generator` is done via `config/sprite.yml`. It allows you to set sprite configuration options, and fine tune exactly which sprites get generated where.
|
64
|
+
|
65
|
+
* `config:` section defines all the global properties for sprite generation. Such as how it generates the styles, where it looks for images, where it writes it output file to, and what image file format it uses by default
|
66
|
+
- `style:` defines how the style rules are outputted. built in options are `css`, `sass`, and `sass_mixin`. (defaults to `css`)
|
67
|
+
- `style_output_path:` defines the file path where your style settings get written (defaults to `stylesheets/sprites`). the file extension not needed as it will be set based on the `style:` setting
|
68
|
+
- `image_output_path:` defines the folder path where the combined sprite images files are written (defaults to `images/sprites/`)
|
69
|
+
- `image_source_path:` defines the folder where source image files are read from (defaults to `images/`)
|
70
|
+
- `public_path:` defines the root folder where static assets live (defaults to `public/`)
|
71
|
+
- `sprites_class:` defines the class name that gets added to all sprite stylesheet rules (defaults to `sprites`)
|
72
|
+
- `default_format:` defines the default file image format of the generated files. (defaults to `png`)
|
73
|
+
- `default_spacing:` defines the default pixel spacing between sprites (defaults to 0)
|
74
|
+
- `class_separator:` used to generated the class name by separating the image name and sprite name (defaults to `-`)
|
75
|
+
|
76
|
+
* `images:` section provides an array of configurations which define which image files are built, and where they get their sprites from. each image setup provides the following config options:
|
77
|
+
- `name:` name of image (required)
|
78
|
+
- `sources:` defines a list of source image filenames to build the target image from (required). They are parsed by <code>Dir.glob</code>
|
79
|
+
- `align:` defines the composite gravity type, horizontal or vertical. (defaults to `vertical`)
|
80
|
+
- `spaced_by:` spacing (in pixels) between the combined images. (defaults to `0`)
|
81
|
+
- `format:` define what image file format gets created (optional, uses `default_format` setting if not set)
|
82
|
+
|
83
|
+
All image and style paths should be set relative to the public folder (which is configurable via public_path setting).
|
84
|
+
|
85
|
+
### Sample Configuration `config/sprite.yml` ###
|
86
|
+
|
87
|
+
# defines the base configuration options (file paths, etc, default style, etc)
|
88
|
+
|
89
|
+
config:
|
90
|
+
style: css
|
91
|
+
style_output_path: stylesheets/sprites
|
92
|
+
image_output_path: images/sprites/
|
93
|
+
image_source_path: images/
|
94
|
+
public_path: public/
|
95
|
+
sprites_class: 'sprites'
|
96
|
+
class_separator: '-'
|
97
|
+
default_format: png
|
98
|
+
default_spacing: 50
|
99
|
+
|
100
|
+
# defines what sprite collections get created
|
101
|
+
images:
|
102
|
+
|
103
|
+
# creates a public/images/sprites/blue_stars.png image with 4 sprites in it
|
104
|
+
- name: blue_stars
|
105
|
+
format: png
|
106
|
+
align: horizontal
|
107
|
+
spaced_by: 50
|
108
|
+
sources:
|
109
|
+
- icons/blue-stars/small.png
|
110
|
+
- icons/blue-stars/medium.png
|
111
|
+
- icons/blue-stars/large.png
|
112
|
+
- icons/blue-stars/xlarge.png
|
113
|
+
|
114
|
+
# creates a public/images/sprites/green-stars.jpg image with
|
115
|
+
# all the gif files contained within /images/icons/green-stars/
|
116
|
+
- name: green_stars
|
117
|
+
format: png
|
118
|
+
align: vertical
|
119
|
+
spaced_by: 50
|
120
|
+
sources:
|
121
|
+
- icons/green-stars/*.gif
|
122
|
+
|
123
|
+
### Style Settings ###
|
124
|
+
|
125
|
+
By default, it will use with `style: css` and generate the file at `public/stylesheets/sprites.css`
|
126
|
+
|
127
|
+
.sprites.blue-stars-small {
|
128
|
+
background: url('/images/icons/blue-stars/small.png') no-repeat 0px 0px;
|
129
|
+
width: 12px;
|
130
|
+
height: 6px;
|
131
|
+
}
|
132
|
+
.sprites.blue-stars-medium {
|
133
|
+
background: url('/images/icons/blue-stars/medium.png') no-repeat 0px 6px;
|
134
|
+
width: 30px;
|
135
|
+
height: 15px;
|
136
|
+
}
|
137
|
+
.sprites.blue-stars-large {
|
138
|
+
background: url('/images/icons/blue-stars/large.png') no-repeat 0px 21px;
|
139
|
+
width: 60px;
|
140
|
+
height: 30px;
|
141
|
+
}
|
142
|
+
.sprites.blue-stars-xlarge {
|
143
|
+
background: url('/images/icons/blue-stars/xlarge.png') no-repeat 0px 96px;
|
144
|
+
width: 100px;
|
145
|
+
height: 75px;
|
146
|
+
}
|
147
|
+
|
148
|
+
We also support mixin syntax via `style: sass_mixin`. If set, it will generate a SASS mixin which you can use in order to mix in these sprites anywhere within your SASS stylesheets. For this option, set `style_output_path:` to `stylesheets/sass/_sprites` in order to generate the sass mixin file at `stylesheets/sass/_sprites.sass`
|
149
|
+
|
150
|
+
@import "sass/mixins/sprites.sass"
|
151
|
+
|
152
|
+
// you can then use your sprite like this
|
153
|
+
.largebluestar
|
154
|
+
+sprite("blue-stars", "large")
|
155
|
+
|
156
|
+
.mysmallbluestar
|
157
|
+
+sprite("blue-stars", "small")
|
158
|
+
|
159
|
+
Additional style generators are very easy to add. We have one for `style: sass` and `style: sass_ext`. The `sass_ext` style is a work in progress, as it's attempting to write the sprite data to yml and use a dynamic sass extension to provide the mixin. Eventually, if it works, this will be the default for `sass_mixin`
|
160
|
+
|
161
|
+
## Framework Integration?? ##
|
162
|
+
|
163
|
+
`sprite` is provided as a command line helper. Deep web framework integration is not implemented at this time, however it shouldn't be needed. Just generate your sprites on your dev machine by running the command line, check in the resulting sprite images and stylesheets to your source control, and deploy!
|
164
|
+
|
165
|
+
You can also easily script it out via capistrano. You could also run `sprite` on application start, or just about anywhere. Let me know what limitations you run into.
|
166
|
+
|
167
|
+
## ABOUT `sprite` ##
|
168
|
+
|
169
|
+
`sprite-generator` is based on `sprite` gem by Jacques Crocker: [sprite](http://github.com/merbjedi/sprite)
|
170
|
+
|
171
|
+
`sprite` was originally based off of Richard Huang's excellent Rails plugin: [css_sprite](http://github.com/flyerhzm/css_sprite)
|
172
|
+
|
173
|
+
Since then it's been rebuilt (with some reuse of the image generation code) to be a general purpose ruby executable, with hooks for merb/rails/sinatra
|
174
|
+
|
175
|
+
|
176
|
+
## LICENSE ##
|
177
|
+
|
178
|
+
Released under the MIT License
|
179
|
+
|
180
|
+
## COPYRIGHT ##
|
181
|
+
|
182
|
+
Copyright (c) 2009 Gist
|
183
|
+
|
184
|
+
Original Codebase Copyright (c) 2009 [Richard Huang]
|
data/Rakefile
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'spec/rake/spectask'
|
3
|
+
require 'jeweler'
|
4
|
+
|
5
|
+
desc 'Default: run unit tests.'
|
6
|
+
task :default => :spec
|
7
|
+
|
8
|
+
desc "Run all specs in spec directory"
|
9
|
+
Spec::Rake::SpecTask.new(:spec) do |t|
|
10
|
+
t.spec_files = FileList['spec/**/*_spec.rb']
|
11
|
+
end
|
12
|
+
|
13
|
+
Jeweler::Tasks.new do |gemspec|
|
14
|
+
gemspec.name = "sprite"
|
15
|
+
gemspec.summary = "generate your css sprites automagically"
|
16
|
+
gemspec.description = "sprite is a rails/merb plugin that generates sprites for css, sass"
|
17
|
+
gemspec.email = "merbjedi@gmail.com"
|
18
|
+
gemspec.homepage = "http://github.com/merbjedi/sprite"
|
19
|
+
gemspec.authors = ["Jacques Crocker"]
|
20
|
+
gemspec.files.exclude '.gitignore'
|
21
|
+
|
22
|
+
# removing test files and specs from the gem to save space
|
23
|
+
gemspec.files -= Dir.glob("spec/**/*")
|
24
|
+
gemspec.test_files = []
|
25
|
+
end
|
26
|
+
Jeweler::GemcutterTasks.new
|
27
|
+
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.6
|
data/bin/sprite
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# The compass command line utility
|
3
|
+
|
4
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib', 'sprite'))
|
5
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib', 'sprite', 'runner'))
|
6
|
+
|
7
|
+
command = Sprite::Runner.new(ARGV)
|
8
|
+
exit command.run!
|
data/lib/sprite.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
module Sprite
|
2
|
+
|
3
|
+
# provides the root directory to use when reading and writing files
|
4
|
+
def self.root
|
5
|
+
@root ||= nil
|
6
|
+
|
7
|
+
# set the root to the framework setting (if not already set)
|
8
|
+
@root ||= begin
|
9
|
+
if defined?(Rails)
|
10
|
+
Rails.root
|
11
|
+
elsif defined?(Merb)
|
12
|
+
Merb.root
|
13
|
+
else
|
14
|
+
"."
|
15
|
+
end
|
16
|
+
end
|
17
|
+
@root
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
require 'sprite/builder'
|
22
|
+
require 'sprite/image_combiner'
|
23
|
+
require 'sprite/styles'
|
@@ -0,0 +1,198 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
module Sprite
|
3
|
+
class Builder
|
4
|
+
DEFAULT_CONFIG_PATH = 'config/sprite.yml'
|
5
|
+
|
6
|
+
attr_reader :config
|
7
|
+
attr_reader :images
|
8
|
+
|
9
|
+
def self.from_config(path = nil)
|
10
|
+
results = {}
|
11
|
+
config_path = File.join(Sprite.root, path || DEFAULT_CONFIG_PATH)
|
12
|
+
|
13
|
+
# read configuration
|
14
|
+
if File.exists?(config_path)
|
15
|
+
begin
|
16
|
+
results = File.open(config_path) {|f| YAML::load(f)} || {}
|
17
|
+
rescue => e
|
18
|
+
puts "Error reading sprite config: #{config_path}"
|
19
|
+
puts e.to_s
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
new(results["config"], results["images"])
|
24
|
+
end
|
25
|
+
|
26
|
+
def initialize(config = nil, images = nil)
|
27
|
+
@config = config || {}
|
28
|
+
set_config_defaults
|
29
|
+
|
30
|
+
@images = images || []
|
31
|
+
set_image_defaults
|
32
|
+
expand_image_paths
|
33
|
+
|
34
|
+
# initialize sprite files
|
35
|
+
@sprite_files = {}
|
36
|
+
end
|
37
|
+
|
38
|
+
def build
|
39
|
+
@sprite_files = {}
|
40
|
+
|
41
|
+
if images.size > 0
|
42
|
+
# create images
|
43
|
+
images.each do |image|
|
44
|
+
write_image(image)
|
45
|
+
end
|
46
|
+
|
47
|
+
if @sprite_files.values.length > 0
|
48
|
+
# write css
|
49
|
+
write_styles
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
protected
|
55
|
+
def write_image(image)
|
56
|
+
results = []
|
57
|
+
sources = image['sources'].to_a
|
58
|
+
return unless sources.length > 0
|
59
|
+
|
60
|
+
name = image['name']
|
61
|
+
format = image['format'] || config["default_format"]
|
62
|
+
spaced_by = image['spaced_by'] || config["default_spacing"] || 0
|
63
|
+
|
64
|
+
combiner = ImageCombiner.new
|
65
|
+
|
66
|
+
dest_image = combiner.get_image(sources.shift)
|
67
|
+
results << combiner.image_properties(dest_image).merge(:x => 0, :y => 0, :group => name)
|
68
|
+
sources.each do |source|
|
69
|
+
source_image = combiner.get_image(source)
|
70
|
+
if image['align'].to_s == 'horizontal'
|
71
|
+
x = dest_image.columns + spaced_by
|
72
|
+
y = 0
|
73
|
+
align = "horizontal"
|
74
|
+
else
|
75
|
+
x = 0
|
76
|
+
y = dest_image.rows + spaced_by
|
77
|
+
align = "vertical"
|
78
|
+
end
|
79
|
+
results << combiner.image_properties(source_image).merge(:x => -x, :y => -y, :group => name, :align => align)
|
80
|
+
dest_image = combiner.composite_images(dest_image, source_image, x, y)
|
81
|
+
end
|
82
|
+
|
83
|
+
# set up path
|
84
|
+
path = image_output_path(name, format)
|
85
|
+
FileUtils.mkdir_p(File.dirname(path))
|
86
|
+
|
87
|
+
# write sprite image file to disk
|
88
|
+
dest_image.write(path)
|
89
|
+
@sprite_files["#{name}.#{format}"] = results
|
90
|
+
end
|
91
|
+
|
92
|
+
def write_styles
|
93
|
+
style = Styles.get(config["style"]).new(self)
|
94
|
+
|
95
|
+
# use the absolute style output path to make sure we have the directory set up
|
96
|
+
path = style_output_path(style.extension, false)
|
97
|
+
FileUtils.mkdir_p(File.dirname(path))
|
98
|
+
|
99
|
+
# send the style the relative path
|
100
|
+
style.write(style_output_path(style.extension, true), @sprite_files)
|
101
|
+
end
|
102
|
+
|
103
|
+
# sets all the default values on the config
|
104
|
+
def set_config_defaults
|
105
|
+
@config['style'] ||= 'css'
|
106
|
+
@config['style_output_path'] ||= 'stylesheets/sprites'
|
107
|
+
@config['image_output_path'] ||= 'images/sprites/'
|
108
|
+
@config['image_source_path'] ||= 'images/'
|
109
|
+
@config['public_path'] ||= 'public/'
|
110
|
+
@config['default_format'] ||= 'png'
|
111
|
+
@config['class_separator'] ||= '-'
|
112
|
+
@config["sprites_class"] ||= 'sprites'
|
113
|
+
@config["default_spacing"] ||= 0
|
114
|
+
end
|
115
|
+
|
116
|
+
# if no image configs are detected, set some intelligent defaults
|
117
|
+
def set_image_defaults
|
118
|
+
return unless @images.size == 0
|
119
|
+
|
120
|
+
sprites_path = image_source_path("sprites")
|
121
|
+
|
122
|
+
if File.exists?(sprites_path)
|
123
|
+
Dir.glob(File.join(sprites_path, "*")) do |dir|
|
124
|
+
next unless File.directory?(dir)
|
125
|
+
source_name = File.basename(dir)
|
126
|
+
|
127
|
+
# default to finding all png, gif, jpg, and jpegs within the directory
|
128
|
+
images << {
|
129
|
+
"name" => source_name,
|
130
|
+
"sources" => [
|
131
|
+
File.join("sprites", source_name, "*.png"),
|
132
|
+
File.join("sprites", source_name, "*.gif"),
|
133
|
+
File.join("sprites", source_name, "*.jpg"),
|
134
|
+
File.join("sprites", source_name, "*.jpeg"),
|
135
|
+
]
|
136
|
+
}
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
# expands out sources, taking the Glob paths and turning them into separate entries in the array
|
142
|
+
def expand_image_paths
|
143
|
+
# cycle through image sources and expand out globs
|
144
|
+
@images.each do |image|
|
145
|
+
# expand out all the globs
|
146
|
+
image['sources'] = image['sources'].to_a.map{ |source|
|
147
|
+
Dir.glob(image_source_path(source))
|
148
|
+
}.flatten.compact
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
# get the disk path for the style output file
|
153
|
+
def style_output_path(file_ext, relative = false)
|
154
|
+
path = config['style_output_path']
|
155
|
+
unless path.include?(".#{file_ext}")
|
156
|
+
path = "#{path}.#{file_ext}"
|
157
|
+
end
|
158
|
+
public_path(path, relative)
|
159
|
+
end
|
160
|
+
|
161
|
+
# get the disk path for a location within the image output folder
|
162
|
+
def image_output_path(name, format, relative = false)
|
163
|
+
path_parts = []
|
164
|
+
path_parts << chop_trailing_slash(config['image_output_path']) if path_present?(config['image_output_path'])
|
165
|
+
path_parts << "#{name}.#{format}"
|
166
|
+
public_path(File.join(*path_parts), relative)
|
167
|
+
end
|
168
|
+
|
169
|
+
# get the disk path for an image source file
|
170
|
+
def image_source_path(location, relative = false)
|
171
|
+
path_parts = []
|
172
|
+
path_parts << chop_trailing_slash(config["image_source_path"]) if path_present?(config['image_source_path'])
|
173
|
+
path_parts << location
|
174
|
+
public_path(File.join(*path_parts), relative)
|
175
|
+
end
|
176
|
+
|
177
|
+
# get the disk path for a location within the public folder (if set)
|
178
|
+
def public_path(location, relative = false)
|
179
|
+
path_parts = []
|
180
|
+
path_parts << Sprite.root unless relative
|
181
|
+
path_parts << chop_trailing_slash(config['public_path']) if path_present?(config['public_path'])
|
182
|
+
path_parts << location
|
183
|
+
|
184
|
+
File.join(*path_parts)
|
185
|
+
end
|
186
|
+
|
187
|
+
# chop off the trailing slash on a directory path (if it exists)
|
188
|
+
def chop_trailing_slash(path)
|
189
|
+
path = path[0...-1] if path[-1] == File::SEPARATOR
|
190
|
+
path
|
191
|
+
end
|
192
|
+
|
193
|
+
# check if the path is set
|
194
|
+
def path_present?(path)
|
195
|
+
path.to_s.strip != ""
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Sprite
|
2
|
+
class ImageCombiner
|
3
|
+
def initialize
|
4
|
+
# avoid loading rmagick till the last possible moment
|
5
|
+
require 'RMagick'
|
6
|
+
end
|
7
|
+
|
8
|
+
def composite_images(dest_image, src_image, x, y)
|
9
|
+
width = [src_image.columns + x, dest_image.columns].max
|
10
|
+
height = [src_image.rows + y, dest_image.rows].max
|
11
|
+
image = Magick::Image.new(width, height)
|
12
|
+
image.opacity = Magick::MaxRGB
|
13
|
+
|
14
|
+
image.composite!(dest_image, 0, 0, Magick::OverCompositeOp)
|
15
|
+
image.composite!(src_image, x, y, Magick::OverCompositeOp)
|
16
|
+
image
|
17
|
+
end
|
18
|
+
|
19
|
+
# Image Utility Methods
|
20
|
+
def get_image(image_filename)
|
21
|
+
image = Magick::Image::read(image_filename).first
|
22
|
+
end
|
23
|
+
|
24
|
+
def image_properties(image)
|
25
|
+
{:name => File.basename(image.filename).split('.')[0], :width => image.columns, :height => image.rows}
|
26
|
+
end
|
27
|
+
|
28
|
+
# REMOVE RMAGICK AND USE IMAGEMAGICK FROM THE COMMAND LINE
|
29
|
+
# identify => find properties for an image
|
30
|
+
# composite => combine 2 images
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Sprite
|
2
|
+
class Runner
|
3
|
+
|
4
|
+
attr_accessor :options
|
5
|
+
def initialize(args)
|
6
|
+
self.options = set_options(args)
|
7
|
+
end
|
8
|
+
|
9
|
+
def set_options(args)
|
10
|
+
opts = {}
|
11
|
+
# TODO
|
12
|
+
# edit options with passed in args
|
13
|
+
opts
|
14
|
+
end
|
15
|
+
|
16
|
+
# run sprite creator
|
17
|
+
def run!
|
18
|
+
begin
|
19
|
+
Sprite::Builder.from_config(options[:path]).build
|
20
|
+
# rescue Exception => e
|
21
|
+
# # catch errors
|
22
|
+
# puts "ERROR"
|
23
|
+
# puts e
|
24
|
+
# return 1
|
25
|
+
end
|
26
|
+
0
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module Sprite::Sass::Extensions
|
2
|
+
def sprite_background(group, image)
|
3
|
+
sprite = sprite_data(group, image)
|
4
|
+
if sprite
|
5
|
+
"url('#{sprite[:img]}') no-repeat #{sprite[:x]}px #{sprite[:y]}px"
|
6
|
+
else
|
7
|
+
""
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def sprite_width(group, image)
|
12
|
+
sprite = sprite_data(group, image)
|
13
|
+
if sprite
|
14
|
+
"#{sprite[:width]}px"
|
15
|
+
else
|
16
|
+
""
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def sprite_height(group, image)
|
21
|
+
sprite = sprite_data(group, image)
|
22
|
+
if sprite
|
23
|
+
"#{sprite[:height]}px"
|
24
|
+
else
|
25
|
+
""
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
protected
|
30
|
+
def sprite_data(group, image)
|
31
|
+
unless @__sprite_data
|
32
|
+
|
33
|
+
# TODO: read template from !sprite_data
|
34
|
+
sprite_data_path = "public/sass/sprites.yml"
|
35
|
+
|
36
|
+
# figure out the site root
|
37
|
+
root = "./"
|
38
|
+
|
39
|
+
# read sprite data from yml
|
40
|
+
@__sprite_data = File.open(File.join(root, sprite_data_path)) { |yf| YAML::load( yf ) }
|
41
|
+
end
|
42
|
+
|
43
|
+
group_data = @__sprite_data[group.to_s]
|
44
|
+
if group_data
|
45
|
+
return group_data[image.to_s]
|
46
|
+
else
|
47
|
+
nil
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
if defined?(Sass)
|
54
|
+
module Sass::Script::Functions
|
55
|
+
include Sprite::Sass::Extensions
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'sprite/styles/sass_generator'
|
2
|
+
require 'sprite/styles/css_generator'
|
3
|
+
require 'sprite/styles/sass_yml_generator'
|
4
|
+
require 'sprite/styles/sass_mixin_generator'
|
5
|
+
|
6
|
+
module Sprite::Styles
|
7
|
+
GENERATORS = {
|
8
|
+
"css" => "CssGenerator",
|
9
|
+
"sass" => "SassGenerator",
|
10
|
+
"sass_mixin" => "SassMixinGenerator",
|
11
|
+
"sass_yml" => "SassYmlGenerator"
|
12
|
+
}
|
13
|
+
|
14
|
+
def self.get(config)
|
15
|
+
const_get(GENERATORS[config])
|
16
|
+
rescue
|
17
|
+
CssGenerator
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Sprite
|
2
|
+
module Styles
|
3
|
+
# renders standard css style rules
|
4
|
+
class CssGenerator
|
5
|
+
def initialize(builder)
|
6
|
+
@builder = builder
|
7
|
+
end
|
8
|
+
|
9
|
+
def write(path, sprite_files)
|
10
|
+
# set up class_name to append to each rule
|
11
|
+
sprites_class = @builder.config['sprites_class'] ? ".#{@builder.config['sprites_class']}" : ""
|
12
|
+
|
13
|
+
# write styles to disk
|
14
|
+
File.open(File.join(Sprite.root, path), 'w') do |f|
|
15
|
+
# write stylesheet file to disk
|
16
|
+
sprite_files.each do |sprite_file, sprites|
|
17
|
+
sprites.each do |sprite|
|
18
|
+
f.puts "#{sprites_class}.#{sprite[:group]}#{@builder.config['class_separator']}#{sprite[:name]} {"
|
19
|
+
f.puts " background: url('/#{@builder.config['image_output_path']}#{sprite_file}') no-repeat #{sprite[:x]}px #{sprite[:y]}px;"
|
20
|
+
f.puts " width: #{sprite[:width]}px;"
|
21
|
+
f.puts " height: #{sprite[:height]}px;"
|
22
|
+
f.puts "}"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def extension
|
29
|
+
"css"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Sprite
|
2
|
+
module Styles
|
3
|
+
|
4
|
+
# renders standard sass rules
|
5
|
+
class SassGenerator
|
6
|
+
def initialize(builder)
|
7
|
+
@builder = builder
|
8
|
+
end
|
9
|
+
|
10
|
+
def write(path, sprite_files)
|
11
|
+
@level = 0
|
12
|
+
|
13
|
+
File.open(File.join(Sprite.root, path), 'w') do |f|
|
14
|
+
if @builder.config['sprites_class']
|
15
|
+
f.puts ".#{@builder.config['sprites_class']}"
|
16
|
+
@level += 1
|
17
|
+
end
|
18
|
+
|
19
|
+
sprite_files.each do |sprite_file, sprites|
|
20
|
+
sprites.each do |sprite|
|
21
|
+
f.puts sass_line("&.#{sprite[:group]}#{@builder.config['class_separator']}#{sprite[:name]}")
|
22
|
+
@level += 1
|
23
|
+
f.puts sass_line("background: url('/#{@builder.config['image_output_path']}#{sprite_file}') no-repeat #{sprite[:x]}px #{sprite[:y]}px")
|
24
|
+
f.puts sass_line("width: #{sprite[:width]}px")
|
25
|
+
f.puts sass_line("height: #{sprite[:height]}px")
|
26
|
+
f.puts sass_line("")
|
27
|
+
@level -= 1
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# write sass output with correct tab spaces prepended
|
34
|
+
def sass_line(sass)
|
35
|
+
"#{' '*@level}#{sass}"
|
36
|
+
end
|
37
|
+
|
38
|
+
def extension
|
39
|
+
"sass"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Sprite
|
2
|
+
module Styles
|
3
|
+
# renders a yml file that is later parsed by a sass extension when generating the mixins
|
4
|
+
class SassMixinGenerator
|
5
|
+
def initialize(builder)
|
6
|
+
@builder = builder
|
7
|
+
end
|
8
|
+
|
9
|
+
def write(path, sprite_files)
|
10
|
+
# write the sass mixins to disk
|
11
|
+
File.open(File.join(Sprite.root, path), 'w') do |f|
|
12
|
+
add_else = false
|
13
|
+
|
14
|
+
f.puts "= sprite(!group_name, !image_name, !offset=0)"
|
15
|
+
sprite_files.each do |sprite_file, sprites|
|
16
|
+
sprites.each do |sprite|
|
17
|
+
|
18
|
+
f << " @"
|
19
|
+
if add_else
|
20
|
+
f << "else "
|
21
|
+
end
|
22
|
+
add_else = true
|
23
|
+
#{sprite[:x]}px #{sprite[:y]}px
|
24
|
+
|
25
|
+
if sprite[:align] == 'horizontal'
|
26
|
+
background_offset = "\#{#{sprite[:x]}+!offset}px #{sprite[:y]}px"
|
27
|
+
else
|
28
|
+
background_offset = "#{sprite[:x]}px \#{#{sprite[:y]}+!offset}px"
|
29
|
+
end
|
30
|
+
|
31
|
+
f.puts %{if !group_name == "#{sprite[:group]}" and !image_name == "#{sprite[:name]}"}
|
32
|
+
f.puts " background: url('/#{@builder.config['image_output_path']}#{sprite_file}') no-repeat #{background_offset}"
|
33
|
+
f.puts " width: #{sprite[:width]}px"
|
34
|
+
f.puts " height: #{sprite[:height]}px"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def extension
|
41
|
+
"sass"
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
module Sprite
|
3
|
+
module Styles
|
4
|
+
# renders a yml file that is later parsed by a sass extension when generating the mixins
|
5
|
+
class SassYmlGenerator
|
6
|
+
def initialize(builder)
|
7
|
+
@builder = builder
|
8
|
+
end
|
9
|
+
|
10
|
+
def write(path, sprite_files)
|
11
|
+
# build the yml file
|
12
|
+
config_location = write_config(path, sprite_files)
|
13
|
+
|
14
|
+
# write the sass mixins to disk
|
15
|
+
File.open(File.join(Sprite.root, path), 'w') do |f|
|
16
|
+
f.puts "!sprite_data = '#{config_location}'"
|
17
|
+
f.puts ""
|
18
|
+
f.puts "= sprite(!group_name, !image_name)"
|
19
|
+
f.puts " background= sprite_background(!group_name, !image_name)"
|
20
|
+
f.puts " width= sprite_width(!group_name, !image_name)"
|
21
|
+
f.puts " height= sprite_height(!group_name, !image_name)"
|
22
|
+
f.puts ""
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# write the sprite configuration file (used by the yml extension)
|
27
|
+
def write_config(path, sprite_files)
|
28
|
+
# build a grouped hash with all the sprites in it
|
29
|
+
result = {}
|
30
|
+
sprite_files.each do |sprite_file, sprites|
|
31
|
+
sprites.each do |sprite|
|
32
|
+
if sprite[:group]
|
33
|
+
result[sprite[:group]] ||= {}
|
34
|
+
result[sprite[:group]][sprite[:name]] = sprite
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# write the config yml to disk
|
40
|
+
config_path = path.gsub(".sass", ".yml")
|
41
|
+
File.open(File.join(Sprite.root, config_path), 'w') do |f|
|
42
|
+
YAML.dump(result, f)
|
43
|
+
end
|
44
|
+
|
45
|
+
config_path
|
46
|
+
end
|
47
|
+
|
48
|
+
def extension
|
49
|
+
"sass"
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
data/rails/init.rb
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{sprite-generator}
|
8
|
+
s.version = "0.1.7"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Jacques Crocker", "Anton Styagun"]
|
12
|
+
s.date = %q{2009-11-27}
|
13
|
+
s.default_executable = %q{sprite}
|
14
|
+
s.description = %q{sprite-generator is a rails/merb plugin that generates sprites for css, sass}
|
15
|
+
s.email = %q{astyagun@gmail.com}
|
16
|
+
s.executables = ["sprite"]
|
17
|
+
s.extra_rdoc_files = [
|
18
|
+
"README.md"
|
19
|
+
]
|
20
|
+
s.files = [
|
21
|
+
"MIT-LICENSE",
|
22
|
+
"README.md",
|
23
|
+
"Rakefile",
|
24
|
+
"VERSION",
|
25
|
+
"bin/sprite",
|
26
|
+
"lib/sprite.rb",
|
27
|
+
"lib/sprite/builder.rb",
|
28
|
+
"lib/sprite/image_combiner.rb",
|
29
|
+
"lib/sprite/runner.rb",
|
30
|
+
"lib/sprite/sass_extensions.rb",
|
31
|
+
"lib/sprite/styles.rb",
|
32
|
+
"lib/sprite/styles/css_generator.rb",
|
33
|
+
"lib/sprite/styles/sass_generator.rb",
|
34
|
+
"lib/sprite/styles/sass_mixin_generator.rb",
|
35
|
+
"lib/sprite/styles/sass_yml_generator.rb",
|
36
|
+
"rails/init.rb",
|
37
|
+
"sprite-generator.gemspec",
|
38
|
+
"tasks/sprite_tasks.rake"
|
39
|
+
]
|
40
|
+
s.homepage = %q{http://github.com/iast/sprite}
|
41
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
42
|
+
s.require_paths = ["lib"]
|
43
|
+
s.rubygems_version = %q{1.3.5}
|
44
|
+
s.summary = %q{generate your css sprites automagically}
|
45
|
+
|
46
|
+
if s.respond_to? :specification_version then
|
47
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
48
|
+
s.specification_version = 3
|
49
|
+
|
50
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
51
|
+
else
|
52
|
+
end
|
53
|
+
else
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '../lib/sprite/sprite.rb')
|
2
|
+
|
3
|
+
namespace :sprite do
|
4
|
+
desc "build sprite images based on config/sprite.yml"
|
5
|
+
task :build do
|
6
|
+
Sprite.new.build
|
7
|
+
end
|
8
|
+
|
9
|
+
task :list => [:build] do
|
10
|
+
# TODO
|
11
|
+
# list all the currently configured sprites
|
12
|
+
end
|
13
|
+
end
|
metadata
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: sprite-generator
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.7
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jacques Crocker
|
8
|
+
- Anton Styagun
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2009-11-27 00:00:00 +02:00
|
14
|
+
default_executable: sprite
|
15
|
+
dependencies: []
|
16
|
+
|
17
|
+
description: sprite-generator is a rails/merb plugin that generates sprites for css, sass
|
18
|
+
email: astyagun@gmail.com
|
19
|
+
executables:
|
20
|
+
- sprite
|
21
|
+
extensions: []
|
22
|
+
|
23
|
+
extra_rdoc_files:
|
24
|
+
- README.md
|
25
|
+
files:
|
26
|
+
- MIT-LICENSE
|
27
|
+
- README.md
|
28
|
+
- Rakefile
|
29
|
+
- VERSION
|
30
|
+
- bin/sprite
|
31
|
+
- lib/sprite.rb
|
32
|
+
- lib/sprite/builder.rb
|
33
|
+
- lib/sprite/image_combiner.rb
|
34
|
+
- lib/sprite/runner.rb
|
35
|
+
- lib/sprite/sass_extensions.rb
|
36
|
+
- lib/sprite/styles.rb
|
37
|
+
- lib/sprite/styles/css_generator.rb
|
38
|
+
- lib/sprite/styles/sass_generator.rb
|
39
|
+
- lib/sprite/styles/sass_mixin_generator.rb
|
40
|
+
- lib/sprite/styles/sass_yml_generator.rb
|
41
|
+
- rails/init.rb
|
42
|
+
- sprite-generator.gemspec
|
43
|
+
- tasks/sprite_tasks.rake
|
44
|
+
has_rdoc: true
|
45
|
+
homepage: http://github.com/iast/sprite
|
46
|
+
licenses: []
|
47
|
+
|
48
|
+
post_install_message:
|
49
|
+
rdoc_options:
|
50
|
+
- --charset=UTF-8
|
51
|
+
require_paths:
|
52
|
+
- lib
|
53
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: "0"
|
58
|
+
version:
|
59
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - ">="
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: "0"
|
64
|
+
version:
|
65
|
+
requirements: []
|
66
|
+
|
67
|
+
rubyforge_project:
|
68
|
+
rubygems_version: 1.3.5
|
69
|
+
signing_key:
|
70
|
+
specification_version: 3
|
71
|
+
summary: generate your css sprites automagically
|
72
|
+
test_files: []
|
73
|
+
|