widthxheight support

This commit is contained in:
Gavin McDonald
2025-08-18 20:24:24 -04:00
parent 7fc9736cdc
commit 8baa70485f
3 changed files with 123 additions and 44 deletions

View File

@@ -1,11 +1,14 @@
defmodule LabelmakerWeb.Constants do defmodule LabelmakerWeb.Constants do
@defaults %{ @defaults %{
color: "black",
font: "Helvetica",
gravity: "Center",
height: "0",
label: "", label: "",
link: "", link: "",
font: "Helvetica",
color: "black",
outline: "none", outline: "none",
size: "72" size: "72",
width: "0"
} }
@preview %{ @preview %{
@@ -53,8 +56,11 @@ defmodule LabelmakerWeb.Constants do
"verdana" => "Verdana" "verdana" => "Verdana"
} }
@max_label_length 64 @max_height 1024
@max_label_error "64-character maximum" @max_width 1024
@max_label_length 1024
@max_label_error "1024-character maximum"
@sizes 16..128 @sizes 16..128
|> Enum.to_list() |> Enum.to_list()
@@ -73,6 +79,8 @@ defmodule LabelmakerWeb.Constants do
|> Enum.map(fn color -> color |> String.replace("-MS", "") |> String.replace("-", " ") end) |> Enum.map(fn color -> color |> String.replace("-MS", "") |> String.replace("-", " ") end)
def font_map, do: @font_map 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_length, do: @max_label_length
def max_label_error, do: @max_label_error def max_label_error, do: @max_label_error
def outlines, do: ["none" | @colors] def outlines, do: ["none" | @colors]

View File

@@ -16,9 +16,14 @@ defmodule LabelmakerWeb.LabelController do
filename = filename <> ".png" filename = filename <> ".png"
filepath = Path.join(@label_dir, filename) filepath = Path.join(@label_dir, filename)
options = Map.put(options, :filepath, filepath)
unless File.exists?(filepath) do unless File.exists?(filepath) do
generate_image(options, filepath) basic_settings(options)
|> size_settings(options)
|> outline_settings(options)
|> final_settings(options)
|> generate_image()
end end
conn conn
@@ -26,36 +31,61 @@ defmodule LabelmakerWeb.LabelController do
|> send_file(200, filepath) |> send_file(200, filepath)
end end
defp generate_image(options, filepath) do defp basic_settings(options) do
File.mkdir_p!(@label_dir) [
args = [
"-background", "-background",
"none", "none",
"-fill", "-fill",
options.color, options.color,
"-pointsize",
options.size,
"-font", "-font",
options.font, options.font
"label:#{String.slice(options.label, 0, Constants.max_label_length())}",
"-set",
"comment",
inspect(Jason.encode!(Map.drop(options, [:link]))),
filepath
] ]
end
args = defp size_settings(args, %{height: 0, width: 0} = options) do
if options.outline != "none" do args ++
[ [
"-stroke", "-pointsize",
options.outline, options.size,
"-strokewidth", "label:#{String.slice(options.label, 0, Constants.max_label_length())}"
"1" ]
] ++ args end
else
args defp size_settings(args, %{gravity: gravity, height: height, width: width} = options) do
end 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) {_, 0} = System.cmd("magick", args)
end end

View File

@@ -8,37 +8,33 @@ defmodule LabelmakerWeb.Tools do
alias LabelmakerWeb.Constants alias LabelmakerWeb.Constants
def process_parameters(parameters) do def process_parameters(parameters) do
# ensure our defaults are in place to cover any missing parameters parameters =
%{"label" => label, "size" => size} =
Constants.defaults() Constants.defaults()
|> Map.new(fn {k, v} -> {Atom.to_string(k), v} end) |> Map.new(fn {k, v} -> {Atom.to_string(k), v} end)
|> Map.merge(parameters) |> 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.take(Constants.permitted_keys())
|> Map.new(fn {k, v} -> {String.to_atom(k), v} end) |> Map.new(fn {k, v} -> {String.to_atom(k), v} end)
|> Enum.map(fn |> Enum.map(fn
{:font, font} -> {:font, font} ->
{:font, Constants.font_map()[String.downcase(font)]} {:font, Constants.font_map()[String.downcase(font)]}
{:height, height} ->
{:height, process_height(height, parameters)}
{:label, label} -> {:label, label} ->
if String.length(label) > Constants.max_label_length(), {:label, process_label(label)}
do: {:label, String.slice(label, 0, Constants.max_label_length() + 1)},
else: {:label, label}
{:link, _} -> {:link, _} ->
{:link, link} {:link, generate_link(parameters)}
{:preview_height, _} -> {:preview_height, _} ->
{:preview_height, size + size * line_breaks} {:preview_height, calculate_preview_height(parameters)}
{:preview_text, _} -> {:preview_text, _} ->
{:preview_text, String.split(label, "\\n")} {:preview_text, String.split(parameters.label, "\\n")}
{:width, width} ->
{:width, process_width(width, parameters)}
pair -> pair ->
pair pair
@@ -55,6 +51,51 @@ defmodule LabelmakerWeb.Tools do
Map.merge(Constants.defaults(), parameters) Map.merge(Constants.defaults(), parameters)
end 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(_, error: true), do: outline(Constants.danger(), false)
def outline("none", _error), do: "" def outline("none", _error), do: ""