Thumbnails becomes inevitable part of the process when dealing with images. They provide us a way to give a peek through the original image which helps in building rich user experience in modern applications.
In an internal productivity tool while building this experience, Our whole attachments feature was ready and we had found the only available option in Elixir/Phoenix ecosystem Thumbnex for generating thumbnails. Once we started integrating this library, we almost immediately got hit by following error:
** (ErlangError) Erlang error: :enoent
(elixir) lib/system.ex:622: System.cmd("ffprobe", ["-show_format", "/var/folders/k2/37ht7xpx4g1fswv0cn003gp80000gp/T/plug-1531/multipart-739416-202247-1"], [stderr_to_stdout: true])
lib/ffprobe.ex:47: FFprobe.format/1
lib/thumbnex/animations.ex:6: Thumbnex.Animations.duration/1
lib/thumbnex.ex:35: Thumbnex.create_thumbnail/3
To give some background, Thumbnex
hex package uses ImageMagick
and FFmpeg
internally to deliver thumbnail generation & other features. ImageMagick & FFmpeg are two most popular image & multimedia manipulation command line tools, respectively.
After debugging we figured out the error is related to ffprobe
which is a tool provided by FFmpeg
for printing info related to media files. Since we were mostly interested in image thumbnail generation, ImageMagick
is what we were focused on.
Therefore we started exploring other options to achieve our goal without adding unwanted complexity. We couldn't find any hex package which is primarily focused on image thumbnail generation. Hence, we decided will roll our own solution.
First step was to understand how to generate thumbnail using ImageMagick
, Their official site has some documentation around dealing with thumbnails. After reading through we could compile a basic thumbnail generation command
convert -define jpeg:size=500x180 trackive-staging/attachments/scope.id/sample.jpeg -auto-orient -thumbnail 250x90 -unsharp 0x.5 sample_thumb.jpeg
-thumbnail
- It resizes the image and strips all the profile and comment data to make it smaller.
-define jpeg:size=
- This is used for setting initial size original image which has been set twice that of final image so that it is clearly visible and doesn't look blurry. It is used to avoid operation over large input images.
-auto-orient
- It is used to set the image to correct orientation. This is helpful if the image is from Cameras.
- unsharp
- We can improve the above result by sharpening the image slightly using "-unsharp" after the "-thumbnail" resize operation.
Specify the required thumbnail dimension after -thumbnail
.
Next step was, executing this command from Elixir/Phoenix application. Elixir's System.cmd can interact with the host system directly, meaning we can pass commands to this function and it will get executed on our machine.
Now it was just a matter of putting together these knowledge in our code. Here is the code snippet we compiled
defmodule Image.Transformer do
def transform(original_file, operation \\ "convert") do
#1 get thumbnail file name
thumb_path = generate_thumb_file(original_file)
#2 generate thumbnail by passing appropriate parameters
System.cmd(operation, operation_commands(original_file_path, thumb_path))
#3 return the generated thumbnail
thumb_path
end
defp generate_thumb_file(original_file) do
thumb_file = original_file
|> String.replace(".", "_thumb.jpeg")
end
defp operation_commands(original_file_path, thumb_path, size \\ "250x90") do
[
"-define",
"jpeg:size=500x180",
original_file_path,
"-auto-orient",
"-thumbnail",
size,
"-unsharp",
"0x.5",
thumb_path
]
end
end
To summarize the above snippet, First, we get the original image file and generate a file name for its thumbnail. If the file name is sample.jpeg
then thumbnail will be named as sample_thumb.jpeg
.
Then, we execute the necessary ImageMagick
command with the appropriate parameters and return the newly generated thumbnail path.
Here is the link of above code snippet https://gist.github.com/trojanh/319d8c01b3c4c139bd1df930ea1c5d48
Discussion on Reddit: https://www.reddit.com/r/elixir/comments/915inl/generating_image_thumbnail_in_elixir_phoenix_with/