Search code examples
haskellsvgrenderingcairo

How do I render in a SVG file with gi-cairo and Haskell


I'm making a program to render several drawings in PNG and SVG formats with Haskell and gi-cairo. I managed to render my drawing in a PNG file with :

import  GI.Cairo.Render 
import  GI.Cairo.Render.Connector 

main :: IO ()
main= do
    withImageSurface FormatRGB24 1000 1000 (\srf -> do  
                                            renderWith srf $ do
                                                        setSourceRGB 1 1 1
                                                        paint
                                                        setSourceRGB 1 0 0
                                                        moveTo 10 10
                                                        lineTo 100 100
                                                        lineTo 200 100
                                                        lineTo 200 400
                                                        stroke
                                                        fill
                                            surfaceWriteToPNG srf "test.png")

And now, I want to render my drawing inside a SVG file.

I tried the following code :

import  GI.Cairo.Render 
import  GI.Cairo.Render.Connector 

main= do
    withSVGSurface "test.svg" 1000 1000 (\srf -> do  
                                            renderWith srf $ do 
                                                        setSourceRGB 1 1 1
                                                        paint
                                                        setSourceRGB 1 0 0
                                                        moveTo 10 10
                                                        lineTo 100 100
                                                        lineTo 200 100
                                                        lineTo 200 400
                                                        stroke
                                                        fill
                                                        showPage)

but when I use this function, it get an empty SVG file (0 bytes) at the given location.

I tried to use the module cairo instead og gi-cairo

import Graphics.Rendering.Cairo

main= do
    withSVGSurface "test.svg" 1000 1000 (\srf -> do  
                                            renderWith srf $ do 
                                                        setSourceRGB 1 1 1
                                                        paint
                                                        setSourceRGB 1 0 0
                                                        moveTo 10 10
                                                        lineTo 100 100
                                                        lineTo 200 100
                                                        lineTo 200 400
                                                        stroke
                                                        fill
                                                        showPage)

and then ... it works ! I get a correct SVG file.

But for an integration with gi-gtk, I would rather like to use the gi-cairo module.

Do you know what is wrong with gi-cairo and why my code work with cairo and not with gi-cairo ?


Solution

  • This has previously been reported as a bug (see issue #5), affecting PDF and SVG (and, in my testing, PostScript).

    However, it looks like you can call surfaceFinish as the last operation on the surface at the end of the withSVGSurface call, and this will generate the SVG file correctly. No idea why this is needed with gi-cairo but not cairo:

    import  GI.Cairo.Render
    
    main = do
        withSVGSurface "test.svg" 1000 1000 $
          \srf -> do
            renderWith srf $ do
              setSourceRGB 1 1 1
              ...
              showPage
            surfaceFinish srf   -- add this as last operation on surface