{-# OPTIONS_GHC -fno-warn-orphans #-}
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE ViewPatterns #-}
-- |
-- Module      : Graphics.Image.IO.Formats.JuicyPixels.Readable
-- Copyright   : (c) Alexey Kuleshevich 2017
-- License     : BSD3
-- Maintainer  : Alexey Kuleshevich <lehins@yandex.ru>
-- Stability   : experimental
-- Portability : non-portable
--
module Graphics.Image.IO.Formats.JuicyPixels.Readable () where

import Prelude as P

import Graphics.Image.ColorSpace
import Graphics.Image.Interface as I
import Graphics.Image.Interface.Vector
import Graphics.Image.IO.Base
import Graphics.Image.IO.Formats.JuicyPixels.Common
import qualified Data.ByteString as B  -- (ByteString)
import qualified Codec.Picture as JP
import qualified Codec.Picture.Types as JP
import qualified Codec.Picture.Gif as JP
import qualified Data.Vector.Storable as V


--------------------------------------------------------------------------------
-- Converting to and from JuicyPixels ------------------------------------------
--------------------------------------------------------------------------------

---- to JuicyPixels -----

---- Exact precision conversions

instance Convertible JP.Pixel8 (Pixel Y Word8) where
  convert = PixelY
  
instance Convertible JP.Pixel16 (Pixel Y Word16) where
  convert = PixelY

instance Convertible JP.Pixel32 (Pixel Y Word32) where
  convert = PixelY

instance Convertible JP.PixelF (Pixel Y Float) where
  convert = PixelY

instance Convertible JP.PixelYA8 (Pixel YA Word8) where
  convert (JP.PixelYA8 g a) = PixelYA g a
  
instance Convertible JP.PixelYA16 (Pixel YA Word16) where
  convert (JP.PixelYA16 g a) = PixelYA g a

instance Convertible JP.PixelRGB8 (Pixel RGB Word8) where
  convert (JP.PixelRGB8 r g b) = PixelRGB r g b
  
instance Convertible JP.PixelRGB16 (Pixel RGB Word16) where
  convert (JP.PixelRGB16 r g b) = PixelRGB r g b

instance Convertible JP.PixelRGBF (Pixel RGB Float) where
  convert (JP.PixelRGBF r g b) = PixelRGB r g b

instance Convertible JP.PixelRGBA8 (Pixel RGBA Word8) where
  convert (JP.PixelRGBA8 r g b a) = PixelRGBA r g b a
  
instance Convertible JP.PixelRGBA16 (Pixel RGBA Word16) where
  convert (JP.PixelRGBA16 r g b a) = PixelRGBA r g b a

instance Convertible JP.PixelYCbCr8 (Pixel YCbCr Word8) where
  convert (JP.PixelYCbCr8 y cb cr) = PixelYCbCr y cb cr

instance Convertible JP.PixelCMYK8 (Pixel CMYK Word8) where
  convert (JP.PixelCMYK8 c m y k) = PixelCMYK c m y k

instance Convertible JP.PixelCMYK16 (Pixel CMYK Word16) where
  convert (JP.PixelCMYK16 c m y k) = PixelCMYK c m y k



instance Convertible (Pixel Y Word8) JP.Pixel8 where
  convert (PixelY y) = y
  
instance Convertible (Pixel Y Word16) JP.Pixel16 where
  convert (PixelY y) = y

instance Convertible (Pixel Y Word32) JP.Pixel32 where
  convert (PixelY y) = y

instance Convertible (Pixel Y Float) JP.PixelF where
  convert (PixelY y) = y

instance Convertible (Pixel YA Word8) JP.PixelYA8 where
  convert (PixelYA y a) = JP.PixelYA8 y a
  
instance Convertible (Pixel YA Word16) JP.PixelYA16 where
  convert (PixelYA y a) = JP.PixelYA16 y a

instance Convertible (Pixel RGB Word8) JP.PixelRGB8 where
  convert (PixelRGB r g b) = JP.PixelRGB8 r g b
  
instance Convertible (Pixel RGB Word16) JP.PixelRGB16 where
  convert (PixelRGB r g b) = JP.PixelRGB16 r g b

instance Convertible (Pixel RGB Float) JP.PixelRGBF where
  convert (PixelRGB r g b) = JP.PixelRGBF r g b

instance Convertible (Pixel RGBA Word8) JP.PixelRGBA8 where
  convert (PixelRGBA r g b a) = JP.PixelRGBA8 r g b a
  
instance Convertible (Pixel RGBA Word16) JP.PixelRGBA16 where
  convert (PixelRGBA r g b a) = JP.PixelRGBA16 r g b a

instance Convertible (Pixel YCbCr Word8) JP.PixelYCbCr8 where
  convert (PixelYCbCr y cb cr) = JP.PixelYCbCr8 y cb cr

instance Convertible (Pixel CMYK Word8) JP.PixelCMYK8 where
  convert (PixelCMYK c m y k) = JP.PixelCMYK8 c m y k

instance Convertible (Pixel CMYK Word16) JP.PixelCMYK16 where
  convert (PixelCMYK c m y k) = JP.PixelCMYK16 c m y k



--------------------------------------------------------------------------------
-- Decoding images using JuicyPixels ------------------------------------------
--------------------------------------------------------------------------------


-- BMP Format Reading

instance Readable (Image VS Binary Bit) BMP where
  decode _ = fmap toImageBinary . jpImageY8ToImage . JP.decodeBitmap

instance Readable (Image VS Y Word8) BMP where
  decode _ = jpImageY8ToImage . JP.decodeBitmap

instance Readable (Image VS RGB Word8) BMP where
  decode _ = jpImageRGB8ToImage . JP.decodeBitmap

instance Readable (Image VS RGBA Word8) BMP where
  decode _ = jpImageRGBA8ToImage . JP.decodeBitmap



-- GIF Format Reading

instance Readable (Image VS RGB Word8) GIF where
  decode _ = jpImageRGB8ToImage . JP.decodeGif

instance Readable (Image VS RGBA Word8) GIF where
  decode _ = jpImageRGBA8ToImage . JP.decodeGif


-- Animated GIF Format frames reading into a list

decodeGifs :: (Either String JP.DynamicImage -> Either String img)
           -> B.ByteString -> Either String [img]
decodeGifs decoder bs = do
  imgs <- JP.decodeGifImages bs
  sequence $ fmap (decoder . Right) imgs


decodeGifsDelays :: (Either String JP.DynamicImage -> Either String img)
                 -> B.ByteString -> Either String [(GifDelay, img)]
decodeGifsDelays decoder bs = do
  imgs <- JP.decodeGifImages bs
  delays <- JP.getDelaysGifImages bs
  gifs <- sequence $ fmap (decoder . Right) imgs
  return $ zip delays gifs



instance Readable [Image VS RGB Word8] GIFA where
  decode _ = decodeGifs jpImageRGB8ToImage

instance Readable [Image VS RGBA Word8] GIFA where
  decode _ = decodeGifs jpImageRGBA8ToImage

instance Readable [(GifDelay, Image VS RGB Word8)] GIFA where
  decode _ = decodeGifsDelays jpImageRGB8ToImage

instance Readable [(GifDelay, Image VS RGBA Word8)] GIFA where
  decode _ = decodeGifsDelays jpImageRGBA8ToImage


-- HDR Format Reading

instance Readable (Image VS RGB Float) HDR where
  decode _ = jpImageRGBFToImage . JP.decodeHDR


-- JPG Format Reading

instance Readable (Image VS Y Word8) JPG where
  decode _ = jpImageY8ToImage . JP.decodeJpeg

instance Readable (Image VS YA Word8) JPG where
  decode _ = jpImageYA8ToImage . JP.decodeJpeg

instance Readable (Image VS RGB Word8) JPG where
  decode _ = jpImageRGB8ToImage . JP.decodeJpeg

instance Readable (Image VS CMYK Word8) JPG where
  decode _ = jpImageCMYK8ToImage . JP.decodeJpeg

instance Readable (Image VS YCbCr Word8) JPG where
  decode _ = jpImageYCbCr8ToImage . JP.decodeJpeg


-- PNG Format Reading

instance Readable (Image VS Binary Bit) PNG where
  decode _ = fmap toImageBinary . jpImageY8ToImage . JP.decodePng

instance Readable (Image VS Y Word8) PNG where
  decode _ = jpImageY8ToImage . JP.decodePng

instance Readable (Image VS Y Word16) PNG where
  decode _ = jpImageY16ToImage . JP.decodePng

instance Readable (Image VS YA Word8) PNG where
  decode _ = jpImageYA8ToImage . JP.decodePng

instance Readable (Image VS YA Word16) PNG where
  decode _ = jpImageYA16ToImage . JP.decodePng

instance Readable (Image VS RGB Word8) PNG where
  decode _ = jpImageRGB8ToImage . JP.decodePng

instance Readable (Image VS RGB Word16) PNG where
  decode _ = jpImageRGB16ToImage . JP.decodePng

instance Readable (Image VS RGBA Word8) PNG where
  decode _ = jpImageRGBA8ToImage . JP.decodePng

instance Readable (Image VS RGBA Word16) PNG where
  decode _ = jpImageRGBA16ToImage . JP.decodePng


-- TGA Format Reading

instance Readable (Image VS Binary Bit) TGA where
  decode _ = fmap toImageBinary . jpImageY8ToImage . JP.decodeTga

instance Readable (Image VS Y Word8) TGA where
  decode _ = jpImageY8ToImage . JP.decodeTga

instance Readable (Image VS RGB Word8) TGA where
  decode _ = jpImageRGB8ToImage . JP.decodeTga

instance Readable (Image VS RGBA Word8) TGA where
  decode _ = jpImageRGBA8ToImage . JP.decodeTga


-- TIF Format Reading

instance Readable (Image VS Binary Bit) TIF where
  decode _ = fmap toImageBinary . jpImageY8ToImage . JP.decodeTiff

instance Readable (Image VS Y Word8) TIF where
  decode _ = jpImageY8ToImage . JP.decodeTiff

instance Readable (Image VS Y Word16) TIF where
  decode _ = jpImageY16ToImage . JP.decodeTiff

instance Readable (Image VS YA Word8) TIF where
  decode _ = jpImageYA8ToImage . JP.decodeTiff

instance Readable (Image VS YA Word16) TIF where
  decode _ = jpImageYA16ToImage . JP.decodeTiff

instance Readable (Image VS RGB Word8) TIF where
  decode _ = jpImageRGB8ToImage . JP.decodeTiff

instance Readable (Image VS RGB Word16) TIF where
  decode _ = jpImageRGB16ToImage . JP.decodeTiff

instance Readable (Image VS RGBA Word8) TIF where
  decode _ = jpImageRGBA8ToImage . JP.decodeTiff

instance Readable (Image VS RGBA Word16) TIF where
  decode _ = jpImageRGBA16ToImage . JP.decodeTiff

instance Readable (Image VS CMYK Word8) TIF where
  decode _ = jpImageCMYK8ToImage . JP.decodeTiff

instance Readable (Image VS CMYK Word16) TIF where
  decode _ = jpImageCMYK16ToImage . JP.decodeTiff


-- To Double precision safe conversion

instance Readable (Image VS Y Double) BMP where
  decode _ = jpDynamicImageToImage . JP.decodeBitmap

instance Readable (Image VS YA Double) BMP where
  decode _ = jpDynamicImageToImage . JP.decodeBitmap

instance Readable (Image VS RGB Double) BMP where
  decode _ = jpDynamicImageToImage . JP.decodeBitmap

instance Readable (Image VS RGBA Double) BMP where
  decode _ = jpDynamicImageToImage . JP.decodeBitmap


instance Readable (Image VS Y Double) GIF where
  decode _ = jpDynamicImageToImage . JP.decodeGif

instance Readable (Image VS YA Double) GIF where
  decode _ = jpDynamicImageToImage . JP.decodeGif

instance Readable (Image VS RGB Double) GIF where
  decode _ = jpDynamicImageToImage . JP.decodeGif

instance Readable (Image VS RGBA Double) GIF where
  decode _ = jpDynamicImageToImage . JP.decodeGif


instance Readable [Image VS Y Double] GIFA where
  decode _ = decodeGifs jpDynamicImageToImage

instance Readable [Image VS YA Double] GIFA where
  decode _ = decodeGifs jpDynamicImageToImage

instance Readable [Image VS RGB Double] GIFA where
  decode _ = decodeGifs jpDynamicImageToImage

instance Readable [Image VS RGBA Double] GIFA where
  decode _ = decodeGifs jpDynamicImageToImage


instance Readable (Image VS Y Double) HDR where
  decode _ = jpDynamicImageToImage . JP.decodeHDR

instance Readable (Image VS YA Double) HDR where
  decode _ = jpDynamicImageToImage . JP.decodeHDR

instance Readable (Image VS RGB Double) HDR where
  decode _ = jpDynamicImageToImage . JP.decodeHDR

instance Readable (Image VS RGBA Double) HDR where
  decode _ = jpDynamicImageToImage . JP.decodeHDR


instance Readable (Image VS Y Double) JPG where
  decode _ = jpDynamicImageToImage . JP.decodeJpeg

instance Readable (Image VS YA Double) JPG where
  decode _ = jpDynamicImageToImage . JP.decodeJpeg

instance Readable (Image VS RGB Double) JPG where
  decode _ = jpDynamicImageToImage . JP.decodeJpeg

instance Readable (Image VS RGBA Double) JPG where
  decode _ = jpDynamicImageToImage . JP.decodeJpeg


instance Readable (Image VS Y Double) PNG where
  decode _ = jpDynamicImageToImage . JP.decodePng

instance Readable (Image VS YA Double) PNG where
  decode _ = jpDynamicImageToImage . JP.decodePng

instance Readable (Image VS RGB Double) PNG where
  decode _ = jpDynamicImageToImage . JP.decodePng

instance Readable (Image VS RGBA Double) PNG where
  decode _ = jpDynamicImageToImage . JP.decodePng


instance Readable (Image VS Y Double) TGA where
  decode _ = jpDynamicImageToImage . JP.decodeTga

instance Readable (Image VS YA Double) TGA where
  decode _ = jpDynamicImageToImage . JP.decodeTga

instance Readable (Image VS RGB Double) TGA where
  decode _ = jpDynamicImageToImage . JP.decodeTga

instance Readable (Image VS RGBA Double) TGA where
  decode _ = jpDynamicImageToImage . JP.decodeTga


instance Readable (Image VS Y Double) TIF where
  decode _ = jpDynamicImageToImage . JP.decodeTiff

instance Readable (Image VS YA Double) TIF where
  decode _ = jpDynamicImageToImage . JP.decodeTiff

instance Readable (Image VS RGB Double) TIF where
  decode _ = jpDynamicImageToImage . JP.decodeTiff

instance Readable (Image VS RGBA Double) TIF where
  decode _ = jpDynamicImageToImage . JP.decodeTiff



-- General decoding and helper functions

jpImageToImageUnsafe :: (Array VS cs e, JP.Pixel jpx) =>
                        JP.Image jpx -> Image VS cs e
jpImageToImageUnsafe (JP.Image n m !v) = fromVector (m, n) $ V.unsafeCast v



-- jpImageToImageSafe :: (Array arr cs e, Convertible jpx (Pixel cs e), JP.Pixel jpx) =>
--                       JP.Image jpx -> Image arr cs e
-- jpImageToImageSafe !jimg = makeImage (JP.imageHeight jimg, JP.imageWidth jimg) getPx
--   where getPx !(y, x) = convert $ JP.pixelAt jimg x y


jpImageY8ToImage :: Either String JP.DynamicImage -> Either String (Image VS Y Word8)
jpImageY8ToImage (Right (JP.ImageY8 jimg)) = Right (jpImageToImageUnsafe jimg)
jpImageY8ToImage jimg = jpCSError "Y8 (Pixel Y Word8)" jimg


jpImageY16ToImage :: Either String JP.DynamicImage -> Either String (Image VS Y Word16)
jpImageY16ToImage (Right (JP.ImageY16 jimg)) = Right (jpImageToImageUnsafe jimg)
jpImageY16ToImage jimg = jpCSError "Y16 (Pixel Y Word16)" jimg

{- -- No JuicyPixels images are actually read in this type
jpImageYFToImage :: Either String JP.DynamicImage -> Either String (Image VS Y Float)
jpImageYFToImage (Right (JP.ImageYF jimg)) = Right (jpImageToImage jimg)
jpImageYFToImage jimg = jpCSError "YF (Pixel Y Float)" jimg
-}

jpImageYA8ToImage :: Either String JP.DynamicImage -> Either String (Image VS YA Word8)
jpImageYA8ToImage (Right (JP.ImageYA8 jimg)) = Right (jpImageToImageUnsafe jimg)
jpImageYA8ToImage jimg = jpCSError "YA8 (Pixel YA Word8)" jimg


jpImageYA16ToImage :: Either String JP.DynamicImage -> Either String (Image VS YA Word16)
jpImageYA16ToImage (Right (JP.ImageYA16 jimg)) = Right (jpImageToImageUnsafe jimg)
jpImageYA16ToImage jimg = jpCSError "YA16 (Pixel YA Word16)" jimg


jpImageRGB8ToImage :: Either String JP.DynamicImage -> Either String (Image VS RGB Word8)
jpImageRGB8ToImage (Right (JP.ImageRGB8 jimg)) = Right (jpImageToImageUnsafe jimg)
jpImageRGB8ToImage jimg = jpCSError "RGB8 (Pixel RGB Word8)" jimg


jpImageRGB16ToImage :: Either String JP.DynamicImage -> Either String (Image VS RGB Word16)
jpImageRGB16ToImage (Right (JP.ImageRGB16 jimg)) = Right (jpImageToImageUnsafe jimg)
jpImageRGB16ToImage jimg = jpCSError "RGB16 (Pixel RGB Word16)" jimg


jpImageRGBFToImage :: Either String JP.DynamicImage -> Either String (Image VS RGB Float)
jpImageRGBFToImage (Right (JP.ImageRGBF jimg)) = Right (jpImageToImageUnsafe jimg)
jpImageRGBFToImage jimg = jpCSError "RGBF (Pixel RGB Float)" jimg


jpImageRGBA8ToImage :: Either String JP.DynamicImage -> Either String (Image VS RGBA Word8)
jpImageRGBA8ToImage (Right (JP.ImageRGBA8 jimg)) = Right (jpImageToImageUnsafe jimg)
jpImageRGBA8ToImage jimg = jpCSError "RGBA8 (Pixel RGBA Word8)" jimg


jpImageRGBA16ToImage :: Either String JP.DynamicImage -> Either String (Image VS RGBA Word16)
jpImageRGBA16ToImage (Right (JP.ImageRGBA16 jimg)) = Right (jpImageToImageUnsafe jimg)
jpImageRGBA16ToImage jimg = jpCSError "RGBA16 (Pixel RGBA Word16)" jimg


jpImageYCbCr8ToImage :: Either String JP.DynamicImage -> Either String (Image VS YCbCr Word8)
jpImageYCbCr8ToImage (Right (JP.ImageYCbCr8 jimg)) = Right (jpImageToImageUnsafe jimg)
jpImageYCbCr8ToImage jimg = jpCSError "YCbCr8 (Pixel YCbCr Word8)" jimg


jpImageCMYK8ToImage :: Either String JP.DynamicImage -> Either String (Image VS CMYK Word8)
jpImageCMYK8ToImage (Right (JP.ImageCMYK8 jimg)) = Right (jpImageToImageUnsafe jimg)
jpImageCMYK8ToImage jimg = jpCSError "CMYK8 (Pixel CMYK Word8)" jimg


jpImageCMYK16ToImage :: Either String JP.DynamicImage -> Either String (Image VS CMYK Word16)
jpImageCMYK16ToImage (Right (JP.ImageCMYK16 jimg)) = Right (jpImageToImageUnsafe jimg)
jpImageCMYK16ToImage jimg = jpCSError "CMYK16 (Pixel CMYK Word16)" jimg


jpDynamicImageToImage' :: (Convertible (Pixel Y Word8) (Pixel cs e),
                           Convertible (Pixel YA Word8) (Pixel cs e),
                           Convertible (Pixel Y Word16) (Pixel cs e),
                           Convertible (Pixel YA Word16) (Pixel cs e),
                           Convertible (Pixel Y Float) (Pixel cs e),
                           Convertible (Pixel RGB Word8) (Pixel cs e),
                           Convertible (Pixel RGBA Word8) (Pixel cs e),
                           Convertible (Pixel RGB Word16) (Pixel cs e),
                           Convertible (Pixel RGBA Word16) (Pixel cs e),
                           Convertible (Pixel RGB Float) (Pixel cs e),
                           Convertible (Pixel YCbCr Word8) (Pixel cs e),
                           Convertible (Pixel CMYK Word8) (Pixel cs e),
                           Convertible (Pixel CMYK Word16) (Pixel cs e),
                           Array VS cs e) =>
                          JP.DynamicImage -> Image VS cs e
jpDynamicImageToImage' (JP.ImageY8 jimg)     =
  I.map convert $ (jpImageToImageUnsafe jimg :: Image VS Y Word8)
jpDynamicImageToImage' (JP.ImageYA8 jimg)    =
  I.map convert $ (jpImageToImageUnsafe jimg :: Image VS YA Word8)
jpDynamicImageToImage' (JP.ImageY16 jimg)    =
  I.map convert $ (jpImageToImageUnsafe jimg :: Image VS Y Word16)
jpDynamicImageToImage' (JP.ImageYA16 jimg)   =
  I.map convert $ (jpImageToImageUnsafe jimg :: Image VS YA Word16)
jpDynamicImageToImage' (JP.ImageYF jimg)     =
  I.map convert $ (jpImageToImageUnsafe jimg :: Image VS Y Float)
jpDynamicImageToImage' (JP.ImageRGB8 jimg)   =
  I.map convert $ (jpImageToImageUnsafe jimg :: Image VS RGB Word8)
jpDynamicImageToImage' (JP.ImageRGBA8 jimg)  =
  I.map convert $ (jpImageToImageUnsafe jimg :: Image VS RGBA Word8)
jpDynamicImageToImage' (JP.ImageRGB16 jimg)  =
  I.map convert $ (jpImageToImageUnsafe jimg :: Image VS RGB Word16)
jpDynamicImageToImage' (JP.ImageRGBA16 jimg) =
  I.map convert $ (jpImageToImageUnsafe jimg :: Image VS RGBA Word16)
jpDynamicImageToImage' (JP.ImageRGBF jimg)   =
  I.map convert $ (jpImageToImageUnsafe jimg :: Image VS RGB Float)
jpDynamicImageToImage' (JP.ImageYCbCr8 jimg) =
  I.map convert $ (jpImageToImageUnsafe jimg :: Image VS YCbCr Word8)
jpDynamicImageToImage' (JP.ImageCMYK8 jimg)  =
  I.map convert $ (jpImageToImageUnsafe jimg :: Image VS CMYK Word8)
jpDynamicImageToImage' (JP.ImageCMYK16 jimg) =
  I.map convert $ (jpImageToImageUnsafe jimg :: Image VS CMYK Word16)


jpDynamicImageToImage :: (Convertible (Pixel Y Word8) (Pixel cs e),
                          Convertible (Pixel YA Word8) (Pixel cs e),
                          Convertible (Pixel Y Word16) (Pixel cs e),
                          Convertible (Pixel YA Word16) (Pixel cs e),
                          Convertible (Pixel Y Float) (Pixel cs e),
                          Convertible (Pixel RGB Word8) (Pixel cs e),
                          Convertible (Pixel RGBA Word8) (Pixel cs e),
                          Convertible (Pixel RGB Word16) (Pixel cs e),
                          Convertible (Pixel RGBA Word16) (Pixel cs e),
                          Convertible (Pixel RGB Float) (Pixel cs e),
                          Convertible (Pixel YCbCr Word8) (Pixel cs e),
                          Convertible (Pixel CMYK Word8) (Pixel cs e),
                          Convertible (Pixel CMYK Word16) (Pixel cs e),
                          Array VS cs e) =>
                         Either String JP.DynamicImage -> Either String (Image VS cs e)
jpDynamicImageToImage = either jpError (Right . jpDynamicImageToImage')


jpImageShowCS :: JP.DynamicImage -> String
jpImageShowCS (JP.ImageY8 _)     = "Y8 (Pixel Y Word8)"
jpImageShowCS (JP.ImageY16 _)    = "Y16 (Pixel Y Word16)"
jpImageShowCS (JP.ImageYF _)     = "YF (Pixel Y Float)"
jpImageShowCS (JP.ImageYA8 _)    = "YA8 (Pixel YA Word8)"
jpImageShowCS (JP.ImageYA16 _)   = "YA16 (Pixel YA Word16)"
jpImageShowCS (JP.ImageRGB8 _)   = "RGB8 (Pixel RGB Word8)"
jpImageShowCS (JP.ImageRGB16 _)  = "RGB16 (Pixel RGB Word16)"
jpImageShowCS (JP.ImageRGBF _)   = "RGBF (Pixel RGB Float)"
jpImageShowCS (JP.ImageRGBA8 _)  = "RGBA8 (Pixel RGBA Word8)"
jpImageShowCS (JP.ImageRGBA16 _) = "RGBA16 (Pixel RGBA Word16)"
jpImageShowCS (JP.ImageYCbCr8 _) = "YCbCr8 (Pixel YCbCr Word8)"
jpImageShowCS (JP.ImageCMYK8 _)  = "CMYK8 (Pixel CMYK Word8)"
jpImageShowCS (JP.ImageCMYK16 _) = "CMYK16 (Pixel CMYK Word16)"


jpError :: String -> Either String a
jpError err = Left ("JuicyPixel decoding error: "++err)


jpCSError :: String -> Either String JP.DynamicImage -> Either String a
jpCSError _  (Left err)   = jpError err
jpCSError cs (Right jimg) =
  jpError $
  "Input image is in " ++
  jpImageShowCS jimg ++ ", cannot convert it to " ++ cs ++ " colorspace."