diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,7 @@
+# Change log
+
+hakyll-images uses [Semantic Versioning][].
+The change log is available through the [releases on GitHub][].
+
+[Semantic Versioning]: http://semver.org/spec/v2.0.0.html
+[releases on GitHub]: https://github.com/githubuser/hakyll-images/releases
diff --git a/LICENSE.md b/LICENSE.md
new file mode 100644
--- /dev/null
+++ b/LICENSE.md
@@ -0,0 +1,11 @@
+Copyright 2018 Laurent P. René de Cotret
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+2. 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.
+
+3. Neither the name of the copyright holder nor the names of its 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 HOLDER 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/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,43 @@
+# hakyll-images
+
+[![Build status](https://ci.appveyor.com/api/projects/status/kf12xsgrx1l26b3y?svg=true)](https://ci.appveyor.com/project/LaurentRDC/hakyll-images)
+
+## A Haskell package containing utilities to deal with images in the context of Hakyll
+
+[Hakyll](https://hackage.haskell.org/package/hakyll) is a static website compiler library. As one of the benefits of static websites is their small size, this repository aims at providing utilities to work with images in the context of Hakyll. Example usage includes:
+
+* Re-encoding Jpeg images at a lower quality to make them much smaller;
+* Re-sizing images to fit within a certain shape
+
+## Usage
+
+`hakyll-images` is meant to be integrated within a Hakyll program. For example, to compress all Jpeg images present in your source:
+
+```haskell
+import Hakyll
+import Hakyll.Images        (compressJpgCompiler)
+
+(... omitted ...)
+
+hakyll $ do
+
+    (... omitted ...)
+
+    -- Compress all source Jpegs to a Jpeg quality of 50 (maximum of 100)
+    match "images/**.jpg" $ do
+            route idRoute
+            compile (compressJpgCompiler 50)
+
+    (... omitted ...)
+```
+
+Take a look at the [documentation](hackage.haskell.org/package/hakyll-images) for more usage examples.
+
+## Installation
+
+`hakyll-images` is available on Hackage. Using the [`cabal-install`](https://www.haskell.org/cabal/) tool:
+
+```bash
+cabal update
+cabal install hakyll-images
+```
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,7 @@
+-- This script is used to build and install your package. Typically you don't
+-- need to change it. The Cabal documentation has more information about this
+-- file: <https://www.haskell.org/cabal/users-guide/installing-packages.html>.
+import qualified Distribution.Simple
+
+main :: IO ()
+main = Distribution.Simple.defaultMain
diff --git a/hakyll-images.cabal b/hakyll-images.cabal
new file mode 100644
--- /dev/null
+++ b/hakyll-images.cabal
@@ -0,0 +1,70 @@
+cabal-version: 1.12
+
+-- This file has been generated from package.yaml by hpack version 0.30.0.
+--
+-- see: https://github.com/sol/hpack
+--
+-- hash: b554c0eda8c5af856ccb735a5ce03132b302a37ce1c444073df2c58b97e755ba
+
+name:           hakyll-images
+version:        0.0.1
+synopsis:       Hakyll utilities to work with images
+description:    hakyll-images is an add-on to the hakyll package. It adds utilities to work with images, including JPEG compression.
+category:       Web
+homepage:       https://github.com/LaurentRDC/hakyll-images#readme
+bug-reports:    https://github.com/LaurentRDC/hakyll-images/issues
+author:         Laurent P. René de Cotret
+maintainer:     Laurent P. René de Cotret
+license:        BSD3
+license-file:   LICENSE.md
+build-type:     Simple
+extra-source-files:
+    CHANGELOG.md
+    LICENSE.md
+    package.yaml
+    README.md
+    stack.yaml
+data-files:
+    tests/data/piccolo.jpg
+
+source-repository head
+  type: git
+  location: https://github.com/LaurentRDC/hakyll-images
+
+library
+  exposed-modules:
+      Hakyll.Images
+      Hakyll.Images.CompressJpg
+  other-modules:
+      Paths_hakyll_images
+  hs-source-dirs:
+      library
+  ghc-options: -Wall -Wcompat
+  build-depends:
+      JuicyPixels >3 && <4
+    , base >=4.8 && <5
+    , bytestring >=0.9 && <0.11
+    , hakyll >4
+  default-language: Haskell2010
+
+test-suite spec
+  type: exitcode-stdio-1.0
+  main-is: TestSuite.hs
+  other-modules:
+      Hakyll.Images.CompressJpg.Tests
+      Hakyll.Images
+      Hakyll.Images.CompressJpg
+      Paths_hakyll_images
+  hs-source-dirs:
+      tests
+      library
+  ghc-options: -Wall -Wcompat
+  build-depends:
+      JuicyPixels >3 && <4
+    , base >=4.8 && <5
+    , bytestring >=0.9 && <0.11
+    , hakyll >4
+    , hakyll-images
+    , tasty >=0.11 && <1.2
+    , tasty-hunit >=0.9 && <0.11
+  default-language: Haskell2010
diff --git a/library/Hakyll/Images.hs b/library/Hakyll/Images.hs
new file mode 100644
--- /dev/null
+++ b/library/Hakyll/Images.hs
@@ -0,0 +1,18 @@
+
+{-|
+Module      : Hakyll.Images
+Description : Hakyll utilities for image files
+Copyright   : (c) Laurent P René de Cotret, 2018
+License     : MIT
+Maintainer  : laurent.decotret@outlook.com
+Stability   : stable
+Portability : portable
+-}
+module Hakyll.Images (
+    -- Jpg compression
+      JpgQuality
+    , compressJpg
+    , compressJpgCompiler
+) where
+
+import Hakyll.Images.CompressJpg (compressJpg, compressJpgCompiler, JpgQuality)
diff --git a/library/Hakyll/Images/CompressJpg.hs b/library/Hakyll/Images/CompressJpg.hs
new file mode 100644
--- /dev/null
+++ b/library/Hakyll/Images/CompressJpg.hs
@@ -0,0 +1,73 @@
+
+{-|
+Module      : Hakyll.Images.CompressJpg
+Description : Hakyll compiler to compress Jpeg images
+Copyright   : (c) Laurent P René de Cotret, 2018
+License     : MIT
+Maintainer  : laurent.decotret@outlook.com
+Stability   : stable
+Portability : portable
+
+This module defines a Hakyll compiler, 'compressJpgCompiler', which can be used to
+re-encode Jpeg images at a lower quality during website compilation. Original images are
+left unchanged, but compressed images can be up to 10x smaller.
+
+The @compressJpgCompiler@ is expected to be used like this:
+
+@
+    import Hakyll
+    import Hakyll.Images        (compressJpgCompiler)
+    
+    (... omitted ...)
+    
+    hakyll $ do
+
+        (... omitted ...)
+        -- Compress all source Jpegs to a Jpeg quality of 50
+        match "images/**.jpg" $ do
+            route idRoute
+            compile (compressJpgCompiler 50)
+        
+        (... omitted ...)
+@
+-}
+module Hakyll.Images.CompressJpg
+    ( JpgQuality
+    , compressJpgCompiler
+    , compressJpg
+    ) where
+
+import Data.ByteString.Lazy             (ByteString, toStrict)
+
+-- From JuicyPixels
+import Codec.Picture.Jpg                (decodeJpeg)
+import Codec.Picture.Saving             (imageToJpg)
+
+import Hakyll.Core.Item                 (Item)
+import Hakyll.Core.Compiler             (Compiler, getResourceLBS)
+
+
+-- | Jpeg encoding quality, from 0 (lower quality) to 100 (best quality).
+type JpgQuality = Int
+
+
+-- | Compress a JPG bytestring to a certain quality setting.
+-- The quality should be between 0 (lowest quality) and 100 (best quality).
+-- An error is raised if the image cannot be decoded, or if the 
+-- encoding quality is out-of-bounds
+compressJpg :: JpgQuality -> ByteString -> ByteString
+compressJpg quality src = case im of
+        Left _         -> error $ "Loading the image failed."
+        Right dynImage -> if (quality < 0 || quality > 100)
+            then error $ "JPEG encoding quality should be between 0 and 100"
+            else imageToJpg quality dynImage
+    -- The function `decodeJpeg` requires strict ByteString
+    -- However, `imageToJpg` requires Lazy Bytestrings
+    where im = (decodeJpeg . toStrict) src
+
+
+-- | Compiler that compresses a JPG image to a certain quality setting.
+-- The quality should be between 0 (lowest quality) and 100 (best quality).
+-- An error is raised if the image cannot be decoded.
+compressJpgCompiler :: JpgQuality -> Compiler (Item ByteString)
+compressJpgCompiler quality = fmap (compressJpg quality) <$> getResourceLBS
diff --git a/package.yaml b/package.yaml
new file mode 100644
--- /dev/null
+++ b/package.yaml
@@ -0,0 +1,51 @@
+name: hakyll-images
+version: '0.0.1'
+github: "LaurentRDC/hakyll-images"
+license: BSD3
+author: "Laurent P. René de Cotret"
+maintainer: "Laurent P. René de Cotret"
+synopsis: "Hakyll utilities to work with images"
+description: 
+  hakyll-images is an add-on to the hakyll package. It adds utilities to work
+  with images, including JPEG compression. 
+category: Web
+license-file: LICENSE.md
+
+extra-source-files:
+- CHANGELOG.md
+- LICENSE.md
+- package.yaml
+- README.md
+- stack.yaml
+
+data-files:
+- tests\data\*.jpg
+
+ghc-options: -Wall -Wcompat
+
+library:
+  dependencies:
+  - base              >= 4.8 && < 5
+  - bytestring        >= 0.9 && < 0.11
+  - hakyll            > 4
+  - JuicyPixels       > 3 && < 4
+  source-dirs: library
+  exposed-modules:
+  - Hakyll.Images
+  - Hakyll.Images.CompressJpg
+
+tests:
+  spec:
+    source-dirs: 
+      - tests
+      - library
+    main: TestSuite.hs
+    dependencies:
+    - hakyll-images
+    - tasty             >= 0.11 && < 1.2
+    - tasty-hunit       >= 0.9  && < 0.11
+    # Base hakyll-images dependencies
+    - base              >= 4.8 && < 5
+    - bytestring        >= 0.9 && < 0.11
+    - hakyll            > 4
+    - JuicyPixels       > 3 && < 4
diff --git a/stack.yaml b/stack.yaml
new file mode 100644
--- /dev/null
+++ b/stack.yaml
@@ -0,0 +1,66 @@
+# This file was automatically generated by 'stack init'
+#
+# Some commonly used options have been documented as comments in this file.
+# For advanced use and comprehensive documentation of the format, please see:
+# https://docs.haskellstack.org/en/stable/yaml_configuration/
+
+# Resolver to choose a 'specific' stackage snapshot or a compiler version.
+# A snapshot resolver dictates the compiler version and the set of packages
+# to be used for project dependencies. For example:
+#
+# resolver: lts-3.5
+# resolver: nightly-2015-09-21
+# resolver: ghc-7.10.2
+# resolver: ghcjs-0.1.0_ghc-7.10.2
+#
+# The location of a snapshot can be provided as a file or url. Stack assumes
+# a snapshot provided as a file might change, whereas a url resource does not.
+#
+# resolver: ./custom-snapshot.yaml
+# resolver: https://example.com/snapshots/2018-01-01.yaml
+resolver: lts-11.7
+
+# User packages to be built.
+# Various formats can be used as shown in the example below.
+#
+# packages:
+# - some-directory
+# - https://example.com/foo/bar/baz-0.0.2.tar.gz
+# - location:
+#    git: https://github.com/commercialhaskell/stack.git
+#    commit: e7b331f14bcffb8367cd58fbfc8b40ec7642100a
+# - location: https://github.com/commercialhaskell/stack/commit/e7b331f14bcffb8367cd58fbfc8b40ec7642100a
+#  subdirs:
+#  - auto-update
+#  - wai
+packages:
+- .
+# Dependency packages to be pulled from upstream that are not in the resolver
+# using the same syntax as the packages field.
+# (e.g., acme-missiles-0.3)
+extra-deps: 
+- hakyll-4.12.4.0
+
+# Override default flag values for local packages and extra-deps
+# flags: {}
+
+# Extra package databases containing global packages
+# extra-package-dbs: []
+
+# Control whether we use the GHC we find on the path
+# system-ghc: true
+#
+# Require a specific version of stack, using version ranges
+# require-stack-version: -any # Default
+# require-stack-version: ">=1.7"
+#
+# Override the architecture used by stack, especially useful on Windows
+# arch: i386
+# arch: x86_64
+#
+# Extra directories used by stack for building
+# extra-include-dirs: [/path/to/dir]
+# extra-lib-dirs: [/path/to/dir]
+#
+# Allow a newer minor version of GHC than the snapshot specifies
+# compiler-check: newer-minor
diff --git a/tests/Hakyll/Images/CompressJpg/Tests.hs b/tests/Hakyll/Images/CompressJpg/Tests.hs
new file mode 100644
--- /dev/null
+++ b/tests/Hakyll/Images/CompressJpg/Tests.hs
@@ -0,0 +1,82 @@
+--------------------------------------------------------------------------------
+module Hakyll.Images.CompressJpg.Tests
+    ( tests
+    ) where
+
+
+--------------------------------------------------------------------------------
+import           Test.Tasty             (TestTree, testGroup)
+import           Test.Tasty.HUnit       (Assertion, assertBool, assertFailure, testCase)
+
+
+--------------------------------------------------------------------------------
+import           Hakyll.Images.CompressJpg
+import qualified Data.ByteString.Lazy   as B
+
+import           Control.Exception      (ErrorCall, catch, evaluate)
+
+import           Text.Printf            (printf)
+
+
+testJpg :: IO B.ByteString 
+testJpg = B.readFile "tests/data/piccolo.jpg"
+
+fromAssertions :: String       -- ^ Name
+               -> [Assertion]  -- ^ Cases
+               -> [TestTree]   -- ^ Result tests
+fromAssertions name =
+    zipWith testCase [printf "[%2d] %s" n name | n <- [1 :: Int ..]]
+
+-- Test that the standard Image compressed to quality 25/100 is smaller
+-- than the initial image
+testCompressionFromImage :: Assertion
+testCompressionFromImage = do
+    image <- testJpg
+    let initialSize = B.length image
+        finalSize   = B.length $ compressJpg 25 image
+    
+    assertBool "Image was not compressed" (initialSize > finalSize)
+
+-- Test that specifying a JPG encoding below 0 will fail
+testJpgEncodingOutOfLowerBound :: Assertion
+testJpgEncodingOutOfLowerBound = do
+    image <- testJpg
+    -- Catching exceptions is an idea from here:
+    -- https://stackoverflow.com/questions/46330592/is-it-possible-to-assert-an-error-case-in-hunit
+    -- Since compressJpg is a "pure" function, we need to evaluate it in an IO context
+    -- to catch errors.
+    errored <- catch (evaluate (compressJpg (-10) image) >> pure False) handler
+    if errored then
+        pure ()
+    else 
+        assertFailure "did not catch expected error"
+    where
+        handler :: ErrorCall -> IO Bool
+        handler _ = pure True
+
+-- Test that specifying a JPG encoding above 100 will fail
+testJpgEncodingOutOfUpperBound :: Assertion
+testJpgEncodingOutOfUpperBound = do
+    image <- testJpg
+    -- Catching exceptions is an idea from here:
+    -- https://stackoverflow.com/questions/46330592/is-it-possible-to-assert-an-error-case-in-hunit
+    -- Since compressJpg is a "pure" function, we need to evaluate it in an IO context
+    -- to catch errors.
+    errored <- catch (evaluate (compressJpg 111 image) >> pure False) handler
+    if errored then
+        pure ()
+    else 
+        assertFailure "did not catch expected error"
+    where
+        handler :: ErrorCall -> IO Bool
+        handler _ = pure True
+
+--------------------------------------------------------------------------------
+tests :: TestTree
+tests = testGroup "Hakyll.Web.CompressJpg.Tests" $ concat
+   [ fromAssertions "compressJpg" 
+        [ testCompressionFromImage 
+        , testJpgEncodingOutOfLowerBound
+        , testJpgEncodingOutOfUpperBound
+        ] 
+    ]
diff --git a/tests/TestSuite.hs b/tests/TestSuite.hs
new file mode 100644
--- /dev/null
+++ b/tests/TestSuite.hs
@@ -0,0 +1,18 @@
+--------------------------------------------------------------------------------
+module Main
+    ( main
+    ) where
+
+
+--------------------------------------------------------------------------------
+import           Test.Tasty                           (defaultMain, testGroup)
+
+
+--------------------------------------------------------------------------------
+import qualified Hakyll.Images.CompressJpg.Tests
+
+
+--------------------------------------------------------------------------------
+main :: IO ()
+main = defaultMain $ testGroup "Hakyll"
+    [ Hakyll.Images.CompressJpg.Tests.tests ]
diff --git a/tests/data/piccolo.jpg b/tests/data/piccolo.jpg
new file mode 100644
Binary files /dev/null and b/tests/data/piccolo.jpg differ
