From 6dfb78fca8f6445ef236444a4ab53f16153f1ec6 Mon Sep 17 00:00:00 2001 From: Albert Yi Date: Tue, 3 Jul 2018 17:55:02 -0700 Subject: [PATCH] split out image cropping to width x height, add StorageManager::Match --- app/logical/danbooru_image_resizer.rb | 14 ++-- app/logical/pixiv_ugoira_converter.rb | 2 +- app/logical/storage_manager/match.rb | 113 ++++++++++++++++++++++++++ app/logical/upload_service.rb | 4 +- test/unit/storage_manager_test.rb | 36 ++++++++ 5 files changed, 159 insertions(+), 10 deletions(-) create mode 100644 app/logical/storage_manager/match.rb diff --git a/app/logical/danbooru_image_resizer.rb b/app/logical/danbooru_image_resizer.rb index 40490e9b0..a62ddc290 100644 --- a/app/logical/danbooru_image_resizer.rb +++ b/app/logical/danbooru_image_resizer.rb @@ -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]" ] diff --git a/app/logical/pixiv_ugoira_converter.rb b/app/logical/pixiv_ugoira_converter.rb index a3608682d..6d645a879 100644 --- a/app/logical/pixiv_ugoira_converter.rb +++ b/app/logical/pixiv_ugoira_converter.rb @@ -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 diff --git a/app/logical/storage_manager/match.rb b/app/logical/storage_manager/match.rb new file mode 100644 index 000000000..6eacefb3e --- /dev/null +++ b/app/logical/storage_manager/match.rb @@ -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 + diff --git a/app/logical/upload_service.rb b/app/logical/upload_service.rb index cd8ea784f..27aa8a32b 100644 --- a/app/logical/upload_service.rb +++ b/app/logical/upload_service.rb @@ -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 diff --git a/test/unit/storage_manager_test.rb b/test/unit/storage_manager_test.rb index 42ca03f15..9af8c6ede 100644 --- a/test/unit/storage_manager_test.rb +++ b/test/unit/storage_manager_test.rb @@ -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")