-- | Svg renderer based on Rasterific.

--

-- Here is a simple example of loading a SVG file (using svg-tree)

-- rendering it to a picture, and saving it to a PNG (using Juicy.Pixels)

--

-- @

-- import Codec.Picture( writePng )

-- import Graphics.Svg( loadSvgFile )

-- import Graphics.Rasterific.Svg( loadCreateFontCache

--                               , renderSvgDocument

--                               )

-- loadRender :: FilePath -> FilePath -> IO ()

-- loadRender svgfilename pngfilename = do

--   f <- loadSvgFile svgfilename

--   case f of

--     Nothing -> putStrLn "Error while loading SVG"

--     Just doc -> do

--       cache <- loadCreateFontCache "fonty-texture-cache"

--       (finalImage, _) <- renderSvgDocument cache Nothing 96 doc

--       writePng pngfilename finalImage

-- @

--

module Graphics.Rasterific.Svg
                    ( -- * Main functions

                      drawingOfSvgDocument
                    , renderSvgDocument
                    , pdfOfSvgDocument
                    , loadCreateFontCache
                      -- * Types

                    , LoadedElements( .. )
                    , Result( .. )
                    , DrawResult( .. )
                    , Dpi
                      -- * Other helper functions

                    , renderSvgFile
                    ) where

import qualified Data.ByteString.Lazy as B
import Graphics.Rasterific.Svg.RasterificRender( DrawResult( .. ) )
import qualified Graphics.Rasterific.Svg.RasterificRender as RR
import Data.Binary( encodeFile, decodeOrFail )
import Graphics.Svg.Types hiding ( Dpi )
import Graphics.Svg hiding ( Dpi )
import Graphics.Rasterific.Svg.RenderContext

import System.Directory( doesFileExist )
import Graphics.Text.TrueType


import qualified Codec.Picture as CP
import Codec.Picture( PixelRGBA8( .. )
                    , writePng )

{-import Graphics.Svg.CssParser-}

-- | Render an svg document to an image.

-- If you provide a size, the document will be stretched to

-- match the provided size.

--

-- The DPI parameter really should depend of your screen, but

-- a good default value is 96

--

-- The use of the IO Monad is there to allow loading of fonts

-- and referenced images.

renderSvgDocument :: FontCache          -- ^ Structure used to access fonts

                  -> Maybe (Int, Int)   -- ^ Optional document size

                  -> Dpi                -- ^ Current resolution for text and elements

                  -> Document           -- ^ Svg document

                  -> IO (CP.Image PixelRGBA8, LoadedElements)
renderSvgDocument cache size dpi =
    RR.renderSvgDocument cache size dpi . applyCSSRules . resolveUses

pdfOfSvgDocument :: FontCache -> Maybe (Int, Int) -> Dpi -> Document
                 -> IO (B.ByteString, LoadedElements)
pdfOfSvgDocument cache sizes dpi =
    RR.pdfOfSvgDocument cache sizes dpi . applyCSSRules . resolveUses

-- | Render an svg document to a Rasterific Drawing.

-- If you provide a size, the document will be stretched to

-- match the provided size.

--

-- The DPI parameter really should depend of your screen, but

-- a good default value is 96

--

-- The use of the IO Monad is there to allow loading of fonts

-- and referenced images.

drawingOfSvgDocument :: FontCache          -- ^ Structure used to access fonts

                     -> Maybe (Int, Int)   -- ^ Optional document size

                     -> Dpi                -- ^ Current resolution for text and elements

                     -> Document           -- ^ Svg document

                     -> IO (DrawResult, LoadedElements)
drawingOfSvgDocument cache size dpi =
    RR.drawingOfSvgDocument cache size dpi . applyCSSRules . resolveUses

-- | Rendering status.

data Result
  = ResultSuccess       -- ^ No problem found

  | ResultError String  -- ^ Error with message

  deriving (Eq, Show)

-- | Convert an SVG file to a PNG file, return True

-- if the operation went without problems.

-- 

-- This function will call loadCreateFontCache with

-- the filename "fonty-texture-cache"

renderSvgFile :: FilePath -> FilePath -> IO Result
renderSvgFile svgfilename pngfilename = do
  f <- loadSvgFile svgfilename
  case f of
     Nothing -> return $ ResultError "Error while loading SVG"
     Just doc -> do
        cache <- loadCreateFontCache "fonty-texture-cache"
        (finalImage, _) <- renderSvgDocument cache Nothing 96 doc
        writePng pngfilename finalImage
        return ResultSuccess

-- | This function will create a font cache,

-- a structure allowing to quickly match a font

-- family name and style to a specific true type font

-- on disk.

--

-- The cache is saved on disk at the filepath given

-- as parameter. If a cache is found it is automatically

-- loaded from the file.

--

-- Creating the cache is a rather long operation (especially

-- on Windows), that's why you may want to keep the cache

-- around.

loadCreateFontCache :: FilePath -> IO FontCache
loadCreateFontCache filename = do
  exist <- doesFileExist filename
  if exist then loadCache else createWrite
  where
    loadCache = do
      bstr <- B.readFile filename
      case decodeOrFail bstr of
        Left _ -> createWrite
        Right (_, _, v) -> return v

    createWrite = do
      cache <- buildCache
      encodeFile filename cache
      return cache