grosser-smusher 0.3.2 → 0.3.3

Sign up to get free protection for your applications and to get access to all the features.
data/README.markdown CHANGED
@@ -7,7 +7,7 @@ Problem
7
7
  Solution
8
8
  ========
9
9
  - *LOSSLESS* size reduction (10-97% size reduction) in the cloud
10
- - optmizes all images(jpg+png) from a given folder
10
+ - optmizes all images(jpg+png+[gif]) from a given folder
11
11
 
12
12
  Install
13
13
  =======
@@ -16,15 +16,25 @@ Install
16
16
 
17
17
  Usage
18
18
  =====
19
- smusher /apps/x/public/images # optimize all jpg/png images, NOT gifs
20
- smusher /apps/x/public/images/x.png # optimize a single image
21
- smusher /apps/x/public/images/x.gif # !!optimize to smaller png, rename it yourself!!
19
+ Optimize a single image or a whole folder in the cloud.
20
+
21
+ converting gif`s to png`s:
22
+ - called with a folder gif`s will not be converted
23
+ - called on a singe .gif, it will be converted if it is optimizeable
24
+
25
+ Usage:
26
+ smusher /apps/x/public/images [options]
27
+ smusher /apps/x/public/images/x.png [options]
28
+
29
+ Options are:
30
+ -q, --quiet no output
31
+ -c, --convert-gifs convert all .gif`s in the given folder
32
+
22
33
 
23
34
  Protection
24
35
  ==========
25
- Smusher makes .backup copies of any image before optimizing.
26
36
  Any image that returns a failure code, is larger than before,
27
- or is empty will be reverted.
37
+ or is empty will not be saved.
28
38
 
29
39
  Example
30
40
  ======
@@ -42,8 +52,9 @@ Example
42
52
 
43
53
  TODO
44
54
  ====
45
- - use rest-client rather than curl
46
- - windows support?
55
+ - only optimize 'new' images -> save time when doing on each deploy
56
+ - use ruby library rather than curl
57
+ - support `smusher images/*.png` ?
47
58
 
48
59
  Author
49
60
  ======
data/Rakefile CHANGED
@@ -9,7 +9,7 @@ end
9
9
  #Gemspec
10
10
  require 'echoe'
11
11
  project_name = 'smusher'
12
- Echoe.new(project_name , '0.3.2') do |p|
12
+ Echoe.new(project_name , '0.3.3') do |p|
13
13
  p.description = "Automatic Lossless Reduction Of All Your Images"
14
14
  p.url = "http://github.com/grosser/#{project_name}"
15
15
  p.author = "Michael Grosser"
data/bin/smusher CHANGED
@@ -1,16 +1,32 @@
1
1
  #!/usr/bin/env ruby
2
2
  require 'rubygems'
3
+ require 'optparse'
3
4
  require 'smusher'
4
5
 
5
- path = ARGV[0]
6
- if ARGV.length != 1 or not File.exist?(path)
7
- puts "smusher DIRECTORY_OR_FILE_TO_OPTIMIZE"
8
- puts "smusher /apps/x/public/images"
9
- exit
6
+ options = {}
7
+ path = ARGV.shift
8
+ OptionParser.new do |opts|
9
+ opts.banner = <<BANNER
10
+ Optimize a single image or a whole folder in the cloud.
11
+
12
+ gif`s:
13
+ - called with a folder gif`s will not be optimized
14
+ - called on a singe .gif, it will be optimized if it is optimizeable
15
+
16
+ Usage:
17
+ smusher /apps/x/public/images [options]
18
+ smusher /apps/x/public/images/x.png [options]
19
+
20
+ Options are:
21
+ BANNER
22
+ opts.on("-q", "--quiet","no output") { options[:quiet]=true }
23
+ opts.on("-c", "--convert-gifs","convert all .gif`s in the given folder") { options[:convert_gifs]=true }
24
+ opts.parse!(ARGV)
25
+ puts opts if path.to_s.empty? or not File.exist?(path)
10
26
  end
11
27
 
12
28
  if File.directory?(path)
13
- Smusher.optimize_images_in_folder(path)
29
+ Smusher.optimize_images_in_folder(path,options)
14
30
  else
15
- Smusher.optimize_image(path)
31
+ Smusher.optimize_image(path,options)
16
32
  end
data/lib/smusher.rb CHANGED
@@ -5,76 +5,81 @@ require 'json'
5
5
  module Smusher
6
6
  extend self
7
7
 
8
- # optimize the given image !!coverts gif to png!!
9
- def optimize_image(file)
10
- if empty?(file)
11
- puts "THIS FILE IS EMPTY!!! #{file}"
12
- return
8
+ MINIMUM_IMAGE_SIZE = 20#byte
9
+
10
+ # optimize the given image
11
+ # converts gif to png, if size is lower
12
+ def optimize_image(file,options={})
13
+ check_options(options)
14
+ puts "THIS FILE IS EMPTY!!! #{file}" and return if size(file).zero?
15
+ success = false
16
+
17
+ with_logging(file,options[:quiet]) do
18
+ write_optimized_data(file)
19
+ success = true
13
20
  end
14
- with_protection(file) do
15
- with_logging(file) do
16
- write_optimized_data(file)
17
- end
21
+
22
+ if success
23
+ gif = /\.gif$/
24
+ `mv #{file} #{file.sub(gif,'.png')}` if file =~ gif
18
25
  end
19
26
  end
20
27
 
21
28
  # fetch all jpg/png images from given folder and optimize them
22
- def optimize_images_in_folder(folder)
23
- images_in_folder(folder).each do |file|
29
+ def optimize_images_in_folder(folder,options={})
30
+ check_options(options)
31
+ images_in_folder(folder,options[:convert_gifs]).each do |file|
24
32
  optimize_image(file)
25
- puts ''
26
33
  end
27
34
  end
28
35
 
29
36
  private
30
37
 
38
+ def check_options(options)
39
+ known_options = [:convert_gifs,:quiet]
40
+ if options.detect{|k,v| not known_options.include?(k)}
41
+ raise "Known options: #{known_options*' '}"
42
+ end
43
+ end
44
+
31
45
  def write_optimized_data(file)
32
- data = optimized_image_data_for(file)
33
- File.open(file,'w') {|f| f.puts data} unless data.nil?
46
+ optimized = optimized_image_data_for(file)
47
+
48
+ raise "Error: got larger" if size(file) < optimized.size
49
+ raise "Error: empty file downloaded" if optimized.size < MINIMUM_IMAGE_SIZE
50
+ raise "cannot be optimized further" if size(file) == optimized.size
51
+
52
+ File.open(file,'w') {|f| f.puts optimized}
34
53
  end
35
54
 
36
55
  def sanitize_folder(folder)
37
56
  folder.sub(%r[/$],'')#remove tailing slash
38
57
  end
39
58
 
40
- def images_in_folder(folder)
59
+ def images_in_folder(folder,with_gifs=false)
41
60
  folder = sanitize_folder(folder)
42
- images = %w[png jpg jpeg JPG].map {|ext| "#{folder}/**/*.#{ext}"}
61
+ images = %w[png jpg jpeg JPG]
62
+ images << 'gif' if with_gifs
63
+ images.map! {|ext| "#{folder}/**/*.#{ext}"}
43
64
  FileList[*images]
44
65
  end
45
66
 
46
- def with_protection(file)
47
- backup = "#{file}.backup"
48
- FileUtils.cp(file,backup)
49
-
50
- before = size(file)
51
- yield
52
-
53
- if empty?(file) or size(file) >= before
54
- FileUtils.mv(backup,file,:force=>true)#revert
55
- puts "reverted!"
56
- else
57
- FileUtils.rm(backup)
58
- end
59
- end
60
-
61
67
  def size(file)
62
68
  File.exist?(file) ? File.size(file) : 0
63
69
  end
64
70
 
65
- def empty?(file)
66
- size(file) <= 4 #empty file = 4kb
67
- end
68
-
69
- def with_logging(file)
70
- puts "smushing #{file}"
71
+ def with_logging(file,quiet)
72
+ puts "smushing #{file}" unless quiet
71
73
 
72
74
  before = size(file)
73
- begin; yield; rescue; puts $!; end
75
+ begin; yield; rescue; puts $! unless quiet; end
74
76
  after = size(file)
75
77
 
76
- result = "#{(100*after)/before}%"
77
- puts "#{before} -> #{after}".ljust(40) + " = #{result}"
78
+ unless quiet
79
+ result = "#{(100*after)/before}%"
80
+ puts "#{before} -> #{after}".ljust(40) + " = #{result}"
81
+ puts ''
82
+ end
78
83
  end
79
84
 
80
85
  def optimized_image_data_for(file)
data/smusher.gemspec CHANGED
@@ -1,42 +1,106 @@
1
- # -*- encoding: utf-8 -*-
2
1
 
3
- Gem::Specification.new do |s|
4
- s.name = %q{smusher}
5
- s.version = "0.3.2"
2
+ # Gem::Specification for Smusher-0.3.3
3
+ # Originally generated by Echoe
6
4
 
7
- s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
- s.authors = ["Michael Grosser"]
9
- s.date = %q{2009-01-27}
10
- s.default_executable = %q{smusher}
11
- s.description = %q{Automatic Lossless Reduction Of All Your Images}
12
- s.email = %q{grosser.michael@gmail.com}
13
- s.executables = ["smusher"]
14
- s.extra_rdoc_files = ["lib/smusher.rb", "bin/smusher", "README.markdown"]
15
- s.files = ["Manifest", "lib/smusher.rb", "spec/out/people.jpg", "spec/spec_helper.rb", "spec/smusher_spec.rb", "spec/images/logo.gif", "spec/images/woman.jpeg", "spec/images/add.png", "spec/images/drink_empty.png", "spec/images/people.jpg", "spec/images/water.JPG", "spec/reduced/fam.png", "spec/reduced/add.png", "bin/smusher", "Rakefile", "README.markdown", "smusher.gemspec"]
16
- s.has_rdoc = true
17
- s.homepage = %q{http://github.com/grosser/smusher}
18
- s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Smusher", "--main", "README.markdown"]
19
- s.require_paths = ["lib"]
20
- s.rubyforge_project = %q{smusher}
21
- s.rubygems_version = %q{1.3.1}
22
- s.summary = %q{Automatic Lossless Reduction Of All Your Images}
5
+ --- !ruby/object:Gem::Specification
6
+ name: smusher
7
+ version: !ruby/object:Gem::Version
8
+ version: 0.3.3
9
+ platform: ruby
10
+ authors:
11
+ - Michael Grosser
12
+ autorequire:
13
+ bindir: bin
23
14
 
24
- if s.respond_to? :specification_version then
25
- current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
26
- s.specification_version = 2
15
+ date: 2009-01-30 00:00:00 +01:00
16
+ default_executable:
17
+ dependencies:
18
+ - !ruby/object:Gem::Dependency
19
+ name: rake
20
+ type: :runtime
21
+ version_requirement:
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: "0"
27
+ version:
28
+ - !ruby/object:Gem::Dependency
29
+ name: json
30
+ type: :runtime
31
+ version_requirement:
32
+ version_requirements: !ruby/object:Gem::Requirement
33
+ requirements:
34
+ - - ">="
35
+ - !ruby/object:Gem::Version
36
+ version: "0"
37
+ version:
38
+ - !ruby/object:Gem::Dependency
39
+ name: echoe
40
+ type: :development
41
+ version_requirement:
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: "0"
47
+ version:
48
+ description: Automatic Lossless Reduction Of All Your Images
49
+ email: grosser.michael@gmail.com
50
+ executables:
51
+ - smusher
52
+ extensions: []
27
53
 
28
- if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
29
- s.add_runtime_dependency(%q<rake>, [">= 0"])
30
- s.add_runtime_dependency(%q<json>, [">= 0"])
31
- s.add_development_dependency(%q<echoe>, [">= 0"])
32
- else
33
- s.add_dependency(%q<rake>, [">= 0"])
34
- s.add_dependency(%q<json>, [">= 0"])
35
- s.add_dependency(%q<echoe>, [">= 0"])
36
- end
37
- else
38
- s.add_dependency(%q<rake>, [">= 0"])
39
- s.add_dependency(%q<json>, [">= 0"])
40
- s.add_dependency(%q<echoe>, [">= 0"])
41
- end
42
- end
54
+ extra_rdoc_files:
55
+ - bin/smusher
56
+ - lib/smusher.rb
57
+ - README.markdown
58
+ files:
59
+ - bin/smusher
60
+ - lib/smusher.rb
61
+ - README.markdown
62
+ - spec/reduced/fam.png
63
+ - spec/reduced/add.png
64
+ - spec/images/drink_empty.png
65
+ - spec/images/logo.gif
66
+ - spec/images/people.jpg
67
+ - spec/images/add.png
68
+ - spec/images/woman.jpeg
69
+ - spec/images/water.JPG
70
+ - spec/smusher_spec.rb
71
+ - spec/out/people.jpg
72
+ - spec/spec_helper.rb
73
+ - Manifest
74
+ - Rakefile
75
+ - smusher.gemspec
76
+ has_rdoc: true
77
+ homepage: http://github.com/grosser/smusher
78
+ post_install_message:
79
+ rdoc_options:
80
+ - --line-numbers
81
+ - --inline-source
82
+ - --title
83
+ - Smusher
84
+ - --main
85
+ - README.markdown
86
+ require_paths:
87
+ - lib
88
+ required_ruby_version: !ruby/object:Gem::Requirement
89
+ requirements:
90
+ - - ">="
91
+ - !ruby/object:Gem::Version
92
+ version: "0"
93
+ version:
94
+ required_rubygems_version: !ruby/object:Gem::Requirement
95
+ requirements:
96
+ - - ">="
97
+ - !ruby/object:Gem::Version
98
+ version: "1.2"
99
+ version:
100
+ requirements: []
101
+
102
+ rubyforge_project: smusher
103
+ rubygems_version: 1.3.1
104
+ specification_version: 2
105
+ summary: Automatic Lossless Reduction Of All Your Images
106
+ test_files: []
data/spec/images/logo.gif CHANGED
Binary file
data/spec/smusher_spec.rb CHANGED
@@ -2,6 +2,10 @@ ROOT = File.expand_path(File.dirname(__FILE__))
2
2
  require File.join(ROOT,"spec_helper")
3
3
 
4
4
  describe :smusher do
5
+ def copy(image_name)
6
+ FileUtils.cp(File.join(ROOT,'images',image_name), @out)
7
+ end
8
+
5
9
  def size
6
10
  File.size(@file)
7
11
  end
@@ -11,7 +15,7 @@ describe :smusher do
11
15
  @out = File.join(ROOT,'out')
12
16
  FileUtils.rm_r @out, :force=>true
13
17
  FileUtils.mkdir @out
14
- FileUtils.cp(File.join(ROOT,'images','people.jpg'), @out)
18
+ copy 'people.jpg'
15
19
 
16
20
  @file = File.join(@out,'people.jpg')
17
21
  end
@@ -22,26 +26,87 @@ describe :smusher do
22
26
  Smusher.optimize_image(@file)
23
27
  size.should < original_size
24
28
  end
29
+
30
+ it "it does nothing if size stayed the same" do
31
+ original_size = size
32
+ Smusher.expects(:optimized_image_data_for).returns File.read(@file)
33
+ Smusher.optimize_image(@file)
34
+ size.should == original_size
35
+ end
36
+
37
+ it "does not save images whoes size got larger" do
38
+ original_size = size
39
+ Smusher.expects(:optimized_image_data_for).returns File.read(@file)*2
40
+ Smusher.optimize_image(@file)
41
+ size.should == original_size
42
+ end
43
+
44
+ it "does not save images if their size is error-sugesting-small" do
45
+ original_size = size
46
+ Smusher.expects(:optimized_image_data_for).returns 'oops...'
47
+ Smusher.optimize_image(@file)
48
+ size.should == original_size
49
+ end
50
+
51
+ describe "gif handling" do
52
+ before do
53
+ copy 'logo.gif'
54
+ @file = File.join(@out,'logo.gif')
55
+ @file_png = File.join(@out,'logo.png')
56
+ end
57
+ it "stores converted .gifs in .png files" do
58
+ Smusher.optimize_image(@file)
59
+ File.exist?(@file).should == false
60
+ File.exist?(@file_png).should == true
61
+ end
62
+ it "does not rename gifs, if optimizing failed" do
63
+ Smusher.expects(:optimized_image_data_for).returns File.read(@file)
64
+ Smusher.optimize_image(@file)
65
+ File.exist?(@file).should == true
66
+ File.exist?(@file_png).should == false
67
+ end
68
+ end
69
+
70
+ describe 'options' do
71
+ it "does not produce output when :quiet is given" do
72
+ $stdout.expects(:write).never
73
+ Smusher.optimize_image(@file,:quiet=>true)
74
+ end
75
+
76
+ it "raises when an unknown option was given" do
77
+ lambda{Smusher.optimize_image(@file,:q=>true)}.should raise_error
78
+ end
79
+ end
25
80
  end
26
81
 
27
82
  describe :optimize_images_in_folder do
28
83
  before do
29
84
  FileUtils.rm @file
30
85
  @files = []
31
- %w[add.png drink_empty.png].each do |name|
32
- file = File.join(ROOT,'images',name)
33
- @files << File.join(@out,name)
34
- FileUtils.cp file, @out
86
+ %w[add.png drink_empty.png].each do |image_name|
87
+ copy image_name
88
+ @files << File.join(@out,image_name)
35
89
  end
36
90
  @before = @files.map {|f|File.size(f)}
37
91
  end
38
92
 
39
- it "smushes all images" do
93
+ it "optimizes all images" do
40
94
  Smusher.optimize_images_in_folder(@out)
41
95
  new_sizes = @files.map {|f|File.size(f)}
42
- puts new_sizes * ' x '
43
96
  new_sizes.size.times {|i| new_sizes[i].should < @before[i]}
44
97
  end
98
+
99
+ it "does not convert gifs" do
100
+ copy 'logo.gif'
101
+ Smusher.optimize_images_in_folder(@out)
102
+ File.exist?(File.join(@out,'logo.png')).should == false
103
+ end
104
+
105
+ it "converts gifs to png when option was given" do
106
+ copy 'logo.gif'
107
+ Smusher.optimize_images_in_folder(@out,:convert_gifs=>true)
108
+ File.exist?(File.join(@out,'logo.png')).should == true
109
+ end
45
110
  end
46
111
 
47
112
  describe :sanitize_folder do
@@ -67,37 +132,6 @@ describe :smusher do
67
132
  end
68
133
  end
69
134
 
70
- describe :with_protection do
71
- def failure_data
72
- 'x' * (Smusher::SMUSHIT_FAILURE_SIZE-1)
73
- end
74
-
75
- def write(data)
76
- File.open(@file,'w') {|f|f.puts data}
77
- end
78
-
79
- def copy
80
- FileUtils.cp(File.join(ROOT,'images','people.jpg'),@file)
81
- end
82
-
83
- before do
84
- @before = size
85
- @before.should_not == 0
86
- end
87
-
88
- it "reverts a file that got larger" do
89
- Smusher.send(:with_protection,@file) do
90
- write(File.open(@file).read + 'x')
91
- end
92
- @before.should == size
93
- end
94
-
95
- it "reverts a file that got empty" do
96
- Smusher.send(:with_protection,@file){write nil}
97
- size.should == @before
98
- end
99
- end
100
-
101
135
  describe :size do
102
136
  it "find the size of a file" do
103
137
  Smusher.send(:size,@file).should == File.size(@file)
@@ -111,7 +145,7 @@ describe :smusher do
111
145
  describe :logging do
112
146
  it "yields" do
113
147
  val = 0
114
- Smusher.send(:with_logging,@file) {val = 1}
148
+ Smusher.send(:with_logging,@file,false) {val = 1}
115
149
  val.should == 1
116
150
  end
117
151
  end
metadata CHANGED
@@ -1,19 +1,19 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: grosser-smusher
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.2
4
+ version: 0.3.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Grosser
8
8
  autorequire:
9
9
  bindir: bin
10
- cert_chain: []
11
-
12
- date: 2009-01-27 00:00:00 -08:00
13
- default_executable: smusher
10
+ cert_chain:
11
+ date: 2009-01-29 15:00:00 -08:00
12
+ default_executable:
14
13
  dependencies:
15
14
  - !ruby/object:Gem::Dependency
16
15
  name: rake
16
+ type: :runtime
17
17
  version_requirement:
18
18
  version_requirements: !ruby/object:Gem::Requirement
19
19
  requirements:
@@ -23,6 +23,7 @@ dependencies:
23
23
  version:
24
24
  - !ruby/object:Gem::Dependency
25
25
  name: json
26
+ type: :runtime
26
27
  version_requirement:
27
28
  version_requirements: !ruby/object:Gem::Requirement
28
29
  requirements:
@@ -32,6 +33,7 @@ dependencies:
32
33
  version:
33
34
  - !ruby/object:Gem::Dependency
34
35
  name: echoe
36
+ type: :development
35
37
  version_requirement:
36
38
  version_requirements: !ruby/object:Gem::Requirement
37
39
  requirements:
@@ -46,26 +48,26 @@ executables:
46
48
  extensions: []
47
49
 
48
50
  extra_rdoc_files:
49
- - lib/smusher.rb
50
51
  - bin/smusher
52
+ - lib/smusher.rb
51
53
  - README.markdown
52
54
  files:
53
- - Manifest
55
+ - bin/smusher
54
56
  - lib/smusher.rb
55
- - spec/out/people.jpg
56
- - spec/spec_helper.rb
57
- - spec/smusher_spec.rb
58
- - spec/images/logo.gif
59
- - spec/images/woman.jpeg
60
- - spec/images/add.png
57
+ - README.markdown
58
+ - spec/reduced/fam.png
59
+ - spec/reduced/add.png
61
60
  - spec/images/drink_empty.png
61
+ - spec/images/logo.gif
62
62
  - spec/images/people.jpg
63
+ - spec/images/add.png
64
+ - spec/images/woman.jpeg
63
65
  - spec/images/water.JPG
64
- - spec/reduced/fam.png
65
- - spec/reduced/add.png
66
- - bin/smusher
66
+ - spec/smusher_spec.rb
67
+ - spec/out/people.jpg
68
+ - spec/spec_helper.rb
69
+ - Manifest
67
70
  - Rakefile
68
- - README.markdown
69
71
  - smusher.gemspec
70
72
  has_rdoc: true
71
73
  homepage: http://github.com/grosser/smusher