# frozen_string_literal: true require_relative 'shell_helper' module Booru module ImageProcessing class GifProcessor < Processor include ShellHelper def initialize(original_path, directory, metadata) super(original_path, directory, metadata) # We keep around references to the Tempfile objects so that they don't get GC'd (and deleted) too early. @palette_tempfile = Tempfile.new(%w[palette .png]).tap(&:close) @palette_path = @palette_tempfile.path @rasterized_tempfile = Tempfile.new(%w[still .png]).tap(&:close) @rasterized = @rasterized_tempfile.path # @palette_path = File.join(@directory, 'palette.png') # @rasterized = File.join(@directory, 'still.png') end def pre_process write_log 'pre_process' # generate a palette for use in later processing ffmpeg '-i', @original_path, '-vf', 'palettegen=stats_mode=diff', @palette_path generate_rasterized end def generate_rasterized # generate a still image for use in intensities generation median_time = @metadata[:duration] / 2.0 generate_thumb @original_path, median_time, @rasterized end def generate_version(dimensions, destination_path) write_log "generate_version #{dimensions} #{destination_path}" width, height = dimensions # okay, this is a little bit fucking complicated, I will give you that. # https://engineering.giphy.com/how-to-make-gifs-with-ffmpeg/ # TL;DR: It's a big ol' pipeline that resizes the image and uses a palette when resizing it (this makes a better looking gif, somehow), ffmpeg '-i', @original_path, '-i', @palette_path, '-filter_complex', "scale=w=#{width}:h=#{height}:force_original_aspect_ratio=decrease [x]; [x][1:v] paletteuse=dither=bayer:bayer_scale=5:diff_mode=rectangle:alpha_threshold=255", destination_path end # def generate_compressed_version(dimensions, destination_path) # write_log "generate_compressed_version #{dimensions} #{destination_path}" # # width, height = dimensions # # ffmpeg '-i', @original_path, # '-i', @palette_path, # '-filter_complex', "scale=w=#{width}:h=#{height}:force_original_aspect_ratio=decrease [x]; [x][1:v] paletteuse=dither=bayer:bayer_scale=5:diff_mode=rectangle:alpha_threshold=255", # '-vcodec', 'libwebp', # '-lossless', '0', # '-vsync', '0', # '-loop', '0', # destination_path # end def post_process write_log 'post_process' # clean up the palette we generated FileUtils.rm(@palette_path) # clean up still image FileUtils.rm(@rasterized) end def additional_process write_log 'additional_process' output_file = "#{@directory}/full.webm" # Generate full WebM from original gif ffmpeg '-f', 'gif', '-i', @original_path, '-pix_fmt', 'yuv420p', '-c:v', 'libvpx', '-quality', 'good', '-cpu-used', '0', '-crf', '6', '-b:v', '1M', '-r', '25', '-an', output_file end end end end