Batch Convert HEIC to JPG in Linux

Recently I began organizing a bunch of pictures from old iPhone archives and beginning with the iPhone X I found that all of my offloaded pictures were in HEIC format. I’m sure if you’ve searched found and found this article you know what that means. That picture format has some definite benefits, but one down side is that it’s not as ubiquitous as something like JPG, so I wanted to convert all of my HEIC files to JPG quickly and easily. I found some command line tools that will do the job, but they’re only designed to convert one file at a time, so I wrote a little Bash script to automate the process.

Start by creating a folder and dumping all of your HEIC files in to it. Open that directory in a terminal so it’s your PWD. If you don’t already have the command line HEIF tools installed, install them with the following command:

sudo add-apt-repository ppa:strukturag/libheif
sudo apt-get install libheif-examples
sudo apt-get update

From here we can use a utility called heif-convert to convert files. You should try it on a single file first, just to make sure it’s going to work in batch. The syntax easy:

heif-convert infile.heif outfile.jpg

Once you know that you can convert a single file, it’s time to batch convert. Create a Bash script with nano by using the following command:

nano convert.sh

Once in nano, you can use the following script

#!/bin/bash
for f in *.HEIC
do
echo "Working on file $f"
heif-convert $f $f.jpg
done

That’s it. Save the file with CTRL + O and exit nano with CTRL + X. Make the script executable:

chmod +x convert.sh

Finally, run the script. Keep in mind the script should be in the same directory as all of your HEIC files.

./convert.sh

That should be it. As the script runs it should convert each file one-by-one, and create new files with the .jpg extension.

Bonus – I found a great script that Ferux posted to the Ubuntu forums that will allow you to rename all of the JPG, PNG, MP4 and AVI files in a directory based on the date and time they were taken, which the script pulls from EXIF data. This is a great way to organize the files chronologically.

For archival purposes, here is the script in its entirety:

#!/bin/bash
# By Ferux, 26 June 2016.
# Script for renaming photos and videos based on their date.
# Useful for watching slideshows with the videos at the moment they were shot instead of all at the end.
# Also useful for combining pictures of multiple sources into the correct order.
# For jpg's, the exif date 'taken on' will be used. If that's not found, the date of last change is used.
# For all other files, date of last change is used. Only following extensions are affected: mp4, mpg, png, avi, mov, jpg.

# To use this:
# 1. Put this text in a file named renamephotos
# 2. Make the file executable.
# 3. Put the file in the folder of which you want to rename the files.
# 4. Nautilus: File --> open in terminal.
# 5. In the terminal window, enter the following command: ./renamephotos

# Make the next one 'true' if you always want to add the original filename at the end of the new one.
# Otherwise the script will only do that if 2 files with the same name would be created.
preservefn="false"

for filename in *.*
do
  echo "$filename"
  tmp="$(echo "$filename" | tr '[A-Z]' '[a-z]')"
  case "$filename" in
    20*) 
      echo 'left alone because already starts with 20'
      ;;
    *.mp4|*.MP4)
      doelextensie=".mp4"
      wadissergebeurd="Video, used date of last change."
      newfilename="$(stat -c %y "$filename" | sed -e 's/\................//g' -e 's/-//g' -e 's/://g' -e 's/ /_/g')"
      if [ -a ""$newfilename""$doelextensie"" ] || [ "$preservefn" == "true" ]
      then
        mv -i "$filename" """$newfilename"_"$filename"""
        echo "$wadissergebeurd"
        echo 'Original name added at the end'
      else
        mv -i "$filename" ""$newfilename""$doelextensie""
        echo "$wadissergebeurd"
      fi
      ;;
    *.mpg|*.MPG)
      doelextensie=".mpg"
      wadissergebeurd="Video, used date of last change."
      newfilename="$(stat -c %y "$filename" | sed -e 's/\................//g' -e 's/-//g' -e 's/://g' -e 's/ /_/g')"
      if [ -a ""$newfilename""$doelextensie"" ] || [ "$preservefn" == "true" ]
      then
        mv -i "$filename" """$newfilename""_""$filename"""
        echo "$wadissergebeurd"
        echo 'Original name added at the end'
      else
        mv -i "$filename" ""$newfilename""$doelextensie""
        echo "$wadissergebeurd"
      fi
      ;;
    *.png|*.PNG)
      doelextensie=".png"
      wadissergebeurd="PNG, used date of last change."
      newfilename="$(stat -c %y "$filename" | sed -e 's/\................//g' -e 's/-//g' -e 's/://g' -e 's/ /_/g')"
      if [ -a ""$newfilename""$doelextensie"" ] || [ "$preservefn" == "true" ]
      then
        mv -i "$filename" """$newfilename""_""$filename"""
        echo "$wadissergebeurd"
        echo 'Original name added at the end'
      else
        mv -i "$filename" ""$newfilename""$doelextensie""
        echo "$wadissergebeurd"
      fi
      ;;
    *.avi|*.AVI)
      doelextensie=".avi"
      wadissergebeurd="Video, used date of last change."
      newfilename="$(stat -c %y "$filename" | sed -e 's/\................//g' -e 's/-//g' -e 's/://g' -e 's/ /_/g')"
      if [ -a ""$newfilename""$doelextensie"" ] || [ "$preservefn" == "true" ]
      then
        mv -i "$filename" """$newfilename""_""$filename"""
        echo "$wadissergebeurd"
        echo 'Original name added at the end'
      else
        mv -i "$filename" ""$newfilename""$doelextensie""
        echo "$wadissergebeurd"
      fi
      ;;
    *.mov|*.MOV)
      doelextensie=".mov"
      wadissergebeurd="Video, used date of last change."
      newfilename="$(stat -c %y "$filename" | sed -e 's/\................//g' -e 's/-//g' -e 's/://g' -e 's/ /_/g')"
      if [ -a ""$newfilename""$doelextensie"" ] || [ "$preservefn" == "true" ]
      then
        mv -i "$filename" """$newfilename""_""$filename"""
        echo "$wadissergebeurd"
        echo 'Original name added at the end'
      else
        mv -i "$filename" ""$newfilename""$doelextensie""
        echo "$wadissergebeurd"
      fi
      ;;
    *.JPG|*.jpg|*.jpeg|*.JPEG)
      newnametemp="$(exiftool -a -s -CreateDate "$filename")"
      doelextensie=".jpg"
      if [ -z "$newnametemp" ]
      then 
        wadissergebeurd="No exif date found, using last changed date"
        newfilename="$(stat -c %y "$filename" | sed -e 's/\................//g' -e 's/-//g' -e 's/://g' -e 's/ /_/g')"
        if [ -a ""$newfilename""$doelextensie"" ] || [ "$preservefn" == "true" ]
        then
          mv -i "$filename" """$newfilename"_"$filename"""
          echo "$wadissergebeurd"
          echo 'Original name added at the end'
        else
          mv -i "$filename" ""$newfilename""$doelextensie""
          echo "$wadissergebeurd"
        fi
      else
        newfilename="$(exiftool -a -s -CreateDate "$filename" | awk -F ': ' '{print $2}' | sed -e 's/://g' -e 's/ /_/g')"
        newfilename="$(echo $newfilename | cut -c 1-15)"
        wadissergebeurd="Date taken from exif info"
        if [ -a ""$newfilename""$doelextensie"" ] || [ "$preservefn" == "true" ]
        then
          mv -i "$filename" """$newfilename"_"$filename"""
          echo "$wadissergebeurd"
          echo 'Original name added at the end'
        else
          mv -i "$filename" ""$newfilename""$doelextensie""
          echo "$wadissergebeurd"
        fi
      fi
      ;;
    *)
      echo 'Not a *.jpg / *.png / *.mp4 / *.avi!'
      ;;
  esac
done

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.