grosser-smusher 0.3.2 → 0.3.3

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/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