spriteful 0.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.
- data/LICENSE +13 -0
- data/README.md +103 -0
- data/bin/spriteful +16 -0
- data/lib/spriteful.rb +9 -0
- data/lib/spriteful/cli.rb +124 -0
- data/lib/spriteful/image.rb +43 -0
- data/lib/spriteful/sprite.rb +135 -0
- data/lib/spriteful/stylesheet.rb +109 -0
- data/lib/spriteful/stylesheets/template.css.erb +21 -0
- data/lib/spriteful/stylesheets/template.scss.erb +25 -0
- data/spec/fixtures/simple/blue.png +0 -0
- data/spec/fixtures/simple/red.png +0 -0
- data/spec/image_spec.rb +13 -0
- data/spec/spec_helper.rb +9 -0
- data/spec/sprite_spec.rb +95 -0
- data/spec/stylesheet_spec.rb +28 -0
- metadata +155 -0
data/LICENSE
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
Copyright (c) 2013 Lucas Mazza <lucastmazza@gmail.com>
|
2
|
+
|
3
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
you may not use this file except in compliance with the License.
|
5
|
+
You may obtain a copy of the License at
|
6
|
+
|
7
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
|
9
|
+
Unless required by applicable law or agreed to in writing, software
|
10
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
See the License for the specific language governing permissions and
|
13
|
+
limitations under the License.
|
data/README.md
ADDED
@@ -0,0 +1,103 @@
|
|
1
|
+
# Spriteful
|
2
|
+
|
3
|
+
Spriteful is a command line sprite generator tool, meant to be used regardless of your programming language, application stack or Web framework.
|
4
|
+
|
5
|
+
## Usage
|
6
|
+
|
7
|
+
Lets say that you have your images in `images/icons/` and you want to generate a sprite for them.
|
8
|
+
|
9
|
+
```bash
|
10
|
+
spriteful images/icons
|
11
|
+
# create icons.png
|
12
|
+
# create icons.css
|
13
|
+
```
|
14
|
+
|
15
|
+
Boom! Spriteful will generate a `icons.png` in your working directory and the respective CSS
|
16
|
+
for your sprite in the `icons.css` file.
|
17
|
+
|
18
|
+
If you want a bit more of control on where we should place the combined image and the CSS, you
|
19
|
+
can use the `s` (for `stylesheets`) and `d` ( for `destination`) flags and Spriteful will place
|
20
|
+
your `icons.png` in a specific directory and will save the CSS in the `icons.css` file instead
|
21
|
+
of copying it to your clipboard.
|
22
|
+
|
23
|
+
```bash
|
24
|
+
spriteful images/icons -s stylesheets -d images
|
25
|
+
# create images/icons.png
|
26
|
+
# create stylesheets/icons.css
|
27
|
+
```
|
28
|
+
|
29
|
+
### The CSS
|
30
|
+
|
31
|
+
By default, Spriteful will generate a set of CSS classes based on the images of your sprite. In the
|
32
|
+
case of having a `new.png` image in our `icons` sprite, you can use it putting together the `icons`
|
33
|
+
and `new` class.
|
34
|
+
|
35
|
+
```html
|
36
|
+
<a href='/new' class='icons new'>New thing</a>
|
37
|
+
```
|
38
|
+
|
39
|
+
### SCSS support
|
40
|
+
|
41
|
+
Spriteful can generate SCSS-ish code with the `-f` flag. This way the generated code will use
|
42
|
+
[Placeholder Selectors](http://sass-lang.com/docs/yardoc/file.SASS_REFERENCE.html#placeholder_selectors_)
|
43
|
+
instead of generating a class for each image in your sprite.
|
44
|
+
|
45
|
+
```bash
|
46
|
+
spriteful images/icons -f scss
|
47
|
+
# create icons.png
|
48
|
+
# copy icons.scss
|
49
|
+
```
|
50
|
+
|
51
|
+
```scss
|
52
|
+
// in your SCSS code...
|
53
|
+
.button {
|
54
|
+
@extend %icons-sprite-new;
|
55
|
+
}
|
56
|
+
```
|
57
|
+
|
58
|
+
### Multiple sprites
|
59
|
+
|
60
|
+
You can deal with multiple sprites in a single run. If `images/icons` has a set of images for one
|
61
|
+
sprite and `images/flags` another set you can generate both `icons.png` and `flags.png` with a single
|
62
|
+
execution.
|
63
|
+
|
64
|
+
```bash
|
65
|
+
spriteful images/icons images/flags -s stylesheets -d images
|
66
|
+
# create images/icons.png
|
67
|
+
# create stylesheets/icons.css
|
68
|
+
# create images/flags.png
|
69
|
+
# create stylesheets/flags.css
|
70
|
+
```
|
71
|
+
|
72
|
+
### Spriteful and Rails
|
73
|
+
|
74
|
+
If you are working on a Ruby on Rails application Spriteful can provide some extra goodies for
|
75
|
+
you. If run you the `spriteful` command with the `--rails` flag, all sprites under `app/assets/images/sprites` will be generated with respective stylesheets at `app/assets/stylesheets/sprites`, using the proper `image_url` helper for the format of your choice.
|
76
|
+
|
77
|
+
So, given that you have the `icons` and `flags` directories with your images under `app/assets/images`, you might get a similar output when generating these two sprites.
|
78
|
+
|
79
|
+
```bash
|
80
|
+
spriteful --rails
|
81
|
+
# create app/assets/images/sprites/flags.png
|
82
|
+
# create app/assets/stylesheets/sprites/flags.css.erb
|
83
|
+
# create app/assets/images/sprites/icons.png
|
84
|
+
# create app/assets/stylesheets/sprites/icons.css.erb
|
85
|
+
```
|
86
|
+
|
87
|
+
## Available options
|
88
|
+
|
89
|
+
* `--stylesheets` (`-s`) - Directory to save the generated stylesheet(s), instead of copying them to the clipboard.
|
90
|
+
* `--destination` (`-d`) - Directory to save the generated image(s).
|
91
|
+
* `--rails` (`-r`) - Forces rails specific settings, see [Spriteful and Rails](#spriteful-and-rails) for more info.
|
92
|
+
* `--format` (`-f`) - Format to generate the sprite(s) stylesheet(s). Either "css" or "scss".
|
93
|
+
* `--horizontal` - Changes the sprite orientation to horizontal, since all sprites are combined vertically by default.
|
94
|
+
* `--save` - Saves the provided arguments for later use.
|
95
|
+
* `--spacing` - Add some spacing between the images in the sprite.
|
96
|
+
|
97
|
+
You can add a `.spritefulrc` file with default options to your home directory or the current one that they will be picked up whenever you run the `spriteful` command.
|
98
|
+
|
99
|
+
### Examples
|
100
|
+
|
101
|
+
This repository contains an `examples` folder with some very simple sprites and the output generated
|
102
|
+
by Spriteful. Feel free to take a look or try it on your own by cloning this repository and running
|
103
|
+
`spriteful` on it.
|
data/bin/spriteful
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'shellwords'
|
3
|
+
|
4
|
+
require 'spriteful'
|
5
|
+
require 'spriteful/cli'
|
6
|
+
|
7
|
+
unless ARGV.include?('--help') || ARGV.include?('-h')
|
8
|
+
%w(~/.spritefulrc ./.spritefulrc).each do |rcfile|
|
9
|
+
path = File.expand_path(rcfile)
|
10
|
+
if File.exist?(path)
|
11
|
+
ARGV.unshift(*Shellwords.split(File.read(path)))
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
Spriteful::CLI.start
|
data/lib/spriteful.rb
ADDED
@@ -0,0 +1,124 @@
|
|
1
|
+
require 'shellwords'
|
2
|
+
require 'thor/group'
|
3
|
+
|
4
|
+
module Spriteful
|
5
|
+
class CLI < Thor::Group
|
6
|
+
include Thor::Actions
|
7
|
+
desc 'Generates image sprites with corresponding stylesheets.'
|
8
|
+
|
9
|
+
argument :sources, type: :array, desc: 'Images to generate the sprites.', default: []
|
10
|
+
|
11
|
+
class_option :format, aliases: '-f', banner: 'FORMAT', type: :string, desc: 'Format to generate the sprite(s) stylesheet(s). Either "css" or "scss".', default: 'css'
|
12
|
+
class_option :stylesheets, aliases: '-s', banner: 'STYLESHEETS_DIR', type: :string, desc: 'Directory to save the generated stylesheet(s), instead of copying them to the clipboard.', default: Dir.pwd
|
13
|
+
class_option :destination, aliases: '-d', banner: 'DESTINATION_DIR', type: :string, desc: 'Destination directory to save the combined image(s).', default: Dir.pwd
|
14
|
+
class_option :root, aliases: '-r', banner: 'ROOT_DIR', type: :string, desc: 'Root folder from where your static files will be served.'
|
15
|
+
|
16
|
+
class_option :rails, type: :boolean, desc: 'Follow default conventions for a Rails application with the Asset Pipeline.'
|
17
|
+
class_option :horizontal, type: :boolean, desc: 'Change the sprite orientation to "horizontal".'
|
18
|
+
class_option :save, type: :boolean, desc: 'Save the supplied arguments to ".spritefulrc".'
|
19
|
+
class_option :spacing, type: :numeric, desc: 'Add spacing between the images in the sprite.'
|
20
|
+
|
21
|
+
# Public: Gets the CLI banner for the Thor help message.
|
22
|
+
#
|
23
|
+
# Returns a String.
|
24
|
+
def self.banner
|
25
|
+
'spriteful sources [options]'
|
26
|
+
end
|
27
|
+
|
28
|
+
# Public: Initializes the CLI object and replaces the frozen
|
29
|
+
# 'options' object with an unfrozen one that we can mutate.
|
30
|
+
def initialize(*)
|
31
|
+
super
|
32
|
+
self.options = options.dup
|
33
|
+
end
|
34
|
+
|
35
|
+
# Public: executes the CLI processing of the sprite sources
|
36
|
+
# into combined images and stylesheets.
|
37
|
+
# Returns nothing.
|
38
|
+
def execute
|
39
|
+
prepare_options!
|
40
|
+
if sources.empty?
|
41
|
+
self.class.help(shell)
|
42
|
+
exit(1)
|
43
|
+
end
|
44
|
+
|
45
|
+
sources.uniq!
|
46
|
+
sources.each do |source|
|
47
|
+
create_sprite(source)
|
48
|
+
end
|
49
|
+
|
50
|
+
save_options
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
# Internal: create a sprite image and stylesheet from a given source.
|
55
|
+
#
|
56
|
+
# Returns nothing.
|
57
|
+
def create_sprite(source)
|
58
|
+
sprite = Spriteful::Sprite.new(File.expand_path(source), options.destination, sprite_options)
|
59
|
+
stylesheet = Spriteful::Stylesheet.new(sprite, File.expand_path(options.stylesheets), stylesheet_options)
|
60
|
+
|
61
|
+
sprite.combine!
|
62
|
+
create_file sprite.path, sprite.blob
|
63
|
+
create_file stylesheet.path, stylesheet.render
|
64
|
+
end
|
65
|
+
|
66
|
+
# Internal: Saves the existing options on 'ARGV' to the '.spritefulrc'
|
67
|
+
# file if the '--save' flag is present.
|
68
|
+
#
|
69
|
+
# Returns nothing.
|
70
|
+
def save_options
|
71
|
+
if options.save?
|
72
|
+
options.delete(:save)
|
73
|
+
parts = sources + options.map { |key, value| ["--#{key}", value.to_s] }.flatten
|
74
|
+
create_file '.spritefulrc', Shellwords.join(parts) + "\n", force: true
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def stylesheet_options
|
79
|
+
{
|
80
|
+
root: options.root,
|
81
|
+
format: options.format,
|
82
|
+
rails: options.rails?
|
83
|
+
}
|
84
|
+
end
|
85
|
+
|
86
|
+
# Internal: Gets the set of options that are specific for the 'Sprite'
|
87
|
+
# class.
|
88
|
+
#
|
89
|
+
# Returns a Hash.
|
90
|
+
def sprite_options
|
91
|
+
{
|
92
|
+
horizontal: options.horizontal?,
|
93
|
+
spacing: options.spacing
|
94
|
+
}
|
95
|
+
end
|
96
|
+
|
97
|
+
# Internal: Change the `options` hash if necessary, based on the
|
98
|
+
# 'rails' flag.
|
99
|
+
#
|
100
|
+
# Returns nothing.
|
101
|
+
def prepare_options!
|
102
|
+
if options.rails?
|
103
|
+
sources.concat(detect_sources)
|
104
|
+
set_rails_defaults
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
# Internal: Detects possible source directories in Rails applications
|
109
|
+
# that are present inside the 'images/sprites' asset path.
|
110
|
+
#
|
111
|
+
# Returns an Array of directories.
|
112
|
+
def detect_sources
|
113
|
+
Dir['app/assets/images/sprites/*'].select { |dir| File.directory?(dir) }
|
114
|
+
end
|
115
|
+
|
116
|
+
# Internal: Sets Rails specific default options to the 'options' object.
|
117
|
+
#
|
118
|
+
# Returns nothing.
|
119
|
+
def set_rails_defaults
|
120
|
+
options['stylesheets'] = File.expand_path('app/assets/stylesheets/sprites')
|
121
|
+
options['destination'] = File.expand_path('app/assets/images/sprites')
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Spriteful
|
2
|
+
# Internal: Data structure to represent the images that are part
|
3
|
+
# of a sprite.
|
4
|
+
class Image
|
5
|
+
# Public: returns the path where the Image lives.
|
6
|
+
attr_reader :path
|
7
|
+
|
8
|
+
# Public: returns the filename of the Image.
|
9
|
+
attr_reader :name
|
10
|
+
|
11
|
+
# Public: returns the Image width in pixels.
|
12
|
+
attr_reader :width
|
13
|
+
|
14
|
+
# Public: returns the Image height in pixels.
|
15
|
+
attr_reader :height
|
16
|
+
|
17
|
+
# Public: Gets/sets the top position of the image in a sprite.
|
18
|
+
attr_accessor :top
|
19
|
+
|
20
|
+
# Public: Gets/sets the left position of the image in a sprite.
|
21
|
+
attr_accessor :left
|
22
|
+
|
23
|
+
# Public: Gets the source 'ChunkyPNG::Image'.
|
24
|
+
attr_reader :source
|
25
|
+
|
26
|
+
# Public: Initializes an Image, extracting the image
|
27
|
+
# metadata such as width and path supplied by an 'ChunkyPNG::Image'
|
28
|
+
# object that was initialized from the real image blob.
|
29
|
+
#
|
30
|
+
# chunky_image - an 'ChunkyPNG::Image' object.
|
31
|
+
# path - the path where the image is present.
|
32
|
+
def initialize(chunky_image, path)
|
33
|
+
@source = chunky_image
|
34
|
+
@path = path
|
35
|
+
@name = File.basename(@path)
|
36
|
+
@width = chunky_image.width
|
37
|
+
@height = chunky_image.height
|
38
|
+
|
39
|
+
@top = 0
|
40
|
+
@left = 0
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,135 @@
|
|
1
|
+
require 'chunky_png'
|
2
|
+
|
3
|
+
module Spriteful
|
4
|
+
# Public: the 'Sprite' class is responsible for combining a directory
|
5
|
+
# of images into a single one, and providing the required information
|
6
|
+
# about the related images.
|
7
|
+
class Sprite
|
8
|
+
# Public: returns the path where the sprite will be saved.
|
9
|
+
attr_reader :path
|
10
|
+
|
11
|
+
# Public: Gets the name of the sprite.
|
12
|
+
attr_reader :name
|
13
|
+
|
14
|
+
# Public: Gets the filename of the sprite.
|
15
|
+
attr_reader :filename
|
16
|
+
|
17
|
+
# Public: Gets the the spacing between the images in the sprite.
|
18
|
+
attr_reader :spacing
|
19
|
+
|
20
|
+
# Public: Gets the the binary contents of the combined image.
|
21
|
+
attr_reader :blob
|
22
|
+
|
23
|
+
# Public: Gets the the width of the combined image.
|
24
|
+
attr_reader :width
|
25
|
+
|
26
|
+
# Public: Gets the the height of the combined image.
|
27
|
+
attr_reader :height
|
28
|
+
|
29
|
+
# Public: Gets the flag to check if the sprite is vertical or not.
|
30
|
+
attr_reader :vertical
|
31
|
+
alias :vertical? :vertical
|
32
|
+
|
33
|
+
# Public: Initialize a Sprite.
|
34
|
+
#
|
35
|
+
# source_dir - the source directory where the sprite images are located.
|
36
|
+
# destination - the destination directory where the sprite should be saved.
|
37
|
+
# options - additional Hash of options.
|
38
|
+
# :horizontal - flag to turn the sprite into the horizontal
|
39
|
+
# orientation.
|
40
|
+
# :spacing - spacing in pixels that should be placed between
|
41
|
+
# the images in the sprite. Defaults to 0.
|
42
|
+
def initialize(source_dir, destination, options = {})
|
43
|
+
source_pattern = File.join(source_dir, '*.png')
|
44
|
+
sources = Dir[source_pattern].sort
|
45
|
+
|
46
|
+
if sources.size == 0
|
47
|
+
raise EmptySourceError, "No image sources found at '#{source_dir}'."
|
48
|
+
end
|
49
|
+
|
50
|
+
@vertical = !options[:horizontal]
|
51
|
+
@spacing = options[:spacing] || 0
|
52
|
+
|
53
|
+
@name = File.basename(source_dir)
|
54
|
+
@filename = "#{name}.png"
|
55
|
+
@path = File.expand_path(File.join(destination, @filename))
|
56
|
+
sources = sources.map { |source| [source, ChunkyPNG::Image.from_file(source)] }
|
57
|
+
@images = initialize_images(Hash[sources])
|
58
|
+
|
59
|
+
@height, @width = detect_dimensions
|
60
|
+
end
|
61
|
+
|
62
|
+
# Public: combines the source images into a single one,
|
63
|
+
# storing the combined image into the sprite path.
|
64
|
+
#
|
65
|
+
# Returns nothing.
|
66
|
+
def combine!
|
67
|
+
combined = ChunkyPNG::Image.new(width, height, ChunkyPNG::Color::TRANSPARENT)
|
68
|
+
@images.each do |image|
|
69
|
+
combined.compose!(image.source, image.left.abs, image.top.abs)
|
70
|
+
end
|
71
|
+
@blob = combined.to_blob(:best_compression)
|
72
|
+
end
|
73
|
+
|
74
|
+
# Public: exposes the source images found in the 'source'
|
75
|
+
# directory.
|
76
|
+
#
|
77
|
+
# Yields an 'Image' object on each interation.
|
78
|
+
#
|
79
|
+
# Returns an 'Enumerator' if no block is given.
|
80
|
+
def each_image
|
81
|
+
return to_enum(__method__) unless block_given?
|
82
|
+
@images.each { |image| yield image }
|
83
|
+
end
|
84
|
+
|
85
|
+
alias :images :each_image
|
86
|
+
|
87
|
+
private
|
88
|
+
# Internal: detect the expected 'height' and 'width' of the
|
89
|
+
# combined image of this sprite. This should take in account
|
90
|
+
# the sprite orientation and the configured spacing.
|
91
|
+
#
|
92
|
+
# Returns an Array with the 'height' and 'width'.
|
93
|
+
def detect_dimensions
|
94
|
+
total_spacing = (@images.size - 1) * spacing
|
95
|
+
|
96
|
+
if vertical?
|
97
|
+
height = @images.map { |image| image.height }.inject(:+) + total_spacing
|
98
|
+
width = @images.map { |image| image.width }.max
|
99
|
+
else
|
100
|
+
height = @images.map { |image| image.height }.max
|
101
|
+
width = @images.map { |image| image.width }.inject(:+) + total_spacing
|
102
|
+
end
|
103
|
+
|
104
|
+
[height, width]
|
105
|
+
end
|
106
|
+
|
107
|
+
# Internal: Initializes a collection of 'Image' objects
|
108
|
+
# based on the 'source' images. The images will have
|
109
|
+
# the source images metadata and the required 'top' and
|
110
|
+
# 'left' coordinates that the image will be placed
|
111
|
+
# in the sprite.
|
112
|
+
#
|
113
|
+
# sources - a Hash of source paths and image objects.
|
114
|
+
#
|
115
|
+
# Returns an Array.
|
116
|
+
def initialize_images(sources)
|
117
|
+
sprite_position = 0
|
118
|
+
images = []
|
119
|
+
sources.each_with_index do |(path, chunky_image), index|
|
120
|
+
image = Image.new(chunky_image, path)
|
121
|
+
padding = index * spacing
|
122
|
+
|
123
|
+
if vertical?
|
124
|
+
image.top = sprite_position
|
125
|
+
sprite_position -= image.height + padding
|
126
|
+
else
|
127
|
+
image.left = sprite_position
|
128
|
+
sprite_position -= image.width + padding
|
129
|
+
end
|
130
|
+
images << image
|
131
|
+
end
|
132
|
+
images
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
require 'erb'
|
3
|
+
|
4
|
+
module Spriteful
|
5
|
+
# Public: class responsible for putting together the CSS code
|
6
|
+
# to use a specific sprite.
|
7
|
+
class Stylesheet
|
8
|
+
# Public: returns the format used to render the Stylesheet.
|
9
|
+
attr_reader :format
|
10
|
+
|
11
|
+
# Public: returns the 'Sprite' of this Stylesheet.
|
12
|
+
attr_reader :sprite
|
13
|
+
|
14
|
+
# Public: returns the path where the Stylesheet should be stored.
|
15
|
+
attr_reader :path
|
16
|
+
|
17
|
+
# Public: Initialize a Stylesheet
|
18
|
+
#
|
19
|
+
# sprite - a 'Sprite' object to create the Stylesheet.
|
20
|
+
# destination - the directory where the Stylesheet will be created.
|
21
|
+
# options - additional Hash of options.
|
22
|
+
# :format - the Stylesheet format.
|
23
|
+
# :rails - A flag to generate Asset Pipeline compatible Stylesheets.
|
24
|
+
def initialize(sprite, destination, options = {})
|
25
|
+
@sprite = sprite
|
26
|
+
@destination = Pathname.new(destination)
|
27
|
+
@root = nil
|
28
|
+
if options[:root]
|
29
|
+
@root = Pathname.new(File.expand_path(options[:root]))
|
30
|
+
end
|
31
|
+
@format = options[:format]
|
32
|
+
@rails = options.fetch(:rails) { false }
|
33
|
+
|
34
|
+
@path = @destination.join(name)
|
35
|
+
end
|
36
|
+
|
37
|
+
# Public: renders the CSS code for this Stylesheet.
|
38
|
+
# An ERB template will be used to process the code, based
|
39
|
+
# on the stylesheet format.
|
40
|
+
#
|
41
|
+
# Returns the CSS code as a 'String'.
|
42
|
+
def render
|
43
|
+
source = File.expand_path("../stylesheets/template.#{format}.erb", __FILE__)
|
44
|
+
ERB.new(File.read(source), nil, '-').result(binding)
|
45
|
+
end
|
46
|
+
|
47
|
+
# Public: returns this Stylesheet name, based
|
48
|
+
# on the Sprite name and the current format.
|
49
|
+
#
|
50
|
+
# Returns a String.
|
51
|
+
def name
|
52
|
+
extension = rails? ? rails_extension : format
|
53
|
+
"#{sprite_name}.#{extension}"
|
54
|
+
end
|
55
|
+
|
56
|
+
protected
|
57
|
+
|
58
|
+
# Internal: returns the 'rails ' flag.
|
59
|
+
def rails?
|
60
|
+
@rails
|
61
|
+
end
|
62
|
+
|
63
|
+
# Internal: defines the file extension to be used with
|
64
|
+
# Rails applications, since we need to account for the ERB
|
65
|
+
# preprocessing of plain CSS files.
|
66
|
+
#
|
67
|
+
# Returns a String.
|
68
|
+
def rails_extension
|
69
|
+
case format
|
70
|
+
when 'css'
|
71
|
+
'css.erb'
|
72
|
+
when 'scss'
|
73
|
+
'scss'
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def sprite_name
|
78
|
+
case format
|
79
|
+
when 'css'
|
80
|
+
sprite.name
|
81
|
+
when 'scss'
|
82
|
+
"_#{sprite.name}"
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
# Internal: sanitizes the 'name' of a given object to
|
87
|
+
# be used as a CSS selector class.
|
88
|
+
#
|
89
|
+
# Returns a 'String'.
|
90
|
+
def class_name_for(object)
|
91
|
+
object.name.split('.').first.downcase.tr('_', '-')
|
92
|
+
end
|
93
|
+
|
94
|
+
# Internal: computes a relative path between the sprite
|
95
|
+
# path and the stylesheet expected location.
|
96
|
+
#
|
97
|
+
# Returns a 'String'.
|
98
|
+
def image_url(sprite)
|
99
|
+
path = Pathname.new(sprite.path)
|
100
|
+
if @rails
|
101
|
+
"sprites/#{sprite.filename}"
|
102
|
+
elsif @root
|
103
|
+
"/#{path.relative_path_from(@root)}"
|
104
|
+
else
|
105
|
+
path.relative_path_from(@destination)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
/*
|
2
|
+
* This Stylesheet was generated by the 'spriteful' gem.
|
3
|
+
* Below there are several CSS classes to use the '<%= sprite.name %>'
|
4
|
+
* sprite on you HTML code, as in:
|
5
|
+
*
|
6
|
+
* <div class='<%= class_name_for(sprite) %> <%= class_name_for(sprite.images.first) %>'>Your markup here.</div>
|
7
|
+
*/
|
8
|
+
|
9
|
+
.<%= class_name_for(sprite) %> {
|
10
|
+
<% if rails? -%>
|
11
|
+
background-image: url(<%%= image_url('<%= image_url(sprite) %>') %>);
|
12
|
+
<% else -%>
|
13
|
+
background-image: url(<%= image_url(sprite) %>);
|
14
|
+
<% end -%>
|
15
|
+
background-repeat: no-repeat;
|
16
|
+
}
|
17
|
+
<% sprite.each_image do |image| %>
|
18
|
+
.<%= class_name_for(sprite) %>.<%= class_name_for(image) %> {
|
19
|
+
background-position: <%= image.left %>px <%= image.top %>px;
|
20
|
+
}
|
21
|
+
<% end %>
|
@@ -0,0 +1,25 @@
|
|
1
|
+
// ============================================================================
|
2
|
+
// This Stylesheet was generated by the 'spriteful' gem.
|
3
|
+
// Below there are several [Placeholder Selectors]
|
4
|
+
// (http://sass-lang.com/docs/yardoc/file.SASS_REFERENCE.html#placeholder_selectors_)
|
5
|
+
// to use the '<%= sprite.name %>' sprite on your SCSS code, as in:
|
6
|
+
//
|
7
|
+
// .my-thing {
|
8
|
+
// @extend %<%= class_name_for(sprite) %>-sprite-<%= class_name_for(sprite.images.first) %>;
|
9
|
+
// // Your styles here.
|
10
|
+
// }
|
11
|
+
|
12
|
+
%<%= class_name_for(sprite) %>-sprite {
|
13
|
+
<%- if rails? -%>
|
14
|
+
background-image: image-url('<%= image_url(sprite) %>');
|
15
|
+
<%- else -%>
|
16
|
+
background-image: url(<%= image_url(sprite) %>);
|
17
|
+
<%- end -%>
|
18
|
+
background-repeat: no-repeat;
|
19
|
+
}
|
20
|
+
<% sprite.each_image do |image| %>
|
21
|
+
%<%= class_name_for(sprite) %>-sprite-<%= class_name_for(image) %> {
|
22
|
+
@extend %<%= class_name_for(sprite) %>-sprite;
|
23
|
+
background-position: <%= image.left %>px <%= image.top %>px;
|
24
|
+
}
|
25
|
+
<% end %>
|
Binary file
|
Binary file
|
data/spec/image_spec.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Spriteful::Image do
|
4
|
+
let(:path) { 'path/to/image.png' }
|
5
|
+
let(:chunky_image) { double('ChunkyPNG Image', width: 10, height: 5) }
|
6
|
+
subject(:image) { Spriteful::Image.new(chunky_image, path) }
|
7
|
+
|
8
|
+
it { expect(image.name).to eq('image.png') }
|
9
|
+
it { expect(image.path).to eq('path/to/image.png') }
|
10
|
+
it { expect(image.width).to eq(10) }
|
11
|
+
it { expect(image.height).to eq(5) }
|
12
|
+
it { expect(image.source).to eq(chunky_image) }
|
13
|
+
end
|
data/spec/spec_helper.rb
ADDED
data/spec/sprite_spec.rb
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe Spriteful::Sprite do
|
5
|
+
let(:source) { File.expand_path('spec/fixtures/simple') }
|
6
|
+
let(:destination) { File.expand_path('tmp') }
|
7
|
+
|
8
|
+
before { FileUtils.rm(Dir["#{destination}/*.png"]) }
|
9
|
+
|
10
|
+
describe 'initialization' do
|
11
|
+
it 'raises an error if the source directory is empty' do
|
12
|
+
source = File.expand_path('spec/fixtures/missing')
|
13
|
+
expect {
|
14
|
+
Spriteful::Sprite.new(source, destination)
|
15
|
+
}.to raise_error(Spriteful::EmptySourceError)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe '#width' do
|
20
|
+
it 'returns the whole sprite width' do
|
21
|
+
sprite = Spriteful::Sprite.new(source, destination)
|
22
|
+
expect(sprite.width).to be(10)
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'accounts for the padding information' do
|
26
|
+
sprite = Spriteful::Sprite.new(source, destination, spacing: 10, horizontal: true)
|
27
|
+
expect(sprite.width).to be(30)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe '#height' do
|
32
|
+
it 'returns the whole sprite height' do
|
33
|
+
sprite = Spriteful::Sprite.new(source, destination)
|
34
|
+
expect(sprite.height).to be(20)
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'accounts for the spacing information' do
|
38
|
+
sprite = Spriteful::Sprite.new(source, destination, spacing: 10)
|
39
|
+
expect(sprite.height).to be(30)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe '#path' do
|
44
|
+
it 'returns the path where the combined image will be saved' do
|
45
|
+
sprite = Spriteful::Sprite.new(source, destination)
|
46
|
+
expect(sprite.path).to eq(File.expand_path('tmp/simple.png'))
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe '#filename' do
|
51
|
+
it 'returns the filename of the sprite combined image' do
|
52
|
+
sprite = Spriteful::Sprite.new(source, destination)
|
53
|
+
expect(sprite.filename).to eq('simple.png')
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe '#combine!' do
|
58
|
+
it 'sets the sprite blob' do
|
59
|
+
sprite = Spriteful::Sprite.new(source, destination)
|
60
|
+
sprite.combine!
|
61
|
+
expect(sprite.blob).to be
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'combine images vertically by default' do
|
65
|
+
sprite = Spriteful::Sprite.new(source, destination)
|
66
|
+
sprite.combine!
|
67
|
+
image = ChunkyPNG::Image.from_blob(sprite.blob)
|
68
|
+
expect(image.width).to be(10)
|
69
|
+
expect(image.height).to be(20)
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'can combine images horizontally' do
|
73
|
+
sprite = Spriteful::Sprite.new(source, destination, horizontal: true)
|
74
|
+
sprite.combine!
|
75
|
+
image = ChunkyPNG::Image.from_blob(sprite.blob)
|
76
|
+
expect(image.width).to be(20)
|
77
|
+
expect(image.height).to be(10)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
describe '#images' do
|
82
|
+
it 'yields an object for each image found in the source directory' do
|
83
|
+
sprite = Spriteful::Sprite.new(source, destination)
|
84
|
+
blue, red = sprite.images.to_a
|
85
|
+
|
86
|
+
expect(blue.name).to eq('blue.png')
|
87
|
+
expect(blue.top).to eq(0)
|
88
|
+
expect(blue.left).to eq(0)
|
89
|
+
|
90
|
+
expect(red.name).to eq('red.png')
|
91
|
+
expect(red.top).to eq(-10)
|
92
|
+
expect(red.left).to eq(0)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Spriteful::Stylesheet do
|
4
|
+
let(:source) { File.expand_path('spec/fixtures/simple') }
|
5
|
+
let(:destination) { File.expand_path('tmp') }
|
6
|
+
let(:sprite) { Spriteful::Sprite.new(source, destination) }
|
7
|
+
|
8
|
+
describe '#render' do
|
9
|
+
it 'renders the CSS for the given sprite' do
|
10
|
+
stylesheet = Spriteful::Stylesheet.new(sprite, destination, format: 'css')
|
11
|
+
output = stylesheet.render
|
12
|
+
|
13
|
+
expect(output).to match(/.simple \{/)
|
14
|
+
expect(output).to match(/.simple.blue \{/)
|
15
|
+
expect(output).to match(/.simple.red \{/)
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'renders the SCSS format' do
|
19
|
+
sprite = Spriteful::Sprite.new(source, destination)
|
20
|
+
stylesheet = Spriteful::Stylesheet.new(sprite, destination, format: 'scss')
|
21
|
+
output = stylesheet.render
|
22
|
+
|
23
|
+
expect(output).to match(/%simple-sprite \{/)
|
24
|
+
expect(output).to match(/%simple-sprite-blue \{/)
|
25
|
+
expect(output).to match(/%simple-sprite-red \{/)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
metadata
ADDED
@@ -0,0 +1,155 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: spriteful
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Lucas Mazza
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-08-21 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: thor
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 0.18.1
|
22
|
+
- - <
|
23
|
+
- !ruby/object:Gem::Version
|
24
|
+
version: '2.0'
|
25
|
+
type: :runtime
|
26
|
+
prerelease: false
|
27
|
+
version_requirements: !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 0.18.1
|
33
|
+
- - <
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: '2.0'
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: chunky_png
|
38
|
+
requirement: !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ~>
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 1.2.8
|
44
|
+
type: :runtime
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: !ruby/object:Gem::Requirement
|
47
|
+
none: false
|
48
|
+
requirements:
|
49
|
+
- - ~>
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: 1.2.8
|
52
|
+
- !ruby/object:Gem::Dependency
|
53
|
+
name: rspec
|
54
|
+
requirement: !ruby/object:Gem::Requirement
|
55
|
+
none: false
|
56
|
+
requirements:
|
57
|
+
- - ~>
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: 2.14.0
|
60
|
+
type: :development
|
61
|
+
prerelease: false
|
62
|
+
version_requirements: !ruby/object:Gem::Requirement
|
63
|
+
none: false
|
64
|
+
requirements:
|
65
|
+
- - ~>
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: 2.14.0
|
68
|
+
- !ruby/object:Gem::Dependency
|
69
|
+
name: bundler
|
70
|
+
requirement: !ruby/object:Gem::Requirement
|
71
|
+
none: false
|
72
|
+
requirements:
|
73
|
+
- - ~>
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '1.3'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
none: false
|
80
|
+
requirements:
|
81
|
+
- - ~>
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: '1.3'
|
84
|
+
- !ruby/object:Gem::Dependency
|
85
|
+
name: rake
|
86
|
+
requirement: !ruby/object:Gem::Requirement
|
87
|
+
none: false
|
88
|
+
requirements:
|
89
|
+
- - ! '>='
|
90
|
+
- !ruby/object:Gem::Version
|
91
|
+
version: '0'
|
92
|
+
type: :development
|
93
|
+
prerelease: false
|
94
|
+
version_requirements: !ruby/object:Gem::Requirement
|
95
|
+
none: false
|
96
|
+
requirements:
|
97
|
+
- - ! '>='
|
98
|
+
- !ruby/object:Gem::Version
|
99
|
+
version: '0'
|
100
|
+
description: A sprite generation tool
|
101
|
+
email:
|
102
|
+
- lucastmazza@gmail.com
|
103
|
+
executables:
|
104
|
+
- spriteful
|
105
|
+
extensions: []
|
106
|
+
extra_rdoc_files: []
|
107
|
+
files:
|
108
|
+
- LICENSE
|
109
|
+
- README.md
|
110
|
+
- lib/spriteful/cli.rb
|
111
|
+
- lib/spriteful/image.rb
|
112
|
+
- lib/spriteful/sprite.rb
|
113
|
+
- lib/spriteful/stylesheet.rb
|
114
|
+
- lib/spriteful/stylesheets/template.css.erb
|
115
|
+
- lib/spriteful/stylesheets/template.scss.erb
|
116
|
+
- lib/spriteful.rb
|
117
|
+
- spec/fixtures/simple/blue.png
|
118
|
+
- spec/fixtures/simple/red.png
|
119
|
+
- spec/image_spec.rb
|
120
|
+
- spec/spec_helper.rb
|
121
|
+
- spec/sprite_spec.rb
|
122
|
+
- spec/stylesheet_spec.rb
|
123
|
+
- bin/spriteful
|
124
|
+
homepage: https://github.com/lucasmazza/spriteful
|
125
|
+
licenses:
|
126
|
+
- Apache 2.0
|
127
|
+
post_install_message:
|
128
|
+
rdoc_options: []
|
129
|
+
require_paths:
|
130
|
+
- lib
|
131
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
132
|
+
none: false
|
133
|
+
requirements:
|
134
|
+
- - ! '>='
|
135
|
+
- !ruby/object:Gem::Version
|
136
|
+
version: '0'
|
137
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
138
|
+
none: false
|
139
|
+
requirements:
|
140
|
+
- - ! '>='
|
141
|
+
- !ruby/object:Gem::Version
|
142
|
+
version: '0'
|
143
|
+
requirements: []
|
144
|
+
rubyforge_project:
|
145
|
+
rubygems_version: 1.8.23
|
146
|
+
signing_key:
|
147
|
+
specification_version: 3
|
148
|
+
summary: ''
|
149
|
+
test_files:
|
150
|
+
- spec/fixtures/simple/blue.png
|
151
|
+
- spec/fixtures/simple/red.png
|
152
|
+
- spec/image_spec.rb
|
153
|
+
- spec/spec_helper.rb
|
154
|
+
- spec/sprite_spec.rb
|
155
|
+
- spec/stylesheet_spec.rb
|