[#2497] Image preview proxy: image resize & background color fix with ffmpeg -filter_complex.
This commit is contained in:
parent
6fd4f58ead
commit
610343edb3
|
@ -9,12 +9,14 @@ defmodule Pleroma.Helpers.MediaHelper do
|
||||||
|
|
||||||
@ffmpeg_opts [{:sync, true}, {:stdout, true}]
|
@ffmpeg_opts [{:sync, true}, {:stdout, true}]
|
||||||
|
|
||||||
def ffmpeg_resize_remote(uri, max_width, max_height) do
|
def ffmpeg_resize_remote(uri, %{max_width: max_width, max_height: max_height}) do
|
||||||
cmd = ~s"""
|
cmd = ~s"""
|
||||||
curl -L "#{uri}" |
|
curl -L "#{uri}" |
|
||||||
ffmpeg -i pipe:0 -vf \
|
ffmpeg -i pipe:0 -f lavfi -i color=c=white \
|
||||||
"scale='min(#{max_width},iw)':min'(#{max_height},ih)':force_original_aspect_ratio=decrease" \
|
-filter_complex "[0:v] scale='min(#{max_width},iw)':'min(#{max_height},ih)': \
|
||||||
-f image2 pipe:1 | \
|
force_original_aspect_ratio=decrease [scaled]; \
|
||||||
|
[1][scaled] scale2ref [bg][img]; [bg] setsar=1 [bg]; [bg][img] overlay=shortest=1" \
|
||||||
|
-f image2 -vcodec mjpeg -frames:v 1 pipe:1 | \
|
||||||
cat
|
cat
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
@ -22,41 +24,4 @@ def ffmpeg_resize_remote(uri, max_width, max_height) do
|
||||||
{:ok, Enum.join(stdout_list)}
|
{:ok, Enum.join(stdout_list)}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@doc "Returns a temporary path for an URI"
|
|
||||||
def temporary_path_for(uri) do
|
|
||||||
name = Path.basename(uri)
|
|
||||||
random = rand_uniform(999_999)
|
|
||||||
Path.join(System.tmp_dir(), "#{random}-#{name}")
|
|
||||||
end
|
|
||||||
|
|
||||||
@doc "Stores binary content fetched from specified URL as a temporary file."
|
|
||||||
@spec store_as_temporary_file(String.t(), binary()) :: {:ok, String.t()} | {:error, atom()}
|
|
||||||
def store_as_temporary_file(url, body) do
|
|
||||||
path = temporary_path_for(url)
|
|
||||||
with :ok <- File.write(path, body), do: {:ok, path}
|
|
||||||
end
|
|
||||||
|
|
||||||
@doc "Modifies image file at specified path by resizing to specified limit dimensions."
|
|
||||||
@spec mogrify_resize_to_limit(String.t(), String.t()) :: :ok | any()
|
|
||||||
def mogrify_resize_to_limit(path, resize_dimensions) do
|
|
||||||
with %Mogrify.Image{} <-
|
|
||||||
path
|
|
||||||
|> Mogrify.open()
|
|
||||||
|> Mogrify.resize_to_limit(resize_dimensions)
|
|
||||||
|> Mogrify.save(in_place: true) do
|
|
||||||
:ok
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
defp rand_uniform(high) do
|
|
||||||
Code.ensure_loaded(:rand)
|
|
||||||
|
|
||||||
if function_exported?(:rand, :uniform, 1) do
|
|
||||||
:rand.uniform(high)
|
|
||||||
else
|
|
||||||
# Erlang/OTP < 19
|
|
||||||
apply(:crypto, :rand_uniform, [1, high])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -82,17 +82,16 @@ defp thumbnail_max_dimensions(params) do
|
||||||
{thumbnail_max_width, thumbnail_max_height}
|
{thumbnail_max_width, thumbnail_max_height}
|
||||||
end
|
end
|
||||||
|
|
||||||
defp handle_preview("image/" <> _ = content_type, %{params: params} = conn, url) do
|
defp handle_preview("image/" <> _ = _content_type, %{params: params} = conn, url) do
|
||||||
with {thumbnail_max_width, thumbnail_max_height} <- thumbnail_max_dimensions(params),
|
with {thumbnail_max_width, thumbnail_max_height} <- thumbnail_max_dimensions(params),
|
||||||
media_proxy_url <- MediaProxy.url(url),
|
media_proxy_url <- MediaProxy.url(url),
|
||||||
{:ok, thumbnail_binary} <-
|
{:ok, thumbnail_binary} <-
|
||||||
MediaHelper.ffmpeg_resize_remote(
|
MediaHelper.ffmpeg_resize_remote(
|
||||||
media_proxy_url,
|
media_proxy_url,
|
||||||
thumbnail_max_width,
|
%{max_width: thumbnail_max_width, max_height: thumbnail_max_height}
|
||||||
thumbnail_max_height
|
|
||||||
) do
|
) do
|
||||||
conn
|
conn
|
||||||
|> put_resp_header("content-type", content_type)
|
|> put_resp_header("content-type", "image/jpeg")
|
||||||
|> send_resp(200, thumbnail_binary)
|
|> send_resp(200, thumbnail_binary)
|
||||||
else
|
else
|
||||||
_ ->
|
_ ->
|
||||||
|
|
Loading…
Reference in New Issue