dither.rb (2301B)
1 require "sinatra" 2 require "mini_magick" 3 require "digest" 4 require "fileutils" 5 require "tempfile" 6 7 MiniMagick.logger.level = Logger::DEBUG 8 9 ROOT = ENV.fetch("ROOT") 10 KEY = ENV.fetch("KEY") 11 DITHER = ENV["DITHER"] != "0" 12 FORMAT = "png" 13 CACHE_DIR = ENV["DITHER_CACHE_DIR"] 14 15 def cache_path_for(path, geometry) 16 return unless CACHE_DIR 17 18 source_path = "#{ROOT}/#{path}.enc" 19 cache_key = Digest::SHA256.hexdigest([ 20 path, 21 Digest::SHA256.file(source_path).hexdigest, 22 geometry, 23 DITHER, 24 FORMAT, 25 1 26 ].join("\0")) 27 28 FileUtils.mkdir_p(CACHE_DIR) 29 File.join(CACHE_DIR, "#{cache_key}.#{FORMAT}") 30 end 31 32 get "/*" do |path| 33 halt 404, {"Content-Type" => "text/plain"}, "not found" unless File.exist?("#{ROOT}/#{path}.enc") 34 35 content_type "image/#{FORMAT}" 36 37 geometry = params["geo"] unless params["geo"] == "" 38 geometry.gsub!(/\d+/) { |n| n.to_i * 2 } if geometry && !DITHER 39 40 cached_path = cache_path_for(path, geometry) 41 if cached_path && File.exist?(cached_path) 42 return File.binread(cached_path) 43 end 44 45 decrypted = Tempfile.new(["dither", File.extname(path)]) 46 decrypted.binmode 47 decrypted.close 48 49 begin 50 openssl_ok = system( 51 "openssl", 52 "aes-256-cbc", 53 "-d", 54 "-in", "#{ROOT}/#{path}.enc", 55 "-out", decrypted.path, 56 "-pass", "file:#{KEY}", 57 "-iter", "1000000" 58 ) 59 halt 500, {"Content-Type" => "text/plain"}, "decrypt failed" unless openssl_ok 60 61 convert = MiniMagick::Tool::Convert.new 62 convert.limit("memory", "128MiB") 63 convert.limit("map", "256MiB") 64 convert.limit("disk", "1GiB") 65 convert << decrypted.path 66 convert.background("white") 67 convert.layers("flatten") 68 convert.strip 69 convert.auto_orient 70 71 if geometry 72 if geometry.match?(/^\d+x\d+$/) 73 convert.resize "#{geometry}^" 74 convert.gravity "center" 75 convert.extent geometry 76 else 77 convert.resize geometry 78 end 79 end 80 81 if DITHER 82 convert.ordered_dither "o8x8" 83 convert.monochrome 84 end 85 86 convert << "#{FORMAT.upcase}:-" 87 output = convert.call 88 89 if cached_path 90 temp_cache_path = "#{cached_path}.tmp-#{Process.pid}" 91 File.binwrite(temp_cache_path, output) 92 FileUtils.mv(temp_cache_path, cached_path) 93 end 94 95 output 96 ensure 97 decrypted.unlink 98 end 99 end