packages feed

reanimate 0.3.0.0 → 0.3.1.0

raw patch · 77 files changed

+136/−37 lines, 77 filesbinary-addedPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

API changes (from Hackage documentation)

+ Reanimate: mkImage :: Double -> Double -> FilePath -> SVG
+ Reanimate: rasterSized :: Int -> Int -> SVG -> DynamicImage
+ Reanimate: svgAsPngFile' :: Int -> Int -> SVG -> FilePath
+ Reanimate.Parameters: instance GHC.Classes.Eq Reanimate.Parameters.Raster
+ Reanimate.Render: requireRaster :: Raster -> IO Raster
+ Reanimate.Render: selectRaster :: Raster -> IO Raster
- Reanimate: embedDynamicImage :: DynamicImage -> Tree
+ Reanimate: embedDynamicImage :: DynamicImage -> SVG
- Reanimate: embedImage :: PngSavable a => Image a -> Tree
+ Reanimate: embedImage :: PngSavable a => Image a -> SVG
- Reanimate: embedPng :: Double -> Double -> ByteString -> Tree
+ Reanimate: embedPng :: Double -> Double -> ByteString -> SVG
- Reanimate: raster :: Tree -> DynamicImage
+ Reanimate: raster :: SVG -> DynamicImage
- Reanimate: svgAsPngFile :: Tree -> FilePath
+ Reanimate: svgAsPngFile :: SVG -> FilePath
- Reanimate: vectorize :: FilePath -> Tree
+ Reanimate: vectorize :: FilePath -> SVG
- Reanimate: vectorize_ :: [String] -> FilePath -> Tree
+ Reanimate: vectorize_ :: [String] -> FilePath -> SVG
- Reanimate.Raster: embedDynamicImage :: DynamicImage -> Tree
+ Reanimate.Raster: embedDynamicImage :: DynamicImage -> SVG
- Reanimate.Raster: embedImage :: PngSavable a => Image a -> Tree
+ Reanimate.Raster: embedImage :: PngSavable a => Image a -> SVG
- Reanimate.Raster: embedPng :: Double -> Double -> ByteString -> Tree
+ Reanimate.Raster: embedPng :: Double -> Double -> ByteString -> SVG
- Reanimate.Raster: raster :: Tree -> DynamicImage
+ Reanimate.Raster: raster :: SVG -> DynamicImage
- Reanimate.Raster: rasterSized :: Int -> Int -> Tree -> DynamicImage
+ Reanimate.Raster: rasterSized :: Int -> Int -> SVG -> DynamicImage
- Reanimate.Raster: svgAsPngFile :: Tree -> FilePath
+ Reanimate.Raster: svgAsPngFile :: SVG -> FilePath
- Reanimate.Raster: svgAsPngFile' :: Int -> Int -> Tree -> FilePath
+ Reanimate.Raster: svgAsPngFile' :: Int -> Int -> SVG -> FilePath
- Reanimate.Raster: vectorize :: FilePath -> Tree
+ Reanimate.Raster: vectorize :: FilePath -> SVG
- Reanimate.Raster: vectorize_ :: [String] -> FilePath -> Tree
+ Reanimate.Raster: vectorize_ :: [String] -> FilePath -> SVG

Files

ChangeLog.md view
@@ -1,5 +1,9 @@ # Revision history for reanimate +## 0.3.1.0 -- 2020-05-12++* Expose 'mkImage'+ ## 0.3.0.0 -- 2020-05-11  * Improve README.md with better examples at a higher framerate.
docs/gifs/doc_andThen.gif view

binary file changed (15149 → 15433 bytes)

docs/gifs/doc_bellS.gif view

binary file changed (11523 → 11942 bytes)

docs/gifs/doc_bonneP.gif view

binary file changed (18438 → 18463 bytes)

docs/gifs/doc_bottomleyP.gif view

binary file changed (22181 → 22206 bytes)

docs/gifs/doc_circlePlot.gif view

binary file changed (17358 → 17221 bytes)

docs/gifs/doc_cividis.gif view

binary file changed (5597 → 5622 bytes)

docs/gifs/doc_collignonP.gif view

binary file changed (18134 → 18159 bytes)

docs/gifs/doc_constantS.gif view

binary file changed (2528 → 2578 bytes)

docs/gifs/doc_cubicBezierS.gif view

binary file changed (11940 → 11580 bytes)

docs/gifs/doc_curveS.gif view

binary file changed (11071 → 11487 bytes)

docs/gifs/doc_drawBox.gif view

binary file changed (2753 → 2813 bytes)

docs/gifs/doc_drawCircle.gif view

binary file changed (14071 → 14117 bytes)

docs/gifs/doc_drawProgress.gif view

binary file changed (11373 → 11795 bytes)

docs/gifs/doc_eckert1P.gif view

binary file changed (25277 → 25302 bytes)

docs/gifs/doc_eckert3P.gif view

binary file changed (27881 → 27906 bytes)

docs/gifs/doc_eckert5P.gif view

binary file changed (26428 → 26453 bytes)

docs/gifs/doc_equirectangularP.gif view

binary file changed (30032 → 30057 bytes)

docs/gifs/doc_faheyP.gif view

binary file changed (17275 → 17300 bytes)

docs/gifs/doc_fromToS.gif view

binary file changed (10888 → 11298 bytes)

docs/gifs/doc_githubIcon.gif view

binary file changed (4469 → 4494 bytes)

docs/gifs/doc_greyscale.gif view

binary file changed (5600 → 5625 bytes)

docs/gifs/doc_hammerP.gif view

binary file changed (25298 → 25323 bytes)

docs/gifs/doc_haskellLogo.gif view

binary file changed (4071 → 4096 bytes)

docs/gifs/doc_hsv.gif view

binary file changed (14980 → 15005 bytes)

docs/gifs/doc_hsvComponents.gif view

binary file changed (5600 → 5625 bytes)

docs/gifs/doc_hsvMatlab.gif view

binary file changed (5600 → 5625 bytes)

docs/gifs/doc_inferno.gif view

binary file changed (5595 → 5620 bytes)

docs/gifs/doc_jet.gif view

binary file changed (5597 → 5622 bytes)

docs/gifs/doc_labComponents.gif view

binary file changed (5595 → 5620 bytes)

docs/gifs/doc_lambertP.gif view

binary file changed (30507 → 30532 bytes)

docs/gifs/doc_latex.gif view

binary file changed (3446 → 3471 bytes)

docs/gifs/doc_latexAlign.gif view

binary file changed (4378 → 4406 bytes)

docs/gifs/doc_lchComponents.gif view

binary file changed (5585 → 5610 bytes)

docs/gifs/doc_magma.gif view

binary file changed (5595 → 5620 bytes)

docs/gifs/doc_mapA.gif view

binary file changed (6786 → 6836 bytes)

docs/gifs/doc_mercatorP.gif view

binary file changed (33057 → 33082 bytes)

docs/gifs/doc_mkBackground.gif view

binary file changed (1768 → 1793 bytes)

+ docs/gifs/doc_mkImage.gif view

binary file changed (absent → 4096 bytes)

docs/gifs/doc_mkText.gif view

binary file changed (8432 → 8482 bytes)

docs/gifs/doc_mollweideP.gif view

binary file changed (25309 → 25580 bytes)

docs/gifs/doc_oscillateS.gif view

binary file changed (11758 → 12190 bytes)

docs/gifs/doc_parA.gif view

binary file changed (28657 → 29837 bytes)

docs/gifs/doc_parDropA.gif view

binary file changed (29365 → 30575 bytes)

docs/gifs/doc_parLoopA.gif view

binary file changed (32781 → 34088 bytes)

docs/gifs/doc_parula.gif view

binary file changed (5588 → 5613 bytes)

docs/gifs/doc_pathify.gif view

binary file changed (9060 → 9235 bytes)

docs/gifs/doc_pause.gif view

binary file changed (12035 → 12484 bytes)

docs/gifs/doc_pauseAround.gif view

binary file changed (12720 → 13194 bytes)

docs/gifs/doc_pauseAtBeginning.gif view

binary file changed (11946 → 12395 bytes)

docs/gifs/doc_pauseAtEnd.gif view

binary file changed (12147 → 12594 bytes)

docs/gifs/doc_plasma.gif view

binary file changed (5598 → 5623 bytes)

docs/gifs/doc_playThenReverseA.gif view

binary file changed (26577 → 27345 bytes)

docs/gifs/doc_repeatA.gif view

binary file changed (20798 → 20923 bytes)

docs/gifs/doc_reverseA.gif view

binary file changed (14984 → 15444 bytes)

docs/gifs/doc_reverseS.gif view

binary file changed (11198 → 11609 bytes)

docs/gifs/doc_rgbComponents.gif view

binary file changed (5600 → 5625 bytes)

docs/gifs/doc_seqA.gif view

binary file changed (15834 → 16118 bytes)

docs/gifs/doc_signalA.gif view

binary file changed (13561 → 14083 bytes)

docs/gifs/doc_sinebow.gif view

binary file changed (5600 → 5625 bytes)

docs/gifs/doc_sinusoidalP.gif view

binary file changed (21495 → 21520 bytes)

docs/gifs/doc_smallEarth.gif view

binary file changed (30032 → 30057 bytes)

docs/gifs/doc_svgLogo.gif view

binary file changed (6437 → 6462 bytes)

docs/gifs/doc_ternaryPlot.gif view

binary file changed (5121 → 5107 bytes)

docs/gifs/doc_turbo.gif view

binary file changed (5589 → 5614 bytes)

docs/gifs/doc_viridis.gif view

binary file changed (5592 → 5617 bytes)

docs/gifs/doc_wernerP.gif view

binary file changed (18319 → 18344 bytes)

docs/gifs/doc_xelatex.gif view

binary file changed (3354 → 3379 bytes)

docs/gifs/doc_xyzComponents.gif view

binary file changed (5588 → 5613 bytes)

+ examples/doc_mkImage.hs view
@@ -0,0 +1,10 @@+#!/usr/bin/env stack+-- stack runghc --package reanimate+module Main (main) where++import           Reanimate+import           Reanimate.Builtin.Documentation++main :: IO ()+main = reanimate $ docEnv $ staticFrame 1 $+    mkImage screenWidth screenHeight "../data/haskell.svg"
examples/tut_glue_povray.hs view
@@ -7,7 +7,6 @@  import           Reanimate import           Reanimate.Povray      (povraySlow')-import           Reanimate.Raster  import           Codec.Picture import           Codec.Picture.Types
reanimate.cabal view
@@ -3,7 +3,7 @@ --  see http://haskell.org/cabal/users-guide/  name:                reanimate-version:             0.3.0.0+version:             0.3.1.0 -- synopsis: -- description: license:             PublicDomain
src/Reanimate.hs view
@@ -141,11 +141,14 @@     module Reanimate.Svg.BoundingBox,     module Reanimate.Svg,     -- ** Raster data+    mkImage,     embedImage,     embedDynamicImage,     embedPng,     raster,+    rasterSized,     svgAsPngFile,+    svgAsPngFile',     vectorize,     vectorize_,     -- ** External SVG providers
src/Reanimate/Driver.hs view
@@ -11,11 +11,10 @@ import           Reanimate.Driver.Server import           Reanimate.Parameters import           Reanimate.Render         (FPS, Format (..), Height, Width,-                                            render, renderSnippets, renderSvgs)+                                            render, renderSnippets, renderSvgs, selectRaster) import           System.Directory import           System.FilePath import           Text.Printf-import           Data.Either  presetFormat :: Preset -> Format presetFormat Youtube    = RenderMp4@@ -160,17 +159,6 @@             fps width height (showFormat fmt) target (show raster)            render animation target raster fmt width height fps--selectRaster :: Raster -> IO Raster-selectRaster RasterAuto = do-  rsvg <- hasRSvg-  ink <- hasInkscape-  conv <- hasConvert-  if | isRight rsvg -> pure RasterRSvg-     | isRight ink  -> pure RasterInkscape-     | isRight conv -> pure RasterConvert-     | otherwise    -> pure RasterNone-selectRaster r = pure r  guessParameter :: Maybe a -> Maybe a -> a -> a guessParameter a b def = fromMaybe def (a <|> b)
src/Reanimate/Parameters.hs view
@@ -30,7 +30,7 @@   | RasterInkscape   | RasterRSvg   | RasterConvert-  deriving (Show)+  deriving (Show, Eq)  {-# NOINLINE pRasterRef #-} pRasterRef :: IORef Raster
src/Reanimate/Raster.hs view
@@ -29,6 +29,7 @@ import           Reanimate.Misc import           Reanimate.Render import           Reanimate.Parameters+import           Reanimate.Constants import           Reanimate.Svg.Constructors import           Reanimate.Svg.Unuse import           System.Directory@@ -37,8 +38,49 @@ import           System.IO.Temp import           System.IO.Unsafe --- FIXME: Embed the image data as inline base64 iff no raster engine is specified.-mkImage :: Double -> Double -> FilePath -> SVG+-- | Load an external image. Width and height must be specified,+--   ignoring the image's aspect ratio. The center of the image is+--   placed at position (0,0).+--+--   For security reasons, must SVG renderer do not allow arbitrary+--   image links. For some renderers, we can get around this by placing+--   the images in the same root directory as the parent SVG file. Other+--   renderers (like Chrome and ffmpeg) requires that the image is inlined+--   as base64 data. External SVG files are an exception, though, as must+--   always be inlined directly. `mkImage` attempts to hide all the complexity+--   but edge-cases may exist.+--+--   Example:+--+--   > mkImage screenWidth screenHeight "../data/haskell.svg"+--+--   <<docs/gifs/doc_mkImage.gif>>+mkImage :: Double -- ^ Desired image width.+        -> Double -- ^ Desired image height.+        -> FilePath -- ^ Path to external image file.+        -> SVG+mkImage width height path | takeExtension path == ".svg" = unsafePerformIO $ do+  svg_data <- B.readFile path+  case parseSvgFile path svg_data of+    Nothing  -> error "Malformed svg"+    Just svg -> return $+      scaleXY (width/screenWidth) (height/screenHeight) $+      embedDocument svg+mkImage width height path | pRaster == RasterNone = unsafePerformIO $ do+  inp <- LBS.readFile path+  let imgData = LBS.unpack $ Base64.encode inp+  return $ flipYAxis $ ImageTree $ defaultSvg+    & Svg.imageWidth .~ Svg.Num width+    & Svg.imageHeight .~ Svg.Num height+    & Svg.imageHref .~ ("data:"++mimeType++";base64,"++imgData)+    & Svg.imageCornerUpperLeft .~ (Svg.Num (-width/2), Svg.Num (-height/2))+    & Svg.imageAspectRatio .~ Svg.PreserveAspectRatio False Svg.AlignNone Nothing+  where+    -- FIXME: Is there a better way to do this?+    mimeType =+      case takeExtension path of+        ".jpg" -> "image/jpeg"+        ext    -> "image/" ++ drop 1 ext mkImage width height path = unsafePerformIO $ do     exists <- doesFileExist target     unless exists $ copyFile path target@@ -59,13 +101,21 @@     template = show (hash key) <.> "png"  {-# INLINE embedImage #-}-embedImage :: PngSavable a => Image a -> Tree+-- | Embed an in-memory PNG image. Note, the pixel size of the image+--   is used as the dimensions. As such, embedding a 100x100 PNG will+--   result in an image 100 units wide and 100 units high. Consider+--   using with 'scaleToSize'.+embedImage :: PngSavable a => Image a -> SVG embedImage img = embedPng width height (encodePng img)   where     width  = fromIntegral $ imageWidth img     height = fromIntegral $ imageHeight img -embedPng :: Double -> Double -> LBS.ByteString -> Tree+-- | Embed in-memory PNG bytestring without parsing it.+embedPng :: Double -- ^ Width+         -> Double -- ^ Height+         -> LBS.ByteString -- ^ Raw PNG data+         -> SVG -- embedPng w h png = unsafePerformIO $ do --     LBS.writeFile path png --     return $ ImageTree $ defaultSvg@@ -86,7 +136,11 @@   {-# INLINE embedDynamicImage #-}-embedDynamicImage :: DynamicImage -> Tree+-- | Embed an in-memory image. Note, the pixel size of the image+--   is used as the dimensions. As such, embedding a 100x100 image will+--   result in an image 100 units wide and 100 units high. Consider+--   using with 'scaleToSize'.+embedDynamicImage :: DynamicImage -> SVG embedDynamicImage img = embedPng width height imgData   where     width   = fromIntegral $ dynamicMap imageWidth img@@ -111,21 +165,29 @@ --           & Svg.imageHref .~ ("file://" ++ path)  --raster :: Tree -> DynamicImage+-- | Convert an SVG object to a pixel-based image. The default resolution+--   is 2560x1440. See also 'rasterSized'. Multiple raster engines are supported+--   and are selected using the '--raster' flag in the driver.+raster :: SVG -> DynamicImage raster = rasterSized 2560 1440 -rasterSized :: Int -> Int -> Tree -> DynamicImage+-- | Convert an SVG object to a pixel-based image.+rasterSized :: Int -- ^ X resolution in pixels+            -> Int -- ^ Y resolution in pixels+            -> SVG -- ^ SVG object+            -> DynamicImage rasterSized w h svg = unsafePerformIO $ do     png <- B.readFile (svgAsPngFile' w h svg)     case decodePng png of       Left{}    -> error "bad image"       Right img -> return img -vectorize :: FilePath -> Tree+-- | Use 'potrace' to trace edges in a raster image and convert them to SVG polygons.+vectorize :: FilePath -> SVG vectorize = vectorize_ [] -vectorize_ :: [String] -> FilePath -> Tree+-- | Same as 'vectorize' but takes a list of arguments for 'potrace'.+vectorize_ :: [String] -> FilePath -> SVG vectorize_ _ path | pNoExternals = mkText $ T.pack path vectorize_ args path = unsafePerformIO $ do     root <- getXdgDirectory XdgCache "reanimate"@@ -154,22 +216,28 @@ -- imageAsFile :: DynamicImage -> FilePath -- imageAsFile img -svgAsPngFile :: Tree -> FilePath+-- | Convert an SVG object to a pixel-based image and save it to disk, returning+--   the filepath. The default resolution is 2560x1440. See also 'svgAsPngFile''.+--   Multiple raster engines are supported and are selected using the '--raster'+--   flag in the driver.+svgAsPngFile :: SVG -> FilePath svgAsPngFile = svgAsPngFile' width height   where     width = 2560     height = width * 9 `div` 16 -svgAsPngFile' :: Int -> Int -> Tree -> FilePath+-- | Convert an SVG object to a pixel-based image and save it to disk, returning+--   the filepath.+svgAsPngFile' :: Int -- ^ Width+              -> Int -- ^ Height+              -> SVG -- ^ SVG object+              -> FilePath svgAsPngFile' _ _ _ | pNoExternals = "/svgAsPngFile/has/been/disabled" svgAsPngFile' width height svg = unsafePerformIO $ cacheFile template $ \pngPath -> do     let svgPath = replaceExtension pngPath "svg"-    -- ffmpeg <- requireExecutable "ffmpeg"-    -- convert <- requireExecutable "convert"-    -- inkscape <- requireExecutable "inkscape"     writeFile svgPath rendered-    -- FIXME: raster should be configurable.-    applyRaster RasterRSvg svgPath+    engine <- requireRaster pRaster+    applyRaster engine svgPath   where     template = show (hash rendered) <.> "png"     rendered = renderSvg (Just $ Px $ fromIntegral width) (Just $ Px $ fromIntegral height) svg
src/Reanimate/Render.hs view
@@ -1,11 +1,14 @@+{-# LANGUAGE MultiWayIf #-} module Reanimate.Render   ( render-  , renderSvgs-  , renderSnippets+  , renderSvgs            -- :: Animation -> IO ()+  , renderSnippets        -- :: Animation -> IO ()   , Format(..)   , Raster(..)   , Width, Height, FPS-  , applyRaster+  , requireRaster         -- :: Raster -> IO Raster+  , selectRaster          -- :: Raster -> IO Raster+  , applyRaster           -- :: Raster -> FilePath -> IO ()   ) where  import           Control.Concurrent@@ -14,18 +17,20 @@ import qualified Data.Text           as T import qualified Data.Text.IO        as T import           Data.Time+import Data.Either import           Graphics.SvgTree    (Number (..)) import           Numeric import           Reanimate.Animation import           Reanimate.Misc import           Reanimate.Parameters+import           Reanimate.Driver.Check import           System.Exit import           System.FilePath     ((</>)) import           System.FilePath     (replaceExtension) import           System.IO import           Text.Printf         (printf) -renderSvgs :: Animation ->  IO ()+renderSvgs :: Animation -> IO () renderSvgs ani = do     print frameCount     lock <- newMVar ()@@ -181,6 +186,28 @@ rasterTemplate :: Raster -> String rasterTemplate RasterNone = "render-%05d.svg" rasterTemplate _          = "render-%05d.png"++requireRaster :: Raster -> IO Raster+requireRaster raster = do+  raster' <- selectRaster (if raster==RasterNone then RasterAuto else raster)+  case raster' of+    RasterNone -> do+      hPutStrLn stderr+        "Raster required but none could be found. \+        \Please install either inkscape, imagemagick, or rsvg-convert."+      exitWith (ExitFailure 1)+    _ -> pure raster'++selectRaster :: Raster -> IO Raster+selectRaster RasterAuto = do+  rsvg <- hasRSvg+  ink <- hasInkscape+  conv <- hasConvert+  if | isRight rsvg -> pure RasterRSvg+     | isRight ink  -> pure RasterInkscape+     | isRight conv -> pure RasterConvert+     | otherwise    -> pure RasterNone+selectRaster r = pure r  applyRaster :: Raster -> FilePath -> IO () applyRaster RasterNone _ = return ()