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.
Files changed (94) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/.rubocop.yml +65 -0
  4. data/.travis.yml +42 -0
  5. data/CHANGELOG.markdown +272 -0
  6. data/CONTRIBUTING.markdown +10 -0
  7. data/Gemfile +9 -0
  8. data/LICENSE.txt +20 -0
  9. data/README.markdown +344 -0
  10. data/Vagrantfile +33 -0
  11. data/bin/image_optim +28 -0
  12. data/image_optim.gemspec +29 -0
  13. data/lib/image_optim.rb +228 -0
  14. data/lib/image_optim/bin_resolver.rb +144 -0
  15. data/lib/image_optim/bin_resolver/bin.rb +105 -0
  16. data/lib/image_optim/bin_resolver/comparable_condition.rb +60 -0
  17. data/lib/image_optim/bin_resolver/error.rb +6 -0
  18. data/lib/image_optim/bin_resolver/simple_version.rb +31 -0
  19. data/lib/image_optim/cmd.rb +49 -0
  20. data/lib/image_optim/config.rb +205 -0
  21. data/lib/image_optim/configuration_error.rb +3 -0
  22. data/lib/image_optim/handler.rb +57 -0
  23. data/lib/image_optim/hash_helpers.rb +45 -0
  24. data/lib/image_optim/image_meta.rb +25 -0
  25. data/lib/image_optim/image_path.rb +68 -0
  26. data/lib/image_optim/non_negative_integer_range.rb +11 -0
  27. data/lib/image_optim/option_definition.rb +32 -0
  28. data/lib/image_optim/option_helpers.rb +17 -0
  29. data/lib/image_optim/railtie.rb +38 -0
  30. data/lib/image_optim/runner.rb +139 -0
  31. data/lib/image_optim/runner/glob_helpers.rb +45 -0
  32. data/lib/image_optim/runner/option_parser.rb +227 -0
  33. data/lib/image_optim/space.rb +29 -0
  34. data/lib/image_optim/true_false_nil.rb +16 -0
  35. data/lib/image_optim/worker.rb +159 -0
  36. data/lib/image_optim/worker/advpng.rb +35 -0
  37. data/lib/image_optim/worker/class_methods.rb +91 -0
  38. data/lib/image_optim/worker/gifsicle.rb +63 -0
  39. data/lib/image_optim/worker/jhead.rb +43 -0
  40. data/lib/image_optim/worker/jpegoptim.rb +58 -0
  41. data/lib/image_optim/worker/jpegrecompress.rb +44 -0
  42. data/lib/image_optim/worker/jpegtran.rb +46 -0
  43. data/lib/image_optim/worker/optipng.rb +45 -0
  44. data/lib/image_optim/worker/pngcrush.rb +54 -0
  45. data/lib/image_optim/worker/pngout.rb +38 -0
  46. data/lib/image_optim/worker/pngquant.rb +51 -0
  47. data/lib/image_optim/worker/svgo.rb +32 -0
  48. data/script/template/jquery-2.1.3.min.js +4 -0
  49. data/script/template/sortable-0.6.0.min.js +2 -0
  50. data/script/template/worker_analysis.erb +254 -0
  51. data/script/update_worker_options_in_readme +60 -0
  52. data/script/worker_analysis +599 -0
  53. data/spec/image_optim/bin_resolver/comparable_condition_spec.rb +37 -0
  54. data/spec/image_optim/bin_resolver/simple_version_spec.rb +57 -0
  55. data/spec/image_optim/bin_resolver_spec.rb +272 -0
  56. data/spec/image_optim/cmd_spec.rb +66 -0
  57. data/spec/image_optim/config_spec.rb +217 -0
  58. data/spec/image_optim/handler_spec.rb +95 -0
  59. data/spec/image_optim/hash_helpers_spec.rb +76 -0
  60. data/spec/image_optim/image_path_spec.rb +54 -0
  61. data/spec/image_optim/railtie_spec.rb +121 -0
  62. data/spec/image_optim/runner/glob_helpers_spec.rb +25 -0
  63. data/spec/image_optim/runner/option_parser_spec.rb +99 -0
  64. data/spec/image_optim/space_spec.rb +25 -0
  65. data/spec/image_optim/worker_spec.rb +192 -0
  66. data/spec/image_optim_spec.rb +242 -0
  67. data/spec/images/comparison.png +0 -0
  68. data/spec/images/decompressed.jpeg +0 -0
  69. data/spec/images/icecream.gif +0 -0
  70. data/spec/images/image.jpg +0 -0
  71. data/spec/images/invisiblepixels/generate +24 -0
  72. data/spec/images/invisiblepixels/image.png +0 -0
  73. data/spec/images/lena.jpg +0 -0
  74. data/spec/images/orient/0.jpg +0 -0
  75. data/spec/images/orient/1.jpg +0 -0
  76. data/spec/images/orient/2.jpg +0 -0
  77. data/spec/images/orient/3.jpg +0 -0
  78. data/spec/images/orient/4.jpg +0 -0
  79. data/spec/images/orient/5.jpg +0 -0
  80. data/spec/images/orient/6.jpg +0 -0
  81. data/spec/images/orient/7.jpg +0 -0
  82. data/spec/images/orient/8.jpg +0 -0
  83. data/spec/images/orient/generate +23 -0
  84. data/spec/images/orient/original.jpg +0 -0
  85. data/spec/images/quant/64.png +0 -0
  86. data/spec/images/quant/generate +25 -0
  87. data/spec/images/rails.png +0 -0
  88. data/spec/images/test.svg +3 -0
  89. data/spec/images/transparency1.png +0 -0
  90. data/spec/images/transparency2.png +0 -0
  91. data/spec/images/vergroessert.jpg +0 -0
  92. data/spec/spec_helper.rb +64 -0
  93. data/vendor/jpegrescan +143 -0
  94. metadata +308 -0
@@ -0,0 +1,344 @@
1
+ [![Gem Version](https://img.shields.io/gem/v/image_optim.svg?style=flat)](https://rubygems.org/gems/image_optim)
2
+ [![Build Status](https://img.shields.io/travis/toy/image_optim/master.svg?style=flat)](https://travis-ci.org/toy/image_optim)
3
+ [![Code Climate](https://img.shields.io/codeclimate/github/toy/image_optim.svg?style=flat)](https://codeclimate.com/github/toy/image_optim)
4
+ [![Code Climate Coverage](https://img.shields.io/codeclimate/coverage/github/toy/image_optim.svg?style=flat)](https://codeclimate.com/github/toy/image_optim)
5
+ [![Dependency Status](https://img.shields.io/gemnasium/toy/image_optim.svg?style=flat)](https://gemnasium.com/toy/image_optim)
6
+ [![Inch CI](http://inch-ci.org/github/toy/image_optim.svg?branch=master&style=flat)](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
+ [![Support via Gratipay](https://cdn.rawgit.com/gratipay/gratipay-badge/2.1.2/dist/gratipay.png)](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.
@@ -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
@@ -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
@@ -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
@@ -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