From 438fa306ae6e6ca6c4c6876a9f8167d2480d61d8 Mon Sep 17 00:00:00 2001 From: Gavin McDonald Date: Mon, 5 May 2025 13:19:37 -0400 Subject: [PATCH] serve images, not HTML --- lib/labelmaker_web/constants.ex | 37 ++++++++++++++ .../controllers/label_controller.ex | 48 +++++++++++++++++++ lib/labelmaker_web/router.ex | 3 +- 3 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 lib/labelmaker_web/constants.ex create mode 100644 lib/labelmaker_web/controllers/label_controller.ex diff --git a/lib/labelmaker_web/constants.ex b/lib/labelmaker_web/constants.ex new file mode 100644 index 0000000..22ff0b4 --- /dev/null +++ b/lib/labelmaker_web/constants.ex @@ -0,0 +1,37 @@ +defmodule LabelmakerWeb.Constants do + @defaults %{ + "label" => "Labelmaker", + "font" => "Helvetica", + "color" => "black", + "size" => "24" + } + + @permitted_keys Map.keys(@defaults) + + @colors System.cmd("magick", ["-list", "color"]) + |> elem(0) + |> String.split("\n") + # drop header stuff + |> Enum.drop(5) + |> Enum.map(fn color_info -> color_info |> String.split() |> List.first() end) + + @fonts System.cmd("magick", ["-list", "font"]) + |> elem(0) + |> String.split("\n") + |> Enum.filter(&String.starts_with?(&1, " Font:")) + |> Enum.reject(&String.starts_with?(&1, " Font: .")) + |> Enum.map(&String.trim_leading(&1, " Font: ")) + + @sizes 8..72 + |> Enum.to_list() + |> Enum.take_every(4) + |> Enum.map(&Integer.to_string/1) + + def defaults, do: @defaults + def permitted_keys, do: @permitted_keys + def colors, do: @colors + def color_count, do: @colors |> length() + def fonts, do: @fonts + def font_count, do: @fonts |> length() + def sizes, do: @sizes +end diff --git a/lib/labelmaker_web/controllers/label_controller.ex b/lib/labelmaker_web/controllers/label_controller.ex new file mode 100644 index 0000000..93eebf1 --- /dev/null +++ b/lib/labelmaker_web/controllers/label_controller.ex @@ -0,0 +1,48 @@ +defmodule LabelmakerWeb.LabelController do + use LabelmakerWeb, :controller + alias LabelmakerWeb.Constants + + @label_dir Path.join(:code.priv_dir(:labelmaker), "static/labels") + File.mkdir_p!(@label_dir) + + def show(conn, params) do + options = + Constants.defaults() + |> Map.merge(params) + |> Map.take(Constants.permitted_keys()) + + filename = + options + |> inspect() + |> (fn str -> :crypto.hash(:sha256, str) end).() + |> Base.encode16(case: :lower) + + filename = filename <> ".png" + filepath = Path.join(@label_dir, filename) + + unless File.exists?(filepath) do + generate_image(options, filepath) + end + + conn + |> put_resp_content_type("image/png") + |> send_file(200, filepath) + end + + defp generate_image(options, filepath) do + args = [ + "-background", + "none", + "-fill", + options["color"], + "-pointsize", + options["size"], + "-font", + options["font"], + "label:#{options["label"]}", + filepath + ] + + {_, 0} = System.cmd("magick", args) + end +end diff --git a/lib/labelmaker_web/router.ex b/lib/labelmaker_web/router.ex index 16838f6..1602490 100644 --- a/lib/labelmaker_web/router.ex +++ b/lib/labelmaker_web/router.ex @@ -24,7 +24,8 @@ defmodule LabelmakerWeb.Router do pipe_through :browser live "/", Home - live "/:label", Label + get "/:label", LabelController, :show + # live "/:label", Label end # Other scopes may use custom stacks.