lib/kino.ex

defmodule Image.Kino do
  @moduledoc """
  Helper functions to simplify rendering images in Kino.

  """

  # Since Kino is not a required dependency we
  # avoid compiler warnings by using `apply/3`

  alias Vix.Vips.Operation
  alias Vix.Vips.Image, as: Vimage

  @default_max_height 200

  @doc """
  Renders an image in [Kino](https://hex.pm/packages/kino),

  ### Arguments

  * `image` is any `t:Vix.Vips.Image.t/0`.

  * `options` is a keyword list of options.

  ### Options

  * `:max_height` determines the maximum height for the
    rendered image. The aspect ratio of the rendered
    image is unchanged.  The default is `#{inspect(@default_max_height)}`.

  ### Returns

  * `maybe_resized_image` of type `t:Kino.Image.t/0`.

  """
  @doc since: "0.18.0"

  @spec show(image :: Vimage.t(), options :: Keyword.t()) :: Vimage.t()

  def show(%Vimage{} = image, opts \\ []) do
    image = maybe_resize_image(image, opts)

    {:ok, image_bin} = Vimage.write_to_buffer(image, ".png")
    apply(Kino.Image, :new, [image_bin, "image/png"])
  end

  # scale down if image height is larger than max_height
  defp maybe_resize_image(image, opts) do
    height = Image.height(image)
    max_height = Keyword.get(opts, :max_height, @default_max_height)

    if height > max_height do
      Operation.resize!(image, max_height / height)
    else
      image
    end
  end
end