diff --git a/README.md b/README.md index 04d410097..4b2bb9d6a 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,15 @@ +## JPEG XL PostThumbnailer + +Experimental code that generates JPEG XL crops, previews, and samples instead of JPEG ones. +Kept for future reference. + +### Notes + +* APNG's will be non-animated JXL's because libvips and libspng is lacking APNG support +* JXL's will be non-animated unless libvips v8.16.0 is used +This can be worked around by doing something like: +$ cjxl XX/XX/md5.png sample/XX/XX/md5.jxl +
diff --git a/app/logical/danbooru_image_resizer.rb b/app/logical/danbooru_image_resizer.rb index 99bfc8831..aa3b6dad4 100644 --- a/app/logical/danbooru_image_resizer.rb +++ b/app/logical/danbooru_image_resizer.rb @@ -8,6 +8,8 @@ module DanbooruImageResizer # https://www.libvips.org/API/current/VipsForeignSave.html#vips-jpegsave JPEG_OPTIONS = { strip: true, interlace: true, optimize_coding: true }.freeze CROP_OPTIONS = { linear: false, no_rotate: true, export_profile: "srgb", import_profile: "srgb", crop: :attention }.freeze + # https://www.libvips.org/API/current/VipsForeignSave.html#vips-jxlsave + JPEGXL_OPTIONS = { lossless: false }.freeze def resize(file, width, height, resize_quality = 90, background_color: "000000") r = background_color[0..1].to_i(16) @@ -20,6 +22,14 @@ module DanbooruImageResizer output_file end + def resize_jxl(file, width, height, distance = 1.0, effort = 7) + output_file = Tempfile.new + resized_image = thumbnail(file, width, height, THUMBNAIL_OPTIONS) + resized_image.jxlsave(output_file.path, distance: distance, effort: effort, **JPEGXL_OPTIONS) + + output_file + end + def crop(file, width, height, resize_quality = 90, background_color: "000000") return nil unless Danbooru.config.enable_image_cropping? @@ -33,6 +43,16 @@ module DanbooruImageResizer output_file end + def crop_jxl(file, width, height, distance = 1.0, effort = 7) + return nil unless Danbooru.config.enable_image_cropping? + + output_file = Tempfile.new + resized_image = thumbnail(file, width, height, CROP_OPTIONS) + resized_image.jxlsave(output_file.path, distance: distance, effort: effort, **JPEGXL_OPTIONS) + + output_file + end + # https://github.com/libvips/libvips/wiki/HOWTO----Image-shrinking # https://www.libvips.org/API/current/Using-vipsthumbnail.md.html def thumbnail(file, width, height, options) diff --git a/app/logical/post_thumbnailer.rb b/app/logical/post_thumbnailer.rb index a9444ca4c..0f418ca02 100644 --- a/app/logical/post_thumbnailer.rb +++ b/app/logical/post_thumbnailer.rb @@ -7,12 +7,12 @@ module PostThumbnailer video = FFMPEG::Movie.new(file.path) crop_file = generate_video_crop_for(video, Danbooru.config.small_image_width) preview_file = generate_video_preview_for(file.path, Danbooru.config.small_image_width) - sample_file = generate_video_sample_for(file.path) + sample_file = generate_video_sample_for(file.path, height) elsif type == :image - preview_file = DanbooruImageResizer.resize(file, Danbooru.config.small_image_width, Danbooru.config.small_image_width, 87, background_color: background_color) - crop_file = DanbooruImageResizer.crop(file, Danbooru.config.small_image_width, Danbooru.config.small_image_width, 87, background_color: background_color) + preview_file = DanbooruImageResizer.resize_jxl(file, Danbooru.config.small_image_width, Danbooru.config.small_image_width, 1.0, 9) + crop_file = DanbooruImageResizer.crop_jxl(file, Danbooru.config.small_image_width, Danbooru.config.small_image_width, 1.0, 9) if width > Danbooru.config.large_image_width - sample_file = DanbooruImageResizer.resize(file, Danbooru.config.large_image_width, height, 87, background_color: background_color) + sample_file = DanbooruImageResizer.resize_jxl(file, Danbooru.config.large_image_width, height, 1.0, 9) end end @@ -23,7 +23,7 @@ module PostThumbnailer if type == :video preview_file = generate_video_preview_for(file.path, Danbooru.config.small_image_width) elsif type == :image - preview_file = DanbooruImageResizer.resize(file, Danbooru.config.small_image_width, Danbooru.config.small_image_width, 87) + preview_file = DanbooruImageResizer.resize_jxl(file, Danbooru.config.small_image_width, Danbooru.config.small_image_width, 1.0, 9) end preview_file @@ -32,7 +32,7 @@ module PostThumbnailer def 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, width, 87) + crop = DanbooruImageResizer.crop_jxl(vp, width, width, 1.0, 9) vp.close return crop end @@ -46,10 +46,11 @@ module PostThumbnailer Rails.logger.warn("[FFMPEG PREVIEW STDERR] #{stderr.chomp!}") raise CorruptFileError.new("could not generate thumbnail") end - output_file + preview_file = DanbooruImageResizer.resize_jxl(output_file, Danbooru.config.small_image_width, Danbooru.config.small_image_width, 1.0, 9) + preview_file end - def generate_video_sample_for(video) + def generate_video_sample_for(video, height) output_file = Tempfile.new(["video-sample", ".jpg"], binmode: true) stdout, stderr, status = Open3.capture3(Danbooru.config.ffmpeg_path, '-y', '-i', video, '-vf', 'thumbnail', '-frames:v', '1', output_file.path) @@ -58,6 +59,7 @@ module PostThumbnailer Rails.logger.warn("[FFMPEG SAMPLE STDERR] #{stderr.chomp!}") raise CorruptFileError.new("could not generate sample") end - output_file + sample_file = DanbooruImageResizer.resize_jxl(output_file, Danbooru.config.large_image_width, height, 1.0, 9) + sample_file end end diff --git a/app/logical/storage_manager.rb b/app/logical/storage_manager.rb index 00a5e4a6d..5035478b1 100644 --- a/app/logical/storage_manager.rb +++ b/app/logical/storage_manager.rb @@ -168,11 +168,11 @@ class StorageManager def file_name(md5, file_ext, type, scale_factor: nil) case type when :preview - "#{md5}.jpg" + "#{md5}.jxl" when :crop - "#{md5}.jpg" + "#{md5}.jxl" when :large - "#{large_image_prefix}#{md5}.jpg" + "#{large_image_prefix}#{md5}.jxl" when :original "#{md5}.#{file_ext}" when :scaled diff --git a/app/models/post.rb b/app/models/post.rb index aa2685c01..0be7efa1d 100644 --- a/app/models/post.rb +++ b/app/models/post.rb @@ -253,7 +253,7 @@ class Post < ApplicationRecord return true if is_video? return false if is_gif? return false if is_flash? - return false if has_tag?("animated_gif", "animated_png") + #return false if has_tag?("animated_gif", "animated_png") is_image? && image_width.present? && image_width > Danbooru.config.large_image_width end