mirror of
https://github.com/ClaperCo/Claper.git
synced 2026-07-10 04:24:14 +02:00
Detect ImageMagick and add to Docker images
This commit is contained in:
@@ -64,7 +64,7 @@ RUN mix release
|
||||
# the compiled release and other runtime necessities
|
||||
FROM ${RUNNER_IMAGE}
|
||||
|
||||
RUN apt-get update -y && apt-get install -y curl libstdc++6 openssl locales ghostscript default-jre libreoffice-java-common \
|
||||
RUN apt-get update -y && apt-get install -y curl libstdc++6 openssl locales ghostscript imagemagick default-jre libreoffice-java-common \
|
||||
&& apt-get install -y libreoffice --no-install-recommends && apt-get clean && rm -f /var/lib/apt/lists/*_*
|
||||
# RUN apk add --no-cache curl libstdc++ openssl ncurses ghostscript openjdk11-jre
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@ RUN apt-get update && apt-get install -y \
|
||||
libtool \
|
||||
openjdk-11-jdk \
|
||||
ghostscript \
|
||||
imagemagick \
|
||||
libreoffice \
|
||||
&& apt-get clean \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
@@ -8,6 +8,8 @@ defmodule Claper.Tasks.Converter do
|
||||
alias Claper.Presentations.PresentationFile
|
||||
alias Porcelain.Result
|
||||
|
||||
@imagemagick_commands ~w(magick convert convert-im6.q16)
|
||||
|
||||
@doc """
|
||||
Convert the presentation file to images.
|
||||
We use original hash :erlang.phash2(code-name) where the files are uploaded to send it to another folder with a new hash. This last stored in db.
|
||||
@@ -157,17 +159,14 @@ defmodule Claper.Tasks.Converter do
|
||||
|
||||
files = Path.wildcard("#{path}/*.jpg")
|
||||
|
||||
if Enum.empty?(files) do
|
||||
{:error, :missing_slides}
|
||||
else
|
||||
with [_ | _] <- files,
|
||||
{:ok, imagemagick_command} <- get_imagemagick_command() do
|
||||
result =
|
||||
Enum.reduce_while(files, :ok, fn file, _acc ->
|
||||
thumb_path = Path.join(thumbs_dir, Path.basename(file))
|
||||
|
||||
# Generate thumbnail with 200px width, maintaining aspect ratio
|
||||
# Using "magick" for ImageMagick v7+ compatibility
|
||||
case Porcelain.exec(
|
||||
"magick",
|
||||
imagemagick_command,
|
||||
[
|
||||
file,
|
||||
"-resize",
|
||||
@@ -187,6 +186,16 @@ defmodule Claper.Tasks.Converter do
|
||||
end
|
||||
|
||||
result
|
||||
else
|
||||
[] -> {:error, :missing_slides}
|
||||
{:error, _reason} = error -> error
|
||||
end
|
||||
end
|
||||
|
||||
defp get_imagemagick_command do
|
||||
case Enum.find(@imagemagick_commands, &System.find_executable/1) do
|
||||
nil -> {:error, :missing_imagemagick}
|
||||
command -> {:ok, command}
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
104
test/claper/tasks/converter_test.exs
Normal file
104
test/claper/tasks/converter_test.exs
Normal file
@@ -0,0 +1,104 @@
|
||||
defmodule Claper.Tasks.ConverterTest do
|
||||
use ExUnit.Case, async: false
|
||||
|
||||
import ExUnit.CaptureIO
|
||||
|
||||
alias Claper.Presentations.PresentationFile
|
||||
alias Claper.Tasks.Converter
|
||||
|
||||
describe "regenerate_thumbnails/1" do
|
||||
test "uses convert when magick is unavailable" do
|
||||
storage_dir = unique_tmp_dir()
|
||||
hash = "convert-fallback"
|
||||
slide_dir = Path.join([storage_dir, "uploads", hash])
|
||||
bin_dir = Path.join(storage_dir, "bin")
|
||||
|
||||
File.mkdir_p!(slide_dir)
|
||||
File.write!(Path.join(slide_dir, "1.jpg"), "slide")
|
||||
File.mkdir_p!(bin_dir)
|
||||
write_fake_imagemagick(bin_dir, "convert")
|
||||
|
||||
put_local_storage_config(storage_dir)
|
||||
put_path(bin_dir)
|
||||
|
||||
presentation_file = %PresentationFile{hash: hash, length: 1}
|
||||
|
||||
output =
|
||||
capture_io(fn -> assert :ok = Converter.regenerate_thumbnails(presentation_file) end)
|
||||
|
||||
assert output =~ "Generated 1 thumbnails"
|
||||
assert File.read!(Path.join([slide_dir, "thumbs", "1.jpg"])) == "fake-thumbnail"
|
||||
end
|
||||
|
||||
test "returns a clear error when ImageMagick is unavailable" do
|
||||
storage_dir = unique_tmp_dir()
|
||||
hash = "missing-imagemagick"
|
||||
slide_dir = Path.join([storage_dir, "uploads", hash])
|
||||
empty_bin_dir = Path.join(storage_dir, "empty-bin")
|
||||
|
||||
File.mkdir_p!(slide_dir)
|
||||
File.write!(Path.join(slide_dir, "1.jpg"), "slide")
|
||||
File.mkdir_p!(empty_bin_dir)
|
||||
|
||||
put_local_storage_config(storage_dir)
|
||||
put_path(empty_bin_dir)
|
||||
|
||||
assert {:error, :missing_imagemagick} =
|
||||
Converter.regenerate_thumbnails(%PresentationFile{hash: hash, length: 1})
|
||||
end
|
||||
end
|
||||
|
||||
defp write_fake_imagemagick(bin_dir, command) do
|
||||
path = Path.join(bin_dir, command)
|
||||
|
||||
File.write!(path, """
|
||||
#!/bin/sh
|
||||
last=""
|
||||
|
||||
for arg in "$@"; do
|
||||
last="$arg"
|
||||
done
|
||||
|
||||
printf fake-thumbnail > "$last"
|
||||
""")
|
||||
|
||||
File.chmod!(path, 0o755)
|
||||
end
|
||||
|
||||
defp put_local_storage_config(storage_dir) do
|
||||
previous_storage_dir = Application.get_env(:claper, :storage_dir)
|
||||
previous_presentations = Application.get_env(:claper, :presentations)
|
||||
|
||||
Application.put_env(:claper, :storage_dir, storage_dir)
|
||||
|
||||
Application.put_env(
|
||||
:claper,
|
||||
:presentations,
|
||||
Keyword.merge(previous_presentations || [], storage: "local")
|
||||
)
|
||||
|
||||
on_exit(fn ->
|
||||
File.rm_rf!(storage_dir)
|
||||
Application.put_env(:claper, :storage_dir, previous_storage_dir)
|
||||
Application.put_env(:claper, :presentations, previous_presentations)
|
||||
end)
|
||||
end
|
||||
|
||||
defp put_path(path) do
|
||||
previous_path = System.get_env("PATH")
|
||||
|
||||
System.put_env("PATH", path)
|
||||
|
||||
on_exit(fn ->
|
||||
if previous_path do
|
||||
System.put_env("PATH", previous_path)
|
||||
else
|
||||
System.delete_env("PATH")
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
defp unique_tmp_dir do
|
||||
Path.join(System.tmp_dir!(), "claper-converter-test-#{System.unique_integer([:positive])}")
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user