Skip to content

Instantly share code, notes, and snippets.

@mbleigh
Created November 15, 2009 14:22
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mbleigh/235251 to your computer and use it in GitHub Desktop.
Save mbleigh/235251 to your computer and use it in GitHub Desktop.
module Rack
class Pictopus
def initialize(app, output_path)
@app = app
@root = ::File.expand_path(output_path)
raise ArgumentError, "#{output_path} is not a directory." unless ::File.directory?(@root)
end
def call(env)
unless env["PATH_INFO"] =~ /.*\/images\/pictopus\/.*\/.*/
return @app.call(env)
end
request = ::Rack::Request.new(env)
kind, command = env["PATH_INFO"].match(/images\/pictopus\/(.*)\/(.*)/i)[1..-1]
if ::File.exist?(@root + env["PATH_INFO"])
return ::Rack::File.new(@root).call(env)
end
case kind
when "gradient"
opts = {
:output_path => @root
}
opts[:start_color], opts[:end_color], opts[:orientation], opts[:size], opts[:format] = command.split('.')
::Pictopus::Gradient.new(opts).run!
# Redirect to this URL since it will now be served.
[301, {'Location' => request.url}, 'Redirecting to created image.']
end
end
end
end
module Pictopus
class CommandLineError < StandardError; end
class << self
def default_options
@options ||= {
:command_path => nil,
:log => true,
:swallow_stderr => true,
:log_command => true
}
end
def run(cmd, params="", options = {})
options[:expected_outcodes] ||= 0
command = %Q[#{path_for_command(cmd)} #{params}].gsub(/\s+/, " ")
command = "#{command} 2>#{bit_bucket}" if Pictopus.default_options[:swallow_stderr]
#Rails.logger.info(command) if Pictopus.default_options[:log_command]
puts command
output = system(command)
unless Array(options[:expected_outcodes]).include?($?.exitstatus)
raise Pictopus::CommandLineError, "Error while running #{cmd}"
end
end
def path_for_command(command)
path = [default_options[:command_path], command].compact!
File.join(*path)
end
def bit_bucket #:nodoc:
File.exists?("/dev/null") ? "/dev/null" : "NUL"
end
end
end
module Pictopus
class Gradient
OPTION_KEYS = [:start_color, :end_color, :orientation, :size, :format]
# Provide some default options for
# generating gradients. You shouldn't
# ever really see this unless you're
# hacking on something custom.
def self.default_options
@options ||= {
:size => '100x100',
:format => 'png',
:orientation => 'vertical',
:start_color => 'fff',
:end_color => '000'
}
end
# Create a new Gradient object and provide
# options. The available options are enumerated
# in OPTION_KEYS.
def initialize(options = {})
@options = self.class.default_options.merge(options)
end
# Convert this object to a string of command line arguments
# acceptable by ImageMagick.
def to_args
args = []
args << "-size #{parse_size(size)}"
args << "gradient:#{parse_color(start_color)}-#{parse_color(end_color)}"
args << "-rotate -90" if horizontal?
args << File.join(output_directory, file_name)
args.join(' ')
end
# Run the actual command to generate the image
# for this instance.
def run!
FileUtils.mkdir_p(output_directory) unless File.directory?(File.dirname(output_directory))
Pictopus.run('convert', self.to_args)
end
OPTION_KEYS.each do |opt|
class_eval <<-RUBY
def #{opt}
@options[#{opt.inspect}]
end
def #{opt}=(value)
@options[#{opt.inspect}] = value
end
RUBY
end
# True if the image is set to be a vertical gradient.
def vertical?
%w(v vertical).include?(orientation)
end
# True if the image is set to be a horizontal gradient.
def horizontal?
%w(h horizontal).include?(orientation)
end
def output_directory # :nodoc:
File.join(@options[:output_path], 'images', 'pictopus', 'gradient')
end
def file_name # :nodoc:
[start_color, end_color, orientation, size, format].join('.')
end
protected
def parse_color(color_string)
if color_string =~ /[0-9a-f]{3}/i ||
color_string =~ /[0-9a-f]{6}/i ||
color_string =~ /[0-9a-f]{8}/i
"##{color_string}".downcase
end
end
def parse_size(size_string)
dimensions = size_string.split('x')
case dimensions.size
when 2
dimensions.reverse! if horizontal?
when 1
dimensions.unshift('1')
end
dimensions.join('x')
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment