miso 0.1.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/LICENSE +20 -0
- data/README +55 -0
- data/Rakefile +54 -0
- data/TODO +2 -0
- data/VERSION +1 -0
- data/html/classes/Miso.html +133 -0
- data/html/classes/Miso/Factory.html +278 -0
- data/html/classes/Miso/Image.html +394 -0
- data/html/classes/Miso/Processor.html +379 -0
- data/html/classes/Miso/Processor/CoreImage.html +246 -0
- data/html/classes/Miso/Processor/ImageMagick.html +345 -0
- data/html/classes/Miso/Processor/NotImplementedError.html +111 -0
- data/html/created.rid +1 -0
- data/html/files/LICENSE.html +133 -0
- data/html/files/README.html +156 -0
- data/html/files/lib/miso/factory_rb.html +101 -0
- data/html/files/lib/miso/image_rb.html +101 -0
- data/html/files/lib/miso/processor/core_image_rb.html +108 -0
- data/html/files/lib/miso/processor/image_magick_rb.html +110 -0
- data/html/files/lib/miso/processor_rb.html +101 -0
- data/html/files/lib/miso_rb.html +101 -0
- data/html/fr_class_index.html +33 -0
- data/html/fr_file_index.html +34 -0
- data/html/fr_method_index.html +62 -0
- data/html/index.html +24 -0
- data/html/rdoc-style.css +208 -0
- data/lib/miso.rb +5 -0
- data/lib/miso/factory.rb +53 -0
- data/lib/miso/image.rb +51 -0
- data/lib/miso/processor.rb +61 -0
- data/lib/miso/processor/core_image.rb +27 -0
- data/lib/miso/processor/image_magick.rb +59 -0
- data/spec/api/factory_spec.rb +31 -0
- data/spec/api/image_spec.rb +115 -0
- data/spec/api/processor/image_magick_spec.rb +22 -0
- data/spec/api/processor_spec.rb +41 -0
- data/spec/fixtures/120x100.png +0 -0
- data/spec/start.rb +30 -0
- metadata +97 -0
@@ -0,0 +1,61 @@
|
|
1
|
+
module Miso
|
2
|
+
class Processor
|
3
|
+
autoload :CoreImage, 'miso/processor/core_image'
|
4
|
+
autoload :ImageMagick, 'miso/processor/image_magick'
|
5
|
+
|
6
|
+
class NotImplementedError < StandardError; end
|
7
|
+
|
8
|
+
class << self
|
9
|
+
# Sets the default processor class.
|
10
|
+
attr_writer :processor_class
|
11
|
+
|
12
|
+
# Sets the default processor classes list.
|
13
|
+
attr_writer :processor_classes
|
14
|
+
|
15
|
+
# The default processor class.
|
16
|
+
#
|
17
|
+
# Returns either the assigned processor, or otherwise finds the first
|
18
|
+
# processor, that is available on the machine, from the processor_classes
|
19
|
+
# array.
|
20
|
+
def processor_class
|
21
|
+
@processor_class ||= processor_classes.find { |c| c.available? }
|
22
|
+
raise "None of the Miso::Processor classes is available." unless @processor_class
|
23
|
+
@processor_class
|
24
|
+
end
|
25
|
+
|
26
|
+
# The list of processor classes.
|
27
|
+
#
|
28
|
+
# When no explicit processor_class is set this list is iterated, from
|
29
|
+
# first to last, and the first available processor on the machine is used.
|
30
|
+
def processor_classes
|
31
|
+
@processor_classes ||= [CoreImage, ImageMagick]
|
32
|
+
end
|
33
|
+
|
34
|
+
def available?
|
35
|
+
raise NotImplementedError, "The class `#{name}' does not implement ::available?."
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
attr_reader :input_file
|
40
|
+
|
41
|
+
def initialize(input_file)
|
42
|
+
@input_file = input_file
|
43
|
+
end
|
44
|
+
|
45
|
+
def crop(width, height)
|
46
|
+
raise NotImplementedError, "The class `#{self.class.name}' does not implement #crop."
|
47
|
+
end
|
48
|
+
|
49
|
+
def fit(width, height)
|
50
|
+
raise NotImplementedError, "The class `#{self.class.name}' does not implement #fit."
|
51
|
+
end
|
52
|
+
|
53
|
+
def dimensions
|
54
|
+
raise NotImplementedError, "The class `#{self.class.name}' does not implement #dimensions."
|
55
|
+
end
|
56
|
+
|
57
|
+
def write(output_file)
|
58
|
+
raise NotImplementedError, "The class `#{self.class.name}' does not implement #write."
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Miso
|
2
|
+
class Processor
|
3
|
+
class CoreImage < Processor
|
4
|
+
def self.available?
|
5
|
+
available = $:.any? { |path| File.exist? File.join(path, 'osx/cocoa.rb') }
|
6
|
+
require 'osx/cocoa'
|
7
|
+
available
|
8
|
+
end
|
9
|
+
|
10
|
+
def crop(width, height)
|
11
|
+
# ...
|
12
|
+
end
|
13
|
+
|
14
|
+
def fit(width, height)
|
15
|
+
# ...
|
16
|
+
end
|
17
|
+
|
18
|
+
def dimensions
|
19
|
+
# ...
|
20
|
+
end
|
21
|
+
|
22
|
+
def write(output_file)
|
23
|
+
# ...
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
begin
|
2
|
+
require 'rubygems'
|
3
|
+
gem 'executioner', '>= 0.2'
|
4
|
+
rescue LoadError
|
5
|
+
end
|
6
|
+
require 'executioner'
|
7
|
+
require 'fileutils'
|
8
|
+
|
9
|
+
module Miso
|
10
|
+
class Processor
|
11
|
+
class ImageMagick < Processor
|
12
|
+
def self.available?
|
13
|
+
`which convert`
|
14
|
+
$?.success
|
15
|
+
end
|
16
|
+
|
17
|
+
def crop(width, height)
|
18
|
+
dimensions = "#{width}x#{height}"
|
19
|
+
operations << "-resize #{dimensions}^ -gravity center -crop #{dimensions}+0+0!"
|
20
|
+
end
|
21
|
+
|
22
|
+
def fit(width, height)
|
23
|
+
operations << "-resize #{width}x#{height}"
|
24
|
+
end
|
25
|
+
|
26
|
+
def dimensions
|
27
|
+
if info = identify(input_file) and match = /\s(\d+)x(\d+)\+/.match(info)
|
28
|
+
match.to_a[1..2].map { |d| d.to_i }
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def write(output_file)
|
33
|
+
options = operations.join(' ')
|
34
|
+
operations.clear
|
35
|
+
convert(input_file, output_file, options)
|
36
|
+
end
|
37
|
+
|
38
|
+
include Executioner
|
39
|
+
executable :convert
|
40
|
+
executable :identify
|
41
|
+
|
42
|
+
alias_method :_convert, :convert
|
43
|
+
def convert(source_path, output_path, options)
|
44
|
+
ensure_output_directory(output_path)
|
45
|
+
_convert "'#{source_path}' #{options} '#{output_path}'"
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def operations
|
51
|
+
@operations ||= []
|
52
|
+
end
|
53
|
+
|
54
|
+
def ensure_output_directory(path)
|
55
|
+
FileUtils.mkdir_p(File.dirname(path))
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require File.expand_path('../../start', __FILE__)
|
2
|
+
|
3
|
+
describe "A Miso::Factory instance" do
|
4
|
+
before do
|
5
|
+
Miso::Processor.processor_class = Miso::Processor
|
6
|
+
|
7
|
+
Miso::Processor.any_instance.stubs(:write)
|
8
|
+
|
9
|
+
@input_file = '/image.png'
|
10
|
+
@output_file = '/output_image.png'
|
11
|
+
@image = Miso::Image.new(@input_file)
|
12
|
+
|
13
|
+
Miso::Image.stubs(:new).with(@input_file, Miso::Processor).returns(@image)
|
14
|
+
Miso::Image.stubs(:new).with(@output_file, Miso::Processor)
|
15
|
+
|
16
|
+
@factory = Miso::Factory.new
|
17
|
+
end
|
18
|
+
|
19
|
+
after do
|
20
|
+
Miso::Processor.processor_class = nil
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should store operations that are to be applied later on" do
|
24
|
+
@factory.crop(123, 456).fit(123, 456)
|
25
|
+
|
26
|
+
@image.expects(:crop).with(123, 456)
|
27
|
+
@image.expects(:fit).with(123, 456)
|
28
|
+
|
29
|
+
@factory.apply(@input_file, @output_file)
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,115 @@
|
|
1
|
+
require File.expand_path('../../start', __FILE__)
|
2
|
+
|
3
|
+
describe "Miso::Image, concerning initialization" do
|
4
|
+
class FakeProcessor; end
|
5
|
+
|
6
|
+
before do
|
7
|
+
Miso::Processor.processor_class = nil
|
8
|
+
end
|
9
|
+
|
10
|
+
after do
|
11
|
+
Miso::Processor.processor_class = nil
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should initialize with only a file argument and use the default processor class" do
|
15
|
+
Miso::Processor.processor_class = Miso::Processor::ImageMagick
|
16
|
+
image = Miso::Image.new('/image.png')
|
17
|
+
|
18
|
+
image.processor.input_file.should == '/image.png'
|
19
|
+
image.processor.class.should == Miso::Processor::ImageMagick
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should initialize with a file and processor class" do
|
23
|
+
image = Miso::Image.new('/image.png', Miso::Processor::ImageMagick)
|
24
|
+
|
25
|
+
image.processor.input_file.should == '/image.png'
|
26
|
+
image.processor.class.should == Miso::Processor::ImageMagick
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe "An instance of Miso::Image, concerning forwarding calls to the processor" do
|
31
|
+
before do
|
32
|
+
Miso::Processor.any_instance.stubs(:fit)
|
33
|
+
Miso::Processor.any_instance.stubs(:crop)
|
34
|
+
|
35
|
+
@image = Miso::Image.new('/image.png', Miso::Processor)
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should forward #crop to the processor" do
|
39
|
+
@image.processor.expects(:crop).with(123, 456)
|
40
|
+
@image.crop(123, 456)
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should return self when calling #crop" do
|
44
|
+
@image.crop(123, 456).should.be @image
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should forward #fit to the processor" do
|
48
|
+
@image.processor.expects(:fit).with(123, 456)
|
49
|
+
@image.fit(123, 456)
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should return self instance when calling #fit" do
|
53
|
+
@image.fit(123, 456).should.be @image
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should forward #dimensions to the processor and return the result" do
|
57
|
+
@image.processor.expects(:dimensions).returns([123, 456])
|
58
|
+
@image.dimensions.should == [123, 456]
|
59
|
+
end
|
60
|
+
|
61
|
+
it "should forward #write to the processor and forward its output file to the new instance of Miso::Image" do
|
62
|
+
@image.processor.expects(:write).with('/output_image.png')
|
63
|
+
output_image = @image.write('/output_image.png')
|
64
|
+
output_image.processor.input_file.should == '/output_image.png'
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
describe "An instance of Miso::Image, concerning combined methods" do
|
69
|
+
before do
|
70
|
+
Miso::Processor.any_instance.stubs(:fit)
|
71
|
+
Miso::Processor.any_instance.stubs(:crop)
|
72
|
+
|
73
|
+
@image = Miso::Image.new('/image.png', Miso::Processor)
|
74
|
+
end
|
75
|
+
|
76
|
+
it "should call #fit to scale and preserve aspect ratio, then call #crop" do
|
77
|
+
@image.expects(:fit).with(123, 456).returns(@image)
|
78
|
+
@image.expects(:crop).with(123, 456).returns(@image)
|
79
|
+
|
80
|
+
@image.crop_fitting(123, 456)
|
81
|
+
end
|
82
|
+
|
83
|
+
it "should return self when calling #crop_fitting" do
|
84
|
+
@image.crop_fitting(123, 456).should.be @image
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
describe "Miso::Image, concerning shortcut class methods" do
|
89
|
+
before do
|
90
|
+
@input_file = fixture_file('120x100.png')
|
91
|
+
@output_file = temp_file('cropped_to_40x30.png')
|
92
|
+
@image = Miso::Image.new(@input_file, Miso::Processor)
|
93
|
+
|
94
|
+
Miso::Image.stubs(:new).with(@input_file, nil).returns(@image)
|
95
|
+
end
|
96
|
+
|
97
|
+
it "should crop to specified dimensions" do
|
98
|
+
@image.expects(:crop).with(40, 30).returns(@image)
|
99
|
+
@image.expects(:write).with(@output_file)
|
100
|
+
|
101
|
+
Miso::Image.crop(@input_file, @output_file, 40, 30)
|
102
|
+
end
|
103
|
+
|
104
|
+
it "should fit to specified dimensions, conserving the original aspect ratio" do
|
105
|
+
@image.expects(:fit).with(40, 30).returns(@image)
|
106
|
+
@image.expects(:write).with(@output_file)
|
107
|
+
|
108
|
+
Miso::Image.fit(@input_file, @output_file, 40, 30)
|
109
|
+
end
|
110
|
+
|
111
|
+
it "should return its dimensions" do
|
112
|
+
@image.expects(:dimensions).returns([120, 100])
|
113
|
+
Miso::Image.dimensions(@input_file).should == [120, 100]
|
114
|
+
end
|
115
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require File.expand_path('../../../start', __FILE__)
|
2
|
+
|
3
|
+
describe "An instance of Miso::Processor::ImageMagick" do
|
4
|
+
before do
|
5
|
+
@image_120_x_100 = Miso::Image.new(fixture_file('120x100.png'), Miso::Processor::ImageMagick)
|
6
|
+
@output_file = temp_file('temp.png')
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should crop to specified dimensions" do
|
10
|
+
@image_120_x_100.crop(40, 30).write(@output_file).dimensions.should == [40, 30]
|
11
|
+
@image_120_x_100.crop(40, 33).write(@output_file).dimensions.should == [40, 33]
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should fit to specified dimensions, conserving the original aspect ratio" do
|
15
|
+
@image_120_x_100.fit(40, 30).write(@output_file).dimensions.should == [36, 30]
|
16
|
+
@image_120_x_100.fit(40, 34).write(@output_file).dimensions.should == [40, 33]
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should return its dimensions" do
|
20
|
+
@image_120_x_100.dimensions.should == [120, 100]
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require File.expand_path('../../start', __FILE__)
|
2
|
+
|
3
|
+
describe "Miso::Processor" do
|
4
|
+
before do
|
5
|
+
Miso::Processor.processor_class = nil
|
6
|
+
end
|
7
|
+
|
8
|
+
after do
|
9
|
+
Miso::Processor.processor_class = nil
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should assign the processor class to use" do
|
13
|
+
Miso::Processor.processor_class = Miso::Processor::ImageMagick
|
14
|
+
Miso::Processor.processor_class.should.be Miso::Processor::ImageMagick
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should find the first available processor class" do
|
18
|
+
Miso::Processor.processor_classes = [
|
19
|
+
stub(:available? => false),
|
20
|
+
stub(:available? => true),
|
21
|
+
stub(:available? => false)
|
22
|
+
]
|
23
|
+
|
24
|
+
Miso::Processor.processor_class.should.be Miso::Processor.processor_classes[1]
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should raise if no available processor class is found" do
|
28
|
+
Miso::Processor.processor_classes = [
|
29
|
+
stub(:available? => false),
|
30
|
+
stub(:available? => false)
|
31
|
+
]
|
32
|
+
|
33
|
+
lambda {
|
34
|
+
Miso::Processor.processor_class
|
35
|
+
}.should.raise
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should initialize with an input file" do
|
39
|
+
Miso::Processor.new('/image.png').input_file.should == '/image.png'
|
40
|
+
end
|
41
|
+
end
|
Binary file
|
data/spec/start.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'rubygems' rescue LoadError
|
2
|
+
require 'test/spec'
|
3
|
+
require 'mocha'
|
4
|
+
|
5
|
+
require 'fileutils'
|
6
|
+
|
7
|
+
$:.unshift(File.expand_path('../../lib', __FILE__))
|
8
|
+
|
9
|
+
require 'miso'
|
10
|
+
require 'miso/processor'
|
11
|
+
|
12
|
+
class Test::Unit::TestCase
|
13
|
+
TMP_DIR = File.expand_path('../tmp', __FILE__)
|
14
|
+
|
15
|
+
def setup
|
16
|
+
FileUtils.mkdir_p(TMP_DIR)
|
17
|
+
end
|
18
|
+
|
19
|
+
def teardown
|
20
|
+
FileUtils.rm_rf(TMP_DIR)
|
21
|
+
end
|
22
|
+
|
23
|
+
def fixture_file(name)
|
24
|
+
File.expand_path("../fixtures/#{name}", __FILE__)
|
25
|
+
end
|
26
|
+
|
27
|
+
def temp_file(filename)
|
28
|
+
File.join(TMP_DIR, filename)
|
29
|
+
end
|
30
|
+
end
|
metadata
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: miso
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Manfred Stienstra
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-10-20 00:00:00 +02:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: Miso is a unified API for simple image operations commonly used on the web.
|
17
|
+
email: manfred@fngtps.com
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files:
|
23
|
+
- LICENSE
|
24
|
+
- README
|
25
|
+
files:
|
26
|
+
- LICENSE
|
27
|
+
- README
|
28
|
+
- Rakefile
|
29
|
+
- TODO
|
30
|
+
- VERSION
|
31
|
+
- html/classes/Miso.html
|
32
|
+
- html/classes/Miso/Factory.html
|
33
|
+
- html/classes/Miso/Image.html
|
34
|
+
- html/classes/Miso/Processor.html
|
35
|
+
- html/classes/Miso/Processor/CoreImage.html
|
36
|
+
- html/classes/Miso/Processor/ImageMagick.html
|
37
|
+
- html/classes/Miso/Processor/NotImplementedError.html
|
38
|
+
- html/created.rid
|
39
|
+
- html/files/LICENSE.html
|
40
|
+
- html/files/README.html
|
41
|
+
- html/files/lib/miso/factory_rb.html
|
42
|
+
- html/files/lib/miso/image_rb.html
|
43
|
+
- html/files/lib/miso/processor/core_image_rb.html
|
44
|
+
- html/files/lib/miso/processor/image_magick_rb.html
|
45
|
+
- html/files/lib/miso/processor_rb.html
|
46
|
+
- html/files/lib/miso_rb.html
|
47
|
+
- html/fr_class_index.html
|
48
|
+
- html/fr_file_index.html
|
49
|
+
- html/fr_method_index.html
|
50
|
+
- html/index.html
|
51
|
+
- html/rdoc-style.css
|
52
|
+
- lib/miso.rb
|
53
|
+
- lib/miso/factory.rb
|
54
|
+
- lib/miso/image.rb
|
55
|
+
- lib/miso/processor.rb
|
56
|
+
- lib/miso/processor/core_image.rb
|
57
|
+
- lib/miso/processor/image_magick.rb
|
58
|
+
- spec/api/factory_spec.rb
|
59
|
+
- spec/api/image_spec.rb
|
60
|
+
- spec/api/processor/image_magick_spec.rb
|
61
|
+
- spec/api/processor_spec.rb
|
62
|
+
- spec/fixtures/120x100.png
|
63
|
+
- spec/start.rb
|
64
|
+
has_rdoc: true
|
65
|
+
homepage: http://github.com/Fingertips/miso
|
66
|
+
licenses: []
|
67
|
+
|
68
|
+
post_install_message:
|
69
|
+
rdoc_options:
|
70
|
+
- --charset=UTF-8
|
71
|
+
require_paths:
|
72
|
+
- lib
|
73
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
74
|
+
requirements:
|
75
|
+
- - ">="
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: "0"
|
78
|
+
version:
|
79
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - ">="
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: "0"
|
84
|
+
version:
|
85
|
+
requirements: []
|
86
|
+
|
87
|
+
rubyforge_project:
|
88
|
+
rubygems_version: 1.3.5
|
89
|
+
signing_key:
|
90
|
+
specification_version: 3
|
91
|
+
summary: Miso is a unified API for simple image operations commonly used on the web.
|
92
|
+
test_files:
|
93
|
+
- spec/api/factory_spec.rb
|
94
|
+
- spec/api/image_spec.rb
|
95
|
+
- spec/api/processor/image_magick_spec.rb
|
96
|
+
- spec/api/processor_spec.rb
|
97
|
+
- spec/start.rb
|