Rajan Tiwari

@trojanh

Image Thumbnail in Elixir using ImageMagick

When you are dealing with images, you cannot live without thumbnails. For large images, thumbnails provide us a way to peek through the image without worrying about the actual image size and waiting for it to finish downloading so that we can see what that image is all about.

Our whole attachments feature was ready and we had found the only available option in Elixir/Phoenix world — Thumbnex, for generating thumbnails. Everything was working fine except for generating thumbnails. We were getting the following error with Thumbnex:


** (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

Just to give you some background Thumbnex hex package uses ImageMagick and FFmpeg to manipulate images and media files to generate thumbnails.

ImageMagick is a command-line tool which is used to resize, flip, mirror, rotate, distort, shear and transform images. We can install it on our machine with sudo apt-get imagemagick.

FFmpeg is also a command line tool which can handle video, audio, and other multimedia files.

Since we are mostly interested in Image thumbnail generation, ImageMagick is what is helping us do that internally. But this blog will help you take any of the above tools and start using them from Elixir.

Coming back to the above error, the error is related to ffprobe which is a tool provided by FFmpeg for printing info related to media files. Initially, I thought it might be related to my system, so I tried it on another machine and it was throwing the same error. Moreover, I couldn’t trust this for prod.

So I started looking for some other options to do the same tasks. Unfortunately, I couldn’t find any other hex package for generating a thumbnail.

So I went on to explore and do it myself. So the first step was to generate a thumbnail from the command line using ImageMagick(). So I found this handy command, which does this:


convert -define jpeg:size=500x180 trackive-staging/attachments/scope.id/sample.jpeg -auto-orient -thumbnail 250x90 -unsharp 0x.5 sample_thumb.jpeg

Note: Make sure you have ImageMagick installed on your machine.

-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 — As such you can improve the above result by sharpening the image slightly (using -unsharp) after the -thumbnail resize operation.

Specify the required thumbnail dimension after -thumbnail.

Above command should give us the required image thumbnail. Once this is done we would be interested in doing it programmatically using Elixir.

In Elixir, System.cmd can interact with the host system directly, meaning whichever commands we pass to this function is executed on the local command line. Now we know the command and we know how to run it programmatically for dynamic image thumbnail generation.

So the final Elixir code which can be used directly to get the thumbnail from the original image is as follows:


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
original_file
|> String.replace(“.”, “_thumb.”)
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

First, we get the original image file and generate a file name for its thumbnail. So if the file name is sample.jpeg them thumbnail file name will be sample_thumb.jpeg.

Then we go ahead with running the ImageMagick command on the host machine by using System.cmd.

Since we passed the thumbnail file name to convert command, that is our file new generated file. Check the original image file directory to confirm if the thumbnail is generated.

I have added this my GitHub gist.
https://gist.github.com/trojanh/319d8c01b3c4c139bd1df930ea1c5d48

You know ImageMagick, you know Elixir, use any of the operations of ImageMagick(or any other tool like FFmpeg) to make any transformations easily from this single file.

Edit: Seems the error was because of corrupt installation of FFmpeg on my machines. So reinstalling the FFmpeg from command line will fix the issue with Thumbnex.

More by Rajan Tiwari

Topics of interest

More Related Stories