-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | A pure haskell drawing engine. -- @package Rasterific @version 0.6 -- | This module is a reduction of the Linear package from Edward -- Kmett to match just the need of Rasterific. -- -- If the flag embed_linear is disabled, this module is just a -- reexport from the real linear package. module Graphics.Rasterific.Linear -- | A 2-dimensional vector -- --
-- >>> pure 1 :: V2 Int -- V2 1 1 ---- --
-- >>> V2 1 2 + V2 3 4 -- V2 4 6 ---- --
-- >>> V2 1 2 * V2 3 4 -- V2 3 8 ---- --
-- >>> sum (V2 1 2) -- 3 --data V2 a V2 :: !a -> !a -> V2 a -- | A 1-dimensional vector newtype V1 a V1 :: a -> V1 a -- | A vector is an additive group with additional structure. class Functor f => Additive f zero :: (Additive f, Num a) => f a (^+^) :: (Additive f, Num a) => f a -> f a -> f a (^-^) :: (Additive f, Num a) => f a -> f a -> f a lerp :: (Additive f, Num a) => a -> f a -> f a -> f a -- | Provides a fairly subjective test to see if a quantity is near zero. -- --
-- >>> nearZero (1e-11 :: Double) -- False ---- --
-- >>> nearZero (1e-17 :: Double) -- True ---- --
-- >>> nearZero (1e-5 :: Float) -- False ---- --
-- >>> nearZero (1e-7 :: Float) -- True --class Num a => Epsilon a nearZero :: Epsilon a => a -> Bool -- | Free and sparse inner product/metric spaces. class Additive f => Metric f where quadrance v = dot v v qd f g = quadrance (f ^-^ g) distance f g = norm (f ^-^ g) norm v = sqrt (quadrance v) signorm v = fmap (/ m) v where m = norm v dot :: (Metric f, Num a) => f a -> f a -> a quadrance :: (Metric f, Num a) => f a -> a qd :: (Metric f, Num a) => f a -> f a -> a distance :: (Metric f, Floating a) => f a -> f a -> a norm :: (Metric f, Floating a) => f a -> a signorm :: (Metric f, Floating a) => f a -> f a -- | Compute the right scalar product -- --
-- >>> V2 3 4 ^* 2 -- V2 6 8 --(^*) :: (Functor f, Num a) => f a -> a -> f a -- | Compute division by a scalar on the right. (^/) :: (Functor f, Floating a) => f a -> a -> f a -- | Normalize a Metric functor to have unit norm. This -- function does not change the functor if its norm is 0 or 1. normalize :: (Floating a, Metric f, Epsilon a) => f a -> f a instance Eq a => Eq (V2 a) instance Show a => Show (V2 a) instance Eq a => Eq (V1 a) instance Show a => Show (V1 a) instance Metric V2 instance Additive V1 instance Additive V2 instance Epsilon a => Epsilon (V2 a) instance Epsilon Double instance Epsilon Float instance Applicative V1 instance Applicative V2 instance Functor V1 instance Num a => Num (V2 a) instance Functor V2 -- | This module provide some helpers in order to perform basic geometric -- transformation on the drawable primitives. -- -- You can combine the transformation is mappend or the -- `(<>)` operator from Data.Monoid . module Graphics.Rasterific.Transformations -- | Represent a 3*3 matrix for homogenous coordinates. -- --
-- | A C E | -- | B D F | -- | 0 0 1 | --data Transformation Transformation :: {-# UNPACK #-} !Float -> {-# UNPACK #-} !Float -> {-# UNPACK #-} !Float -> {-# UNPACK #-} !Float -> {-# UNPACK #-} !Float -> {-# UNPACK #-} !Float -> Transformation _transformA :: Transformation -> {-# UNPACK #-} !Float _transformC :: Transformation -> {-# UNPACK #-} !Float -- | X translation _transformE :: Transformation -> {-# UNPACK #-} !Float _transformB :: Transformation -> {-# UNPACK #-} !Float _transformD :: Transformation -> {-# UNPACK #-} !Float -- | Y translation _transformF :: Transformation -> {-# UNPACK #-} !Float -- | Effectively transform a point given a transformation. applyTransformation :: Transformation -> Point -> Point -- | Effectively transform a vector given a transformation. The translation -- part won't be applied. applyVectorTransformation :: Transformation -> Vector -> Vector -- | Perform a translation of the given primitives. -- --
-- fill . transform (applyTransformation $ translate (V2 100 100)) -- $ rectangle (V2 40 40) 40 40 ---- translate :: Vector -> Transformation -- | Perform a scaling of the given primitives. -- --
-- fill . transform (applyTransformation $ scale 2 2) -- $ rectangle (V2 40 40) 40 40 ---- scale :: Float -> Float -> Transformation -- | Create a transformation representing a rotation on the plane. -- --
-- fill . transform (applyTransformation $ rotate 0.2) -- $ rectangle (V2 40 40) 120 120 ---- rotate :: Float -> Transformation -- | Create a transformation representing a rotation on the plane. The -- rotation center is given in parameter -- --
-- fill . transform (applyTransformation $ rotateCenter 0.2 (V2 200 200)) -- $ rectangle (V2 40 40) 120 120 ---- rotateCenter :: Float -> Point -> Transformation -- | Skew transformation along the X axis. -- --
-- fill . transform (applyTransformation $ skewX 0.3) -- $ rectangle (V2 50 50) 80 80 ---- skewX :: Float -> Transformation -- | Skew transformation along the Y axis. -- --
-- fill . transform (applyTransformation $ skewY 0.3) -- $ rectangle (V2 50 50) 80 80 ---- skewY :: Float -> Transformation -- | Given a new X-acis vector, create a rotation matrix to get into this -- new base, assuming an Y basis orthonormal to the X one. toNewXBase :: Vector -> Transformation -- | Inverse a transformation (if possible) inverseTransformation :: Transformation -> Maybe Transformation instance Eq Transformation instance Show Transformation instance Monoid Transformation -- | This module provide lenses compatible with the lens module but -- without the dependency to it. module Graphics.Rasterific.Lenses -- | Line origin point. lineX0 :: Lens' Line Point -- | Line end point. lineX1 :: Lens' Line Point -- | Traverse all the points of a line. linePoints :: Traversal' Line Point -- | Quadratic bezier starting point. bezX0 :: Lens' Bezier Point -- | bezier control point. bezX1 :: Lens' Bezier Point -- | bezier end point. bezX2 :: Lens' Bezier Point -- | Traversal of all the bezier's points. bezierPoints :: Traversal' Bezier Point -- | Cubic bezier first point cbezX0 :: Lens' CubicBezier Point -- | Cubic bezier first control point. cbezX1 :: Lens' CubicBezier Point -- | Cubic bezier second control point. cbezX2 :: Lens' CubicBezier Point -- | Cubic bezier last point. cbezX3 :: Lens' CubicBezier Point -- | Traversal of all the points of the cubic bezier. cubicBezierPoints :: Traversal' CubicBezier Point -- | Traverse all the points defined in the primitive. primitivePoints :: Traversal' Primitive Point -- | Traversal of all the points of a path pathCommandPoints :: Traversal' PathCommand Point -- | Traversal of all the points in a path. pathPoints :: Traversal' Path Point -- | Does it look familiar? yes it's the official Lens type. type Lens s t a b = forall f. Functor f => (a -> f b) -> s -> f t -- | Try to match the Lens' type alias. type Lens' s a = Lens s s a a -- | Traversal type, matched to the one of the lens package. type Traversal s t a b = forall f. Applicative f => (a -> f b) -> s -> f t type Traversal' s a = Traversal s s a a -- | This module provide helper functions to create outline of shapes. module Graphics.Rasterific.Outline -- | Type alias just to get more meaningful type signatures type StrokeWidth = Float -- | This function will create the outline of a given geometry given a -- path. You can then stroke it. -- --
-- stroke 3 (JoinMiter 0) (CapStraight 0, CapStraight 0) $ -- strokize 40 JoinRound (CapRound, CapRound) $ -- CubicBezier (V2 40 160) (V2 40 40) -- (V2 160 40) (V2 160 160) ---- strokize :: Geometry geom => StrokeWidth -> Join -> (Cap, Cap) -> geom -> [Primitive] -- | Create a list of outlines corresponding to all the dashed elements. -- They can be then stroked -- --
-- mapM_ (stroke 3 (JoinMiter 0) (CapStraight 0, CapStraight 0)) $ -- dashedStrokize 0 [10, 5] -- 40 JoinRound (CapStraight 0, CapStraight 0) $ -- CubicBezier (V2 40 160) (V2 40 40) (V2 160 40) (V2 160 160) ---- dashedStrokize :: Geometry geom => Float -> DashPattern -> StrokeWidth -> Join -> (Cap, Cap) -> geom -> [[Primitive]] -- | Return an approximation of the length of a given path. It's results is -- not precise but should be enough for rough calculations approximatePathLength :: Path -> Float -- | This module implements drawing primitives to draw directly into the -- output texture, without generating an intermediate scene -- representation. -- -- If you need to draw complex scenes or plot an important set of data, -- this is the module you should use. The downside is that you must -- specify everything you need at each draw call, there is no API to help -- you propagate constants. -- -- The "stroking" must be done using the functions of the Outline -- module. module Graphics.Rasterific.Immediate -- | Monad used to describe the drawing context. type DrawContext m px = StateT (MutableImage (PrimState m) px) m -- | Reify a filling function call, to be able to manipulate them in a -- simpler fashion. data DrawOrder px DrawOrder :: ![[Primitive]] -> !(Texture px) -> !FillMethod -> !(Maybe (Texture (PixelBaseComponent px))) -> DrawOrder px -- | Primitives to be filled. _orderPrimitives :: DrawOrder px -> ![[Primitive]] -- | Texture for the filled primitives. _orderTexture :: DrawOrder px -> !(Texture px) -- | How to fill the primitives. _orderFillMethod :: DrawOrder px -> !FillMethod -- | Optional mask used for clipping. _orderMask :: DrawOrder px -> !(Maybe (Texture (PixelBaseComponent px))) -- | Transform back a low level drawing order to a more high level Drawing orderToDrawing :: DrawOrder px -> Drawing px () -- | Start an image rendering. See fillWithTexture for an usage -- example. This function can work with either IO or ST. runDrawContext :: (PrimMonad m, RenderablePixel px) => Int -> Int -> px -> DrawContext m px () -> m (Image px) -- | Fill some geometry using a composition mask for visibility. -- --
-- immediateDrawMaskExample :: Image PixelRGBA8 -- immediateDrawMaskExample = runST $ -- runDrawContext 200 200 (PixelRGBA8 0 0 0 255) $ -- forM_ [1 .. 10] $ \ix -> -- fillWithTextureAndMask FillWinding texture mask $ -- rectangle (V2 10 (ix * 18 - 5)) 180 13 -- where -- texture = uniformTexture $ PixelRGBA8 0 0x86 0xc1 255 -- mask = sampledImageTexture -- $ runST -- $ runDrawContext 200 200 0 -- $ fillWithTexture FillWinding (uniformTexture 255) maskGeometry -- -- maskGeometry = strokize 15 JoinRound (CapRound, CapRound) -- $ circle (V2 100 100) 80 ---- fillWithTextureAndMask :: (PrimMonad m, RenderablePixel px, MonadState (MutableImage (PrimState m) px) (DrawContext m px)) => FillMethod -> Texture px -> Texture (PixelBaseComponent px) -> [Primitive] -> DrawContext m px () -- | Fill some geometry. -- --
-- immediateDrawExample :: Image PixelRGBA8 -- immediateDrawExample = runST $ -- runDrawContext 200 200 (PixelRGBA8 0 0 0 0) $ -- fillWithTexture FillWinding texture geometry -- where -- circlePrimitives = circle (V2 100 100) 50 -- geometry = strokize 4 JoinRound (CapRound, CapRound) circlePrimitives -- texture = uniformTexture (PixelRGBA8 255 255 255 255) ---- fillWithTexture :: (PrimMonad m, RenderablePixel px, MonadState (MutableImage (PrimState m) px) (DrawContext m px)) => FillMethod -> Texture px -> [Primitive] -> DrawContext m px () -- | Render the drawing orders on the canvas. fillOrder :: (PrimMonad m, RenderablePixel px) => DrawOrder px -> DrawContext m px () -- | Helper function transforming text range to draw order. textToDrawOrders :: Dpi -> Texture px -> Point -> [TextRange px] -> [DrawOrder px] transformOrder :: (Point -> Point) -> DrawOrder px -> DrawOrder px instance Transformable (DrawOrder px) instance PlaneBoundable (DrawOrder px) -- | This module help the walking of path of any shape, being able to -- return the current position and the actual orientation. module Graphics.Rasterific.PathWalker -- | The walking transformer monad. data PathWalkerT m a -- | Simpler alias if monad transformers are not needed. type PathWalker a = PathWalkerT Identity a -- | Callback function in charge to transform the DrawOrder given the -- transformation to place it on the path. type PathDrawer m px = Transformation -> PlaneBound -> DrawOrder px -> m () -- | Create a path walker from a given path runPathWalking :: Monad m => Path -> PathWalkerT m a -> m a -- | Advance by the given amount of pixels on the path. advanceBy :: Monad m => Float -> PathWalkerT m () -- | Obtain the current position if we are still on the path, if not, -- return Nothing. currentPosition :: Monad m => PathWalkerT m (Maybe Point) -- | Obtain the current tangeant of the path if we're still on it. Return -- Nothing otherwise. currentTangeant :: Monad m => PathWalkerT m (Maybe Vector) -- | This function is the workhorse of the placement, it will walk the path -- and calculate the appropriate transformation for every order. drawOrdersOnPath :: Monad m => PathDrawer m px -> Float -> Float -> Path -> [DrawOrder px] -> m () instance Monad m => Monad (PathWalkerT m) instance (Monad m, Functor m) => Applicative (PathWalkerT m) instance Functor m => Functor (PathWalkerT m) instance MonadTrans PathWalkerT -- | Main module of Rasterific, an Haskell rasterization engine. -- -- Creating an image is rather simple, here is a simple example of a -- drawing and saving it in a PNG file: -- --
-- import Codec.Picture( PixelRGBA8( .. ), writePng ) -- import Graphics.Rasterific -- import Graphics.Rasterific.Texture -- -- main :: IO () -- main = do -- let white = PixelRGBA8 255 255 255 255 -- drawColor = PixelRGBA8 0 0x86 0xc1 255 -- recColor = PixelRGBA8 0xFF 0x53 0x73 255 -- img = renderDrawing 400 200 white $ -- withTexture (uniformTexture drawColor) $ do -- fill $ circle (V2 0 0) 30 -- stroke 4 JoinRound (CapRound, CapRound) $ -- circle (V2 400 200) 40 -- withTexture (uniformTexture recColor) . -- fill $ rectangle (V2 100 100) 200 100 -- -- writePng "yourimage.png" img ---- -- -- The coordinate system is the picture classic one, with the origin in -- the upper left corner; with the y axis growing to the bottom and the x -- axis growing to the right: -- module Graphics.Rasterific -- | Fill some geometry. The geometry should be "looping", ie. the last -- point of the last primitive should be equal to the first point of the -- first primitive. -- -- The primitive should be connected. -- --
-- fill $ circle (V2 100 100) 75 ---- fill :: Geometry geom => geom -> Drawing px () -- | This function let you choose how to fill the primitives in case of -- self intersection. See FillMethod documentation for more -- information. fillWithMethod :: Geometry geom => FillMethod -> geom -> Drawing px () -- | Will stroke geometry with a given stroke width. The elements should be -- connected -- --
-- stroke 5 JoinRound (CapRound, CapRound) $ circle (V2 100 100) 75 ---- stroke :: Geometry geom => Float -> Join -> (Cap, Cap) -> geom -> Drawing px () -- | With stroke geometry with a given stroke width, using a dash pattern. -- --
-- dashedStroke [5, 10, 5] 3 JoinRound (CapRound, CapStraight 0) $ -- line (V2 0 100) (V2 200 100) ---- dashedStroke :: Geometry geom => DashPattern -> Float -> Join -> (Cap, Cap) -> geom -> Drawing px () -- | With stroke geometry with a given stroke width, using a dash pattern. -- The offset is there to specify the starting point into the pattern, -- the value can be negative. -- --
-- dashedStrokeWithOffset 3 [5, 10, 5] 3 JoinRound (CapRound, CapStraight 0) $ -- line (V2 0 100) (V2 200 100) ---- dashedStrokeWithOffset :: Geometry geom => Float -> DashPattern -> Float -> Join -> (Cap, Cap) -> geom -> Drawing px () -- | Draw a string at a given position. Text printing imply loading a font, -- there is no default font (yet). Below an example of font rendering -- using a font installed on Microsoft Windows. -- --
-- import Graphics.Text.TrueType( loadFontFile ) -- import Codec.Picture( PixelRGBA8( .. ), writePng ) -- import Graphics.Rasterific -- import Graphics.Rasterific.Texture -- -- main :: IO () -- main = do -- fontErr <- loadFontFile "test_fonts/DejaVuSans.ttf" -- case fontErr of -- Left err -> putStrLn err -- Right font -> -- writePng "text_example.png" . -- renderDrawing 300 70 (PixelRGBA8 255 255 255 255) -- . withTexture (uniformTexture $ PixelRGBA8 0 0 0 255) $ -- printTextAt font (PointSize 12) (V2 20 40) -- "A simple text test!" ---- -- -- You can use any texture, like a gradient while rendering text. printTextAt :: Font -> PointSize -> Point -> String -> Drawing px () -- | Print complex text, using different texture font and point size for -- different parts of the text. -- --
-- let blackTexture = -- Just . uniformTexture $ PixelRGBA8 0 0 0 255 -- redTexture = -- Just . uniformTexture $ PixelRGBA8 255 0 0 255 -- in -- printTextRanges (V2 20 40) -- [ TextRange font1 (PointSize 12) "A complex " blackTexture -- , TextRange font2 (PointSize 8) "text test" redTexture] ---- printTextRanges :: Point -> [TextRange px] -> Drawing px () -- | Define the texture applyied to all the children draw call. -- --
-- withTexture (uniformTexture $ PixelRGBA8 0 0x86 0xc1 255) $ do -- fill $ circle (V2 50 50) 20 -- fill $ circle (V2 100 100) 20 -- withTexture (uniformTexture $ PixelRGBA8 0xFF 0x53 0x73 255) -- $ circle (V2 150 150) 20 ---- withTexture :: Texture px -> Drawing px () -> Drawing px () -- | Draw some geometry using a clipping path. -- --
-- withClipping (fill $ circle (V2 100 100) 75) $ -- mapM_ (stroke 7 JoinRound (CapRound, CapRound)) -- [line (V2 0 yf) (V2 200 (yf + 10)) -- | y <- [5 :: Int, 17 .. 200] -- , let yf = fromIntegral y ] ---- withClipping :: (forall innerPixel. Drawing innerPixel ()) -> Drawing px () -> Drawing px () -- | Will render the whole subaction with a given group opacity, after each -- element has been rendered. That means that completly opaque -- overlapping shapes will be rendered transparently, not one after -- another. -- --
-- withTexture (uniformTexture $ PixelRGBA8 0xFF 0x53 0x73 255) $ -- stroke 3 JoinRound (CapRound, CapRound) $ -- line (V2 0 100) (V2 200 100) -- -- withGroupOpacity 128 $ do -- withTexture (uniformTexture $ PixelRGBA8 0 0x86 0xc1 255) . -- fill $ circle (V2 70 100) 60 -- withTexture (uniformTexture $ PixelRGBA8 0xff 0xf4 0xc1 255) . -- fill $ circle (V2 120 100) 60 ---- -- -- To be compared to the item opacity -- --
-- withTexture (uniformTexture $ PixelRGBA8 0xFF 0x53 0x73 255) $ -- stroke 3 JoinRound (CapRound, CapRound) $ -- line (V2 0 100) (V2 200 100) -- withTexture (uniformTexture $ PixelRGBA8 0 0x86 0xc1 128) . -- fill $ circle (V2 70 100) 60 -- withTexture (uniformTexture $ PixelRGBA8 0xff 0xf4 0xc1 128) . -- fill $ circle (V2 120 100) 60 ---- withGroupOpacity :: Pixel px => PixelBaseComponent px -> Drawing px () -> Drawing px () -- | Draw all the sub drawing commands using a transformation. withTransformation :: Transformation -> Drawing px () -> Drawing px () -- | This command allows you to draw primitives on a given curve, for -- example, you can draw text on a curve: -- --
-- let path = Path (V2 100 180) False -- [PathCubicBezierCurveTo (V2 20 20) (V2 170 20) (V2 300 200)] in -- stroke 3 JoinRound (CapStraight 0, CapStraight 0) path -- withTexture (uniformTexture $ PixelRGBA8 0 0 0 255) $ -- withPathOrientation path 0 $ -- printTextAt font (PointSize 24) (V2 0 0) "Text on path" ---- -- -- You can note that the position of the baseline match the size of the -- characters. -- -- You are not limited to text drawing while using this function, you can -- draw arbitrary geometry like in the following example: -- --
-- let path = Path (V2 100 180) False -- [PathCubicBezierCurveTo (V2 20 20) (V2 170 20) (V2 300 200)] -- withTexture (uniformTexture $ PixelRGBA8 0 0 0 255) $ -- stroke 3 JoinRound (CapStraight 0, CapStraight 0) path -- -- withPathOrientation path 0 $ do -- printTextAt font (PointSize 24) (V2 0 0) "TX" -- fill $ rectangle (V2 (-10) (-10)) 30 20 -- fill $ rectangle (V2 45 0) 10 20 -- fill $ rectangle (V2 60 (-10)) 20 20 -- fill $ rectangle (V2 100 (-15)) 20 50 ---- withPathOrientation :: Path -> Float -> Drawing px () -> Drawing px () -- | Structure defining how to render a text range data TextRange px TextRange :: Font -> PointSize -> String -> Maybe (Texture px) -> TextRange px -- | Font used during the rendering _textFont :: TextRange px -> Font -- | Size of the text (in pixels) _textSize :: TextRange px -> PointSize -- | Text to draw | Texture to use for drawing, if Nothing, the currently -- active texture is used. _text :: TextRange px -> String _textTexture :: TextRange px -> Maybe (Texture px) -- | Font size expressed in points. You must convert size expressed in -- pixels to point using the DPI information. See pixelSizeInPointAtDpi newtype PointSize :: * PointSize :: Float -> PointSize getPointSize :: PointSize -> Float -- | This constraint ensure that a type is a pixel and we're allowed to -- modulate it's color components generically. type ModulablePixel px = (Pixel px, PackeablePixel px, Storable (PackedRepresentation px), Modulable (PixelBaseComponent px)) -- | This constraint tells us that pixel component must also be pixel and -- be the "bottom" of component, we cannot go further than a -- PixelBaseComponent level. -- -- All pixel instances of JuicyPixels should be usable. type RenderablePixel px = (ModulablePixel px, Pixel (PixelBaseComponent px), PackeablePixel (PixelBaseComponent px), Num (PackedRepresentation px), Num (PackedRepresentation (PixelBaseComponent px)), Storable (PackedRepresentation (PixelBaseComponent px)), PixelBaseComponent (PixelBaseComponent px) ~ (PixelBaseComponent px)) -- | Function to call in order to start the image creation. Tested pixels -- type are PixelRGBA8 and Pixel8, pixel types in other colorspace will -- probably produce weird results. Default DPI is 96 renderDrawing :: RenderablePixel px => Int -> Int -> px -> Drawing px () -> Image px -- | Function to call in order to start the image creation. Tested pixels -- type are PixelRGBA8 and Pixel8, pixel types in other colorspace will -- probably produce weird results. renderDrawingAtDpi :: RenderablePixel px => Int -> Int -> Dpi -> px -> Drawing px () -> Image px renderDrawingAtDpiToPDF :: Int -> Int -> Dpi -> Drawing PixelRGBA8 () -> ByteString renderOrdersAtDpiToPdf :: Int -> Int -> Dpi -> [DrawOrder PixelRGBA8] -> ByteString -- | Transform a path description into a list of renderable primitives. pathToPrimitives :: Path -> [Primitive] -- | Reification of texture type data Texture px -- | Monad used to record the drawing actions. type Drawing px = F (DrawCommand px) -- | Typeclass intented at pixel value modulation. May be throwed out soon. class (Ord a, Num a) => Modulable a where coverageModulate c a = (clamped, fullValue - clamped) where clamped = modulate a c -- | A 2-dimensional vector -- --
-- >>> pure 1 :: V2 Int -- V2 1 1 ---- --
-- >>> V2 1 2 + V2 3 4 -- V2 4 6 ---- --
-- >>> V2 1 2 * V2 3 4 -- V2 3 8 ---- --
-- >>> sum (V2 1 2) -- 3 --data V2 a V2 :: !a -> !a -> V2 a -- | Represent a point type Point = V2 Float -- | Represent a vector type Vector = V2 Float -- | Describe a cubic bezier spline, described using 4 points. -- --
-- stroke 4 JoinRound (CapRound, CapRound) $ -- CubicBezier (V2 0 10) (V2 205 250) (V2 (-10) 250) (V2 160 35) ---- data CubicBezier CubicBezier :: {-# UNPACK #-} !Point -> {-# UNPACK #-} !Point -> {-# UNPACK #-} !Point -> {-# UNPACK #-} !Point -> CubicBezier -- | Origin point, the spline will pass through it. _cBezierX0 :: CubicBezier -> {-# UNPACK #-} !Point -- | First control point of the cubic bezier curve. _cBezierX1 :: CubicBezier -> {-# UNPACK #-} !Point -- | Second control point of the cubic bezier curve. _cBezierX2 :: CubicBezier -> {-# UNPACK #-} !Point -- | End point of the cubic bezier curve _cBezierX3 :: CubicBezier -> {-# UNPACK #-} !Point -- | Describe a simple 2D line between two points. -- --
-- fill [ Line (V2 10 10) (V2 190 10) -- , Line (V2 190 10) (V2 95 170) -- , Line (V2 95 170) (V2 10 10)] ---- data Line Line :: {-# UNPACK #-} !Point -> {-# UNPACK #-} !Point -> Line -- | Origin point _lineX0 :: Line -> {-# UNPACK #-} !Point -- | End point _lineX1 :: Line -> {-# UNPACK #-} !Point -- | Describe a quadratic bezier spline, described using 3 points. -- --
-- fill [Bezier (V2 10 10) (V2 200 50) (V2 200 100) -- ,Bezier (V2 200 100) (V2 150 200) (V2 120 175) -- ,Bezier (V2 120 175) (V2 30 100) (V2 10 10)] ---- data Bezier Bezier :: {-# UNPACK #-} !Point -> {-# UNPACK #-} !Point -> {-# UNPACK #-} !Point -> Bezier -- | Origin points, the spline will pass through it. _bezierX0 :: Bezier -> {-# UNPACK #-} !Point -- | Control point, the spline won't pass on it. _bezierX1 :: Bezier -> {-# UNPACK #-} !Point -- | End point, the spline will pass through it. _bezierX2 :: Bezier -> {-# UNPACK #-} !Point -- | This datatype gather all the renderable primitives, they are kept -- separated otherwise to allow specialization on some specific -- algorithms. You can mix the different primitives in a single call : -- --
-- fill [ toPrim $ CubicBezier (V2 50 20) (V2 90 60) -- (V2 5 100) (V2 50 140) -- , toPrim $ Line (V2 50 140) (V2 120 80) -- , toPrim $ Line (V2 120 80) (V2 50 20) ] ---- data Primitive -- | Primitive used for lines LinePrim :: !Line -> Primitive -- | Primitive used for quadratic beziers curves BezierPrim :: !Bezier -> Primitive -- | Primitive used for cubic bezier curve CubicBezierPrim :: !CubicBezier -> Primitive -- | Describe a path in a way similar to many graphical packages, using a -- "pen" position in memory and reusing it for the next "move" For -- example the example from Primitive could be rewritten: -- --
-- fill $ Path (V2 50 20) True -- [ PathCubicBezierCurveTo (V2 90 60) (V2 5 100) (V2 50 140) -- , PathLineTo (V2 120 80) ] ---- data Path Path :: Point -> Bool -> [PathCommand] -> Path -- | Origin of the point, equivalent to the first "move" command. _pathOriginPoint :: Path -> Point -- | Tell if we must close the path. _pathClose :: Path -> Bool -- | List of commands in the path _pathCommand :: Path -> [PathCommand] -- | Actions to create a path data PathCommand -- | Draw a line from the current point to another point PathLineTo :: Point -> PathCommand -- | Draw a quadratic bezier curve from the current point through the -- control point to the end point. PathQuadraticBezierCurveTo :: Point -> Point -> PathCommand -- | Draw a cubic bezier curve using 2 control points. PathCubicBezierCurveTo :: Point -> Point -> Point -> PathCommand -- | Generalizing constructors of the Primitive type to work -- generically. class Primitivable a toPrim :: Primitivable a => a -> Primitive -- | All the rasterization works on lists of primitives, in order to ease -- the use of the library, the Geometry type class provides conversion -- facility, which help generalising the geometry definition and avoid -- applying Primitive constructor. -- -- Also streamline the Path conversion. class Geometry a where listToPrims = concatMap toPrimitives . toList toPrimitives :: Geometry a => a -> [Primitive] listToPrims :: (Geometry a, Foldable f) => f a -> [Primitive] -- | This typeclass is there to help transform the geometry, by applying a -- transformation on every point of a geometric element. class Transformable a transform :: Transformable a => (Point -> Point) -> a -> a -- | Typeclass helper gathering all the points of a given geometry. class PointFoldable a foldPoints :: PointFoldable a => (b -> Point -> b) -> b -> a -> b -- | Class used to calculate bounds of various geometrical primitives. The -- calculated is precise, the bounding should be minimal with respect -- with drawn curve. class PlaneBoundable a planeBounds :: PlaneBoundable a => a -> PlaneBound -- | Represent the minimal axis aligned rectangle in which some primitives -- can be drawn. Should fit to bezier curve and not use directly their -- control points. data PlaneBound PlaneBound :: !Point -> !Point -> PlaneBound -- | Corner upper left of the bounding box of the considered primitives. _planeMinBound :: PlaneBound -> !Point -- | Corner lower right of the bounding box of the considered primitives. _planeMaxBound :: PlaneBound -> !Point -- | Extract the width of the bounds boundWidth :: PlaneBound -> Float -- | Extract the height of the bound boundHeight :: PlaneBound -> Float -- | Extract the position of the lower left corner of the bounds. boundLowerLeftCorner :: PlaneBound -> Point -- | Return a simple line ready to be stroked. -- --
-- stroke 17 JoinRound (CapRound, CapRound) $ -- line (V2 10 10) (V2 180 170) ---- line :: Point -> Point -> [Primitive] -- | Generate a list of primitive representing a rectangle -- --
-- fill $ rectangle (V2 30 30) 150 100 ---- rectangle :: Point -> Float -> Float -> [Primitive] -- | Generate a list of primitive representing a rectangle with rounded -- corner. -- --
-- fill $ roundedRectangle (V2 10 10) 150 150 20 10 ---- roundedRectangle :: Point -> Float -> Float -> Float -> Float -> [Primitive] -- | Generate a list of primitive representing a circle. -- --
-- fill $ circle (V2 100 100) 75 ---- circle :: Point -> Float -> [Primitive] -- | Generate a list of primitive representing an ellipse. -- --
-- fill $ ellipse (V2 100 100) 75 30 ---- ellipse :: Point -> Float -> Float -> [Primitive] -- | Generate a strokable line out of points list. Just an helper around -- lineFromPath. -- --
-- stroke 4 JoinRound (CapRound, CapRound) $ -- polyline [V2 10 10, V2 100 70, V2 190 190] ---- polyline :: [Point] -> [Primitive] -- | Generate a fillable polygon out of points list. Similar to the -- polyline function, but close the path. -- --
-- fill $ polygon [V2 30 30, V2 100 70, V2 80 170] ---- polygon :: [Point] -> [Primitive] -- | Draw an image with the desired size -- --
-- drawImageAtSize textureImage 2 (V2 30 30) 128 128 ---- drawImageAtSize :: (Pixel px, Modulable (PixelBaseComponent px)) => Image px -> StrokeWidth -> Point -> Float -> Float -> Drawing px () -- | Simply draw an image into the canvas. Take into account any previous -- transformation performed on the geometry. -- --
-- drawImage textureImage 0 (V2 30 30) ---- drawImage :: ModulablePixel px => Image px -> StrokeWidth -> Point -> Drawing px () -- | This function perform an optimisation, it will render a drawing to an -- image interanlly and create a new order to render this image instead -- of the geometry, effectively cuting the geometry generation part. -- -- It can save execution time when drawing complex elements multiple -- times. cacheDrawing :: RenderablePixel px => Int -> Int -> Dpi -> Drawing px () -> Drawing px () -- | Clip the geometry to a rectangle. clip :: Point -> Point -> Primitive -> Container Primitive -- | Create a list of bezier patch from a list of points, -- --
-- bezierFromPath [a, b, c, d, e] == [Bezier a b c, Bezier c d e] -- bezierFromPath [a, b, c, d, e, f] == [Bezier a b c, Bezier c d e] -- bezierFromPath [a, b, c, d, e, f, g] == -- [Bezier a b c, Bezier c d e, Bezier e f g] --bezierFromPath :: [Point] -> [Bezier] -- | Transform a list a point to a list of lines -- --
-- lineFromPath [a, b, c, d] = [Line a b, Line b c, Line c d] --lineFromPath :: [Point] -> [Line] -- | Create a list of cubic bezier patch from a list of points. -- --
-- cubicBezierFromPath [a, b, c, d, e] = [CubicBezier a b c d] -- cubicBezierFromPath [a, b, c, d, e, f, g] = -- [CubicBezier a b c d, CubicBezier d e f g] --cubicBezierFromPath :: [Point] -> [CubicBezier] -- | Gives the orientation vector for the start of the primitive. firstTangeantOf :: Primitive -> Vector -- | Gives the orientation vector at the end of the primitive. lastTangeantOf :: Primitive -> Vector -- | Extract the first point of the primitive. firstPointOf :: Primitive -> Point -- | Return the last point of a given primitive. lastPointOf :: Primitive -> Point -- | Describe how to display the join of broken lines while stroking. data Join -- | Make a curved join. JoinRound :: Join -- | Make a mitter join. Value must be positive or null. Seems to make -- sense in [0;1] only -- --
-- fillingSample :: FillMethod -> Drawing px () -- fillingSample fillMethod = fillWithMethod fillMethod geometry where -- geometry = transform (applyTransformation $ scale 0.35 0.4 -- <> translate (V2 (-80) (-180))) -- [ Path (V2 484 499) True -- [ PathCubicBezierCurveTo (V2 681 452) (V2 639 312) (V2 541 314) -- , PathCubicBezierCurveTo (V2 327 337) (V2 224 562) (V2 484 499) -- ] -- , Path (V2 136 377) True -- [ PathCubicBezierCurveTo (V2 244 253) (V2 424 420) (V2 357 489) -- , PathCubicBezierCurveTo (V2 302 582) (V2 47 481) (V2 136 377) -- ] -- , Path (V2 340 265) True -- [ PathCubicBezierCurveTo (V2 64 371) (V2 128 748) (V2 343 536) -- , PathCubicBezierCurveTo (V2 668 216) (V2 17 273) (V2 367 575) -- , PathCubicBezierCurveTo (V2 589 727) (V2 615 159) (V2 340 265) -- ] -- ] --data FillMethod -- | Also known as nonzero rule. To determine if a point falls inside the -- curve, you draw an imaginary line through that point. Next you will -- count how many times that line crosses the curve before it reaches -- that point. For every clockwise rotation, you subtract 1 and for every -- counter-clockwise rotation you add 1. -- FillWinding :: FillMethod -- | This rule determines the insideness of a point on the canvas by -- drawing a ray from that point to infinity in any direction and -- counting the number of path segments from the given shape that the ray -- crosses. If this number is odd, the point is inside; if even, the -- point is outside. -- FillEvenOdd :: FillMethod -- | Dash pattern to use type DashPattern = [Float] -- | Transform a drawing into a serie of low-level drawing orders. drawOrdersOfDrawing :: RenderablePixel px => Int -> Int -> Dpi -> px -> Drawing px () -> [DrawOrder px] -- | This function will spit out drawing instructions to help debugging. -- -- The outputted code looks like Haskell, but there is no guarantee that -- it is compilable. dumpDrawing :: (Show px, Show (PixelBaseComponent px), PixelBaseComponent (PixelBaseComponent px) ~ (PixelBaseComponent px)) => Drawing px () -> String -- | Module describing the various filling method of the geometric -- primitives. -- -- All points coordinate given in this module are expressed final image -- pixel coordinates. module Graphics.Rasterific.Texture -- | Reification of texture type data Texture px -- | A gradient definition is just a list of stop and pixel values. For -- instance for a simple gradient of black to white, the finition would -- be : -- --
-- [(0, PixelRGBA8 0 0 0 255), (1, PixelRGBA8 255 255 255 255)] ---- -- the first stop value must be zero and the last, one. type Gradient px = [(Float, px)] -- | Set the repeat pattern of the texture (if any). With padding: -- --
-- withTexture (sampledImageTexture textureImage) $ -- fill $ rectangle (V2 0 0) 200 200 ---- -- -- With repeat: -- --
-- withTexture (withSampler SamplerRepeat $ -- sampledImageTexture textureImage) $ -- fill $ rectangle (V2 0 0) 200 200 ---- -- -- With reflect: -- --
-- withTexture (withSampler SamplerReflect $ -- sampledImageTexture textureImage) $ -- fill $ rectangle (V2 0 0) 200 200 ---- withSampler :: SamplerRepeat -> Texture px -> Texture px -- | The uniform texture is the simplest texture of all: an uniform color. uniformTexture :: px -> Texture px -- | Linear gradient texture. -- --
-- let gradDef = [(0, PixelRGBA8 0 0x86 0xc1 255) -- ,(0.5, PixelRGBA8 0xff 0xf4 0xc1 255) -- ,(1, PixelRGBA8 0xFF 0x53 0x73 255)] in -- withTexture (linearGradientTexture SamplerPad gradDef -- (V2 40 40) (V2 130 130)) $ -- fill $ circle (V2 100 100) 100 ---- linearGradientTexture :: Gradient px -> Point -> Point -> Texture px -- | Radial gradient texture -- --
-- let gradDef = [(0, PixelRGBA8 0 0x86 0xc1 255) -- ,(0.5, PixelRGBA8 0xff 0xf4 0xc1 255) -- ,(1, PixelRGBA8 0xFF 0x53 0x73 255)] in -- withTexture (radialGradientTexture gradDef -- (V2 100 100) 75) $ -- fill $ circle (V2 100 100) 100 ---- radialGradientTexture :: Gradient px -> Point -> Float -> Texture px -- | Radial gradient texture with a focus point. -- --
-- let gradDef = [(0, PixelRGBA8 0 0x86 0xc1 255) -- ,(0.5, PixelRGBA8 0xff 0xf4 0xc1 255) -- ,(1, PixelRGBA8 0xFF 0x53 0x73 255)] in -- withTexture (radialGradientWithFocusTexture gradDef -- (V2 100 100) 75 (V2 70 70) ) $ -- fill $ circle (V2 100 100) 100 ---- radialGradientWithFocusTexture :: Gradient px -> Point -> Float -> Point -> Texture px -- | Use another image as a texture for the filling. Contrary to -- imageTexture, this function perform a bilinear filtering on -- the texture. sampledImageTexture :: Image px -> Texture px -- | Use a drawing as a repeating background pattern. -- --
-- let pattern = -- patternTexture 40 40 96 (PixelRGBA8 0xFF 0x53 0x73 255) . -- withTexture (uniformTexture $ PixelRGBA8 0 0x86 0xc1 255) $ -- fill $ circle (V2 20 20) 13 -- in -- withTexture pattern $ -- fill $ roundedRectangle (V2 20 20) 160 160 20 20 ---- patternTexture :: RenderablePixel px => Int -> Int -> Dpi -> px -> Drawing px () -> Texture px -- | Perform a multiplication operation between a full color texture and a -- greyscale one, used for clip-path implementation. modulateTexture :: Pixel px => Texture px -> Texture (PixelBaseComponent px) -> Texture px -- | Transform the coordinates used for texture before applying it, allow -- interesting transformations. -- --
-- withTexture (withSampler SamplerRepeat $ -- transformTexture (rotateCenter 1 (V2 0 0) <> -- scale 0.5 0.25) -- $ sampledImageTexture textureImage) $ -- fill $ rectangle (V2 0 0) 200 200 ---- transformTexture :: Transformation -> Texture px -> Texture px