Skip to content

Instantly share code, notes, and snippets.

Created August 2, 2015 22:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save anonymous/b51291c5a63183a53a79 to your computer and use it in GitHub Desktop.
Save anonymous/b51291c5a63183a53a79 to your computer and use it in GitHub Desktop.
bl_info = {
"name": "Viewport to SVG",
"author": "Zeffi, modified by eppo",
"version": (0, 1, 3),
"blender": (2, 75, 0),
"location": "View3D > Properties",
"description": "Generate an SVG file from selected objects",
"warning": "Objects should have LocRotScale applied -> Ctrl-A menu",
"tracker_url": "http://blenderartists.org/forum/showthread.php?375100-Export-%28a-lot-of%29-curves-to-svg",
"category": "Render"}
# Cycles Diffuse Color is used for svg outlines.
import bpy
from bpy_extras.view3d_utils import location_3d_to_region_2d as loc3d2d
def flatten(l, ltypes=(list, tuple)):
ltype = type(l)
l = list(l)
i = 0
while i < len(l):
while isinstance(l[i], ltypes):
if not l[i]:
l.pop(i)
i -= 1
break
else:
l[i:i + 1] = l[i]
i += 1
return ltype(l)
def write_svg(context, region):
wm = bpy.context.window_manager
width, height = region.width, region.height
rv3d = context.space_data.region_3d
#bpy.context.area.type = 'VIEW_3D'
C= bpy.context
styles = []
styles.append('0x000000') #black by default
svg_body= []
for idx, ob in enumerate(C.selected_objects):
ob_svg= []
if ob.type == 'MESH':
C.scene.objects.active = ob
vertlist = ob.data.vertices
edge_list = []
for edge in ob.data.edges:
idx1, idx2 = edge.vertices[:]
co1, co2 = vertlist[idx1].co, vertlist[idx2].co
co2d_1 = loc3d2d(region, rv3d, co1)
co2d_2 = loc3d2d(region, rv3d, co2)
edge_list.append((co2d_1, co2d_2))
ob_uses_style = 0
ob_svg.append('\n<g id="%s">' % ob.name)
# TODO Gamma correction, again?
if len(ob.material_slots)>0 and hasattr(ob.material_slots[0].material,'diffuse_color'):
hex_col = '0x%02x%02x%02x' % (ob.material_slots[0].material.diffuse_color * 255.0)[:]
if str(hex_col) not in styles:
styles.append(str(hex_col))
ob_uses_style = len(styles)-1
else:
for i, colr in enumerate(styles):
if str(hex_col) == colr:
ob_uses_style = i
break
nones=0 #count None type errors
for idx, edge in enumerate(edge_list):
path_name="path"+str(idx)
co1, co2 = edge
if type(co1)==type(None) or type(co2)==type(None):
nones += 1
continue
ob_svg.append("""\
<path class="fil0 str%s" d="M %s,%s %s,%s" id="%s"/>""" % (str(ob_uses_style),co1.x, height-co1.y, co2.x, height-co2.y, path_name))
ob_svg.append('</g>')
svg_body.append(ob_svg)
svg_body.append('</svg>')
print(nones, '"None type" errors.')
# End SVG body
# Prepare style block
svg_styles=[]
svg_styles.append('''\
<defs>
<style type="text/css">
<![CDATA[''')
en= list(enumerate(styles))
for i, v in enumerate(en):
svg_styles.append('''\
.str%s {stroke:#%s;stroke-width:2}''' % (str(i), v[1][2:]))
svg_styles.append('''\
.fil0 {fill:none}
]]>
</style></defs>
''')
# Drop some header info in
svg_header = '''\
<svg width="%spx" height="%spx" id="svg2" version="1.1">\n''' % (width, height)
file_to_write = open(wm.path_fn, 'w')
file_to_write.write(svg_header)
file_to_write.write('\n'.join(svg_styles))
file_to_write.write(str('\n'.join(flatten(svg_body))))
file_to_write.close()
print ('Saved as ',wm.path_fn)
#That's All Folks.
def draw_data(self, context):
region = context.region
write_svg(context, region)
return
class RenderButton(bpy.types.Operator):
"""Will write svg file"""
bl_idname = "svg.render"
bl_label = "Render to svg"
def execute(self, context):
draw_data(self, context)
return{'FINISHED'}
class SVGPanel(bpy.types.Panel):
"""Creates a Panel in the Object properties window"""
bl_label = "Render SVG"
bl_idname = "OBJECT_PT_render"
bl_space_type = "VIEW_3D"
bl_region_type = "UI"
bl_context = "object"
def draw(self, context):
wm = bpy.context.window_manager
layout = self.layout
obj = context.object
row = layout.row()
sel=[]
for ob in bpy.context.selected_objects:
sel.append(ob.name)
if len(sel)>3:
sel=[]
sel.append("A whole lot of Objects")
row.label(text="Current Selection: " + str(sel))
# Path selector
column = layout.column()
column.prop(wm, 'path_fn')
# display button
self.layout.operator("svg.render", text='Render')
classes = [SVGPanel, RenderButton]
bpy.types.WindowManager.path_fn=bpy.props.StringProperty(name='', subtype='FILE_PATH',
default='\\tmp\\exported.svg', description='Save SVG file - use absolute path - checkbox on T-shelf')
def register():
for i in classes:
bpy.utils.register_class(i)
def unregister():
for i in classes:
bpy.utils.unregister_class(i)
if __name__ == "__main__":
register()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment