add service to rotate jpg attachment automatically

This commit is contained in:
Lisa Durand 2024-04-22 15:12:49 +02:00 committed by Eric Leroy-Terquem
parent c794f654ea
commit 96238da249
No known key found for this signature in database
GPG key ID: ECE60B4C1FA2ABB3
5 changed files with 68 additions and 0 deletions

View file

@ -0,0 +1,22 @@
module AttachmentAutoRotateConcern
extend ActiveSupport::Concern
included do
after_create_commit :auto_rotate
end
private
def auto_rotate
return if blob.nil?
return if ["image/jpeg", "image/jpg"].exclude?(blob.content_type)
blob.open do |file|
Tempfile.create(["rotated", File.extname(file)]) do |output|
processed = AutoRotateService.new.process(file, output)
blob.upload(processed) # also update checksum & byte_size accordingly
blob.save!
end
end
end
end

View file

@ -0,0 +1,30 @@
class AutoRotateService
def process(file, output)
auto_rotate_image(file, output)
output
end
private
def auto_rotate_image(file, output)
image = MiniMagick::Image.new(file.to_path)
case image["%[orientation]"]
when 'LeftBottom'
rotate_image(file, output, 90)
when 'BottomRight'
rotate_image(file, output, 180)
when 'RightTop'
rotate_image(file, output, 270)
end
end
def rotate_image(file, output, degree)
MiniMagick::Tool::Convert.new do |convert|
convert << file.to_path
convert.rotate(degree)
convert.auto_orient
convert << output.to_path
end
end
end

View file

@ -17,6 +17,7 @@ end
ActiveSupport.on_load(:active_storage_attachment) do
include AttachmentTitreIdentiteWatermarkConcern
include AttachmentVirusScannerConcern
include AttachmentAutoRotateConcern
end
Rails.application.reloader.to_prepare do

BIN
spec/fixtures/files/image-rotated.jpg vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View file

@ -0,0 +1,15 @@
RSpec.describe AutoRotateService do
let(:image) { file_fixture("image-rotated.jpg") }
let(:auto_rotate_service) { AutoRotateService.new }
describe '#process' do
it 'returns a tempfile if auto_rotate succeeds' do
Tempfile.create do |output|
auto_rotate_service.process(image, output)
expect(MiniMagick::Image.new(image.to_path)["%[orientation]"]).to eq('LeftBottom')
expect(MiniMagick::Image.new(output.to_path)["%[orientation]"]).to eq('TopLeft')
expect(output.size).to be_between(image.size / 1.2, image.size)
end
end
end
end