diff --git a/README.md b/README.md index 0851e89..c35f8a8 100644 --- a/README.md +++ b/README.md @@ -3,9 +3,13 @@ Image to ASCII-Converter # build instructions -execute `stack build`. Result is then in your `.stack-work/dist/$system/$cabal/build/img2ascii/` folder. Replace `$system` and `$cabal` according to your installation. +Execute `stack build`. Result is then in your `.stack-work/dist/$system/$cabal/build/img2ascii/` folder. Replace `$system` and `$cabal` according to your installation. -Trhee example images in the resolution of 225x65, 225x65 and 100x40 are included. To view them just type `cat image1.img` in a suitable (aka TrueColor) terminal. +Alternatively you can install the program with `stack install` to `~/.local/img2ascii` or for all users (if `stack install` is invoked as root). + +Three true-color example images in the resolution of 225x65, 225x65 and 100x40 are included. To view them just type `cat image1.img` in a suitable (aka TrueColor) terminal. + +One 256-color example is also included. Type `cat rose_256.img` to view that. # example diff --git a/rose_256.img b/rose_256.img new file mode 100644 index 0000000..1c073d3 --- /dev/null +++ b/rose_256.img @@ -0,0 +1,40 @@ +                                                                                                     +                                                                                                     +                                                                                                     +                                                                                                     +                                                                                                     +                                                                                                     +                                                               ooo.                                  +                                                           oo oooooo                                 +                                  oox                   ooooooooooooo                                +                                 xxoooooooo.   oooooooooooooooooooooooo                              +                                 ooooooooooooooooooooooooooooooooooooooo .                           +                                 oooooooooooooooooxoooooooooooooooooooooooo                          +                                oooooooooooooooooooooooooooooooooooooooooooooooooo                   +                               oooooooooooooxxoooooooooxxoooooxooooooooooooooooox.                   +                               ooooooooooooooooooooxxxoooooooooxoooooooooooooooxx                    +                              ooooooooooooxoooxxxxxooxxxxxoooooooooxooooooooooxx                     +                            .ooooooooooooxxoooxxxooxooxxxooooooxooooooooooooooxx                     +                          oooooooooooooooooooxoooxxooxxxooxooooooooooxoooooooxxx                     +                  .xooooooooooooooooooooooooooooooooooooooooooooooooxxooooooooxx                     +                    xxxxooooooooooooooooooooooooooooooxxxxoooxoooooo.xooooooooox                     +                     xxxooooooooooooooooooooooxooooxxxxoooooxoooooox xoooooooooo                     +                      xxxxoooooooooooooooooooooooooooooooxooooooox.  ooooooxxoo                      +                      .xooooooooooooooooooooooooooxoooxoooooooooxxxxoooooxxx.                        +                       xxxxxooooooxooooooxx.oooooooxooooooooxxxxxxooooooxxxx                         +                       xxxoxxxoooooxxoooooooxxxxxxxooox.xxxxooooooooooxxxxx                          +                       xxxxxxxxxxoooxxxxxxxxoooooooooooooooooooxxoooxxxxx.                           +                       xx..xxxxxxxxoxxxooooooooooooooooooooxxx..oooxxx..                             +                            xxxxxxxxxx.xxxxxxxxxxx...xxxx......xoxxx..                               +                            xxxxx.xxxxxx.........        ......xxx..                                 +                            ooooooooxxxxxx.........     .xx......                                    +                            oooooooooooxxx...        .........                                       +                           ooooooooooooooooooxx.......x....x..                                       +                          oooooooooooooooooooooooooxx.......                                         +                         ooxxxxxxxxxxxxxoooooooooooooo....                                           +                            x...xxxxxxxxxxxxxxoooooxxxx.                                             +                                 ...........xxxxooxxx.                                               +                                               .xox                                                  +                                                                                                     +                                                                                                     +                                                                                                     diff --git a/src/Main.hs b/src/Main.hs index 3e98ed5..b38c3cb 100644 --- a/src/Main.hs +++ b/src/Main.hs @@ -4,7 +4,7 @@ import Codec.Picture import Codec.Picture.Types import Data.Maybe (fromJust) import Data.Word (Word8) -import Data.List (transpose) +import Data.List as L (transpose,foldl') import Text.Printf (printf) import Control.Arrow ((&&&)) import Options.Applicative @@ -14,15 +14,17 @@ import System.IO (stdin) data Options = Options { srcFile :: String - , width :: Int - , height :: Int + , width :: Int + , height :: Int + , trueColor :: Bool } options :: Parser Options options = Options <$> argument str (metavar "SRC" <> help "source file (or - for stdin)") <*> argument auto (metavar "WIDTH" <> help "resulting width") - <*> argument auto (metavar "HEIGH" <> help "resulting height") + <*> argument auto (metavar "HEIGHT" <> help "resulting height") + <*> switch (long "256-colors" <> short 'c' <> help "only use 256-color-mode for old terminals") opthelp :: ParserInfo Options opthelp = info (helper <*> options) @@ -35,7 +37,7 @@ main :: IO () main = execParser opthelp >>= run run :: Options -> IO () -run (Options src w h) = do +run (Options src w h redcol) = do src' <- if src == "-" then B.getContents else B.readFile src case decodeImage src' of Left err -> putStrLn err @@ -43,7 +45,7 @@ run (Options src w h) = do case extractDynImage img >>= pixelize w h of Nothing -> return () Just (f,b) -> - let str = img2ascii conv (f,b) + let str = if redcol then img2ascii conv256 (f,b) else img2ascii conv (f,b) in mapM_ (\x -> putStr x >> putStrLn "\x1b[0m") (concat <$> str) chunksof :: Int -> [a] -> [[a]] @@ -55,12 +57,30 @@ conv (fp@(PixelRGB8 fr fg fb),PixelRGB8 br bg bb) = printf "\x1b[48;2;%d;%d;%dm\ where lumi :: Word8 -> Char lumi x - | x > 225 = '@' - | x > 180 = 'O' - | x > 150 = 'X' - | x > 50 = 'o' - | x > 25 = 'x' - | x > 10 = '.' + | x > 225 = '@' + | x > 180 = 'O' + | x > 150 = 'X' + | x > 50 = 'o' + | x > 25 = 'x' + | x > 10 = '.' + | otherwise = ' ' + +conv256 :: (PixelRGB8,PixelRGB8) -> String +conv256 (fp@(PixelRGB8 fr fg fb),PixelRGB8 br bg bb) = printf "\x1b[48;5;%dm\x1b[38;5;%dm%c" bcolor fcolor (lumi.computeLuma $ fp) + where + -- converts [0..255] -> [0..5] + s = (`div` 51) + -- conversion: 6x6x6 rgb-cube so color is red * 36 + green * 6 + blue + 16 offset with red/green/blue in [0..5] + bcolor = s br * 36 + s bg * 6 + s bb + 16 + fcolor = s fr * 36 + s fg * 6 + s fb + 16 + lumi :: Word8 -> Char + lumi x + | x > 225 = '@' + | x > 180 = 'O' + | x > 150 = 'X' + | x > 50 = 'o' + | x > 25 = 'x' + | x > 10 = '.' | otherwise = ' ' img2ascii :: ((PixelRGB8,PixelRGB8) -> String) -> (Image PixelRGB8,Image PixelRGB8) -> [[String]] @@ -77,16 +97,17 @@ pixelize tw th im@(Image iw ih id) = windowh = fromIntegral ih / fromIntegral th folder :: ((PixelRGB8, Int, Int) -> (PixelRGB8, Int, Int) -> (PixelRGB8, Int, Int)) -> Double -> Double -> Image PixelRGB8 -> Int -> Int -> (Image PixelRGB8, PixelRGB8) -folder f ww wh im@(Image iw ih id) x y = (im,(\(a,_,_) -> a) $ foldl1 f +folder f ww wh im@(Image iw ih id) x y = (im,(\(a,_,_) -> a) $ L.foldl' f (pixelAt im x' y',0,0) [ (pixelAt im (x'+dx) (y'+dy),dx,dy) - | dx <- [-(floor $ ww / 2)..(floor $ ww*0.5)] - , dy <- [-(floor $ ww / 2)..(floor $ ww*0.5)] + | dx <- [-dw..dw] + , dy <- [-dw..dw] , x'+dx > 0 && x'+dx < iw , y'+dy > 0 && y'+dy < ih ]) where - x' = floor $ fromIntegral x *ww - y' = floor $ fromIntegral y *wh + dw = floor $ ww + x' = floor $ fromIntegral x * ww + y' = floor $ fromIntegral y * wh filterfun :: (PixelRGB8,Int,Int) -> (PixelRGB8, Int, Int) -> (PixelRGB8,Int,Int) filterfun (x@(PixelRGB8 r g b),_,_) (y@(PixelRGB8 r' g' b'),_,_) = if computeLuma x > computeLuma y then (x,0,0) else (y,0,0)