packages feed

JuicyPixels-blp-1.0.0.0: blp2any/Statistics.hs

module Statistics(
    collectSamples 
  , printStatistics
  , collectStatistics
  ) where

import Codec.Picture.Blp.Internal.Data
import Codec.Picture.Blp (BlpVersion(..), displayBlpDecodeError)
import Codec.Picture.Blp.Internal.Parser
import Control.Monad
import Data.Char (toLower)
import Data.Word 
import System.Directory
import System.FilePath
import System.IO

import qualified Data.ByteString as BS
import qualified Data.Map.Strict as M
import qualified Data.List as L 

import File 

-- | What files are grouped by: version, content type and the header fields
-- that vary between files, with their names.
data BlpInfo = BlpInfo BlpVersion BlpCompression [(String, Word32)]
  deriving (Eq, Ord)

type BlpStat = (FilePath, Int)

type StatMap = M.Map BlpInfo BlpStat

collectSamples :: FilePath -> IO StatMap
collectSamples dir = do 
  f <- doesDirectoryExist dir
  unless f $ fail $ "Provided directory " ++ dir ++ " doesn't exists!"
  forEachFile True dir ((".blp" ==) . map toLower . takeExtension) collectSample M.empty

collectSample :: StatMap -> FilePath -> IO StatMap
collectSample stats inputFile = do
  putStrLn $ "Sampling " ++ inputFile
  result <- tryAll (either (Left . displayBlpDecodeError) Right . parseBlpFile <$> BS.readFile inputFile)
  case join result of
    Left err -> do
      -- One unreadable file should not lose the statistics of the rest.
      hPutStrLn stderr $ inputFile ++ ": skipped, " ++ err
      return stats
    Right blp -> return $ adjust' (updateStat inputFile) (blpType blp) stats

blpType :: BlpFile -> BlpInfo
blpType (BlpFile1 blp@BlpStruct{..}) = BlpInfo Blp1 (blpCompression blp)
  [("alpha", blpAlphaBits), ("extra", blpExtra), ("mips", blpHasMipmaps)]
blpType (BlpFile2 blp@Blp2Struct{..}) = BlpInfo Blp2 (blp2Compression blp)
  [("alpha", fromIntegral blp2AlphaDepth), ("alphaType", fromIntegral blp2AlphaType), ("mips", fromIntegral blp2HasMips)]

adjust' :: (Maybe BlpStat -> BlpStat) -> BlpInfo -> StatMap -> StatMap 
adjust' f k m = M.insert k (f $ M.lookup k m) m

updateStat :: FilePath -> Maybe BlpStat -> BlpStat 
updateStat path Nothing = (path, 1)
updateStat _ (Just (p, i)) = (p, i+1)

printStatistics :: FilePath -> StatMap -> IO () 
printStatistics dir stats = do
    createDirectoryIfMissing True dir
    forM_ (M.toList stats) $ \(BlpInfo version compression fields, (path, i)) -> do
      let postfix = L.intercalate "-" $ [show version | version /= Blp1] ++ show compression : [name ++ show v | (name, v) <- fields]
      copyFile path $ dir </> dropExtension (takeFileName path) ++ "-" ++ postfix ++ ".blp"
      putStrLn $ postfix ++ ": " ++ show i ++ " images"

collectStatistics :: FilePath -> FilePath -> IO ()
collectStatistics dir outputDir = printStatistics outputDir =<< collectSamples dir