Blame src/Codec/Picture/Saving.hs

Packit c600df
{-# LANGUAGE TypeFamilies #-}
Packit c600df
{-# LANGUAGE CPP #-}
Packit c600df
-- | Helper functions to save dynamic images to other file format
Packit c600df
-- with automatic color space/sample format conversion done automatically.
Packit c600df
module Codec.Picture.Saving( imageToJpg
Packit c600df
                           , imageToPng
Packit c600df
                           , imageToGif
Packit c600df
                           , imageToBitmap
Packit c600df
                           , imageToTiff
Packit c600df
                           , imageToRadiance
Packit c600df
                           , imageToTga
Packit c600df
                           ) where
Packit c600df
Packit c600df
#if !MIN_VERSION_base(4,8,0)
Packit c600df
import Data.Monoid( mempty )
Packit c600df
#endif
Packit c600df
Packit c600df
import Data.Bits( unsafeShiftR )
Packit c600df
import Data.Word( Word8, Word16 )
Packit c600df
import qualified Data.ByteString.Lazy as L
Packit c600df
import Codec.Picture.Bitmap
Packit c600df
import Codec.Picture.Jpg
Packit c600df
import Codec.Picture.Png
Packit c600df
import Codec.Picture.Gif
Packit c600df
import Codec.Picture.ColorQuant
Packit c600df
import Codec.Picture.HDR
Packit c600df
import Codec.Picture.Types
Packit c600df
import Codec.Picture.Tiff
Packit c600df
import Codec.Picture.Tga
Packit c600df
Packit c600df
import qualified Data.Vector.Storable as V
Packit c600df
Packit c600df
componentToLDR :: Float -> Word8
Packit c600df
componentToLDR = truncate . (255 *) . min 1.0 . max 0.0
Packit c600df
Packit c600df
toStandardDef :: Image PixelRGBF -> Image PixelRGB8
Packit c600df
toStandardDef = pixelMap pixelConverter
Packit c600df
  where pixelConverter (PixelRGBF rf gf bf) = PixelRGB8 r g b
Packit c600df
          where r = componentToLDR rf
Packit c600df
                g = componentToLDR gf
Packit c600df
                b = componentToLDR bf
Packit c600df
Packit c600df
greyScaleToStandardDef :: Image PixelF -> Image Pixel8
Packit c600df
greyScaleToStandardDef = pixelMap componentToLDR
Packit c600df
Packit c600df
from16to8 :: ( PixelBaseComponent source ~ Word16
Packit c600df
             , PixelBaseComponent dest ~ Word8 )
Packit c600df
          => Image source -> Image dest
Packit c600df
from16to8 Image { imageWidth = w, imageHeight = h
Packit c600df
                , imageData = arr } = Image w h transformed
Packit c600df
   where transformed = V.map toWord8 arr
Packit c600df
         toWord8 v = fromIntegral (v `unsafeShiftR` 8)
Packit c600df
Packit c600df
from16toFloat :: ( PixelBaseComponent source ~ Word16
Packit c600df
                 , PixelBaseComponent dest ~ Float )
Packit c600df
          => Image source -> Image dest
Packit c600df
from16toFloat Image { imageWidth = w, imageHeight = h
Packit c600df
                    , imageData = arr } = Image w h transformed
Packit c600df
   where transformed = V.map toWord8 arr
Packit c600df
         toWord8 v = fromIntegral v / 65536.0
Packit c600df
Packit c600df
-- | This function will try to do anything to encode an image
Packit c600df
-- as RADIANCE, make all color conversion and such. Equivalent
Packit c600df
-- of 'decodeImage' for radiance encoding
Packit c600df
imageToRadiance :: DynamicImage -> L.ByteString
Packit c600df
imageToRadiance (ImageCMYK8 img) =
Packit c600df
    imageToRadiance . ImageRGB8 $ convertImage img
Packit c600df
imageToRadiance (ImageCMYK16 img) =
Packit c600df
    imageToRadiance . ImageRGB16 $ convertImage img
Packit c600df
imageToRadiance (ImageYCbCr8 img) =
Packit c600df
    imageToRadiance . ImageRGB8 $ convertImage img
Packit c600df
imageToRadiance (ImageRGB8   img) =
Packit c600df
    imageToRadiance . ImageRGBF $ promoteImage img
Packit c600df
imageToRadiance (ImageRGBF   img) = encodeHDR img
Packit c600df
imageToRadiance (ImageRGBA8  img) =
Packit c600df
    imageToRadiance . ImageRGBF . promoteImage $ dropAlphaLayer img
Packit c600df
imageToRadiance (ImageY8     img) =
Packit c600df
    imageToRadiance . ImageRGB8 $ promoteImage img
Packit c600df
imageToRadiance (ImageYF     img) =
Packit c600df
    imageToRadiance . ImageRGBF $ promoteImage img
Packit c600df
imageToRadiance (ImageYA8    img) =
Packit c600df
    imageToRadiance . ImageRGB8 . promoteImage $ dropAlphaLayer img
Packit c600df
imageToRadiance (ImageY16    img) =
Packit c600df
  imageToRadiance . ImageRGBF $ pixelMap toRgbf img
Packit c600df
    where toRgbf v = PixelRGBF val val val
Packit c600df
            where val = fromIntegral v / 65536.0
Packit c600df
Packit c600df
imageToRadiance (ImageYA16   img) =
Packit c600df
  imageToRadiance . ImageRGBF $ pixelMap toRgbf img
Packit c600df
    where toRgbf (PixelYA16 v _) = PixelRGBF val val val
Packit c600df
            where val = fromIntegral v / 65536.0
Packit c600df
imageToRadiance (ImageRGB16  img) =
Packit c600df
    imageToRadiance . ImageRGBF $ from16toFloat img
Packit c600df
imageToRadiance (ImageRGBA16 img) =
Packit c600df
    imageToRadiance . ImageRGBF $ pixelMap toRgbf img
Packit c600df
    where toRgbf (PixelRGBA16 r g b _) = PixelRGBF (f r) (f g) (f b)
Packit c600df
            where f v = fromIntegral v / 65536.0
Packit c600df
Packit c600df
-- | This function will try to do anything to encode an image
Packit c600df
-- as JPEG, make all color conversion and such. Equivalent
Packit c600df
-- of 'decodeImage' for jpeg encoding
Packit c600df
-- Save Y or YCbCr Jpeg only, all other colorspaces are converted.
Packit c600df
-- To save a RGB or CMYK JPEG file, use the
Packit c600df
-- 'Codec.Picture.Jpg.encodeDirectJpegAtQualityWithMetadata' function
Packit c600df
imageToJpg :: Int -> DynamicImage -> L.ByteString
Packit c600df
imageToJpg quality dynImage =
Packit c600df
    let encodeAtQuality = encodeJpegAtQuality (fromIntegral quality)
Packit c600df
        encodeWithMeta = encodeDirectJpegAtQualityWithMetadata (fromIntegral quality) mempty
Packit c600df
    in case dynImage of
Packit c600df
        ImageYCbCr8 img -> encodeAtQuality img
Packit c600df
        ImageCMYK8  img -> imageToJpg quality . ImageRGB8 $ convertImage img
Packit c600df
        ImageCMYK16 img -> imageToJpg quality . ImageRGB16 $ convertImage img
Packit c600df
        ImageRGB8   img -> encodeAtQuality (convertImage img)
Packit c600df
        ImageRGBF   img -> imageToJpg quality . ImageRGB8 $ toStandardDef img
Packit c600df
        ImageRGBA8  img -> encodeAtQuality (convertImage $ dropAlphaLayer img)
Packit c600df
        ImageYF     img -> imageToJpg quality . ImageY8 $ greyScaleToStandardDef img
Packit c600df
        ImageY8     img -> encodeWithMeta img
Packit c600df
        ImageYA8    img -> encodeWithMeta $ dropAlphaLayer img
Packit c600df
        ImageY16    img -> imageToJpg quality . ImageY8 $ from16to8 img
Packit c600df
        ImageYA16   img -> imageToJpg quality . ImageYA8 $ from16to8 img
Packit c600df
        ImageRGB16  img -> imageToJpg quality . ImageRGB8 $ from16to8 img
Packit c600df
        ImageRGBA16 img -> imageToJpg quality . ImageRGBA8 $ from16to8 img
Packit c600df
Packit c600df
-- | This function will try to do anything to encode an image
Packit c600df
-- as PNG, make all color conversion and such. Equivalent
Packit c600df
-- of 'decodeImage' for PNG encoding
Packit c600df
imageToPng :: DynamicImage -> L.ByteString
Packit c600df
imageToPng (ImageYCbCr8 img) = encodePng (convertImage img :: Image PixelRGB8)
Packit c600df
imageToPng (ImageCMYK8 img)  = encodePng (convertImage img :: Image PixelRGB8)
Packit c600df
imageToPng (ImageCMYK16 img) = encodePng (convertImage img :: Image PixelRGB16)
Packit c600df
imageToPng (ImageRGB8   img) = encodePng img
Packit c600df
imageToPng (ImageRGBF   img) = encodePng $ toStandardDef img
Packit c600df
imageToPng (ImageRGBA8  img) = encodePng img
Packit c600df
imageToPng (ImageY8     img) = encodePng img
Packit c600df
imageToPng (ImageYF     img) = encodePng $ greyScaleToStandardDef img
Packit c600df
imageToPng (ImageYA8    img) = encodePng img
Packit c600df
imageToPng (ImageY16    img) = encodePng img
Packit c600df
imageToPng (ImageYA16   img) = encodePng img
Packit c600df
imageToPng (ImageRGB16  img) = encodePng img
Packit c600df
imageToPng (ImageRGBA16 img) = encodePng img
Packit c600df
Packit c600df
-- | This function will try to do anything to encode an image
Packit c600df
-- as a Tiff, make all color conversion and such. Equivalent
Packit c600df
-- of 'decodeImage' for Tiff encoding
Packit c600df
imageToTiff :: DynamicImage -> L.ByteString
Packit c600df
imageToTiff (ImageYCbCr8 img) = encodeTiff img
Packit c600df
imageToTiff (ImageCMYK8 img)  = encodeTiff img
Packit c600df
imageToTiff (ImageCMYK16 img) = encodeTiff img
Packit c600df
imageToTiff (ImageRGB8   img) = encodeTiff img
Packit c600df
imageToTiff (ImageRGBF   img) = encodeTiff $ toStandardDef img
Packit c600df
imageToTiff (ImageRGBA8  img) = encodeTiff img
Packit c600df
imageToTiff (ImageY8     img) = encodeTiff img
Packit c600df
imageToTiff (ImageYF     img) = encodeTiff $ greyScaleToStandardDef img
Packit c600df
imageToTiff (ImageYA8    img) = encodeTiff $ dropAlphaLayer img
Packit c600df
imageToTiff (ImageY16    img) = encodeTiff img
Packit c600df
imageToTiff (ImageYA16   img) = encodeTiff $ dropAlphaLayer img
Packit c600df
imageToTiff (ImageRGB16  img) = encodeTiff img
Packit c600df
imageToTiff (ImageRGBA16 img) = encodeTiff img
Packit c600df
Packit c600df
-- | This function will try to do anything to encode an image
Packit c600df
-- as bitmap, make all color conversion and such. Equivalent
Packit c600df
-- of 'decodeImage' for Bitmap encoding
Packit c600df
imageToBitmap :: DynamicImage -> L.ByteString
Packit c600df
imageToBitmap (ImageYCbCr8 img) = encodeBitmap (convertImage img :: Image PixelRGB8)
Packit c600df
imageToBitmap (ImageCMYK8  img) = encodeBitmap (convertImage img :: Image PixelRGB8)
Packit c600df
imageToBitmap (ImageCMYK16 img) = imageToBitmap . ImageRGB16 $ convertImage img
Packit c600df
imageToBitmap (ImageRGBF   img) = encodeBitmap $ toStandardDef img
Packit c600df
imageToBitmap (ImageRGB8   img) = encodeBitmap img
Packit c600df
imageToBitmap (ImageRGBA8  img) = encodeBitmap img
Packit c600df
imageToBitmap (ImageY8     img) = encodeBitmap img
Packit c600df
imageToBitmap (ImageYF     img) = encodeBitmap $ greyScaleToStandardDef img
Packit c600df
imageToBitmap (ImageYA8    img) = encodeBitmap (promoteImage img :: Image PixelRGBA8)
Packit c600df
imageToBitmap (ImageY16    img) = imageToBitmap . ImageY8 $ from16to8 img
Packit c600df
imageToBitmap (ImageYA16   img) = imageToBitmap . ImageYA8 $ from16to8 img
Packit c600df
imageToBitmap (ImageRGB16  img) = imageToBitmap . ImageRGB8 $ from16to8 img
Packit c600df
imageToBitmap (ImageRGBA16 img) = imageToBitmap . ImageRGBA8 $ from16to8 img
Packit c600df
Packit c600df
Packit c600df
-- | This function will try to do anything to encode an image
Packit c600df
-- as a gif, make all color conversion and quantization. Equivalent
Packit c600df
-- of 'decodeImage' for gif encoding
Packit c600df
imageToGif :: DynamicImage -> Either String L.ByteString
Packit c600df
imageToGif (ImageYCbCr8 img) = imageToGif . ImageRGB8 $ convertImage img
Packit c600df
imageToGif (ImageCMYK8  img) = imageToGif . ImageRGB8 $ convertImage img
Packit c600df
imageToGif (ImageCMYK16 img) = imageToGif . ImageRGB16 $ convertImage img
Packit c600df
imageToGif (ImageRGBF   img) = imageToGif . ImageRGB8 $ toStandardDef img
Packit c600df
imageToGif (ImageRGB8   img) = encodeGifImageWithPalette indexed pal
Packit c600df
  where (indexed, pal) = palettize defaultPaletteOptions img
Packit c600df
imageToGif (ImageRGBA8  img) = imageToGif . ImageRGB8 $ dropAlphaLayer img
Packit c600df
imageToGif (ImageY8     img) = Right $ encodeGifImage img
Packit c600df
imageToGif (ImageYF     img) = imageToGif . ImageY8 $ greyScaleToStandardDef img
Packit c600df
imageToGif (ImageYA8    img) = imageToGif . ImageY8 $ dropAlphaLayer img
Packit c600df
imageToGif (ImageY16    img) = imageToGif . ImageY8 $ from16to8 img
Packit c600df
imageToGif (ImageYA16   img) = imageToGif . ImageYA8 $ from16to8 img
Packit c600df
imageToGif (ImageRGB16  img) = imageToGif . ImageRGB8 $ from16to8 img
Packit c600df
imageToGif (ImageRGBA16 img) = imageToGif . ImageRGBA8 $ from16to8 img
Packit c600df
Packit c600df
-- | This function will try to do anything to encode an image
Packit c600df
-- as a tga, make all color conversion and quantization. Equivalent
Packit c600df
-- of 'decodeImage' for tga encoding
Packit c600df
imageToTga :: DynamicImage -> L.ByteString
Packit c600df
imageToTga (ImageYCbCr8 img) = encodeTga (convertImage img :: Image PixelRGB8)
Packit c600df
imageToTga (ImageCMYK8  img) = encodeTga (convertImage img :: Image PixelRGB8)
Packit c600df
imageToTga (ImageCMYK16 img) = encodeTga (from16to8 img :: Image PixelRGB8)
Packit c600df
imageToTga (ImageRGBF   img) = encodeTga $ toStandardDef img
Packit c600df
imageToTga (ImageRGB8   img) = encodeTga img
Packit c600df
imageToTga (ImageRGBA8  img) = encodeTga img
Packit c600df
imageToTga (ImageY8     img) = encodeTga img
Packit c600df
imageToTga (ImageYF     img) = encodeTga $ greyScaleToStandardDef img
Packit c600df
imageToTga (ImageYA8    img) = encodeTga (promoteImage img :: Image PixelRGBA8)
Packit c600df
imageToTga (ImageY16    img) = encodeTga (from16to8 img :: Image Pixel8)
Packit c600df
imageToTga (ImageYA16   img) = encodeTga (from16to8 img :: Image PixelRGBA8)
Packit c600df
imageToTga (ImageRGB16  img) = encodeTga (from16to8 img :: Image PixelRGB8)
Packit c600df
imageToTga (ImageRGBA16 img) = encodeTga (from16to8 img :: Image PixelRGBA8)