image_optim 0.3.2 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -4,6 +4,40 @@ Optimize images (jpeg, png, gif) using external utilities (advpng, gifsicle, jpe
4
4
 
5
5
  Based on [ImageOptim.app](http://imageoptim.pornel.net/).
6
6
 
7
+ ## Usage
8
+
9
+ In terminal:
10
+
11
+ image_optim *.{jpg,png,gif}
12
+
13
+ image_optim -h
14
+
15
+ Initilize optimizer (options are described in comments for ImageOptim, Worker and all workers):
16
+
17
+ io = ImageOptim.new
18
+
19
+ io = ImageOptim.new(:pngout => false)
20
+
21
+ io = ImageOptim.new(:nice => 20)
22
+
23
+ Optimize image getting temp path:
24
+
25
+ io.optimize_image('a.png')
26
+
27
+ Optimize image in place:
28
+
29
+ io.optimize_image('b.jpg')
30
+
31
+ Multiple images:
32
+
33
+ io.optimize_images(Dir['*.png']) do |unoptimized, optimized|
34
+ if optimized
35
+ puts "#{unoptimized} => #{optimized}"
36
+ end
37
+ end
38
+
39
+ io.optimize_images!(Dir['*.*'])
40
+
7
41
  ## Copyright
8
42
 
9
43
  Copyright (c) 2012 Ivan Kuchin. See LICENSE.txt for details.
data/TODO CHANGED
@@ -1,3 +1 @@
1
- allow setting nice level?
2
1
  timeout workers?
3
- cyclic run until got maximum optimization?
@@ -20,6 +20,10 @@ Usege:
20
20
  options[:threads] = threads
21
21
  end
22
22
 
23
+ op.on('--[no-]nice NUMBER', Integer, 'Nice levle (defaults to 10)') do |nice|
24
+ options[:nice] = nice
25
+ end
26
+
23
27
  ImageOptim::Worker.klasses.each do |klass|
24
28
  bin = klass.underscored_name.to_sym
25
29
  op.on("--[no-]#{bin} PATH", "#{bin} path or disable") do |path|
@@ -2,7 +2,7 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = 'image_optim'
5
- s.version = '0.3.2'
5
+ s.version = '0.4.0'
6
6
  s.summary = %q{Optimize images (jpeg, png, gif) using external utilities (advpng, gifsicle, jpegoptim, jpegtran, optipng, pngcrush, pngout)}
7
7
  s.homepage = "http://github.com/toy/#{s.name}"
8
8
  s.authors = ['Ivan Kuchin']
@@ -27,7 +27,35 @@ class ImageOptim
27
27
  # or hash with options to worker and :bin specifying binary
28
28
  #
29
29
  # ImageOptim.new(:advpng => {:level => 3}, :optipng => {:level => 2}, :jpegoptim => {:bin => 'jpegoptim345'})
30
+ #
31
+ # use :threads to set number of parallel optimizers to run (passing true or nil determines number of processors, false disables parallel processing)
32
+ #
33
+ # ImageOptim.new(:threads => 8)
34
+ #
35
+ # use :nice to specify optimizers nice level (true or nil makes it 10, false makes it 0)
36
+ #
37
+ # ImageOptim.new(:threads => 8)
30
38
  def initialize(options = {})
39
+ nice = case nice = options.delete(:nice)
40
+ when true, nil
41
+ 10
42
+ when false
43
+ 0
44
+ else
45
+ nice.to_i
46
+ end
47
+
48
+ threads = options.delete(:threads)
49
+ threads = case threads
50
+ when true, nil
51
+ Util.processor_count
52
+ when false
53
+ 1
54
+ else
55
+ threads.to_i
56
+ end
57
+ @threads = limit_with_range(threads, 1..16)
58
+
31
59
  @workers_by_format = {}
32
60
  Worker.klasses.each do |klass|
33
61
  case worker_options = options.delete(klass.underscored_name.to_sym)
@@ -41,7 +69,7 @@ class ImageOptim
41
69
  else
42
70
  raise "Got #{worker_options.inspect} for #{klass.name} options"
43
71
  end
44
- worker = klass.new(worker_options)
72
+ worker = klass.new({:nice => nice}.merge(worker_options))
45
73
  klass.image_formats.each do |format|
46
74
  @workers_by_format[format] ||= []
47
75
  @workers_by_format[format] << worker
@@ -51,17 +79,6 @@ class ImageOptim
51
79
  workers.replace workers.sort_by(&:run_priority)
52
80
  end
53
81
 
54
- threads = options.delete(:threads)
55
- threads = case threads
56
- when true, nil
57
- Util.processor_count
58
- when false
59
- 1
60
- else
61
- threads.to_i
62
- end
63
- @threads = limit_with_range(threads, 1..16)
64
-
65
82
  assert_options_empty!(options)
66
83
  end
67
84
 
@@ -2,15 +2,6 @@ require 'shellwords'
2
2
 
3
3
  class ImageOptim
4
4
  module Util
5
- # Run command redirecting both stdout and stderr to /dev/null, raising signal if command was signaled and return successfulness
6
- def self.run(*args)
7
- res = system "#{args.map(&:to_s).shelljoin} &> /dev/null"
8
- if $?.signaled?
9
- raise SignalException.new($?.termsig)
10
- end
11
- res
12
- end
13
-
14
5
  # http://stackoverflow.com/questions/891537/ruby-detect-number-of-cpus-installed
15
6
  def self.processor_count
16
7
  @processor_count ||= case host_os = RbConfig::CONFIG['host_os']
@@ -31,9 +31,13 @@ class ImageOptim
31
31
  # Binary name or path
32
32
  attr_reader :bin
33
33
 
34
+ # Binary name or path
35
+ attr_reader :nice
36
+
34
37
  # Configure (raises on extra options), find binary (raises if not found)
35
38
  def initialize(options = {})
36
39
  get_option!(options, :bin, default_bin)
40
+ get_option!(options, :nice, 10){ |v| v.to_i }
37
41
  parse_options(options)
38
42
  raise "`#{bin}` not found" if `which #{bin.to_s.shellescape}`.empty?
39
43
  assert_options_empty!(options)
@@ -43,20 +47,29 @@ class ImageOptim
43
47
  def run_first?
44
48
  end
45
49
 
46
- # Optimize file, return new path or nil if optimization failed
50
+ # Priority in list of workers
51
+ def run_priority
52
+ run_first? ? 0 : 1
53
+ end
54
+
55
+ # Optimize file from src to dst, return boolean representing success status
47
56
  def optimize(src, dst)
48
- Util.run(bin, *command_args(src, dst)) && dst.size? && dst.size < src.size
57
+ pid = fork do
58
+ $stdout.reopen('/dev/null', 'w')
59
+ $stderr.reopen('/dev/null', 'w')
60
+ Process.setpriority(Process::PRIO_PROCESS, 0, nice)
61
+ exec bin, *command_args(src, dst)
62
+ end
63
+ Process.wait pid
64
+ if $?.signaled?
65
+ raise SignalException.new($?.termsig)
66
+ end
67
+ $?.success? && dst.size? && dst.size < src.size
49
68
  end
50
69
 
51
70
  # Name of binary determined from class name
52
71
  def default_bin
53
72
  self.class.underscored_name
54
73
  end
55
-
56
- private
57
-
58
- def run_priority
59
- run_first? ? 0 : 1
60
- end
61
74
  end
62
75
  end
@@ -13,7 +13,7 @@ def temp_copy_path(original)
13
13
  end
14
14
  end
15
15
 
16
- Tempfile.class_eval do
16
+ class Tempfile
17
17
  alias_method :initialize_orig, :initialize
18
18
 
19
19
  def initialize(*args, &block)
@@ -141,14 +141,14 @@ describe ImageOptim do
141
141
  describe "given block" do
142
142
  it "should optimize images, yield path and result for each and return array of yield results" do
143
143
  io = ImageOptim.new
144
+ results = []
144
145
  srcs.each do |src|
145
- io.should_receive(single_method).with(src).and_return("#{src}_")
146
+ dst = "#{src}_"
147
+ io.should_receive(single_method).with(src).and_return(dst)
148
+ results << "#{src} #{dst}"
146
149
  end
147
- results = []
148
150
  io.send(list_method, srcs) do |src, dst|
149
- result = "#{src} #{dst}"
150
- results << "#{src} #{dst}"
151
- result
151
+ "#{src} #{dst}"
152
152
  end.should == results
153
153
  end
154
154
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: image_optim
3
3
  version: !ruby/object:Gem::Version
4
- hash: 23
4
+ hash: 15
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
- - 3
9
- - 2
10
- version: 0.3.2
8
+ - 4
9
+ - 0
10
+ version: 0.4.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Ivan Kuchin
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2012-01-12 00:00:00 Z
18
+ date: 2012-01-13 00:00:00 Z
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
21
  name: fspath