# SVG as page layout in Latex

I know we can use parshape and the shapepar package to have customized paragraph shapes, but I wonder if it is possible to read an SVG file and use it as page layout?

A possible solution might be to use luaxml and read SVG files to recognize boxes or closed-pathes, by some order, and then use parshape. However I wonder how boxes can be connected to each other to allow the text flow between them, and how boxes can be used repeatedly until the whole text is consumed and typesetted especially across several pages. The tcolorbox package with magazine library have some similar features but not sure if it can be used in that way.

Is there any solution (or similar thing) available? The main intent is not to have odd paragraph shapes but to use SVG editing tools for easy page layout editing.

• I think that the flowfram can do what you want. You can definitely read the SVG using LuaXML, it should be quite easy to process all rectangles using the DOM functions. – michal.h21 Dec 3 '19 at 11:48
• @michal.h21, thanks it looks very interesting. I also noticed there is GUI app for defining the frames, FlowframTk. I should loot at it more closely. – Shahryar Dec 3 '19 at 12:36

Here is a proof of concept using LuaXML for SVG parsing and Flowfram for flow frames.

I've created a package svgflowfram.sty:

\ProvidesPackage{svgflowfram}
\RequirePackage{flowfram}
\RequirePackage{xparse}
\RequirePackage{luacode}
\begin{luacode*}
function print_frame(x,y, width, height)
tex.print(string.format("\\newflowframe{%isp}{%isp}{%isp}{%isp}", width, height, x, y))
end

\end{luacode*}
\NewDocumentCommand\svgframes{o m o}{%
\IfNoValueTF{#1}{\def\svgflowfram@pages{}}{\def\svgflowfram@pages{#1}}
\IfNoValueTF{#3}{\def\svgflowfram@name{}}{\def\svgflowfram@name{#3}}
\directlua{
for _, frame in ipairs(frames) do
print_frame(frame.x, frame.y, frame.width, frame.height)
end
}
}

\endinput


It provides a command \svgframes. It can consume three parameters, one is mandatory, others optional. The optional arguments should add support for the page specification used by Flowframe and optional name for the frames. These features are not implemented yet, so you can just use the mandatory argument, which is the SVG file name.

The SVG frame parsing is implemented in the svgframes.lua library:

local domobj = require "luaxml-domobject"

-- just assume we use milimeters at the moment
local function get_dimen(el, dimen_attr)
return tex.sp(el:get_attribute(dimen_attr) .. "mm")
end
local f=io.open(svgfile, "r")
if not f then return nil, "Cannot open file " ..  svgfile end
f:close()
local dom = domobj.parse(content)
local frames = {}
for _, r in ipairs(dom:query_selector("rect")) do
local x, y, width, height = get_dimen(r, "x"), get_dimen(r, "y"), get_dimen(r, "width"), get_dimen(r, "height")
y = tex.pageheight - (y + height)
frames[#frames+1] = {x=x, y=y, width=width, height=height}
end
return frames
end



It provides function load_frames which loads the SVG file using LuaXML DOM funnctions, loops over all <rect> elements. The dimensions are converted to millimeters and then to sp. The y dimension needs to be calculated relative to the page height.

It can be used in this way:

\documentclass{article}
\usepackage{svgflowfram}
\usepackage{lipsum}
\usepackage[margin=0pt]{geometry}
\svgframes{frames.svg}
\begin{document}
\lipsum[1-10]
\end{document}


Sample SVG file:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->

<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="210mm"
height="297mm"
viewBox="0 0 210 297"
version="1.1"
id="svg8"
inkscape:version="0.92.4 (unknown)"
sodipodi:docname="frames.svg">
<defs
id="defs2" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:zoom="0.41"
inkscape:cx="-316.1324"
inkscape:cy="554.28571"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="1920"
inkscape:window-height="1016"
inkscape:window-x="0"
inkscape:window-y="27"
inkscape:window-maximized="1" />
<rdf:RDF>
<cc:Work
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
<g
inkscape:label="Vrstva 1"
inkscape:groupmode="layer"
id="layer1">
<rect
style="fill:#ffffff;stroke:#000000;stroke-width:0.27966458;stroke-miterlimit:0.30000001;stroke-dasharray:none;stroke-dashoffset:0"
id="rect815"
width="58.724594"
height="40.655487"
x="17.42378"
y="33.061993" />
<rect
style="fill:#ffffff;stroke:#000000;stroke-width:0.27966458;stroke-miterlimit:0.30000001;stroke-dasharray:none;stroke-dashoffset:0"
id="rect817"
width="82.601608"
height="36.783535"
x="90.990852"
y="91.141266" />
<rect
style="fill:#ffffff;stroke:#000000;stroke-width:0.27966458;stroke-miterlimit:0.30000001;stroke-dasharray:none;stroke-dashoffset:0;image-rendering:auto"
id="rect819"
width="80.020325"
height="41.94614"
x="20.005081"
y="143.4126">
<title
id="title842">logo</title>
</rect>
<rect
style="fill:#ffffff;stroke:#000000;stroke-width:0.27966458;stroke-miterlimit:0.30000001;stroke-dasharray:none;stroke-dashoffset:0"
id="rect821"
width="108.41463"
height="43.236786"
x="70.985771"
y="203.42784" />
</g>
</svg>


Rendered in Inkscape

And the PDF:

One issue is that widths for paragraphs that are split over two frames are wrong. I am not sure how to fix that.

• Wonderful! II think it deserves to become a package or at least be an extension for flowfram. It not only provides easy page layout solution, but also, with some tweaks, it can be used to include svg images that need some text to be inserted into them. – Shahryar Dec 3 '19 at 22:33
• @Shahryar it would need to fix the paragraph width issue first. the box dimension code is also not really robust, it just assumes millimeters are used. – michal.h21 Dec 4 '19 at 12:26