split out image cropping to width x height, add StorageManager::Match

This commit is contained in:
Albert Yi
2018-07-03 17:55:02 -07:00
parent 99807580d5
commit 6dfb78fca8
5 changed files with 159 additions and 10 deletions

View File

@@ -17,11 +17,11 @@ module DanbooruImageResizer
end
end
def self.crop(file, length, quality = 90)
def self.crop(file, width, height, quality = 90)
if Vips.at_least_libvips?(8, 5)
crop_ruby(file, length, quality)
crop_ruby(file, width, height, quality)
else
crop_shell(file, length, quality)
crop_shell(file, width, height, quality)
end
end
@@ -35,9 +35,9 @@ module DanbooruImageResizer
output_file
end
def self.crop_ruby(file, length, resize_quality)
def self.crop_ruby(file, width, height, resize_quality)
output_file = Tempfile.new
resized_image = Vips::Image.thumbnail(file.path, length, height: length, **CROP_OPTIONS)
resized_image = Vips::Image.thumbnail(file.path, width, height: height, **CROP_OPTIONS)
resized_image.jpegsave(output_file.path, Q: resize_quality, **JPEG_OPTIONS)
output_file
@@ -65,7 +65,7 @@ module DanbooruImageResizer
output_file
end
def self.crop_shell(file, length, quality)
def self.crop_shell(file, width, height, quality)
output_file = Tempfile.new(["crop", ".jpg"])
# --size=WxH will upscale if the image is smaller than the target size.
@@ -76,7 +76,7 @@ module DanbooruImageResizer
file.path,
"--eprofile=#{SRGB_PROFILE}",
"--smartcrop=attention",
"--size=#{length}",
"--size=#{width}x#{height}",
"--format=#{output_file.path}[Q=#{quality},background=255,strip,interlace,optimize_coding]"
]

View File

@@ -69,7 +69,7 @@ class PixivUgoiraConverter
zipfile = Zip::File.new(ugoira_file.path)
zipfile.entries.first.extract(file.path) { true } # 'true' means overwrite the existing tempfile.
DanbooruImageResizer.crop(file, Danbooru.config.small_image_width, 85)
DanbooruImageResizer.crop(file, Danbooru.config.small_image_width, Danbooru.config.small_image_width, 85)
ensure
file.close!
end

View File

@@ -0,0 +1,113 @@
=begin
Generalizes the hybrid storage manager to be more declarative in
syntax. Matches are executed in order of appearance so the first
matching manager is returned. You should always add at least one
manager with no constraints as a default case.
This does not derive from StorageManager so only `open_file`,
`delete_file`, `store_file`, `file_url`, and `file_path` are
implemented.
### Example
StorageManager::Match.new do |matcher|
matcher.add_manager(type: :crop) do
StorageManager::SFTP.new("raikou3.donmai.us", base_url: "https://raikou3.donmai.us", hierarchical: true, base_dir: "/var/www/raikou3")
end
matcher.add_manager(id: 1..850_000) do
StorageManager::SFTP.new("raikou1.donmai.us", base_url: "https://raikou1.donmai.us", hierarchical: true, base_dir: "/var/www/raikou1")
end
matcher.add_manager(id: 850_001..2_000_000) do
StorageManager::SFTP.new("raikou2.donmai.us", base_url: "https://raikou2.donmai.us", hierarchical: true, base_dir: "/var/www/raikou2")
end
matcher.add_manager(id: 1..3_000_000, type: [:large, :original]) do
StorageManager::SFTP.new(*Danbooru.config.all_server_hosts, base_url: "https://hijiribe.donmai.us/data")
end
matcher.add_manager({}) do
StorageManager::SFTP.new(*Danbooru.config.all_server_hosts, base_url: "#{CurrentUser.root_url}/data")
end
end
=end
class StorageManager::Match
def initialize
@managers = []
yield self if block_given?
end
def add_manager(constraints)
manager = yield
@managers << [constraints, manager]
end
def find(params)
@managers.each do |constraints, manager|
match = true
if params[:id] && constraints[:id] && !constraints[:id].include?(params[:id].to_i)
match = false
end
if constraints[:id] && !params[:id]
match = false
end
if params[:type] && constraints[:type]
if constraints[:type].respond_to?(:include?)
if !constraints[:type].include?(params[:type])
match = false
end
elsif constraints[:type] != params[:type]
match = false
end
end
if constraints[:type] && !params[:type]
match = false
end
if match
yield manager if block_given?
return manager unless block_given?
end
end
end
def store_file(io, post, type)
find(id: post.id, type: type) do |manager|
manager.store_file(io, post, type)
end
end
def delete_file(post_id, md5, file_ext, type)
find(id: post_id, type: type) do |manager|
manager.delete_file(post_id, md5, file_ext, type)
end
end
def open_file(post, type)
find(id: post.id, type: type) do |manager|
manager.open_file(post, type)
end
end
def file_url(post, type, **options)
find(id: post.id, type: type) do |manager|
manager.file_url(post, type, **options)
end
end
def file_path(post, type, **options)
find(id: post.id, type: type) do |manager|
manager.file_path(post, type, **options)
end
end
end

View File

@@ -140,7 +140,7 @@ class UploadService
elsif upload.is_image?
preview_file = DanbooruImageResizer.resize(file, Danbooru.config.small_image_width, Danbooru.config.small_image_width, 85)
crop_file = DanbooruImageResizer.crop(file, Danbooru.config.small_image_width, 85)
crop_file = DanbooruImageResizer.crop(file, Danbooru.config.small_image_width, Danbooru.config.small_image_width, 85)
if upload.image_width > Danbooru.config.large_image_width
sample_file = DanbooruImageResizer.resize(file, Danbooru.config.large_image_width, upload.image_height, 90)
end
@@ -152,7 +152,7 @@ class UploadService
def self.generate_video_crop_for(video, width)
vp = Tempfile.new(["video-preview", ".jpg"], binmode: true)
video.screenshot(vp.path, {:seek_time => 0, :resolution => "#{video.width}x#{video.height}"})
crop = DanbooruImageResizer.crop(vp, width, 85)
crop = DanbooruImageResizer.crop(vp, width, width, 85)
vp.close
return crop
end

View File

@@ -7,6 +7,42 @@ class StorageManagerTest < ActiveSupport::TestCase
CurrentUser.ip_addr = "127.0.0.1"
end
context "StorageManager::Match" do
setup do
@storage_manager = StorageManager::Match.new do |matcher|
matcher.add_manager(type: :crop) do
"crop"
end
matcher.add_manager(type: [:large, :original]) do
"large or original"
end
matcher.add_manager(id: 1..100) do
"first"
end
matcher.add_manager(id: 101..200, type: :preview) do
"preview"
end
matcher.add_manager({}) do
"default"
end
end
end
should "find the different matches" do
assert_equal("large or original", @storage_manager.find(type: :original))
assert_equal("crop", @storage_manager.find(type: :crop))
assert_equal("large or original", @storage_manager.find(type: :large))
assert_equal("preview", @storage_manager.find(type: :preview, id: 150))
assert_equal("default", @storage_manager.find(type: :preview, id: 1000))
assert_equal("crop", @storage_manager.find(type: :crop, id: 1_000))
assert_equal("large or original", @storage_manager.find(type: :large, id: 1_000))
end
end
context "StorageManager::Local" do
setup do
@storage_manager = StorageManager::Local.new(base_dir: BASE_DIR, base_url: "/data")