使用libcairo和Haskell的多页SVG

我正在编写的应用程序使用libcairo输出矢量图形;一切都适用于支持多页(PDF,PostScript)的输出格式,但我也想支持SVG和光栅图像格式.

我目前只是使用showPage推送页面,否则我会溢出底部边距,我想保持代码结构这样.我提出了两种可能的解决方案:

a)一个帮助monad,它包裹着Cairo的Render monad,但提供了一个flushPage动作,当链接到它时,将当前的Render动作推送到内部页面堆栈,一个liftRender动作,它将一个Render动作提升到monad通过将它链接到先前缓冲的动作,以及帮助函数来提取Render()动作列表,每个页面一个.所以我只是调用我的主渲染函数,但不是Render()动作,它会返回一个分页包装动作,然后我将从中提取单个页面并处理它们 – 对于多页面格式,我可以简单地链它们在一起,在它们之间插入showPage动作,而对于单页面格式,我会单独渲染它们.举个例子,这就是它的样子:

-- original code
renderMe :: Render ()
renderMe = do
    newPath
    moveTo 10 10
    lineTo 20 20
    lineTo 10 30
    lineTo 10 10
    fill

    showPage

    newPath
    moveTo 10 10
    lineTo 20 20
    lineTo 10 30
    lineTo 10 10
    fill

-- new code
renderPages :: PagedRender ()
renderPages = do
    liftRender (do
        newPath
        moveTo 10 10
        lineTo 20 20
        lineTo 10 30
        lineTo 10 10
        fill)

    flushPage

    liftRender (do
        newPath
        moveTo 10 10
        lineTo 20 20
        lineTo 10 30
        lineTo 10 10
        fill)

    flushPage

b)一种cairo表面类型,其外部类似于多页文档,但在外部生成一系列单页文档.这将是理想的,因为它根本不需要对渲染代码进行任何更改,但是我不确定是否可以在源代码级别与cairo本身混淆时执行此操作.

那么,实际的问题是:上述任何一种解决方案是否已经存在?就像在,有没有人写过’分页包装monad’或’多页SVG表面’?并且,如果答案是“否”;哪一项更可取,你会如何实施呢?

最佳答案 如果有人有兴趣,我想通过#haskell的伙伴们的一些友好帮助来解决这个问题.

我的渲染函数返回Render [Render()]而不是编写自定义包装器monad.我递归地渲染片段,传递一些状态,并且在每次迭代时,我检查当前操作是否会溢出当前页面.如果是,那么递归调用会附加一个新页面并再次尝试;否则,它将当前操作链接到首页.结果是一个Render()动作列表,每个页面一个.

然后,main函数将这些Render()动作从render函数的结果中取出.然后它检查所需的输出格式;如果它是像PostScript或PDF这样的多页面格式,它只是将动作链接在一起,在它们之间插入showPage动作.如果它是单页面格式,它会为每个页面创建一个新的渲染表面,并在其上呈现一个页面操作.第一页兼作初始渲染调用的上下文.

点赞