Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pngquant worker #52

Merged
merged 12 commits into from
Aug 18, 2014
12 changes: 9 additions & 3 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,18 @@ script:
before_install:
- sudo apt-get update -qq
- sudo apt-get install -qq advancecomp gifsicle jhead jpegoptim libjpeg-progs optipng pngcrush
- npm install -g svgo
- mkdir ~/bin
# pngquant:
- git clone git://github.com/pornel/pngquant.git
- pushd pngquant && git checkout $(git describe --tags --abbrev=0) && make && popd
- mv pngquant/pngquant ~/bin
# pngout:
- wget http://static.jonof.id.au/dl/kenutils/pngout-20130221-linux.tar.gz
- tar -xzf pngout-*-linux.tar.gz
- mv pngout-*-linux pngout-linux
- npm install -g svgo
- mv pngout-*-linux/x86_64/pngout ~/bin
env:
- PATH=pngout-linux/x86_64:$PATH
- PATH=~/bin:$PATH
matrix:
allow_failures:
- rvm: ruby-head
Expand Down
15 changes: 11 additions & 4 deletions README.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ Optimize (lossless compress) images (jpeg, png, gif, svg) using external utiliti
* [optipng](http://optipng.sourceforge.net/)
* [pngcrush](http://pmt.sourceforge.net/pngcrush/)
* [pngout](http://www.advsys.net/ken/util/pngout.htm)
* [pngquant](http://pngquant.org/)
* [svgo](https://github.com/svg/svgo)

Based on [ImageOptim.app](http://imageoptim.com/).
Expand Down Expand Up @@ -81,13 +82,15 @@ Besides permanently setting environment variables in `~/.profile`, `~/.bash_prof
### Linux - Debian/Ubuntu

```bash
sudo apt-get install -y advancecomp gifsicle jhead jpegoptim libjpeg-progs optipng pngcrush
sudo apt-get install -y advancecomp gifsicle jhead jpegoptim libjpeg-progs optipng pngcrush pngquant
```

If you get an old version of `pngquant`, please check how to install up-to-date version or compile from source at [http://pngquant.org/](http://pngquant.org/).

### Linux - RHEL/Fedora/Centos

```bash
sudo yum install -y advancecomp gifsicle jhead libjpeg optipng
sudo yum install -y advancecomp gifsicle jhead libjpeg optipng pngquant
```

You may also need to install `libjpeg-turbo-utils` instead of `libjpeg`:
Expand Down Expand Up @@ -127,13 +130,13 @@ make && cp -f pngcrush /usr/local/bin
### OS X: Macports

```bash
sudo port install advancecomp gifsicle jhead jpegoptim jpeg optipng pngcrush
sudo port install advancecomp gifsicle jhead jpegoptim jpeg optipng pngcrush pngquant
```

### OS X: Brew

```bash
brew install advancecomp gifsicle jhead jpegoptim jpeg optipng pngcrush
brew install advancecomp gifsicle jhead jpegoptim jpeg optipng pngcrush pngquant
```

### pngout installation (optional)
Expand Down Expand Up @@ -256,6 +259,10 @@ Worker can be disabled by passing `false` instead of options hash.
### :advpng =>
* `:level` — Compression level: `0` - don't compress, `1` - fast, `2` - normal, `3` - extra, `4` - extreme *(defaults to `4`)*

### :pngquant =>
* `:quality` — min..max - don't save below min, use less colors below max (both in range `0..100`; in yaml - `!ruby/range 0..100`) *(defaults to `100..100`)*
* `:speed` — speed/quality trade-off: `1` - slow, `3` - default, `11` - fast & rough *(defaults to `3`)*

### :jhead =>
Worker has no options

Expand Down
4 changes: 4 additions & 0 deletions bin/image_optim
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@

require 'image_optim/runner'
require 'image_optim/true_false_nil'
require 'image_optim/non_negative_integer_range'

options = {}

option_parser = OptionParser.new do |op|
ImageOptim::TrueFalseNil.add_to_option_parser(op)
ImageOptim::NonNegativeIntegerRange.add_to_option_parser(op)

op.banner = <<-TEXT.gsub(/^\s*\|/, '')
|#{ImageOptim.full_version}
Expand Down Expand Up @@ -66,6 +68,8 @@ option_parser = OptionParser.new do |op|
[Integer, 'N']
when Array >= type
[Array, 'a,b,c']
when ImageOptim::NonNegativeIntegerRange == type
[type, 'M-N']
else
fail "Unknown type #{type}"
end
Expand Down
2 changes: 1 addition & 1 deletion image_optim.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
Gem::Specification.new do |s|
s.name = 'image_optim'
s.version = '0.14.0'
s.summary = %q{Optimize (lossless compress) images (jpeg, png, gif, svg) using external utilities (advpng, gifsicle, jpegoptim, jpegtran, optipng, pngcrush, pngout, svgo)}
s.summary = %q{Optimize (lossless compress) images (jpeg, png, gif, svg) using external utilities (advpng, gifsicle, jpegoptim, jpegtran, optipng, pngcrush, pngout, pngquant, svgo)}
s.homepage = "http://github.com/toy/#{s.name}"
s.authors = ['Ivan Kuchin']
s.license = 'MIT'
Expand Down
2 changes: 1 addition & 1 deletion lib/image_optim.rb
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ def apply_threading(enum)
end

%w[
pngcrush pngout optipng advpng
pngcrush pngout optipng advpng pngquant
jhead jpegoptim jpegtran
gifsicle
svgo
Expand Down
9 changes: 8 additions & 1 deletion lib/image_optim/bin_resolver.rb
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ def accessible?(name)

def version(name)
case name.to_sym
when :advpng, :gifsicle, :jpegoptim, :optipng
when :advpng, :gifsicle, :jpegoptim, :optipng, :pngquant
capture_output("#{name} --version")[/\d+(\.\d+){1,}/]
when :svgo
capture_output("#{name} --version 2>&1")[/\d+(\.\d+){1,}/]
Expand Down Expand Up @@ -114,6 +114,13 @@ def check!(bin)
when c = is < '1.17'
warn "Note that `#{bin}` (#{c}) does not use zopfli"
end
when :pngquant
case bin.version
when c = is < '2.0'
fail BadBinVersion, "`#{bin}` (#{c}) is not supported"
when c = is < '2.1'
warn "Note that `#{bin}` (#{c}) may be lossy even with quality `100-`"
end
end
end

Expand Down
11 changes: 11 additions & 0 deletions lib/image_optim/non_negative_integer_range.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
class ImageOptim
# Denote range of non negative integers for worker option
class NonNegativeIntegerRange
# Add handling of range of non negative integers in OptionParser instance
def self.add_to_option_parser(option_parser)
option_parser.accept(self, /(\d+)(?:-|\.\.)(\d+)/) do |_, m, n|
m.to_i..n.to_i
end
end
end
end
43 changes: 43 additions & 0 deletions lib/image_optim/worker/pngquant.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
require 'image_optim/worker'
require 'image_optim/option_helpers'
require 'image_optim/non_negative_integer_range'

class ImageOptim
class Worker
# http://pngquant.org/
class Pngquant < Worker
QUALITY_OPTION =
option(:quality, 100..100, NonNegativeIntegerRange, 'min..max - don\'t '\
'save below min, use less colors below max (both in range `0..100`; '\
'in yaml - `!ruby/range 0..100`)') do |v|
min = OptionHelpers.limit_with_range(v.begin, 0..100)
min..OptionHelpers.limit_with_range(v.end, min..100)
end

SPEED_OPTION =
option(:speed, 3, 'speed/quality trade-off: '\
'`1` - slow, '\
'`3` - default, '\
'`11` - fast & rough') do |v|
OptionHelpers.limit_with_range(v.to_i, 1..11)
end

# Always run first
def run_order
-5
end

def optimize(src, dst)
args = %W[
--quality=#{quality.begin}-#{quality.end}
--speed=#{speed}
--output=#{dst}
--force
--
#{src}
]
execute(:pngquant, *args) && optimized?(src, dst)
end
end
end
end
Binary file added spec/images/quant/64.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
25 changes: 25 additions & 0 deletions spec/images/quant/generate
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#!/usr/bin/env ruby

Dir.chdir(File.dirname(__FILE__))

require 'shellwords'

palettes = [64]
side = 256

palettes.each do |palette|
IO.popen(%W[
convert
-depth 8
-size #{side}x#{side}
-strip
rgb:-
PNG24:#{palette}.png
].shelljoin, 'w') do |f|
(side * side).times do |i|
color = i * palette / (side * side) * 0x10000 / palette
f << [color / 0x100, color % 0x100, 0].pack('C*')
end
end
system "identify -format 'Wrote %f with %k unique colors\n' #{palette}.png"
end