avoid switching directory in ihaskell-display

This commit is contained in:
Hypercube 2022-07-19 00:00:00 +00:00
parent 5bcfb8976c
commit 5bf443fb7c
10 changed files with 124 additions and 146 deletions

View File

@ -5,6 +5,7 @@ import Data.Default.Class
import Graphics.Rendering.Chart.Renderable
import Graphics.Rendering.Chart.Backend.Cairo
import qualified Data.ByteString.Char8 as Char
import System.IO.Temp
import System.IO.Unsafe
import IHaskell.Display
@ -27,16 +28,15 @@ instance IHaskellDisplay (Renderable a) where
chartData :: Renderable a -> FileFormat -> IO DisplayData
chartData renderable format = do
switchToTmpDir
withSystemTempFile "ihaskell-chart.png" $ \path _ -> do
-- Write the PNG image.
let filename = ".ihaskell-chart.png"
opts = def { _fo_format = format, _fo_size = (width, height) }
renderableToFile opts filename renderable
-- Write the PNG image.
let opts = def { _fo_format = format, _fo_size = (width, height) }
renderableToFile opts path renderable
-- Convert to base64.
imgData <- Char.readFile filename
return $
case format of
PNG -> png width height $ base64 imgData
SVG -> svg $ Char.unpack imgData
-- Convert to base64.
imgData <- Char.readFile path
return $
case format of
PNG -> png width height $ base64 imgData
SVG -> svg $ Char.unpack imgData

View File

@ -58,6 +58,7 @@ library
bytestring,
data-default-class,
directory,
temporary,
Chart,
Chart-cairo >=1.2,
ihaskell >= 0.6.2

View File

@ -9,6 +9,7 @@ module IHaskell.Display.Diagrams
import qualified Data.ByteString.Char8 as Char
import System.Directory
import System.IO.Temp
import Diagrams.Backend.Cairo
import Diagrams.Prelude
import IHaskell.Display
@ -23,21 +24,20 @@ instance IHaskellDisplay (ManuallySized (QDiagram Cairo V2 Double Any)) where
diagramData :: ManuallySized (Diagram Cairo) -> OutputType -> IO DisplayData
diagramData (ManuallySized renderable imgWidth imgHeight) format = do
switchToTmpDir
withSystemTempFile ("ihaskell-diagram." ++ extension format) $ \path _ -> do
-- Write the image.
let filename = ".ihaskell-diagram." ++ extension format
renderCairo filename (mkSizeSpec2D (Just imgWidth)
(Just imgHeight)) renderable
-- Write the image.
renderCairo path (mkSizeSpec2D (Just imgWidth)
(Just imgHeight)) renderable
-- Convert to base64.
imgData <- Char.readFile filename
let value =
case format of
PNG -> png (floor imgWidth) (floor imgHeight) $ base64 imgData
SVG -> svg (Char.unpack imgData)
-- Convert to base64.
imgData <- Char.readFile path
let value =
case format of
PNG -> png (floor imgWidth) (floor imgHeight) $ base64 imgData
SVG -> svg (Char.unpack imgData)
return value
return value
where
extension SVG = "svg"

View File

@ -16,6 +16,7 @@ import Diagrams.Prelude
import Diagrams.Backend.Cairo
import Diagrams.Backend.Cairo.CmdLine (GifOpts(..))
import Diagrams.Backend.CmdLine (DiagramOpts(..), mainRender)
import System.IO.Temp
import IHaskell.Display
import IHaskell.Display.Diagrams.ImgSize
@ -45,28 +46,27 @@ instance IHaskellDisplay (ManuallySized (ManuallySampled (QAnimation Cairo V2 Do
animationData :: ManuallySized (ManuallySampled (Animation Cairo V2 Double)) -> IO String
animationData (ManuallySized (ManuallySampled renderable fps) imgWidth imgHeight) = do
switchToTmpDir
withSystemTempFile "ihaskell-diagram.gif" $ \path _ -> do
-- Generate the frames
let actualFps = fromMaybe defaultFps fps
animAdjusted = animEnvelope' actualFps renderable
frames = simulate actualFps animAdjusted
timediff = 100 `div` ceiling actualFps :: Int
frameSet = map (\x -> (x # bg white, timediff)) frames
-- Generate the frames
let actualFps = fromMaybe defaultFps fps
animAdjusted = animEnvelope' actualFps renderable
frames = simulate actualFps animAdjusted
timediff = 100 `div` ceiling actualFps :: Int
frameSet = map (\x -> (x # bg white, timediff)) frames
-- Write the image.
let filename = ".ihaskell-diagram.gif"
diagOpts = DiagramOpts
{ _width = Just . ceiling $ imgWidth
, _height = Just . ceiling $ imgHeight
, _output = filename
}
gifOpts = GifOpts { _dither = True, _noLooping = False, _loopRepeat = Nothing }
mainRender (diagOpts, gifOpts) frameSet
-- Write the image.
let diagOpts = DiagramOpts
{ _width = Just . ceiling $ imgWidth
, _height = Just . ceiling $ imgHeight
, _output = path
}
gifOpts = GifOpts { _dither = True, _noLooping = False, _loopRepeat = Nothing }
mainRender (diagOpts, gifOpts) frameSet
-- Convert to ascii represented base64 encoding
imgData <- CBS.readFile filename
return . T.unpack . base64 $ imgData
-- Convert to ascii represented base64 encoding
imgData <- CBS.readFile path
return . T.unpack . base64 $ imgData
-- Rendering hint.
@ -134,4 +134,4 @@ instance IHaskellDisplay (ManuallySampled (ManuallySized (QAnimation Cairo V2 Do
display (ManuallySampled (ManuallySized renderable w h) fps) = out
where
sizeSpec = mkSizeSpec2D (Just w) (Just h)
out = display . withSizeSpec sizeSpec $ withSamplingSpec fps renderable
out = display . withSizeSpec sizeSpec $ withSamplingSpec fps renderable

View File

@ -59,6 +59,7 @@ library
text,
bytestring,
directory,
temporary,
-- Use diagrams wrapper package to ensure all same versions of subpackages
diagrams >= 1.3,
diagrams-lib,

View File

@ -21,6 +21,7 @@ import qualified Graphics.Gnuplot.Terminal.SVG as Sv
import qualified Graphics.Gnuplot.Graph.TwoDimensional as Tw
import qualified Graphics.Gnuplot.Graph.ThreeDimensional as Th
import qualified Data.ByteString.Char8 as Char
import System.IO.Temp
import Graphics.Gnuplot.Advanced (plot)
import Graphics.Gnuplot.Value.Atom (C)
import IHaskell.Display
@ -58,9 +59,6 @@ instance IHaskellDisplay M.T where
svgDisp <- graphDataSVGM fig
return $ Display [pngDisp, svgDisp]
-- Filename
name = ".ihaskell-gnuplot."
-- Width and height
w = 300
@ -68,120 +66,110 @@ h = 300
graphDataPNG2P :: (C x, C y) => P.T (Tw.T x y) -> IO DisplayData
graphDataPNG2P graph = do
switchToTmpDir
withSystemTempFile "ihaskell-gnuplot.png" $ \path _ -> do
-- Write the image.
let fname = Pn.cons $ name ++ "png"
plot fname graph
-- Write the image.
plot (Pn.cons path) graph
-- Read back, and convert to base64.
imgData <- Char.readFile $ name ++ "png"
return $ png w h $ base64 imgData
-- Read back, and convert to base64.
imgData <- Char.readFile path
return $ png w h $ base64 imgData
graphDataSVG2P :: (C x, C y) => P.T (Tw.T x y) -> IO DisplayData
graphDataSVG2P graph = do
switchToTmpDir
withSystemTempFile "ihaskell-gnuplot.svg" $ \path _ -> do
-- Write the image.
let fname = Sv.cons $ name ++ "svg"
plot fname graph
-- Write the image.
plot (Sv.cons path) graph
-- Read back, and convert to base64.
imgData <- Char.readFile $ name ++ "svg"
return $ svg $ Char.unpack imgData
-- Read back, and convert to base64.
imgData <- Char.readFile path
return $ svg $ Char.unpack imgData
graphDataPNG2F :: (C x, C y) => F.T (Tw.T x y) -> IO DisplayData
graphDataPNG2F graph = do
switchToTmpDir
withSystemTempFile "ihaskell-gnuplot.png" $ \path _ -> do
-- Write the image.
let fname = Pn.cons $ name ++ "png"
plot fname graph
-- Write the image.
plot (Pn.cons path) graph
-- Read back, and convert to base64.
imgData <- Char.readFile $ name ++ "png"
return $ png w h $ base64 imgData
-- Read back, and convert to base64.
imgData <- Char.readFile path
return $ png w h $ base64 imgData
graphDataSVG2F :: (C x, C y) => F.T (Tw.T x y) -> IO DisplayData
graphDataSVG2F graph = do
switchToTmpDir
withSystemTempFile "ihaskell-gnuplot.svg" $ \path _ -> do
-- Write the image.
let fname = Sv.cons $ name ++ "svg"
plot fname graph
-- Write the image.
plot (Sv.cons path) graph
-- Read back, and convert to base64.
imgData <- Char.readFile $ name ++ "svg"
return $ svg $ Char.unpack imgData
-- Read back, and convert to base64.
imgData <- Char.readFile path
return $ svg $ Char.unpack imgData
graphDataPNG3P :: (C x, C y, C z) => P.T (Th.T x y z) -> IO DisplayData
graphDataPNG3P graph = do
switchToTmpDir
withSystemTempFile "ihaskell-gnuplot.png" $ \path _ -> do
-- Write the image.
let fname = Pn.cons $ name ++ "png"
plot fname graph
-- Write the image.
plot (Pn.cons path) graph
-- Read back, and convert to base64.
imgData <- Char.readFile $ name ++ "png"
return $ png w h $ base64 imgData
-- Read back, and convert to base64.
imgData <- Char.readFile path
return $ png w h $ base64 imgData
graphDataSVG3P :: (C x, C y, C z) => P.T (Th.T x y z) -> IO DisplayData
graphDataSVG3P graph = do
switchToTmpDir
withSystemTempFile "ihaskell-gnuplot.svg" $ \path _ -> do
-- Write the image.
let fname = Sv.cons $ name ++ "svg"
plot fname graph
-- Write the image.
plot (Sv.cons path) graph
-- Read back, and convert to base64.
imgData <- Char.readFile $ name ++ "svg"
return $ svg $ Char.unpack imgData
-- Read back, and convert to base64.
imgData <- Char.readFile path
return $ svg $ Char.unpack imgData
graphDataPNG3F :: (C x, C y, C z) => F.T (Th.T x y z) -> IO DisplayData
graphDataPNG3F graph = do
switchToTmpDir
withSystemTempFile "ihaskell-gnuplot.png" $ \path _ -> do
-- Write the image.
let fname = Pn.cons $ name ++ "png"
plot fname graph
-- Write the image.
plot (Pn.cons path) graph
-- Read back, and convert to base64.
imgData <- Char.readFile $ name ++ "png"
return $ png w h $ base64 imgData
-- Read back, and convert to base64.
imgData <- Char.readFile path
return $ png w h $ base64 imgData
graphDataSVG3F :: (C x, C y, C z) => F.T (Th.T x y z) -> IO DisplayData
graphDataSVG3F graph = do
switchToTmpDir
withSystemTempFile "ihaskell-gnuplot.svg" $ \path _ -> do
-- Write the image.
let fname = Sv.cons $ name ++ "svg"
plot fname graph
-- Write the image.
plot (Sv.cons path) graph
-- Read back, and convert to base64.
imgData <- Char.readFile $ name ++ "svg"
return $ svg $ Char.unpack imgData
-- Read back, and convert to base64.
imgData <- Char.readFile path
return $ svg $ Char.unpack imgData
graphDataPNGM :: M.T -> IO DisplayData
graphDataPNGM graph = do
switchToTmpDir
withSystemTempFile "ihaskell-gnuplot.png" $ \path _ -> do
-- Write the image.
let fname = Pn.cons $ name ++ "png"
plot fname graph
-- Write the image.
plot (Pn.cons path) graph
-- Read back, and convert to base64.
imgData <- Char.readFile $ name ++ "png"
return $ png w h $ base64 imgData
-- Read back, and convert to base64.
imgData <- Char.readFile path
return $ png w h $ base64 imgData
graphDataSVGM :: M.T -> IO DisplayData
graphDataSVGM graph = do
switchToTmpDir
withSystemTempFile "ihaskell-gnuplot.svg" $ \path _ -> do
-- Write the image.
let fname = Sv.cons $ name ++ "svg"
plot fname graph
-- Write the image.
plot (Sv.cons path) graph
-- Read back, and convert to base64.
imgData <- Char.readFile $ name ++ "svg"
return $ svg $ Char.unpack imgData
-- Read back, and convert to base64.
imgData <- Char.readFile path
return $ svg $ Char.unpack imgData

View File

@ -56,6 +56,7 @@ library
-- Other library packages from which modules are imported.
build-depends: base >=4.9 && <5,
bytestring,
temporary,
gnuplot >= 0.5.4,
ihaskell >= 0.6.2

View File

@ -4,6 +4,7 @@ import qualified Data.ByteString.Char8 as Char
import Graphics.Rendering.Plot
import Control.Monad (void)
import Control.Applicative ((<$>))
import System.IO.Temp
import IHaskell.Display
@ -16,26 +17,25 @@ instance IHaskellDisplay (Figure a) where
figureData :: Figure () -> OutputType -> IO DisplayData
figureData figure format = do
switchToTmpDir
withSystemTempFile ("ihaskell-plot." ++ extension format) $ \path _ -> do
-- Width and height
let size = 300
w = size
h = size
-- Width and height
let size = 300
w = size
h = size
-- Write the image.
let fname = ".ihaskell-plot." ++ extension format
writeFigure format fname (w, h) figure
-- Write the image.
writeFigure format path (w, h) figure
-- Read back, and convert to base64.
imgData <- Char.readFile fname
let value =
case format of
PNG -> png w h $ base64 imgData
SVG -> svg $ Char.unpack imgData
_ -> error "Unsupported format for display"
-- Read back, and convert to base64.
imgData <- Char.readFile path
let value =
case format of
PNG -> png w h $ base64 imgData
SVG -> svg $ Char.unpack imgData
_ -> error "Unsupported format for display"
return value
return value
where
extension SVG = "svg"

View File

@ -57,6 +57,7 @@ library
build-depends: base >=4.9 && <5,
plot,
bytestring,
temporary,
hmatrix >= 0.10,
ihaskell >= 0.6.2

View File

@ -48,9 +48,6 @@ module IHaskell.Display (
encode64,
base64,
-- ** Utilities
switchToTmpDir,
-- * Internal only use
displayFromChanEncoded,
serializeDisplay,
@ -64,10 +61,8 @@ import qualified Data.ByteString.Lazy as LBS
import Data.Binary as Binary
import qualified Data.ByteString.Base64 as Base64
import System.Directory (getTemporaryDirectory, setCurrentDirectory)
import Control.Concurrent.STM (atomically)
import Control.Exception (try)
import Control.Concurrent.STM.TChan
import System.IO.Unsafe (unsafePerformIO)
@ -184,12 +179,3 @@ displayFromChanEncoded =
-- execution call ends.
printDisplay :: IHaskellDisplay a => a -> IO ()
printDisplay disp = display disp >>= atomically . writeTChan displayChan
-- | Convenience function for client libraries. Switch to a temporary directory so that any files we
-- create aren't visible. On Unix, this is usually /tmp.
switchToTmpDir :: IO ()
switchToTmpDir = void (try switchDir :: IO (Either SomeException ()))
where
switchDir =
getTemporaryDirectory >>=
setCurrentDirectory