openstreetmap-image_optim 0.21.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 +17 -0
- data/.rubocop.yml +65 -0
- data/.travis.yml +42 -0
- data/CHANGELOG.markdown +272 -0
- data/CONTRIBUTING.markdown +10 -0
- data/Gemfile +9 -0
- data/LICENSE.txt +20 -0
- data/README.markdown +344 -0
- data/Vagrantfile +33 -0
- data/bin/image_optim +28 -0
- data/image_optim.gemspec +29 -0
- data/lib/image_optim.rb +228 -0
- data/lib/image_optim/bin_resolver.rb +144 -0
- data/lib/image_optim/bin_resolver/bin.rb +105 -0
- data/lib/image_optim/bin_resolver/comparable_condition.rb +60 -0
- data/lib/image_optim/bin_resolver/error.rb +6 -0
- data/lib/image_optim/bin_resolver/simple_version.rb +31 -0
- data/lib/image_optim/cmd.rb +49 -0
- data/lib/image_optim/config.rb +205 -0
- data/lib/image_optim/configuration_error.rb +3 -0
- data/lib/image_optim/handler.rb +57 -0
- data/lib/image_optim/hash_helpers.rb +45 -0
- data/lib/image_optim/image_meta.rb +25 -0
- data/lib/image_optim/image_path.rb +68 -0
- data/lib/image_optim/non_negative_integer_range.rb +11 -0
- data/lib/image_optim/option_definition.rb +32 -0
- data/lib/image_optim/option_helpers.rb +17 -0
- data/lib/image_optim/railtie.rb +38 -0
- data/lib/image_optim/runner.rb +139 -0
- data/lib/image_optim/runner/glob_helpers.rb +45 -0
- data/lib/image_optim/runner/option_parser.rb +227 -0
- data/lib/image_optim/space.rb +29 -0
- data/lib/image_optim/true_false_nil.rb +16 -0
- data/lib/image_optim/worker.rb +159 -0
- data/lib/image_optim/worker/advpng.rb +35 -0
- data/lib/image_optim/worker/class_methods.rb +91 -0
- data/lib/image_optim/worker/gifsicle.rb +63 -0
- data/lib/image_optim/worker/jhead.rb +43 -0
- data/lib/image_optim/worker/jpegoptim.rb +58 -0
- data/lib/image_optim/worker/jpegrecompress.rb +44 -0
- data/lib/image_optim/worker/jpegtran.rb +46 -0
- data/lib/image_optim/worker/optipng.rb +45 -0
- data/lib/image_optim/worker/pngcrush.rb +54 -0
- data/lib/image_optim/worker/pngout.rb +38 -0
- data/lib/image_optim/worker/pngquant.rb +51 -0
- data/lib/image_optim/worker/svgo.rb +32 -0
- data/script/template/jquery-2.1.3.min.js +4 -0
- data/script/template/sortable-0.6.0.min.js +2 -0
- data/script/template/worker_analysis.erb +254 -0
- data/script/update_worker_options_in_readme +60 -0
- data/script/worker_analysis +599 -0
- data/spec/image_optim/bin_resolver/comparable_condition_spec.rb +37 -0
- data/spec/image_optim/bin_resolver/simple_version_spec.rb +57 -0
- data/spec/image_optim/bin_resolver_spec.rb +272 -0
- data/spec/image_optim/cmd_spec.rb +66 -0
- data/spec/image_optim/config_spec.rb +217 -0
- data/spec/image_optim/handler_spec.rb +95 -0
- data/spec/image_optim/hash_helpers_spec.rb +76 -0
- data/spec/image_optim/image_path_spec.rb +54 -0
- data/spec/image_optim/railtie_spec.rb +121 -0
- data/spec/image_optim/runner/glob_helpers_spec.rb +25 -0
- data/spec/image_optim/runner/option_parser_spec.rb +99 -0
- data/spec/image_optim/space_spec.rb +25 -0
- data/spec/image_optim/worker_spec.rb +192 -0
- data/spec/image_optim_spec.rb +242 -0
- data/spec/images/comparison.png +0 -0
- data/spec/images/decompressed.jpeg +0 -0
- data/spec/images/icecream.gif +0 -0
- data/spec/images/image.jpg +0 -0
- data/spec/images/invisiblepixels/generate +24 -0
- data/spec/images/invisiblepixels/image.png +0 -0
- data/spec/images/lena.jpg +0 -0
- data/spec/images/orient/0.jpg +0 -0
- data/spec/images/orient/1.jpg +0 -0
- data/spec/images/orient/2.jpg +0 -0
- data/spec/images/orient/3.jpg +0 -0
- data/spec/images/orient/4.jpg +0 -0
- data/spec/images/orient/5.jpg +0 -0
- data/spec/images/orient/6.jpg +0 -0
- data/spec/images/orient/7.jpg +0 -0
- data/spec/images/orient/8.jpg +0 -0
- data/spec/images/orient/generate +23 -0
- data/spec/images/orient/original.jpg +0 -0
- data/spec/images/quant/64.png +0 -0
- data/spec/images/quant/generate +25 -0
- data/spec/images/rails.png +0 -0
- data/spec/images/test.svg +3 -0
- data/spec/images/transparency1.png +0 -0
- data/spec/images/transparency2.png +0 -0
- data/spec/images/vergroessert.jpg +0 -0
- data/spec/spec_helper.rb +64 -0
- data/vendor/jpegrescan +143 -0
- metadata +308 -0
data/README.markdown
ADDED
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
[](https://rubygems.org/gems/image_optim)
|
|
2
|
+
[](https://travis-ci.org/toy/image_optim)
|
|
3
|
+
[](https://codeclimate.com/github/toy/image_optim)
|
|
4
|
+
[](https://codeclimate.com/github/toy/image_optim)
|
|
5
|
+
[](https://gemnasium.com/toy/image_optim)
|
|
6
|
+
[](http://inch-ci.org/github/toy/image_optim)
|
|
7
|
+
|
|
8
|
+
# image_optim
|
|
9
|
+
|
|
10
|
+
Optimize (lossless compress, optionally lossy) images (jpeg, png, gif, svg) using external utilities:
|
|
11
|
+
|
|
12
|
+
* [advpng](http://advancemame.sourceforge.net/doc-advpng.html) from [AdvanceCOMP](http://advancemame.sourceforge.net/comp-readme.html)
|
|
13
|
+
(will use [zopfli](https://code.google.com/p/zopfli/) on default/maximum level 4)
|
|
14
|
+
* [gifsicle](http://www.lcdf.org/gifsicle/)
|
|
15
|
+
* [jhead](http://www.sentex.net/~mwandel/jhead/)
|
|
16
|
+
* [jpegoptim](http://www.kokkonen.net/tjko/projects.html)
|
|
17
|
+
* [jpeg-recompress](https://github.com/danielgtaylor/jpeg-archive#jpeg-recompress)
|
|
18
|
+
* jpegtran from [Independent JPEG Group's JPEG library](http://www.ijg.org/)
|
|
19
|
+
* [optipng](http://optipng.sourceforge.net/)
|
|
20
|
+
* [pngcrush](http://pmt.sourceforge.net/pngcrush/)
|
|
21
|
+
* [pngout](http://www.advsys.net/ken/util/pngout.htm)
|
|
22
|
+
* [pngquant](http://pngquant.org/)
|
|
23
|
+
* [svgo](https://github.com/svg/svgo)
|
|
24
|
+
|
|
25
|
+
Based on [ImageOptim.app](http://imageoptim.com/).
|
|
26
|
+
|
|
27
|
+
Documentation for [latest version](http://rubydoc.info/gems/image_optim/frames) and [master](http://rubydoc.info/github/toy/image_optim/master/frames).
|
|
28
|
+
|
|
29
|
+
## Gem installation
|
|
30
|
+
|
|
31
|
+
```sh
|
|
32
|
+
gem install image_optim
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
You may also want to install [`image_optim_pack`](https://github.com/toy/image_optim_pack) (see [Binaries pack](#binaries-pack)).
|
|
36
|
+
|
|
37
|
+
```sh
|
|
38
|
+
gem install image_optim_pack
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Bundler
|
|
42
|
+
|
|
43
|
+
Add to your `Gemfile`:
|
|
44
|
+
|
|
45
|
+
```ruby
|
|
46
|
+
gem 'image_optim'
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
With `image_optim_pack`:
|
|
50
|
+
|
|
51
|
+
```ruby
|
|
52
|
+
gem 'image_optim'
|
|
53
|
+
gem 'image_optim_pack'
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
With version:
|
|
57
|
+
|
|
58
|
+
```ruby
|
|
59
|
+
gem 'image_optim', '~> 0.11'
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
If you want to check latest changes:
|
|
63
|
+
|
|
64
|
+
```ruby
|
|
65
|
+
gem 'image_optim', :git => 'git://github.com/toy/image_optim.git'
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Binaries location
|
|
69
|
+
|
|
70
|
+
Simplest way for `image_optim` to locate binaries is to install them in common location present in `PATH` (see [Binaries installation](#binaries-installation)).
|
|
71
|
+
|
|
72
|
+
If you cannot install to common location, then install to custom one and add it to `PATH`.
|
|
73
|
+
|
|
74
|
+
Specify custom bin location using `XXX_BIN` environment variable (`JPEGOPTIM_BIN`, `OPTIPNG_BIN`, …).
|
|
75
|
+
|
|
76
|
+
Besides permanently setting environment variables in `~/.profile`, `~/.bash_profile`, `~/.bashrc`, `~/.zshrc`, … they can be set:
|
|
77
|
+
|
|
78
|
+
* before command:
|
|
79
|
+
|
|
80
|
+
`PATH="/custom/location:$PATH" image_optim *.jpg`
|
|
81
|
+
|
|
82
|
+
for example:
|
|
83
|
+
|
|
84
|
+
`PATH="/Applications/ImageOptim.app/Contents/MacOS:$PATH" image_optim *.jpg`
|
|
85
|
+
|
|
86
|
+
* inside script:
|
|
87
|
+
|
|
88
|
+
`ENV['PATH'] = "/custom/location:#{ENV['PATH']}"; ImageOptim.optimize_images([…])`
|
|
89
|
+
|
|
90
|
+
for example:
|
|
91
|
+
|
|
92
|
+
`ENV['PATH'] = "/Applications/ImageOptim.app/Contents/MacOS:#{ENV['PATH']}"; ImageOptim.optimize_images([…])`
|
|
93
|
+
|
|
94
|
+
## Binaries installation
|
|
95
|
+
|
|
96
|
+
### Binaries pack
|
|
97
|
+
|
|
98
|
+
Easiest way to get latest versions of most binaries for `image_optim` for Linux and Mac OS X is by installing [`image_optim_pack`](https://github.com/toy/image_optim_pack) gem.
|
|
99
|
+
|
|
100
|
+
Check installation instructions in [Gem installation](#gem-installation) section.
|
|
101
|
+
|
|
102
|
+
Pack doesn't include `pngout` and `svgo` binaries, their installation instructions are provided below.
|
|
103
|
+
|
|
104
|
+
### Linux - Debian/Ubuntu
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
sudo apt-get install -y advancecomp gifsicle jhead jpegoptim libjpeg-progs optipng pngcrush pngquant
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
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/).
|
|
111
|
+
|
|
112
|
+
### Linux - RHEL/Fedora/Centos
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
sudo yum install -y advancecomp gifsicle jhead libjpeg optipng pngquant
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
You may also need to install `libjpeg-turbo-utils` instead of `libjpeg`:
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
sudo yum install -y libjpeg-turbo-utils
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
You will also need to install `jpegoptim` and `pngcrush` from source:
|
|
125
|
+
|
|
126
|
+
#### jpegoptim
|
|
127
|
+
|
|
128
|
+
Replace `X.Y.Z` with latest version number from http://www.kokkonen.net/tjko/projects.html#jpegoptim.
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
JPEGOPTIM_VERSION=X.Y.Z
|
|
132
|
+
cd /tmp
|
|
133
|
+
curl -O http://www.kokkonen.net/tjko/src/jpegoptim-$JPEGOPTIM_VERSION.tar.gz
|
|
134
|
+
tar zxf jpegoptim-$JPEGOPTIM_VERSION.tar.gz
|
|
135
|
+
cd jpegoptim-$JPEGOPTIM_VERSION
|
|
136
|
+
./configure && make && make install
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
#### pngcrush
|
|
140
|
+
|
|
141
|
+
Replace `X.Y.Z` with latest version number from http://sourceforge.net/projects/pmt/files/pngcrush/.
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
PNGCRUSH_VERSION=X.Y.Z
|
|
145
|
+
cd /tmp
|
|
146
|
+
curl -O http://iweb.dl.sourceforge.net/project/pmt/pngcrush/$PNGCRUSH_VERSION/pngcrush-$PNGCRUSH_VERSION.tar.gz
|
|
147
|
+
tar zxf pngcrush-$PNGCRUSH_VERSION.tar.gz
|
|
148
|
+
cd pngcrush-$PNGCRUSH_VERSION
|
|
149
|
+
make && cp -f pngcrush /usr/local/bin
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### OS X: Macports
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
sudo port install advancecomp gifsicle jhead jpegoptim jpeg optipng pngcrush pngquant
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
### OS X: Brew
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
brew install advancecomp gifsicle jhead jpegoptim jpeg optipng pngcrush pngquant
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### pngout installation (optional)
|
|
165
|
+
|
|
166
|
+
You can install `pngout` by downloading and installing the [binary versions](http://www.jonof.id.au/kenutils).
|
|
167
|
+
|
|
168
|
+
_Note: pngout is free to use even in commercial soft, but you can not redistribute, repackage or reuse it without consent and agreement of creator. [license](http://advsys.net/ken/utils.htm#pngoutkziplicense)_
|
|
169
|
+
|
|
170
|
+
### svgo installation (optional)
|
|
171
|
+
|
|
172
|
+
`svgo` is available from NPM.
|
|
173
|
+
|
|
174
|
+
```bash
|
|
175
|
+
npm install -g svgo
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### jpeg-recompress installation (optional)
|
|
179
|
+
|
|
180
|
+
Download and install the `jpeg-recompress` binary from the [JPEG-Archive Releases](https://github.com/danielgtaylor/jpeg-archive/releases) page,
|
|
181
|
+
or follow the instructions to [build from source](https://github.com/danielgtaylor/jpeg-archive#building).
|
|
182
|
+
|
|
183
|
+
## Usage
|
|
184
|
+
|
|
185
|
+
### From shell
|
|
186
|
+
|
|
187
|
+
```sh
|
|
188
|
+
image_optim *.{jpg,png,gif,svg}
|
|
189
|
+
|
|
190
|
+
image_optim -r .
|
|
191
|
+
|
|
192
|
+
image_optim -h
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### From ruby
|
|
196
|
+
|
|
197
|
+
Initialize optimizer (or you can call optimization methods directly on `ImageOptim`):
|
|
198
|
+
|
|
199
|
+
```ruby
|
|
200
|
+
image_optim = ImageOptim.new
|
|
201
|
+
|
|
202
|
+
image_optim = ImageOptim.new(:pngout => false)
|
|
203
|
+
|
|
204
|
+
image_optim = ImageOptim.new(:nice => 20)
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
Optimize image getting temp path:
|
|
208
|
+
|
|
209
|
+
```ruby
|
|
210
|
+
image_optim.optimize_image('a.png')
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
Optimize image in place:
|
|
214
|
+
|
|
215
|
+
```ruby
|
|
216
|
+
image_optim.optimize_image!('b.jpg')
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
Optimize image data:
|
|
220
|
+
|
|
221
|
+
```ruby
|
|
222
|
+
image_optim.optimize_image_data(data)
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
Multiple images:
|
|
226
|
+
|
|
227
|
+
```ruby
|
|
228
|
+
image_optim.optimize_images(Dir['*.png']) do |unoptimized, optimized|
|
|
229
|
+
if optimized
|
|
230
|
+
puts "#{unoptimized} => #{optimized}"
|
|
231
|
+
end
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
image_optim.optimize_images!(Dir['*.*'])
|
|
235
|
+
|
|
236
|
+
image_optim.optimize_images_data(datas)
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
### From rails
|
|
240
|
+
|
|
241
|
+
`ImageOptim::Railtie` will automatically register sprockets preprocessor unless you set `config.assets.image_optim = false` or `config.assets.compress = false` (later for partial rails 3 compatibility).
|
|
242
|
+
|
|
243
|
+
You can provide options for image_optim used for preprocessor through config `config.assets.image_optim = {nice: 20, svgo: false}` (ruby1.8 style: `{:nice => 20, :svgo => false}`).
|
|
244
|
+
Check available options in [options section](#options).
|
|
245
|
+
|
|
246
|
+
Image optimization can be time consuming, so depending on your deployment process you may prefer to optimize original asset files.
|
|
247
|
+
|
|
248
|
+
## Configuration
|
|
249
|
+
|
|
250
|
+
Configuration in YAML format will be read and prepended to options from two paths:
|
|
251
|
+
|
|
252
|
+
* `$XDG_CONFIG_HOME/image_optim.yml` (by default `~/.config/image_optim.yml`)
|
|
253
|
+
* `.image_optim.yml` in current working directory
|
|
254
|
+
|
|
255
|
+
Paths can be changed using `:config_paths` option and `--config-paths` argument.
|
|
256
|
+
|
|
257
|
+
Example configuration:
|
|
258
|
+
|
|
259
|
+
```yaml
|
|
260
|
+
nice: 20
|
|
261
|
+
pngout: false # disable
|
|
262
|
+
optipng:
|
|
263
|
+
level: 5
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
## Options
|
|
267
|
+
|
|
268
|
+
* `:nice` — Nice level *(defaults to `10`)*
|
|
269
|
+
* `:threads` — Number of threads or disable *(defaults to number of processors)*
|
|
270
|
+
* `:verbose` — Verbose output *(defaults to `false`)*
|
|
271
|
+
* `:pack` — Require image\_optim\_pack or disable it, by default image\_optim\_pack will be used if available, will turn on `:skip-missing-workers` unless explicitly disabled *(defaults to `nil`)*
|
|
272
|
+
* `:skip_missing_workers` — Skip workers with missing or problematic binaries *(defaults to `false`)*
|
|
273
|
+
* `:allow_lossy` — Allow lossy workers and optimizations *(defaults to `false`)*
|
|
274
|
+
|
|
275
|
+
Worker can be disabled by passing `false` instead of options hash or by setting option `:disable` to `true`.
|
|
276
|
+
|
|
277
|
+
<!---<worker-options>-->
|
|
278
|
+
<!-- markdown for worker options is generated by `script/update_worker_options_in_readme` -->
|
|
279
|
+
|
|
280
|
+
### :advpng =>
|
|
281
|
+
* `:level` — Compression level: `0` - don't compress, `1` - fast, `2` - normal, `3` - extra, `4` - extreme *(defaults to `4`)*
|
|
282
|
+
|
|
283
|
+
### :gifsicle =>
|
|
284
|
+
* `:interlace` — Interlace: `true` - interlace on, `false` - interlace off, `nil` - as is in original image (defaults to running two instances, one with interlace off and one with on)
|
|
285
|
+
* `:level` — Compression level: `1` - light and fast, `2` - normal, `3` - heavy (slower) *(defaults to `3`)*
|
|
286
|
+
* `:careful` — Avoid bugs with some software *(defaults to `false`)*
|
|
287
|
+
|
|
288
|
+
### :jhead =>
|
|
289
|
+
Worker has no options
|
|
290
|
+
|
|
291
|
+
### :jpegoptim =>
|
|
292
|
+
* `:strip` — List of extra markers to strip: `:comments`, `:exif`, `:iptc`, `:icc` or `:all` *(defaults to `:all`)*
|
|
293
|
+
* `:max_quality` — Maximum image quality factor `0`..`100`, ignored in default/lossless mode *(defaults to `100`)*
|
|
294
|
+
|
|
295
|
+
### :jpegrecompress =>
|
|
296
|
+
* `:quality` — JPEG quality preset: `0` - low, `1` - medium, `2` - high, `3` - veryhigh *(defaults to `3`)*
|
|
297
|
+
|
|
298
|
+
### :jpegtran =>
|
|
299
|
+
* `:copy_chunks` — Copy all chunks *(defaults to `false`)*
|
|
300
|
+
* `:progressive` — Create progressive JPEG file *(defaults to `true`)*
|
|
301
|
+
* `:jpegrescan` — Use jpegtran through jpegrescan, ignore progressive option *(defaults to `false`)*
|
|
302
|
+
|
|
303
|
+
### :optipng =>
|
|
304
|
+
* `:level` — Optimization level preset: `0` is least, `7` is best *(defaults to `6`)*
|
|
305
|
+
* `:interlace` — Interlace: `true` - interlace on, `false` - interlace off, `nil` - as is in original image *(defaults to `false`)*
|
|
306
|
+
* `:strip` — Remove all auxiliary chunks *(defaults to `true`)*
|
|
307
|
+
|
|
308
|
+
### :pngcrush =>
|
|
309
|
+
* `:chunks` — List of chunks to remove or `:alla` - all except tRNS/transparency or `:allb` - all except tRNS and gAMA/gamma *(defaults to `:alla`)*
|
|
310
|
+
* `:fix` — Fix otherwise fatal conditions such as bad CRCs *(defaults to `false`)*
|
|
311
|
+
* `:brute` — Brute force try all methods, very time-consuming and generally not worthwhile *(defaults to `false`)*
|
|
312
|
+
* `:blacken` — Blacken fully transparent pixels *(defaults to `true`)*
|
|
313
|
+
|
|
314
|
+
### :pngout =>
|
|
315
|
+
* `:copy_chunks` — Copy optional chunks *(defaults to `false`)*
|
|
316
|
+
* `:strategy` — Strategy: `0` - xtreme, `1` - intense, `2` - longest Match, `3` - huffman Only, `4` - uncompressed *(defaults to `0`)*
|
|
317
|
+
|
|
318
|
+
### :pngquant =>
|
|
319
|
+
* `:quality` — min..max - don't save below min, use less colors below max (both in range `0..100`; in yaml - `!ruby/range 0..100`), ignored in default/lossless mode *(defaults to `100..100`)*
|
|
320
|
+
* `:speed` — speed/quality trade-off: `1` - slow, `3` - default, `11` - fast & rough *(defaults to `3`)*
|
|
321
|
+
|
|
322
|
+
### :svgo =>
|
|
323
|
+
* `disable_plugins` - List of plugins to disable *(defaults to none)*
|
|
324
|
+
* `enable_plugins` - List of plugins to enable *(defaults to none)*
|
|
325
|
+
|
|
326
|
+
<!---</worker-options>-->
|
|
327
|
+
|
|
328
|
+
## Contributing
|
|
329
|
+
|
|
330
|
+
[List](https://github.com/toy/image_optim/graphs/contributors) of contributors to `image_optim`.
|
|
331
|
+
|
|
332
|
+
If you would like to contribute - that is great and you are very welcome. Please check few notes in file [CONTRIBUTING.markdown](CONTRIBUTING.markdown).
|
|
333
|
+
|
|
334
|
+
Financial contributions can be made via [gratipay](https://gratipay.com/toy/).
|
|
335
|
+
|
|
336
|
+
[](https://gratipay.com/toy/)
|
|
337
|
+
|
|
338
|
+
## ChangeLog
|
|
339
|
+
|
|
340
|
+
In separate file [CHANGELOG.markdown](CHANGELOG.markdown).
|
|
341
|
+
|
|
342
|
+
## Copyright
|
|
343
|
+
|
|
344
|
+
Copyright (c) 2012-2015 Ivan Kuchin. See [LICENSE.txt](LICENSE.txt) for details.
|
data/Vagrantfile
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
VAGRANTFILE_API_VERSION = '2'
|
|
2
|
+
|
|
3
|
+
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
|
|
4
|
+
config.vm.box = 'ubuntu/trusty64'
|
|
5
|
+
|
|
6
|
+
config.vm.provision 'shell', :inline => <<-SH
|
|
7
|
+
set -e
|
|
8
|
+
|
|
9
|
+
cd /vagrant
|
|
10
|
+
|
|
11
|
+
echo 'Install git, node, npm, imagemagick...'
|
|
12
|
+
apt-get install -y git npm nodejs-legacy imagemagick > /dev/null
|
|
13
|
+
|
|
14
|
+
echo 'Update rubygems...'
|
|
15
|
+
REALLY_GEM_UPDATE_SYSTEM=x gem update --system > /dev/null
|
|
16
|
+
|
|
17
|
+
echo 'Install bundler...'
|
|
18
|
+
gem install bundler > /dev/null
|
|
19
|
+
|
|
20
|
+
echo 'Install svgo...'
|
|
21
|
+
npm install -g -q svgo > /dev/null
|
|
22
|
+
|
|
23
|
+
echo 'Install pngout...'
|
|
24
|
+
curl -s \
|
|
25
|
+
'http://static.jonof.id.au/dl/kenutils/pngout-20130221-linux.tar.gz' | \
|
|
26
|
+
tar -xz -C /usr/local/bin --strip-components 2 \
|
|
27
|
+
--wildcards '*/x86_64/pngout'
|
|
28
|
+
|
|
29
|
+
echo 'Bundle...'
|
|
30
|
+
bundle install --jobs=3 --quiet
|
|
31
|
+
bundle list
|
|
32
|
+
SH
|
|
33
|
+
end
|
data/bin/image_optim
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# encoding: UTF-8
|
|
3
|
+
|
|
4
|
+
require 'image_optim/runner'
|
|
5
|
+
require 'image_optim/runner/option_parser'
|
|
6
|
+
|
|
7
|
+
args = ARGV.dup
|
|
8
|
+
|
|
9
|
+
options = ImageOptim::Runner::OptionParser.parse!(args)
|
|
10
|
+
|
|
11
|
+
begin
|
|
12
|
+
if options[:verbose]
|
|
13
|
+
$stderr.puts ImageOptim.full_version
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
only_info = options.delete(:only_info)
|
|
17
|
+
runner = ImageOptim::Runner.new(options)
|
|
18
|
+
unless only_info
|
|
19
|
+
abort 'specify paths to optimize' if args.empty?
|
|
20
|
+
abort unless runner.run!(args)
|
|
21
|
+
end
|
|
22
|
+
rescue => e
|
|
23
|
+
if options[:verbose]
|
|
24
|
+
abort "#{e}\n#{e.backtrace.join("\n")}"
|
|
25
|
+
else
|
|
26
|
+
abort e.to_s
|
|
27
|
+
end
|
|
28
|
+
end
|
data/image_optim.gemspec
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# encoding: UTF-8
|
|
2
|
+
|
|
3
|
+
Gem::Specification.new do |s|
|
|
4
|
+
s.name = 'openstreetmap-image_optim'
|
|
5
|
+
s.version = '0.21.0.1'
|
|
6
|
+
s.summary = %q{Optimize (lossless compress, optionally lossy) images (jpeg, png, gif, svg) using external utilities (advpng, gifsicle, jhead, jpeg-recompress, jpegoptim, jpegrescan, jpegtran, optipng, pngcrush, pngout, pngquant, svgo)}
|
|
7
|
+
s.homepage = "http://github.com/toy/#{s.name}"
|
|
8
|
+
s.authors = ['Ivan Kuchin']
|
|
9
|
+
s.license = 'MIT'
|
|
10
|
+
|
|
11
|
+
s.rubyforge_project = s.name
|
|
12
|
+
|
|
13
|
+
s.files = `git ls-files`.split("\n")
|
|
14
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
|
15
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
|
16
|
+
s.require_paths = %w[lib]
|
|
17
|
+
|
|
18
|
+
s.add_dependency 'fspath', '~> 2.1'
|
|
19
|
+
s.add_dependency 'image_size', '~> 1.3'
|
|
20
|
+
s.add_dependency 'exifr', '~> 1.2', '>= 1.2.2'
|
|
21
|
+
s.add_dependency 'progress', '~> 3.0', '>= 3.0.1'
|
|
22
|
+
s.add_dependency 'in_threads', '~> 1.3'
|
|
23
|
+
|
|
24
|
+
s.add_development_dependency 'image_optim_pack', '~> 0.2'
|
|
25
|
+
s.add_development_dependency 'rspec', '~> 3.0'
|
|
26
|
+
if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('1.9.3')
|
|
27
|
+
s.add_development_dependency 'rubocop', '~> 0.27', '!= 0.30.1'
|
|
28
|
+
end
|
|
29
|
+
end
|
data/lib/image_optim.rb
ADDED
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
require 'image_optim/bin_resolver'
|
|
2
|
+
require 'image_optim/config'
|
|
3
|
+
require 'image_optim/handler'
|
|
4
|
+
require 'image_optim/image_meta'
|
|
5
|
+
require 'image_optim/image_path'
|
|
6
|
+
require 'image_optim/railtie' if defined?(Rails)
|
|
7
|
+
require 'image_optim/worker'
|
|
8
|
+
require 'in_threads'
|
|
9
|
+
require 'shellwords'
|
|
10
|
+
|
|
11
|
+
%w[
|
|
12
|
+
pngcrush pngout advpng optipng pngquant
|
|
13
|
+
jhead jpegoptim jpegrecompress jpegtran
|
|
14
|
+
gifsicle
|
|
15
|
+
svgo
|
|
16
|
+
].each do |worker|
|
|
17
|
+
require "image_optim/worker/#{worker}"
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Main interface
|
|
21
|
+
class ImageOptim
|
|
22
|
+
# Nice level
|
|
23
|
+
attr_reader :nice
|
|
24
|
+
|
|
25
|
+
# Number of threads to run with
|
|
26
|
+
attr_reader :threads
|
|
27
|
+
|
|
28
|
+
# Verbose output?
|
|
29
|
+
attr_reader :verbose
|
|
30
|
+
|
|
31
|
+
# Use image_optim_pack
|
|
32
|
+
attr_reader :pack
|
|
33
|
+
|
|
34
|
+
# Skip workers with missing or problematic binaries
|
|
35
|
+
attr_reader :skip_missing_workers
|
|
36
|
+
|
|
37
|
+
# Allow lossy workers and optimizations
|
|
38
|
+
attr_reader :allow_lossy
|
|
39
|
+
|
|
40
|
+
# Initialize workers, specify options using worker underscored name:
|
|
41
|
+
#
|
|
42
|
+
# pass false to disable worker
|
|
43
|
+
#
|
|
44
|
+
# ImageOptim.new(:pngcrush => false)
|
|
45
|
+
#
|
|
46
|
+
# or hash with options to worker
|
|
47
|
+
#
|
|
48
|
+
# ImageOptim.new(:advpng => {:level => 3}, :optipng => {:level => 2})
|
|
49
|
+
#
|
|
50
|
+
# use :threads to set number of parallel optimizers to run (passing true or
|
|
51
|
+
# nil determines number of processors, false disables parallel processing)
|
|
52
|
+
#
|
|
53
|
+
# ImageOptim.new(:threads => 8)
|
|
54
|
+
#
|
|
55
|
+
# use :nice to specify optimizers nice level (true or nil makes it 10, false
|
|
56
|
+
# makes it 0)
|
|
57
|
+
#
|
|
58
|
+
# ImageOptim.new(:nice => 20)
|
|
59
|
+
def initialize(options = {})
|
|
60
|
+
config = Config.new(options)
|
|
61
|
+
@verbose = config.verbose
|
|
62
|
+
$stderr << "config:\n#{config.to_s.gsub(/^/, ' ')}" if verbose
|
|
63
|
+
|
|
64
|
+
%w[
|
|
65
|
+
nice
|
|
66
|
+
threads
|
|
67
|
+
pack
|
|
68
|
+
skip_missing_workers
|
|
69
|
+
allow_lossy
|
|
70
|
+
].each do |name|
|
|
71
|
+
instance_variable_set(:"@#{name}", config.send(name))
|
|
72
|
+
$stderr << "#{name}: #{send(name)}\n" if verbose
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
@bin_resolver = BinResolver.new(self)
|
|
76
|
+
|
|
77
|
+
@workers_by_format = Worker.create_all_by_format(self) do |klass|
|
|
78
|
+
config.for_worker(klass)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
log_workers_by_format if verbose
|
|
82
|
+
|
|
83
|
+
config.assert_no_unused_options!
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# Get workers for image
|
|
87
|
+
def workers_for_image(path)
|
|
88
|
+
@workers_by_format[ImagePath.convert(path).format]
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# Optimize one file, return new path as OptimizedImagePath or nil if
|
|
92
|
+
# optimization failed
|
|
93
|
+
def optimize_image(original)
|
|
94
|
+
original = ImagePath.convert(original)
|
|
95
|
+
return unless (workers = workers_for_image(original))
|
|
96
|
+
result = Handler.for(original) do |handler|
|
|
97
|
+
workers.each do |worker|
|
|
98
|
+
handler.process do |src, dst|
|
|
99
|
+
worker.optimize(src, dst)
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
return unless result
|
|
104
|
+
ImagePath::Optimized.new(result, original)
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# Optimize one file in place, return original as OptimizedImagePath or nil if
|
|
108
|
+
# optimization failed
|
|
109
|
+
def optimize_image!(original)
|
|
110
|
+
original = ImagePath.convert(original)
|
|
111
|
+
return unless (result = optimize_image(original))
|
|
112
|
+
result.replace(original)
|
|
113
|
+
ImagePath::Optimized.new(original, result.original_size)
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# Optimize image data, return new data or nil if optimization failed
|
|
117
|
+
def optimize_image_data(original_data)
|
|
118
|
+
image_meta = ImageMeta.for_data(original_data)
|
|
119
|
+
return unless image_meta && image_meta.format
|
|
120
|
+
ImagePath.temp_file %W[image_optim .#{image_meta.format}] do |temp|
|
|
121
|
+
temp.binmode
|
|
122
|
+
temp.write(original_data)
|
|
123
|
+
temp.close
|
|
124
|
+
|
|
125
|
+
if (result = optimize_image(temp.path))
|
|
126
|
+
result.binread
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
# Optimize multiple images
|
|
132
|
+
# if block given yields path and result for each image and returns array of
|
|
133
|
+
# yield results
|
|
134
|
+
# else return array of path and result pairs
|
|
135
|
+
def optimize_images(paths, &block)
|
|
136
|
+
run_method_for(paths, :optimize_image, &block)
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
# Optimize multiple images in place
|
|
140
|
+
# if block given yields path and result for each image and returns array of
|
|
141
|
+
# yield results
|
|
142
|
+
# else return array of path and result pairs
|
|
143
|
+
def optimize_images!(paths, &block)
|
|
144
|
+
run_method_for(paths, :optimize_image!, &block)
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
# Optimize multiple image datas
|
|
148
|
+
# if block given yields original and result for each image data and returns
|
|
149
|
+
# array of yield results
|
|
150
|
+
# else return array of path and result pairs
|
|
151
|
+
def optimize_images_data(datas, &block)
|
|
152
|
+
run_method_for(datas, :optimize_image_data, &block)
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
# Optimization methods with default options
|
|
156
|
+
def self.method_missing(method, *args, &block)
|
|
157
|
+
if method_defined?(method) && method.to_s =~ /^optimize_image/
|
|
158
|
+
new.send(method, *args, &block)
|
|
159
|
+
else
|
|
160
|
+
super
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
# Version of image_optim gem spec loaded
|
|
165
|
+
def self.version
|
|
166
|
+
Gem.loaded_specs['image_optim'].version.to_s rescue 'DEV'
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
# Full version of image_optim
|
|
170
|
+
def self.full_version
|
|
171
|
+
"image_optim v#{version}"
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
# Are there workers for file at path?
|
|
175
|
+
def optimizable?(path)
|
|
176
|
+
!!workers_for_image(path)
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
# Check existance of binary, create symlink if ENV contains path for key
|
|
180
|
+
# XXX_BIN where XXX is upper case bin name
|
|
181
|
+
def resolve_bin!(bin)
|
|
182
|
+
@bin_resolver.resolve!(bin)
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
# Join resolve_dir, default path and vendor path for PATH environment variable
|
|
186
|
+
def env_path
|
|
187
|
+
@bin_resolver.env_path
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
private
|
|
191
|
+
|
|
192
|
+
def log_workers_by_format
|
|
193
|
+
$stderr << "Workers by format:\n"
|
|
194
|
+
@workers_by_format.each do |format, workers|
|
|
195
|
+
$stderr << "#{format}:\n"
|
|
196
|
+
workers.each do |worker|
|
|
197
|
+
$stderr << " #{worker.class.bin_sym}:\n"
|
|
198
|
+
worker.options.each do |name, value|
|
|
199
|
+
$stderr << " #{name}: #{value.inspect}\n"
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
end
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
# Run method for each item in list
|
|
206
|
+
# if block given yields item and result for item and returns array of yield
|
|
207
|
+
# results
|
|
208
|
+
# else return array of item and result pairs
|
|
209
|
+
def run_method_for(list, method_name, &block)
|
|
210
|
+
apply_threading(list).map do |item|
|
|
211
|
+
result = send(method_name, item)
|
|
212
|
+
if block
|
|
213
|
+
block.call(item, result)
|
|
214
|
+
else
|
|
215
|
+
[item, result]
|
|
216
|
+
end
|
|
217
|
+
end
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
# Apply threading if threading is allowed
|
|
221
|
+
def apply_threading(enum)
|
|
222
|
+
if threads > 1
|
|
223
|
+
enum.in_threads(threads)
|
|
224
|
+
else
|
|
225
|
+
enum
|
|
226
|
+
end
|
|
227
|
+
end
|
|
228
|
+
end
|