2011-09-19 12 views
4

L'application que j'écris utilise libcairo pour générer des graphiques vectoriels; tout fonctionne bien pour les formats de sortie qui prennent en charge plusieurs pages (PDF, PostScript), mais je voudrais également prendre en charge les formats d'image SVG et raster.SVG multi-pages utilisant libcairo et Haskell

Je suis actuellement simplement pousser les pages en utilisant showPage chaque fois que je serais autrement déborder de la marge inférieure, et je voudrais garder le code structuré de cette façon. Je suis venu avec deux solutions theroretically possibles:

a) Une monade d'aide qui s'enroule autour Render monade du Caire, mais fournit une action flushPage qui, lorsqu'il est enchaîné en elle, pousse l'action en cours de rendu sur une pile de page interne, un liftRender action qui, bien, lève une action Render dans la monade en la chaînant sur l'action précédemment tamponnée, et une fonction d'assistance pour extraire une liste d'actions Render(), une pour chaque page. Donc j'appellerais simplement ma fonction de rendu principale, mais au lieu d'une action Render(), elle retournerait une action pagination-wrapper, à partir de laquelle j'extrais des pages individuelles et les traitions - pour les formats multi-pages, je pouvais simplement les enchaîner , en insérant showPage actions entre eux, tandis que pour les formats d'une seule page, je les rendrais individuellement. À titre d'exemple, voici ce qu'il ressemblerait à ceci:

-- 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) Un type de surface caire qui agit comme un document de plusieurs pages à l'extérieur, mais produit une série de documents d'une seule page à l'extérieur. Ce serait idéal, car cela ne nécessiterait aucune modification du code de rendu, mais je ne suis pas sûr qu'il soit possible de le faire sans jouer avec le cairo lui-même au niveau de la source. Donc, la véritable question: L'une des solutions ci-dessus existe-t-elle déjà? Comme dans, est-ce que quelqu'un a écrit soit une «monade de pagination» ou une «surface SVG de plusieurs pages»? Et, dans le cas où la réponse est «non»; lequel est préférable et comment le mettre en œuvre?

Répondre

2

Dans le cas où quelqu'un est intéressé, j'ai tout compris grâce à une aide amicale des gars à #haskell.

Au lieu d'écrire une monad wrapper personnalisée, ma fonction de rendu renvoie Render [Render()]. Je restitue des fragments de façon récursive, en passant un certain état, et à chaque itération, je vérifie si l'opération en cours déborderait de la page en cours. Si tel est le cas, l'appel récursif ajoute une nouvelle page et réessaie; sinon, il enchaîne l'opération en cours sur la première page. Le résultat est une liste d'actions Render(), une pour chaque page.

La fonction principale prend alors ces actions Render() hors du résultat de la fonction de rendu. Ensuite, il vérifie le format de sortie souhaité; s'il s'agit d'un format multi-page comme PostScript ou PDF, il enchaîne simplement les actions ensemble, en insérant des actions showPage entre elles. S'il s'agit d'un format de page unique, il crée une nouvelle surface de rendu pour chaque page et affiche une action sur une page. La première page sert également de contexte pour l'appel de rendu initial.

0

Si vous n'avez pas besoin d'imprimer le 'doc', plusieurs couches de nœuds svg 'g' pourraient être rendues visibles en tant que pages. Pour paginer, la visibilité peut être activée ou désactivée.

Si un processus d'impression a l'intelligence de comprendre cela, alors l'impression est possible?

MarkT

+0

Ce n'est pas exactement ce que je cherche - je suis en train de sortir des fichiers SVG et d'autres formats vectoriels dans des fichiers, et puisque j'utilise libcairo pour cela, je n'ai pas le niveau de contrôle requis pour cela. – tdammers