Fix #3582: Switch from ImageMagick to libvips
This commit is contained in:
@@ -1,52 +1,18 @@
|
||||
module DanbooruImageResizer
|
||||
def resize(file, width, height, resize_quality = 90)
|
||||
image = Magick::Image.read(file.path).first
|
||||
geometry = "#{width}x>"
|
||||
# Taken from ArgyllCMS 2.0.0 (see also: https://ninedegreesbelow.com/photography/srgb-profile-comparison.html)
|
||||
SRGB_PROFILE = "#{Rails.root}/config/sRGB.icm"
|
||||
# http://jcupitt.github.io/libvips/API/current/libvips-resample.html#vips-thumbnail
|
||||
THUMBNAIL_OPTIONS = { size: :down, linear: false, auto_rotate: false, export_profile: SRGB_PROFILE }
|
||||
# http://jcupitt.github.io/libvips/API/current/VipsForeignSave.html#vips-jpegsave
|
||||
JPEG_OPTIONS = { background: 255, strip: true, interlace: true, optimize_coding: true }
|
||||
|
||||
if width == Danbooru.config.small_image_width
|
||||
# wider than it is tall
|
||||
geometry = "#{Danbooru.config.small_image_width}x#{Danbooru.config.small_image_width}>"
|
||||
end
|
||||
# https://github.com/jcupitt/libvips/wiki/HOWTO----Image-shrinking
|
||||
# http://jcupitt.github.io/libvips/API/current/Using-vipsthumbnail.md.html
|
||||
def self.resize(file, width, height, resize_quality = 90)
|
||||
output_file = Tempfile.new
|
||||
resized_image = Vips::Image.thumbnail(file.path, width, height: height, **THUMBNAIL_OPTIONS)
|
||||
resized_image.jpegsave(output_file.path, Q: resize_quality, **JPEG_OPTIONS)
|
||||
|
||||
image.change_geometry(geometry) do |new_width, new_height, img|
|
||||
img.resize!(new_width, new_height)
|
||||
width = new_width
|
||||
height = new_height
|
||||
end
|
||||
|
||||
image = flatten(image, width, height)
|
||||
image.strip!
|
||||
|
||||
output_file = Tempfile.new(binmode: true)
|
||||
image.write("jpeg:" + output_file.path) do
|
||||
self.quality = resize_quality
|
||||
# setting PlaneInterlace enables progressive encoding for JPEGs
|
||||
self.interlace = Magick::PlaneInterlace
|
||||
end
|
||||
|
||||
image.destroy!
|
||||
output_file
|
||||
end
|
||||
|
||||
def flatten(image, width, height)
|
||||
if image.alpha?
|
||||
# since jpeg can't represent transparency, we need to create an image list,
|
||||
# put a white image on the bottom, then flatten it.
|
||||
|
||||
list = Magick::ImageList.new
|
||||
list.new_image(width, height) do
|
||||
self.background_color = "#FFFFFF"
|
||||
end
|
||||
list << image
|
||||
flattened_image = list.flatten_images
|
||||
list.each do |image|
|
||||
image.destroy!
|
||||
end
|
||||
return flattened_image
|
||||
else
|
||||
return image
|
||||
end
|
||||
end
|
||||
|
||||
module_function :resize, :flatten
|
||||
end
|
||||
|
||||
@@ -226,7 +226,17 @@ class Upload < ApplicationRecord
|
||||
end
|
||||
|
||||
def is_animated_gif?
|
||||
file_ext == "gif" && Magick::Image.ping(file.path).length > 1
|
||||
return false if file_ext != "gif"
|
||||
|
||||
# Check whether the gif has multiple frames by trying to load the second frame.
|
||||
result = Vips::Image.gifload(file.path, page: 1) rescue $ERROR_INFO
|
||||
if result.is_a?(Vips::Image)
|
||||
true
|
||||
elsif result.is_a?(Vips::Error) && result.message.match?(/too few frames in GIF file/)
|
||||
false
|
||||
else
|
||||
raise result
|
||||
end
|
||||
end
|
||||
|
||||
def is_animated_png?
|
||||
@@ -245,7 +255,7 @@ class Upload < ApplicationRecord
|
||||
preview_file = DanbooruImageResizer.resize(file, Danbooru.config.small_image_width, Danbooru.config.small_image_width, 85)
|
||||
|
||||
if image_width > Danbooru.config.large_image_width
|
||||
sample_file = DanbooruImageResizer.resize(file, Danbooru.config.large_image_width, nil, 90)
|
||||
sample_file = DanbooruImageResizer.resize(file, Danbooru.config.large_image_width, image_height, 90)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
Reference in New Issue
Block a user