pixelated-avatar-generator 0.1.2 → 0.1.3
raw patch · 5 files changed
+113/−56 lines, 5 filesdep +asyncdep +clidep +randomPVP ok
version bump matches the API change (PVP)
Dependencies added: async, cli, random
API changes (from Hackage documentation)
Files
- CHANGELOG.md +5/−0
- README.md +18/−23
- app/Main.hs +78/−24
- pixelated-avatar-generator.cabal +4/−1
- src/Graphics/Avatars/Pixelated.hs +8/−8
CHANGELOG.md view
@@ -1,5 +1,10 @@ # Changelog +## 0.1.3+* Create new executable program.+* Make several small internal fixes.+* Add badges for Hackage and Stackage to readme.+ ## 0.1.2 * Add missing test files to Cabal config, to allow tests to pass from Hackage package.
README.md view
@@ -1,4 +1,4 @@-# Pixelated Avatar Generator [](https://travis-ci.org/ExcaliburZero/pixelated-avatar-generator) [](https://coveralls.io/github/ExcaliburZero/pixelated-avatar-generator?branch=master)+# Pixelated Avatar Generator [](https://travis-ci.org/ExcaliburZero/pixelated-avatar-generator) [](https://coveralls.io/github/ExcaliburZero/pixelated-avatar-generator?branch=master) [](https://hackage.haskell.org/package/pixelated-avatar-generator) [](http://stackage.org/nightly/package/pixelated-avatar-generator) Pixelated Avatar Generator is a Haskell library and application for generating pixelated avatar images from seed values. ```haskell@@ -33,41 +33,36 @@ ``` ## Executable-An example executable program that uses the library is also provided. It creates an avatar from a given seed string and saves the created `.png` image to a given file location.+An executable program for generating avatar image files is also provided. It can generate several avatar images concurrently to given file locations. -The executable can be compiled by running the following command:+The executable can be installed along with the library by running the following command: ```-$ stack build+$ stack install pixelated-avatar-generator ``` -The executable can then by run by running it with `stack exec` and providing it the desired filepath of the output file including the `.png` extension and a random seed string.+The executable can then by run by calling it with the desired filepath(s) of the output file(s) including the `.png` extension. ```-$ stack exec pixelated-avatar-generator image.png "Hello, World"-Creating avatar at image.png-Grey-█ ████ █- - ████ -█ ██ █-████████-█ █ █ █-█ █-████████-Successfully created avatar, and saved it to image.png+$ pixelated-avatar-generator image1.png image2.png+Successfully created 2 avatars. ``` +By default, the avatars are at a size of 256x256px. Though the size can be changed by using a custom scaling factor via the `--scaling-factor` flag.+ ### Usage ```-Usage: pixelated-avatar-generator FILEPATH SEEDSTRING+Usage: pixelated-avatar-generator FILEPATH_1 [FILEPATH_2] [FILEPATH_3] ... -FILEPATH -- The location to save the generated avatar at. "img/test.png"-SEEDSTRING -- The string to use to generate the avatar. "Hello"-```+FILEPATH_(1...) -- The locations to save generated avatars at. "img/test.png" -## Links-* [Pixelated Avatar Generator package on Hackage](https://hackage.haskell.org/package/pixelated-avatar-generator)+Options:++ --scaling-factor+ Use a custom scaling factor. The scaling factor is multiplied by 8 to+ get the dimensions of the image. For example, a scaling factor of 4+ would yield a 32x32px image. The default scaling factor is 32.+``` ## License The source code of Pixelated Avatar Generator is available under the [MIT license](https://opensource.org/licenses/MIT), see `LICENSE` for more information.
app/Main.hs view
@@ -1,35 +1,89 @@ module Main where +import Console.Options+import Control.Concurrent.Async (mapConcurrently)+import Data.Char (isDigit)+import Data.List (nub)+import Data.Maybe (fromMaybe)+import Data.Monoid ((<>))+import Data.Version (makeVersion) import Graphics.Avatars.Pixelated-import System.Environment (getArgs)+import System.Random (randomIO) main :: IO ()-main = do- args <- getArgs- checkForProperArgs args- let path = head args- let seedString = args !! 1- putStrLn $ "Creating avatar at " ++ path- createAndSaveAvatar path seedString- putStrLn $ "Successfully created avatar, and saved it to " ++ path+main = defaultMain $ do+ -- Define program information+ programName "pixelated-avatar-generator"+ programDescription "Generates pixelated avatar images"+ programVersion $ makeVersion [0,1,2] -checkForProperArgs :: [String] -> IO ()-checkForProperArgs args = if length args /= 2- then error $ "Improper number of arguments.\n\n" ++ usageInfo- else return ()+ -- Gather program flags and arguments+ flagS <- flagParam+ (FlagLong "scaling-factor" <> FlagDescription scalingFlagDescription)+ (FlagRequired scaleParser)+ firstFile <- argument "FILEPATH" Right+ tailFiles <- remainingArguments "FILEPATHS" -usageInfo :: String-usageInfo = unlines [- "Usage: pixelated-avatar-generator FILEPATH SEEDSTRING"- , ""- , "FILEPATH -- The location to save the generated avatar at. \"img/test.png\""- , "SEEDSTRING -- The string to use to generate the avatar. \"Hello\""+ -- Perform the functionality of the program+ action $ \toParam -> do+ let scalingFactor = fromMaybe defaultScalingFactor (toParam flagS)+ let paths = nub $ toParam firstFile : toParam tailFiles+ _ <- mapConcurrently (saveRandomAvatar scalingFactor) paths+ putStrLn $ createSuccessMessage paths++-- | The default avatar scaling factor that is used when the user does not+-- specify a custom scaling factor via the "--scaling-factor" flag.+defaultScalingFactor :: Int+defaultScalingFactor = 32++-- | The description of the "--scaling-factor" flag.+scalingFlagDescription :: String+scalingFlagDescription = unwords+ [ "Use a custom scaling factor. The scaling factor is multiplied by 8 to get"+ , "the dimensions of the image. For example, a scaling factor of 4 would"+ , "yield a 32x32px image. The default scaling factor is 32." ] -createAndSaveAvatar :: FilePath -> String -> IO ()-createAndSaveAvatar path s = do- let seed = createSeed s+-- | Prints a success message noting the number of images created.+--+-- >>> createSuccessMessage ["1.png", "2.png"]+-- "Successfully created 2 avatars."+createSuccessMessage :: [FilePath] -> String+createSuccessMessage paths = message+ where+ message = unwords ["Successfully created", numberOfAvatars, "avatars."]+ numberOfAvatars = (show . length) paths++-- | Creates and saves a random avatar at the given filepath using the given+-- scaling factor.+saveRandomAvatar :: Int -> FilePath -> IO ()+saveRandomAvatar factor path = do+ seed <- show <$> (randomIO :: IO Double)+ saveCustomAvatar factor path seed++-- | Creates and saves an avatar at the given filepath using the given seed+-- string and the given scaling factor.+saveCustomAvatar :: Int -> FilePath -> String -> IO ()+saveCustomAvatar factor path string = do+ let seed = createSeed string let avatar = generateAvatar seed- print avatar- let avatarScaled = scaleAvatar 32 avatar+ let avatarScaled = scaleAvatar factor avatar saveAvatar avatarScaled path++-- | Attempts to parse a scaling factor, which must be a non-positive integer+-- (1, 2, 3, ...).+--+-- >>> scaleParser "1"+-- Right 1+-- >>> scaleParser "0"+-- Left "The given String is not a positive integer"+-- >>> scaleParser "-1"+-- Left "The given String is not a positive integer"+scaleParser :: String -> Either String Int+scaleParser string+ | isPosInt string = Right ((read :: String -> Int) string)+ | otherwise = Left "The given String is not a positive integer"+ where+ isPosInt s = isNaturalNum s && isNotZero s+ isNaturalNum = all isDigit+ isNotZero s = not $ all (== '0') s
pixelated-avatar-generator.cabal view
@@ -1,5 +1,5 @@ name: pixelated-avatar-generator-version: 0.1.2+version: 0.1.3 synopsis: A library and application for generating pixelated avatars. description: <<data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAA1AAAACABAMAAAD345WwAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4AcREioaDb4fhAAAABVQTFRFKSkpaLb/lpaW0JT//4xB/+eU////Sm1svwAAAeBJREFUeNrt2bFxwzAQBEC2oBbUglpwC2zB/ZfgRHbwMzf/oKUAmr0M4IHg/IY87iXfz6zu13w1SefOZ9J62nuE1PdMezVHSde//TMHKFCgQIECBQoUKFCgQIECBQoUKFCgQIECBQrUh0GlpP4UZNpLEFPIlFWQCtNBJbg6+NV9UKBAgQIFChQoUKBAgQIFChQoUKBAgQIFChSo3aGmH1zBKkAHknod0BQywXRQHdyxmPSeVai/+0GBAgUKFChQoECBAgUKFChQoECBAgUKFChQoDaF6gC6/ZoOKIEliA6qA7qaV0N1QB0YKFCgQIECBQoUKFCgQIECBQoUKFCgQIECBQrUrlD3kg4i9evgp0B1XQd/NknnusF3sB3U6vMENu2BAgUKFChQoECBAgUKFChQoECBAgUKFChQoEB9CtRq6gV18Cmp1wFMe1OgBFYBrsLVwV8NKFCgQIECBQoUKFCgQIECBQoUKFCgQIECBQrU7lD1og4k7SeQKeBZcrX/CEkw7/5x+DvwtO56oECBAgUKFChQoECBAgUKFChQoECBAgUKFChQu0JNAVZhOqjpj8MpYAfbQaVzdfBHk3TuFpKgakCBAgUKFChQoECBAgUKFChQoECBAgUKFChQoDaF+gF8d9lnmZmUZAAAAABJRU5ErkJggg==>>@@ -44,6 +44,9 @@ ghc-options: -threaded -rtsopts -with-rtsopts=-N -Wall build-depends: base , pixelated-avatar-generator+ , cli >= 0.1.2+ , random >= 1.0.0.2+ , async >= 2.0.2 default-language: Haskell2010 test-suite unit-tests
src/Graphics/Avatars/Pixelated.hs view
@@ -62,9 +62,9 @@ import Codec.Picture (encodeColorReducedGifImage, encodePng, encodeTiff, generateImage, Image(..), PixelRGB8(..)) import Data.Char (ord) import qualified Data.ByteString.Lazy as B (ByteString, writeFile)-import Data.ByteString.Lazy.Internal (packChars) import Data.Digest.Pure.MD5 (md5) import Data.List.Split (chunksOf)+import Data.String (fromString) ------------------------------------------------------------------------------- -- Seeds@@ -81,7 +81,7 @@ -- >>> createSeed "Hello" -- Seed {unSeed = "8b1a9953c4611296a827abf8c47804d7"} createSeed :: String -> Seed-createSeed = Seed . show . md5 . packChars+createSeed = Seed . show . md5 . fromString ------------------------------------------------------------------------------- -- Avatars@@ -100,7 +100,7 @@ -- | Generates a String containing the color and pattern of the avatar. instance Show Avatar where- show a = (show . color) a ++ "\n" ++ ((show . grid) a)+ show a = (show . color) a ++ "\n" ++ (show . grid) a -- | Generates an avatar from the given seed. --@@ -129,7 +129,7 @@ -- into a 32x32px avatar. scaleAvatar :: Int -> Avatar -> Avatar scaleAvatar factor avatar = avatar { grid = AvatarGrid scaledGrid }- where scaledGrid = ((scaleList factor) . (map (scaleList factor))) unscaledGrid+ where scaledGrid = (scaleList factor . map (scaleList factor)) unscaledGrid unscaledGrid = unAvatarGrid $ grid avatar -- | Saves the given avatar as a png image file to the given file path. The@@ -238,14 +238,14 @@ -- | Converts the grid into a String representation. instance Show AvatarGrid where- show x = (showGrid . unAvatarGrid) x+ show = showGrid . unAvatarGrid -- | The left half of an AvatarGrid. newtype AvatarGridSide = AvatarGridSide { unAvatarGridSide :: [[Bool]] } -- | Converts the grid side into a String representation. instance Show AvatarGridSide where- show x = (showGrid . unAvatarGridSide) x+ show = showGrid . unAvatarGridSide -- | Converts a grid of boolean values into a String representation. --@@ -285,7 +285,7 @@ -- y-axis. mirrorGrid :: AvatarGridSide -> AvatarGrid mirrorGrid side = AvatarGrid $ map mirror $ unAvatarGridSide side- where mirror l = l ++ (reverse l)+ where mirror l = l ++ reverse l -- | Generates the right side of an AvatarGrid using the given seed. generateAvatarGridSide :: Seed -> AvatarGridSide@@ -294,7 +294,7 @@ -- | Converts the given hexidecimal number String into a grid of boolean values. numToGrid :: String -> [[Bool]] numToGrid s = boolGrid- where boolGrid = (map . map) convertToPixel $ (map . map) ord numGrid+ where boolGrid = (map . map) (convertToPixel . ord) numGrid numGrid = chunksOf 4 s convertToPixel = (> ord '7')