massiv-io-0.1.3.0: src/Data/Massiv/Array/IO/Image.hs
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TypeSynonymInstances #-}
-- |
-- Module : Data.Massiv.Array.IO.Image
-- Copyright : (c) Alexey Kuleshevich 2018
-- License : BSD3
-- Maintainer : Alexey Kuleshevich <lehins@yandex.ru>
-- Stability : experimental
-- Portability : non-portable
--
module Data.Massiv.Array.IO.Image
( Encode
, encodeImage
, imageWriteFormats
, imageWriteAutoFormats
, Decode
, decodeImage
, imageReadFormats
, imageReadAutoFormats
, module Data.Massiv.Array.IO.Image.JuicyPixels
, module Data.Massiv.Array.IO.Image.Netpbm
) where
import Control.Exception (throw)
import Data.Massiv.Array
import Data.Massiv.Array.IO.Base
import Data.Massiv.Array.IO.Image.JuicyPixels
import Data.Massiv.Array.IO.Image.Netpbm
import qualified Data.ByteString as B (ByteString)
import qualified Data.ByteString.Lazy as BL (ByteString)
import Data.Char (toLower)
import Graphics.ColorSpace
import Prelude as P
import System.FilePath (takeExtension)
data Encode out where
EncodeAs :: (FileFormat f, Writable f out) => f -> Encode out
instance Show (Encode out) where
show (EncodeAs f) = show f
instance FileFormat (Encode (Image r cs e)) where
ext (EncodeAs f) = ext f
exts (EncodeAs f) = exts f
instance Writable (Encode (Image r cs e)) (Image r cs e) where
encode (EncodeAs f) _ = encode f (defaultWriteOptions f)
-- | Encode an image into a lazy `BL.ByteString`, while selecting the appropriate format from the
-- file extension.
encodeImage
:: (Source r Ix2 (Pixel cs e), ColorSpace cs e)
=> [Encode (Image r cs e)] -- ^ List of image formats to choose from (useful lists are
-- `imageWriteFormats` and `imageWriteAutoFormats`
-> FilePath -- ^ File name with extension, so the format can be inferred
-> Image r cs e -- ^ Image to encode
-> BL.ByteString
encodeImage formats path img = do
let ext' = P.map toLower . takeExtension $ path
case dropWhile (not . isFormat ext') formats of
[] -> throw $ EncodeError $ "File format is not supported: " ++ ext'
(f:_) -> encode f () img
-- | List of image formats that can be encoded without any color space conversion.
imageWriteFormats :: (Source r Ix2 (Pixel cs e), ColorSpace cs e) => [Encode (Image r cs e)]
imageWriteFormats =
[ EncodeAs BMP
, EncodeAs GIF
, EncodeAs HDR
, EncodeAs JPG
, EncodeAs PNG
, EncodeAs TGA
, EncodeAs TIF
]
-- | List of image formats that can be encoded with any necessary color space conversions.
imageWriteAutoFormats
:: ( Source r Ix2 (Pixel cs e)
, ColorSpace cs e
, ToYA cs e
, ToRGBA cs e
, ToYCbCr cs e
, ToCMYK cs e
)
=> [Encode (Image r cs e)]
imageWriteAutoFormats =
[ EncodeAs (Auto BMP)
, EncodeAs (Auto GIF)
, EncodeAs (Auto HDR)
, EncodeAs (Auto JPG)
, EncodeAs (Auto PNG)
, EncodeAs (Auto TGA)
, EncodeAs (Auto TIF)
]
data Decode out where
DecodeAs :: (FileFormat f, Readable f out) => f -> Decode out
instance Show (Decode out) where
show (DecodeAs f) = show f
instance FileFormat (Decode (Image r cs e)) where
ext (DecodeAs f) = ext f
exts (DecodeAs f) = exts f
instance Readable (Decode (Image r cs e)) (Image r cs e) where
decode (DecodeAs f) _ = decode f (defaultReadOptions f)
-- | Decode an image from the strict `ByteString` while inferring format the image is encoded in
-- from the file extension
decodeImage
:: (Source r Ix2 (Pixel cs e), ColorSpace cs e)
=> [Decode (Image r cs e)] -- ^ List of available formats to choose from
-> FilePath -- ^ File name with extension, so format can be inferred
-> B.ByteString -- ^ Encoded image
-> Image r cs e
decodeImage formats path bs = do
let ext' = P.map toLower . takeExtension $ path
case dropWhile (not . isFormat ext') formats of
[] -> throw $ DecodeError $ "File format is not supported: " ++ ext'
(f:_) -> decode f () bs
-- | List of image formats decodable with no colorspace conversion
imageReadFormats
:: (Source S Ix2 (Pixel cs e), ColorSpace cs e)
=> [Decode (Image S cs e)]
imageReadFormats =
[ DecodeAs BMP
, DecodeAs GIF
, DecodeAs HDR
, DecodeAs JPG
, DecodeAs PNG
, DecodeAs TGA
, DecodeAs TIF
, DecodeAs PBM
, DecodeAs PGM
, DecodeAs PPM
]
-- | List of image formats decodable with no colorspace conversion
imageReadAutoFormats
:: (Mutable r Ix2 (Pixel cs e), ColorSpace cs e)
=> [Decode (Image r cs e)]
imageReadAutoFormats =
[ DecodeAs (Auto BMP)
, DecodeAs (Auto GIF)
, DecodeAs (Auto HDR)
, DecodeAs (Auto JPG)
, DecodeAs (Auto PNG)
, DecodeAs (Auto TGA)
, DecodeAs (Auto TIF)
, DecodeAs (Auto PBM)
, DecodeAs (Auto PGM)
, DecodeAs (Auto PPM)
]