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)
Files
- ChangeLog.md +4/−0
- docs/gifs/doc_andThen.gif binary
- docs/gifs/doc_bellS.gif binary
- docs/gifs/doc_bonneP.gif binary
- docs/gifs/doc_bottomleyP.gif binary
- docs/gifs/doc_circlePlot.gif binary
- docs/gifs/doc_cividis.gif binary
- docs/gifs/doc_collignonP.gif binary
- docs/gifs/doc_constantS.gif binary
- docs/gifs/doc_cubicBezierS.gif binary
- docs/gifs/doc_curveS.gif binary
- docs/gifs/doc_drawBox.gif binary
- docs/gifs/doc_drawCircle.gif binary
- docs/gifs/doc_drawProgress.gif binary
- docs/gifs/doc_eckert1P.gif binary
- docs/gifs/doc_eckert3P.gif binary
- docs/gifs/doc_eckert5P.gif binary
- docs/gifs/doc_equirectangularP.gif binary
- docs/gifs/doc_faheyP.gif binary
- docs/gifs/doc_fromToS.gif binary
- docs/gifs/doc_githubIcon.gif binary
- docs/gifs/doc_greyscale.gif binary
- docs/gifs/doc_hammerP.gif binary
- docs/gifs/doc_haskellLogo.gif binary
- docs/gifs/doc_hsv.gif binary
- docs/gifs/doc_hsvComponents.gif binary
- docs/gifs/doc_hsvMatlab.gif binary
- docs/gifs/doc_inferno.gif binary
- docs/gifs/doc_jet.gif binary
- docs/gifs/doc_labComponents.gif binary
- docs/gifs/doc_lambertP.gif binary
- docs/gifs/doc_latex.gif binary
- docs/gifs/doc_latexAlign.gif binary
- docs/gifs/doc_lchComponents.gif binary
- docs/gifs/doc_magma.gif binary
- docs/gifs/doc_mapA.gif binary
- docs/gifs/doc_mercatorP.gif binary
- docs/gifs/doc_mkBackground.gif binary
- docs/gifs/doc_mkImage.gif binary
- docs/gifs/doc_mkText.gif binary
- docs/gifs/doc_mollweideP.gif binary
- docs/gifs/doc_oscillateS.gif binary
- docs/gifs/doc_parA.gif binary
- docs/gifs/doc_parDropA.gif binary
- docs/gifs/doc_parLoopA.gif binary
- docs/gifs/doc_parula.gif binary
- docs/gifs/doc_pathify.gif binary
- docs/gifs/doc_pause.gif binary
- docs/gifs/doc_pauseAround.gif binary
- docs/gifs/doc_pauseAtBeginning.gif binary
- docs/gifs/doc_pauseAtEnd.gif binary
- docs/gifs/doc_plasma.gif binary
- docs/gifs/doc_playThenReverseA.gif binary
- docs/gifs/doc_repeatA.gif binary
- docs/gifs/doc_reverseA.gif binary
- docs/gifs/doc_reverseS.gif binary
- docs/gifs/doc_rgbComponents.gif binary
- docs/gifs/doc_seqA.gif binary
- docs/gifs/doc_signalA.gif binary
- docs/gifs/doc_sinebow.gif binary
- docs/gifs/doc_sinusoidalP.gif binary
- docs/gifs/doc_smallEarth.gif binary
- docs/gifs/doc_svgLogo.gif binary
- docs/gifs/doc_ternaryPlot.gif binary
- docs/gifs/doc_turbo.gif binary
- docs/gifs/doc_viridis.gif binary
- docs/gifs/doc_wernerP.gif binary
- docs/gifs/doc_xelatex.gif binary
- docs/gifs/doc_xyzComponents.gif binary
- examples/doc_mkImage.hs +10/−0
- examples/tut_glue_povray.hs +0/−1
- reanimate.cabal +1/−1
- src/Reanimate.hs +3/−0
- src/Reanimate/Driver.hs +1/−13
- src/Reanimate/Parameters.hs +1/−1
- src/Reanimate/Raster.hs +85/−17
- src/Reanimate/Render.hs +31/−4
@@ -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.
binary file changed (15149 → 15433 bytes)
binary file changed (11523 → 11942 bytes)
binary file changed (18438 → 18463 bytes)
binary file changed (22181 → 22206 bytes)
binary file changed (17358 → 17221 bytes)
binary file changed (5597 → 5622 bytes)
binary file changed (18134 → 18159 bytes)
binary file changed (2528 → 2578 bytes)
binary file changed (11940 → 11580 bytes)
binary file changed (11071 → 11487 bytes)
binary file changed (2753 → 2813 bytes)
binary file changed (14071 → 14117 bytes)
binary file changed (11373 → 11795 bytes)
binary file changed (25277 → 25302 bytes)
binary file changed (27881 → 27906 bytes)
binary file changed (26428 → 26453 bytes)
binary file changed (30032 → 30057 bytes)
binary file changed (17275 → 17300 bytes)
binary file changed (10888 → 11298 bytes)
binary file changed (4469 → 4494 bytes)
binary file changed (5600 → 5625 bytes)
binary file changed (25298 → 25323 bytes)
binary file changed (4071 → 4096 bytes)
binary file changed (14980 → 15005 bytes)
binary file changed (5600 → 5625 bytes)
binary file changed (5600 → 5625 bytes)
binary file changed (5595 → 5620 bytes)
binary file changed (5597 → 5622 bytes)
binary file changed (5595 → 5620 bytes)
binary file changed (30507 → 30532 bytes)
binary file changed (3446 → 3471 bytes)
binary file changed (4378 → 4406 bytes)
binary file changed (5585 → 5610 bytes)
binary file changed (5595 → 5620 bytes)
binary file changed (6786 → 6836 bytes)
binary file changed (33057 → 33082 bytes)
binary file changed (1768 → 1793 bytes)
binary file changed (absent → 4096 bytes)
binary file changed (8432 → 8482 bytes)
binary file changed (25309 → 25580 bytes)
binary file changed (11758 → 12190 bytes)
binary file changed (28657 → 29837 bytes)
binary file changed (29365 → 30575 bytes)
binary file changed (32781 → 34088 bytes)
binary file changed (5588 → 5613 bytes)
binary file changed (9060 → 9235 bytes)
binary file changed (12035 → 12484 bytes)
binary file changed (12720 → 13194 bytes)
binary file changed (11946 → 12395 bytes)
binary file changed (12147 → 12594 bytes)
binary file changed (5598 → 5623 bytes)
binary file changed (26577 → 27345 bytes)
binary file changed (20798 → 20923 bytes)
binary file changed (14984 → 15444 bytes)
binary file changed (11198 → 11609 bytes)
binary file changed (5600 → 5625 bytes)
binary file changed (15834 → 16118 bytes)
binary file changed (13561 → 14083 bytes)
binary file changed (5600 → 5625 bytes)
binary file changed (21495 → 21520 bytes)
binary file changed (30032 → 30057 bytes)
binary file changed (6437 → 6462 bytes)
binary file changed (5121 → 5107 bytes)
binary file changed (5589 → 5614 bytes)
binary file changed (5592 → 5617 bytes)
binary file changed (18319 → 18344 bytes)
binary file changed (3354 → 3379 bytes)
binary file changed (5588 → 5613 bytes)
@@ -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"
@@ -7,7 +7,6 @@ import Reanimate import Reanimate.Povray (povraySlow')-import Reanimate.Raster import Codec.Picture import Codec.Picture.Types
@@ -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
@@ -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
@@ -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)
@@ -30,7 +30,7 @@ | RasterInkscape | RasterRSvg | RasterConvert- deriving (Show)+ deriving (Show, Eq) {-# NOINLINE pRasterRef #-} pRasterRef :: IORef Raster
@@ -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
@@ -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 ()