A serializable image value used by image generation, editing, and vision inputs. See spec §35.2.1.
Layer A — pure data. The :source is one of four tagged tuples and is the
only required field. All other fields are nilable to support both inputs
(vision: only :source/:mime_type) and outputs (generated:
:prompt/:revised_prompt/:width/:height populated by the adapter).
Source variants
{:binary, bytes}— raw image bytes; an explicit:mime_typeMUST be supplied viafrom_binary/2.{:base64, encoded}— standard base64-encoded bytes (with padding) plus explicit:mime_type. Constructed viafrom_base64/2— pure data, no decode validation. Callers passing URL-safe (-/_) or unpadded base64 will round-trip cleanly through ETF / JSON butto_data_uri/1's fast-path (which forwards the encoded string verbatim) may emit adata:URI a consumer rejects.{:url, url}— public HTTP/HTTPS URL.from_url/1does NOT inspect or fetch the URL;:mime_typeisniland the adapter resolves it. URLs are NEVER fetched in Layer A — seeto_binary/1andto_data_uri/1for the:remote_sourceerror.{:file, path}— local filesystem path.from_file/1does NOT callFile.read/1; only the path is stored. MIME type is inferred from the extension (lowercase) and may benilwhen the extension is missing or unknown. Filesystem I/O happens only into_binary/1/to_data_uri/1.
Serializability
ETF round-trip via :erlang.term_to_binary/1 preserves every legal source
shape verbatim. JSON round-trip via ALLM.Serializer represents :source
as %{"type" => "<kind>", "value" => <value>}; the {:binary, _} variant
Base64-encodes its bytes on the wire so JSON stays text-safe. Decoding
dispatches on data["source"]["type"] against the closed set
~w[binary base64 url file]; an unknown type falls through to the
{:_unknown, :atom_decode_failed} field-error path. A "binary" source
whose "value" is not valid base64 surfaces as
{[:source], :invalid_base64} (raised pre-emptively as a
ValidationError so the field-error survives Serializer.from_json/1's
ArgumentError rescue).
Summary
Functions
Build an %Image{} from a base64-encoded string plus an explicit MIME type.
Build an %Image{} from raw bytes plus an explicit MIME type.
Build an %Image{} from a local filesystem path.
Build an %Image{} from a URL string.
Resolve the image's :source to raw bytes.
Resolve the image to a data:<mime>;base64,<...> URI.
Types
@type t() :: %ALLM.Image{ height: non_neg_integer() | nil, metadata: map(), mime_type: String.t() | nil, prompt: String.t() | nil, revised_prompt: String.t() | nil, source: source(), width: non_neg_integer() | nil }
Functions
Build an %Image{} from a base64-encoded string plus an explicit MIME type.
Pure data — does NOT validate that encoded is well-formed base64. Standard
base64 with padding is the documented contract; URL-safe base64 (-/_)
or unpadded variants may produce a struct whose to_data_uri/1 fast-path
emits a data: URI a downstream consumer rejects. mime_type: nil raises
FunctionClauseError.
Examples
iex> img = ALLM.Image.from_base64("aGk=", "image/png")
iex> img.source
{:base64, "aGk="}
iex> img.mime_type
"image/png"
Build an %Image{} from raw bytes plus an explicit MIME type.
Both arguments are required and must be binaries — mime_type: nil raises
FunctionClauseError (the is_binary(mime_type) runtime guard backs the
@spec so callers don't get silently-nil-mime structs).
Examples
iex> img = ALLM.Image.from_binary(<<137, 80>>, "image/png")
iex> img.source
{:binary, <<137, 80>>}
iex> img.mime_type
"image/png"
Build an %Image{} from a local filesystem path.
Pure data — does NOT call File.read/1. The path is stored verbatim and the
filesystem is only touched at to_binary/1 / to_data_uri/1 time. The
:mime_type is inferred from the lowercased extension against the closed
set [".png", ".jpg", ".jpeg", ".webp", ".gif"]; unknown or missing
extensions leave :mime_type as nil.
Examples
iex> img = ALLM.Image.from_file("/tmp/cat.png")
iex> img.source
{:file, "/tmp/cat.png"}
iex> img.mime_type
"image/png"
iex> ALLM.Image.from_file("/tmp/noext").mime_type
nil
Build an %Image{} from a URL string.
Pure data — does NOT inspect or fetch the URL. The :mime_type is nil;
the adapter that consumes the image resolves the type at request-build
time. URL fetching is banned in Layer A (Decision #2 / phasing principle
#8).
Examples
iex> img = ALLM.Image.from_url("https://example.com/x.png")
iex> img.source
{:url, "https://example.com/x.png"}
iex> img.mime_type
nil
@spec to_binary(t()) :: {:ok, binary()} | {:error, :remote_source | :invalid_base64 | File.posix()}
Resolve the image's :source to raw bytes.
{:binary, b}returns{:ok, b}verbatim.{:base64, s}decodes viaBase.decode64/1; invalid base64 returns{:error, :invalid_base64}.{:url, _}returns{:error, :remote_source}— Layer A NEVER fetches URLs (Decision #2). Adapters fetch at request-build time.{:file, path}reads the file viaFile.read/1and returns its{:ok, _} | {:error, posix()}shape directly (:enoenton missing, etc.).
Examples
iex> ALLM.Image.to_binary(ALLM.Image.from_binary(<<1, 2>>, "image/png"))
{:ok, <<1, 2>>}
iex> ALLM.Image.to_binary(ALLM.Image.from_base64("aGVsbG8=", "image/png"))
{:ok, "hello"}
iex> ALLM.Image.to_binary(ALLM.Image.from_url("https://example.com/x.png"))
{:error, :remote_source}
@spec to_data_uri(t()) :: {:ok, String.t()} | {:error, :remote_source | :missing_mime_type | :invalid_base64 | File.posix()}
Resolve the image to a data:<mime>;base64,<...> URI.
{:binary, b}with a:mime_typeBase64-encodes the bytes.{:base64, s}with a:mime_typeforwardssverbatim — fast path, no decode-then-re-encode.{:file, path}with a:mime_typereads + Base64-encodes.{:url, _}returns{:error, :remote_source}(Decision #6) — adata:URI and anhttps:URI are different addressing schemes; passing the URL through verbatim would surprise.- Missing
:mime_typereturns{:error, :missing_mime_type}— there is no default likeapplication/octet-stream.
Examples
iex> ALLM.Image.to_data_uri(ALLM.Image.from_binary("hi", "image/png"))
{:ok, "data:image/png;base64,aGk="}
iex> ALLM.Image.to_data_uri(ALLM.Image.from_base64("aGk=", "image/png"))
{:ok, "data:image/png;base64,aGk="}
iex> ALLM.Image.to_data_uri(ALLM.Image.from_url("https://example.com/x.png"))
{:error, :remote_source}