Skip to content

Commit

Permalink
feat: Use transparent background on animations
Browse files Browse the repository at this point in the history
Note that we use `DisposalRestoreBackground` in encoding the GIF, whereas previously we indirectly used `diagrams-rasterific`'s default, `DisposalAny`. While that worked with the default black background, retaining it now would mean that we would see previous frames remaining in the background rather than disappearing.
  • Loading branch information
georgefst committed Nov 20, 2023
1 parent 68d0aa3 commit 9a258af
Show file tree
Hide file tree
Showing 4 changed files with 20 additions and 9 deletions.
1 change: 1 addition & 0 deletions primer/primer.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ library
, exceptions >=0.10.4 && <0.11.0
, extra >=1.7.10 && <1.8.0
, generic-optics >=2.0 && <2.3.0
, JuicyPixels ^>=3.3.8
, list-t >=1.0 && <1.1.0
, logging-effect ^>=1.4
, mmorph ^>=1.2.0
Expand Down
28 changes: 19 additions & 9 deletions primer/src/Primer/Primitives.hs
Original file line number Diff line number Diff line change
Expand Up @@ -28,17 +28,24 @@ module Primer.Primitives (

import Foreword hiding (rotate)

import Codec.Picture.ColorQuant (palettizeWithAlpha)
import Codec.Picture.Gif (
GifDisposalMethod (DisposalRestoreBackground),
GifEncode (GifEncode),
GifLooping (LoopingForever),
encodeComplexGifImage,
)
import Control.Monad.Fresh (MonadFresh)
import Data.Aeson (FromJSON (..), ToJSON (..))
import Data.ByteString.Base64 qualified as B64
import Data.Data (Data)
import Data.Map qualified as M
import Diagrams.Backend.Rasterific (
GifLooping (LoopingForever),
defaultPaletteOptions,
rasterGif,
Options (RasterificOptions),
Rasterific (Rasterific),
)
import Diagrams.Prelude (
Diagram,
V2 (..),
circle,
deg,
Expand All @@ -48,6 +55,7 @@ import Diagrams.Prelude (
mkSizeSpec,
rect,
rectEnvelope,
renderDia,
rotate,
sRGB24,
translate,
Expand Down Expand Up @@ -343,7 +351,7 @@ primFunDef def args = case def of
-- Since we only support translating a `Picture` expression to an image once it is in normal form,
-- this guard will only pass when `picture` has no free variables other than `time`.
[PrimCon () (PrimInt duration), Lam () time picture]
| Just frames <- traverse diagramAtTime [0 .. (duration * 100) `div` frameLength - 1] ->
| Just (frames :: [Diagram Rasterific]) <- traverse diagramAtTime [0 .. (duration * 100) `div` frameLength - 1] ->
Right
$ prim
$ PrimAnimation
Expand All @@ -354,12 +362,14 @@ primFunDef def args = case def of
-- for unrelated reasons (getting the `Bytestring` without dumping it to a file).
mempty
(decodeUtf8 . B64.encode . toS)
$ rasterGif @Double
(mkSizeSpec $ Just . fromInteger <$> V2 width height)
gifLooping
defaultPaletteOptions
$ encodeComplexGifImage
$ GifEncode (fromInteger width) (fromInteger height) Nothing Nothing gifLooping
$ flip palettizeWithAlpha DisposalRestoreBackground
$ map
( (,fromInteger frameLength)
( (fromInteger frameLength,)
. renderDia
Rasterific
(RasterificOptions (mkSizeSpec $ Just . fromInteger <$> V2 width height))
. rectEnvelope
(fromInteger <$> mkP2 (-width `div` 2) (-height `div` 2))
(fromInteger <$> V2 width height)
Expand Down
Binary file modified primer/test/outputs/eval/animation/1.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified primer/test/outputs/eval/animation/2.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 9a258af

Please sign in to comment.