DEV Community

hexfloor
hexfloor

Posted on • Edited on

More storage for media : organize files using ChatGPT : part 2, converting JPEG to HEIC

Main article
Think to do backups and to fix metadata before processing, see in part 1

Introduction

The setup is the outcome of part1, I will focus on image files only: JPEG and HEIC and I will convert everything to HEIC. Why? Because I can, if you can't - use JPEG.
TL;DR : use ImageMagick built from sources --with-heic=yes on linux to make it happen after having installed libheif

Failed attempt to use jrottenberg/ffmpeg:4.1-alpine image to convert JPEG to HEIC

I will use docker image of ffpeg on alpine and I'm skipping steps as you can get this information from the internet search or generative AI, I'm using the ChatGPT as no login is required and most of readers will be able to reproduce my steps.

Thank you! I have jrottenberg/ffmpeg:4.1-alpine image, I wish to convert all the files in the jpg directory to the heic format with the resolution not more than 960x1280 and the size of approximately 300Kb and to have them in the directory jpg_heic, I don't wish to create my dockerfile just to run a command from git bash or cmd on windows

Image description

docker run --rm -v <path_to_jpg_directory>:/input -v <path_to_output_directory>:/output jrottenberg/ffmpeg:4.1-alpine \
    -i /input/%01d.jpg -vf "scale=w=960:h=1280:force_original_aspect_ratio=decrease" -b:v 300k /output/%01d.heic

Enter fullscreen mode Exit fullscreen mode

Image description

Somehow it didn't work out of the box, let me try another approach:

can we start docker once and mount the volumes once, then execute the loop with the same container ? I think it will be more optimal

Image description

Image description

docker run -it --rm -v /path/to/jpg:/input -v /path/to/jpg_heic:/output --name ffmpeg-container jrottenberg/ffmpeg:4.1-alpine /bin/sh

for img in /input/*.jpg; do
  ffmpeg -i "$img" -vf "scale=iw*min(960/iw\,1280/ih):ih*min(960/iw\,1280/ih),format=heic" -b:v 300k "/output/$(basename "${img%.jpg}.heic")"
done

Enter fullscreen mode Exit fullscreen mode

This didn't work either:

Image description
Let's start over:

Unable to find a suitable output format for '/bin/sh'
/bin/sh: Invalid argument

Image description

docker run --rm -v /path/to/jpg:/input -v /path/to/jpg_heic:/output jrottenberg/ffmpeg:4.1-alpine /bin/sh -c "for img in /input/*.jpg; do ffmpeg -i \"\$img\" -vf 'scale=iw*min(960/iw\,1280/ih):ih*min(960/iw\,1280/ih),format=heic' -b:v 300k \"/output/\$(basename \"\${img%.jpg}.heic\")\"; done"

Enter fullscreen mode Exit fullscreen mode

Image description

Image description

Well...still doesn't work, okay let's use the creator's guide and do the work in the interactive way :

docker run -it --entrypoint=/bin/sh -v /path/to/jpg:/input -v /path/to/jpg_heic:/output jrottenberg/ffmpeg:4.1-alpine
Enter fullscreen mode Exit fullscreen mode

and then run the command inside the container :

for img in /input/*.jpg; do ffmpeg -i "$img" -vf "scale=iw*min(960/iw\,1280/ih):ih*min(960/iw\,1280/ih),format=heic" -b:v 300k "/output/$(basename "$img" .jpg).heic"; done
Enter fullscreen mode Exit fullscreen mode

Still failure, let's make it more simple :

for img in /input/*.jpg; do ffmpeg -i "$img" -vf "scale=iw*min(960/iw\,1280/ih):ih*min(960/iw\,1280/ih)" -c:v hevc -crf 28 "/output/$(basename "$img" .jpg).heic"; done

Enter fullscreen mode Exit fullscreen mode

Another failure, let's check if the format is supported :

ffmpeg -formats | grep heic
Enter fullscreen mode Exit fullscreen mode

No it's not. Okay let's move on and use the latest image.

Failed attempt to use jrottenberg/ffmpeg:latest image to convert JPEG to HEIC

Let's go :

docker pull jrottenberg/ffmpeg

docker run -it --entrypoint=/bin/sh -v /path/to/jpg:/input -v /path/to/jpg_heic:/output jrottenberg/ffmpeg:latest

ffmpeg -formats | grep heic
Enter fullscreen mode Exit fullscreen mode

Still no support for HEIC.
Okay whatever, I will go to the official page now, something I should have considered at the beginning.

Failed attempt to use ffmpeg builds from Gyan Dev to convert JPEG to HEIC

I've got some help from ChatGPT, check the SHA256, installed the release build for ffmpeg, feel free to do the same on your risk.
Checking the version and the formats:

ffmpeg -version

ffmpeg -formats
Enter fullscreen mode Exit fullscreen mode

Still no HEIC.
Let's get the latest build from master.
I have installed: ffmpeg-2024-10-24-git-153a6dc8fa-full_build.7z after having checked SHA256.
Still no HEIC.
Let's check the github of ffmpeg
and it seems that HEIC is not listed in the ffmpeg image formats
HEIC is not supported...read the manual before diving into the implementation.

Failed attempt to use ImageMagic on Win11 to convert JPEG to HEIC

Let's give a try with ImageMagic
checking if the format is supported :

magick -list format | find "HEIC"
Enter fullscreen mode Exit fullscreen mode

All good, the command looks pretty simple:

magick mogrify -path /path/to/output_directory -resize 960x1280 -format heic /path/to/input_directory/*.jpg
Enter fullscreen mode Exit fullscreen mode

No luck, trying CMD version:

for %i in ("C:\path\to\input_directory\*.jpg") do magick convert "%i" -resize 960x1280 "C:\path\to\output_directory\%~ni.heic"
Enter fullscreen mode Exit fullscreen mode

And the result is the same: no encode delegate for this image format HEIC
It seems I need to the have the libheif.
Looks prominent, I will try to run it on WSL later on.

Failed attempt to use IrfanView on Win11 to convert JPEG to HEIC

Got it from IrfanView with all the plugins, conversion from HEIC to JPEG works, vice-versa - NO.

Failed attempt to use Win11 Photos to convert JPEG to HEIC

Conversion from HEIC to JPEG works, vice-versa - NO.

WSL

Let's get WSL
Then :

sudo apt update
sudo apt install libheif-dev
sudo apt install build-essential
sudo apt install imagemagick

Enter fullscreen mode Exit fullscreen mode

same error when using convert temp.jpg temp.heic

convert-im6.q16: no encode delegate for this image format `HEIC' @ warning/constitute.c/WriteImage/1305.
Enter fullscreen mode Exit fullscreen mode

Let's start over and install ImageMagick from source, at the time of writing the last version is ImageMagick-7.1.1-39, you may need to change the link to tar.gz
Cleanup:

sudo apt remove --purge imagemagick
Enter fullscreen mode Exit fullscreen mode

Install from sources:

sudo apt update
sudo apt install build-essential libheif-dev libmagickwand-dev
sudo apt install wget
sudo apt install libjpeg-dev libpng-dev libtiff-dev
wget https://download.imagemagick.org/ImageMagick/download/ImageMagick.tar.gz
tar -xvf ImageMagick.tar.gz
cd ImageMagick-7.1.1-39/
Enter fullscreen mode Exit fullscreen mode

and now the moment of the glory (maybe)

./configure --with-heic=yes
make
sudo make install
Enter fullscreen mode Exit fullscreen mode

I have seen the line I've been waiting for :

  DELEGATES         = bzlib djvu fontconfig freetype heic jbig jng jp2 jpeg lcms lqr lzma openexr png ps tiff webp x xml zlib zstd
Enter fullscreen mode Exit fullscreen mode

checking with magick -version
New error:

magick: error while loading shared libraries: libMagickCore-7.Q16HDRI.so.10: cannot open shared object file: No such file or directory
Enter fullscreen mode Exit fullscreen mode

let's do our best:

sudo ldconfig
ldconfig -p | grep MagickCore
Enter fullscreen mode Exit fullscreen mode

Checking again magick -version:

Version: ImageMagick 7.1.1-39 Q16-HDRI x86_64 22428 https://imagemagick.org
Copyright: (C) 1999 ImageMagick Studio LLC
License: https://imagemagick.org/script/license.php
Features: Cipher DPC HDRI OpenMP(4.5)
Delegates (built-in): bzlib djvu fontconfig freetype heic jbig jng jp2 jpeg lcms lqr lzma openexr png tiff webp x xml zlib zstd
Compiler: gcc (13.2)
Enter fullscreen mode Exit fullscreen mode

The tricky part is ./configure --with-heic=yes and sudo ldconfig.
Those who know…….know..
Testing:

magick input.jpg output.heic
Enter fullscreen mode Exit fullscreen mode

I've got a log message, however conversion worked:

magick: no encode delegate for this image format `HEIC' @ warning/constitute.c/WriteImage/1403.
Enter fullscreen mode Exit fullscreen mode

Image description
All the rest is trivial.

Summary

It might have worked with a simple ImageMagick installation on WSL, the original goal of the post was to show how easy it is to move on with ChatGPT and in fact still you need to know what you are doing as sometimes you get suggestions which are not supported. Still it's helpful to move on.
Why has it been so difficult to make it work on Win? Most probably due to the fact that patents for HEVC will have expired somewhere near 2030.
Hopefully we have Linux, OpenSource, ImageMagick, ChatGPT and some brains.
Apply the guides to your needs, if you are in doubt - use JPEG. Check about HEVC and VVC before taking your own decision.

Bonus

This should be a good start for you:

Hi ChatGPT, I wish to compress some old photos of mine into the heic with normal quality, possibly with some loss, and my best wish would be to reduce the file size as much as we can, however preserving the quality, could you please suggest me the resolution and the file size in one line, and the ImageMagick command in the second line ? Short answer, thank you !

Image description

magick input.jpg -resize 1920x1080 -quality 80 output.heic
Enter fullscreen mode Exit fullscreen mode

Industrial version:

#!/bin/bash

# Input and Output directories
input_dir="./input"
output_dir="./output"

# Ensure the output directory exists
mkdir -p "$output_dir"

# Loop through all jpg files in the input directory
for img in "$input_dir"/*.jpg; do
    # Get the image dimensions (width x height)
    dimensions=$(identify -format "%wx%h" "$img")
    width=$(echo $dimensions | cut -d'x' -f1)
    height=$(echo $dimensions | cut -d'x' -f2)

    # Check for vertical images (height >= width)
    if [ "$height" -ge "$width" ]; then
        # Vertical and height > 1280, resize to height 1280
        if [ "$height" -gt 1280 ]; then
            output_file="$output_dir/$(basename "$img" .jpg).heic"
            magick "$img" -resize x1280 -quality 80 "$output_file"
            echo "Resized and converted $img to $output_file"
        else
            # Vertical image with height <= 1280, just convert to HEIC
            output_file="$output_dir/$(basename "$img" .jpg).heic"
            magick "$img" "$output_file"
            echo "Converted $img to $output_file"
        fi
    elif [ "$width" -gt "$height" ]; then
        # Landscape and width > 1280, resize to width 1280
        if [ "$width" -gt 1280 ]; then
            output_file="$output_dir/$(basename "$img" .jpg).heic"
            magick "$img" -resize 1280x -quality 80 "$output_file"
            echo "Resized and converted $img to $output_file"
        else
            # Landscape image with width <= 1280, just convert to HEIC
            output_file="$output_dir/$(basename "$img" .jpg).heic"
            magick "$img" "$output_file"
            echo "Converted $img to $output_file"
        fi
    else
        echo "Skipping $img: does not fit any criteria"
    fi
done

Enter fullscreen mode Exit fullscreen mode

Top comments (0)