never executed always true always false
1 module HelVM.HelMA.Automata.Piet.Parser (
2 parseToRightTextIO,
3 parseRightIO,
4 ) where
5
6 import HelVM.HelMA.Automata.Piet.Color
7 import HelVM.HelMA.Automata.Piet.Coordinates
8 import HelVM.HelMA.Automata.Piet.Image
9 import HelVM.HelMA.Automata.Piet.MonadFailExtra
10
11 import HelVM.HelIO.Extra
12
13 import Control.Applicative.Tools
14 import Control.Exception
15
16 import Data.ListLike (length)
17
18 import Graphics.Imlib
19
20 import Safe (findJust)
21
22 import Prelude hiding (length)
23
24 parseToRightTextIO :: FilePath -> IO Text
25 parseToRightTextIO = showP <.> parseRightIO
26
27 parseRightIO :: FilePath -> IO ColorImage
28 parseRightIO = eitherToMonadFail <=< parseIO
29
30 parseIO :: FilePath -> ColorImageEitherIO
31 parseIO = imageFromFilePath Nothing
32
33 imageFromFilePath :: Maybe Int -> FilePath -> ColorImageEitherIO
34 imageFromFilePath codelInfo = flip (uncurry buildColorImageEitherIO) codelInfo . swap <=< loadImageWithErrorReturn
35
36 buildColorImageEitherIO :: ImlibLoadError -> ImlibImage -> Maybe Int -> ColorImageEitherIO
37 buildColorImageEitherIO ImlibLoadErrorNone img codelInfo = Right <$> imageFromImlib img codelInfo
38 buildColorImageEitherIO err _ _ = pure $ Left err
39
40 imageFromImlib :: ImlibImage -> Maybe Int -> IO ColorImage
41 imageFromImlib img = setImlibImage img . buildColorImageIO
42
43 setImlibImage :: ImlibImage -> IO a -> IO a
44 setImlibImage img = bracket_ (contextSetImage img) freeImageAndDecache
45
46 buildColorImageIO :: Maybe Int -> IO ColorImage
47 buildColorImageIO = imageFromContext <=< imageGuessCodelLength
48
49 imageGuessCodelLength :: Maybe Int -> IO Int
50 imageGuessCodelLength = maybe imageGuessCodelLengthDefault pure
51
52 imageGuessCodelLengthDefault :: IO Int
53 imageGuessCodelLengthDefault = do
54 width <- imageGetWidth
55 height <- imageGetHeight
56 rows <- mapM (\y -> mapM (`imageQueryPixel` y) [0 .. width -1]) [0 .. height-1]
57 cols <- mapM (\x -> mapM ( imageQueryPixel x) [0 .. height-1]) [0 .. width -1]
58 pure $ imageGuessCodelLengthDefault' rows cols width height
59
60 imageGuessCodelLengthDefault' :: (Eq a1, Eq a2) => [a1] -> [a2] -> Int -> Int -> Int
61 imageGuessCodelLengthDefault' rows cols width height = findJust (== 1) $ scanl gcd (gcd width height) list
62 where list = groupAndLength rows <> groupAndLength cols
63
64 groupAndLength :: Eq a => [a] -> [Int]
65 groupAndLength = length <.> group
66
67 imageFromContext :: Int -> IO ColorImage
68 imageFromContext = imageFromContextWithMax . max 1
69
70 imageFromContextWithMax :: Int -> IO ColorImage
71 imageFromContextWithMax codelLength = do
72 width <- (`div` codelLength) <$> imageGetWidth
73 height <- (`div` codelLength) <$> imageGetHeight
74 pixels <- mapM (toColors codelLength) [ (x, y) | x <- [ 0 .. width-1 ], y <- [ 0 .. height-1 ] ]
75 pure $ newImage pixels (width-1 , height-1)
76
77 toColors :: Int -> Coordinates -> IO (Coordinates , Color)
78 toColors codelLength xy = (xy , ) . toColor <$> toImlibColorIO codelLength xy
79
80 toImlibColorIO :: Int -> (Int, Int) -> IO ImlibColor
81 toImlibColorIO codelLength (x , y) = imageQueryPixel (x * codelLength) (y * codelLength)
82
83 toColor :: ImlibColor -> Color
84 toColor (ImlibColor _ r g b) = rgb2Color $ RGBColor r g b
85
86 -- | Types
87
88 type ColorImageEitherIO = IO (Either ImlibLoadError ColorImage)
89 type ColorImage = Image Color