Fig - Manipulating FIG files in Haskell

Introduction

Fig is a Haskell library for manipulating files in the FIG format (the format used by the Xfig drawing program). Only version 3.2 of the format is supported. To compile the library you will need GHC.

Fig is mostly useful for simple search-and-replace operations that change the file header or the style of individual elements. Operations that insert objects or change their sizes or positions are trickier to implement and are usually easier done in Xfig.

Download

fig-1.3.1.tar.gz

License

BSD style license.

Interface of the Fig module

Files in FIG format are parsed into a syntax tree of type Fig. The Fig data type and all of its sub elements are defined in the Graphics.Fig.Syntax module (the Graphics/Fig/Syntax.hs file). For names of fonts, colors, line styles, etc., refer to this module.

The layout and naming of the Fig data type is adapted from the description in the FORMAT3.2 file included with the Xfig distribution. The best way to get familiar with the meaning of the different names and units really is the Xfig user interface.

The Fig module exports a parser, a pretty printer, and an interface for performing search-and-replace operations on Fig values. The parser converts a string in the FIG format into a value of type Fig:

    parse ::
        FilePath ->   -- Name of input source (used in error messages).
        String ->     -- String in FIG format.
        Either
            String    -- Error messages if failed parse.
            Fig       -- Syntax tree if successful parse.

The pretty printer performs the opposite operation of converting a Fig value into a string suitable for printing to a FIG file:

    pretty ::
        Fig ->        -- Syntax tree of a FIG file.
        String        -- String in FIG format.

Search-and-replace operations are specified by a record of type ReplaceDef:

    data ReplaceDef =
        ReplaceDef
            { headerOrientation :: Orientation -> Orientation
            , headerJustification :: Justification -> Justification
            , headerUnits :: Units -> Units
            , headerPapersize :: PaperSize -> PaperSize
            , headerMagnification :: Double -> Double
            , headerMultiplePage :: MultiplePage -> MultiplePage
            , headerTransparentColor :: Transparent -> Transparent
            , headerResolution :: Integer -> Integer
            , textColor :: ColorSpec -> ColorSpec
            , textFontSize :: Double -> Double
            , textFont :: Font -> Font
            , textFontFlags :: FontFlags -> FontFlags
            , picFlipped :: Flipped -> Flipped
            , picFile :: FilePath -> FilePath
            , arrowType :: ArrowType -> ArrowType
            , arrowStyle :: ArrowStyle -> ArrowStyle
            , arrowThickness :: Double -> Double
            , arrowWidth :: Double -> Double
            , arrowHeight :: Double -> Double
            , areaFill :: AreaFill -> AreaFill
            , areaFillColor :: ColorSpec -> ColorSpec
            , lineStyle :: LineStyle -> LineStyle
            , lineThickness :: Integer -> Integer
            , linePenColor :: ColorSpec -> ColorSpec
            , lineStyleVal :: Double -> Double
            , lineCapStyle :: CapStyle -> CapStyle
            , lineJoinStyle :: JoinStyle -> JoinStyle
            }

Each field of ReplaceDef specifies how attributes of a certain type should be transformed. The definitions of the types Orientation, Justification, etc., are found in Graphics.Fig.Syntax.

The area and line functions of ReplaceDef apply to all line based objects of the figure. Thus setting linePenColor = const Pink will change the color of every line in the figure to pink.

Not all attributes of objects or the FIG file header are included in ReplaceDef. In particular the attributes do not involve the layout or positions of individual objects like boxes, ellipses, or splines.

The value emptyDef is convenient when constructing values of type ReplaceDef:

    emptyDef :: ReplaceDef

emptyDef is the value of type ReplaceDef with every field set to the identity function id.

The functions of a ReplaceDef value are applied to to the attributes of a Fig syntax tree by the function applyReplaceDef:

    applyReplaceDef ::
        ReplaceDef ->      -- The replacements to perform.
        Fig ->             -- A syntax tree of a Fig file.
        Fig                -- The syntax tree with elements replaced.

Example of use

The main function below reads a FIG file from stdin and prints the transformed file to stdout. The program calls a function process to transform the Fig value of the parsed input. If the parse fails, the program aborts with an error message.

    module Main where

    import Graphics.Fig

    main = do
        input <- getContents
        either fail succeed
            (parse "stdin" input)
        where
        succeed = putStr . pretty . process

To transform the Fig value we choose to write the process function by help of the ReplaceDef interface:

    process = applyReplaceDef replaceDef

The replacement specification selects a font, pen color, and arrow type; the width of arrows are scaled by a factor of 1.5; and a pair of green and blue colors are swapped:

    replaceDef =
        emptyDef
            { textFontSize = const 14
            , textFont = const (Ps HelveticaBold)
            , linePenColor = const Magenta
            , arrowWidth = (* 1.5)
            , arrowType = const Closed
            , areaFillColor = x ->
                case x of
                    Green4 -> LtBlue
                    LtBlue -> Green4
                    _ -> x
            }

The figure shows the effect of running the program for one particular FIG file:
Before
After

Anders Lau Olsen (an...@bergsoe.org)
Page created Mar 2004, last updated Aug 2011