1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
5 defmodule Pleroma.Upload.Filter.AnalyzeMetadata do
7 Extracts metadata about the upload, such as width/height
12 alias Vix.Vips.Operation
14 @behaviour Pleroma.Upload.Filter
16 @spec filter(Pleroma.Upload.t()) ::
17 {:ok, :filtered, Pleroma.Upload.t()} | {:ok, :noop} | {:error, String.t()}
18 def filter(%Pleroma.Upload{tempfile: file, content_type: "image" <> _} = upload) do
20 {:ok, image} = Image.new_from_file(file)
21 {width, height} = {Image.width(image), Image.height(image)}
25 |> Map.put(:width, width)
26 |> Map.put(:height, height)
27 |> Map.put(:blurhash, get_blurhash(image))
29 {:ok, :filtered, upload}
32 Logger.warning("#{__MODULE__}: #{inspect(e)}")
37 def filter(%Pleroma.Upload{tempfile: file, content_type: "video" <> _} = upload) do
39 result = media_dimensions(file)
43 |> Map.put(:width, result.width)
44 |> Map.put(:height, result.height)
46 {:ok, :filtered, upload}
49 Logger.warning("#{__MODULE__}: #{inspect(e)}")
54 def filter(_), do: {:ok, :noop}
56 defp get_blurhash(file) do
57 with {:ok, blurhash} <- vips_blurhash(file) do
64 defp media_dimensions(file) do
65 with executable when is_binary(executable) <- System.find_executable("ffprobe"),
70 "stream=width,height",
75 {result, 0} <- System.cmd(executable, args),
77 String.split(String.trim(result), "x") |> Enum.map(&String.to_integer(&1)) do
78 %{width: width, height: height}
80 nil -> {:error, {:ffprobe, :command_not_found}}
81 error -> {:error, error}
85 defp vips_blurhash(%Vix.Vips.Image{} = image) do
86 with {:ok, resized_image} <- Operation.thumbnail_image(image, 100),
87 {height, width} <- {Image.height(resized_image), Image.width(resized_image)},
88 max <- max(height, width),
89 {x, y} <- {max(round(width * 5 / max), 1), max(round(height * 5 / max), 1)} do
91 if Image.has_alpha?(resized_image) do
92 # remove alpha channel
94 |> Operation.extract_band!(0, n: 3)
95 |> Image.write_to_binary()
97 Image.write_to_binary(resized_image)
100 Blurhash.encode(rgb, width, height, x, y)