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 makes normalises orientations.


Create sample files

rem Remove any versions from previus builds of his page.
del or_*.jpg

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

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

%IM%convert or_2.jpg -flop or_2.jpg
%IM%convert or_3.jpg -rotate 180 or_3.jpg
%IM%convert or_4.jpg -flip or_4.jpg
%IM%convert or_5.jpg -flop -rotate -90 or_5.jpg
%IM%convert or_6.jpg -rotate -90 or_6.jpg
%IM%convert or_7.jpg -flop -rotate 90 or_7.jpg
%IM%convert 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:

%IM%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 (
  %IM%convert 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
%IM%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
%IM%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 100x200
or_et_6.jpg 100x200
or_et_7.jpg 100x200
or_et_8.jpg 100x200


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 @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 %IM%convert 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 %IM%convert 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 %IM%convert 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 %IM%convert 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 %IM%convert 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 %IM%convert 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 %IM%convert 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:

%IM%identify -version
Version: ImageMagick 6.9.2-5 Q16 x64 2015-10-31
Copyright: Copyright (C) 1999-2015 ImageMagick Studio LLC
Visual C++: 180031101
Features: Cipher DPC Modules OpenMP 
Delegates (built-in): bzlib cairo freetype jng jp2 jpeg lcms lqr openexr pangocairo png ps rsvg tiff webp xml zlib

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 27-May-2016 16:31:06.

Copyright © 2016 Alan Gibson.