magick_title 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,6 @@
1
+ *.gem
2
+ .bundle
3
+ .DS_Store
4
+ Gemfile.lock
5
+ pkg/*
6
+ test/dummy/public/system
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in magick_title.gemspec
4
+ gemspec
data/README.md ADDED
@@ -0,0 +1,49 @@
1
+ Magick Title
2
+ ============
3
+
4
+ Want beautiful browser-compatible custom-smoothed & kerned fonts? Magick Title delivers just that by using imagemagick to generate titles based on the options you provide.
5
+
6
+ ** ----- under construction! ----- **
7
+
8
+ Usage
9
+ -----
10
+
11
+ Using MagickTitle is easy:
12
+
13
+ MagickTitle.say("Hello!").to_html
14
+
15
+ # outputs
16
+ # <h1><img src="/system/titles/hello.png" alt="Bienvenida al mundo de 28 Buenos Días " class="magick-title"></h1>
17
+
18
+ Without the h1 tag:
19
+
20
+ MagickTitle.say("Hello!").to_html(false)
21
+
22
+ # outputs
23
+ # <img src="/system/titles/hello.png" alt="Bienvenida al mundo de 28 Buenos Días " class="magick-title">
24
+
25
+
26
+ To just get an instance of MagickTitle::Image:
27
+
28
+ title = MagickTitle.say("Hello!")
29
+
30
+ puts title.filename #=> "hello.png"
31
+ puts title.url #=> "/system/titles/hello.png"
32
+
33
+
34
+ More to come!
35
+
36
+
37
+ To Do
38
+ -----
39
+
40
+ * Write tests
41
+ * Write documentation
42
+ * Auto ActiveRecord integration (this will be a seperate HasImage gem)
43
+ * Clean up and publish demo app
44
+
45
+
46
+ License
47
+ -------
48
+
49
+ Copyright (c) 2011 Spencer Steffen, released under the New BSD License All rights reserved.
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ require 'bundler'
2
+ require 'rake/testtask'
3
+
4
+ Bundler::GemHelper.install_tasks
5
+
6
+ Rake::TestTask.new(:test) do |t|
7
+ t.libs << 'test' << 'lib'
8
+ t.verbose = true
9
+ end
10
+
11
+ desc "Default Task"
12
+ task :default => [ :test ]
@@ -0,0 +1,17 @@
1
+ class Hash
2
+ # Stolen from rails
3
+ def symbolize_keys
4
+ self.inject({}){|result, (key, value)|
5
+ new_key = case key
6
+ when String then key.to_sym
7
+ else key
8
+ end
9
+ new_value = case value
10
+ when Hash then value.symbolize_keys
11
+ else value
12
+ end
13
+ result[new_key] = new_value
14
+ result
15
+ }
16
+ end
17
+ end
@@ -0,0 +1,169 @@
1
+ require 'fileutils' unless defined?(FileUtils)
2
+
3
+ module MagickTitle
4
+
5
+ class Image
6
+
7
+ # The hash of options used for building
8
+ attr_accessor :text
9
+
10
+ # The hash of options used for building
11
+ # This hash is subclassed as Options and has some fancy features
12
+ attr_accessor :options
13
+
14
+ # File path to destination folder
15
+ attr_accessor :path
16
+
17
+ # Returns the filename of the title
18
+ attr_reader :filename
19
+
20
+ # Relative url to the image
21
+ attr_reader :url
22
+
23
+
24
+ # Initializes a new image title with a string
25
+ def initialize(text="", opts={})
26
+ update(text, opts)
27
+ super
28
+ end
29
+
30
+
31
+ # updates the image title to reflect new text
32
+ def update(text, opts={})
33
+ @text = text
34
+ return false unless valid?
35
+ @options = (@options || MagickTitle.options).merge(opts.symbolize_keys)
36
+ @filename = unique_filename(@text)
37
+ @path = options.destination
38
+ @url = File.join((@path.match(/public(\/.*)/) || ['', './'])[1].to_s, @filename)
39
+ end
40
+
41
+
42
+
43
+ # saves title and generates image
44
+ def save
45
+ return false unless valid?
46
+ FileUtils.mkdir_p(path)
47
+ run('convert', title_command_string)
48
+ File.exists?(fullpath)
49
+ end
50
+
51
+
52
+ # Checks if the image title is valid
53
+ def valid?
54
+ 1 < @text.strip.length
55
+ end
56
+
57
+
58
+ # Returns the full path to the file
59
+ def fullpath
60
+ File.join(path, filename)
61
+ end
62
+
63
+
64
+
65
+ def to_html(opts={})
66
+ opts = { :parent => nil } if opts === false
67
+ opts = {
68
+ :parent => {
69
+ :tag => "h1",
70
+ :class => "image-title"
71
+ },
72
+ :class => "magick-title",
73
+ :alt => text,
74
+ :src => url
75
+ }.merge(opts)
76
+ parent = opts.delete(:parent)
77
+ parent = { :tag => parent } if parent.is_a?(String)
78
+ tag = %(<img #{hash_to_attributes(opts)}/>)
79
+ if parent
80
+ ptag = parent.delete(:tag)
81
+ tag = %(<#{ptag} #{hash_to_attributes(parent)}>#{tag}</#{ptag}>)
82
+ end
83
+ tag
84
+ end
85
+
86
+ def hash_to_attributes(hash)
87
+ attributes = ""
88
+ hash.each { |key, value| attributes << key.to_s << "=\"" << value << "\" " if value and 0 < value.length }
89
+
90
+ puts "* 88"
91
+ puts attributes.inspect
92
+
93
+ attributes
94
+ end
95
+
96
+
97
+ private
98
+
99
+
100
+ # builds an imagemagick identify command to the specified fild
101
+ def info_command_string(file)
102
+ "-format '%b,%w,%h' #{file}"
103
+ end
104
+
105
+ # builds an imagemagick command based on the supplied options
106
+ def title_command_string
107
+ %(
108
+ -trim
109
+ -antialias
110
+ -background '#{options.background_color}#{options.background_alpha}'
111
+ -fill '#{options.color}'
112
+ -font #{options.font_path}/#{options.font}
113
+ -pointsize #{options.font_size}
114
+ -size #{options.width}x#{options.height}
115
+ -weight #{options.weight}
116
+ -kerning #{options.kerning}
117
+ caption:'#{@text}'
118
+ #{fullpath}
119
+ ).gsub(/[\n\r\s]+/, ' ')
120
+ end
121
+
122
+ # Cleans and runs the supplied command
123
+ # (stolen from paperclip)
124
+ def run(cmd, params)
125
+ command = [path_for_command(cmd), params.to_s.gsub(/\\|\n|\r/, '')].join(" ")
126
+ puts command if options.log_command
127
+ `#{command}`
128
+ end
129
+
130
+ # returns the `bin` path to the command
131
+ def path_for_command(command)
132
+ path = [options.command_path, command].compact
133
+ File.join(*path)
134
+ end
135
+
136
+ # converts the text to a useable filename
137
+ # defaults to a random string if the filename is blank after replacing illegal chars
138
+ def fileize_text(text)
139
+ file = text.to_s.downcase.gsub(/[^a-z0-9\s\-\_]/, '').strip.gsub(/[\s\-\_]+/, '_')
140
+ unless 0 < file.length
141
+ o = [('a'..'z'),('0'..'9')].map{|i| i.to_a}.flatten
142
+ file = (0..31).map{ o[rand(o.length)] }.join
143
+ end
144
+ file
145
+ end
146
+
147
+
148
+ # creates a unique filename for the supplied text
149
+ def unique_filename(text)
150
+ file = fileize_text(text)
151
+ exists = exists_in_destination? file
152
+ dupe, count = nil, 0
153
+ while exists do
154
+ count += 1
155
+ dupe = "#{file}_#{count}"
156
+ exists = exists_in_destination? dupe
157
+ end
158
+ "#{dupe || file}.#{options.extension}"
159
+ end
160
+
161
+ # Checks if file exists in the destination option
162
+ def exists_in_destination?(file)
163
+ file += options.extension unless file.match(/\.[a-z]{3,4}$/)
164
+ File.exists?(File.join(options.destination, file))
165
+ end
166
+
167
+ end # Image
168
+
169
+ end # MagickTitle
@@ -0,0 +1,72 @@
1
+ module MagickTitle
2
+
3
+ class Options < Hash
4
+
5
+ # Initializes the options hash with the defaults
6
+ def initialize
7
+ super
8
+ default!
9
+ end
10
+
11
+ # Clears current options and resets to the defaults
12
+ def default!
13
+ clear
14
+ store :root, defined?(::Rails) ? ::Rails.root.to_s : "./"
15
+ merge! defaults
16
+ end
17
+
18
+ # A shortcut to [:root]
19
+ def root
20
+ @root ||= fetch(:root)
21
+ end
22
+
23
+ # The default options hash
24
+ def defaults
25
+ {
26
+ :root => "./",
27
+ :field_name => 'title',
28
+ :font => "HelveticaNeueLTStd-UltLt.otf",
29
+ :font_path => Proc.new{ File.join MagickTitle.root, "fonts" },
30
+ :font_size => 50,
31
+ :destination => Proc.new{ File.join MagickTitle.root, "public/system/titles" },
32
+ :extension => "png",
33
+ :width => 800,
34
+ :height => nil,
35
+ :background_color => '#ffffff',
36
+ :background_alpha => '00',
37
+ :color => '#68962c',
38
+ :weight => 400,
39
+ :kerning => 0,
40
+ :command_path => nil,
41
+ :log_command => false,
42
+ :cache => true
43
+ }
44
+ end
45
+
46
+ # Sets and option and converts its key to a symbol
47
+ def []=(key, value)
48
+ key = key.to_sym
49
+ raise ArgumentError, "MagickTitle::InvalidOption: #{key} is not an available option." unless defaults.keys.include?(key)
50
+ super(key, value)
51
+ end
52
+
53
+ # Turns the key into a symbol and returns the requested value
54
+ def [](key)
55
+ val = fetch key.to_sym
56
+ val.is_a?(Proc) ? val.call : val
57
+ end
58
+
59
+ # Retrieve a saved setting or return nil if it doesn't exist.
60
+ #
61
+ # Options.foo #=> "bar"
62
+ # Options.fuz #=> method missing error
63
+ #
64
+ def method_missing(method, *args, &block)
65
+ key = method.to_sym
66
+ val = fetch(key) # if has_key? key
67
+ val.nil? ? nil : val.is_a?(Proc) ? val.call : val
68
+ end
69
+
70
+ end
71
+
72
+ end
@@ -0,0 +1,3 @@
1
+ module MagickTitle
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,40 @@
1
+ require 'magick_title/hash'
2
+ require 'magick_title/options'
3
+ require 'magick_title/image'
4
+
5
+ module MagickTitle
6
+
7
+ extend self
8
+
9
+ # A shortcut to options[:root]
10
+ def root
11
+ options.root
12
+ end
13
+
14
+ # Returns the options hash
15
+ def options
16
+ @options ||= Options.new
17
+ end
18
+
19
+ # Sets the options hash
20
+ def options=(value)
21
+ raise ArgumentError, "Magick Title options must be a Hash" unless value.is_a?(Hash)
22
+ value.each_pair do |key, value|
23
+ options[key] = value
24
+ end
25
+ options
26
+ end
27
+
28
+ # A helper tag to create or fetch and image title
29
+ #
30
+ # MagickTitle.image("Hello!")
31
+ # MagickTitle.say("Hi", :refresh => true)
32
+ #
33
+ def image(text, opts={})
34
+ title = ::MagickTitle::Image.new(text, opts)
35
+ title.save unless title.options.cache && File.exists?(title.fullpath)
36
+ title
37
+ end
38
+ alias :say :image
39
+
40
+ end # MagickTitle
@@ -0,0 +1,26 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "magick_title/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "magick_title"
7
+ s.version = MagickTitle::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Spencer Steffen"]
10
+ s.email = ["spencer@citrusme.com"]
11
+ s.homepage = "https://github.com/citrus/magick_title"
12
+ s.summary = %q{Converts text to an image using imagemagick.}
13
+ s.description = %q{Want beautiful browser-compatible custom-smoothed & kerned fonts? Magick Title delivers just that by using imagemagick to generate titles based on the options you provide.}
14
+
15
+ s.rubyforge_project = "magick_title"
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.require_paths = ["lib"]
21
+
22
+ s.add_development_dependency 'shoulda', '2.11.3'
23
+ s.add_development_dependency 'rack-test', '0.5.7'
24
+ s.add_development_dependency 'sinatra', '1.1.0'
25
+
26
+ end
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ gem "sinatra"
4
+ gem "magick_title", :path => File.expand_path("../../../", __FILE__)
data/test/dummy/app.rb ADDED
@@ -0,0 +1,18 @@
1
+ require 'bundler/setup'
2
+ Bundler.require if defined?(Bundler)
3
+
4
+
5
+ MagickTitle.options = { :font_size => 56 }
6
+
7
+
8
+ use Rack::Static
9
+
10
+ get '/' do
11
+ erb :index
12
+ end
13
+
14
+ post '/' do
15
+ @image_title = MagickTitle::Image.new(params[:text], params[:options])
16
+ @success = @image_title.save
17
+ erb :index
18
+ end
Binary file
@@ -0,0 +1,31 @@
1
+ body {
2
+ font-family: "HelveticaNeue", Helvetica, Arial, sans-serif;
3
+ color: #080603;
4
+ }
5
+ a {
6
+ text-decoration: none;
7
+ color: #68962c;
8
+ }
9
+ .container {
10
+ width: 500px;
11
+ margin: 0 auto;
12
+ }
13
+ .header {
14
+ border-bottom: 1px solid #ddd;
15
+ }
16
+ .header a {
17
+ display: inline-block;
18
+ padding: 4px 10px;
19
+ background-color: #eee;
20
+ }
21
+
22
+ .flash {
23
+ padding: 10px 0;
24
+ border-bottom: 1px solid #ddd;
25
+ }
26
+ .flash.notice {
27
+ color: #68962c;
28
+ }
29
+ .flash.error {
30
+ color: #c00e0e;
31
+ }
@@ -0,0 +1,42 @@
1
+ <% if @success && @image_title %>
2
+ <h1>Success!</h1>
3
+ <img src=<%= @image_title.url.inspect %> alt=<%= @image_title.text.inspect %>/>
4
+ <% elsif @success === false %>
5
+ <h1>Failed.</h1>
6
+ <% else %>
7
+ <%= MagickTitle.say("Hello!").to_html %>
8
+ <h2><%= MagickTitle.say("Welcome to MagickTitle!", :cache => false, :font => 'PermanentMarker.ttf', :font_size => 20, :color => '#999').to_html(false) %></h2>
9
+ <% end %>
10
+
11
+
12
+ <h2>Generate an image title!</h2>
13
+
14
+ <form action="/" method="post">
15
+ <p>
16
+ <label for="text">Text:</label>
17
+ <input type="text" name="text" id="name"/>
18
+ </p>
19
+ <p>
20
+ <label for="options_font">Font:</label>
21
+ <select name="options[font]" id="options_font">
22
+ <option value="Cuprum.ttf">Cuprum</option>
23
+ <option value="HelveticaNeueLTStd-UltLt.otf">Helvetica Neue Ultra Light</option>
24
+ <option value="PermanentMarker.ttf">Permanent Marker</option>
25
+
26
+ </select>
27
+ </p>
28
+
29
+ <p>
30
+ <label for="options_color">Color:</label>
31
+ <select name="options[color]" id="options_color">
32
+ <option value="#ff0000">Red</option>
33
+ <option value="#0000ff">Blue</option>
34
+ <option value="#000000">Black</option>
35
+ <option value="#00ff00">Green</option>
36
+ </select>
37
+ </p>
38
+
39
+ <p>
40
+ <input type="submit" value="generate"/>
41
+ </p>
42
+ </form>
@@ -0,0 +1,16 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Magick Title Demo</title>
5
+ <link rel="stylesheet" type="text/css" href="styles.css" />
6
+ </head>
7
+ <body>
8
+
9
+ <div class="container">
10
+
11
+ <%= yield %>
12
+
13
+ </div>
14
+
15
+ </body>
16
+ </html>
data/test/helper.rb ADDED
@@ -0,0 +1,6 @@
1
+ ENV["environment"] = "test"
2
+
3
+ require 'test/unit'
4
+ #require 'rack/test'
5
+ require 'shoulda'
6
+ require 'magick_title'
@@ -0,0 +1,28 @@
1
+ require 'helper'
2
+
3
+ class TestImage < Test::Unit::TestCase
4
+
5
+ def setup
6
+ MagickTitle.options[:root] = File.expand_path("../dummy", __FILE__)
7
+ end
8
+
9
+ context "a valid title" do
10
+
11
+ setup do
12
+ @title = MagickTitle.say("hello!")
13
+ end
14
+
15
+ should "return an image title" do
16
+ assert @title.is_a?(MagickTitle::Image)
17
+ assert File.exists?(@title.fullpath)
18
+ end
19
+
20
+ should "create an html img tag" do
21
+ tag = @title.to_html
22
+ assert tag.is_a?(String)
23
+ assert tag.match("src=#{@title.url.inspect}")
24
+ assert tag.match("alt=#{@title.text.inspect}")
25
+ end
26
+
27
+ end
28
+ end
@@ -0,0 +1,34 @@
1
+ require 'helper'
2
+
3
+ class TestImage < Test::Unit::TestCase
4
+
5
+ def setup
6
+ MagickTitle.options[:root] = File.expand_path("../dummy", __FILE__)
7
+ end
8
+
9
+
10
+ should "not allow empty string" do
11
+ @title = MagickTitle::Image.new("")
12
+ assert !@title.valid?
13
+ assert !@title.save
14
+ end
15
+
16
+
17
+ context "a valid image title" do
18
+
19
+ setup do
20
+ @title = MagickTitle::Image.new("hello")
21
+ end
22
+
23
+ should "allow valid string" do
24
+ assert @title.valid?
25
+ end
26
+
27
+ should "save a valid title" do
28
+ assert @title.save
29
+ assert File.exists?(@title.fullpath)
30
+ end
31
+
32
+ end
33
+
34
+ end
metadata ADDED
@@ -0,0 +1,119 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: magick_title
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.1.0
6
+ platform: ruby
7
+ authors:
8
+ - Spencer Steffen
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2011-02-24 00:00:00 -08:00
14
+ default_executable:
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: shoulda
18
+ prerelease: false
19
+ requirement: &id001 !ruby/object:Gem::Requirement
20
+ none: false
21
+ requirements:
22
+ - - "="
23
+ - !ruby/object:Gem::Version
24
+ version: 2.11.3
25
+ type: :development
26
+ version_requirements: *id001
27
+ - !ruby/object:Gem::Dependency
28
+ name: rack-test
29
+ prerelease: false
30
+ requirement: &id002 !ruby/object:Gem::Requirement
31
+ none: false
32
+ requirements:
33
+ - - "="
34
+ - !ruby/object:Gem::Version
35
+ version: 0.5.7
36
+ type: :development
37
+ version_requirements: *id002
38
+ - !ruby/object:Gem::Dependency
39
+ name: sinatra
40
+ prerelease: false
41
+ requirement: &id003 !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - "="
45
+ - !ruby/object:Gem::Version
46
+ version: 1.1.0
47
+ type: :development
48
+ version_requirements: *id003
49
+ description: Want beautiful browser-compatible custom-smoothed & kerned fonts? Magick Title delivers just that by using imagemagick to generate titles based on the options you provide.
50
+ email:
51
+ - spencer@citrusme.com
52
+ executables: []
53
+
54
+ extensions: []
55
+
56
+ extra_rdoc_files: []
57
+
58
+ files:
59
+ - .gitignore
60
+ - Gemfile
61
+ - README.md
62
+ - Rakefile
63
+ - lib/magick_title.rb
64
+ - lib/magick_title/hash.rb
65
+ - lib/magick_title/image.rb
66
+ - lib/magick_title/options.rb
67
+ - lib/magick_title/version.rb
68
+ - magick_title.gemspec
69
+ - test/dummy/Gemfile
70
+ - test/dummy/app.rb
71
+ - test/dummy/fonts/Cuprum.ttf
72
+ - test/dummy/fonts/HelveticaNeueLTStd-UltLt.otf
73
+ - test/dummy/fonts/PermanentMarker.ttf
74
+ - test/dummy/public/styles.css
75
+ - test/dummy/views/index.erb
76
+ - test/dummy/views/layout.erb
77
+ - test/helper.rb
78
+ - test/test_image_title.rb
79
+ - test/test_magick_title.rb
80
+ has_rdoc: true
81
+ homepage: https://github.com/citrus/magick_title
82
+ licenses: []
83
+
84
+ post_install_message:
85
+ rdoc_options: []
86
+
87
+ require_paths:
88
+ - lib
89
+ required_ruby_version: !ruby/object:Gem::Requirement
90
+ none: false
91
+ requirements:
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ version: "0"
95
+ required_rubygems_version: !ruby/object:Gem::Requirement
96
+ none: false
97
+ requirements:
98
+ - - ">="
99
+ - !ruby/object:Gem::Version
100
+ version: "0"
101
+ requirements: []
102
+
103
+ rubyforge_project: magick_title
104
+ rubygems_version: 1.5.0
105
+ signing_key:
106
+ specification_version: 3
107
+ summary: Converts text to an image using imagemagick.
108
+ test_files:
109
+ - test/dummy/Gemfile
110
+ - test/dummy/app.rb
111
+ - test/dummy/fonts/Cuprum.ttf
112
+ - test/dummy/fonts/HelveticaNeueLTStd-UltLt.otf
113
+ - test/dummy/fonts/PermanentMarker.ttf
114
+ - test/dummy/public/styles.css
115
+ - test/dummy/views/index.erb
116
+ - test/dummy/views/layout.erb
117
+ - test/helper.rb
118
+ - test/test_image_title.rb
119
+ - test/test_magick_title.rb