Skip to main content

lib/astral/image/metadata.ex

defmodule Astral.Image.Metadata do
  @moduledoc """
  Source image metadata used by Astral image transforms.
  """

  @type t :: %__MODULE__{
          path: String.t(),
          width: pos_integer(),
          height: pos_integer(),
          format: atom(),
          content_hash: String.t()
        }

  defstruct [:path, :width, :height, :format, :content_hash]

  @doc "Read image dimensions, format, and content hash from a source file."
  @spec read(String.t()) :: {:ok, t()} | {:error, term()}
  def read(path) do
    with {:ok, image} <- Image.open(path),
         {width, height, _bands} <- Image.shape(image),
         {:ok, binary} <- File.read(path) do
      {:ok,
       %__MODULE__{
         path: path,
         width: width,
         height: height,
         format: Astral.Image.Format.from_path(path),
         content_hash: hash(binary)
       }}
    end
  rescue
    error in [Image.Error] -> {:error, error}
  end

  defp hash(binary) do
    :sha256
    |> :crypto.hash(binary)
    |> Base.url_encode64(padding: false)
    |> binary_part(0, 16)
  end
end