{-| Module : Gegl.Buffer Description : Functions for Buffer manipulation Copyright : (c) Amedeo Molnár, 2015-2016 License : LGPL-3 Maintainer : nek0@nek0.eu Stability : experimental Portability : POSIX This module contains all functions necessary for manipulate 'GeglBuffer's. Contents is roughly comparable to the functions provided by @gegl-buffer.h@ in gegl-0.3.8. -} {-# LANGUAGE RecordWildCards #-} module GEGL.Buffer ( FFI.GeglBuffer(..) , gegl_buffer_new , gegl_buffer_default_new , gegl_buffer_save , gegl_buffer_load , gegl_buffer_flush , gegl_buffer_create_sub_buffer , gegl_buffer_get_extent , gegl_buffer_set_extent -- | Some convenience functions that operate on the basis of -- 'gegl_buffer_get_extent'. , gegl_buffer_get_x , gegl_buffer_get_y , gegl_buffer_get_height , gegl_buffer_get_width , gegl_buffer_get_pixel_count -- | Returning to main functions , gegl_buffer_set_color , gegl_buffer_set_pattern -- , gegl_buffer_iterator_new , gegl_buffer_clear , gegl_buffer_get ) where import qualified GEGL.FFI.Buffer as FFI import qualified GEGL.FFI.Rectangle as FFI (GeglRectangle(..)) import qualified GEGL.FFI.Color as FFI (GeglColor(..)) import GEGL.Enums (GeglAccessMode, GeglAbyssPolicy) import BABL.Format (PixelFormat, babl_format) import BABL.FFI.Format (BablFormatPtr(..)) import System.Glib.GObject (objectUnref) import Foreign.ForeignPtr import Foreign.Storable (peek) import Foreign.C.String import Foreign.C.Types (CDouble(..), CInt(..)) import Foreign.Ptr (nullPtr, Ptr(..)) import Foreign.Marshal (free) import Foreign.Marshal.Utils (new) import Foreign.Marshal.Alloc (malloc) -- | Create a new 'GeglBuffer'. gegl_buffer_new :: Maybe FFI.GeglRectangle -- ^ Geometry of the buffer. If 'Nothing' is passed -- , the buffer is created empty -> BablFormatPtr -- ^ Pixel format of the buffer -> IO FFI.GeglBuffer gegl_buffer_new mrect (BablFormatPtr format) = do ptr <- case mrect of Just rect -> new rect Nothing -> return nullPtr val <- FFI.GeglBuffer <$> (newForeignPtr objectUnref =<< FFI.c_gegl_buffer_new ptr format) free ptr return val -- | Creates a new 'GeglBuffer', which defaults to an empty buffer with the 'RGBAfloat' format. gegl_buffer_default_new :: IO FFI.GeglBuffer gegl_buffer_default_new = FFI.GeglBuffer <$> (newForeignPtr objectUnref =<< FFI.c_gegl_buffer_new nullPtr nullPtr) -- | Create a new 'GeglBuffer' from a backend. If @Nothing@ is passed as geometry, -- The extent will be inherited from the backend gegl_buffer_new_for_backend :: Maybe FFI.GeglRectangle -- ^ Geometry -> Ptr a -- ^ Backend -> IO FFI.GeglBuffer -- ^ New buffer gegl_buffer_new_for_backend mext backend = do rectPtr <- case mext of Just ext -> new ext Nothing -> return nullPtr buf <- FFI.GeglBuffer <$> (newForeignPtr objectUnref =<< FFI.c_gegl_buffer_new_for_backend rectPtr backend) free rectPtr return buf -- | Open an existing on-disk 'GeglBuffer'. The buffer is opened in a monitored -- state so multiple instances of gegl can share the same buffer. Sets on one -- buffer are reflected in th eother. gegl_buffer_open :: FilePath -- ^ Path to buffer -> IO FFI.GeglBuffer -- ^ The buffer gegl_buffer_open fp = do cfp <- newCString fp ret <- FFI.GeglBuffer <$> (newForeignPtr objectUnref =<< FFI.c_gegl_buffer_open cfp) free cfp return ret -- | Write a 'GeglBuffer' to a file. gegl_buffer_save :: FFI.GeglBuffer -- Buffer to save -> FilePath -- Path where to save -> FFI.GeglRectangle -- Region of interest to write -> IO () gegl_buffer_save (FFI.GeglBuffer fbuf) fp roi = do croi <- new roi cfp <- newCString fp withForeignPtr fbuf $ \buf -> FFI.c_gegl_buffer_save buf cfp croi free croi free cfp -- | Load an existing buffer from disk. gegl_buffer_load :: FilePath -- File path to saved buffer -> IO FFI.GeglBuffer -- Resulting buffer gegl_buffer_load path = do cpath <- newCString path ret <- FFI.GeglBuffer <$> (newForeignPtr objectUnref =<< FFI.c_gegl_buffer_load cpath) free cpath return ret -- | Flush all unsaved data to disk. This is not necessary for shared 'GeglBuffer's -- opened with "gegl_buffer_open" since they auto-sync on writes. gegl_buffer_flush :: FFI.GeglBuffer -- ^ Buffer to flush -> IO () gegl_buffer_flush (FFI.GeglBuffer fbuf) = withForeignPtr fbuf $ \buf -> FFI.c_gegl_buffer_flush buf -- | Create a new sub 'GeglBuffer', that is a view on a larger buffer. gegl_buffer_create_sub_buffer :: FFI.GeglBuffer -- ^ Parent buffer -> FFI.GeglRectangle -- ^ Coordinates of new buffer -> IO FFI.GeglBuffer -- ^ Child buffer gegl_buffer_create_sub_buffer (FFI.GeglBuffer fbuf) rect = do crect <- new rect ret <- withForeignPtr fbuf $ \buf -> FFI.GeglBuffer <$> (newForeignPtr objectUnref =<< FFI.c_gegl_buffer_create_sub_buffer buf crect) free crect return ret -- | Retrieve position and size of the area considered active in a buffer. gegl_buffer_get_extent :: FFI.GeglBuffer -- ^ The buffer -> IO FFI.GeglRectangle -- ^ active area gegl_buffer_get_extent (FFI.GeglBuffer fbuffer) = do rectPtr <- withForeignPtr fbuffer $ \buffer -> FFI.c_gegl_buffer_get_extent buffer rect <- peek rectPtr -- free rectPtr return rect -- | Change postition and size of the area considered active in a buffer. gegl_buffer_set_extent :: FFI.GeglBuffer -- ^ The buffer -> FFI.GeglRectangle -- ^ New extent of the buffer -> IO Bool -- ^ Returns 'True' on success, otherwise 'False' gegl_buffer_set_extent (FFI.GeglBuffer fbuffer) rect = do ptr <- new rect val <- withForeignPtr fbuffer $ \buffer -> FFI.c_gegl_buffer_set_extent buffer ptr free ptr return val -- | get X coordinate of the upper left corner of a buffer gegl_buffer_get_x :: FFI.GeglBuffer -- ^ The buffer -> IO Int gegl_buffer_get_x buffer = do FFI.GeglRectangle{..} <- gegl_buffer_get_extent buffer return rectangleX -- | get Y coordinate of the upper left corner of a buffer gegl_buffer_get_y :: FFI.GeglBuffer -- ^ The buffer -> IO Int gegl_buffer_get_y buffer = do FFI.GeglRectangle{..} <- gegl_buffer_get_extent buffer return rectangleY -- | get height of a buffer gegl_buffer_get_height :: FFI.GeglBuffer -- ^ The buffer -> IO Int gegl_buffer_get_height buffer = do FFI.GeglRectangle{..} <- gegl_buffer_get_extent buffer return rectangleHeight -- | get width of a buffer gegl_buffer_get_width :: FFI.GeglBuffer -- ^ The buffer -> IO Int gegl_buffer_get_width buffer = do FFI.GeglRectangle{..} <- gegl_buffer_get_extent buffer return rectangleWidth -- | get pixel count of a buffer gegl_buffer_get_pixel_count :: FFI.GeglBuffer -- ^ The buffer -> IO Int gegl_buffer_get_pixel_count buffer = do FFI.GeglRectangle{..} <- gegl_buffer_get_extent buffer return $ rectangleWidth * rectangleHeight -- | Sets a region covered by a 'GeglRectangle' to a specified colour. gegl_buffer_set_color :: FFI.GeglBuffer -- ^ The buffer -> FFI.GeglRectangle -- ^ Area of the buffer to fill -> FFI.GeglColor -- ^ The colour to fill with -> IO () gegl_buffer_set_color (FFI.GeglBuffer fbuffer) rect (FFI.GeglColor color) = do rectPtr <- new rect withForeignPtr fbuffer $ \buffer -> FFI.c_gegl_buffer_set_color buffer rectPtr color free rectPtr -- | Fill a region with a repeating pattern. gegl_buffer_set_pattern :: FFI.GeglBuffer -- ^ Target buffer -> FFI.GeglRectangle -- ^ Area of target buffer to fill -> FFI.GeglBuffer -- ^ A buffer to be repeated as pattern -> Double -- ^ X offset -> Double -- ^ Y offset -> IO () gegl_buffer_set_pattern (FFI.GeglBuffer fbuffer) rect (FFI.GeglBuffer fpattern) xoff yoff = do rectPtr <- new rect let (cx, cy) = (CDouble xoff, CDouble yoff) withForeignPtr fbuffer $ \buffer -> withForeignPtr fpattern $ \pattern -> FFI.c_gegl_buffer_set_pattern buffer rectPtr pattern cx cy free rectPtr -- | Clear a provided rectangular region by setting all associated memory to 0. gegl_buffer_clear :: FFI.GeglBuffer -- ^ Target buffer -> FFI.GeglRectangle -- ^ Area to clear -> IO () gegl_buffer_clear (FFI.GeglBuffer fbuf) rect = do rectPtr <- new rect withForeignPtr fbuf $ \buf -> FFI.c_gegl_buffer_clear buf rectPtr free rectPtr -- | Fetch a rectangular linear buffer of pixel data from the 'GeglBuffer', -- convert it if neccessary and push it into a memory location. gegl_buffer_get :: FFI.GeglBuffer -- ^ Buffer to retrieve data from -> Maybe FFI.GeglRectangle -- ^ Coordinates to retrieve data from. If set to -- 'Nothing' the whole buffer is taken. -> Double -- ^ Sampling scale -> Maybe BablFormatPtr -- ^ Format to convert the data to. If set to 'Nothing' -- no conversion is performed. -> Ptr a -- The memory destination to write the data to. -> Int -- Rowstride in bytes or @0@ to compute it -- automatically from format -> GeglAbyssPolicy -- Abyss policy -> IO () gegl_buffer_get (FFI.GeglBuffer fbuf) mrect scale mformat dest stride ap = do rect <- case mrect of Just r -> new r Nothing -> return nullPtr let format = case mformat of Just (BablFormatPtr ptr) -> ptr Nothing -> nullPtr withForeignPtr fbuf $ \buf -> FFI.c_gegl_buffer_get buf rect (CDouble scale) format dest (CInt $ fromIntegral stride) (CInt $ fromIntegral $ fromEnum ap) free rect