picedit 0.1.0.0 → 0.1.1.0
raw patch · 3 files changed
+43/−21 lines, 3 files
Files
- app/Main.hs +12/−7
- picedit.cabal +1/−1
- src/Data/Picture.hs +30/−13
app/Main.hs view
@@ -11,6 +11,7 @@ , argContrast :: Double , argGamma :: Int , argBrightness :: Double+ , argCompress :: Int } opts = Options { file = ""@@ -22,6 +23,7 @@ , argContrast = 0 , argGamma = 1 , argBrightness = 0+ , argCompress = 0 } main :: IO ()@@ -39,6 +41,7 @@ putStrLn " --rotate <n> - rotate image by n degrees" putStrLn " --grayscale - turn the image grayscale" putStrLn " --invert - invert (negative) the image"+ putStrLn " --compress <n> - approximate the (width - n)-th rank of image using SVD, note: this is not size compression, a number between 0 (no compression) and image width (full compression)" putStrLn " --output <filename> - output name, defaults to output.png" else do let options = parseArgs args opts@@ -49,13 +52,14 @@ Left err -> print err Right p -> do let edited = rotate (argRotate options) Nothing - . fade (argFade options / 100)- . contrast (argContrast options)- . gamma (argGamma options)- . brightness (argBrightness options)- . conditionalFn grayscale (argGrayscale options) - . conditionalFn invert (argInvert options) $ p- writePicturePng "output.png" edited+ . fade (argFade options / 100)+ . contrast (argContrast options)+ . gamma (argGamma options)+ . brightness (argBrightness options)+ . conditionalFn grayscale (argGrayscale options) + . conditionalFn invert (argInvert options)+ . compress (argCompress options) $ p+ writePicturePng (output options) edited return () @@ -72,6 +76,7 @@ parseArgs ("--contrast":n:rest) opts = parseArgs rest (opts { argContrast = read n }) parseArgs ("--brightness":n:rest) opts = parseArgs rest (opts { argBrightness = read n }) parseArgs ("--gamma":n:rest) opts = parseArgs rest (opts { argGamma = read n })+ parseArgs ("--compress":n:rest) opts = parseArgs rest (opts { argCompress = read n }) parseArgs ("--output":n:rest) opts = parseArgs rest (opts { output = n }) parseArgs (name:rest) opts = parseArgs rest (opts { file = name })
picedit.cabal view
@@ -1,5 +1,5 @@ name: picedit-version: 0.1.0.0+version: 0.1.1.0 synopsis: simple image manipulation functions description: Simple set of functions for image manipulation: contrast, brightnesss, rotation, etc. homepage: https://github.com/mdibaiee/picedit#readme
src/Data/Picture.hs view
@@ -3,25 +3,30 @@ {-# LANGUAGE TypeFamilies #-} {-|-Module : Picture-Description : manipulation functions+Module : Data.Picture+Description : picture manipulation functions Copyright : (c) Mahdi Dibaiee, 2016 License : GPL-3 Maintainer : mdibaiee@aol.com Stability : experimental Portability : POSIX -}-module Data.Picture ( grayscale- , readPicture- , fromImage- , toImage- , writePicturePng+module Data.Picture ( Picture+ -- * Manipulation functions+ , grayscale , fade , rotate , contrast , brightness , gamma , invert+ , compress+ -- * Converting between Image and Picture+ , fromImage+ , toImage+ -- * IO operations+ , readPicture+ , writePicturePng ) where @@ -30,11 +35,12 @@ import qualified Data.Vector.Storable as V import System.IO import Data.Maybe+ import Debug.Trace - -- | 'Picture' type is just a triple of color channel matrices: (R, G, B)+ -- | (R, G, B) color channels type Picture = (Matrix Double, Matrix Double, Matrix Double) - -- |Converts a JuicyPixel 'Image PixelRGB8' to 'Picture'+ -- | Converts a JuicyPixel 'Image PixelRGB8' to 'Picture' fromImage :: Image PixelRGB8 -> Picture fromImage Image { imageWidth = w, imageHeight = h, imageData = vec } = let [r, g, b] = map (reshape w . V.fromList . reverse) (snd $ V.foldl' gp (0, [[],[],[]]) (V.map fromIntegral vec))@@ -46,7 +52,7 @@ (1, [r, g, b]) -> (2, [r, x:g, b]) (2, [r, g, b]) -> (0, [r, g, x:b]) - -- |Converts a 'Picture' to JuicyPixel 'Image PixelRGB8'+ -- | Converts a 'Picture' to JuicyPixel 'Image PixelRGB8' toImage :: Picture -> Image PixelRGB8 toImage (r, g, b) = let (fr, fg, fb) = (toList $ flatten r, toList $ flatten g, toList $ flatten b)@@ -104,9 +110,8 @@ where f = cmap (`subtract` 255) - {- | Rotate 'Picture' for the specified degrees, around the specified origin.- - If the origin is `Nothing`, rotates around the center- -}+ -- | Rotate 'Picture' for the specified degrees, around the specified origin.+ -- If the origin is `Nothing`, rotates around the center rotate :: Double -> Maybe (Int, Int) -> Picture -> Picture rotate deg orig (r, g, b) = (f r, f g, f b) where@@ -130,6 +135,18 @@ movedIndices = map (\[x, y] -> [x + originX, y + originY]) rotatedIndices f m = reshape (cols m) $ fromList $ map (\[x, y] -> if y < 0 || y >= rows r || x < 0 || x >= cols r then 255 else m `atIndex` (y, x)) movedIndices++ -- | Compress the image using SVD+ -- note: this is not size compression, it's just a k-rank approximation of the image+ compress :: Int -> Picture -> Picture+ compress rate (r, g, b) = (f r, f g, f b)+ where+ k = cols r - rate+ f m =+ let (u, s, v) = svd m+ si = diagRect 0 s (rows m) (cols m)+ (mu, ms, mv) = (u ?? (All, Take k), si ?? (Take k, Take k), (tr v) ?? (Take k, All))+ in mu <> ms <> mv bound (l, u) x = max l $ min u x pixelBound = bound (0, 255)