snibgo's ImageMagick pages


JPEGs from cameras are often wider than they are high, with metadata that specifies the true orientation. But software often ignores this metadata, so viewers don't display or process as we would hope. This script normalises orientations.


Create sample files

rem Remove any versions from previous builds of this page.
del or_*.jpg

for /L %%n in (1,1,8) do (
  set FILENAME=or_%%n.jpg

  %IMG7%magick -size 100x200 xc: ^
    -sparse-color barycentric 0,0,#f88,%%[fx:h-1],%%[fx:h-1],#8f8 ^
    -pointsize 50 -gravity Center -annotate 0 "a%%nb" ^

%IMG7%magick or_2.jpg -flop or_2.jpg
%IMG7%magick or_3.jpg -rotate 180 or_3.jpg
%IMG7%magick or_4.jpg -flip or_4.jpg
%IMG7%magick or_5.jpg -flop -rotate -90 or_5.jpg
%IMG7%magick or_6.jpg -rotate -90 or_6.jpg
%IMG7%magick or_7.jpg -flop -rotate 90 or_7.jpg
%IMG7%magick or_8.jpg -rotate 90 or_8.jpg

for /L %%n in (1,1,8) do (
  set FILENAME=or_%%n.jpg

  exiftool -n -Orientation=%%n !FILENAME!

  del or_*.jpg_original

We can list the dimensions:

%IMG7%magick identify -format "%%f %%wx%%h\n" or_?.jpg 
or_1.jpg 100x200
or_2.jpg 100x200
or_3.jpg 100x200
or_4.jpg 100x200
or_5.jpg 200x100
or_6.jpg 200x100
or_7.jpg 200x100
or_8.jpg 200x100

This is how a web-browser displays the images:

or_1.jpg or_2.jpg or_3.jpg or_4.jpg or_5.jpg or_6.jpg or_7.jpg or_8.jpg

On my computer, both Firefox and MS Internet Explorer show all images (except the first) incorrectly. These browsers ignore the orientation metadata.

Auto-orient with ImageMagick

ImageMagick can easily re-orient the images.

for /L %%n in (1,1,8) do (
  %IMG7%magick or_%%n.jpg -auto-orient or_ao_%%n.jpg
or_ao_1.jpg or_ao_2.jpg or_ao_3.jpg or_ao_4.jpg or_ao_5.jpg or_ao_6.jpg or_ao_7.jpg or_ao_8.jpg
%IMG7%magick identify -format "%%f %%wx%%h\n" or_ao_?.jpg 
or_ao_1.jpg 100x200
or_ao_2.jpg 100x200
or_ao_3.jpg 100x200
or_ao_4.jpg 100x200
or_ao_5.jpg 100x200
or_ao_6.jpg 100x200
or_ao_7.jpg 100x200
or_ao_8.jpg 100x200

ImageMagick's -auto-orient works correctly. However, it re-compresses JPEGs, and this is lossy.

Auto-orient with orientate.bat

The script orientate.bat finds the orientation with exiftool. It then tries to re-orient the image with jpegtran.

When the image dimensions are an exact multiple of the iMCU size (usually 8 or 16 pixels), jpegtran works fine. Otherwise, jpegtran will either put pixels in the wrong place or trim them off. I don't like either option.

So I tell jpegtran to make a perfect result. If it doesn't make a perfect result, I fallback to ImageMagick to do the job.

for /L %%n in (1,1,8) do (
  copy or_%%n.jpg or_et_%%n.jpg
call %PICTBAT%orientate or_et_*.jpg
or_et_1.jpg or_et_2.jpg or_et_3.jpg or_et_4.jpg or_et_5.jpg or_et_6.jpg or_et_7.jpg or_et_8.jpg
%IMG7%magick identify -format "%%f %%wx%%h\n" or_et_?.jpg 
or_et_1.jpg 100x200
or_et_2.jpg 100x200
or_et_3.jpg 100x200
or_et_4.jpg 100x200
or_et_5.jpg 200x100
or_et_6.jpg 200x100
or_et_7.jpg 200x100
or_et_8.jpg 200x100


For convenience, .bat scripts are also available in a single zip file. See Zipped BAT files.


rem From image(s) %1 (eg *.jpg), creates orientated versions.
rem exiftool tells us the orientation.
rem jpegtran does the work.
@rem Updated:
@rem   13-August-2022 for IM v7.

rem @echo off
setlocal enabledelayedexpansion

if "%1"=="" goto Bad

set JT=

rem For each file that needs re-orienting:
rem   copy it to .\backup
rem   %JT%jpegtran from .\backup to here
rem   exiftool copy all the tags from .\backup to here, changing the orientation to 1.

rem Note: filenames containing commas might cause problems.

set TMPFILE=%TEMP%\orient.jpg

exiftool -p "$FileName,$Orientation#" %1>orient.lis

type orient.lis

rem 1 Horizontal (normal)
rem 2 Mirror horizontal
rem 3 Rotate 180
rem 4 Mirror vertical
rem 5 Mirror horizontal and rotate 270 CW
rem 6 Rotate 90 CW
rem 7 Mirror horizontal and rotate 90 CW
rem 8 Rotate 270 CW

rem Note: untested for all values except 1, 6 and 8.

if not exist backup md backup

for /F "tokens=1,2 delims=," %%a ^
in (orient.lis) ^
do (
  set FileName=%%a
  set /A Orient=%%b
  if !Orient! gtr 1 (
    copy /Y !FileName! backup\
    exiftool -n -Orientation=1 backup\!FileName!
  set ERR=0
  if !Orient! equ 2 (
    echo !FileName! !Orient! flip horizontal
    %JT%jpegtran -perfect -flip horizontal -outfile !FileName! backup\!FileName!
    if ERRORLEVEL 1 %IMG7%magick backup\!FileName! -flop !FileName!
  ) else if !Orient! equ 3 (
    echo !FileName! !Orient! rotate 180
    %JT%jpegtran -perfect -rotate 180 -outfile !FileName! backup\!FileName!
    if ERRORLEVEL 1 %IMG7%magick backup\!FileName! -rotate 180 !FileName!
  ) else if !Orient! equ 4 (
    echo !FileName! !Orient! flip vertical
    %JT%jpegtran -perfect -flip vertical -outfile !FileName! backup\!FileName!
    if ERRORLEVEL 1 %IMG7%magick backup\!FileName! -flip !FileName!
  ) else if !Orient! equ 5 (
    echo !FileName! !Orient! flip horizontal, rotate 270
    %JT%jpegtran -perfect -flip horizontal -outfile %TMPFILE% backup\!FileName!
    if ERRORLEVEL 1 set ERR=1
    if !ERR!==0 (
      %JT%jpegtran -perfect -rotate 270 -outfile !FileName! %TMPFILE%
      if ERRORLEVEL 1 set ERR=1
    if !ERR!==1 %IMG7%magick backup\!FileName! -rotate 90 -flop !FileName!
  ) else if !Orient! equ 6 (
    echo !FileName! !Orient! rotate 90
    %JT%jpegtran -perfect -rotate 90 -outfile !FileName! backup\!FileName!
    if ERRORLEVEL 1 %IMG7%magick backup\!FileName! -rotate 90 !FileName!
  ) else if !Orient! equ 7 (
    echo !FileName! !Orient! flip horizontal, rotate 90
    %JT%jpegtran -perfect -flip horizontal -outfile %TMPFILE% backup\!FileName!
    if ERRORLEVEL 1 set ERR=1
    if !ERR!==0 (
      %JT%jpegtran -perfect -rotate 90 -outfile !FileName! %TMPFILE%
      if ERRORLEVEL 1 set ERR=1
    if !ERR!==1 %IMG7%magick backup\!FileName! -rotate -90 -flop !FileName!
  ) else if !Orient! equ 8 (
    echo !FileName! !Orient! rotate 270
    %JT%jpegtran -perfect -rotate 270 -outfile !FileName! backup\!FileName!
    if ERRORLEVEL 1 %IMG7%magick backup\!FileName! -rotate -90 !FileName!
  if !Orient! gtr 1 (
    exiftool -tagsFromFile backup\!FileName! -n -Orientation=1 !FileName!
    del !FileName!_original

if exist backup\*.jp* (
  echo Original files are in .\backup
) else (
  echo Removing possibly empty backup directory.
  rd backup

goto :end

echo Call with %%1=filename
echo %%1 can contain wilcards, eg *.jpg

@echo on

All images on this page were created by the commands shown, using:

%IMG7%magick -version
Version: ImageMagick 7.1.0-42 Q16-HDRI x64 396d87c:20220709
Copyright: (C) 1999 ImageMagick Studio LLC
Features: Cipher DPC HDRI OpenCL 
Delegates (built-in): bzlib cairo freetype gslib heic jng jp2 jpeg jxl lcms lqr lzma openexr pangocairo png ps raqm raw rsvg tiff webp xml zip zlib
Compiler: Visual Studio 2022 (193231332)

Source file for this web page is orient.h1. To re-create this web page, execute "procH1 orient".

This page, including the images, is my copyright. Anyone is permitted to use or adapt any of the code, scripts or images for any purpose, including commercial use.

Anyone is permitted to re-publish this page, but only for non-commercial use.

Anyone is permitted to link to this page, including for commercial use.

Page version v1.0 30-Dec-2014.

Page created 14-Aug-2022 18:42:56.

Copyright © 2022 Alan Gibson.