#!/usr/bin/env ruby # app.rb — Simple Ruby/Sinatra Image → JPEG converter # Supports: # - JPEG quality slider # - CRT/scanline retro effect # - Pixelation (with user slider) # # Requires: # gem install sinatra sinatra-contrib mini_magick rackup puma # sudo apt install imagemagick # # Run: # bundle exec ruby app.rb # # Then open: http://localhost:4567/ require "sinatra" require "sinatra/reloader" if development? require "mini_magick" require "fileutils" require "securerandom" set :bind, "0.0.0.0" set :port, 4567 set :public_folder, File.join(__dir__, "public") OUTPUT_DIR = File.join(settings.public_folder, "output") FileUtils.mkdir_p OUTPUT_DIR # ------------------------------------------------------------------- # HELPERS — Image effects + utilities # ------------------------------------------------------------------- helpers do # ----------------------------------------------------------------- # CRT / Scanline effect # ----------------------------------------------------------------- def apply_crt_effect(image) image.combine_options do |c| c.resize "640x480" c.contrast c.noise "2" end scanlines_path = File.join(settings.public_folder, "scanlines.png") if File.exist?(scanlines_path) scan = MiniMagick::Image.open(scanlines_path) scan.resize "#{image.width}x#{image.height}!" image = image.composite(scan) do |c| c.compose "overlay" c.gravity "center" end end image end # ----------------------------------------------------------------- # Pixelation effect with user-adjustable factor # ----------------------------------------------------------------- def apply_pixelate_effect(image, factor = 8) width = image.width height = image.height small_w = [width / factor, 1].max small_h = [height / factor, 1].max image.combine_options do |c| c.filter "point" c.resize "#{small_w}x#{small_h}!" c.resize "#{width}x#{height}!" end image end # Human-readable formatting def human_size(bytes) kb = bytes / 1024.0 return "#{kb.round(1)} KB" if kb < 1024 mb = kb / 1024.0 "#{mb.round(2)} MB" end end # ------------------------------------------------------------------- # ROUTES # ------------------------------------------------------------------- get "/" do erb :index end post "/convert" do unless params[:image] && params[:image][:tempfile] @error = "Please choose an image file." return erb :index end tempfile = params[:image][:tempfile] filename = params[:image][:filename] quality = (params[:quality] || "80").to_i effect = params[:effect] quality = 1 if quality < 1 quality = 100 if quality > 100 begin image = MiniMagick::Image.open(tempfile.path) # ------------------------------ # Apply effects # ------------------------------ case effect when "crt" image = apply_crt_effect(image) @effect_used = "CRT / scanline" when "pixel" factor = (params[:pixel_factor] || 8).to_i factor = 2 if factor < 2 factor = 25 if factor > 25 image = apply_pixelate_effect(image, factor) @effect_used = "Pixelated (factor #{factor})" else @effect_used = "None" end # Convert to JPEG image.format "jpg" image.quality quality.to_s output_name = "converted-#{SecureRandom.hex(8)}.jpg" output_path = File.join(OUTPUT_DIR, output_name) image.write(output_path) @original_name = filename @output_url = "/output/#{output_name}" @output_size = human_size(File.size(output_path)) @chosen_quality = quality erb :result rescue => e @error = "Conversion failed: #{e.message}" erb :index end end # ------------------------------------------------------------------- # INLINE HTML TEMPLATES # ------------------------------------------------------------------- __END__ @@layout Rubymagick JPG Converter

♦️ Image → JPEG Converter

<%= yield %> @@index
<% if @error %>
<%= @error %>
<% end %>
@@result

Conversion complete

Original: <%= @original_name %>
Quality: <%= @chosen_quality %>
Effect: <%= @effect_used %>
Output size: <%= @output_size %>

Converted image preview
Download JPEG