使用libcairo和Haskell的多页SVG
我正在编写的应用程序使用libcairo输出矢量图形;对于支持多页(PDF、PostScript)的输出格式,一切都很好,但是我也希望支持SVG和光栅图像格式 我现在只是使用使用libcairo和Haskell的多页SVG,haskell,svg,cairo,Haskell,Svg,Cairo,我正在编写的应用程序使用libcairo输出矢量图形;对于支持多页(PDF、PostScript)的输出格式,一切都很好,但是我也希望支持SVG和光栅图像格式 我现在只是使用showPage来推送页面,否则我会溢出底部的空白,我希望保持代码的这种结构。我提出了两种理论上可能的解决方案: a) 一个帮助器monad,它围绕Cairo的Rendermonad,但提供了一个flushPage操作,当链接到该操作中时,它会将当前呈现操作推到内部页面堆栈上,这是一个liftRender操作,它会,通过将R
showPage
来推送页面,否则我会溢出底部的空白,我希望保持代码的这种结构。我提出了两种理论上可能的解决方案:
a) 一个帮助器monad,它围绕Cairo的Render
monad,但提供了一个flushPage
操作,当链接到该操作中时,它会将当前呈现操作推到内部页面堆栈上,这是一个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表面”?如果答案是“不”;其中哪一个更可取,您将如何实现它?如果您不必打印“doc”,那么svg“g”节点的多层可以作为页面显示。 若要分页,则可以打开或关闭可见性 如果打印过程聪明地理解了这一点,那么打印是可能的吗
MarkT如果有人感兴趣,多亏了哈斯凯尔公司的朋友们的友好帮助,我才弄明白 我的render函数返回
render[render()]
,而不是编写自定义包装器monad。我递归地呈现片段,传递一些状态,在每次迭代中,我检查当前操作是否会溢出当前页面。如果会,则递归调用会附加一个新页并重试;否则,它会将当前操作链接到首页。结果是一个Render()
操作列表,每个页面一个
然后,主函数从渲染函数的结果中提取这些
Render()
操作。然后检查所需的输出格式;如果是PostScript或PDF等多页格式,则只需将操作链接在一起,在它们之间插入showPage
操作。如果是单页格式,则会为每个页面创建一个新的渲染曲面,并在其上渲染一个页面动作。第一个页面同时作为初始呈现调用的上下文。这并不是我想要的——我实际上是在将SVG和其他矢量格式输出到文件中,因为我使用libcairo来实现这一点,所以我没有必要的控制级别。