Fix #5065: .webp images upload support

Add ability to upload .webp images.

Animated WebP images aren't supported. This is because they aren't
supported by FFmpeg yet[1], so generating thumbnails and samples for
them would be more complicated than for other formats.

[1]: https://trac.ffmpeg.org/ticket/4907
This commit is contained in:
evazion
2022-10-25 21:58:25 -05:00
parent df0e9bc4a7
commit acea0d5553
17 changed files with 91 additions and 11 deletions

View File

@@ -48,7 +48,7 @@ class ExifTool
end
def is_animated?
frame_count.to_i > 1 || is_animated_avif?
frame_count.to_i > 1 || is_animated_webp? || is_animated_avif?
end
def is_animated_gif?
@@ -59,6 +59,10 @@ class ExifTool
file_ext == :png && is_animated?
end
def is_animated_webp?
file_ext == :webp && metadata["RIFF:Duration"].present?
end
def is_animated_avif?
file_ext == :avif && metadata["QuickTime:CompatibleBrands"].to_a.include?("avis")
end
@@ -123,8 +127,10 @@ class ExifTool
def loop_count
return Float::INFINITY if metadata["GIF:AnimationIterations"] == "Infinite"
return Float::INFINITY if metadata["PNG:AnimationPlays"] == "inf"
return Float::INFINITY if metadata["RIFF:AnimationLoopCount"] == "inf"
return metadata["GIF:AnimationIterations"] if has_key?("GIF:AnimationIterations")
return metadata["PNG:AnimationPlays"] if has_key?("PNG:AnimationPlays")
return metadata["RIFF:AnimationLoopCount"] if has_key?("RIFF:AnimationLoopCount")
# If the AnimationIterations tag isn't present, then it's counted as a loop count of 0.
return 0 if is_animated_gif? && !has_key?("GIF:AnimationIterations")
@@ -153,6 +159,8 @@ class ExifTool
:avif
elsif has_key?("QuickTime:MovieHeaderVersion")
:mp4
elsif keys.grep(/\ARIFF:/).any?
:webp
elsif has_key?("Matroska:DocType")
:webm
elsif has_key?("Flash:FlashVersion")

View File

@@ -26,7 +26,7 @@ class MediaFile
file = Kernel.open(file, "r", binmode: true) unless file.respond_to?(:read)
case file_ext(file)
when :jpg, :gif, :png, :avif
when :jpg, :gif, :png, :webp, :avif
MediaFile::Image.new(file, **options)
when :swf
MediaFile::Flash.new(file, **options)
@@ -62,6 +62,10 @@ class MediaFile
when /\A\x1a\x45\xdf\xa3/n
:webm
# https://developers.google.com/speed/webp/docs/riff_container
when /\ARIFF....WEBP/
:webp
# https://www.ftyps.com
# isom (common) - MP4 Base Media v1 [IS0 14496-12:2003]
# mp42 (common) - MP4 v2 [ISO 14496-14]
@@ -144,7 +148,7 @@ class MediaFile
# @return [Boolean] true if the file is an image
def is_image?
file_ext.in?([:jpg, :png, :gif, :avif])
file_ext.in?(%i[jpg png gif webp avif])
end
# @return [Boolean] true if the file is a video

View File

@@ -16,6 +16,8 @@ class MediaFile::Image < MediaFile
when :avif
# XXX Mirrored AVIFs should be unsupported too, but we currently can't detect the mirrored flag using exiftool or ffprobe.
!metadata.is_rotated? && !metadata.is_cropped? && !metadata.is_grid_image? && !metadata.is_animated_avif?
when :webp
!is_animated?
else
true
end
@@ -34,11 +36,12 @@ class MediaFile::Image < MediaFile
end
def frame_count
if file_ext == :gif
image.get("n-pages")
elsif file_ext == :png
case file_ext
when :gif, :webp
image.get("n-pages") if image.get_fields.include?("n-pages")
when :png
metadata.fetch("PNG:AnimationFrames", 1)
elsif file_ext == :avif
when :avif
video.frame_count
else
nil
@@ -124,6 +127,10 @@ class MediaFile::Image < MediaFile
file_ext == :png && is_animated?
end
def is_animated_webp?
file_ext == :webp && is_animated?
end
def is_animated_avif?
file_ext == :avif && is_animated?
end

View File

@@ -3,7 +3,7 @@
class MediaAsset < ApplicationRecord
class Error < StandardError; end
FILE_TYPES = %w[jpg png gif avif mp4 webm swf zip]
FILE_TYPES = %w[jpg png gif webp avif mp4 webm swf zip]
FILE_KEY_LENGTH = 9
VARIANTS = %i[preview 180x180 360x360 720x720 sample original]
MAX_FILE_SIZE = Danbooru.config.max_file_size.to_i
@@ -372,7 +372,7 @@ class MediaAsset < ApplicationRecord
concerning :FileTypeMethods do
def is_image?
file_ext.in?(%w[jpg png gif avif])
file_ext.in?(%w[jpg png gif webp avif])
end
def is_static_image?

View File

@@ -188,7 +188,7 @@ class Post < ApplicationRecord
end
def is_image?
file_ext =~ /jpg|gif|png|avif/i
file_ext =~ /jpg|gif|png|webp|avif/i
end
def is_flash?