vivid_png/lib/vivid/png/buffer.ex

49 lines
1.2 KiB
Elixir
Raw Normal View History

2017-01-12 08:40:31 +13:00
defimpl Vivid.PNG, for: Vivid.Buffer do
alias Vivid.{Buffer, RGBA}
2017-01-12 08:55:58 +13:00
@moduledoc """
Convert a Vivid buffer to a PNG file.
"""
@doc """
Convert a Vivid buffer into a PNG file.
"""
2018-09-04 14:52:12 +12:00
@spec to_png(Buffer.t(), Path.t()) :: :ok | {:error, any}
2017-01-12 08:40:31 +13:00
def to_png(buffer, path) do
with {:ok, file} <- File.open(path, [:write]),
2018-09-04 14:52:12 +12:00
png <- create_png(buffer, file),
:ok <- :png.close(png),
do: File.close(file)
2017-01-12 08:40:31 +13:00
end
defp config(%Buffer{rows: height, columns: width}, file) do
%{
2018-09-04 14:52:12 +12:00
size: {width, height},
mode: {:rgba, 8},
file: file
2017-01-12 08:40:31 +13:00
}
end
2018-09-04 14:52:12 +12:00
defp create_png(%Buffer{columns: width} = buffer, file) do
png =
buffer
2017-01-12 08:40:31 +13:00
|> config(file)
2018-09-04 14:52:12 +12:00
|> :png.create()
2017-01-12 08:40:31 +13:00
buffer
2018-09-04 14:52:12 +12:00
|> Stream.map(&colour_to_binary(&1))
|> Stream.chunk(width)
|> Stream.map(&Enum.join(&1))
|> Enum.reverse()
|> Enum.reduce(png, &:png.append(&2, {:row, &1}))
2017-01-12 08:40:31 +13:00
end
defp colour_to_binary(%RGBA{red: r, green: g, blue: b, alpha: a}) do
r = round(r * 255)
g = round(g * 255)
b = round(b * 255)
a = round(a * 255)
2018-09-04 14:52:12 +12:00
<<r::integer-size(8), g::integer-size(8), b::integer-size(8), a::integer-size(8)>>
2017-01-12 08:40:31 +13:00
end
2018-09-04 14:52:12 +12:00
end