berrypod/lib/simpleshop_theme_web/controllers/image_controller.ex

94 lines
2.7 KiB
Elixir
Raw Normal View History

defmodule SimpleshopThemeWeb.ImageController do
use SimpleshopThemeWeb, :controller
alias SimpleshopTheme.Media
alias SimpleshopTheme.Media.SVGRecolorer
@doc """
Serves an image from the database by ID.
Images are served with aggressive caching headers since they are
immutable once uploaded.
"""
def show(conn, %{"id" => id}) do
case Media.get_image(id) do
nil ->
send_resp(conn, 404, "Image not found")
image ->
conn
|> put_resp_content_type(image.content_type)
|> put_resp_header("cache-control", "public, max-age=31536000, immutable")
|> put_resp_header("etag", ~s("#{image.id}"))
|> send_resp(200, image.data)
end
end
@doc """
Serves a thumbnail of an image if available, otherwise falls back to full image.
"""
def thumbnail(conn, %{"id" => id}) do
case Media.get_image(id) do
nil ->
send_resp(conn, 404, "Image not found")
%{thumbnail_data: thumbnail_data} = image when not is_nil(thumbnail_data) ->
conn
|> put_resp_content_type("image/jpeg")
|> put_resp_header("cache-control", "public, max-age=31536000, immutable")
|> put_resp_header("etag", ~s("#{image.id}-thumb"))
|> send_resp(200, thumbnail_data)
image ->
conn
|> put_resp_content_type(image.content_type)
|> put_resp_header("cache-control", "public, max-age=31536000, immutable")
|> put_resp_header("etag", ~s("#{image.id}"))
|> send_resp(200, image.data)
end
end
@doc """
Serves an SVG image recolored with the specified color.
The color should be a hex color code (with or without the leading #).
Only works with SVG images.
"""
def recolored_svg(conn, %{"id" => id, "color" => color}) do
clean_color = normalize_color(color)
with true <- SVGRecolorer.valid_hex_color?(clean_color),
%{is_svg: true, svg_content: svg} when not is_nil(svg) <- Media.get_image(id) do
recolored = SVGRecolorer.recolor(svg, clean_color)
conn
|> put_resp_content_type("image/svg+xml")
|> put_resp_header("cache-control", "public, max-age=3600")
|> put_resp_header("etag", ~s("#{id}-#{clean_color}"))
|> send_resp(200, recolored)
else
false ->
send_resp(conn, 400, "Invalid color format")
nil ->
send_resp(conn, 404, "Image not found")
%{is_svg: false} ->
send_resp(conn, 400, "Image is not an SVG")
%{svg_content: nil} ->
send_resp(conn, 400, "SVG content not available")
end
end
defp normalize_color(color) do
color = String.trim(color)
if String.starts_with?(color, "#") do
color
else
"#" <> color
end
end
end