packages feed

brillo-juicy-0.2.4: Brillo/Juicy.hs

{-# LANGUAGE TupleSections #-}

module Brillo.Juicy (
  -- * Conversion from JuicyPixels' types to brillo' Picture
  fromDynamicImage,
  fromImageRGBA8,
  fromImageRGB8,
  fromImageY8,
  fromImageYA8,
  fromImageYCbCr8,

  -- * Loading a brillo Picture from a file through JuicyPixels
  loadJuicy,
  loadJuicyWithMetadata,
  loadJuicyJPG,
  loadJuicyPNG,

  -- * From brillo, exported here for convenience
  loadBMP,
)
where

import Brillo.Data.Bitmap (
  BitmapFormat (BitmapFormat),
  PixelFormat (PxRGBA),
  RowOrder (TopToBottom),
  bitmapOfForeignPtr,
  loadBMP,
 )
import Brillo.Data.Picture (Picture)
import Codec.Picture (
  DynamicImage (
    ImageRGB8,
    ImageRGBA8,
    ImageRGBF,
    ImageY8,
    ImageYA8,
    ImageYCbCr8,
    ImageYF
  ),
  Image (..),
  Pixel8,
  PixelRGB8,
  PixelRGBA8,
  PixelYA8,
  PixelYCbCr8,
  readImage,
  readImageWithMetadata,
  readJpeg,
  readPng,
 )
import Codec.Picture.Metadata (Metadatas)
import Codec.Picture.Types (
  ColorConvertible (promoteImage),
  ColorSpaceConvertible (convertImage),
 )
import Data.Vector.Storable (unsafeToForeignPtr)


{-| Tries to convert a 'DynamicImage' from JuicyPixels to a brillo 'Picture'.
All formats except RGBF and YF should successfully yield a 'Picture'.
-}
fromDynamicImage :: DynamicImage -> Maybe Picture
fromDynamicImage (ImageY8 img) = Just $ fromImageY8 img
fromDynamicImage (ImageYA8 img) = Just $ fromImageYA8 img
fromDynamicImage (ImageRGB8 img) = Just $ fromImageRGB8 img
fromDynamicImage (ImageRGBA8 img) = Just $ fromImageRGBA8 img
fromDynamicImage (ImageYCbCr8 img) = Just $ fromImageYCbCr8 img
fromDynamicImage (ImageRGBF _) = Nothing
fromDynamicImage (ImageYF _) = Nothing
fromDynamicImage _ = Nothing


{-| O(N) conversion from 'PixelRGBA8' image to brillo 'Picture',
where N is the number of pixels.
-}
fromImageRGBA8 :: Image PixelRGBA8 -> Picture
fromImageRGBA8 (Image{imageWidth = w, imageHeight = h, imageData = imgDat}) = do
  let (ptr, _, _) = unsafeToForeignPtr imgDat
  bitmapOfForeignPtr w h (BitmapFormat TopToBottom PxRGBA) ptr True
{-# INLINE fromImageRGBA8 #-}


{-| Creation of a brillo 'Picture' by promoting (through 'promoteImage')
the 'PixelRGB8' image to 'PixelRGBA8' and calling 'fromImageRGBA8'.
-}
fromImageRGB8 :: Image PixelRGB8 -> Picture
fromImageRGB8 = fromImageRGBA8 . promoteImage
{-# INLINE fromImageRGB8 #-}


{-| Creation of a brillo 'Picture' by promoting (through 'promoteImage')
the 'PixelY8' image to 'PixelRGBA8' and calling 'fromImageRGBA8'.
-}
fromImageY8 :: Image Pixel8 -> Picture
fromImageY8 = fromImageRGBA8 . promoteImage
{-# INLINE fromImageY8 #-}


{-| Creation of a brillo 'Picture' by promoting (through 'promoteImage')
the 'PixelYA8' image to 'PixelRGBA8' and calling 'fromImageRGBA8'.
-}
fromImageYA8 :: Image PixelYA8 -> Picture
fromImageYA8 = fromImageRGBA8 . promoteImage
{-# INLINE fromImageYA8 #-}


{-| Creation of a brillo 'Picture' by promoting (through 'promoteImage')
the 'PixelYCbCr8' image to 'PixelRGBA8' and calling 'fromImageRGBA8'.
-}
fromImageYCbCr8 :: Image PixelYCbCr8 -> Picture
fromImageYCbCr8 = fromImageRGB8 . convertImage
{-# INLINE fromImageYCbCr8 #-}


{-| Tries to load an image file into a Picture
  using 'readImage' from JuicyPixels.
  It means it'll try to successively read the content
  as an image in the following order,
  until it succeeds (or fails on all of them):
  jpeg, png, bmp, gif, hdr (the last two are not supported)
  This is handy when you don't know
  what format the image contained in the file is encoded with.
  If you know the format in advance,
  use 'loadBMP', 'loadJuicyJPG' or 'loadJuicyPNG'
-}
loadJuicy :: FilePath -> IO (Maybe Picture)
loadJuicy = loadWith readImage
{-# INLINE loadJuicy #-}


loadJuicyWithMetadata :: FilePath -> IO (Maybe (Picture, Metadatas))
loadJuicyWithMetadata = loadWithMetadata readImageWithMetadata
{-# INLINE loadJuicyWithMetadata #-}


loadJuicyJPG :: FilePath -> IO (Maybe Picture)
loadJuicyJPG = loadWith readJpeg
{-# INLINE loadJuicyJPG #-}


loadJuicyPNG :: FilePath -> IO (Maybe Picture)
loadJuicyPNG = loadWith readPng
{-# INLINE loadJuicyPNG #-}


loadWith
  :: (FilePath -> IO (Either String DynamicImage))
  -> FilePath
  -> IO (Maybe Picture)
loadWith reader fp = do
  eImg <- reader fp
  return $ either (const Nothing) fromDynamicImage eImg


loadWithMetadata
  :: (FilePath -> IO (Either String (DynamicImage, Metadatas)))
  -> FilePath
  -> IO (Maybe (Picture, Metadatas))
loadWithMetadata reader fp = do
  eImg <- reader fp
  return $
    either
      (const Nothing)
      (\(x, y) -> fmap (,y) (fromDynamicImage x))
      eImg