Prefer 'magick' command to 'convert', if available

ImageMagick version 7 provides command 'magick' (as well as legacy 'convert'), is readily available on Windows but is not, currently, readily available on Ubuntu.

On Windows, the name of ImageMagick's `convert` utility clashes with Microsoft's `C:\Windows\System32\convert.exe` utility. Using `magick`, if available, avoids the conflict.

For clarity and to be command name-agnostic, the raster option name is changed from 'convert' (the command) to 'imagemagick' (the name of the software).

For consistency with the version 7 command name, references in the code to 'convert' are changed to 'magick', throughout.
This commit is contained in:
Mike Pilgrem 2020-07-05 16:14:19 +01:00 committed by David Himmelstrup
commit 4b338de094
8 changed files with 49 additions and 27 deletions

View file

@ -44,7 +44,7 @@ reanimate checks:
Has blender: 2.82 Has blender: 2.82
Has rsvg-convert: 2.44.10 Has rsvg-convert: 2.44.10
Has inkscape: 0.92.4 Has inkscape: 0.92.4
Has convert: 6.9.10-14 Has imagemagick: 6.9.10-14
Has LaTeX: /usr/bin/latex Has LaTeX: /usr/bin/latex
Has LaTeX package 'babel': OK Has LaTeX package 'babel': OK
Has LaTeX package 'preview': OK Has LaTeX package 'preview': OK

View file

@ -105,6 +105,7 @@ library
Reanimate.Driver Reanimate.Driver
Reanimate.Driver.Check Reanimate.Driver.Check
Reanimate.Driver.CLI Reanimate.Driver.CLI
Reanimate.Driver.Magick
Reanimate.Driver.Server Reanimate.Driver.Server
Reanimate.Driver.Compile Reanimate.Driver.Compile
Paths_reanimate Paths_reanimate

View file

@ -48,19 +48,19 @@ data Preset = Youtube | ExampleGif | Quick | MediumQ | HighQ | LowFPS
readRaster :: String -> Maybe Raster readRaster :: String -> Maybe Raster
readRaster raster = readRaster raster =
case map toLower raster of case map toLower raster of
"none" -> Just RasterNone "none" -> Just RasterNone
"auto" -> Just RasterAuto "auto" -> Just RasterAuto
"inkscape" -> Just RasterInkscape "inkscape" -> Just RasterInkscape
"rsvg" -> Just RasterRSvg "rsvg" -> Just RasterRSvg
"convert" -> Just RasterConvert "imagemagick" -> Just RasterMagick
_ -> Nothing _ -> Nothing
showRaster :: Raster -> String showRaster :: Raster -> String
showRaster RasterNone = "none" showRaster RasterNone = "none"
showRaster RasterAuto = "auto" showRaster RasterAuto = "auto"
showRaster RasterInkscape = "inkscape" showRaster RasterInkscape = "inkscape"
showRaster RasterRSvg = "rsvg" showRaster RasterRSvg = "rsvg"
showRaster RasterConvert = "convert" showRaster RasterMagick = "imagemagick"
readFormat :: String -> Maybe Format readFormat :: String -> Maybe Format
readFormat fmt = readFormat fmt =
@ -185,7 +185,7 @@ renderCommand = info parse
(long "raster" <> showDefaultWith showRaster (long "raster" <> showDefaultWith showRaster
<> metavar "RASTER" <> metavar "RASTER"
<> value RasterNone <> value RasterNone
<> help "Raster engine: none, auto, inkscape, rsvg, convert") <> help "Raster engine: none, auto, inkscape, rsvg, imagemagick")
opts :: ParserInfo Options opts :: ParserInfo Options
opts = info (options <**> helper ) opts = info (options <**> helper )

View file

@ -3,7 +3,7 @@ module Reanimate.Driver.Check
( checkEnvironment ( checkEnvironment
, hasRSvg , hasRSvg
, hasInkscape , hasInkscape
, hasConvert , hasMagick
) where ) where
import Control.Exception (SomeException, handle) import Control.Exception (SomeException, handle)
@ -11,6 +11,7 @@ import Control.Monad
import Data.Maybe import Data.Maybe
import Data.Version import Data.Version
import Reanimate.Misc (runCmd_) import Reanimate.Misc (runCmd_)
import Reanimate.Driver.Magick (magickCmd)
import System.Console.ANSI.Codes import System.Console.ANSI.Codes
import System.Directory (findExecutable) import System.Directory (findExecutable)
import System.IO import System.IO
@ -30,7 +31,7 @@ checkEnvironment = do
runCheck "Has blender" hasBlender runCheck "Has blender" hasBlender
runCheck "Has rsvg-convert" hasRSvg runCheck "Has rsvg-convert" hasRSvg
runCheck "Has inkscape" hasInkscape runCheck "Has inkscape" hasInkscape
runCheck "Has convert" hasConvert runCheck "Has imagemagick" hasMagick
runCheck "Has LaTeX" hasLaTeX runCheck "Has LaTeX" hasLaTeX
runCheck ("Has LaTeX package '"++ "babel" ++ "'") $ hasTeXPackage "latex" runCheck ("Has LaTeX package '"++ "babel" ++ "'") $ hasTeXPackage "latex"
"[english]{babel}" "[english]{babel}"
@ -107,8 +108,8 @@ hasInkscape = checkMinVersion minVersion <$> inkscapeVersion
where where
minVersion = Version [0,92] [] minVersion = Version [0,92] []
hasConvert :: IO (Either String String) hasMagick :: IO (Either String String)
hasConvert = checkMinVersion minVersion <$> convertVersion hasMagick = checkMinVersion minVersion <$> magickVersion
where where
minVersion = Version [6,0,0] [] minVersion = Version [6,0,0] []
@ -136,8 +137,8 @@ inkscapeVersion = extractVersion "inkscape" ["--version"] $ \line ->
["Inkscape", vs] -> vs ["Inkscape", vs] -> vs
_ -> "" _ -> ""
convertVersion :: IO (Maybe Version) magickVersion :: IO (Maybe Version)
convertVersion = extractVersion "convert" ["-version"] $ \line -> magickVersion = extractVersion magickCmd ["-version"] $ \line ->
case take 3 $ words line of case take 3 $ words line of
["Version:", "ImageMagick", vs] -> vs ["Version:", "ImageMagick", vs] -> vs
_ -> "" _ -> ""

View file

@ -0,0 +1,18 @@
module Reanimate.Driver.Magick
( magickCmd
) where
import System.IO.Unsafe (unsafePerformIO)
import System.Directory (findExecutable)
-- |The name of the ImageMagick command. On Unix-like operating systems, the
-- command 'convert' does not conflict with the name of other commands. On
-- Windows, ImageMagick version 7 is readily available, the command 'magick'
-- should be present, and is preferred over 'convert'. If it is not present,
-- 'convert' is assumed to be the relevant command.
magickCmd :: String
-- The use of 'unsafeperformIO' is justified on the basis that if 'magick' is
-- found once, it will always be present.
magickCmd = unsafePerformIO $ do
mPath <- findExecutable "magick"
pure $ maybe "convert" (const "magick") mPath

View file

@ -29,7 +29,7 @@ data Raster
| RasterAuto | RasterAuto
| RasterInkscape | RasterInkscape
| RasterRSvg | RasterRSvg
| RasterConvert | RasterMagick
deriving (Show, Eq) deriving (Show, Eq)
{-# NOINLINE pRasterRef #-} {-# NOINLINE pRasterRef #-}

View file

@ -33,6 +33,7 @@ import Graphics.SvgTree ( Number(..)
import qualified Graphics.SvgTree as Svg import qualified Graphics.SvgTree as Svg
import Reanimate.Animation import Reanimate.Animation
import Reanimate.Cache import Reanimate.Cache
import Reanimate.Driver.Magick
import Reanimate.Misc import Reanimate.Misc
import Reanimate.Render import Reanimate.Render
import Reanimate.Parameters import Reanimate.Parameters
@ -248,8 +249,8 @@ vectorize_ args path = unsafePerformIO $ do
hClose svgH hClose svgH
hClose bmpH hClose bmpH
potrace <- requireExecutable "potrace" potrace <- requireExecutable "potrace"
convert <- requireExecutable "convert" magick <- requireExecutable magickCmd
runCmd convert [path, "-flatten", tmpBmpPath] runCmd magick [path, "-flatten", tmpBmpPath]
runCmd potrace (args ++ ["--svg", "--output", tmpSvgPath, tmpBmpPath]) runCmd potrace (args ++ ["--svg", "--output", tmpSvgPath, tmpBmpPath])
renameOrCopyFile tmpSvgPath svgPath renameOrCopyFile tmpSvgPath svgPath
svg_data <- B.readFile svgPath svg_data <- B.readFile svgPath

View file

@ -23,6 +23,7 @@ import Graphics.SvgTree (Number (..))
import Numeric import Numeric
import Reanimate.Animation import Reanimate.Animation
import Reanimate.Driver.Check import Reanimate.Driver.Check
import Reanimate.Driver.Magick
import Reanimate.Misc import Reanimate.Misc
import Reanimate.Parameters import Reanimate.Parameters
import System.Console.ANSI.Codes import System.Console.ANSI.Codes
@ -298,14 +299,14 @@ requireRaster raster = do
selectRaster :: Raster -> IO Raster selectRaster :: Raster -> IO Raster
selectRaster RasterAuto = do selectRaster RasterAuto = do
rsvg <- hasRSvg rsvg <- hasRSvg
ink <- hasInkscape ink <- hasInkscape
conv <- hasConvert magick <- hasMagick
if if
| isRight rsvg -> pure RasterRSvg | isRight rsvg -> pure RasterRSvg
| isRight ink -> pure RasterInkscape | isRight ink -> pure RasterInkscape
| isRight conv -> pure RasterConvert | isRight magick -> pure RasterMagick
| otherwise -> pure RasterNone | otherwise -> pure RasterNone
selectRaster r = pure r selectRaster r = pure r
applyRaster :: Raster -> FilePath -> IO () applyRaster :: Raster -> FilePath -> IO ()
@ -320,8 +321,8 @@ applyRaster RasterInkscape path = runCmd
applyRaster RasterRSvg path = runCmd applyRaster RasterRSvg path = runCmd
"rsvg-convert" "rsvg-convert"
[path, "--unlimited", "--output", replaceExtension path "png"] [path, "--unlimited", "--output", replaceExtension path "png"]
applyRaster RasterConvert path = applyRaster RasterMagick path =
runCmd "convert" [path, replaceExtension path "png"] runCmd magickCmd [path, replaceExtension path "png"]
concurrentForM_ :: [a] -> (a -> IO ()) -> IO () concurrentForM_ :: [a] -> (a -> IO ()) -> IO ()
concurrentForM_ lst action = do concurrentForM_ lst action = do