Skip to content

Commit

Permalink
Merge pull request #58 from curationexperts/sampling_factor
Browse files Browse the repository at this point in the history
Set Jpeg sampling factor and strip EXIF tags
  • Loading branch information
mejackreed authored Apr 11, 2017
2 parents 21ff317 + e218fd7 commit bc8b72c
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 40 deletions.
82 changes: 60 additions & 22 deletions app/services/riiif/imagemagick_command_factory.rb
Original file line number Diff line number Diff line change
@@ -1,52 +1,90 @@
# frozen_string_literal: true

module Riiif
# Builds a command to run a transformation using Imagemagick
class ImagemagickCommandFactory
# A helper method to instantiate and invoke build
# @param [String] path the location of the file
# @param [Transformation] transformation
# @param [Integer] compression (85) the compression level to use (set 0 for no compression)
# @param [String] sampling_factor ("4:2:0") the chroma sample factor (set 0 for no compression)
# @param [Boolean] strip_metadata (true) do we want to strip EXIF tags?
# @return [String] a command for running imagemagick to produce the requested output
def self.build(path, transformation, compression: 85)
new(path, transformation, compression: compression).build
def self.build(path, transformation, compression: 85, sampling_factor: '4:2:0', strip_metadata: true)
new(path, transformation,
compression: compression,
sampling_factor: sampling_factor,
strip_metadata: strip_metadata).build
end

# A helper method to instantiate and invoke build
# @param [String] path the location of the file
# @param [Transformation] transformation
# @param [Integer] compression the compression level to use (set 0 for no compression)
def initialize(path, transformation, compression:)
def initialize(path, transformation, compression:, sampling_factor:, strip_metadata:)
@path = path
@transformation = transformation
@compression = compression
@sampling_factor = sampling_factor
@strip_metadata = strip_metadata
end

attr_reader :path, :transformation, :compression
attr_reader :path, :transformation, :compression, :sampling_factor, :strip_metadata

# @return [String] a command for running imagemagick to produce the requested output
def build
command = 'convert'
command << " -crop #{transformation.crop}" if transformation.crop
command << " -resize #{transformation.size}" if transformation.size
if transformation.rotation
command << " -virtual-pixel white +distort srt #{transformation.rotation}"
end

case transformation.quality
when 'grey'
command << ' -colorspace Gray'
when 'bitonal'
command << ' -colorspace Gray'
command << ' -type Bilevel'
end
command << " -quality #{compression}" if use_compression?
command << " #{path} #{transformation.format}:-"
command
[command, crop, size, rotation, colorspace, quality, sampling, metadata, output].join
end

private

def command
'convert'
end

def use_compression?
compression > 0 && transformation.format == 'jpg'
compression > 0 && jpeg?
end

def jpeg?
transformation.format == 'jpg'.freeze
end

def output
" #{path} #{transformation.format}:-"
end

def crop
" -crop #{transformation.crop}" if transformation.crop
end

def size
" -resize #{transformation.size}" if transformation.size
end

def rotation
" -virtual-pixel white +distort srt #{transformation.rotation}" if transformation.rotation
end

def quality
" -quality #{compression}" if use_compression?
end

def metadata
' -strip' if strip_metadata
end

def sampling
" -sampling-factor #{sampling_factor}" if jpeg?
end

def colorspace
case transformation.quality
when 'grey'
' -colorspace Gray'
when 'bitonal'
' -colorspace Gray -type Bilevel'
end
end
end
end
38 changes: 20 additions & 18 deletions spec/models/riiif/image_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@
subject { described_class.new('world') }
describe 'happy path' do
before do
expect(subject.image).to receive(:execute).with("convert -quality 85 #{filename} jpg:-").and_return('imagedata')
expect(subject.image).to receive(:execute)
.with("convert -quality 85 -sampling-factor 4:2:0 -strip #{filename} jpg:-")
.and_return('imagedata')
end
it 'renders' do
expect(subject.render('size' => 'full', format: 'jpg')).to eq 'imagedata'
Expand Down Expand Up @@ -63,25 +65,25 @@
describe 'mogrify' do
describe 'region' do
it 'returns the original when specifing full size' do
expect(Riiif::CommandRunner).to receive(:execute).with("convert #{filename} png:-")
expect(Riiif::CommandRunner).to receive(:execute).with("convert -strip #{filename} png:-")
subject.render(region: 'full', format: 'png')
end
it 'handles absolute geometry' do
expect(Riiif::CommandRunner).to receive(:execute).with("convert -crop 60x75+80+15 #{filename} png:-")
expect(Riiif::CommandRunner).to receive(:execute).with("convert -crop 60x75+80+15 -strip #{filename} png:-")
subject.render(region: '80,15,60,75', format: 'png')
end

it 'handles percent geometry' do
expect(Riiif::CommandRunner).to receive(:execute)
.with("identify -format %hx%w #{filename}").and_return('131x175')
expect(Riiif::CommandRunner).to receive(:execute).with("convert -crop 80%x70+18+13 #{filename} png:-")
expect(Riiif::CommandRunner).to receive(:execute).with("convert -crop 80%x70+18+13 -strip #{filename} png:-")
subject.render(region: 'pct:10,10,80,70', format: 'png')
end

it 'handles square geometry' do
expect(Riiif::CommandRunner).to receive(:execute)
.with("identify -format %hx%w #{filename}").and_return('131x175')
expect(Riiif::CommandRunner).to receive(:execute).with("convert -crop 131x131+22+0 #{filename} png:-")
expect(Riiif::CommandRunner).to receive(:execute).with("convert -crop 131x131+22+0 -strip #{filename} png:-")
subject.render(region: 'square', format: 'png')
end
it 'raises an error for invalid geometry' do
Expand All @@ -91,31 +93,31 @@

describe 'resize' do
it 'returns the original when specifing full size' do
expect(Riiif::CommandRunner).to receive(:execute).with("convert #{filename} png:-")
expect(Riiif::CommandRunner).to receive(:execute).with("convert -strip #{filename} png:-")
subject.render(size: 'full', format: 'png')
end
it 'handles integer percent sizes' do
expect(Riiif::CommandRunner).to receive(:execute).with("convert -resize 50% #{filename} png:-")
expect(Riiif::CommandRunner).to receive(:execute).with("convert -resize 50% -strip #{filename} png:-")
subject.render(size: 'pct:50', format: 'png')
end
it 'handles float percent sizes' do
expect(Riiif::CommandRunner).to receive(:execute).with("convert -resize 12.5% #{filename} png:-")
expect(Riiif::CommandRunner).to receive(:execute).with("convert -resize 12.5% -strip #{filename} png:-")
subject.render(size: 'pct:12.5', format: 'png')
end
it 'handles w,' do
expect(Riiif::CommandRunner).to receive(:execute).with("convert -resize 50 #{filename} png:-")
expect(Riiif::CommandRunner).to receive(:execute).with("convert -resize 50 -strip #{filename} png:-")
subject.render(size: '50,', format: 'png')
end
it 'handles ,h' do
expect(Riiif::CommandRunner).to receive(:execute).with("convert -resize x50 #{filename} png:-")
expect(Riiif::CommandRunner).to receive(:execute).with("convert -resize x50 -strip #{filename} png:-")
subject.render(size: ',50', format: 'png')
end
it 'handles w,h' do
expect(Riiif::CommandRunner).to receive(:execute).with("convert -resize 150x75! #{filename} png:-")
expect(Riiif::CommandRunner).to receive(:execute).with("convert -resize 150x75! -strip #{filename} png:-")
subject.render(size: '150,75', format: 'png')
end
it 'handles bestfit (!w,h)' do
expect(Riiif::CommandRunner).to receive(:execute).with("convert -resize 150x75 #{filename} png:-")
expect(Riiif::CommandRunner).to receive(:execute).with("convert -resize 150x75 -strip #{filename} png:-")
subject.render(size: '!150,75', format: 'png')
end
it 'raises an error for invalid size' do
Expand All @@ -125,12 +127,12 @@

describe 'rotate' do
it 'returns the original when specifing full size' do
expect(Riiif::CommandRunner).to receive(:execute).with("convert #{filename} png:-")
expect(Riiif::CommandRunner).to receive(:execute).with("convert -strip #{filename} png:-")
subject.render(rotation: '0', format: 'png')
end
it 'handles floats' do
expect(Riiif::CommandRunner).to receive(:execute)
.with("convert -virtual-pixel white +distort srt 22.5 #{filename} png:-")
.with("convert -virtual-pixel white +distort srt 22.5 -strip #{filename} png:-")
subject.render(rotation: '22.5', format: 'png')
end
it 'raises an error for invalid angle' do
Expand All @@ -140,20 +142,20 @@

describe 'quality' do
it 'returns the original when specifing default' do
expect(Riiif::CommandRunner).to receive(:execute).with("convert #{filename} png:-")
expect(Riiif::CommandRunner).to receive(:execute).with("convert -strip #{filename} png:-")
subject.render(quality: 'default', format: 'png')
end
it 'returns the original when specifing color' do
expect(Riiif::CommandRunner).to receive(:execute).with("convert #{filename} png:-")
expect(Riiif::CommandRunner).to receive(:execute).with("convert -strip #{filename} png:-")
subject.render(quality: 'color', format: 'png')
end
it 'converts to grayscale' do
expect(Riiif::CommandRunner).to receive(:execute).with("convert -colorspace Gray #{filename} png:-")
expect(Riiif::CommandRunner).to receive(:execute).with("convert -colorspace Gray -strip #{filename} png:-")
subject.render(quality: 'grey', format: 'png')
end
it 'converts to bitonal' do
expect(Riiif::CommandRunner).to receive(:execute)
.with("convert -colorspace Gray -type Bilevel #{filename} png:-")
.with("convert -colorspace Gray -type Bilevel -strip #{filename} png:-")
subject.render(quality: 'bitonal', format: 'png')
end
it 'raises an error for invalid angle' do
Expand Down

0 comments on commit bc8b72c

Please sign in to comment.