| 
									
										
										
										
											2010-01-13 19:00:18 +00:00
										 |  |  | # ##### BEGIN GPL LICENSE BLOCK ##### | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | #  This program is free software; you can redistribute it and/or | 
					
						
							|  |  |  | #  modify it under the terms of the GNU General Public License | 
					
						
							|  |  |  | #  as published by the Free Software Foundation; either version 2 | 
					
						
							|  |  |  | #  of the License, or (at your option) any later version. | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | #  This program is distributed in the hope that it will be useful, | 
					
						
							|  |  |  | #  but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  | #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
					
						
							|  |  |  | #  GNU General Public License for more details. | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | #  You should have received a copy of the GNU General Public License | 
					
						
							|  |  |  | #  along with this program; if not, write to the Free Software Foundation, | 
					
						
							| 
									
										
										
										
											2010-02-12 13:34:04 +00:00
										 |  |  | #  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | 
					
						
							| 
									
										
										
										
											2010-01-13 19:00:18 +00:00
										 |  |  | # | 
					
						
							|  |  |  | # ##### END GPL LICENSE BLOCK ##### | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-01-31 14:46:28 +00:00
										 |  |  | # <pep8 compliant> | 
					
						
							| 
									
										
										
										
											2010-01-13 19:00:18 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | import bpy | 
					
						
							|  |  |  | from bpy.props import * | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-01-31 14:46:28 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-01-13 19:00:18 +00:00
										 |  |  | class ExportUVLayout(bpy.types.Operator): | 
					
						
							| 
									
										
										
										
											2010-02-11 23:13:47 +00:00
										 |  |  |     '''Export the Mesh as SVG''' | 
					
						
							| 
									
										
										
										
											2010-01-13 19:00:18 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     bl_idname = "uv.export_layout" | 
					
						
							|  |  |  |     bl_label = "Export UV Layout" | 
					
						
							| 
									
										
										
										
											2010-03-01 00:03:51 +00:00
										 |  |  |     bl_options = {'REGISTER', 'UNDO'} | 
					
						
							| 
									
										
										
										
											2010-01-31 14:46:28 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-06-14 03:52:10 +00:00
										 |  |  |     filepath = StringProperty(name="File Path", description="File path used for exporting the SVG file", maxlen=1024, default="") | 
					
						
							| 
									
										
										
										
											2010-02-01 22:04:33 +00:00
										 |  |  |     check_existing = BoolProperty(name="Check Existing", description="Check and warn on overwriting existing files", default=True, options={'HIDDEN'}) | 
					
						
							| 
									
										
										
										
											2010-02-05 15:20:12 +00:00
										 |  |  |     export_all = BoolProperty(name="All UV's", description="Export all UVs in this mesh (not just the visible ones)", default=False) | 
					
						
							|  |  |  |     mode = EnumProperty(items=( | 
					
						
							| 
									
										
										
										
											2010-02-11 23:13:47 +00:00
										 |  |  |                         ('SVG', "Scalable Vector Graphic (.svg)", "Export the UV layout to a vector SVG file"), | 
					
						
							|  |  |  |                         ('EPS', "Encapsulate PostScript (.eps)", "Export the UV layout to a vector EPS file")), | 
					
						
							| 
									
										
										
										
											2010-02-05 15:20:12 +00:00
										 |  |  |                 name="Format", | 
					
						
							|  |  |  |                 description="File format to export the UV layout to", | 
					
						
							|  |  |  |                 default='SVG') | 
					
						
							| 
									
										
										
										
											2010-02-22 23:32:58 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-08-09 01:37:09 +00:00
										 |  |  |     @classmethod | 
					
						
							|  |  |  |     def poll(cls, context): | 
					
						
							| 
									
										
										
										
											2010-01-29 15:20:25 +00:00
										 |  |  |         obj = context.active_object | 
					
						
							|  |  |  |         return (obj and obj.type == 'MESH') | 
					
						
							| 
									
										
										
										
											2010-01-31 14:46:28 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-02-05 15:20:12 +00:00
										 |  |  |     def _space_image(self, context): | 
					
						
							|  |  |  |         space_data = context.space_data | 
					
						
							|  |  |  |         if type(space_data) == bpy.types.SpaceImageEditor: | 
					
						
							|  |  |  |             return space_data | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             return None | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-01-13 19:53:34 +00:00
										 |  |  |     def _image_size(self, context, default_width=1024, default_height=1024): | 
					
						
							|  |  |  |         # fallback if not in image context. | 
					
						
							|  |  |  |         image_width, image_height = default_width, default_height | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-02-05 15:20:12 +00:00
										 |  |  |         space_data = self._space_image(context) | 
					
						
							|  |  |  |         if space_data: | 
					
						
							| 
									
										
										
										
											2010-01-13 19:53:34 +00:00
										 |  |  |             image = space_data.image | 
					
						
							|  |  |  |             if image: | 
					
						
							|  |  |  |                 width, height = tuple(context.space_data.image.size) | 
					
						
							|  |  |  |                 # incase no data is found. | 
					
						
							|  |  |  |                 if width and height: | 
					
						
							|  |  |  |                     image_width, image_height = width, height | 
					
						
							| 
									
										
										
										
											2010-01-31 14:46:28 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-01-13 19:53:34 +00:00
										 |  |  |         return image_width, image_height | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-02-05 15:20:12 +00:00
										 |  |  |     def _face_uv_iter(self, context): | 
					
						
							|  |  |  |         obj = context.active_object | 
					
						
							|  |  |  |         mesh = obj.data | 
					
						
							| 
									
										
										
										
											2010-08-23 22:16:45 +00:00
										 |  |  |         uv_layer = mesh.uv_textures.active.data | 
					
						
							| 
									
										
										
										
											2010-02-05 15:20:12 +00:00
										 |  |  |         uv_layer_len = len(uv_layer) | 
					
						
							| 
									
										
										
										
											2010-02-22 23:32:58 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-02-05 15:20:12 +00:00
										 |  |  |         if not self.properties.export_all: | 
					
						
							| 
									
										
										
										
											2010-02-22 23:32:58 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-02-05 15:20:12 +00:00
										 |  |  |             local_image = Ellipsis | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-08-17 17:03:52 +00:00
										 |  |  |             if context.tool_settings.show_uv_local_view: | 
					
						
							| 
									
										
										
										
											2010-02-05 15:20:12 +00:00
										 |  |  |                 space_data = self._space_image(context) | 
					
						
							|  |  |  |                 if space_data: | 
					
						
							|  |  |  |                     local_image = space_data.image | 
					
						
							| 
									
										
										
										
											2010-02-22 23:32:58 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-02-05 15:20:12 +00:00
										 |  |  |             faces = mesh.faces | 
					
						
							| 
									
										
										
										
											2010-02-22 23:32:58 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-02-05 15:20:12 +00:00
										 |  |  |             for i in range(uv_layer_len): | 
					
						
							|  |  |  |                 uv_elem = uv_layer[i] | 
					
						
							|  |  |  |                 # context checks | 
					
						
							| 
									
										
										
										
											2010-07-15 16:56:04 +00:00
										 |  |  |                 if faces[i].select and (local_image is Ellipsis or local_image == uv_elem.image): | 
					
						
							| 
									
										
										
										
											2010-02-05 15:20:12 +00:00
										 |  |  |                     #~ uv = uv_elem.uv | 
					
						
							| 
									
										
										
										
											2010-07-15 16:56:04 +00:00
										 |  |  |                     #~ if False not in uv_elem.select_uv[:len(uv)]: | 
					
						
							| 
									
										
										
										
											2010-02-05 15:20:12 +00:00
										 |  |  |                     #~     yield (i, uv) | 
					
						
							| 
									
										
										
										
											2010-02-22 23:32:58 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-02-05 15:20:12 +00:00
										 |  |  |                     # just write what we see. | 
					
						
							|  |  |  |                     yield (i, uv_layer[i].uv) | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             # all, simple | 
					
						
							|  |  |  |             for i in range(uv_layer_len): | 
					
						
							|  |  |  |                 yield (i, uv_layer[i].uv) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-01-13 19:00:18 +00:00
										 |  |  |     def execute(self, context): | 
					
						
							| 
									
										
										
										
											2010-01-20 11:08:50 +00:00
										 |  |  |         # for making an XML compatible string | 
					
						
							|  |  |  |         from xml.sax.saxutils import escape | 
					
						
							|  |  |  |         from os.path import basename | 
					
						
							| 
									
										
										
										
											2010-01-31 14:46:28 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-01-29 15:20:25 +00:00
										 |  |  |         obj = context.active_object | 
					
						
							|  |  |  |         is_editmode = (obj.mode == 'EDIT') | 
					
						
							| 
									
										
										
										
											2010-01-13 19:00:18 +00:00
										 |  |  |         if is_editmode: | 
					
						
							|  |  |  |             bpy.ops.object.mode_set(mode='OBJECT', toggle=False) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-01-13 19:53:34 +00:00
										 |  |  |         image_width, image_height = self._image_size(context) | 
					
						
							| 
									
										
										
										
											2010-01-29 15:20:25 +00:00
										 |  |  |         mesh = obj.data | 
					
						
							| 
									
										
										
										
											2010-02-05 15:20:12 +00:00
										 |  |  |         faces = mesh.faces | 
					
						
							| 
									
										
										
										
											2010-01-31 14:46:28 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-02-05 15:20:12 +00:00
										 |  |  |         mode = self.properties.mode | 
					
						
							| 
									
										
										
										
											2010-02-22 23:32:58 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-08-06 01:40:54 +00:00
										 |  |  |         filepath = self.properties.filepath | 
					
						
							|  |  |  |         filepath = bpy.path.ensure_ext(filepath, "." + mode.lower()) | 
					
						
							|  |  |  |         file = open(filepath, "w") | 
					
						
							| 
									
										
										
										
											2010-01-13 19:00:18 +00:00
										 |  |  |         fw = file.write | 
					
						
							| 
									
										
										
										
											2010-01-31 14:46:28 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-02-05 15:20:12 +00:00
										 |  |  |         if mode == 'SVG': | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             fw('<?xml version="1.0" standalone="no"?>\n') | 
					
						
							|  |  |  |             fw('<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" \n') | 
					
						
							|  |  |  |             fw('  "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">\n') | 
					
						
							|  |  |  |             fw('<svg width="%dpx" height="%dpx" viewBox="0px 0px %dpx %dpx"\n' % (image_width, image_height, image_width, image_height)) | 
					
						
							|  |  |  |             fw('     xmlns="http://www.w3.org/2000/svg" version="1.1">\n') | 
					
						
							| 
									
										
										
										
											2010-06-02 17:58:28 +00:00
										 |  |  |             desc = "%s, %s, %s (Blender %s)" % (basename(bpy.data.filepath), obj.name, mesh.name, bpy.app.version_string) | 
					
						
							| 
									
										
										
										
											2010-02-05 15:20:12 +00:00
										 |  |  |             fw('<desc>%s</desc>\n' % escape(desc)) | 
					
						
							| 
									
										
										
										
											2010-02-22 23:32:58 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-02-05 15:20:12 +00:00
										 |  |  |             # svg colors | 
					
						
							|  |  |  |             fill_settings = [] | 
					
						
							|  |  |  |             fill_default = 'fill="grey"' | 
					
						
							|  |  |  |             for mat in mesh.materials if mesh.materials else [None]: | 
					
						
							|  |  |  |                 if mat: | 
					
						
							| 
									
										
										
										
											2010-02-22 23:32:58 +00:00
										 |  |  |                     fill_settings.append('fill="rgb(%d, %d, %d)"' % tuple(int(c * 255) for c in mat.diffuse_color)) | 
					
						
							| 
									
										
										
										
											2010-02-05 15:20:12 +00:00
										 |  |  |                 else: | 
					
						
							|  |  |  |                     fill_settings.append(fill_default) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             for i, uvs in self._face_uv_iter(context): | 
					
						
							|  |  |  |                 try: # rare cases material index is invalid. | 
					
						
							|  |  |  |                     fill = fill_settings[faces[i].material_index] | 
					
						
							|  |  |  |                 except IndexError: | 
					
						
							|  |  |  |                     fill = fill_default | 
					
						
							| 
									
										
										
										
											2010-02-22 23:32:58 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-02-05 15:20:12 +00:00
										 |  |  |                 fw('<polygon %s fill-opacity="0.5" stroke="black" stroke-width="1px" \n' % fill) | 
					
						
							|  |  |  |                 fw('  points="') | 
					
						
							| 
									
										
										
										
											2010-02-22 23:32:58 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-02-05 15:20:12 +00:00
										 |  |  |                 for j, uv in enumerate(uvs): | 
					
						
							|  |  |  |                     x, y = uv[0], 1.0 - uv[1] | 
					
						
							|  |  |  |                     fw('%.3f,%.3f ' % (x * image_width, y * image_height)) | 
					
						
							|  |  |  |                 fw('" />\n') | 
					
						
							|  |  |  |             fw('\n') | 
					
						
							|  |  |  |             fw('</svg>\n') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         elif mode == 'EPS': | 
					
						
							|  |  |  |             fw('%!PS-Adobe-3.0 EPSF-3.0\n') | 
					
						
							|  |  |  |             fw("%%%%Creator: Blender %s\n" % bpy.app.version_string) | 
					
						
							|  |  |  |             fw('%%Pages: 1\n') | 
					
						
							|  |  |  |             fw('%%Orientation: Portrait\n') | 
					
						
							|  |  |  |             fw("%%%%BoundingBox: 0 0 %d %d\n" % (image_width, image_height)) | 
					
						
							|  |  |  |             fw("%%%%HiResBoundingBox: 0.0 0.0 %.4f %.4f\n" % (image_width, image_height)) | 
					
						
							|  |  |  |             fw('%%EndComments\n') | 
					
						
							|  |  |  |             fw('%%Page: 1 1\n') | 
					
						
							|  |  |  |             fw('0 0 translate\n') | 
					
						
							|  |  |  |             fw('1.0 1.0 scale\n') | 
					
						
							|  |  |  |             fw('0 0 0 setrgbcolor\n') | 
					
						
							|  |  |  |             fw('[] 0 setdash\n') | 
					
						
							|  |  |  |             fw('1 setlinewidth\n') | 
					
						
							|  |  |  |             fw('1 setlinejoin\n') | 
					
						
							|  |  |  |             fw('1 setlinecap\n') | 
					
						
							| 
									
										
										
										
											2010-05-23 06:00:08 +00:00
										 |  |  |             fw('/DRAW {') | 
					
						
							|  |  |  |             # can remove from here to next comment to disable filling, aparently alpha is not supported | 
					
						
							|  |  |  |             fw('gsave\n') | 
					
						
							|  |  |  |             fw('0.7 setgray\n') | 
					
						
							|  |  |  |             fw('fill\n') | 
					
						
							|  |  |  |             fw('grestore\n') | 
					
						
							|  |  |  |             fw('0 setgray\n') | 
					
						
							|  |  |  |             # remove to here | 
					
						
							|  |  |  |             fw('stroke\n') | 
					
						
							|  |  |  |             fw('} def\n') | 
					
						
							| 
									
										
										
										
											2010-02-05 15:20:12 +00:00
										 |  |  |             fw('newpath\n') | 
					
						
							| 
									
										
										
										
											2010-06-09 19:12:03 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-05-23 06:00:08 +00:00
										 |  |  |             firstline = True | 
					
						
							| 
									
										
										
										
											2010-02-05 15:20:12 +00:00
										 |  |  |             for i, uvs in self._face_uv_iter(context): | 
					
						
							|  |  |  |                 for j, uv in enumerate(uvs): | 
					
						
							|  |  |  |                     x, y = uv[0], uv[1] | 
					
						
							| 
									
										
										
										
											2010-02-22 23:32:58 +00:00
										 |  |  |                     if j == 0: | 
					
						
							| 
									
										
										
										
											2010-05-23 06:00:08 +00:00
										 |  |  |                         if not firstline: | 
					
						
							|  |  |  |                             fw('closepath\n') | 
					
						
							|  |  |  |                             fw('DRAW\n') | 
					
						
							|  |  |  |                             fw('newpath\n') | 
					
						
							|  |  |  |                         firstline = False | 
					
						
							| 
									
										
										
										
											2010-02-05 15:20:12 +00:00
										 |  |  |                         fw('%.5f %.5f moveto\n' % (x * image_width, y * image_height)) | 
					
						
							|  |  |  |                     else: | 
					
						
							|  |  |  |                         fw('%.5f %.5f lineto\n' % (x * image_width, y * image_height)) | 
					
						
							| 
									
										
										
										
											2010-02-22 23:32:58 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-02-05 15:20:12 +00:00
										 |  |  |             fw('closepath\n') | 
					
						
							| 
									
										
										
										
											2010-05-23 06:00:08 +00:00
										 |  |  |             fw('DRAW\n') | 
					
						
							| 
									
										
										
										
											2010-02-05 15:20:12 +00:00
										 |  |  |             fw('showpage\n') | 
					
						
							|  |  |  |             fw('%%EOF\n') | 
					
						
							| 
									
										
										
										
											2010-01-31 14:46:28 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-01-13 19:00:18 +00:00
										 |  |  |         if is_editmode: | 
					
						
							|  |  |  |             bpy.ops.object.mode_set(mode='EDIT', toggle=False) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return {'FINISHED'} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def invoke(self, context, event): | 
					
						
							| 
									
										
										
										
											2010-09-02 04:53:05 +00:00
										 |  |  |         wm = context.window_manager | 
					
						
							| 
									
										
										
										
											2010-01-13 19:00:18 +00:00
										 |  |  |         wm.add_fileselect(self) | 
					
						
							|  |  |  |         return {'RUNNING_MODAL'} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-01-31 14:46:28 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-01-13 19:00:18 +00:00
										 |  |  | def menu_func(self, context): | 
					
						
							| 
									
										
										
										
											2010-07-14 11:58:19 +00:00
										 |  |  |     import os | 
					
						
							|  |  |  |     default_path = os.path.splitext(bpy.data.filepath)[0] + ".svg" | 
					
						
							| 
									
										
										
										
											2010-06-14 03:52:10 +00:00
										 |  |  |     self.layout.operator(ExportUVLayout.bl_idname).filepath = default_path | 
					
						
							| 
									
										
										
										
											2010-01-13 19:00:18 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-02-14 11:21:21 +00:00
										 |  |  | def register(): | 
					
						
							|  |  |  |     bpy.types.IMAGE_MT_uvs.append(menu_func) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-02-22 23:32:58 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-05-23 06:00:08 +00:00
										 |  |  | def unregister(): | 
					
						
							| 
									
										
										
										
											2010-02-14 11:21:21 +00:00
										 |  |  |     bpy.types.IMAGE_MT_uvs.remove(menu_func) | 
					
						
							| 
									
										
										
										
											2010-02-16 09:55:07 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | if __name__ == "__main__": | 
					
						
							|  |  |  |     register() |