etch.love/export.lua

118 lines
3.9 KiB
Lua

base64 = require('base64')
function export(filename)
local outfile = io.open(filename, 'w')
if outfile == nil then
error('failed to create "'..filename)
end
for _,line in ipairs(Editor_state.lines) do
if line.mode == 'drawing' then
local svg_contents = export_drawing(line)
outfile:write('<img src="data:image/svg+xml;base64,'..base64.encode(svg_contents)..'"/>')
else
outfile:write(line.data)
end
outfile:write('<br/>\n')
end
outfile:close()
end
function export_drawing(drawing)
local out = {}
table.insert(out, '<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="256" height="128">\n')
for _,shape in ipairs(drawing.shapes) do
if shape.mode == 'freehand' then
export_freehand(shape, out)
elseif shape.mode == 'line' or shape.mode == 'manhattan' then
export_line(drawing, shape, out)
elseif shape.mode == 'polygon' or shape.mode == 'rectangle' or shape.mode == 'square' then
export_polygon(drawing, shape, out)
elseif shape.mode == 'circle' then
export_circle(drawing, shape, out)
elseif shape.mode == 'arc' then
export_circle_arc(drawing, shape, out)
elseif shape.mode == 'deleted' then
-- ignore
else
assert(false, ('unknown drawing mode %s'):format(shape.mode))
end
table.insert(out, '\n')
end
table.insert(out, '</svg>\n')
return table.concat(out)
end
function file_exists(filename)
local f = io.open(filename)
if f then
f:close()
return true
end
return false
end
function export_freehand(shape, out)
table.insert(out, ('<path stroke="black" fill="none" d="M %d %d L'):format(shape.points[1].x, shape.points[1].y))
for i=2,#shape.points do
table.insert(out, (' %d %d'):format(shape.points[i].x, shape.points[i].y))
end
table.insert(out, '"/>\n')
end
function export_line(drawing, shape, out)
local p1 = drawing.points[shape.p1]
local p2 = drawing.points[shape.p2]
table.insert(out, ('<line stroke="black" x1="%d" y1="%d" x2="%d" y2="%d"/>\n'):format(p1.x, p1.y, p2.x, p2.y))
export_point(p1, out)
export_point(p2, out)
end
function export_polygon(drawing, shape, out)
table.insert(out, '<polygon stroke="black" fill="none" points="')
for _,p in ipairs(shape.vertices) do
local vertex = drawing.points[p]
table.insert(out, ('%d,%d, '):format(vertex.x, vertex.y))
end
table.insert(out, '"/>\n')
for _,p in ipairs(shape.vertices) do
export_point(drawing.points[p], out)
end
end
function export_circle(drawing, shape, out)
local center = drawing.points[shape.center]
table.insert(out, ('<circle stroke="black" fill="none" cx="%d" cy="%d" r="%d"/>\n'):format(center.x, center.y, shape.radius))
export_point(center, out)
end
function export_circle_arc(drawing, shape, out)
local center = drawing.points[shape.center]
local cx,cy = center.x, center.y
-- angle 0
local zx,zy = cx+shape.radius, cy
local sx,sy = geom.rotate(cx,cy, zx,zy, shape.start_angle)
local ex,ey = geom.rotate(cx,cy, zx,zy, shape.end_angle)
local sweep_flag = 0
if shape.start_angle < shape.end_angle then
sweep_flag = 1
end
table.insert(out, ('<path stroke="black" fill="none" d="M %d %d A %d,%d 0 0 %d %d,%d"/>'):format(sx,sy, shape.radius,shape.radius, sweep_flag, ex,ey))
export_point(center, out)
end
function export_point(p, out)
table.insert(out, ('<circle cx="%d" cy="%d" r="1"/>\n'):format(p.x, p.y))
if p.name then
-- couple of adjustments:
-- * lines.love text coordinate starts at top left, but SVG starts at baseline.
--
-- * lines.love renders labels at x,y both offset by 5px on the screen.
-- While rendering SVG, however, we don't have pixels, only viewport coordinates. Seems to work well to just drop the increment.
table.insert(out, ('<text fill="black" x="%d" y="%d">%s</text>\n'):format(p.x, p.y+Drawing_text_baseline_height, p.name))
end
end
function basename(s)
return string.gsub(s, "(.*/)(.*)", "%2")
end