elrio 0.0.1
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.
- checksums.yaml +7 -0
- data/.gitignore +16 -0
- data/.rspec +2 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +3 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +29 -0
- data/LICENSE.txt +22 -0
- data/README.md +51 -0
- data/Rakefile +6 -0
- data/bin/elrio +5 -0
- data/elrio.gemspec +27 -0
- data/lib/elrio/cap_inset_detector.rb +37 -0
- data/lib/elrio/cli.rb +32 -0
- data/lib/elrio/geometry.rb +13 -0
- data/lib/elrio/image_optimizer.rb +110 -0
- data/lib/elrio/runner.rb +44 -0
- data/lib/elrio/version.rb +3 -0
- data/lib/elrio.rb +6 -0
- data/spec/elrio/cap_inset_detector_spec.rb +40 -0
- data/spec/elrio/cli_spec.rb +56 -0
- data/spec/elrio/image_optimizer_spec.rb +82 -0
- data/spec/elrio/runner_spec.rb +86 -0
- data/spec/fixtures/optimized.png +0 -0
- data/spec/fixtures/optimized@2x.png +0 -0
- data/spec/fixtures/original.png +0 -0
- data/spec/spec_helper.rb +5 -0
- metadata +136 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: a80ee82d7cdb243d0d7e440a1189f284a951257a
|
4
|
+
data.tar.gz: 3d5e5d5f8f7f5095d627603002055dc2c3817f8e
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: e65300dd7bf244c69aea9e48f361c345056793cdf8ae9ec5c51b7489692a2a0bb39a562fee1e10d78a00829d537da4a72dae94719b64a55c1ae993483a664ff8
|
7
|
+
data.tar.gz: ff40869a428d24ad6d534c170a16fd2ba6d380092f2e34e78bb930d5b802ddf8e665e2aa3bc942815440731d17c512df63439a43d64f3259f8040d847d1288b5
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.ruby-gemset
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
elrio
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
ruby-2.0.0-p247
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
elrio (0.0.1)
|
5
|
+
chunky_png
|
6
|
+
|
7
|
+
GEM
|
8
|
+
remote: https://rubygems.org/
|
9
|
+
specs:
|
10
|
+
chunky_png (1.2.8)
|
11
|
+
diff-lcs (1.2.4)
|
12
|
+
rake (0.9.6)
|
13
|
+
rspec (2.14.1)
|
14
|
+
rspec-core (~> 2.14.0)
|
15
|
+
rspec-expectations (~> 2.14.0)
|
16
|
+
rspec-mocks (~> 2.14.0)
|
17
|
+
rspec-core (2.14.5)
|
18
|
+
rspec-expectations (2.14.2)
|
19
|
+
diff-lcs (>= 1.1.3, < 2.0)
|
20
|
+
rspec-mocks (2.14.3)
|
21
|
+
|
22
|
+
PLATFORMS
|
23
|
+
ruby
|
24
|
+
|
25
|
+
DEPENDENCIES
|
26
|
+
bundler (~> 1.3)
|
27
|
+
elrio!
|
28
|
+
rake
|
29
|
+
rspec
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Can Berk Güder
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
# Elrio
|
2
|
+
|
3
|
+
Cap inset detector & optimizer for resizable UIKit assets.
|
4
|
+
|
5
|
+
[](https://codeclimate.com/github/cbguder/elrio)
|
6
|
+
[](https://travis-ci.org/cbguder/elrio)
|
7
|
+
|
8
|
+
## Installation
|
9
|
+
|
10
|
+
Add this line to your application's Gemfile:
|
11
|
+
|
12
|
+
gem 'elrio'
|
13
|
+
|
14
|
+
And then execute:
|
15
|
+
|
16
|
+
$ bundle
|
17
|
+
|
18
|
+
Or install it yourself as:
|
19
|
+
|
20
|
+
$ gem install elrio
|
21
|
+
|
22
|
+
## Usage
|
23
|
+
|
24
|
+
To get the resizable cap insets for an asset:
|
25
|
+
|
26
|
+
$ elrio analyze image.png
|
27
|
+
|
28
|
+
To create an optimized version of the asset:
|
29
|
+
|
30
|
+
$ elrio optimize image.png
|
31
|
+
|
32
|
+
## Example
|
33
|
+
|
34
|
+
When run with this image:
|
35
|
+
|
36
|
+

|
37
|
+
|
38
|
+
$ elrio optimize image.png
|
39
|
+
image.png: [48, 48, 48, 48] # Top, Left, Bottom, Right
|
40
|
+
|
41
|
+
This optimized version is written to `image-optimized.png`:
|
42
|
+
|
43
|
+

|
44
|
+
|
45
|
+
## Contributing
|
46
|
+
|
47
|
+
1. Fork it
|
48
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
49
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
50
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
51
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
data/bin/elrio
ADDED
data/elrio.gemspec
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
lib = File.expand_path("../lib", __FILE__)
|
4
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
|
+
require "elrio/version"
|
6
|
+
|
7
|
+
Gem::Specification.new do |spec|
|
8
|
+
spec.name = "elrio"
|
9
|
+
spec.version = Elrio::VERSION
|
10
|
+
spec.authors = ["Can Berk Güder"]
|
11
|
+
spec.email = ["cbguder@gmail.com"]
|
12
|
+
spec.description = "Cap inset detector & optimizer for resizable UIKit assets."
|
13
|
+
spec.summary = "Cap inset detector & optimizer for resizable UIKit assets."
|
14
|
+
spec.homepage = "https://github.com/cbguder/elrio"
|
15
|
+
spec.license = "MIT"
|
16
|
+
|
17
|
+
spec.files = `git ls-files`.split($/)
|
18
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
19
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
20
|
+
spec.require_paths = ["lib"]
|
21
|
+
|
22
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
23
|
+
spec.add_development_dependency "rake"
|
24
|
+
spec.add_development_dependency "rspec"
|
25
|
+
|
26
|
+
spec.add_runtime_dependency "chunky_png"
|
27
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Elrio
|
2
|
+
class CapInsetDetector
|
3
|
+
def detect_cap_insets(array)
|
4
|
+
prev = array.first
|
5
|
+
runs = [1]
|
6
|
+
|
7
|
+
(1...array.count).each do |i|
|
8
|
+
if array[i] == prev
|
9
|
+
runs[-1] += 1
|
10
|
+
else
|
11
|
+
runs << 1
|
12
|
+
end
|
13
|
+
|
14
|
+
prev = array[i]
|
15
|
+
end
|
16
|
+
|
17
|
+
longest_run_length = runs.max
|
18
|
+
|
19
|
+
return [array.count, 0] if longest_run_length == 1
|
20
|
+
|
21
|
+
longest_run_index = runs.index(longest_run_length)
|
22
|
+
|
23
|
+
if longest_run_index > 0
|
24
|
+
run_start = runs[0, longest_run_index].reduce(:+)
|
25
|
+
else
|
26
|
+
run_start = 0
|
27
|
+
end
|
28
|
+
|
29
|
+
run_end = run_start + longest_run_length
|
30
|
+
|
31
|
+
[
|
32
|
+
run_start,
|
33
|
+
array.count - run_end
|
34
|
+
]
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/lib/elrio/cli.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
module Elrio
|
2
|
+
class CLI
|
3
|
+
def initialize(output = $stdout)
|
4
|
+
@output = output
|
5
|
+
end
|
6
|
+
|
7
|
+
def run(args)
|
8
|
+
runner = Runner.new
|
9
|
+
cmd = args.shift
|
10
|
+
|
11
|
+
return usage unless cmd
|
12
|
+
|
13
|
+
args.each do |path|
|
14
|
+
insets = runner.send(cmd, path)
|
15
|
+
@output.puts "#{path}: #{insets}"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def usage
|
22
|
+
@output.puts(<<-EOF)
|
23
|
+
Usage: elrio <command> <images>
|
24
|
+
|
25
|
+
Commands:
|
26
|
+
analyze Analyzes each file and prints the resizable cap insets.
|
27
|
+
optimize Creates an optimized version of each file and prints the
|
28
|
+
resizable cap insets for the optimized file.
|
29
|
+
EOF
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
module Elrio
|
2
|
+
class ImageOptimizer
|
3
|
+
def initialize(retina = false)
|
4
|
+
@retina = retina
|
5
|
+
end
|
6
|
+
|
7
|
+
def detect_cap_insets(image)
|
8
|
+
insets = detect_cap_insets_in_pixels(image)
|
9
|
+
|
10
|
+
if @retina
|
11
|
+
Insets.new(
|
12
|
+
(insets.top + 1) / 2,
|
13
|
+
(insets.left + 1) / 2,
|
14
|
+
(insets.bottom + 1) / 2,
|
15
|
+
(insets.right + 1) / 2
|
16
|
+
)
|
17
|
+
else
|
18
|
+
insets
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def optimize(image, insets)
|
23
|
+
insets = insets.dup
|
24
|
+
repeatable_size = 1
|
25
|
+
|
26
|
+
if @retina
|
27
|
+
repeatable_size *= 2
|
28
|
+
insets.top *= 2
|
29
|
+
insets.left *= 2
|
30
|
+
insets.bottom *= 2
|
31
|
+
insets.right *= 2
|
32
|
+
end
|
33
|
+
|
34
|
+
target_height = insets.top + insets.bottom + repeatable_size
|
35
|
+
target_width = insets.left + insets.right + repeatable_size
|
36
|
+
|
37
|
+
return nil if target_height > image.height || target_width > image.width
|
38
|
+
|
39
|
+
source_x = image.width - insets.right
|
40
|
+
source_y = image.height - insets.bottom
|
41
|
+
target_x = target_width - insets.right
|
42
|
+
target_y = target_height - insets.bottom
|
43
|
+
|
44
|
+
optimized = ChunkyPNG::Image.new(target_width, target_height)
|
45
|
+
|
46
|
+
copy_rect(
|
47
|
+
image,
|
48
|
+
optimized,
|
49
|
+
Rect.new(0, 0, insets.left + repeatable_size, insets.top + repeatable_size),
|
50
|
+
Point.new(0, 0)
|
51
|
+
)
|
52
|
+
|
53
|
+
copy_rect(
|
54
|
+
image,
|
55
|
+
optimized,
|
56
|
+
Rect.new(source_x, 0, insets.right, insets.top + repeatable_size),
|
57
|
+
Point.new(target_x, 0)
|
58
|
+
)
|
59
|
+
|
60
|
+
copy_rect(
|
61
|
+
image,
|
62
|
+
optimized,
|
63
|
+
Rect.new(0, source_y, insets.left + repeatable_size, insets.bottom),
|
64
|
+
Point.new(0, target_y)
|
65
|
+
)
|
66
|
+
|
67
|
+
copy_rect(
|
68
|
+
image,
|
69
|
+
optimized,
|
70
|
+
Rect.new(source_x, source_y, insets.right, insets.bottom),
|
71
|
+
Point.new(target_x, target_y)
|
72
|
+
)
|
73
|
+
|
74
|
+
optimized
|
75
|
+
end
|
76
|
+
|
77
|
+
private
|
78
|
+
|
79
|
+
def detect_cap_insets_in_pixels(image)
|
80
|
+
columns = (0...image.width).map {|x| image.column(x) }
|
81
|
+
rows = (0...image.height).map {|y| image.row(y) }
|
82
|
+
|
83
|
+
detector = CapInsetDetector.new
|
84
|
+
|
85
|
+
column_info = detector.detect_cap_insets(columns)
|
86
|
+
row_info = detector.detect_cap_insets(rows)
|
87
|
+
|
88
|
+
Insets.new(
|
89
|
+
row_info[0],
|
90
|
+
column_info[0],
|
91
|
+
row_info[1],
|
92
|
+
column_info[1]
|
93
|
+
)
|
94
|
+
end
|
95
|
+
|
96
|
+
def copy_rect(src, dest, src_rect, dest_origin)
|
97
|
+
(0...src_rect.width).each do |x|
|
98
|
+
(0...src_rect.height).each do |y|
|
99
|
+
src_x = src_rect.x + x
|
100
|
+
src_y = src_rect.y + y
|
101
|
+
|
102
|
+
dest_x = dest_origin.x + x
|
103
|
+
dest_y = dest_origin.y + y
|
104
|
+
|
105
|
+
dest[dest_x, dest_y] = src[src_x, src_y]
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
data/lib/elrio/runner.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
require "chunky_png"
|
2
|
+
|
3
|
+
module Elrio
|
4
|
+
class Runner
|
5
|
+
def analyze(path)
|
6
|
+
image = ChunkyPNG::Image.from_file(path)
|
7
|
+
image_optimizer = ImageOptimizer.new(is_retina?(path))
|
8
|
+
image_optimizer.detect_cap_insets(image)
|
9
|
+
end
|
10
|
+
|
11
|
+
def optimize(path)
|
12
|
+
retina = is_retina?(path)
|
13
|
+
|
14
|
+
if retina
|
15
|
+
opt_suffix = "-optimized@2x.png"
|
16
|
+
opt_base = path.sub(/@2x/, '')
|
17
|
+
else
|
18
|
+
opt_suffix = "-optimized.png"
|
19
|
+
opt_base = path
|
20
|
+
end
|
21
|
+
|
22
|
+
optimized_path = File.join(
|
23
|
+
File.dirname(opt_base),
|
24
|
+
File.basename(opt_base, ".*") + opt_suffix
|
25
|
+
)
|
26
|
+
|
27
|
+
image = ChunkyPNG::Image.from_file(path)
|
28
|
+
|
29
|
+
image_optimizer = ImageOptimizer.new(retina)
|
30
|
+
insets = image_optimizer.detect_cap_insets(image)
|
31
|
+
|
32
|
+
optimized = image_optimizer.optimize(image, insets)
|
33
|
+
optimized.save(optimized_path) if optimized
|
34
|
+
|
35
|
+
insets
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def is_retina?(path)
|
41
|
+
!!(path =~ /@2x/)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
data/lib/elrio.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Elrio::CapInsetDetector do
|
4
|
+
describe "#detect_cap_insets" do
|
5
|
+
it "returns the non-repeating prefix and suffix lengths of a collection" do
|
6
|
+
data = %w(A - - - B C)
|
7
|
+
subject.detect_cap_insets(data).should == [1, 2]
|
8
|
+
end
|
9
|
+
|
10
|
+
it "returns zero when all items are the same" do
|
11
|
+
data = %w(- - -)
|
12
|
+
subject.detect_cap_insets(data).should == [0, 0]
|
13
|
+
end
|
14
|
+
|
15
|
+
it "returns the length of the collection when all items are unique" do
|
16
|
+
data = %w(A B C D E)
|
17
|
+
subject.detect_cap_insets(data).should == [5, 0]
|
18
|
+
end
|
19
|
+
|
20
|
+
it "does not fail with a single-item collection" do
|
21
|
+
data = %w(A)
|
22
|
+
subject.detect_cap_insets(data).should == [1, 0]
|
23
|
+
end
|
24
|
+
|
25
|
+
it "can handle multiple runs" do
|
26
|
+
data = %w(A A A B C - - - - - D E F F F)
|
27
|
+
subject.detect_cap_insets(data).should == [5, 5]
|
28
|
+
end
|
29
|
+
|
30
|
+
it "can handle longest runs at the beginning" do
|
31
|
+
data = %w(- - - A)
|
32
|
+
subject.detect_cap_insets(data).should == [0, 1]
|
33
|
+
end
|
34
|
+
|
35
|
+
it "can handle longest runs at the end" do
|
36
|
+
data = %w(A - - -)
|
37
|
+
subject.detect_cap_insets(data).should == [1, 0]
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Elrio::CLI do
|
4
|
+
let(:output) { double(:output) }
|
5
|
+
|
6
|
+
subject { Elrio::CLI.new(output) }
|
7
|
+
|
8
|
+
describe "#run" do
|
9
|
+
let(:runner) { double(Elrio::Runner) }
|
10
|
+
|
11
|
+
before do
|
12
|
+
Elrio::Runner.stub(:new).and_return(runner)
|
13
|
+
end
|
14
|
+
|
15
|
+
context "when run without a command" do
|
16
|
+
it "prints usage instructions" do
|
17
|
+
output.should_receive(:puts).with(/Usage: elrio <command> <images>/)
|
18
|
+
subject.run([])
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
context "when run with the analyze command" do
|
23
|
+
before do
|
24
|
+
runner.stub(:analyze).and_return(Elrio::Insets.new(1, 2, 3, 4))
|
25
|
+
end
|
26
|
+
|
27
|
+
it "prints the cap insets for each file" do
|
28
|
+
args = %w(analyze foo bar)
|
29
|
+
|
30
|
+
args[1..-1].each do |arg|
|
31
|
+
runner.should_receive(:analyze).with(arg)
|
32
|
+
output.should_receive(:puts).with("#{arg}: [1, 2, 3, 4]")
|
33
|
+
end
|
34
|
+
|
35
|
+
subject.run(args)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
context "when run with the optimize command" do
|
40
|
+
before do
|
41
|
+
runner.stub(:optimize).and_return(Elrio::Insets.new(1, 2, 3, 4))
|
42
|
+
end
|
43
|
+
|
44
|
+
it "prints the cap insets for each file" do
|
45
|
+
args = %w(optimize foo bar)
|
46
|
+
|
47
|
+
args[1..-1].each do |arg|
|
48
|
+
runner.should_receive(:optimize).with(arg)
|
49
|
+
output.should_receive(:puts).with("#{arg}: [1, 2, 3, 4]")
|
50
|
+
end
|
51
|
+
|
52
|
+
subject.run(args)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Elrio::ImageOptimizer do
|
4
|
+
describe "#detect_cap_insets" do
|
5
|
+
let(:cap_inset_detector) { double(Elrio::CapInsetDetector) }
|
6
|
+
let(:image) { double(ChunkyPNG::Image) }
|
7
|
+
let(:columns) { [double] * 5 }
|
8
|
+
let(:rows) { [double] * 3 }
|
9
|
+
|
10
|
+
before do
|
11
|
+
image.stub(:width).and_return(columns.count)
|
12
|
+
image.stub(:height).and_return(rows.count)
|
13
|
+
image.stub(:column) {|x| columns[x] }
|
14
|
+
image.stub(:row) {|x| rows[x] }
|
15
|
+
|
16
|
+
cap_inset_detector.stub(:detect_cap_insets).with(rows).and_return([1, 3])
|
17
|
+
cap_inset_detector.stub(:detect_cap_insets).with(columns).and_return([2, 4])
|
18
|
+
|
19
|
+
Elrio::CapInsetDetector.stub(:new).and_return(cap_inset_detector)
|
20
|
+
end
|
21
|
+
|
22
|
+
context "in non-retina mode" do
|
23
|
+
it "passes the rows and columns to the detector" do
|
24
|
+
subject.detect_cap_insets(image).should == Elrio::Insets.new(1, 2, 3, 4)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
context "in retina mode" do
|
29
|
+
subject { Elrio::ImageOptimizer.new(true) }
|
30
|
+
|
31
|
+
it "halves the cap insets" do
|
32
|
+
subject.detect_cap_insets(image).should == Elrio::Insets.new(1, 1, 2, 2)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe "#optimize" do
|
38
|
+
let(:image) { ChunkyPNG::Image.from_file("spec/fixtures/original.png") }
|
39
|
+
|
40
|
+
context "in non-retina mode" do
|
41
|
+
let(:expected) { ChunkyPNG::Image.from_file("spec/fixtures/optimized.png") }
|
42
|
+
|
43
|
+
it "produces the expected image" do
|
44
|
+
optimized = subject.optimize(image, Elrio::Insets.new(48, 48, 48, 48))
|
45
|
+
optimized.should == expected
|
46
|
+
end
|
47
|
+
|
48
|
+
it "does not modify the insets" do
|
49
|
+
insets = Elrio::Insets.new(48, 48, 48, 48)
|
50
|
+
subject.optimize(image, insets)
|
51
|
+
insets.should == Elrio::Insets.new(48, 48, 48, 48)
|
52
|
+
end
|
53
|
+
|
54
|
+
it "returns nil if insets are too big" do
|
55
|
+
optimized = subject.optimize(image, Elrio::Insets.new(image.height, image.width, 0, 0))
|
56
|
+
optimized.should be_nil
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
context "in retina mode" do
|
61
|
+
let(:expected) { ChunkyPNG::Image.from_file("spec/fixtures/optimized@2x.png") }
|
62
|
+
|
63
|
+
subject { Elrio::ImageOptimizer.new(true) }
|
64
|
+
|
65
|
+
it "produces the expected image" do
|
66
|
+
optimized = subject.optimize(image, Elrio::Insets.new(24, 24, 24, 24))
|
67
|
+
optimized.should == expected
|
68
|
+
end
|
69
|
+
|
70
|
+
it "does not modify the insets" do
|
71
|
+
insets = Elrio::Insets.new(24, 24, 24, 24)
|
72
|
+
subject.optimize(image, insets)
|
73
|
+
insets.should == Elrio::Insets.new(24, 24, 24, 24)
|
74
|
+
end
|
75
|
+
|
76
|
+
it "returns nil if insets are too big" do
|
77
|
+
optimized = subject.optimize(image, Elrio::Insets.new(image.height / 2, image.width / 2, 0, 0))
|
78
|
+
optimized.should be_nil
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Elrio::Runner do
|
4
|
+
let(:image) { double(ChunkyPNG::Image) }
|
5
|
+
let(:optimized) { double(ChunkyPNG::Image) }
|
6
|
+
let(:image_optimizer) { double(Elrio::ImageOptimizer) }
|
7
|
+
let(:insets) { double(Elrio::Insets) }
|
8
|
+
|
9
|
+
before do
|
10
|
+
ChunkyPNG::Image.stub(:from_file).with(path).and_return(image)
|
11
|
+
image_optimizer.stub(:detect_cap_insets).and_return(insets)
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "#analyze" do
|
15
|
+
context "with a non-retina image" do
|
16
|
+
let(:path) { "file/path.png".freeze }
|
17
|
+
|
18
|
+
before do
|
19
|
+
Elrio::ImageOptimizer.should_receive(:new).with(false).and_return(image_optimizer)
|
20
|
+
end
|
21
|
+
|
22
|
+
it "returns the cap insets detected by the optimizer" do
|
23
|
+
subject.analyze(path).should == insets
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
context "with a retina image" do
|
28
|
+
let(:path) { "file/path@2x.png".freeze }
|
29
|
+
|
30
|
+
before do
|
31
|
+
Elrio::ImageOptimizer.should_receive(:new).with(true).and_return(image_optimizer)
|
32
|
+
end
|
33
|
+
|
34
|
+
it "returns the cap insets detected by the optimizer" do
|
35
|
+
subject.analyze(path).should == insets
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe "#optimize" do
|
41
|
+
context "when the image is optimizable" do
|
42
|
+
before do
|
43
|
+
image_optimizer.stub(:optimize).with(image, insets).and_return(optimized)
|
44
|
+
end
|
45
|
+
|
46
|
+
context "with a non-retina image" do
|
47
|
+
let(:path) { "file/path.png".freeze }
|
48
|
+
|
49
|
+
before do
|
50
|
+
Elrio::ImageOptimizer.should_receive(:new).with(false).and_return(image_optimizer)
|
51
|
+
optimized.should_receive(:save).with("file/path-optimized.png")
|
52
|
+
end
|
53
|
+
|
54
|
+
it "returns the cap insets detected by the optimizer" do
|
55
|
+
subject.optimize(path).should == insets
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
context "with a retina image" do
|
60
|
+
let(:path) { "file/path@2x.png".freeze }
|
61
|
+
|
62
|
+
before do
|
63
|
+
Elrio::ImageOptimizer.should_receive(:new).with(true).and_return(image_optimizer)
|
64
|
+
optimized.should_receive(:save).with("file/path-optimized@2x.png")
|
65
|
+
end
|
66
|
+
|
67
|
+
it "returns the cap insets detected by the optimizer" do
|
68
|
+
subject.optimize(path).should == insets
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
context "when the image is not optimizable" do
|
74
|
+
let(:path) { "file/path.png".freeze }
|
75
|
+
|
76
|
+
before do
|
77
|
+
Elrio::ImageOptimizer.should_receive(:new).and_return(image_optimizer)
|
78
|
+
image_optimizer.stub(:optimize).with(image, insets).and_return(nil)
|
79
|
+
end
|
80
|
+
|
81
|
+
it "does not blow up" do
|
82
|
+
-> { subject.optimize(path) }.should_not raise_exception
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
Binary file
|
Binary file
|
Binary file
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,136 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: elrio
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Can Berk Güder
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-09-11 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.3'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.3'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: chunky_png
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
description: Cap inset detector & optimizer for resizable UIKit assets.
|
70
|
+
email:
|
71
|
+
- cbguder@gmail.com
|
72
|
+
executables:
|
73
|
+
- elrio
|
74
|
+
extensions: []
|
75
|
+
extra_rdoc_files: []
|
76
|
+
files:
|
77
|
+
- .gitignore
|
78
|
+
- .rspec
|
79
|
+
- .ruby-gemset
|
80
|
+
- .ruby-version
|
81
|
+
- .travis.yml
|
82
|
+
- Gemfile
|
83
|
+
- Gemfile.lock
|
84
|
+
- LICENSE.txt
|
85
|
+
- README.md
|
86
|
+
- Rakefile
|
87
|
+
- bin/elrio
|
88
|
+
- elrio.gemspec
|
89
|
+
- lib/elrio.rb
|
90
|
+
- lib/elrio/cap_inset_detector.rb
|
91
|
+
- lib/elrio/cli.rb
|
92
|
+
- lib/elrio/geometry.rb
|
93
|
+
- lib/elrio/image_optimizer.rb
|
94
|
+
- lib/elrio/runner.rb
|
95
|
+
- lib/elrio/version.rb
|
96
|
+
- spec/elrio/cap_inset_detector_spec.rb
|
97
|
+
- spec/elrio/cli_spec.rb
|
98
|
+
- spec/elrio/image_optimizer_spec.rb
|
99
|
+
- spec/elrio/runner_spec.rb
|
100
|
+
- spec/fixtures/optimized.png
|
101
|
+
- spec/fixtures/optimized@2x.png
|
102
|
+
- spec/fixtures/original.png
|
103
|
+
- spec/spec_helper.rb
|
104
|
+
homepage: https://github.com/cbguder/elrio
|
105
|
+
licenses:
|
106
|
+
- MIT
|
107
|
+
metadata: {}
|
108
|
+
post_install_message:
|
109
|
+
rdoc_options: []
|
110
|
+
require_paths:
|
111
|
+
- lib
|
112
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
113
|
+
requirements:
|
114
|
+
- - '>='
|
115
|
+
- !ruby/object:Gem::Version
|
116
|
+
version: '0'
|
117
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
118
|
+
requirements:
|
119
|
+
- - '>='
|
120
|
+
- !ruby/object:Gem::Version
|
121
|
+
version: '0'
|
122
|
+
requirements: []
|
123
|
+
rubyforge_project:
|
124
|
+
rubygems_version: 2.0.6
|
125
|
+
signing_key:
|
126
|
+
specification_version: 4
|
127
|
+
summary: Cap inset detector & optimizer for resizable UIKit assets.
|
128
|
+
test_files:
|
129
|
+
- spec/elrio/cap_inset_detector_spec.rb
|
130
|
+
- spec/elrio/cli_spec.rb
|
131
|
+
- spec/elrio/image_optimizer_spec.rb
|
132
|
+
- spec/elrio/runner_spec.rb
|
133
|
+
- spec/fixtures/optimized.png
|
134
|
+
- spec/fixtures/optimized@2x.png
|
135
|
+
- spec/fixtures/original.png
|
136
|
+
- spec/spec_helper.rb
|