diff --git a/app/controllers/media_controller.rb b/app/controllers/media_controller.rb
new file mode 100644
index 0000000000000000000000000000000000000000..d634564413bc28edb75b4aeecd32b8a1ca760aad
--- /dev/null
+++ b/app/controllers/media_controller.rb
@@ -0,0 +1,54 @@
+class MediaController < ApplicationController
+  def show
+    @blob = ActiveStorage::Blob.find_signed! params[:signed_id]
+    filename_with_transformations = params[:filename_with_transformations]
+    parts = filename_with_transformations.split('_')
+    transformations = { format: params[:format] }
+    dimensions = nil
+    loop do
+      key, value = parts.pop(2)
+      if ['crop', 'scale'].include?(key)
+        transformations[key.to_sym] = value
+      else
+        dimensions = (value || key).split('x')
+        dimensions << '' if dimensions.one?
+        break
+      end
+    end
+
+    dimensions.map! { |dimension| dimension.to_i.to_s == dimension ? dimension.to_i : nil }
+    dimensions = [
+      @blob.metadata[:width],
+      @blob.metadata[:height]
+    ] unless dimensions.any? { |dimension| dimension.is_a?(Integer) }
+
+    scale_value = transformations.delete(:scale).to_i
+    dimensions.map! { |dimension| dimension * scale_value if dimension.is_a?(Integer) } if [2, 3].include? scale_value
+
+    crop_value = transformations.delete(:crop)
+    crop_parameter = gravity_per_crop.keys.detect { |gravity| gravity == crop_value }
+    if crop_parameter.present?
+      gravity = gravity_per_crop[crop_parameter] || 'Center'
+      transformations.merge!({
+        resize_to_fill: [*dimensions, { gravity: gravity }],
+        crop: "#{dimensions.join('x')}+0+0"
+      })
+    else
+      transformations.merge!({ resize_to_limit: dimensions })
+    end
+
+    render json: { transformations: transformations, url: url_for(@blob.variant(transformations)) }
+  end
+
+  protected
+
+  def gravity_per_crop
+    {
+      'top' => 'North',
+      'right' => 'East',
+      'bottom' => 'South',
+      'left' => 'West',
+      'center' => 'Center'
+    }
+  end
+end
diff --git a/config/routes.rb b/config/routes.rb
index 47406f626d9ccb002e8f6b0dfda383fcd4b24754..516bcd0b11ebee16dc86f330595789eb993461e2 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -26,5 +26,7 @@ Rails.application.routes.draw do
     root to: 'dashboard#index'
   end
 
+  get '/media/:signed_id/:filename_with_transformations' => 'media#show', as: :medium
+
   root to: 'admin/dashboard#index'
 end