module Graphics.Filters.GD
(
brightness
, colorize
, contrast
, gaussianBlur
, grayscale
, edgeDetect
, emboss
, meanRemoval
, negative
, smoothing
, pixelTransform
, convolute
) where
import Graphics.GD
import Graphics.Filters.Util
import Control.Monad (mapM_,foldM)
pixelTransform :: Image
-> ( RGBA -> RGBA )
-> IO ()
pixelTransform img fx = do
(width,height) <- imageSize img
mapM_ (\y ->
mapM_ (\x -> do
curr <- getPixel (x,y) img
let
(r,g,b,a) = toRGBA curr
(nr,ng,nb,na) = fx (r,g,b,a)
setPixel (x,y) (rgba nr ng nb na) img
) [0..(width1)]
) [0..(height1)]
return ()
convolute :: Image
-> [[Float]]
-> Float
-> Float
-> IO ()
convolute img matrix fdiv offset = do
(width,height) <- imageSize img
imgCpy <- copyImage img
mapM_ (\y ->
mapM_ (\x -> convoluteImage img imgCpy matrix fdiv offset x y) [0..(width1)]
) [0..(height1)]
return ()
convoluteImage :: Image -> Image -> [[Float]] -> Float -> Float -> Int -> Int -> IO ()
convoluteImage img imgCpy matrix fdiv offset x y = do
(nr,ng,nb,na) <- foldM (\(or,og,ob,oa) j -> do
let yy = min (max (y(1+j)) 0) (max (y1) 0)
(pr,pg,pb,pa) <- foldM (\(ar,ag,ab,aa) k -> do
let xx = min (max (x(1+k)) 0) (max (x1) 0)
curr <- getPixel (xx,yy) imgCpy
let (r,g,b,a) = toRGBA curr
return (ar + fromIntegral r * ((matrix!!j)!!k)
,ag + fromIntegral g * ((matrix!!j)!!k)
,ab + fromIntegral b * ((matrix!!j)!!k)
,fromIntegral a)
) (or,og,ob,oa) [0.. (length (matrix!!j) 1)]
return (pr,pg,pb,pa)
) ((0.0,0.0,0.0,0.0) :: (Float,Float,Float,Float)) [0.. (length matrix 1)]
let
new_r = clamp 0 255 . truncate $ (nr/fdiv)+offset
new_g = clamp 0 255 . truncate $ (ng/fdiv)+offset
new_b = clamp 0 255 . truncate $ (nb/fdiv)+offset
setPixel (x,y) (rgba new_r new_g new_b (truncate na)) img
colorize :: Image -> RGBA -> IO ()
colorize img (ar,ag,ab,aa) =
if or [ar > 255, ar < (255), ag > 255, ag < (255), ab > 255, ab < (255), aa > 127, aa < (127)] then
error "Argument out of bounds. Colorize expects the color argument's RGB components to be between -255 and +255\
\ and it's A component between -127 and +127"
else
pixelTransform img (\(r,g,b,a) -> let
nr = clamp 0 255 (r+ar)
ng = clamp 0 255 (g+ag)
nb = clamp 0 255 (b+ab)
na = clamp 0 127 (a+aa)
in (nr,ng,nb,na))
negative :: Image -> IO ()
negative img =
pixelTransform img (\(r,g,b,a) -> let
nr = abs 255r
ng = abs 255g
nb = abs 255b
in (nr,ng,nb,a))
grayscale :: Image -> IO ()
grayscale img =
pixelTransform img (\(r,g,b,a) -> let
newcol = truncate $ 0.299 * fromIntegral r + 0.587 * fromIntegral g + 0.114 * fromIntegral b
in (newcol, newcol, newcol, a))
contrast :: Image -> Int -> IO ()
contrast img contVal =
if or [contVal > 100, contVal < (100)] then
error "Argument out of bounds. Contrast expects the contrast argument to be between -100 and +100"
else
pixelTransform img (\(r,g,b,a) -> let
contr = (**2) $ (100.0 fromIntegral contVal )/100.0
(ur,ug,ub,_) = normalizeRGBA (r,g,b,a)
nr = clamp 0 255 $ (*) 255 . (+) 0.5 . (*) contr $ ur0.5
ng = clamp 0 255 $ (*) 255 . (+) 0.5 . (*) contr $ ug0.5
nb = clamp 0 255 $ (*) 255 . (+) 0.5 . (*) contr $ ub0.5
in (truncate nr, truncate ng, truncate nb, a))
brightness :: Image -> Int -> IO ()
brightness img brightVal =
if or [brightVal > 255, brightVal < (255)] then
error "Argument out of bounds. Brightness expects the brightness argument to be between -255 and +255"
else
colorize img (brightVal,brightVal,brightVal,0)
gaussianBlur :: Image -> IO ()
gaussianBlur img = convolute img [[1.0,2.0,1.0],[2.0,4.0,2.0],[1.0,2.0,1.0]] 16 0
emboss :: Image -> IO ()
emboss img = convolute img [[1.5,0.0,0.0],[0.0,0.0,0.0],[0.0,0.0,1.5]] 1 127
edgeDetect :: Image -> IO ()
edgeDetect img = convolute img [[1.0,0.0,1.0],[0.0,4.0,0.0],[1.0,0.0,1.0]] 1 127
meanRemoval :: Image -> IO ()
meanRemoval img = convolute img [[1.0,1.0,1.0],[1.0,9.0,1.0],[1.0,1.0,1.0]] 1 0
smoothing :: Image -> Float -> IO ()
smoothing img weighting= convolute img [[1.0,1.0,1.0],[1.0,weighting,1.0],[1.0,1.0,1.0]] (weighting+8.0) 0