Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I deploy an executable using Chart-diagrams' standard fonts without Cabal

Tags:

haskell

I need to deploy applications in a Windows environment (Window XP to be specific) where my deployment options are pretty much limited to copying a .exe or possibly a folder structure. I'm using the Chart library with the new(ish) Diagrams backend which seemed perfect for this scenario.

However, I soon found out that an application built with Chart's Diagrams backend references data files (font SVGs) with absolute paths, which in this case are buried deep in a .cabal-sandbox directory on my development computer. Needless to say this doesn't work too well when the executable is copied to the production workstation.

Is there a pretty and non-fragile solution to this problem? (I think I could hack it by move the repo to, e.g., C:\myrepo\ on my dev comp, build it there, and then make sure to copy the relevent files into C:\myrepo.cabal-sandbox on the production workstation, but is that ever ugly and fragile!)

like image 978
Björn Buckwalter Avatar asked Dec 01 '25 02:12

Björn Buckwalter


1 Answers

As pointed out to me by Jan Bracker, the Chart-diagrams library/backend offers the possibility to supply custom fonts. The standard fonts delivered with the library can be copied to a custom (relative) location and reconfigured through this mechanism.

With Jan's pointers I found a workable solution. Here is what I ended up with:

-- | Makes the standard font relocatable.
module LocalFonts (localFonts) where

import qualified Data.Map as M
import Graphics.Rendering.Chart.Backend.Types
import System.FilePath (replaceFileName)


localFonts :: FilePath -> M.Map (String, FontSlant, FontWeight) FilePath
localFonts exec = let
    serifR   = replaceFileName exec "fonts/LinLibertine_R.svg"
    serifRB  = replaceFileName exec "fonts/LinLibertine_RB.svg"
    serifRBI = replaceFileName exec "fonts/LinLibertine_RBI.svg"
    serifRI  = replaceFileName exec "fonts/LinLibertine_RI.svg"
    sansR    = replaceFileName exec "fonts/SourceSansPro_R.svg"
    sansRB   = replaceFileName exec "fonts/SourceSansPro_RB.svg"
    sansRBI  = replaceFileName exec "fonts/SourceSansPro_RBI.svg"
    sansRI   = replaceFileName exec "fonts/SourceSansPro_RI.svg"
    monoR    = replaceFileName exec "fonts/SourceCodePro_R.svg"
    monoRB   = replaceFileName exec "fonts/SourceCodePro_RB.svg"
  in M.fromList
    [ ( ("serif"     , FontSlantNormal , FontWeightNormal) , serifR   )
    , ( ("serif"     , FontSlantNormal , FontWeightBold  ) , serifRB  )
    , ( ("serif"     , FontSlantItalic , FontWeightNormal) , serifRI  )
    , ( ("serif"     , FontSlantOblique, FontWeightNormal) , serifRI  )
    , ( ("serif"     , FontSlantItalic , FontWeightBold  ) , serifRBI )
    , ( ("serif"     , FontSlantOblique, FontWeightBold  ) , serifRBI )

    , ( ("sans-serif", FontSlantNormal , FontWeightNormal) , sansR    )
    , ( ("sans-serif", FontSlantNormal , FontWeightBold  ) , sansRB   )
    , ( ("sans-serif", FontSlantItalic , FontWeightNormal) , sansRI   )
    , ( ("sans-serif", FontSlantOblique, FontWeightNormal) , sansRI   )
    , ( ("sans-serif", FontSlantItalic , FontWeightBold  ) , sansRBI  )
    , ( ("sans-serif", FontSlantOblique, FontWeightBold  ) , sansRBI  )

    , ( ("monospace" , FontSlantNormal , FontWeightNormal) , monoR    )
    , ( ("monospace" , FontSlantNormal , FontWeightBold  ) , monoRB   )
    , ( ("monospace" , FontSlantItalic , FontWeightNormal) , monoR    )
    , ( ("monospace" , FontSlantOblique, FontWeightNormal) , monoR    )
    , ( ("monospace" , FontSlantItalic , FontWeightBold  ) , monoRB   )
    , ( ("monospace" , FontSlantOblique, FontWeightBold  ) , monoRB   )
    ]

In my application code I use localFonts with something like:

  exec <- getExecutablePath  -- from System.Environment
  renderableToFile (localFO exec) ...
  where
    localFO = FileOptions (width opts, height opts) SVG_EMBEDDED . localFonts

Then, when installing in production I copy the fonts directory from charts-diagrams into the same directory as the executable. Works well enough for my needs.

like image 170
Björn Buckwalter Avatar answered Dec 04 '25 00:12

Björn Buckwalter



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!