суббота, 4 июля 2009 г.

HTML + SVG -> PDF

Продолжаем тему вики-документации с векторной графикой. Вот у нас есть Dokuwiki с плагином svg_pureinsert, и иллюстрации прекрасно выглядят в броузерах, поддерживающих SVG. Добавив &do=export_html в конец адресной строки документа в dokuwiki, можно получить «чистый» HTML, без элементов управления самой вики. Но когда возникает необходимость преобразовать эту страницу в PDF, то оказывается, что сделать это, не потеряв иллюстрации, практически невозможно. Есть два способа:
  1. Сохранить в PDF прямо из браузера (Firefox 3 это умеет).
  2. Открыть страницу в OpenOffice и сохранить PDF из него.
Если мы хотим добавить в документ оглавление с номерами страниц, то первый способ нам никак не подойдёт. Второй способ имеет особенности, о которых сейчас пойдёт речь.

svg_pureinsert вставляет svg-иллюстрации в <iframe>. Это не единственный способ вставки SVG в HTML, но по случайности — единственный подходящий для OpenOffice; теги <object> и <embed> он не замечает. Есть ещё одна неприятность: когда oowriter открывает HTML-страницу, все такие iframe преобразуются в т.н. «floating frames», в которые помимо самой картинки втиснут интерфейс oodraw:
Чтобы превратить каждую floating frame в обычный embedded object, ссылающийся на тот же svg-файл, надо выполнить следующий макрос на OpenOffice Basic:
Sub ConvertFloatingFrames
doc = ThisComponent
found = True

While found
found = False
For i = 0 To doc.getDrawPage().getCount() - 1
If Not found Then
obj = doc.getDrawPage().getByIndex(0)
If obj.getImplementationName() = "SwXTextEmbeddedObject" then
emb = obj.getExtendedControlOverEmbeddedObject
url = emb.Component.frameUrl
size = obj.getSize()
oText = obj.getAnchor().getText()
EmbedGraphic(doc, obj.getAnchor(), url, size.Width, size.Height)
oText.removeTextContent(obj)
found = True
End If
End If
Next
Wend
End Sub
Вспомогательный к нему макрос был позаимствован из известной книги про макросы OpenOffice.
Sub EmbedGraphic (doc, anchor, url, width, height)
shape = doc.createInstance("com.sun.star.drawing.GraphicObjectShape")
obj = doc.createInstance("com.sun.star.text.GraphicObject")
doc.getDrawPage().add(shape)

provider = createUnoService("com.sun.star.graphic.GraphicProvider")

Dim props(0) as new com.sun.star.beans.PropertyValue
props(0).Name = "URL"
props(0).Value = url

shape.Graphic = provider.queryGraphic(props())

obj.graphicurl = shape.graphicurl
obj.width = width
obj.height = height
obj.AnchorType = com.sun.star.text.TextContentAnchorType.AS_CHARACTER

anchor.getText().insertTextContent(anchor, obj, false)
doc.getDrawPage().remove(shape)
End Sub

Проверял на OpenOffice.org 3.1. Макрос работает всегда со второго раза, из-за каких-то трудностей с ThisComponent, которые я не знаю как решить. Да, и поддерживаются только самые примитивные SVG. Сторонний фильтр SVG для OpenOffice 2.0 поддерживает формат в большей мере, но при отрисовке embedded-объектов не задействуется, к сожалению.

Комментариев нет: