Michal Zalecki
Michal Zalecki
software development, testing, JavaScript,
TypeScript, Node.js, React, and other stuff

Convert files for the web from your terminal

For me, using a terminal is fundamental to tasks automation. I love to augment my workflow using a command line tools. One of the things I try to automate is preparing assets for using them in web apps. This post is a kind of documentation to me.

Presented tools are mostly cross-platform and it might be the case that you have already some of them installed. To stick to the merits of the post I decided not to include any tips on how to get those tools up and running. Nonetheless I haven not strugled which any of these so you should be just fine. Just google a command and follow instructions specific your operating system.

Table of contents:

JPG, PNG, SVG to Base64

OpenSSL provides us with command line utilities. To perform Base64 encoding we use enc command with -base64 option or -a for short. The tool is not restricted to work with any particular format although I rarely use it for something other than encoding an image.

$ openssl enc -base64 -in image.jpg > image.jpg.b64
$ openssl enc -a -in image.jpg > image.jpg.b64

The result of each of the commands is the same. I use 84KB JPEG file which is encoded to 114KB Base64 representation. Make sure your use case justifies an overhead of Base64 representation which is on average 137% of what is the size of a binary file.

Add a data URI to use a Base64 string as an image source or background.

<img src="data:image/jpeg;base64,/4AAQSk[…]FRQP9k=">
<img src="data:image/png;base64,/4AAQSk[…]FRQP9k=">
<img src="data:image/svg+xml;base64,/4AAQSk[…]FRQP9k=">

You can easily decode Base64 file back to its original representation passing a -d option which stands for decode.

$ openssl enc -d -base64 -in image.jpg.b64 > image.jpg
$ openssl enc -d -a -in image.jpg.b64 > image.jpg

SVG to PNG

When you want to convert SVG to a PNG file you have a few options. One of them is to open a file in the browser and try to save it as a PNG. It is neither quick nor fun but it is more than likely that you a have browser already. You are reading this blog post after all. Contrary to doing it by hand you can use one of a few command line tools.

My first choice is always svgexport. Definitely, give this project a start on GitHub!

$ svgexport image.svg image.png

By default, the PNG size is derived from the viewBox of an <svg> element. In my case, it is 256 pixels wide and 228 pixels high React.js logo from SVG Porn. Now I would like to prepare a file for higher pixel density devices. I can use a scale, set both dimensions or use only one like a width and height will be scaled to preserve the ratio.

$ svgexport image.svg [email protected] 2x
$ svgexport image.svg [email protected] 512:

I suggest you also experiment with the quality to get the best quality/size ratio. In many cases default, 100% is an overkill. I often set it to 70% and take it from there.

$ svgexport image.svg image-1.0.png 100%
$ svgexport image.svg image-0.7.png 70%

Looking at the MBP 13" 2017 screen I can not tell the difference between those two but size varies significantly. It is 18KB for 70% and 229KB for 100%.

Inkscape is a very decent alternative for svgexport. After initial start of XQuartz (X11 for macOS), it is also pretty fast too. The biggest advantage of Inkscape over the other tools is its versatility.

$ inkscape -z -w 512 $PWD/image.svg -e $PWD/image.ink.png

Optimize SVG size

Let's stick to the topic of SVG files. Very often file sent to you by a graphic designer is not optimized for size. How can you optimize SVG? It is a text file so it will benefit vastly from enabling gzip or brotli but it is not the optimization I would like to show you. It is likely that SVG file made in Illustrator or Sketch contains multiple comments, editor metadata or unnecessarily precise values (such as insignificant for a screen decimal places).

You can easily get rid of all this bloat with svgo. There are multiple configuration options available.

$ svgo --pretty image.svg
$ svgo -f /path/to/directory

PDF to PNG

There are two major solutions for converting PDF document to PNG images from your terminal. ImageMagic and Ghostscript. To use ImageMagic's convert command you will need to install Ghowstscript anyway as gs is used by convert to rasterize vector files. You can use gs directly, it is much faster than ImageMagick. Nonetheless, I have noticed that ImageMagic is doing a better job when it comes to text smoothing so you may want to play with both before deciding.

$ convert -density 300 -background white -alpha remove test.pdf test.png

Converting 9 pages long PDF document took ImageMagick 14 seconds and the size of output files is 1.9MB.

$ gs -sDEVICE=png16m -dTextAlphaBits=4 -r300 -o test-%02d.png test.pdf

Converting the same PDF took Ghostscript only 2.6 second and the size of output files is 2.4MB.

DOCX to PDF

I have not found a perfect solution to convert a DOCX document created with Microsoft Word to PDF preserving 1:1 layout. Well, except using World itself. That said, it is still possible to achieve really good result using LibreOffice. It happens that LibreOffice can run in a headless mode!

The command is not the same across different platforms. On macOS, it is a soffice and you will find it here /Applications/LibreOffice.app/Contents/MacOS/soffice. I suggest creating a symlink. On Linux, it should be just libreoffice and soffice.exe on Windows.

$ soffice --headless --convert-to pdf test.docx

I have used this approach before and explained in more details in a different post: Converting DOCX to PDF using Python.

Remove EXIF data

Removing EXIF information is not only a good thing to do concerning your privacy but also can save some kilobytes sent down the wire. From the overall file size standpoint, information about your camera model or GPS coordinates is negligible but it all adds up. Removing all EXIF data from a photo taken by iPhone shave 5KB off. To put it into perspective 5KB is a size of a not trivial library.

$ exiftool -all= IMG_0001.jpg

Working on multiple files

Unix philosophy of combining "small, sharp tools" pays off. You have just gone through the list of (I hope) helpful examples of how to convert various file formats. Using a find command you can fairly easy perform those operations on multiple files.

$ find . -name "*.jpeg" -exec sh -c "exiftool -all= {}" \;

Wrap up

That is it, for now. I am going to add more as soon as I find myself using something worth sharing. Feel free to let me know if there is a tool you use and which I am missing here.

Photo by Pablo Lancaster Jones on Unsplash.