mirror of
https://github.com/philomena-dev/philomena.git
synced 2025-02-17 11:04:22 +01:00
add processor skeleton
This commit is contained in:
parent
813ff87f9e
commit
2159fbd9c7
10 changed files with 378 additions and 110 deletions
|
@ -87,14 +87,9 @@ defmodule Philomena.Images.Image do
|
|||
field :removed_tags, {:array, :any}, default: [], virtual: true
|
||||
field :added_tags, {:array, :any}, default: [], virtual: true
|
||||
|
||||
timestamps(inserted_at: :created_at)
|
||||
end
|
||||
field :uploaded_image, :string, virtual: true
|
||||
|
||||
@doc false
|
||||
def changeset(image, attrs) do
|
||||
image
|
||||
|> cast(attrs, [])
|
||||
|> validate_required([])
|
||||
timestamps(inserted_at: :created_at)
|
||||
end
|
||||
|
||||
def interaction_data(image) do
|
||||
|
@ -106,6 +101,32 @@ defmodule Philomena.Images.Image do
|
|||
}
|
||||
end
|
||||
|
||||
@doc false
|
||||
def changeset(image, attrs) do
|
||||
image
|
||||
|> cast(attrs, [])
|
||||
|> validate_required([])
|
||||
end
|
||||
|
||||
def image_changeset(image, attrs) do
|
||||
image
|
||||
|> cast(attrs, [
|
||||
:image, :image_name, :image_width, :image_height, :image_size,
|
||||
:image_format, :image_mime_type, :image_aspect_ratio,
|
||||
:image_orig_sha512_hash, :image_sha512_hash, :uploaded_image
|
||||
])
|
||||
|> validate_required([
|
||||
:image, :image_width, :image_height, :image_size,
|
||||
:image_format, :image_mime_type, :image_aspect_ratio,
|
||||
:image_orig_sha512_hash, :image_sha512_hash, :uploaded_image
|
||||
])
|
||||
|> validate_number(:image_size, greater_than: 0, less_than_or_equal_to: 26214400)
|
||||
|> validate_number(:image_width, greater_than: 0, less_than_or_equal_to: 32767)
|
||||
|> validate_number(:image_height, greater_than: 0, less_than_or_equal_to: 32767)
|
||||
|> validate_length(:image_name, max: 255, count: :bytes)
|
||||
|> validate_inclusion(:image_mime_type, ~W(image/gif image/jpeg image/png image/svg+xml video/webm))
|
||||
end
|
||||
|
||||
def source_changeset(image, attrs) do
|
||||
image
|
||||
|> cast(attrs, [:source_url])
|
||||
|
|
98
lib/philomena/processors.ex
Normal file
98
lib/philomena/processors.ex
Normal file
|
@ -0,0 +1,98 @@
|
|||
defmodule Philomena.Processors do
|
||||
# alias Philomena.Images.Image
|
||||
# alias Philomena.Repo
|
||||
alias Philomena.Sha512
|
||||
|
||||
@mimes %{
|
||||
"image/gif" => "image/gif",
|
||||
"image/jpeg" => "image/jpeg",
|
||||
"image/png" => "image/png",
|
||||
"image/svg+xml" => "image/svg+xml",
|
||||
"video/webm" => "video/webm",
|
||||
"image/svg" => "image/svg+xml",
|
||||
"audio/webm" => "video/webm"
|
||||
}
|
||||
|
||||
@analyzers %{
|
||||
"image/gif" => Philomena.Analyzers.Gif,
|
||||
"image/jpeg" => Philomena.Analyzers.Jpeg,
|
||||
"image/png" => Philomena.Analyzers.Png,
|
||||
"image/svg+xml" => Philomena.Analyzers.Svg,
|
||||
"video/webm" => Philomena.Analyzers.Webm
|
||||
}
|
||||
|
||||
@processors %{
|
||||
"image/gif" => Philomena.Processors.Gif,
|
||||
"image/jpeg" => Philomena.Processors.Jpeg,
|
||||
"image/png" => Philomena.Processors.Png,
|
||||
"image/svg+xml" => Philomena.Processors.Svg,
|
||||
"video/webm" => Philomena.Processors.Webm
|
||||
}
|
||||
|
||||
def analysis_to_changes(analysis, file, upload_name) do
|
||||
{width, height} = analysis.dimensions
|
||||
%{size: size} = File.stat(file)
|
||||
sha512 = Sha512.file(file)
|
||||
filename = build_filename(analysis.extension)
|
||||
|
||||
%{
|
||||
"image" => filename,
|
||||
"image_name" => upload_name,
|
||||
"image_width" => width,
|
||||
"image_height" => height,
|
||||
"image_size" => size,
|
||||
"image_format" => analysis.extension,
|
||||
"image_mime_type" => analysis.mime_type,
|
||||
"image_aspect_ratio" => aspect_ratio(width, height),
|
||||
"image_orig_sha512_hash" => sha512,
|
||||
"image_sha512_hash" => sha512,
|
||||
"uploaded_image" => file
|
||||
}
|
||||
end
|
||||
|
||||
def after_upload(image) do
|
||||
File.cp(image.uploaded_image, Path.join([image_file_root(), image.image]))
|
||||
end
|
||||
|
||||
defp aspect_ratio(_, 0), do: 0.0
|
||||
defp aspect_ratio(w, h), do: w / h
|
||||
|
||||
defp build_filename(extension) do
|
||||
[
|
||||
time_identifier(),
|
||||
"/",
|
||||
usec_identifier(),
|
||||
pid_identifier(),
|
||||
".",
|
||||
extension
|
||||
]
|
||||
|> Enum.join()
|
||||
end
|
||||
|
||||
defp time_identifier do
|
||||
now = DateTime.utc_now()
|
||||
|
||||
Enum.join([now.year, now.month, now.day], "/")
|
||||
end
|
||||
|
||||
defp usec_identifier do
|
||||
DateTime.utc_now()
|
||||
|> DateTime.to_unix(:microsecond)
|
||||
|> to_string()
|
||||
end
|
||||
|
||||
defp pid_identifier do
|
||||
self()
|
||||
|> :erlang.pid_to_list()
|
||||
|> to_string()
|
||||
|> String.replace(~r/[^0-9]/, "")
|
||||
end
|
||||
|
||||
defp image_file_root do
|
||||
Application.get_env(:philomena, :image_file_root)
|
||||
end
|
||||
|
||||
defp image_thumbnail_root do
|
||||
image_file_root() <> "/thumbs"
|
||||
end
|
||||
end
|
|
@ -1,59 +1,93 @@
|
|||
defmodule Philomena.Processors.Gif do
|
||||
alias Philomena.Processors.Gif
|
||||
alias Philomena.Intensities
|
||||
|
||||
defstruct [:duration, :file, :palette]
|
||||
def process(analysis, file, versions) do
|
||||
dimensions = analysis.dimensions
|
||||
duration = analysis.duration
|
||||
preview = preview(duration, file)
|
||||
palette = palette(file)
|
||||
|
||||
def new(analysis, file) do
|
||||
%Gif{
|
||||
file: file,
|
||||
duration: analysis.duration,
|
||||
palette: nil
|
||||
{:ok, intensities} = Intensities.file(preview)
|
||||
|
||||
scaled = Enum.flat_map(versions, &scale_if_smaller(palette, file, dimensions, &1))
|
||||
|
||||
%{
|
||||
intensities: intensities,
|
||||
thumbnails: scaled ++ [{:copy, preview, "rendered.png"}]
|
||||
}
|
||||
end
|
||||
|
||||
def strip(processor) do
|
||||
{processor, processor.file}
|
||||
def post_process(_analysis, file) do
|
||||
%{replace_original: optimize(file)}
|
||||
end
|
||||
|
||||
def preview(processor) do
|
||||
preview = Briefly.create!(extname: ".png")
|
||||
|
||||
{_output, 0} =
|
||||
System.cmd("ffmpeg", ["-y", "-i", processor.file, "-ss", to_string(processor.duration / 2), "-frames:v", "1", preview])
|
||||
|
||||
{processor, preview}
|
||||
end
|
||||
|
||||
def optimize(processor) do
|
||||
defp optimize(file) do
|
||||
optimized = Briefly.create!(extname: ".gif")
|
||||
|
||||
{_output, 0} =
|
||||
System.cmd("gifsicle", ["--careful", "-O2", processor.file, "-o", optimized])
|
||||
System.cmd("gifsicle", ["--careful", "-O2", file, "-o", optimized])
|
||||
|
||||
{processor, optimized}
|
||||
optimized
|
||||
end
|
||||
|
||||
def scale(processor, {width, height}) do
|
||||
processor = generate_palette(processor)
|
||||
scaled = Briefly.create!(extname: ".gif")
|
||||
defp preview(duration, file) do
|
||||
preview = Briefly.create!(extname: ".png")
|
||||
|
||||
{_output, 0} =
|
||||
System.cmd("ffmpeg", ["-loglevel", "0", "-y", "-i", file, "-ss", to_string(duration / 2), "-frames:v", "1", preview])
|
||||
|
||||
preview
|
||||
end
|
||||
|
||||
defp palette(file) do
|
||||
palette = Briefly.create!(extname: ".png")
|
||||
|
||||
{_output, 0} =
|
||||
System.cmd("ffmpeg", ["-loglevel", "0", "-y", "-i", file, "-vf", "palettegen=stats_mode=diff", palette])
|
||||
|
||||
palette
|
||||
end
|
||||
|
||||
# Generate full version, and WebM and MP4 previews
|
||||
defp scale_if_smaller(_palette, file, _dimensions, {:full, _target_dim}) do
|
||||
[{:symlink_original, "full.gif"}] ++ generate_videos(file)
|
||||
end
|
||||
|
||||
defp scale_if_smaller(palette, file, {width, height}, {thumb_name, {target_width, target_height}}) do
|
||||
if width > target_width or height > target_height do
|
||||
scaled = scale(palette, file, {target_width, target_height})
|
||||
|
||||
[{:copy, scaled, "#{thumb_name}.gif"}]
|
||||
else
|
||||
[{:symlink_original, "#{thumb_name}.gif"}]
|
||||
end
|
||||
end
|
||||
|
||||
defp scale(palette, file, {width, height}) do
|
||||
scaled = Briefly.create!(extname: ".gif")
|
||||
|
||||
scale_filter = "scale=w=#{width}:h=#{height}:force_original_aspect_ratio=decrease"
|
||||
palette_filter = "paletteuse=dither=bayer:bayer_scale=5:diff_mode=rectangle"
|
||||
filter_graph = "#{scale_filter} [x]; [x][1:v] #{palette_filter}"
|
||||
|
||||
{_output, 0} =
|
||||
System.cmd("ffmpeg", ["-y", "-i", processor.file, "-i", processor.palette, "-lavfi", filter_graph, scaled])
|
||||
System.cmd("ffmpeg", ["-loglevel", "0", "-y", "-i", file, "-i", palette, "-lavfi", filter_graph, scaled])
|
||||
|
||||
{processor, scaled}
|
||||
scaled
|
||||
end
|
||||
|
||||
defp generate_palette(%{palette: nil} = processor) do
|
||||
palette = Briefly.create!(extname: ".png")
|
||||
defp generate_videos(file) do
|
||||
webm = Briefly.create!(extname: ".webm")
|
||||
mp4 = Briefly.create!(extname: ".mp4")
|
||||
|
||||
{_output, 0} =
|
||||
System.cmd("ffmpeg", ["-y", "-i", processor.file, "-vf", "palettegen=stats_mode=diff", palette])
|
||||
|
||||
%{processor | palette: palette}
|
||||
System.cmd("ffmpeg", ["-loglevel", "0", "-y", "-i", file, "-pix_fmt", "yuv420p", "-c:v", "libvpx", "-quality", "good", "-b:v", "5M", webm])
|
||||
{_output, 0} =
|
||||
System.cmd("ffmpeg", ["-loglevel", "0", "-y", "-i", file, "-vf", "scale=ceil(iw/2)*2:ceil(ih/2)*2", "-c:v", "libx264", "-preset", "medium", "-crf", "18", "-b:v", "5M", mp4])
|
||||
|
||||
[
|
||||
{:copy, webm, "full.webm"},
|
||||
{:copy, mp4, "full.mp4"}
|
||||
]
|
||||
end
|
||||
defp generate_palette(processor), do: processor
|
||||
end
|
|
@ -1,43 +1,64 @@
|
|||
defmodule Philomena.Processors.Jpeg do
|
||||
alias Philomena.Processors.Jpeg
|
||||
alias Philomena.Intensities
|
||||
|
||||
defstruct [:file]
|
||||
def process(analysis, file, versions) do
|
||||
dimensions = analysis.dimensions
|
||||
stripped = optimize(strip(file))
|
||||
|
||||
def new(_analysis, file) do
|
||||
%Jpeg{file: file}
|
||||
{:ok, intensities} = Intensities.file(stripped)
|
||||
|
||||
scaled = Enum.flat_map(versions, &scale_if_smaller(stripped, dimensions, &1))
|
||||
|
||||
%{
|
||||
replace_original: stripped,
|
||||
intensities: intensities,
|
||||
thumbnails: scaled
|
||||
}
|
||||
end
|
||||
|
||||
def strip(processor) do
|
||||
def post_process(_analysis, _file), do: %{}
|
||||
|
||||
defp strip(file) do
|
||||
stripped = Briefly.create!(extname: ".jpg")
|
||||
|
||||
{_output, 0} =
|
||||
System.cmd("convert", [processor.file, "-auto-orient", "-strip", stripped])
|
||||
System.cmd("convert", [file, "-auto-orient", "-strip", stripped])
|
||||
|
||||
processor = %{processor | file: stripped}
|
||||
|
||||
{processor, stripped}
|
||||
stripped
|
||||
end
|
||||
|
||||
def preview(processor) do
|
||||
{processor, processor.file}
|
||||
end
|
||||
|
||||
def optimize(processor) do
|
||||
defp optimize(file) do
|
||||
optimized = Briefly.create!(extname: ".jpg")
|
||||
|
||||
{_output, 0} =
|
||||
System.cmd("jpegtran", ["-optimize", "-outfile", optimized, processor.file])
|
||||
System.cmd("jpegtran", ["-optimize", "-outfile", optimized, file])
|
||||
|
||||
optimized
|
||||
end
|
||||
|
||||
def scale(processor, {width, height}) do
|
||||
defp scale_if_smaller(_file, _dimensions, {:full, _target_dim}) do
|
||||
[{:symlink_original, "full.jpg"}]
|
||||
end
|
||||
|
||||
defp scale_if_smaller(file, {width, height}, {thumb_name, {target_width, target_height}}) do
|
||||
if width > target_width or height > target_height do
|
||||
scaled = scale(file, {target_width, target_height})
|
||||
|
||||
[{:copy, scaled, "#{thumb_name}.jpg"}]
|
||||
else
|
||||
[{:symlink_original, "#{thumb_name}.jpg"}]
|
||||
end
|
||||
end
|
||||
|
||||
defp scale(file, {width, height}) do
|
||||
scaled = Briefly.create!(extname: ".jpg")
|
||||
scale_filter = "scale=w=#{width}:h=#{height}:force_original_aspect_ratio=decrease"
|
||||
|
||||
{_output, 0} =
|
||||
System.cmd("ffmpeg", ["-y", "-i", processor.file, "-vf", scale_filter, scaled])
|
||||
System.cmd("ffmpeg", ["-loglevel", "0", "-y", "-i", file, "-vf", scale_filter, scaled])
|
||||
{_output, 0} =
|
||||
System.cmd("jpegtran", ["-optimize", "-outfile", scaled, scaled])
|
||||
|
||||
{processor, scaled}
|
||||
scaled
|
||||
end
|
||||
end
|
|
@ -1,38 +1,55 @@
|
|||
defmodule Philomena.Processors.Png do
|
||||
alias Philomena.Processors.Png
|
||||
alias Philomena.Intensities
|
||||
|
||||
defstruct [:file]
|
||||
def process(analysis, file, versions) do
|
||||
dimensions = analysis.dimensions
|
||||
|
||||
def new(_analysis, file) do
|
||||
%Png{file: file}
|
||||
{:ok, intensities} = Intensities.file(file)
|
||||
|
||||
scaled = Enum.flat_map(versions, &scale_if_smaller(file, dimensions, &1))
|
||||
|
||||
%{
|
||||
intensities: intensities,
|
||||
thumbnails: scaled
|
||||
}
|
||||
end
|
||||
|
||||
def strip(processor) do
|
||||
{processor, processor.file}
|
||||
def post_process(_analysis, file) do
|
||||
%{replace_original: optimize(file)}
|
||||
end
|
||||
|
||||
def preview(processor) do
|
||||
{processor, processor.file}
|
||||
end
|
||||
|
||||
def optimize(processor) do
|
||||
defp optimize(file) do
|
||||
optimized = Briefly.create!(extname: ".png")
|
||||
|
||||
{_output, 0} =
|
||||
System.cmd("optipng", ["-fix", "-i0", "-o2", processor.file, "-out", optimized])
|
||||
System.cmd("optipng", ["-fix", "-i0", "-o2", file, "-out", optimized])
|
||||
|
||||
{processor, optimized}
|
||||
optimized
|
||||
end
|
||||
|
||||
def scale(processor, {width, height}) do
|
||||
defp scale_if_smaller(_file, _dimensions, {:full, _target_dim}) do
|
||||
[{:symlink_original, "full.jpg"}]
|
||||
end
|
||||
|
||||
defp scale_if_smaller(file, {width, height}, {thumb_name, {target_width, target_height}}) do
|
||||
if width > target_width or height > target_height do
|
||||
scaled = scale(file, {target_width, target_height})
|
||||
|
||||
[{:copy, scaled, "#{thumb_name}.jpg"}]
|
||||
else
|
||||
[{:symlink_original, "#{thumb_name}.jpg"}]
|
||||
end
|
||||
end
|
||||
|
||||
defp scale(file, {width, height}) do
|
||||
scaled = Briefly.create!(extname: ".png")
|
||||
scale_filter = "scale=w=#{width}:h=#{height}:force_original_aspect_ratio=decrease"
|
||||
|
||||
{_output, 0} =
|
||||
System.cmd("ffmpeg", ["-y", "-i", processor.file, "-vf", scale_filter, scaled])
|
||||
System.cmd("ffmpeg", ["-loglevel", "0", "-y", "-i", file, "-vf", scale_filter, scaled])
|
||||
{_output, 0} =
|
||||
System.cmd("optipng", ["-i0", "-o1", scaled])
|
||||
|
||||
{processor, scaled}
|
||||
scaled
|
||||
end
|
||||
end
|
|
@ -1,41 +1,49 @@
|
|||
defmodule Philomena.Processors.Svg do
|
||||
alias Philomena.Processors.Svg
|
||||
alias Philomena.Intensities
|
||||
|
||||
defstruct [:file, :preview]
|
||||
def process(_analysis, file, versions) do
|
||||
preview = preview(file)
|
||||
|
||||
def new(_analysis, file) do
|
||||
%Svg{file: file, preview: nil}
|
||||
{:ok, intensities} = Intensities.file(preview)
|
||||
|
||||
scaled = Enum.flat_map(versions, &scale_if_smaller(file, preview, &1))
|
||||
|
||||
%{
|
||||
intensities: intensities,
|
||||
thumbnails: scaled ++ [{:copy, preview, "rendered.png"}]
|
||||
}
|
||||
end
|
||||
|
||||
# FIXME
|
||||
def strip(processor) do
|
||||
{processor, processor.file}
|
||||
end
|
||||
def post_process(_analysis, _file), do: %{}
|
||||
|
||||
def preview(processor) do
|
||||
defp preview(file) do
|
||||
preview = Briefly.create!(extname: ".png")
|
||||
|
||||
{_output, 0} =
|
||||
System.cmd("inkscape", [processor.file, "--export-png", preview])
|
||||
|
||||
processor = %{processor | preview: preview}
|
||||
System.cmd("inkscape", [file, "--export-png", preview])
|
||||
|
||||
{processor, preview}
|
||||
preview
|
||||
end
|
||||
|
||||
def optimize(processor) do
|
||||
{processor, processor.file}
|
||||
defp scale_if_smaller(_file, preview, {:full, _target_dim}) do
|
||||
[{:symlink_original, "full.svg"}, {:copy, preview, "full.png"}]
|
||||
end
|
||||
|
||||
def scale(processor, {width, height}) do
|
||||
defp scale_if_smaller(_file, preview, {thumb_name, {target_width, target_height}}) do
|
||||
scaled = scale(preview, {target_width, target_height})
|
||||
|
||||
[{:copy, scaled, "#{thumb_name}.png"}]
|
||||
end
|
||||
|
||||
defp scale(preview, {width, height}) do
|
||||
scaled = Briefly.create!(extname: ".png")
|
||||
scale_filter = "scale=w=#{width}:h=#{height}:force_original_aspect_ratio=decrease"
|
||||
|
||||
{_output, 0} =
|
||||
System.cmd("ffmpeg", ["-y", "-i", processor.preview, "-vf", scale_filter, scaled])
|
||||
System.cmd("ffmpeg", ["-y", "-i", preview, "-vf", scale_filter, scaled])
|
||||
{_output, 0} =
|
||||
System.cmd("optipng", ["-i0", "-o1", scaled])
|
||||
|
||||
{processor, scaled}
|
||||
scaled
|
||||
end
|
||||
end
|
|
@ -1,39 +1,97 @@
|
|||
defmodule Philomena.Processors.Webm do
|
||||
alias Philomena.Processors.Webm
|
||||
alias Philomena.Intensities
|
||||
import Bitwise
|
||||
|
||||
defstruct [:duration, :file]
|
||||
def process(analysis, file, versions) do
|
||||
dimensions = analysis.dimensions
|
||||
duration = analysis.duration
|
||||
preview = preview(duration, file)
|
||||
palette = gif_palette(file)
|
||||
|
||||
def new(analysis, file) do
|
||||
%Webm{duration: analysis.duration, file: file}
|
||||
{:ok, intensities} = Intensities.file(preview)
|
||||
|
||||
scaled = Enum.flat_map(versions, &scale_if_smaller(file, palette, dimensions, &1))
|
||||
|
||||
%{
|
||||
intensities: intensities,
|
||||
thumbnails: scaled ++ [{:copy, preview, "rendered.png"}]
|
||||
}
|
||||
end
|
||||
|
||||
def strip(processor) do
|
||||
{processor, processor.file}
|
||||
end
|
||||
def post_process(_analysis, _file), do: %{}
|
||||
|
||||
def preview(processor) do
|
||||
defp preview(duration, file) do
|
||||
preview = Briefly.create!(extname: ".png")
|
||||
|
||||
{_output, 0} =
|
||||
System.cmd("ffmpeg", ["-y", "-i", processor.file, "-ss", to_string(processor.duration / 2), "-frames:v", "1", preview])
|
||||
|
||||
{processor, preview}
|
||||
System.cmd("ffmpeg", ["-loglevel", "0", "-y", "-i", file, "-ss", to_string(duration / 2), "-frames:v", "1", preview])
|
||||
|
||||
preview
|
||||
end
|
||||
|
||||
def optimize(processor) do
|
||||
{processor, processor.file}
|
||||
defp scale_if_smaller(palette, file, dimensions, {:full, _target_dim}) do
|
||||
{webm, mp4} = scale_videos(file, palette, dimensions)
|
||||
|
||||
[
|
||||
{:copy, webm, "full.webm"},
|
||||
{:copy, mp4, "full.mp4"}
|
||||
]
|
||||
end
|
||||
|
||||
def scale(processor, dimensions) do
|
||||
defp scale_if_smaller(palette, file, _dimensions, {thumb_name, {target_width, target_height}}) do
|
||||
{webm, mp4} = scale_videos(file, palette, {target_width, target_height})
|
||||
|
||||
cond do
|
||||
thumb_name in [:thumb, :thumb_small, :thumb_tiny] ->
|
||||
gif = scale_gif(file, palette, {target_width, target_height})
|
||||
|
||||
[
|
||||
{:copy, webm, "#{thumb_name}.webm"},
|
||||
{:copy, mp4, "#{thumb_name}.mp4"},
|
||||
{:copy, gif, "#{thumb_name}.gif"}
|
||||
]
|
||||
|
||||
true ->
|
||||
[
|
||||
{:copy, webm, "#{thumb_name}.webm"},
|
||||
{:copy, mp4, "#{thumb_name}.mp4"}
|
||||
]
|
||||
end
|
||||
end
|
||||
|
||||
defp scale_videos(file, _palette, dimensions) do
|
||||
{width, height} = normalize_dimensions(dimensions)
|
||||
scaled = Briefly.create!(extname: ".webm")
|
||||
webm = Briefly.create!(extname: ".webm")
|
||||
mp4 = Briefly.create!(extname: ".mp4")
|
||||
scale_filter = "scale=w=#{width}:h=#{height}:force_original_aspect_ratio=decrease"
|
||||
|
||||
{_output, 0} =
|
||||
System.cmd("ffmpeg", ["-y", "-i", processor.file, "-c:v", "libvpx", "-crf", "10", "-b:v", "5M", "-vf", scale_filter, scaled])
|
||||
System.cmd("ffmpeg", ["-loglevel", "0", "-y", "-i", file, "-c:v", "libvpx", "-crf", "10", "-b:v", "5M", "-vf", scale_filter, webm])
|
||||
{_output, 0} =
|
||||
System.cmd("ffmpeg", ["-loglevel", "0", "-y", "-i", file, "-c:v", "libx264", "-preset", "medium", "-crf", "18", "-b:v", "5M", "-vf", scale_filter, mp4])
|
||||
|
||||
{processor, scaled}
|
||||
{webm, mp4}
|
||||
end
|
||||
|
||||
defp scale_gif(file, palette, {width, height}) do
|
||||
gif = Briefly.create!(extname: ".gif")
|
||||
scale_filter = "scale=w=#{width}:h=#{height}:force_original_aspect_ratio=decrease"
|
||||
palette_filter = "paletteuse=dither=bayer:bayer_scale=5:diff_mode=rectangle"
|
||||
filter_graph = "#{scale_filter} [x]; [x][1:v] #{palette_filter}"
|
||||
|
||||
{_output, 0} =
|
||||
System.cmd("ffmpeg", ["-loglevel", "0", "-y", "-i", file, "-i", palette, "-lavfi", filter_graph, gif])
|
||||
|
||||
gif
|
||||
end
|
||||
|
||||
defp gif_palette(file) do
|
||||
palette = Briefly.create!(extname: ".png")
|
||||
|
||||
{_output, 0} =
|
||||
System.cmd("ffmpeg", ["-loglevel", "0", "-y", "-i", file, "-vf", "palettegen=stats_mode=diff", palette])
|
||||
|
||||
palette
|
||||
end
|
||||
|
||||
# Force dimensions to be a multiple of 2. This is required by the
|
||||
|
|
11
lib/philomena/sha512.ex
Normal file
11
lib/philomena/sha512.ex
Normal file
|
@ -0,0 +1,11 @@
|
|||
defmodule Philomena.Sha512 do
|
||||
@spec file(String.t()) :: String.t()
|
||||
def file(file) do
|
||||
hash_ref = :crypto.hash_init(:sha512)
|
||||
|
||||
File.stream!(file, [], 10_485_760)
|
||||
|> Enum.reduce(hash_ref, &:crypto.hash_update(&2, &1))
|
||||
|> :crypto.hash_final()
|
||||
|> Base.encode16(case: :lower)
|
||||
end
|
||||
end
|
|
@ -9,7 +9,7 @@ defmodule PhilomenaWeb.Image.SourceChangeController do
|
|||
plug PhilomenaWeb.CanaryMapPlug, index: :show
|
||||
plug :load_and_authorize_resource, model: Image, id_name: "image_id", persisted: true
|
||||
|
||||
def index(conn, params) do
|
||||
def index(conn, _params) do
|
||||
image = conn.assigns.image
|
||||
|
||||
source_changes =
|
||||
|
|
|
@ -55,7 +55,7 @@ if ! install_packages build-essential postgresql-11 libpq-dev nginx nodejs \
|
|||
elasticsearch esl-erlang elixir inotify-tools git \
|
||||
redis-server automake libtool zlib1g-dev ffmpeg \
|
||||
libavutil-dev libavcodec-dev libavformat-dev \
|
||||
libmagic-dev libpng-dev; then
|
||||
libmagic-dev libpng-dev gifsicle optipng libjpeg-progs; then
|
||||
>&2 echo "Installation of dependencies failed."
|
||||
exit 1
|
||||
fi
|
||||
|
|
Loading…
Reference in a new issue