module Sound.Jammit.Internal.ImageMagick
( connectVertical
, splitVertical
, joinPages
) where
import Control.Applicative ((<$>))
import Control.Monad (void)
import Data.Char (isDigit)
import Data.List (isPrefixOf, sortBy)
import Data.Maybe (listToMaybe)
import Data.Ord (comparing)
import System.Environment (lookupEnv)
import System.Exit (ExitCode(..))
import qualified System.Info as Info
import System.Directory (getDirectoryContents)
import System.FilePath ((</>))
import System.IO.Temp (createTempDirectory)
import System.Process (readProcess, readProcessWithExitCode)
import Sound.Jammit.Internal.TempFile
imageMagick :: String -> IO (Maybe String)
imageMagick cmd = do
(code, _, _) <- readProcessWithExitCode cmd ["-version"] ""
case code of
ExitSuccess -> return $ Just cmd
_ -> case Info.os of
"mingw32" -> firstJustM $
flip map ["ProgramFiles", "ProgramFiles(x86)", "ProgramW6432"] $ \env ->
lookupEnv env >>= \var -> case var of
Nothing -> return Nothing
Just pf
-> fmap (\im -> pf </> im </> cmd)
. listToMaybe
. filter ("ImageMagick" `isPrefixOf`)
<$> getDirectoryContents pf
_ -> return Nothing
imageMagick' :: String -> IO String
imageMagick' cmd = imageMagick cmd >>= \ms -> case ms of
Nothing -> error $ "imageMagick': couldn't find program " ++ cmd
Just s -> return s
firstJustM :: (Monad m) => [m (Maybe a)] -> m (Maybe a)
firstJustM [] = return Nothing
firstJustM (mx : xs) = mx >>= \x -> case x of
Nothing -> firstJustM xs
Just y -> return $ Just y
connectVertical :: [FilePath] -> TempIO FilePath
connectVertical [fin] = return fin
connectVertical fins = do
cmd <- liftIO $ imageMagick' "montage"
fout <- newTempFile "connectVertical.png"
void $ liftIO $ readProcess cmd
(["-geometry", "100%", "-tile", "1x"] ++ fins ++ [fout]) ""
return fout
splitVertical :: Integer -> FilePath -> TempIO [FilePath]
splitVertical i fin = do
cmd <- liftIO $ imageMagick' "convert"
tempdir <- ask
splitdir <- liftIO $ createTempDirectory tempdir "splitVertical"
void $ liftIO $
readProcess cmd ["-crop", "x" ++ show i, fin, splitdir </> "x.png"] ""
map (splitdir </>) . sortBy (comparing getNumber) . filter isFile
<$> liftIO (getDirectoryContents splitdir)
where getNumber :: String -> Integer
getNumber = read . takeWhile isDigit . dropWhile (not . isDigit)
isFile = (`notElem` [".", ".."])
joinPages :: [FilePath] -> TempIO FilePath
joinPages fins = do
cmd <- liftIO $ imageMagick' "convert"
fout <- newTempFile "joinPages.pdf"
void $ liftIO $ readProcess cmd (fins ++ [fout]) ""
return fout