diff --git a/lib/labelmaker_web/constants.ex b/lib/labelmaker_web/constants.ex index 2ee98bb..ffa8a7b 100644 --- a/lib/labelmaker_web/constants.ex +++ b/lib/labelmaker_web/constants.ex @@ -1,11 +1,14 @@ defmodule LabelmakerWeb.Constants do @defaults %{ + color: "black", + font: "Helvetica", + gravity: "Center", + height: "0", label: "", link: "", - font: "Helvetica", - color: "black", outline: "none", - size: "72" + size: "72", + width: "0" } @preview %{ @@ -53,8 +56,11 @@ defmodule LabelmakerWeb.Constants do "verdana" => "Verdana" } - @max_label_length 64 - @max_label_error "64-character maximum" + @max_height 1024 + @max_width 1024 + + @max_label_length 1024 + @max_label_error "1024-character maximum" @sizes 16..128 |> Enum.to_list() @@ -73,6 +79,8 @@ defmodule LabelmakerWeb.Constants do |> Enum.map(fn color -> color |> String.replace("-MS", "") |> String.replace("-", " ") end) def font_map, do: @font_map + def max_height, do: @max_height + def max_width, do: @max_width def max_label_length, do: @max_label_length def max_label_error, do: @max_label_error def outlines, do: ["none" | @colors] diff --git a/lib/labelmaker_web/controllers/label_controller.ex b/lib/labelmaker_web/controllers/label_controller.ex index b4d0799..b0e30cf 100644 --- a/lib/labelmaker_web/controllers/label_controller.ex +++ b/lib/labelmaker_web/controllers/label_controller.ex @@ -16,9 +16,14 @@ defmodule LabelmakerWeb.LabelController do filename = filename <> ".png" filepath = Path.join(@label_dir, filename) + options = Map.put(options, :filepath, filepath) unless File.exists?(filepath) do - generate_image(options, filepath) + basic_settings(options) + |> size_settings(options) + |> outline_settings(options) + |> final_settings(options) + |> generate_image() end conn @@ -26,36 +31,61 @@ defmodule LabelmakerWeb.LabelController do |> send_file(200, filepath) end - defp generate_image(options, filepath) do - File.mkdir_p!(@label_dir) - - args = [ + defp basic_settings(options) do + [ "-background", "none", "-fill", options.color, - "-pointsize", - options.size, "-font", - options.font, - "label:#{String.slice(options.label, 0, Constants.max_label_length())}", - "-set", - "comment", - inspect(Jason.encode!(Map.drop(options, [:link]))), - filepath + options.font ] + end - args = - if options.outline != "none" do - [ - "-stroke", - options.outline, - "-strokewidth", - "1" - ] ++ args - else - args - end + defp size_settings(args, %{height: 0, width: 0} = options) do + args ++ + [ + "-pointsize", + options.size, + "label:#{String.slice(options.label, 0, Constants.max_label_length())}" + ] + end + + defp size_settings(args, %{gravity: gravity, height: height, width: width} = options) do + args ++ + [ + "-gravity", + gravity, + "-size", + "#{width}x#{height}", + "caption:#{String.slice(options.label, 0, Constants.max_label_length())}" + ] + end + + defp outline_settings(args, %{outline: "none"}), do: args + + defp outline_settings(args, %{outline: color}) do + args ++ + [ + "-stroke", + color, + "-strokewidth", + "1" + ] + end + + defp final_settings(args, options) do + args ++ + [ + "-set", + "comment", + inspect(Jason.encode!(Map.drop(options, [:filepath, :link]))), + options.filepath + ] + end + + defp generate_image(args) do + File.mkdir_p!(@label_dir) {_, 0} = System.cmd("magick", args) end diff --git a/lib/labelmaker_web/tools.ex b/lib/labelmaker_web/tools.ex index 914a345..c061a2f 100644 --- a/lib/labelmaker_web/tools.ex +++ b/lib/labelmaker_web/tools.ex @@ -8,37 +8,33 @@ defmodule LabelmakerWeb.Tools do alias LabelmakerWeb.Constants def process_parameters(parameters) do - # ensure our defaults are in place to cover any missing parameters - %{"label" => label, "size" => size} = + parameters = Constants.defaults() |> Map.new(fn {k, v} -> {Atom.to_string(k), v} end) |> Map.merge(parameters) - - link = ~p"/#{label}?#{Map.take(parameters, ["color", "font", "outline", "size"])}" - line_breaks = Regex.scan(~r/#{Regex.escape("\\n")}/, label) |> length() - size = String.to_integer(size) - - parameters = - parameters |> Map.take(Constants.permitted_keys()) |> Map.new(fn {k, v} -> {String.to_atom(k), v} end) |> Enum.map(fn {:font, font} -> {:font, Constants.font_map()[String.downcase(font)]} + {:height, height} -> + {:height, process_height(height, parameters)} + {:label, label} -> - if String.length(label) > Constants.max_label_length(), - do: {:label, String.slice(label, 0, Constants.max_label_length() + 1)}, - else: {:label, label} + {:label, process_label(label)} {:link, _} -> - {:link, link} + {:link, generate_link(parameters)} {:preview_height, _} -> - {:preview_height, size + size * line_breaks} + {:preview_height, calculate_preview_height(parameters)} {:preview_text, _} -> - {:preview_text, String.split(label, "\\n")} + {:preview_text, String.split(parameters.label, "\\n")} + + {:width, width} -> + {:width, process_width(width, parameters)} pair -> pair @@ -55,6 +51,51 @@ defmodule LabelmakerWeb.Tools do Map.merge(Constants.defaults(), parameters) end + defp process_height("0", parameters) do + parameters.width |> String.to_integer() |> max(0) |> min(Constants.max_height()) + end + + defp process_height(height, _parameters) do + height |> String.to_integer() |> max(0) |> min(Constants.max_height()) + end + + defp process_label(label) do + if String.length(label) > Constants.max_label_length() do + String.slice(label, 0, Constants.max_label_length()) + else + label + end + end + + defp generate_link(%{:height => "0", "label" => label, :width => "0"} = parameters) do + ~p"/#{label}?#{Map.take(parameters, ["color", "font", "outline", "size"])}" + end + + defp generate_link(%{height: "0", width: width} = parameters), + do: generate_link(%{parameters | height: width, width: width}) + + defp generate_link(%{height: height, width: "0"} = parameters), + do: generate_link(%{parameters | height: height, width: height}) + + defp generate_link(%{"label" => label} = parameters) do + ~p"/#{label}?#{Map.take(parameters, ["color", "font", "height", "outline", "width"])}" + end + + defp process_width("0", parameters) do + parameters.height |> String.to_integer() |> max(0) |> min(Constants.max_width()) + end + + defp process_width(width, _parameters) do + width |> String.to_integer() |> max(0) |> min(Constants.max_width()) + end + + defp calculate_preview_height(parameters) do + size = parameters.size |> String.to_integer() + line_breaks = Regex.scan(~r/#{Regex.escape("\\n")}/, parameters.label) |> length() + + size + size * line_breaks + end + def outline(_, error: true), do: outline(Constants.danger(), false) def outline("none", _error), do: ""