hakyll-images 0.3.0 → 0.3.1
raw patch · 12 files changed
+170/−143 lines, 12 filessetup-changedPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
API changes (from Hackage documentation)
- Hakyll.Images: type Image = ByteString
+ Hakyll.Images: type Image = Image_ ByteString
Files
- CHANGELOG.md +16/−16
- LICENSE.md +10/−10
- README.md +2/−1
- Setup.hs +7/−7
- hakyll-images.cabal +3/−3
- library/Hakyll/Images.hs +2/−1
- library/Hakyll/Images/Common.hs +32/−13
- library/Hakyll/Images/CompressJpg.hs +16/−10
- library/Hakyll/Images/Resize.hs +7/−8
- package.yaml +1/−1
- stack.yaml +64/−64
- tests/Hakyll/Images/CompressJpg/Tests.hs +10/−9
CHANGELOG.md view
@@ -1,16 +1,16 @@-# Change log - -Release 0.1.1 - -* Exposed `resizeImageCompiler` and `scaleImageCompiler` to the base `Hakyll.Images` module - -Release 0.1.0 -------------- - -* added `resizeImageCompiler` to resize images to a specific shape; -* added `scaleImageCompiler` to scale images while keeping aspect ratio. - -Release 0.0.1 -------------- - -* Added compressJpgCompiler to compress JPEGs. +# Change log++Release 0.1.1++* Exposed `resizeImageCompiler` and `scaleImageCompiler` to the base `Hakyll.Images` module++Release 0.1.0+-------------++* added `resizeImageCompiler` to resize images to a specific shape;+* added `scaleImageCompiler` to scale images while keeping aspect ratio.++Release 0.0.1+-------------++* Added compressJpgCompiler to compress JPEGs.
LICENSE.md view
@@ -1,11 +1,11 @@-Copyright 2019 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. - +Copyright 2019 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.
README.md view
@@ -15,7 +15,8 @@ ```haskell import Hakyll -import Hakyll.Images ( compressJpgCompiler +import Hakyll.Images ( loadImage + , compressJpgCompiler , resizeImageCompiler , scaleImageCompiler )
Setup.hs view
@@ -1,7 +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 +-- 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
hakyll-images.cabal view
@@ -1,13 +1,13 @@ cabal-version: 1.12 --- This file has been generated from package.yaml by hpack version 0.31.1.+-- This file has been generated from package.yaml by hpack version 0.30.0. -- -- see: https://github.com/sol/hpack ----- hash: 2c391e45aeacd80cae44a88331bc4c4cff67e69127f1aaed68d4fb7ea7f56d29+-- hash: ae9f128028bfb7b003b7940adbbacf13e15a99ee309055e70cf616edbd4fb9b2 name: hakyll-images-version: 0.3.0+version: 0.3.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
library/Hakyll/Images.hs view
@@ -5,13 +5,14 @@ Copyright : (c) Laurent P René de Cotret, 2019 License : BSD3 Maintainer : laurent.decotret@outlook.com -Stability : stable +Stability : unstable Portability : portable This package defines a few Hakyll compilers. These compilers help deal with images in the context of Hakyll programs, such as JPEG compression or image resizing. Items must be loaded before compilers can be used, like so: + @ import Hakyll import Hakyll.Images ( loadImage
library/Hakyll/Images/Common.hs view
@@ -5,13 +5,15 @@ Copyright : (c) Laurent P René de Cotret, 2019 License : BSD3 Maintainer : laurent.decotret@outlook.com -Stability : stable +Stability : unstable Portability : portable -} -module Hakyll.Images.Common ( Image - , ImageFormat - , fromExt +module Hakyll.Images.Common ( Image + , Image_(..) + , ImageFormat(..) + , format + , image , loadImage , encode ) where @@ -24,19 +26,33 @@ import Data.ByteString.Lazy (toStrict) import Data.ByteString (ByteString) -import Hakyll.Core.Compiler (Compiler, getResourceLBS) +import Hakyll.Core.Compiler (Compiler, getResourceLBS, getUnderlyingExtension) import Hakyll.Core.Item (Item(..)) - -type Image = ByteString - -- Supported (i.e. encodable) image formats data ImageFormat = Jpeg | Png | Bitmap | Tiff + deriving (Eq) +-- Polymorphic type only to get an instance of functor +data Image_ a = Image ImageFormat a + +instance Functor Image_ where + fmap f (Image fmt a) = Image fmt (f a) + +type Image = Image_ ByteString + +-- | Extract format from an image +format :: Image_ a -> ImageFormat +format (Image fmt _) = fmt + +-- | Extract data from image +image :: Image_ a -> a +image (Image _ im) = im + -- | Load an image from a file. -- This function can be combined with other compilers. -- @@ -47,7 +63,10 @@ -- >>= compressJpgCompiler 50 -- @ loadImage :: Compiler (Item Image) -loadImage = fmap toStrict <$> getResourceLBS +loadImage = do + content <- fmap toStrict <$> getResourceLBS + fmt <- fromExt <$> getUnderlyingExtension + return $ (Image fmt) <$> content -- | Translation between file extensions and image formats. -- It is important to keep track of image formats because Hakyll @@ -63,7 +82,7 @@ -- Encode images based on file extension encode :: ImageFormat -> DynamicImage -> Image -encode Jpeg = toStrict . imageToJpg 100 -encode Png = toStrict . imageToPng -encode Bitmap = toStrict . imageToBitmap -encode Tiff = toStrict . imageToTiff+encode Jpeg im = Image Jpeg $ (toStrict . imageToJpg 100) im +encode Png im = Image Png $ (toStrict . imageToPng) im +encode Bitmap im = Image Bitmap $ (toStrict . imageToBitmap) im +encode Tiff im = Image Tiff $ (toStrict . imageToTiff) im
library/Hakyll/Images/CompressJpg.hs view
@@ -5,7 +5,7 @@ Copyright : (c) Laurent P René de Cotret, 2019 License : BSD3 Maintainer : laurent.decotret@outlook.com -Stability : stable +Stability : unstable Portability : portable This module defines a Hakyll compiler, 'compressJpgCompiler', which can be used to @@ -45,7 +45,12 @@ import Hakyll.Core.Item (Item(..)) import Hakyll.Core.Compiler (Compiler) -import Hakyll.Images.Common (Image) +import Hakyll.Images.Common ( Image + , Image_(..) + , ImageFormat(..) + , image + , format + ) -- | Jpeg encoding quality, from 0 (lower quality) to 100 (best quality). @@ -57,14 +62,15 @@ -- An error is raised if the image cannot be decoded, or if the -- encoding quality is out-of-bounds compressJpg :: JpgQuality -> Image -> Image -compressJpg quality src = case decodeJpeg src 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 toStrict $ imageToJpg quality dynImage - -- The function `decodeJpeg` requires strict ByteString - -- However, `imageToJpg` requires Lazy Bytestrings - +compressJpg quality src = if (format src) /= Jpeg + then error $ "Image is not a JPEG." + else + case decodeJpeg $ image src 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 Image Jpeg $ (toStrict $ imageToJpg quality dynImage) -- | Compiler that compresses a JPG image to a certain quality setting. -- The quality should be between 0 (lowest quality) and 100 (best quality).
library/Hakyll/Images/Resize.hs view
@@ -5,7 +5,7 @@ Copyright : (c) Laurent P René de Cotret, 2019 License : BSD3 Maintainer : laurent.decotret@outlook.com -Stability : stable +Stability : unstable Portability : portable This module defines two Hakyll compilers. The first one, 'resizeImageCompiler', @@ -53,11 +53,10 @@ import Data.ByteString (ByteString) import Data.Ratio ((%)) -import Hakyll.Core.Identifier (toFilePath) import Hakyll.Core.Item (Item(..)) import Hakyll.Core.Compiler (Compiler) -import Hakyll.Images.Common (Image, encode, fromExt) +import Hakyll.Images.Common (Image, encode, format, image) type Width = Int type Height = Int @@ -65,7 +64,7 @@ decodeImage' :: ByteString -> DynamicImage decodeImage' im = case decodeImage im of Left msg -> error msg - Right image -> image + Right im' -> im' -- | Resize an image to specified width and height using the bilinear transform. -- The aspect ratio may not be respected. @@ -86,8 +85,8 @@ -- @ resizeImageCompiler :: Width -> Height -> Item Image -> Compiler (Item Image) resizeImageCompiler w h item = do - let ext = (fromExt . toFilePath . itemIdentifier) item - return $ (encode ext . resize w h . decodeImage') <$> item + let fmt = (format . itemBody) item + return $ (encode fmt . resize w h . decodeImage' . image) <$> item -- | Scale an image to a size that will fit in the specified width and height, -- while preserving aspect ratio. @@ -116,5 +115,5 @@ -- @ scaleImageCompiler :: Width -> Height -> Item Image -> Compiler (Item Image) scaleImageCompiler w h item = do - let ext = (fromExt . toFilePath . itemIdentifier) item - return $ (encode ext . scale w h . decodeImage') <$> item+ let fmt = (format . itemBody) item + return $ (encode fmt . scale w h . decodeImage' . image) <$> item
package.yaml view
@@ -1,5 +1,5 @@ name: hakyll-images -version: '0.3.0' +version: '0.3.1' github: "LaurentRDC/hakyll-images" license: BSD3 author: "Laurent P. René de Cotret"
stack.yaml view
@@ -1,65 +1,65 @@-# 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-12.24 - -# 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: [] - -# 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 +# 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-12.26++# 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: []++# 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
tests/Hakyll/Images/CompressJpg/Tests.hs view
@@ -11,6 +11,7 @@ -------------------------------------------------------------------------------- import Hakyll.Images.CompressJpg +import Hakyll.Images.Common import qualified Data.ByteString as B import Control.Exception (ErrorCall, catch, evaluate) @@ -18,8 +19,8 @@ import Text.Printf (printf) -testJpg :: IO B.ByteString -testJpg = B.readFile "tests/data/piccolo.jpg" +testJpg :: IO Image +testJpg = Image Jpeg <$> (B.readFile "tests/data/piccolo.jpg") fromAssertions :: String -- ^ Name -> [Assertion] -- ^ Cases @@ -31,21 +32,21 @@ -- than the initial image testCompressionFromImage :: Assertion testCompressionFromImage = do - image <- testJpg - let initialSize = B.length image - finalSize = B.length $ compressJpg 25 image + im <- testJpg + let initialSize = (B.length . image) im + finalSize = (B.length . image . compressJpg 25) im assertBool "Image was not compressed" (initialSize > finalSize) -- Test that specifying a JPG encoding below 0 will fail testJpgEncodingOutOfLowerBound :: Assertion testJpgEncodingOutOfLowerBound = do - image <- testJpg + im <- 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 + errored <- catch (evaluate (compressJpg (-10) im) >> pure False) handler if errored then pure () else @@ -57,12 +58,12 @@ -- Test that specifying a JPG encoding above 100 will fail testJpgEncodingOutOfUpperBound :: Assertion testJpgEncodingOutOfUpperBound = do - image <- testJpg + im <- 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 + errored <- catch (evaluate (compressJpg 111 im) >> pure False) handler if errored then pure () else