我正在编写的应用程序使用 libcairo 来输出矢量图形;对于支持多页(PDF、PostScript)的输出格式,一切正常,但我也想支持 SVG 和光栅图像格式。
我目前只是使用 showPage
推送页面,否则我会溢出底部边距,并且我希望以这种方式保持代码结构。我想出了两个理论上可能的解决方案:
a) 一个辅助 monad 环绕开罗的 Render
monad,但提供了一个 flushPage
Action ,当链接到它时,将当前的 Render Action 推送到内部页面堆栈上,一个 liftRender
Action 可以将 Render
Action 提升到 monad 中通过将其链接到先前缓冲的操作上,以及一个辅助函数来提取 Render ()
操作列表,每个页面一个。所以我会简单地调用我的主渲染函数,而不是 Render ()
Action ,它会返回一个分页包装器 Action ,然后我会从中提取单个页面并处理它们 - 对于多页面格式,我可以简单地将它们链接在一起,在它们之间插入 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 的人的一些友好帮助。
我的渲染函数没有编写自定义包装器 monad,而是返回 Render [Render ()]
。我递归地渲染片段,传递一些状态,并在每次迭代时检查当前操作是否会溢出当前页面。如果是,则递归调用会附加一个新页面并再次尝试;否则,它将当前操作链接到首页。结果是一个 Render ()
操作列表,每个页面一个。
然后,主函数从渲染函数的结果中取出这些 Render()
操作。然后它检查所需的输出格式;如果是像 PostScript 或 PDF 这样的多页格式,它只是将 Action 链接在一起,在它们之间插入 showPage
Action 。如果它是单页格式,它会为每个页面创建一个新的渲染表面,并在其上渲染一个页面操作。第一个页面兼作初始渲染调用的上下文。
关于haskell - 使用 libcairo 和 Haskell 的多页 SVG,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/7467089/