Многостраничный SVG с использованием libcairo и Haskell - PullRequest
4 голосов
/ 19 сентября 2011

Приложение, которое я пишу, использует libcairo для вывода векторной графики; все прекрасно работает для форматов вывода, которые поддерживают несколько страниц (PDF, PostScript), однако я также хотел бы поддерживать форматы SVG и растровых изображений.

В настоящее время я просто нажимаю на страницы, используя showPage всякий раз, когда я бы переполнял нижнее поле, и я хотел бы сохранить структурированный код таким образом. Я предложил два теоретически возможных решения:

a) Вспомогательная монада, которая оборачивается вокруг монады Каира Render, но обеспечивает действие flushPage, которое, будучи прикованным к ней, помещает текущее действие Render во внутренний стек страниц, действие liftRender, которое хорошо, поднимите действие Render в монаду, связав его с ранее буферизованным действием, и вспомогательную функцию для извлечения списка 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 на уровне исходного кода.

Итак, актуальный вопрос: Существует ли какое-либо из вышеперечисленных решений? Как, например, кто-нибудь написал «монаду обертки для пагинации» или «многостраничную поверхность SVG»? И, если ответ «нет»; какой из них предпочтительнее и как вы будете его реализовывать?

Ответы [ 2 ]

2 голосов
/ 20 сентября 2011

На тот случай, если кому-то будет интересно, я понял это благодаря дружеской помощи от парней из # haskell.

Вместо написания пользовательской монады обертки, моя функция рендеринга возвращает Render [Render ()].Я отрисовываю фрагменты рекурсивно, передавая какое-то состояние, и на каждой итерации проверяю, не переполнит ли текущая операция текущую страницу.Если это так, то рекурсивный вызов добавляет новую страницу и пытается снова;в противном случае текущая операция связывается с главной страницей.Результатом является список Render () действий, по одному на каждую страницу.

Затем основная функция извлекает эти Render() действия из результата функции рендеринга.Затем он проверяет желаемый формат вывода;если это многостраничный формат, такой как PostScript или PDF, он просто объединяет действия в цепочку, вставляя между ними действия showPage.Если это одностраничный формат, он создает новую поверхность рендеринга для каждой страницы и отображает на ней одно действие страницы.Первая страница удваивается как контекст для начального вызова рендеринга.

0 голосов
/ 20 сентября 2011

Если вам не нужно печатать 'doc', тогда несколько слоев узлов svg 'g' могут быть видны как страницы.Для разбивки на страницы, тогда видимость может быть включена или выключена.

Если у процесса печати есть ум, чтобы понять это, тогда печать возможна?

MarkT

...