sprite 0.1.7 → 0.2.0
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/Gemfile +9 -0
- data/Gemfile.lock +50 -0
- data/README.md +27 -23
- data/Rakefile +37 -20
- data/lib/sprite.rb +5 -0
- data/lib/sprite/builder.rb +90 -101
- data/lib/sprite/config.rb +48 -0
- data/lib/sprite/image_combiner.rb +17 -10
- data/lib/sprite/image_config.rb +40 -0
- data/lib/sprite/image_reader.rb +14 -0
- data/lib/sprite/image_resizer.rb +19 -0
- data/lib/sprite/image_writer.rb +29 -0
- data/lib/sprite/runner.rb +6 -4
- data/lib/sprite/sass_extensions.rb +93 -48
- data/lib/sprite/styles.rb +3 -1
- data/lib/sprite/styles/css_generator.rb +19 -15
- data/lib/sprite/styles/sass_generator.rb +5 -4
- data/lib/sprite/styles/sass_mixin_generator.rb +7 -7
- data/lib/sprite/styles/sass_yml_generator.rb +15 -16
- data/lib/sprite/styles/templated_css_generator.rb +41 -0
- data/spec/output/android_horizontal/images/sprites/android-icons.png +0 -0
- data/spec/output/android_horizontal/stylesheets/android-icons.css +1 -0
- data/spec/output/android_vertical/images/sprites/android-icons.png +0 -0
- data/spec/output/android_vertical/stylesheets/android-icons.css +1 -0
- data/spec/resources/android_css.erb +5 -0
- data/spec/resources/configs/android-icons.yml +19 -0
- data/spec/resources/configs/config-test.yml +26 -0
- data/spec/resources/images/android-icons/LICENSE +1 -0
- data/spec/resources/images/android-icons/barcode.png +0 -0
- data/spec/resources/images/android-icons/cards.png +0 -0
- data/spec/resources/images/android-icons/chart.png +0 -0
- data/spec/resources/images/android-icons/clock.png +0 -0
- data/spec/resources/images/android-icons/cloud.png +0 -0
- data/spec/resources/images/android-icons/colour-picker.png +0 -0
- data/spec/resources/images/android-icons/dialog.png +0 -0
- data/spec/resources/images/android-icons/dice.png +0 -0
- data/spec/resources/images/android-icons/disc.png +0 -0
- data/spec/resources/images/android-icons/equalizer.png +0 -0
- data/spec/resources/images/android-icons/filter.png +0 -0
- data/spec/resources/images/android-icons/flag.png +0 -0
- data/spec/resources/images/android-icons/flash.png +0 -0
- data/spec/resources/images/android-icons/globe.png +0 -0
- data/spec/resources/images/android-icons/happy.png +0 -0
- data/spec/resources/images/android-icons/large-tiles.png +0 -0
- data/spec/resources/images/android-icons/light.png +0 -0
- data/spec/resources/images/android-icons/love.png +0 -0
- data/spec/resources/images/android-icons/magnet.png +0 -0
- data/spec/resources/images/android-icons/monitor.png +0 -0
- data/spec/resources/images/android-icons/music.png +0 -0
- data/spec/resources/images/android-icons/pie-chart.png +0 -0
- data/spec/resources/images/android-icons/ruler.png +0 -0
- data/spec/resources/images/android-icons/sad.png +0 -0
- data/spec/resources/images/android-icons/seal.png +0 -0
- data/spec/resources/images/android-icons/shopping.png +0 -0
- data/spec/resources/images/android-icons/small-tiles.png +0 -0
- data/spec/resources/images/android-icons/sun.png +0 -0
- data/spec/resources/images/android-icons/tag.png +0 -0
- data/spec/resources/images/android-icons/umbrella.png +0 -0
- data/spec/resources/images/topics/good-topic.gif +0 -0
- data/spec/resources/images/topics/mid-topic.gif +0 -0
- data/spec/spec_helper.rb +32 -0
- data/spec/sprite/builder_spec.rb +76 -0
- data/spec/sprite/config_spec.rb +64 -0
- data/spec/sprite/image_combiner_spec.rb +40 -0
- data/spec/sprite/image_reader_spec.rb +16 -0
- data/spec/sprite/styles/css_spec.rb +0 -0
- data/spec/sprite/styles/sass_mixin_spec.rb +0 -0
- data/spec/sprite/styles/sass_spec.rb +0 -0
- data/sprite.gemspec +30 -49
- metadata +142 -21
- data/VERSION +0 -1
@@ -0,0 +1,48 @@
|
|
1
|
+
module Sprite
|
2
|
+
class Config
|
3
|
+
DEFAULT_CONFIG_PATH = 'config/sprite.yml'
|
4
|
+
|
5
|
+
def self.read_config(path = nil)
|
6
|
+
config_path = File.join(Sprite.root, path || DEFAULT_CONFIG_PATH)
|
7
|
+
|
8
|
+
# read configuration
|
9
|
+
if File.exists?(config_path)
|
10
|
+
begin
|
11
|
+
File.open(config_path) {|f| YAML::load(f)} || {}
|
12
|
+
rescue => e
|
13
|
+
puts "Error reading sprite config: #{config_path}"
|
14
|
+
puts e.to_s
|
15
|
+
{}
|
16
|
+
end
|
17
|
+
else
|
18
|
+
{}
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# chop off the trailing slash on a directory path (if it exists)
|
23
|
+
def self.chop_trailing_slash(path)
|
24
|
+
path = path[0...-1] if path[-1] == File::SEPARATOR
|
25
|
+
path
|
26
|
+
end
|
27
|
+
|
28
|
+
# check if the path is set
|
29
|
+
def self.path_present?(path)
|
30
|
+
path.to_s.strip != ""
|
31
|
+
end
|
32
|
+
|
33
|
+
def initialize(settings_hash)
|
34
|
+
@settings = settings_hash
|
35
|
+
end
|
36
|
+
|
37
|
+
# get the disk path for a location within the public folder (if set)
|
38
|
+
def public_path(location, relative = false)
|
39
|
+
path_parts = []
|
40
|
+
path_parts << Sprite.root unless relative
|
41
|
+
path_parts << Config.chop_trailing_slash(@settings['public_path']) if Config.path_present?(@settings['public_path'])
|
42
|
+
path_parts << location
|
43
|
+
|
44
|
+
File.join(*path_parts)
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
@@ -1,15 +1,25 @@
|
|
1
1
|
module Sprite
|
2
2
|
class ImageCombiner
|
3
|
-
def initialize
|
4
|
-
|
5
|
-
|
3
|
+
def initialize(image_config)
|
4
|
+
begin
|
5
|
+
# avoid loading rmagick till the last possible moment
|
6
|
+
require "RMagick"
|
7
|
+
rescue LoadError
|
8
|
+
require 'rmagick'
|
9
|
+
end
|
10
|
+
|
11
|
+
@image_config = image_config
|
6
12
|
end
|
7
|
-
|
13
|
+
|
8
14
|
def composite_images(dest_image, src_image, x, y)
|
9
15
|
width = [src_image.columns + x, dest_image.columns].max
|
10
16
|
height = [src_image.rows + y, dest_image.rows].max
|
11
17
|
image = Magick::Image.new(width, height)
|
12
|
-
|
18
|
+
if @image_config.background_color
|
19
|
+
image.opacity = 0
|
20
|
+
else
|
21
|
+
image.opacity = Magick::MaxRGB
|
22
|
+
end
|
13
23
|
|
14
24
|
image.composite!(dest_image, 0, 0, Magick::OverCompositeOp)
|
15
25
|
image.composite!(src_image, x, y, Magick::OverCompositeOp)
|
@@ -17,17 +27,14 @@ module Sprite
|
|
17
27
|
end
|
18
28
|
|
19
29
|
# Image Utility Methods
|
20
|
-
def get_image(image_filename)
|
21
|
-
image = Magick::Image::read(image_filename).first
|
22
|
-
end
|
23
30
|
|
24
31
|
def image_properties(image)
|
25
32
|
{:name => File.basename(image.filename).split('.')[0], :width => image.columns, :height => image.rows}
|
26
33
|
end
|
27
|
-
|
34
|
+
|
28
35
|
# REMOVE RMAGICK AND USE IMAGEMAGICK FROM THE COMMAND LINE
|
29
36
|
# identify => find properties for an image
|
30
37
|
# composite => combine 2 images
|
31
38
|
|
32
39
|
end
|
33
|
-
end
|
40
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Sprite
|
2
|
+
class ImageConfig
|
3
|
+
def initialize(image_info, global_config_info)
|
4
|
+
@image_info = image_info
|
5
|
+
@global_config_info = global_config_info
|
6
|
+
end
|
7
|
+
|
8
|
+
def sources
|
9
|
+
@image_info['sources'].to_a
|
10
|
+
end
|
11
|
+
|
12
|
+
def name
|
13
|
+
@image_info['name']
|
14
|
+
end
|
15
|
+
|
16
|
+
def format
|
17
|
+
@image_info['format'] || @global_config_info["default_format"]
|
18
|
+
end
|
19
|
+
|
20
|
+
def quality
|
21
|
+
@image_info['quality'] || @global_config_info["default_quality"]
|
22
|
+
end
|
23
|
+
|
24
|
+
def background_color
|
25
|
+
@image_info['background_color'] || @global_config_info["default_background_color"]
|
26
|
+
end
|
27
|
+
|
28
|
+
def spaced_by
|
29
|
+
@image_info['spaced_by'] || @global_config_info["default_spacing"] || 0
|
30
|
+
end
|
31
|
+
|
32
|
+
def resize_to
|
33
|
+
@image_info['resize_to'] || @global_config_info['resize_to']
|
34
|
+
end
|
35
|
+
|
36
|
+
def horizontal_layout?
|
37
|
+
@image_info['align'].to_s == 'horizontal'
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Sprite
|
2
|
+
class ImageReader
|
3
|
+
def self.read(image_filename)
|
4
|
+
# avoid loading rmagick till the last possible moment
|
5
|
+
begin
|
6
|
+
require "RMagick"
|
7
|
+
rescue LoadError
|
8
|
+
require 'rmagick'
|
9
|
+
end
|
10
|
+
|
11
|
+
Magick::Image::read(image_filename).first
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Sprite
|
2
|
+
class ImageResizer
|
3
|
+
def initialize(resize_to)
|
4
|
+
if resize_to
|
5
|
+
@resizing = true
|
6
|
+
@target_width, @target_height = *(resize_to.split('x').map(&:to_i))
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def resize(image)
|
11
|
+
if @resizing
|
12
|
+
needs_resizing = image.columns != @target_width || image.rows != @target_height
|
13
|
+
if needs_resizing
|
14
|
+
image.scale!(@target_width, @target_height)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Sprite
|
2
|
+
class ImageWriter
|
3
|
+
def initialize(config)
|
4
|
+
@config = config
|
5
|
+
end
|
6
|
+
|
7
|
+
def write(image, name, format, quality = nil, background_color = nil)
|
8
|
+
# set up path
|
9
|
+
path = image_output_path(name, format)
|
10
|
+
FileUtils.mkdir_p(File.dirname(path))
|
11
|
+
|
12
|
+
# write sprite image file to disk
|
13
|
+
image.write(path) {
|
14
|
+
self.quality = quality unless quality.nil?
|
15
|
+
self.background_color = background_color unless background_color.nil?
|
16
|
+
}
|
17
|
+
end
|
18
|
+
|
19
|
+
# get the disk path for a location within the image output folder
|
20
|
+
def image_output_path(name, format, relative = false)
|
21
|
+
path_parts = []
|
22
|
+
path_parts << Config.chop_trailing_slash(@config['image_output_path']) if Config.path_present?(@config['image_output_path'])
|
23
|
+
|
24
|
+
cache_buster = "-#{@config['cache_buster']}" if @config['cache_buster']
|
25
|
+
path_parts << "#{name}#{cache_buster}.#{format}"
|
26
|
+
Config.new(@config).public_path(File.join(*path_parts), relative)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/lib/sprite/runner.rb
CHANGED
@@ -1,18 +1,20 @@
|
|
1
1
|
module Sprite
|
2
2
|
class Runner
|
3
|
-
|
3
|
+
|
4
4
|
attr_accessor :options
|
5
5
|
def initialize(args)
|
6
6
|
self.options = set_options(args)
|
7
7
|
end
|
8
|
-
|
8
|
+
|
9
9
|
def set_options(args)
|
10
10
|
opts = {}
|
11
11
|
# TODO
|
12
12
|
# edit options with passed in args
|
13
|
+
opts[:path] = args.first if args.any?
|
14
|
+
|
13
15
|
opts
|
14
16
|
end
|
15
|
-
|
17
|
+
|
16
18
|
# run sprite creator
|
17
19
|
def run!
|
18
20
|
begin
|
@@ -25,6 +27,6 @@ module Sprite
|
|
25
27
|
end
|
26
28
|
0
|
27
29
|
end
|
28
|
-
|
30
|
+
|
29
31
|
end
|
30
32
|
end
|
@@ -1,57 +1,102 @@
|
|
1
|
-
module Sprite
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
1
|
+
module Sprite
|
2
|
+
module Sass
|
3
|
+
module Extensions
|
4
|
+
def sprite_background(group, image)
|
5
|
+
sprite = sprite_data(group, image)
|
6
|
+
if sprite
|
7
|
+
sprite_path = sprite_builder.image_path(group.value)
|
8
|
+
::Sass::Script::String.new "url('#{sprite_path}') no-repeat #{sprite[:x]}px #{sprite[:y]}px"
|
9
|
+
else
|
10
|
+
::Sass::Script::String.new ""
|
11
|
+
end
|
12
|
+
end
|
10
13
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
#
|
37
|
-
|
38
|
-
|
39
|
-
#
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
14
|
+
def sprite_width(*args)
|
15
|
+
::Sass::Script::String.new sprite_attr(:width, *args)
|
16
|
+
end
|
17
|
+
|
18
|
+
def sprite_height(*args)
|
19
|
+
::Sass::Script::String.new sprite_attr(:height, *args)
|
20
|
+
end
|
21
|
+
|
22
|
+
def sprite_x_offset(*args)
|
23
|
+
::Sass::Script::String.new sprite_attr(:x, *args)
|
24
|
+
end
|
25
|
+
|
26
|
+
def sprite_y_offset(*args)
|
27
|
+
::Sass::Script::String.new sprite_attr(:y, *args)
|
28
|
+
end
|
29
|
+
|
30
|
+
def sprite_image(group)
|
31
|
+
::Sass::Script::String.new sprite_builder.image_path(group.value)
|
32
|
+
end
|
33
|
+
|
34
|
+
def sprite_url(group)
|
35
|
+
::Sass::Script::String.new "url('#{sprite_image(group)}')"
|
36
|
+
end
|
37
|
+
|
38
|
+
##
|
39
|
+
# Return a sprite offset for the given image. When the optional x and y values are passed,
|
40
|
+
# numeric values are treated as additional offsets to the sprite image offset. Any string
|
41
|
+
# values are treated as replacement offsets.
|
42
|
+
#
|
43
|
+
# Examples:
|
44
|
+
# * sprite_offset("common", "icon", "100%", 5) => offset is "100% x+5" where x is the x offset in the sprite
|
45
|
+
# * sprite_offset("common", "icon", "top", "right") => offset is "top right"
|
46
|
+
def sprite_offset(group, image, x=nil, y=nil)
|
47
|
+
xoff = compute_offset(group, image, :x, x)
|
48
|
+
yoff = compute_offset(group, image, :y, y)
|
49
|
+
::Sass::Script::String.new "#{xoff} #{yoff}"
|
50
|
+
end
|
51
|
+
|
52
|
+
protected
|
53
|
+
def compute_offset(group, image, axis, offset)
|
54
|
+
if offset
|
55
|
+
val = offset.value
|
56
|
+
if val.is_a? Fixnum
|
57
|
+
(sprite_attr(axis, group, image).to_i + val).to_s + 'px'
|
58
|
+
else
|
59
|
+
val
|
60
|
+
end
|
61
|
+
else
|
62
|
+
sprite_attr(axis, group, image)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def sprite_attr(attr, group, image)
|
67
|
+
sprite = sprite_data(group, image)
|
68
|
+
if sprite
|
69
|
+
"#{sprite[attr]}px"
|
70
|
+
else
|
71
|
+
""
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def sprite_builder
|
76
|
+
@__sprite_builder ||= Builder.from_config
|
77
|
+
end
|
78
|
+
|
79
|
+
def sprite_data(group, image)
|
80
|
+
unless @__sprite_data
|
81
|
+
sprite_data_path = sprite_builder.style_output_path
|
82
|
+
|
83
|
+
# read sprite data from yml
|
84
|
+
@__sprite_data = File.open(sprite_data_path) { |yf| YAML::load( yf ) }
|
85
|
+
end
|
86
|
+
|
87
|
+
group_data = @__sprite_data[group.value]
|
88
|
+
if group_data
|
89
|
+
return group_data[image.value]
|
90
|
+
else
|
91
|
+
nil
|
92
|
+
end
|
93
|
+
end
|
48
94
|
end
|
49
95
|
end
|
50
|
-
|
51
96
|
end
|
52
97
|
|
53
98
|
if defined?(Sass)
|
54
99
|
module Sass::Script::Functions
|
55
100
|
include Sprite::Sass::Extensions
|
56
101
|
end
|
57
|
-
end
|
102
|
+
end
|
data/lib/sprite/styles.rb
CHANGED
@@ -2,15 +2,17 @@ require 'sprite/styles/sass_generator'
|
|
2
2
|
require 'sprite/styles/css_generator'
|
3
3
|
require 'sprite/styles/sass_yml_generator'
|
4
4
|
require 'sprite/styles/sass_mixin_generator'
|
5
|
+
require 'sprite/styles/templated_css_generator'
|
5
6
|
|
6
7
|
module Sprite::Styles
|
7
8
|
GENERATORS = {
|
8
9
|
"css" => "CssGenerator",
|
10
|
+
"templated_css" => "TemplatedCssGenerator",
|
9
11
|
"sass" => "SassGenerator",
|
10
12
|
"sass_mixin" => "SassMixinGenerator",
|
11
13
|
"sass_yml" => "SassYmlGenerator"
|
12
14
|
}
|
13
|
-
|
15
|
+
|
14
16
|
def self.get(config)
|
15
17
|
const_get(GENERATORS[config])
|
16
18
|
rescue
|
@@ -5,26 +5,30 @@ module Sprite
|
|
5
5
|
def initialize(builder)
|
6
6
|
@builder = builder
|
7
7
|
end
|
8
|
-
|
8
|
+
|
9
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
10
|
# write styles to disk
|
14
11
|
File.open(File.join(Sprite.root, path), 'w') do |f|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
12
|
+
write_standard_css(f, sprite_files)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def write_standard_css(f, sprite_files)
|
17
|
+
# set up class_name to append to each rule
|
18
|
+
sprites_class = @builder.config['sprites_class'] ? ".#{@builder.config['sprites_class']}" : ""
|
19
|
+
|
20
|
+
sprite_files.each do |sprite_file, sprites|
|
21
|
+
background_url = @builder.background_url(sprite_file)
|
22
|
+
sprites.each do |sprite|
|
23
|
+
f.puts "#{sprites_class}.#{sprite[:group]}#{@builder.config['class_separator']}#{sprite[:name]} {"
|
24
|
+
f.puts " background: #{background_url} no-repeat #{sprite[:x]}px #{sprite[:y]}px;"
|
25
|
+
f.puts " width: #{sprite[:width]}px;"
|
26
|
+
f.puts " height: #{sprite[:height]}px;"
|
27
|
+
f.puts "}"
|
24
28
|
end
|
25
|
-
end
|
29
|
+
end
|
26
30
|
end
|
27
|
-
|
31
|
+
|
28
32
|
def extension
|
29
33
|
"css"
|
30
34
|
end
|