2021-05-12 20:38:11 +02:00
|
|
|
# Pleroma: A lightweight social networking server
|
2023-01-02 21:38:50 +01:00
|
|
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
2021-05-12 20:38:11 +02:00
|
|
|
# SPDX-License-Identifier: AGPL-3.0-only
|
|
|
|
|
2021-05-18 22:33:33 +02:00
|
|
|
defmodule Pleroma.Upload.Filter.AnalyzeMetadata do
|
2021-05-12 20:38:11 +02:00
|
|
|
@moduledoc """
|
|
|
|
Extracts metadata about the upload, such as width/height
|
|
|
|
"""
|
|
|
|
require Logger
|
|
|
|
|
2023-11-16 23:04:47 +01:00
|
|
|
alias Vix.Vips.Image
|
|
|
|
alias Vix.Vips.Operation
|
|
|
|
|
2021-05-12 20:38:11 +02:00
|
|
|
@behaviour Pleroma.Upload.Filter
|
|
|
|
|
|
|
|
@spec filter(Pleroma.Upload.t()) ::
|
|
|
|
{:ok, :filtered, Pleroma.Upload.t()} | {:ok, :noop} | {:error, String.t()}
|
|
|
|
def filter(%Pleroma.Upload{tempfile: file, content_type: "image" <> _} = upload) do
|
|
|
|
try do
|
2023-11-16 23:04:47 +01:00
|
|
|
{:ok, image} = Image.new_from_file(file)
|
|
|
|
{width, height} = {Image.width(image), Image.height(image)}
|
2021-05-12 20:38:11 +02:00
|
|
|
|
|
|
|
upload =
|
|
|
|
upload
|
2023-11-16 23:04:47 +01:00
|
|
|
|> Map.put(:width, width)
|
|
|
|
|> Map.put(:height, height)
|
|
|
|
|> Map.put(:blurhash, get_blurhash(image))
|
2021-05-12 20:38:11 +02:00
|
|
|
|
|
|
|
{:ok, :filtered, upload}
|
|
|
|
rescue
|
|
|
|
e in ErlangError ->
|
|
|
|
Logger.warn("#{__MODULE__}: #{inspect(e)}")
|
|
|
|
{:ok, :noop}
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2021-06-03 23:58:18 +02:00
|
|
|
def filter(%Pleroma.Upload{tempfile: file, content_type: "video" <> _} = upload) do
|
|
|
|
try do
|
|
|
|
result = media_dimensions(file)
|
|
|
|
|
|
|
|
upload =
|
|
|
|
upload
|
|
|
|
|> Map.put(:width, result.width)
|
|
|
|
|> Map.put(:height, result.height)
|
|
|
|
|
|
|
|
{:ok, :filtered, upload}
|
|
|
|
rescue
|
|
|
|
e in ErlangError ->
|
|
|
|
Logger.warn("#{__MODULE__}: #{inspect(e)}")
|
|
|
|
{:ok, :noop}
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2021-05-12 20:38:11 +02:00
|
|
|
def filter(_), do: {:ok, :noop}
|
2021-05-14 15:38:23 +02:00
|
|
|
|
|
|
|
defp get_blurhash(file) do
|
2023-11-16 23:04:47 +01:00
|
|
|
with {:ok, blurhash} <- vips_blurhash(file) do
|
2021-05-14 15:38:23 +02:00
|
|
|
blurhash
|
|
|
|
else
|
|
|
|
_ -> nil
|
|
|
|
end
|
|
|
|
end
|
2021-06-03 23:58:18 +02:00
|
|
|
|
|
|
|
defp media_dimensions(file) do
|
|
|
|
with executable when is_binary(executable) <- System.find_executable("ffprobe"),
|
|
|
|
args = [
|
|
|
|
"-v",
|
|
|
|
"error",
|
|
|
|
"-show_entries",
|
|
|
|
"stream=width,height",
|
|
|
|
"-of",
|
|
|
|
"csv=p=0:s=x",
|
|
|
|
file
|
|
|
|
],
|
|
|
|
{result, 0} <- System.cmd(executable, args),
|
|
|
|
[width, height] <-
|
|
|
|
String.split(String.trim(result), "x") |> Enum.map(&String.to_integer(&1)) do
|
|
|
|
%{width: width, height: height}
|
|
|
|
else
|
|
|
|
nil -> {:error, {:ffprobe, :command_not_found}}
|
|
|
|
{:error, _} = error -> error
|
|
|
|
end
|
|
|
|
end
|
2023-11-16 23:04:47 +01:00
|
|
|
|
|
|
|
defp vips_blurhash(image = %Vix.Vips.Image{}) do
|
2023-11-17 17:06:31 +01:00
|
|
|
{:ok, resized_image} = Operation.thumbnail_image(image, 100)
|
2023-11-16 23:04:47 +01:00
|
|
|
{height, width} = {Image.height(resized_image), Image.width(resized_image)}
|
|
|
|
max = max(height, width)
|
|
|
|
{x, y} = {max(round(width * 5 / max), 1), max(round(height * 5 / max), 1)}
|
|
|
|
|
|
|
|
{:ok, rgba} =
|
|
|
|
if Image.has_alpha?(resized_image) do
|
|
|
|
Image.to_list(resized_image)
|
|
|
|
else
|
|
|
|
Operation.bandjoin_const!(resized_image, [255])
|
|
|
|
|> Image.to_list()
|
|
|
|
end
|
|
|
|
|
|
|
|
rgba = List.flatten(rgba)
|
|
|
|
|
|
|
|
Blurhash.encode(x, y, width, height, rgba)
|
|
|
|
end
|
2021-05-12 20:38:11 +02:00
|
|
|
end
|