dragonfly-lossless_rotate 0.1.1 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +8 -63
- data/lib/dragonfly/lossless_rotate.rb +101 -102
- data/lib/dragonfly/lossless_rotate/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 344be41ffd0ead843a69adc18b8161e08dab0fef2ffb8c1591607976ff01f2b2
|
4
|
+
data.tar.gz: a515cc697760c756aac4d2dfe770d42507f2948833de0d9623b6ee0a00b41845
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 82c2acf9d420d436f6f356674de868247176401c51c6ba9b0a7225115b25078b1a50c564d6e7ae99e4ece9dd11e39e1f8a50f7faa101d424364d17db98daf5f7
|
7
|
+
data.tar.gz: 8cc2b9bad7e9769e5559a9cb3ac1259ef2676e189ea30265e95b7869b5b207f103a1f30e690b9258b0e6882263a193775e357dfe66ac42f61f5c4072264f9fa5
|
data/README.md
CHANGED
@@ -71,7 +71,6 @@ plugin :lossless_rotate, libjpeg_progressive: true
|
|
71
71
|
|
72
72
|
## Benchmark
|
73
73
|
|
74
|
-
- _libjpeg_ version 9b (17-Jan-2016)
|
75
74
|
- _libjpeg-turbo_ version 1.4.2 (build 20160222)
|
76
75
|
- _MozJPEG_ version 3.3.2 (build 20180713)
|
77
76
|
|
@@ -88,34 +87,6 @@ puts Benchmark.measure { 500.times { @image.rotate(90).apply } }
|
|
88
87
|
|
89
88
|
### Lossless rotate
|
90
89
|
|
91
|
-
#### libjpeg
|
92
|
-
|
93
|
-
##### (optimize=true)
|
94
|
-
```bash
|
95
|
-
jpegtran -rotate 90 -perfect -optimize old_path > new_path
|
96
|
-
```
|
97
|
-
|
98
|
-
```ruby
|
99
|
-
puts Benchmark.measure { 500.times { @image.process(:lossless_rotate).apply } }
|
100
|
-
0.240000 1.190000 10.600000 ( 11.368903)
|
101
|
-
|
102
|
-
puts Benchmark.measure { 500.times { @image.process(:safe_lossless_rotate).apply } }
|
103
|
-
0.440000 1.640000 24.360000 ( 26.211808)
|
104
|
-
```
|
105
|
-
|
106
|
-
##### (optimize=false)
|
107
|
-
```bash
|
108
|
-
jpegtran -rotate 90 -perfect old_path > new_path
|
109
|
-
```
|
110
|
-
|
111
|
-
```ruby
|
112
|
-
puts Benchmark.measure { 500.times { @image.process(:lossless_rotate, 90, optimize: false).apply } }
|
113
|
-
0.290000 1.170000 9.600000 ( 10.321087)
|
114
|
-
|
115
|
-
puts Benchmark.measure { 500.times { @image.process(:safe_lossless_rotate, 90, optimize: false).apply } }
|
116
|
-
0.450000 1.470000 23.610000 ( 25.478872)
|
117
|
-
```
|
118
|
-
|
119
90
|
#### libjpeg-turbo
|
120
91
|
|
121
92
|
##### (optimize=true)
|
@@ -138,10 +109,10 @@ jpegtran -rotate 90 -perfect old_path > new_path
|
|
138
109
|
|
139
110
|
```ruby
|
140
111
|
puts Benchmark.measure { 500.times { @image.process(:lossless_rotate, 90, optimize: false).apply } }
|
141
|
-
0.
|
112
|
+
0.250000 1.090000 8.110000 ( 8.601707)
|
142
113
|
|
143
114
|
puts Benchmark.measure { 500.times { @image.process(:safe_lossless_rotate, 90, optimize: false).apply } }
|
144
|
-
0.
|
115
|
+
0.360000 1.170000 21.480000 ( 22.744040)
|
145
116
|
```
|
146
117
|
|
147
118
|
#### MozJPEG
|
@@ -178,32 +149,6 @@ puts Benchmark.measure { 500.times { @image.process(:safe_lossless_rotate, 90, o
|
|
178
149
|
|
179
150
|
Same image but resized to 556x417px
|
180
151
|
|
181
|
-
#### libjpeg
|
182
|
-
|
183
|
-
##### (optimize=true)
|
184
|
-
```bash
|
185
|
-
djpeg old_path | pnmflip -r270 | cjpeg -optimize > new_path
|
186
|
-
```
|
187
|
-
```ruby
|
188
|
-
puts Benchmark.measure { 500.times { @image.process(:lossless_rotate).apply } }
|
189
|
-
0.340000 0.930000 19.320000 ( 16.055059)
|
190
|
-
|
191
|
-
puts Benchmark.measure { 500.times { @image.process(:safe_lossless_rotate).apply } }
|
192
|
-
0.390000 1.240000 32.520000 ( 30.055926)
|
193
|
-
```
|
194
|
-
|
195
|
-
##### (optimize=false)
|
196
|
-
```bash
|
197
|
-
djpeg old_path | convert - -rotate 90 JPG:new_path
|
198
|
-
```
|
199
|
-
```ruby
|
200
|
-
puts Benchmark.measure { 500.times { @image.process(:lossless_rotate, 90, optimize: false).apply } }
|
201
|
-
0.310000 1.450000 30.520000 ( 28.357557)
|
202
|
-
|
203
|
-
puts Benchmark.measure { 500.times { @image.process(:safe_lossless_rotate, 90, optimize: false).apply } }
|
204
|
-
0.530000 1.520000 43.790000 ( 41.732961)
|
205
|
-
```
|
206
|
-
|
207
152
|
#### libjpeg-turbo
|
208
153
|
|
209
154
|
##### (optimize=true)
|
@@ -220,14 +165,14 @@ puts Benchmark.measure { 500.times { @image.process(:safe_lossless_rotate).apply
|
|
220
165
|
|
221
166
|
##### (optimize=false)
|
222
167
|
```bash
|
223
|
-
djpeg old_path |
|
168
|
+
djpeg old_path | pnmflip -r270 | cjpeg > new_path
|
224
169
|
```
|
225
170
|
```ruby
|
226
171
|
puts Benchmark.measure { 500.times { @image.process(:lossless_rotate, 90, optimize: false).apply } }
|
227
|
-
0.
|
172
|
+
0.330000 1.250000 15.190000 ( 11.990070)
|
228
173
|
|
229
174
|
puts Benchmark.measure { 500.times { @image.process(:safe_lossless_rotate, 90, optimize: false).apply } }
|
230
|
-
0.
|
175
|
+
0.330000 1.330000 29.010000 ( 26.816061)
|
231
176
|
```
|
232
177
|
|
233
178
|
#### MozJPEG
|
@@ -246,12 +191,12 @@ puts Benchmark.measure { 500.times { @image.process(:safe_lossless_rotate).apply
|
|
246
191
|
|
247
192
|
##### (optimize=false)
|
248
193
|
```bash
|
249
|
-
mozjpeg-djpeg old_path |
|
194
|
+
mozjpeg-djpeg old_path | pnmflip -r270 | mozjpeg-cjpeg > new_path
|
250
195
|
```
|
251
196
|
```ruby
|
252
197
|
puts Benchmark.measure { 500.times { @image.process(:lossless_rotate, 90, optimize: false).apply } }
|
253
|
-
0.
|
198
|
+
0.240000 0.860000 40.550000 ( 38.247647)
|
254
199
|
|
255
200
|
puts Benchmark.measure { 500.times { @image.process(:safe_lossless_rotate, 90, optimize: false).apply } }
|
256
|
-
0.
|
201
|
+
0.480000 1.330000 54.550000 ( 52.941735)
|
257
202
|
```
|
@@ -1,102 +1,101 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "dragonfly"
|
4
|
-
|
5
|
-
Dragonfly::App.register_plugin(:lossless_rotate) { Dragonfly::LosslessRotate::Plugin.new }
|
6
|
-
|
7
|
-
module Dragonfly
|
8
|
-
class LosslessRotate
|
9
|
-
class Plugin
|
10
|
-
def call(app, opts = {})
|
11
|
-
app.env[:cjpeg_bin] = opts[:cjpeg_bin] || "cjpeg"
|
12
|
-
app.env[:djpeg_bin] = opts[:djpeg_bin] || "djpeg"
|
13
|
-
app.env[:jpegtran_bin] = opts[:jpegtran_bin] || "jpegtran"
|
14
|
-
app.env[:pnmflip_bin] = opts[:pnmflip_bin] || "pnmflip"
|
15
|
-
|
16
|
-
app.env[:libjpeg_optimize] = opts[:libjpeg_optimize] || true
|
17
|
-
app.env[:libjpeg_progressive] = opts[:libjpeg_progressive] || false
|
18
|
-
|
19
|
-
app.add_processor :lossless_rotate, Dragonfly::LosslessRotate::Rotate.new
|
20
|
-
app.add_processor :safe_lossless_rotate, Dragonfly::LosslessRotate::SafeRotate.new
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
# Only JPEG format
|
25
|
-
class Rotate
|
26
|
-
def call(content, degree = 90, optimize: nil, progressive: nil)
|
27
|
-
unless [90, 180, 270, -90, -180, -270].include?(degree)
|
28
|
-
warn "Rotate only by 90, 180 and 270 degrees allowed"
|
29
|
-
degree = 90
|
30
|
-
end
|
31
|
-
|
32
|
-
optimize
|
33
|
-
progressive
|
34
|
-
|
35
|
-
rotate(content, degree, optimize, progressive)
|
36
|
-
end
|
37
|
-
|
38
|
-
private
|
39
|
-
|
40
|
-
def rotate(content, degree, optimize, progressive)
|
41
|
-
cjpeg_bin = content.env[:cjpeg_bin] || "cjpeg"
|
42
|
-
djpeg_bin = content.env[:djpeg_bin] || "djpeg"
|
43
|
-
jpegtran_bin = content.env[:jpegtran_bin] || "jpegtran"
|
44
|
-
pnmflip_bin = content.env[:pnmflip_bin] || "pnmflip"
|
45
|
-
|
46
|
-
content.shell_update escape: false do |old_path, new_path|
|
47
|
-
optimize_option = " -optimize" if optimize
|
48
|
-
progressive_option = " -progressive" if progressive
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
-
|
69
|
-
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
-
|
80
|
-
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
end
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dragonfly"
|
4
|
+
|
5
|
+
Dragonfly::App.register_plugin(:lossless_rotate) { Dragonfly::LosslessRotate::Plugin.new }
|
6
|
+
|
7
|
+
module Dragonfly
|
8
|
+
class LosslessRotate
|
9
|
+
class Plugin
|
10
|
+
def call(app, opts = {})
|
11
|
+
app.env[:cjpeg_bin] = opts[:cjpeg_bin] || "cjpeg"
|
12
|
+
app.env[:djpeg_bin] = opts[:djpeg_bin] || "djpeg"
|
13
|
+
app.env[:jpegtran_bin] = opts[:jpegtran_bin] || "jpegtran"
|
14
|
+
app.env[:pnmflip_bin] = opts[:pnmflip_bin] || "pnmflip"
|
15
|
+
|
16
|
+
app.env[:libjpeg_optimize] = opts[:libjpeg_optimize] || true
|
17
|
+
app.env[:libjpeg_progressive] = opts[:libjpeg_progressive] || false
|
18
|
+
|
19
|
+
app.add_processor :lossless_rotate, Dragonfly::LosslessRotate::Rotate.new
|
20
|
+
app.add_processor :safe_lossless_rotate, Dragonfly::LosslessRotate::SafeRotate.new
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# Only JPEG format
|
25
|
+
class Rotate
|
26
|
+
def call(content, degree = 90, optimize: nil, progressive: nil)
|
27
|
+
unless [90, 180, 270, -90, -180, -270].include?(degree)
|
28
|
+
warn "Rotate only by 90, 180 and 270 degrees allowed"
|
29
|
+
degree = 90
|
30
|
+
end
|
31
|
+
|
32
|
+
optimize = content.env[:libjpeg_optimize] if optimize.nil?
|
33
|
+
progressive = content.env[:libjpeg_progressive] if progressive.nil?
|
34
|
+
|
35
|
+
rotate(content, degree, optimize, progressive)
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def rotate(content, degree, optimize, progressive)
|
41
|
+
cjpeg_bin = content.env[:cjpeg_bin] || "cjpeg"
|
42
|
+
djpeg_bin = content.env[:djpeg_bin] || "djpeg"
|
43
|
+
jpegtran_bin = content.env[:jpegtran_bin] || "jpegtran"
|
44
|
+
pnmflip_bin = content.env[:pnmflip_bin] || "pnmflip"
|
45
|
+
|
46
|
+
content.shell_update escape: false do |old_path, new_path|
|
47
|
+
optimize_option = " -optimize" if optimize
|
48
|
+
progressive_option = " -progressive" if progressive
|
49
|
+
|
50
|
+
lossless_rotate_command = "#{jpegtran_bin} -rotate #{jpegtran_degrees(degree)} -perfect#{progressive_option}#{optimize_option} '#{old_path}' > '#{new_path}'"
|
51
|
+
|
52
|
+
decompress_command = " #{djpeg_bin} '#{old_path}'"
|
53
|
+
pnmflip_command = " #{pnmflip_bin} -r#{pnmflip_degrees(degree)}"
|
54
|
+
cjpeg_command = " #{cjpeg_bin}#{progressive_option}#{optimize_option} > '#{new_path}'"
|
55
|
+
|
56
|
+
lossy_rotate_command = "#{decompress_command} |#{pnmflip_command} |#{cjpeg_command}"
|
57
|
+
|
58
|
+
"#{lossless_rotate_command} ||#{lossy_rotate_command}"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def pnmflip_degrees(degree)
|
63
|
+
{
|
64
|
+
90 => 270,
|
65
|
+
180 => 180,
|
66
|
+
270 => 90,
|
67
|
+
-90 => 90,
|
68
|
+
-180 => 180,
|
69
|
+
-270 => 270
|
70
|
+
}[degree]
|
71
|
+
end
|
72
|
+
|
73
|
+
def jpegtran_degrees(degree)
|
74
|
+
{
|
75
|
+
90 => 90,
|
76
|
+
180 => 180,
|
77
|
+
270 => 180,
|
78
|
+
-90 => 270,
|
79
|
+
-180 => 180,
|
80
|
+
-270 => 90
|
81
|
+
}[degree]
|
82
|
+
end
|
83
|
+
|
84
|
+
def jpeg?(content)
|
85
|
+
content.shell_eval { |path| "identify -format \%m #{path}" } == "JPEG"
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
# All formats support by ImageMagick
|
90
|
+
class SafeRotate < Rotate
|
91
|
+
def rotate(content, degree, optimize, progressive)
|
92
|
+
return super if jpeg?(content)
|
93
|
+
|
94
|
+
content.shell_update do |old_path, new_path|
|
95
|
+
"convert #{old_path} -rotate #{degree} #{new_path}"
|
96
|
+
end
|
97
|
+
end
|
98
|
+
private :rotate
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dragonfly-lossless_rotate
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Maxim Perepelitsa
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-07-
|
11
|
+
date: 2018-07-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: dragonfly
|