diff --git a/Graphics/Filters/GD.hs b/Graphics/Filters/GD.hs
new file mode 100644
--- /dev/null
+++ b/Graphics/Filters/GD.hs
@@ -0,0 +1,193 @@
+module Graphics.Filters.GD 
+( 
+    -- * Filters
+    brightness
+    , colorize
+    , contrast
+    , gaussianBlur
+    , grayscale
+    , edgeDetect
+    , emboss
+    , meanRemoval
+    , negative
+    , smoothing
+    -- * Pixel transformation functions
+    , pixelTransform
+    , convolute
+) where
+    
+import Graphics.GD
+import Graphics.Filters.Util
+import Control.Monad (mapM_,foldM)
+
+{- |
+    Performs the supplied transform function on every pixel of the image.
+    The transform function should take as it's argument a quadruple of Ints (RGBA) and returns a new RGBA quadruple
+    which is will be the new RGBA values of the the pixel.
+
+    For example, the 'colorize' filter's inner workings are implemented with this as the transform function:
+
+    @
+      (\\(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))
+    @
+-}
+pixelTransform ::    Image 
+                    -> ( RGBA -> RGBA ) -- ^ Transform function to be performed on each pixel
+                    -> 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..(width-1)]
+        ) [0..(height-1)] 
+    return ()
+
+{- |
+    Performs the convolution matrix on each pixel of the original image.
+    After the matrix has been applied, the resulting RGBA value has each of it's elements divided by the Divisor argument
+    and then the Offset argument is added to each element
+
+    For example, the 'emboss' filter is implemented with the following convolution:
+
+    >   emboss img = convolute img [[1.5,0.0,0.0],[0.0,0.0,0.0],[0.0,0.0,-1.5]] 1 127
+-}
+convolute ::    Image 
+                -> [[Float]]    -- ^ Convolution matrix
+                -> Float        -- ^ Divisor
+                -> Float        -- ^ Offset
+                -> 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..(width-1)]
+        ) [0..(height-1)] 
+    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 (y-1) 0)
+        (pr,pg,pb,pa) <- foldM (\(ar,ag,ab,aa) k -> do
+                        let xx = min (max (x-(1+k)) 0) (max (x-1) 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
+
+{- |
+    Applies the supplied color transformation to the image.
+    The range of the passed RGB values are -255 to +255, and the range of the A value is -127 to +127.
+-}
+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))
+
+{- |
+    Inverts the image's color.
+-}
+negative :: Image -> IO ()
+negative img =
+    pixelTransform img (\(r,g,b,a) -> let
+            nr = abs 255-r
+            ng = abs 255-g
+            nb = abs 255-b
+        in (nr,ng,nb,a))
+
+{- |
+    Converts an image to grayscale
+-}
+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))        
+
+{- |
+    Applies the supplied contrast adjustment to the image. 
+    The range of the contrast argument is -100 to +100, with
+    -100 being maximum contrast, and +100 being minimum contrast
+-}
+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 $ ur-0.5
+                ng = clamp 0 255 $ (*) 255 . (+) 0.5 . (*) contr $ ug-0.5
+                nb = clamp 0 255 $ (*) 255 . (+) 0.5 . (*) contr $ ub-0.5
+            in (truncate nr, truncate ng, truncate nb, a))
+
+{- |
+    Applies the supplied brightness adjustment to the image.
+    The range of the brightness argument is -255 to +255
+-}
+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)
+
+{- |
+    Applies Gaussian blur to the image
+-}
+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
+
+{- |
+    Applies an Emboss effect to the image
+-}
+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
+
+{- | 
+    Applies Edge Detection to the image
+-}
+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
+
+{- |
+    Applies a Mean Removal effect to the image
+-}
+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
+
+{- |
+    Applies weighted Smoothing to the image. The smoothing amount is technically unbounded, 
+    but larger values produce a less noticeable result
+-}
+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
diff --git a/Graphics/Filters/Util.hs b/Graphics/Filters/Util.hs
new file mode 100644
--- /dev/null
+++ b/Graphics/Filters/Util.hs
@@ -0,0 +1,19 @@
+module Graphics.Filters.Util where
+
+type RGBA = (Int,Int,Int,Int)
+
+-- | Utility function for clamping a value between a minimum and maximum value
+clamp :: (Ord a, Num a) =>  a       -- ^ Minimum
+                            -> a    -- ^ Maximum
+                            -> a    -- ^ Value to clamp
+                            -> a
+clamp minm maxm num 
+	| num < minm = minm
+	| num > maxm = maxm
+	| otherwise = num
+
+-- | Function for converting RGBA from an Int 0-255 range to a Float 0.0-1.0 range 
+normalizeRGBA :: RGBA -> (Float,Float,Float,Float)
+normalizeRGBA (r,g,b,a) = (fromIntegral r/255,fromIntegral g/255,fromIntegral b/255,fromIntegral a/127)
+
+
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright (c)2012, Tim Channell
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+
+    * Neither the name of Tim Channell nor the names of other
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/imagefilters.cabal b/imagefilters.cabal
new file mode 100644
--- /dev/null
+++ b/imagefilters.cabal
@@ -0,0 +1,24 @@
+Name:                imagefilters
+Version:             0.1
+Synopsis:            Image Filters (contrast, brightness, gaussian blur, etc)
+Description:         
+    This package brings image filters comparable to PHP's imagefilter functions. In the current release,
+    these filters may only be used with the GD Haskell extension library, but in the future it may support
+    other image management libraries, such as the new JuicyPixels library.
+    .
+    imagefilters also supplies functionality for creating custom filters by using the 'pixelTransform' function
+    for per-pixel transformations, or the 'convolute' function for the application of convolution matrices
+
+Homepage:            https://github.com/tchannel/imagefilters
+License:             BSD3
+License-file:        LICENSE
+Author:              Tim Channell
+Maintainer:          tim.channell@gmail.com
+Category:            Graphics
+Build-type:          Simple
+Cabal-version:       >=1.2
+
+Library
+  Exposed-modules:     Graphics.Filters.Util, Graphics.Filters.GD  
+  Build-depends: base >= 4 && < 5, gd >= 3000      
+
