Packages
image
0.67.0
0.72.0
0.71.0
0.70.0
0.69.0
0.68.0
0.67.0
0.67.0-dev
retired
0.66.0
0.65.0
0.64.0
0.63.0
0.62.1
0.62.0
0.61.1
0.61.0
0.60.0
0.59.3
0.59.2
0.59.1
0.59.0
0.58.0
0.57.0
0.56.1
0.56.0
0.55.2
0.55.1
retired
0.55.0
0.54.4
0.54.3
0.54.2
0.54.1
0.54.0
0.53.0
0.52.3
0.52.2
0.52.1
0.52.0
retired
0.51.0
0.50.0
0.49.0
0.48.1
0.48.0
0.47.0
0.46.0
0.45.0
0.44.0
0.43.2
0.43.1
0.43.0
0.42.0
0.41.0
0.40.0
0.39.3
0.39.2
0.39.1
0.39.0
0.38.4
0.38.3
0.38.2
0.38.1
0.38.0
0.37.0
0.36.2
0.36.1
0.36.0
0.35.0
0.34.0
0.33.0
0.32.0
0.31.1
0.31.0
0.30.0
0.29.0
0.28.2
0.28.1
0.28.0
0.27.0
0.26.0
0.25.1
0.25.0
0.24.1
0.24.0
0.23.2
0.23.1
0.23.0
0.22.1
0.22.0
0.21.0
0.20.0
retired
0.19.0
0.18.1
0.18.0
0.17.0
0.16.0
0.15.0
0.14.4
0.14.2
0.14.1
0.14.0
retired
0.13.1
0.13.0
0.12.0
0.11.0
0.10.0
0.10.0-rc.0
retired
0.9.0
retired
0.8.0
0.7.0
0.6.0
0.5.0
0.4.0
0.3.0
0.2.0
0.1.0
An approachable image processing library primarily based upon Vix and libvips that is NIF-based, fast, multi-threaded, pipelined and has a low memory footprint.
Current section
Files
Jump to
Current section
Files
lib/image/options/meme.ex
defmodule Image.Options.Meme do
@moduledoc """
Options and option validation for `Image.meme/2`.
"""
alias Image.Pixel
@typedoc "Valid font weights"
@type font_weight :: :ultralight | :light | :normal | :bold | :ultrabold | :heavy
@typedoc "Valid type transforms"
@type text_transform :: :capitalize | :upcase | :downcase | :none
@typedoc "Options applicable to Image.meme/3"
@type meme_options ::
[
{:text, String.t()}
| {:font, String.t()}
| {:weight, font_weight()}
| {:color, Pixel.t()}
| {:outline_color, Pixel.t()}
| {:justify, boolean()}
| {:transform, text_transform()}
| {:width, pos_integer()}
]
| map()
@doc """
Validate the options for `Image.meme/3`.
See `t:Image.Options.Meme.meme_options/0`.
"""
def validate_options(image, options) when is_list(options) do
options = Keyword.merge(default_options(image), options)
case Enum.reduce_while(options, options, &validate_option(&1, &2)) do
{:error, value} ->
{:error, value}
options ->
options =
cond do
options[:font] == "Impact" && options[:fontfile] == :default ->
Keyword.put(options, :fontfile, font_file("Impact"))
options[:fontfile] == :default ->
Keyword.delete(options, :fontfile)
true ->
options
end
{:ok, Map.new(options)}
end
end
def validate_options(%{} = options) do
{:ok, options}
end
defp validate_option({:font, font}, options) when is_binary(font) do
{:cont, options}
end
defp validate_option({:font_file, font_file}, options) when is_binary(font_file) do
font_file = font_file(font_file)
if File.exists?(font_file) do
options =
options
|> Keyword.delete(:font_file)
|> Keyword.put(:fontfile, font_file)
{:cont, options}
else
{:halt, {:error, no_such_font_file(font_file)}}
end
end
defp validate_option({:font_file, :default}, options) do
options =
options
|> Keyword.delete(:font_file)
|> Keyword.put(:fontfile, :default)
{:cont, options}
end
defp validate_option({:margin, margin}, options) when is_integer(margin) and margin > 0 do
{:cont, options}
end
defp validate_option({:text, text}, options) when is_binary(text) do
{:cont, options}
end
defp validate_option({:weight, weight}, options)
when weight in [:ultralight, :light, :normal, :bold, :ultrabold, :heavy] do
{:cont, options}
end
defp validate_option({:transform, transform}, options)
when transform in [:upcase, :downcase, :capitalize, :none] do
{:cont, options}
end
defp validate_option({:justify, justify}, options) when is_boolean(justify) do
{:cont, options}
end
defp validate_option({key, size}, options)
when key in [:headline_size, :text_size] and is_integer(size) and size > 0 do
{:cont, options}
end
defp validate_option({key, color} = option, options) when key in [:color, :outline_color] do
case Pixel.to_srgb(color) do
{:ok, pixel} -> {:cont, Keyword.put(options, key, Enum.take(pixel, 3))}
_other -> {:halt, {:error, invalid_option(option)}}
end
end
defp validate_option(option, _options) do
{:halt, {:error, invalid_option(option)}}
end
defp invalid_option(option) do
"Invalid option or option value: #{inspect(option)}"
end
def no_such_font_file(file) do
"Font file #{inspect(file)} could not be found"
end
defp default_options(image) do
height = Image.height(image)
[
text: "",
font: "Impact",
font_file: :default,
weight: :bold,
color: :white,
outline_color: :black,
justify: false,
transform: :upcase,
headline_size: default_headline_size(height),
text_size: default_text_size(height),
margin: default_margin(image)
]
end
def default_margin(image) do
div(Image.width(image), 20)
end
defp default_headline_size(height) do
height_in_points(height) * 10
end
defp default_text_size(height) do
height_in_points(height) * 6
end
defp height_in_points(height) do
div(height, 72)
end
defp font_file("Impact") do
Path.join(to_string(:code.priv_dir(:image)), "fonts/unicode.impact.ttf")
end
defp font_file(name) when is_binary(name) do
name
end
end