diff --git a/lib/upload_creator.rb b/lib/upload_creator.rb index 9c2f4abbda1..3d8b0e8383d 100644 --- a/lib/upload_creator.rb +++ b/lib/upload_creator.rb @@ -126,7 +126,7 @@ class UploadCreator if is_image @upload.thumbnail_width, @upload.thumbnail_height = ImageSizer.resize(*@image_info.size) @upload.width, @upload.height = @image_info.size - @upload.animated = FastImage.animated?(@file) + @upload.animated = animated? end add_metadata! @@ -267,13 +267,13 @@ class UploadCreator end def should_alter_quality? - return false if FastImage.animated?(@file) + return false if animated? @upload.target_image_quality(@file.path, SiteSetting.recompress_original_jpg_quality).present? end def should_downsize? - max_image_size > 0 && filesize >= max_image_size && !FastImage.animated?(@file) + max_image_size > 0 && filesize >= max_image_size && !animated? end def downsize! @@ -351,7 +351,7 @@ class UploadCreator end def should_crop? - return false if ['profile_background', 'card_background', 'custom_emoji'].include?(@opts[:type]) && FastImage.animated?(@file) + return false if ['profile_background', 'card_background', 'custom_emoji'].include?(@opts[:type]) && animated? TYPES_TO_CROP.include?(@opts[:type]) end @@ -427,4 +427,30 @@ class UploadCreator @upload.secure = UploadSecurity.new(@upload, @opts).should_be_secure? end + private + + def animated? + return @animated if @animated != nil + + @animated ||= begin + is_animated = FastImage.animated?(@file) + type = @image_info.type.to_s + + if is_animated != nil + # FastImage will return nil if it cannot determine if animated + is_animated + elsif type == "gif" || type == "webp" + # Only GIFs, WEBPs and a few other unsupported image types can be animated + OptimizedImage.ensure_safe_paths!(@file.path) + + command = ["identify", "-format", "%n\\n", @file.path] + frames = Discourse::Utils.execute_command(*command).to_i rescue 1 + + frames > 1 + else + false + end + end + end + end diff --git a/spec/fixtures/images/animated.webp b/spec/fixtures/images/animated.webp new file mode 100644 index 00000000000..5b00711b6a1 Binary files /dev/null and b/spec/fixtures/images/animated.webp differ diff --git a/spec/lib/upload_creator_spec.rb b/spec/lib/upload_creator_spec.rb index 23442bcdfac..2de42a6cd24 100644 --- a/spec/lib/upload_creator_spec.rb +++ b/spec/lib/upload_creator_spec.rb @@ -137,6 +137,9 @@ RSpec.describe UploadCreator do let(:animated_filename) { "animated.gif" } let(:animated_file) { file_from_fixtures(animated_filename) } + let(:animated_webp_filename) { "animated.webp" } + let(:animated_webp_file) { file_from_fixtures(animated_webp_filename) } + before do SiteSetting.png_to_jpg_quality = 1 end @@ -208,6 +211,20 @@ RSpec.describe UploadCreator do expect(File.extname(upload.url)).to eq('.gif') expect(upload.original_filename).to eq('animated.gif') end + + it 'should not convert animated WEBP images' do + expect do + UploadCreator.new(animated_webp_file, animated_webp_filename, + force_optimize: true + ).create_for(user.id) + end.to change { Upload.count }.by(1) + + upload = Upload.last + + expect(upload.extension).to eq('webp') + expect(File.extname(upload.url)).to eq('.webp') + expect(upload.original_filename).to eq('animated.webp') + end end end