diff options
author | Campbell Barton <ideasman42@gmail.com> | 2010-02-05 18:20:12 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2010-02-05 18:20:12 +0300 |
commit | a1d2b842220a881611ff2f77f2acd299863dbf8b (patch) | |
tree | d99d70ae33a19ce84aaab31a55f0e985c0e0ee8b /release | |
parent | 31955feba15cc243cb54d3532ca504cf2de38bec (diff) |
patch [#20910] Support for exporting UV layouts to EPS files
also improved this so visible UVs are exported unless 'All UVs' is enabled, taking into account local-view and mesh face selection.
Diffstat (limited to 'release')
-rw-r--r-- | release/scripts/op/uv.py | 183 |
1 files changed, 120 insertions, 63 deletions
diff --git a/release/scripts/op/uv.py b/release/scripts/op/uv.py index 4e55f538a45..8e8fce6d4f8 100644 --- a/release/scripts/op/uv.py +++ b/release/scripts/op/uv.py @@ -32,18 +32,31 @@ class ExportUVLayout(bpy.types.Operator): path = StringProperty(name="File Path", description="File path used for exporting the SVG file", maxlen=1024, default="") check_existing = BoolProperty(name="Check Existing", description="Check and warn on overwriting existing files", default=True, options={'HIDDEN'}) - only_selected = BoolProperty(name="Only Selected", description="Export Only the selected UVs", default=False) - + export_all = BoolProperty(name="All UV's", description="Export all UVs in this mesh (not just the visible ones)", default=False) + mode = EnumProperty(items=( + ('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.")), + name="Format", + description="File format to export the UV layout to", + default='SVG') + def poll(self, context): obj = context.active_object return (obj and obj.type == 'MESH') + def _space_image(self, context): + space_data = context.space_data + if type(space_data) == bpy.types.SpaceImageEditor: + return space_data + else: + return None + 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 - space_data = context.space_data - if type(space_data) == bpy.types.SpaceImageEditor: + space_data = self._space_image(context) + if space_data: image = space_data.image if image: width, height = tuple(context.space_data.image.size) @@ -53,6 +66,41 @@ class ExportUVLayout(bpy.types.Operator): return image_width, image_height + def _face_uv_iter(self, context): + obj = context.active_object + mesh = obj.data + uv_layer = mesh.active_uv_texture.data + uv_layer_len = len(uv_layer) + + if not self.properties.export_all: + + local_image = Ellipsis + + if context.tool_settings.uv_local_view: + space_data = self._space_image(context) + if space_data: + local_image = space_data.image + + faces = mesh.faces + + for i in range(uv_layer_len): + uv_elem = uv_layer[i] + # context checks + if faces[i].selected and (local_image is Ellipsis or local_image == uv_elem.image): + #~ uv = uv_elem.uv + #~ if False not in uv_elem.uv_selected[:len(uv)]: + #~ yield (i, uv) + + # 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) + + + + def execute(self, context): # for making an XML compatible string from xml.sax.saxutils import escape @@ -64,70 +112,79 @@ class ExportUVLayout(bpy.types.Operator): bpy.ops.object.mode_set(mode='OBJECT', toggle=False) image_width, image_height = self._image_size(context) - mesh = obj.data + faces = mesh.faces - active_uv_layer = None - for lay in mesh.uv_textures: - if lay.active: - active_uv_layer = lay.data - break - - fuvs = [(uv.uv1, uv.uv2, uv.uv3, uv.uv4) for uv in active_uv_layer] - fuvs_cpy = [(uv[0].copy(), uv[1].copy(), uv[2].copy(), uv[3].copy()) for uv in fuvs] - - # as a list - faces = mesh.faces[:] - - fuvsel = [(False not in uv.uv_selected) for uv in active_uv_layer] - + mode = self.properties.mode + file = open(self.properties.path, "w") fw = file.write - 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') - - desc = "%s, %s, %s (Blender %s)" % (basename(bpy.data.filename), obj.name, mesh.name, bpy.app.version_string) - fw('<desc>%s</desc>\n' % escape(desc)) - - # svg colors - fill_settings = [] - fill_default = 'fill="grey"' - for mat in mesh.materials if mesh.materials else [None]: - if mat: - fill_settings.append('fill="rgb(%d, %d, %d)"' % tuple(int(c * 255) for c in mat.diffuse_color)) - else: - fill_settings.append(fill_default) - - only_selected = self.properties.only_selected - - for i, uv in enumerate(active_uv_layer): - - if only_selected and False in uv.uv_selected: - continue - - if len(faces[i].verts) == 3: - uvs = uv.uv1, uv.uv2, uv.uv3 - else: - uvs = uv.uv1, uv.uv2, uv.uv3, uv.uv4 - - try: # rare cases material index is invalid. - fill = fill_settings[faces[i].material_index] - except IndexError: - fill = fill_default - - fw('<polygon %s fill-opacity="0.5" stroke="black" stroke-width="1px" \n' % fill) - fw(' points="') - - for j, uv in enumerate(uvs): - x, y = uv.x, 1.0 - uv.y - fw('%.3f,%.3f ' % (x * image_width, y * image_height)) - fw('" />\n') - fw('\n') - fw('</svg>\n') + 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') + desc = "%s, %s, %s (Blender %s)" % (basename(bpy.data.filename), obj.name, mesh.name, bpy.app.version_string) + fw('<desc>%s</desc>\n' % escape(desc)) + + # svg colors + fill_settings = [] + fill_default = 'fill="grey"' + for mat in mesh.materials if mesh.materials else [None]: + if mat: + fill_settings.append('fill="rgb(%d, %d, %d)"' % tuple(int(c*255) for c in mat.diffuse_color)) + 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 + + fw('<polygon %s fill-opacity="0.5" stroke="black" stroke-width="1px" \n' % fill) + fw(' points="') + + 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') + fw('newpath\n') + + for i, uvs in self._face_uv_iter(context): + for j, uv in enumerate(uvs): + x, y = uv[0], uv[1] + if j==0: + fw('%.5f %.5f moveto\n' % (x * image_width, y * image_height)) + else: + fw('%.5f %.5f lineto\n' % (x * image_width, y * image_height)) + + fw('closepath\n') + fw('stroke\n') + fw('showpage\n') + fw('%%EOF\n') if is_editmode: bpy.ops.object.mode_set(mode='EDIT', toggle=False) |