Skip to content

Lossless rotating and compressing JPEG images via libjpeg tools

Notifications You must be signed in to change notification settings

N0xFF/dragonfly-lossless_rotate

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

31 Commits
 
 
 
 
 
 
 
 

Repository files navigation

Dragonfly Lossless Rotate

About 60% more performance with libjpeg-turbo tools

ImageMagick convert command which used in Dragonfly for rotation is lossy for JPEG images. This gem uses libjpeg for lossless rotation.

NOTE

Tool jpegtran from MozJPEG may work incorrectly and not rotate same image many times. You should test it before run in production.

Setup

gem "dragonfly-lossless_rotate"
Dragonfly.app.configure
  require "dragonfly/lossless_rotate"
  plugin :lossless_rotate
end

Requirements

By default gem uses libjpeg binaries and pnmflip from netpbm:

cjpeg
djpeg
jpegtran
pnmflip

Ubuntu

sudo apt-get install libjpeg-turbo-progs netpbm

macOS

brew install libjpeg netpbm

FreeBSD

MozJPEG binaries

But you can set MozJPEG binaries in ENV CJPEG_BIN=mozjpeg-cjpeg or in config:

Dragonfly.app.configure
  require "dragonfly/lossless_rotate"
  plugin :lossless_rotate, cjpeg_bin: "mozjpeg-cjpeg",
                           djpeg_bin: "mozjpeg-djpeg",
                           jpegtran_bin: "mozjpeg-jpegtran"

end

Use pamflip as pnmflip compatible binary

plugin :lossless_rotate, pnmflip_bin: "pamflip"

Usage

JPEG only:

@image.process(:lossless_rotate) # default 90
@image.process(:lossless_rotate, 180)
@image.process(:lossless_rotate, 270)
@image.process(:lossless_rotate, -90)

With fallback for other formats (rotate via ImageMagick):

@image.process(:safe_lossless_rotate)

Other options:

# Without JPEG optimization (default: true)
@image.process(:lossless_rotate, 90, optimize: false)
# Set default value
plugin :lossless_rotate, libjpeg_optimize: false

# Create progressive JPEG file (default: false)
@image.process(:lossless_rotate, 90, progressive: true)
# Set default value
plugin :lossless_rotate, libjpeg_progressive: true

Benchmark

  • ImageMagick 6.8.9-9 Q16 x86_64 2017-07-31
  • libjpeg-turbo version 1.4.2 (build 20160222)
  • MozJPEG version 3.3.2 (build 20180713)

JPEG 85KB 552x416px

ImageMagick rotate

convert old_path -rotate 90 new_path
puts Benchmark.measure { 500.times { @image.rotate(90).apply } }
  0.360000   1.570000  25.270000 ( 25.168681)

Lossless rotate

libjpeg-turbo

jpegtran -rotate 90 -perfect -optimize old_path > new_path
puts Benchmark.measure { 500.times { @image.process(:lossless_rotate).apply } }
  0.280000   1.160000   9.170000 (  9.876645)

puts Benchmark.measure { 500.times { @image.process(:safe_lossless_rotate).apply } }
  0.560000   1.780000  22.710000 ( 23.879913)

MozJPEG

mozjpeg-jpegtran -rotate 90 -perfect -optimize old_path > new_path
puts Benchmark.measure { 500.times { @image.process(:lossless_rotate).apply } }
  0.270000   1.110000  35.230000 ( 36.693039)

puts Benchmark.measure { 500.times { @image.process(:safe_lossless_rotate).apply } }
  0.550000   1.540000  48.880000 ( 50.171667)

Fallback when jpegtran transformation is not perfect

if the image dimensions are not a multiple of the iMCU size (usually 8 or 16 pixels)

Same image but resized to 556x417px

libjpeg-turbo

djpeg old_path | pnmflip -r270 | cjpeg -optimize > new_path
puts Benchmark.measure { 500.times { @image.process(:lossless_rotate).apply } }
  0.410000   1.280000  16.310000 ( 13.220535)

puts Benchmark.measure { 500.times { @image.process(:safe_lossless_rotate).apply } }
  0.310000   1.330000  30.300000 ( 28.332533)

MozJPEG

mozjpeg-djpeg old_path | pnmflip -r270 | mozjpeg-cjpeg -optimize > new_path
puts Benchmark.measure { 500.times { @image.process(:lossless_rotate).apply } }
  0.400000   1.150000  41.190000 ( 37.970843)

puts Benchmark.measure { 500.times { @image.process(:safe_lossless_rotate).apply } }
  0.420000   1.670000  55.700000 ( 52.835614)

About

Lossless rotating and compressing JPEG images via libjpeg tools

Resources

Stars

Watchers

Forks

Packages

No packages published

Languages