mapel 0.1.5

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.
@@ -0,0 +1,3 @@
1
+ /nbproject
2
+ /pkg
3
+ /rdoc
@@ -0,0 +1,21 @@
1
+ == Mapel: A dead-simple image-rendering DSL
2
+
3
+ <tt>Mapel</tt> is a dead-simple, chainable image-rendering DSL for ImageMagick.
4
+ Still very much an experiment-in-progress, it supports a dozen or so essential
5
+ commands.
6
+
7
+ Example:
8
+
9
+ Mapel.render('image.jpg').resize("50%").to('output.jpg').run
10
+
11
+ == Fun Fact
12
+
13
+ <tt>Mapel</tt> is named after a tortoiseshell cat.
14
+
15
+ == Meta
16
+
17
+ Written by Aleks Williams (http://github.com/akdubya)
18
+
19
+ Released under the MIT License: www.opensource.org/licenses/mit-license.php
20
+
21
+ github.com/akdubya/mapel
@@ -0,0 +1,54 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ name = 'mapel'
5
+ version = '0.1.5'
6
+
7
+ begin
8
+ require 'jeweler'
9
+ Jeweler::Tasks.new do |gem|
10
+ gem.name = name
11
+ gem.version = version
12
+ gem.summary = %Q{A dead-simple image rendering DSL.}
13
+ gem.email = "alekswilliams@earthlink.net"
14
+ gem.homepage = "http://github.com/akdubya/mapel"
15
+ gem.authors = ["Aleksander Williams"]
16
+ gem.add_development_dependency "bacon", ">= 0"
17
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
18
+ end
19
+ Jeweler::GemcutterTasks.new
20
+ rescue LoadError
21
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
22
+ end
23
+
24
+ require 'rake/testtask'
25
+ Rake::TestTask.new(:spec) do |spec|
26
+ spec.libs << 'lib' << 'spec'
27
+ spec.pattern = 'spec/**/*_spec.rb'
28
+ spec.verbose = true
29
+ end
30
+
31
+ begin
32
+ require 'rcov/rcovtask'
33
+ Rcov::RcovTask.new do |spec|
34
+ spec.libs << 'spec'
35
+ spec.pattern = 'spec/**/*_spec.rb'
36
+ spec.verbose = true
37
+ end
38
+ rescue LoadError
39
+ task :rcov do
40
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
41
+ end
42
+ end
43
+
44
+ task :spec => :check_dependencies
45
+
46
+ task :default => :spec
47
+
48
+ require 'rake/rdoctask'
49
+ Rake::RDocTask.new do |rdoc|
50
+ rdoc.rdoc_dir = 'rdoc'
51
+ rdoc.title = "rack-thumb #{version}"
52
+ rdoc.rdoc_files.include('README*')
53
+ rdoc.rdoc_files.include('lib/**/*.rb')
54
+ end
@@ -0,0 +1,188 @@
1
+ def Mapel(source)
2
+ Mapel.render(source)
3
+ end
4
+
5
+ module Mapel
6
+
7
+ # Mapel.info('image.jpg')
8
+ def self.info(source, engine = :image_magick)
9
+ Mapel::Engine.const_get(camelize(engine)).info(source)
10
+ end
11
+
12
+ # Mapel.render('image.jpg').resize("50%").to('output.jpg').run
13
+ def self.render(source, engine = :image_magick)
14
+ Mapel::Engine.const_get(camelize(engine)).render(source)
15
+ end
16
+
17
+ # Mapel.list
18
+ def self.list(engine = :image_magick)
19
+ Mapel::Engine.const_get(camelize(engine)).list
20
+ end
21
+
22
+ class Engine
23
+ attr_reader :command, :status, :output
24
+ attr_accessor :commands
25
+
26
+ def initialize(source = nil)
27
+ @source = source
28
+ @commands = []
29
+ end
30
+
31
+ def success?
32
+ @status
33
+ end
34
+
35
+ class ImageMagick < Engine
36
+ def self.info(source)
37
+ im = new(source)
38
+ im.commands << 'identify'
39
+ im.commands << source
40
+ im.run.to_info_hash
41
+ end
42
+
43
+ def self.render(source = nil)
44
+ im = new(source)
45
+ im.commands << 'convert'
46
+ im.commands << source unless source.nil?
47
+ im
48
+ end
49
+
50
+ def self.list(type = nil)
51
+ im = new
52
+ im.commands << 'convert -list'
53
+ im.run
54
+ end
55
+
56
+ def crop(*args)
57
+ @commands << "-crop \"#{Geometry.new(*args).to_s(true)}\""
58
+ self
59
+ end
60
+
61
+ def gravity(type = :center)
62
+ @commands << "-gravity #{type}"
63
+ self
64
+ end
65
+
66
+ def repage
67
+ @commands << "+repage"
68
+ self
69
+ end
70
+
71
+ def resize(*args)
72
+ @commands << "-resize \"#{Geometry.new(*args)}\""
73
+ self
74
+ end
75
+
76
+ def resize!(*args)
77
+ @commands << lambda {
78
+ cmd = self.class.new
79
+ width, height = Geometry.new(*args).dimensions
80
+ if @source
81
+ origin_width, origin_height = Mapel.info(@source)[:dimensions]
82
+
83
+ # Crop dimensions should not exceed original dimensions.
84
+ width = [width, origin_width].min
85
+ height = [height, origin_height].min
86
+
87
+ if width != origin_width || height != origin_height
88
+ scale = [width/origin_width.to_f, height/origin_height.to_f].max
89
+ cmd.resize((scale*(origin_width+0.5)), (scale*(origin_height+0.5)))
90
+ end
91
+ cmd.crop(width, height).to_preview
92
+ else
93
+ "\{crop_resized #{args}\}"
94
+ end
95
+ }
96
+ self
97
+ end
98
+
99
+ def scale(*args)
100
+ @commands << "-scale \"#{Geometry.new(*args)}\""
101
+ self
102
+ end
103
+
104
+ def to(path)
105
+ @commands << path
106
+ self
107
+ end
108
+
109
+ def undo
110
+ @commands.pop
111
+ self
112
+ end
113
+
114
+ def run
115
+ @output = `#{to_preview}`
116
+ @status = ($? == 0)
117
+ self
118
+ end
119
+
120
+ def to_preview
121
+ @commands.map { |cmd| cmd.respond_to?(:call) ? cmd.call : cmd }.join(' ')
122
+ end
123
+
124
+ def to_info_hash
125
+ meta = {}
126
+ meta[:dimensions] = @output.split(' ')[2].split('x').map { |d| d.to_i }
127
+ meta
128
+ end
129
+ end
130
+ end
131
+
132
+ class Geometry
133
+ attr_accessor :width, :height, :x, :y, :flag
134
+
135
+ FLAGS = ['', '%', '<', '>', '!', '@']
136
+ RFLAGS = {
137
+ '%' => :percent,
138
+ '!' => :aspect,
139
+ '<' => :<,
140
+ '>' => :>,
141
+ '@' => :area
142
+ }
143
+
144
+ # Regex parser for geometry strings
145
+ RE = /\A(\d*)(?:x(\d+)?)?([-+]\d+)?([-+]\d+)?([%!<>@]?)\Z/
146
+
147
+ def initialize(*args)
148
+ if (args.length == 1) && (args.first.kind_of?(String))
149
+ raise(ArgumentError, "Invalid geometry string") unless m = RE.match(args.first)
150
+ args = m.to_a[1..5]
151
+ args[4] = args[4] ? RFLAGS[args[4]] : nil
152
+ end
153
+ @width = args[0] ? args[0].to_i.round : 0
154
+ @height = args[1] ? args[1].to_i.round : 0
155
+ raise(ArgumentError, "Width must be >= 0") if @width < 0
156
+ raise(ArgumentError, "Height must be >= 0") if @height < 0
157
+ @x = args[2] ? args[2].to_i : 0
158
+ @y = args[3] ? args[3].to_i : 0
159
+ @flag = (args[4] && RFLAGS.has_value?(args[4])) ? args[4] : nil
160
+ end
161
+
162
+ def dimensions
163
+ [width, height]
164
+ end
165
+
166
+ # Convert object to a geometry string
167
+ def to_s(crop = false)
168
+ str = ''
169
+ str << "%g" % @width if @width > 0
170
+ str << 'x' if @height > 0
171
+ str << "%g" % @height if @height > 0
172
+ str << "%+d%+d" % [@x, @y] if (@x != 0 || @y != 0 || crop)
173
+ str << (RFLAGS.respond_to?(:key) ? RFLAGS.key(@flag) : RFLAGS.index(@flag)).to_s
174
+ end
175
+ end
176
+
177
+ # By default, camelize converts strings to UpperCamelCase.
178
+ #
179
+ # camelize will also convert '/' to '::' which is useful for converting paths to namespaces
180
+ #
181
+ # @example
182
+ # "active_record".camelize #=> "ActiveRecord"
183
+ # "active_record/errors".camelize #=> "ActiveRecord::Errors"
184
+ #
185
+ def self.camelize(word, *args)
186
+ word.to_s.gsub(/\/(.?)/) { "::" + $1.upcase }.gsub(/(^|_)(.)/) { $2.upcase }
187
+ end
188
+ end
@@ -0,0 +1,50 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{mapel}
8
+ s.version = "0.1.5"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Aleksander Williams"]
12
+ s.date = %q{2010-02-24}
13
+ s.email = %q{alekswilliams@earthlink.net}
14
+ s.extra_rdoc_files = [
15
+ "README.rdoc"
16
+ ]
17
+ s.files = [
18
+ ".gitignore",
19
+ "README.rdoc",
20
+ "Rakefile",
21
+ "lib/mapel.rb",
22
+ "mapel.gemspec",
23
+ "spec/fixtures/ImageMagick.jpg",
24
+ "spec/mapel_spec.rb",
25
+ "spec/spec_helper.rb"
26
+ ]
27
+ s.homepage = %q{http://github.com/akdubya/mapel}
28
+ s.rdoc_options = ["--charset=UTF-8"]
29
+ s.require_paths = ["lib"]
30
+ s.rubygems_version = %q{1.3.5}
31
+ s.summary = %q{A dead-simple image rendering DSL.}
32
+ s.test_files = [
33
+ "spec/spec_helper.rb",
34
+ "spec/mapel_spec.rb"
35
+ ]
36
+
37
+ if s.respond_to? :specification_version then
38
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
39
+ s.specification_version = 3
40
+
41
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
42
+ s.add_development_dependency(%q<bacon>, [">= 0"])
43
+ else
44
+ s.add_dependency(%q<bacon>, [">= 0"])
45
+ end
46
+ else
47
+ s.add_dependency(%q<bacon>, [">= 0"])
48
+ end
49
+ end
50
+
@@ -0,0 +1,63 @@
1
+ require File.dirname(__FILE__) + '/spec_helper.rb'
2
+
3
+ describe Mapel do
4
+ before do
5
+ @input = File.dirname(__FILE__) + '/fixtures'
6
+ @output = File.dirname(__FILE__) + '/output'
7
+ @logo = @input + '/ImageMagick.jpg'
8
+ end
9
+
10
+ after do
11
+ Dir.glob(@output + '/*') { |f| File.delete(f) }
12
+ end
13
+
14
+ it "should respond to #info" do
15
+ Mapel.respond_to?(:info).should == true
16
+ end
17
+
18
+ it "should respond to #render" do
19
+ Mapel.respond_to?(:render).should == true
20
+ end
21
+
22
+ it "should support compact rendering syntax" do
23
+ Mapel(@logo).should.be.kind_of(Mapel::Engine)
24
+ end
25
+
26
+ describe "#info" do
27
+ it "should return image dimensions" do
28
+ Mapel.info(@logo)[:dimensions].should == [572, 591]
29
+ end
30
+ end
31
+
32
+ describe "#render" do
33
+ it "should be able to scale an image" do
34
+ cmd = Mapel(@logo).scale('50%').to(@output + '/scaled.jpg').run
35
+ cmd.status.should == true
36
+ Mapel.info(@output + '/scaled.jpg')[:dimensions].should == [286, 296]
37
+ end
38
+
39
+ it "should be able to crop an image" do
40
+ cmd = Mapel(@logo).crop('50x50+0+0').to(@output + '/cropped.jpg').run
41
+ cmd.status.should == true
42
+ Mapel.info(@output + '/cropped.jpg')[:dimensions].should == [50, 50]
43
+ end
44
+
45
+ it "should be able to resize an image" do
46
+ cmd = Mapel(@logo).resize('100x').to(@output + '/resized.jpg').run
47
+ cmd.status.should == true
48
+ Mapel.info(@output + '/resized.jpg')[:dimensions].should == [100, 103]
49
+ end
50
+
51
+ it "should be able to crop-resize an image" do
52
+ cmd = Mapel(@logo).gravity(:west).resize!('50x100').to(@output + '/crop_resized.jpg').run
53
+ cmd.status.should == true
54
+ Mapel.info(@output + '/crop_resized.jpg')[:dimensions].should == [50, 99]
55
+ end
56
+
57
+ it "should allow arbitrary addition of commands to the queue" do
58
+ cmd = Mapel(@logo).gravity(:west)
59
+ cmd.resize(50, 50)
60
+ cmd.to_preview.should == "convert #{@logo} -gravity west -resize \"50x50\""
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,6 @@
1
+ require 'rubygems'
2
+ require 'bacon'
3
+
4
+ require File.dirname(__FILE__) + '/../lib/mapel'
5
+
6
+ Bacon.summary_on_exit
metadata ADDED
@@ -0,0 +1,72 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mapel
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.5
5
+ platform: ruby
6
+ authors:
7
+ - Aleksander Williams
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2010-02-24 00:00:00 -05:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: bacon
17
+ type: :development
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ version:
25
+ description:
26
+ email: alekswilliams@earthlink.net
27
+ executables: []
28
+
29
+ extensions: []
30
+
31
+ extra_rdoc_files:
32
+ - README.rdoc
33
+ files:
34
+ - .gitignore
35
+ - README.rdoc
36
+ - Rakefile
37
+ - lib/mapel.rb
38
+ - mapel.gemspec
39
+ - spec/fixtures/ImageMagick.jpg
40
+ - spec/mapel_spec.rb
41
+ - spec/spec_helper.rb
42
+ has_rdoc: true
43
+ homepage: http://github.com/akdubya/mapel
44
+ licenses: []
45
+
46
+ post_install_message:
47
+ rdoc_options:
48
+ - --charset=UTF-8
49
+ require_paths:
50
+ - lib
51
+ required_ruby_version: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: "0"
56
+ version:
57
+ required_rubygems_version: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: "0"
62
+ version:
63
+ requirements: []
64
+
65
+ rubyforge_project:
66
+ rubygems_version: 1.3.5
67
+ signing_key:
68
+ specification_version: 3
69
+ summary: A dead-simple image rendering DSL.
70
+ test_files:
71
+ - spec/spec_helper.rb
72
+ - spec/mapel_spec.rb