asset_compiler 0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/asset_compiler.rb +26 -0
- data/lib/asset_compiler/asset_task.rb +168 -0
- data/lib/asset_compiler/image_task.rb +39 -0
- data/lib/asset_compiler/rmagick_transformation_script.rb +156 -0
- metadata +53 -0
@@ -0,0 +1,26 @@
|
|
1
|
+
$: << File.join( File.dirname( __FILE__ ), 'asset_compiler' )
|
2
|
+
|
3
|
+
require 'rubygems' unless $".include? 'rubygems.rb'
|
4
|
+
require 'asset_task'
|
5
|
+
require 'image_task'
|
6
|
+
|
7
|
+
# Convenience method to define an AssetTask in the assets namespace.
|
8
|
+
def asset_task name, &block
|
9
|
+
namespace :assets do
|
10
|
+
AssetTask.new name, &block
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
# Convenience method to define an ImageTask in the assets namespace.
|
15
|
+
def image_task name, &block
|
16
|
+
namespace :assets do
|
17
|
+
ImageTask.new name, &block
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# Convenience method to add transformations to RMagickTransformationScript
|
22
|
+
def define_image_transformation name, &block
|
23
|
+
RMagickTransformationScript.class_eval do
|
24
|
+
define_method name, &block
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,168 @@
|
|
1
|
+
#--
|
2
|
+
# Jeremy Voorhis
|
3
|
+
# March 2006
|
4
|
+
#++
|
5
|
+
|
6
|
+
# Task library for managing a directory of assets.
|
7
|
+
# For example:
|
8
|
+
#
|
9
|
+
# namespace :assets do
|
10
|
+
# AssetTask.new( :old_war_films ) do |t|
|
11
|
+
# t.src_files = Rake::FileList[image_src 'old_war_films/*.mov']
|
12
|
+
# t.build_path = File.join RAILS_ROOT, 'public/assets/old_war_films'
|
13
|
+
#
|
14
|
+
# t.transformation do |src, target|
|
15
|
+
# cp src, target
|
16
|
+
# end
|
17
|
+
# end
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# This example defines the following tasks:
|
21
|
+
# rake assets:build # Build all assets
|
22
|
+
# rake assets:clobber # Clobber all assets
|
23
|
+
# rake assets:old_war_films:build # Build the old_war_films files
|
24
|
+
# rake assets:old_war_films:clobber # Remove old_war_films files
|
25
|
+
# rake assets:old_war_films:rebuild # Force a rebuild of the old_war_films files
|
26
|
+
# rake assets:rebuild # Rebuild all assets
|
27
|
+
|
28
|
+
require 'rake/tasklib'
|
29
|
+
|
30
|
+
class AssetTask
|
31
|
+
attr_accessor :name
|
32
|
+
attr_accessor :src_files
|
33
|
+
attr_accessor :build_path
|
34
|
+
attr_accessor :remote_dirs
|
35
|
+
|
36
|
+
def initialize name, &block
|
37
|
+
@name = name
|
38
|
+
@src_files = Rake::FileList.new
|
39
|
+
@remote_dirs = []
|
40
|
+
|
41
|
+
instance_eval &block
|
42
|
+
|
43
|
+
define_clobber
|
44
|
+
define_rebuild
|
45
|
+
define_build_directory_task
|
46
|
+
define_build_task
|
47
|
+
add_dependencies_to_main_task
|
48
|
+
end
|
49
|
+
|
50
|
+
def from path
|
51
|
+
@src_files = path
|
52
|
+
end
|
53
|
+
|
54
|
+
def to path
|
55
|
+
@build_path = path
|
56
|
+
end
|
57
|
+
|
58
|
+
# Captures the transformation run on each individual object.
|
59
|
+
def transformation
|
60
|
+
@transformation = Proc.new
|
61
|
+
end
|
62
|
+
|
63
|
+
protected
|
64
|
+
# Returns an absolute target path for a given absolute +src+ path.
|
65
|
+
def target_for src
|
66
|
+
File.join @build_path, File.basename( src )
|
67
|
+
end
|
68
|
+
|
69
|
+
# Name of the build task for this task library.
|
70
|
+
def build_task_name
|
71
|
+
"#{@name}:build"
|
72
|
+
end
|
73
|
+
|
74
|
+
# Name of the clobber task for this task library.
|
75
|
+
def clobber_task_name
|
76
|
+
"#{@name}:clobber"
|
77
|
+
end
|
78
|
+
|
79
|
+
# Name of the rebuild task for this task library.
|
80
|
+
def rebuild_task_name
|
81
|
+
"#{@name}:rebuild"
|
82
|
+
end
|
83
|
+
|
84
|
+
# Defines the rebuild task for this task library.
|
85
|
+
def define_rebuild
|
86
|
+
desc "Force a rebuild of the #{@name} files"
|
87
|
+
task rebuild_task_name => [clobber_task_name, build_task_name]
|
88
|
+
end
|
89
|
+
|
90
|
+
# Defines the clobber task for this task library.
|
91
|
+
def define_clobber
|
92
|
+
desc "Remove #{@name} files"
|
93
|
+
task clobber_task_name do
|
94
|
+
rm_r @build_path rescue nil
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
# Defines the task which creates the build directory if it does not exist.
|
99
|
+
# Automatically a dependency of the task lib's build task.
|
100
|
+
def define_build_directory_task
|
101
|
+
directory @build_path
|
102
|
+
task build_task_name => @build_path
|
103
|
+
end
|
104
|
+
|
105
|
+
# Defines the main build task for this task library.
|
106
|
+
def define_build_task
|
107
|
+
desc "Build the #{@name} files"
|
108
|
+
task build_task_name
|
109
|
+
|
110
|
+
@src_files.each do |src|
|
111
|
+
# Figure our target
|
112
|
+
target = target_for src
|
113
|
+
|
114
|
+
# Process each file
|
115
|
+
file target => [src, @build_path] do
|
116
|
+
do_transformation src, target
|
117
|
+
do_transfer target
|
118
|
+
end
|
119
|
+
|
120
|
+
# Add target as a dependency
|
121
|
+
task build_task_name => target
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
# Adds dependencies for main asset-related tasks in this namespace
|
126
|
+
def add_dependencies_to_main_task
|
127
|
+
desc 'Build all assets' unless task( :build ).comment
|
128
|
+
task :build => build_task_name
|
129
|
+
|
130
|
+
desc 'Clobber all assets' unless task( :clobber ).comment
|
131
|
+
task :clobber => [clobber_task_name]
|
132
|
+
|
133
|
+
desc 'Rebuild all assets' unless task( :rebuild ).comment
|
134
|
+
task :rebuild => [clobber_task_name, build_task_name]
|
135
|
+
end
|
136
|
+
|
137
|
+
protected
|
138
|
+
# Transform a file based on a previously captured block where +src+ is the path to a source file
|
139
|
+
# and +target+ is the build task's target file. Dependent tasks may expect +target+ to exist.
|
140
|
+
def do_transformation src, target
|
141
|
+
@transformation.call src, target
|
142
|
+
end
|
143
|
+
|
144
|
+
# Transfer a file to a remote directory. Supports multiple file transports.
|
145
|
+
def do_transfer target
|
146
|
+
unless @remote_dirs.empty? || ENV['TRANSFER'] == 'no'
|
147
|
+
raise "File #{target} not found!" unless File.exist? target
|
148
|
+
|
149
|
+
@remote_dirs.each do |dir|
|
150
|
+
case dir[:transport]
|
151
|
+
when :ftp
|
152
|
+
do_ftp dir[:host], dir[:user], dir[:password], dir[:path], target
|
153
|
+
when :ssh
|
154
|
+
# TODO: implement me!
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
# Transport a file to a remote directory via FTP.
|
161
|
+
def do_ftp host, user, pwd, path, file
|
162
|
+
require 'net/ftp'
|
163
|
+
Net::FTP.open host, user, pwd do |ftp|
|
164
|
+
ftp.chdir path
|
165
|
+
ftp.putbinaryfile file
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
#--
|
2
|
+
# Jeremy Voorhis
|
3
|
+
# March 2006
|
4
|
+
#++
|
5
|
+
|
6
|
+
require 'rmagick_transformation_script'
|
7
|
+
|
8
|
+
# Task library for managing a directory of images.
|
9
|
+
#
|
10
|
+
# For example:
|
11
|
+
# namespace :assets do
|
12
|
+
# ImageTask.new( :navigation_icons ) do |t|
|
13
|
+
# t.src_files = Rake::FileList[image_src 'navigation_icons/*.jpg']
|
14
|
+
# t.build_path = File.join RAILS_ROOT, 'public/assets/navigation_icons'
|
15
|
+
#
|
16
|
+
# t.transformation do |img|
|
17
|
+
# img.greyscale
|
18
|
+
# img.size_to_fit '64x64'
|
19
|
+
# img.icc_profile icc_profile_path
|
20
|
+
# img.icm_profile icm_profile_path
|
21
|
+
# end
|
22
|
+
# end
|
23
|
+
# end
|
24
|
+
#
|
25
|
+
# This example defines the following tasks:
|
26
|
+
# rake assets:build # Build all assets
|
27
|
+
# rake assets:clobber # Clobber all assets
|
28
|
+
# rake assets:navigation_icons:build # Build the navigation_icons files
|
29
|
+
# rake assets:navigation_icons:clobber # Remove navigation_icons files
|
30
|
+
# rake assets:navigation_icons:rebuild # Force a rebuild of the navigation_icons files
|
31
|
+
# rake assets:rebuild # Rebuild all assets
|
32
|
+
class ImageTask < AssetTask
|
33
|
+
|
34
|
+
protected
|
35
|
+
def do_transformation src, target
|
36
|
+
transformation_script = RMagickTransformationScript.new src, &@transformation
|
37
|
+
transformation_script.write target
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,156 @@
|
|
1
|
+
require 'RMagick'
|
2
|
+
|
3
|
+
# Holds a reference to an instance of <tt>Magick::Image</tt> and manages operations on it. Used
|
4
|
+
# to provide a more consistent, higher-level api than is given by RMagick.
|
5
|
+
#
|
6
|
+
# +ImageTransformationScript+ automatically invokes Ruby's garbage collector by calling <tt>GC.start</tt>
|
7
|
+
# upon instantiating a Magick::Image object. To bypass this, set the +GC+ environment variable to 'no'.
|
8
|
+
class RMagickTransformationScript
|
9
|
+
|
10
|
+
GRAVITY_TYPES = {
|
11
|
+
:none => Magick::ForgetGravity,
|
12
|
+
:northwest => Magick::NorthWestGravity,
|
13
|
+
:north => Magick::NorthGravity,
|
14
|
+
:northeast => Magick::NorthEastGravity,
|
15
|
+
:west => Magick::WestGravity,
|
16
|
+
:center => Magick::CenterGravity,
|
17
|
+
:east => Magick::EastGravity,
|
18
|
+
:southwest => Magick::SouthWestGravity,
|
19
|
+
:south => Magick::SouthGravity,
|
20
|
+
:southeast => Magick::SouthEastGravity
|
21
|
+
}
|
22
|
+
|
23
|
+
# Initialize an <tt>ImageTransformationScript</tt> where +img+ is either a path to an image or
|
24
|
+
# an instance of <tt>Magick::Image</tt>.
|
25
|
+
def initialize img, &block
|
26
|
+
@image = img if img.is_a? Magick::Image
|
27
|
+
@image = read img if img.is_a? String
|
28
|
+
raise ArgumentError.new( 'img must be either a path to an image or a Magick::Image object' ) \
|
29
|
+
unless @image
|
30
|
+
|
31
|
+
instance_eval &block
|
32
|
+
|
33
|
+
GC.start unless ENV['GC'] == 'no'
|
34
|
+
end
|
35
|
+
|
36
|
+
# Read an image from a file specified by +src+ and return a <tt>Magick::Image</tt> instance.
|
37
|
+
def read src
|
38
|
+
Magick::Image.read( src ).first
|
39
|
+
end
|
40
|
+
|
41
|
+
# Write the image to a specified path, <tt>target</tt>.
|
42
|
+
def write target
|
43
|
+
@image.write target do
|
44
|
+
quality = 95
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# Tints the image according to the following parameters:
|
49
|
+
# * <tt>r</tt> Blending factor for the red channel
|
50
|
+
# * <tt>g</tt> Blending factor for the green channel
|
51
|
+
# * <tt>b</tt> Blending factor for the blue channel
|
52
|
+
# * <tt>overlay</tt> Color to tint the image
|
53
|
+
# img.tint 0.25, 0.25, 0.25, #ffffff # lightens the image 25%
|
54
|
+
def tint r, g, b, overlay
|
55
|
+
@image = @image.colorize r, g, b, overlay
|
56
|
+
@image
|
57
|
+
end
|
58
|
+
|
59
|
+
# Sharpen only the edges of the image. Parameters are:
|
60
|
+
# * <tt>rad</tt> Radius: how big an edge can be
|
61
|
+
# * <tt>sig</tt> Sigma weight for gaussian: leave it at 1.0.
|
62
|
+
# * <tt>blend</tt> Blending factor: how much sharpening to apply as a percentage
|
63
|
+
# * <tt>thresh</tt> Threshold: how different 2 pixels must be to qualify as an edge
|
64
|
+
# img.unsharp_mask 0.5, 1.0, 0.5, 0.25
|
65
|
+
def unsharp_mask rad = 0.5, sig = 1.0, blend = 0.5, thresh = 0.25
|
66
|
+
@image = @image.unsharp_mask rad, sig, blend, thresh
|
67
|
+
@image
|
68
|
+
end
|
69
|
+
|
70
|
+
# Lightens the image. Defaults to a blend factor of 25%.
|
71
|
+
# img.lighten # lightens the image 25%.
|
72
|
+
# img.lighten 0.40 # lightens the image 40%.
|
73
|
+
def lighten factor = 0.25
|
74
|
+
tint factor, factor, factor, '#ffffff'
|
75
|
+
end
|
76
|
+
|
77
|
+
# Darkens the image. Defaults to a blend factor of 25%.
|
78
|
+
# img.darken # darkens the image 25%.
|
79
|
+
# img.darken 0.40 # darkens the image 40%.
|
80
|
+
def darken factor = 0.25
|
81
|
+
tint factor, factor, factor, '#000000'
|
82
|
+
end
|
83
|
+
|
84
|
+
# Converts the image to greyscale.
|
85
|
+
# img.greyscale # uses default overlay of #aa9955.
|
86
|
+
# img.greyscale '#aaaaaa' # uses specified overlay.
|
87
|
+
def greyscale overlay = '#aa9955'
|
88
|
+
@image = @image.quantize 256, Magick::GRAYColorspace
|
89
|
+
tint 0.25, 0.25, 0.25, overlay
|
90
|
+
@image
|
91
|
+
end
|
92
|
+
|
93
|
+
# Resizes the image to fit within the constraints specified by +dimensions+ where +dimensions+ is
|
94
|
+
# a +String+ in the format of 'WIDTHxLENGTH'.
|
95
|
+
# img.size_to_fit '64x64'
|
96
|
+
def size_to_fit dimensions
|
97
|
+
@image.change_geometry dimensions do |w,h,img|
|
98
|
+
img.density = '72x72'
|
99
|
+
img.resize! w, h
|
100
|
+
# radius, sigma, blend, threshold
|
101
|
+
unsharp_mask 0.5, 1.0, 0.5, 0.25
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
# Resizes the image proportionally to fit the smaller dimension, then crops excess.
|
106
|
+
# Optionally, a gravity setting may be provided. From the RMagick docs:
|
107
|
+
#
|
108
|
+
# Gravity provides a convenient way to locate objects irrespective of the size of the
|
109
|
+
# bounding region, in other words, you don't need to provide absolute coordinates in
|
110
|
+
# order to position an object.
|
111
|
+
#
|
112
|
+
# The default gravity setting is <tt>:center</tt>. Available settings are:
|
113
|
+
# [<tt>:none</tt>] don't use gravity
|
114
|
+
# [<tt>:northwest</tt>] crop to northwest
|
115
|
+
# [<tt>:north</tt>] crop to north - good for vertical images
|
116
|
+
# [<tt>:northeast</tt>] crop to northeast
|
117
|
+
# [<tt>:west</tt>] crop to west
|
118
|
+
# [<tt>:center</tt>] crop to center - default
|
119
|
+
# [<tt>:east</tt>] crop to east
|
120
|
+
# [<tt>:southwest</tt>] crop to southwest
|
121
|
+
# [<tt>:south</tt>] crop to south
|
122
|
+
# [<tt>:southeast</tt>] crop to southeast
|
123
|
+
#
|
124
|
+
# Usage:
|
125
|
+
# img.crop_to '64x64' # crops to center, 64x64 pixels
|
126
|
+
# img.crop_to '64x64', :north # crops to north - common for thumbnailing portraits
|
127
|
+
def crop_to size_string, gravity = :center
|
128
|
+
width, height = size_string.scan( /\d+/ ).collect { |i| i.to_i }
|
129
|
+
max = ( width > height ? width : height )
|
130
|
+
aspect = @image.columns.to_f / @image.rows.to_f
|
131
|
+
@image.resize!( max, ( max / aspect ).to_i ) if aspect < 1.0
|
132
|
+
@image.resize!( (max*aspect).to_i, max ) unless aspect < 1.0
|
133
|
+
# radius, sigma, blend, threshold
|
134
|
+
unsharp_mask 0.5, 1.0, 0.5, 0.25
|
135
|
+
@image.crop!( GRAVITY_TYPES[gravity], width, height )
|
136
|
+
@image
|
137
|
+
end
|
138
|
+
|
139
|
+
# Applies an ICC profile to the image. Requires +path+ which is a path to a file containing
|
140
|
+
# a valid ICC profile.
|
141
|
+
# img.icc_profile 'srgb.icc'
|
142
|
+
def icc_profile path
|
143
|
+
profile = File.open( path ).readlines.join( '' ) if File.exist? path
|
144
|
+
@image.profile! 'ICC', profile if profile
|
145
|
+
@image
|
146
|
+
end
|
147
|
+
|
148
|
+
# Applies an ICM profile to the image. Requires +path+ which is a path to a file containing
|
149
|
+
# a valid ICM profile.
|
150
|
+
# img.icm_profile 'srgb.icm'
|
151
|
+
def icm_profile path
|
152
|
+
profile = File.open( path ).readlines.join('') if File.exist? path
|
153
|
+
@image.profile! 'ICM', profile if profile
|
154
|
+
@image
|
155
|
+
end
|
156
|
+
end
|
metadata
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
rubygems_version: 0.8.10
|
3
|
+
specification_version: 1
|
4
|
+
name: asset_compiler
|
5
|
+
version: !ruby/object:Gem::Version
|
6
|
+
version: "0.2"
|
7
|
+
date: 2006-05-08
|
8
|
+
summary: Rake task libraries for managing assets. Especially images.
|
9
|
+
require_paths:
|
10
|
+
- lib
|
11
|
+
email: jeremy@planetargon.com
|
12
|
+
homepage:
|
13
|
+
rubyforge_project:
|
14
|
+
description: "Asset Compiler is a collection of Rake task libraries to lighten the load of
|
15
|
+
asset management. These libraries allow you to manage local assets, manipulate
|
16
|
+
images and transport assets to a remote server."
|
17
|
+
autorequire: asset_compiler
|
18
|
+
default_executable:
|
19
|
+
bindir: bin
|
20
|
+
has_rdoc: true
|
21
|
+
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
22
|
+
requirements:
|
23
|
+
-
|
24
|
+
- ">"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 0.0.0
|
27
|
+
version:
|
28
|
+
platform: ruby
|
29
|
+
authors:
|
30
|
+
- Jeremy Voorhis
|
31
|
+
files:
|
32
|
+
- lib/asset_compiler.rb
|
33
|
+
- lib/asset_compiler/asset_task.rb
|
34
|
+
- lib/asset_compiler/image_task.rb
|
35
|
+
- lib/asset_compiler/rmagick_transformation_script.rb
|
36
|
+
test_files: []
|
37
|
+
rdoc_options: []
|
38
|
+
extra_rdoc_files: []
|
39
|
+
executables: []
|
40
|
+
extensions: []
|
41
|
+
requirements:
|
42
|
+
- "RMagick, built with lcms"
|
43
|
+
dependencies:
|
44
|
+
- !ruby/object:Gem::Dependency
|
45
|
+
name: rake
|
46
|
+
version_requirement:
|
47
|
+
version_requirements: !ruby/object:Gem::Version::Requirement
|
48
|
+
requirements:
|
49
|
+
-
|
50
|
+
- ">="
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: 0.7.0
|
53
|
+
version:
|