1 # ##### BEGIN GPL LICENSE BLOCK #####
3 # This program is free software; you can redistribute it and/or
4 # modify it under the terms of the GNU General Public License
5 # as published by the Free Software Foundation; either version 2
6 # of the License, or (at your option) any later version.
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
13 # You should have received a copy of the GNU General Public License
14 # along with this program; if not, write to the Free Software Foundation,
15 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 # ##### END GPL LICENSE BLOCK #####
22 from bpy.types import Operator
23 from bpy.props import StringProperty
26 class EditExternally(Operator):
27 '''Edit image in an external application'''
28 bl_idname = "image.external_edit"
29 bl_label = "Image Edit Externally"
30 bl_options = {'REGISTER'}
32 filepath = StringProperty(
34 description="Path to an image file",
38 def _editor_guess(self, context):
41 image_editor = context.user_preferences.filepaths.image_editor
43 # use image editor in the preferences when available.
45 if sys.platform[:3] == "win":
46 image_editor = ["start"] # not tested!
47 elif sys.platform == "darwin":
48 image_editor = ["open"]
50 image_editor = ["gimp"]
52 if sys.platform == "darwin":
53 # blender file selector treats .app as a folder
54 # and will include a trailing backslash, so we strip it.
55 image_editor.rstrip('\\')
56 image_editor = ["open", "-a", image_editor]
58 image_editor = [image_editor]
62 def execute(self, context):
66 filepath = self.filepath
69 self.report({'ERROR'}, "Image path not set")
72 filepath = os.path.normpath(bpy.path.abspath(filepath))
74 if not os.path.exists(filepath):
75 self.report({'ERROR'},
76 "Image path %r not found, image may be packed or "
77 "unsaved." % filepath)
80 cmd = self._editor_guess(context) + [filepath]
87 self.report({'ERROR'},
88 "Image editor not found, "
89 "please specify in User Preferences > File")
95 def invoke(self, context, event):
97 filepath = context.space_data.image.filepath
100 traceback.print_exc()
101 self.report({'ERROR'}, "Image not found on disk")
104 self.filepath = filepath
105 self.execute(context)
110 class SaveDirty(Operator):
111 """Save all modified textures"""
112 bl_idname = "image.save_dirty"
113 bl_label = "Save Dirty"
114 bl_options = {'REGISTER', 'UNDO'}
116 def execute(self, context):
118 for image in bpy.data.images:
120 filepath = bpy.path.abspath(image.filepath)
121 if "\\" not in filepath and "/" not in filepath:
122 self.report({'WARNING'}, "Invalid path: " + filepath)
123 elif filepath in unique_paths:
124 self.report({'WARNING'},
125 "Path used by more then one image: %r" %
128 unique_paths.add(filepath)
133 class ProjectEdit(Operator):
134 """Edit a snapshot of the viewport in an external image editor"""
135 bl_idname = "image.project_edit"
136 bl_label = "Project Edit"
137 bl_options = {'REGISTER'}
141 def execute(self, context):
144 EXT = "png" # could be made an option but for now ok
146 for image in bpy.data.images:
149 if 'FINISHED' not in bpy.ops.paint.image_from_view():
153 for image in bpy.data.images:
159 self.report({'ERROR'}, "Could not make new image")
162 filepath = os.path.basename(bpy.data.filepath)
163 filepath = os.path.splitext(filepath)[0]
164 # fixes <memory> rubbish, needs checking
165 # filepath = bpy.path.clean_name(filepath)
167 if bpy.data.is_saved:
168 filepath = "//" + filepath
170 tmpdir = context.user_preferences.filepaths.temporary_directory
171 filepath = os.path.join(tmpdir, "project_edit")
176 filepath += "_" + bpy.path.clean_name(obj.name)
178 filepath_final = filepath + "." + EXT
181 while os.path.exists(bpy.path.abspath(filepath_final)):
182 filepath_final = filepath + ("%.3d.%s" % (i, EXT))
185 image_new.name = bpy.path.basename(filepath_final)
186 ProjectEdit._proj_hack[0] = image_new.name
188 image_new.filepath_raw = filepath_final # TODO, filepath raw is crummy
189 image_new.file_format = 'PNG'
193 bpy.ops.image.external_edit(filepath=filepath_final)
194 except RuntimeError as re:
195 self.report({'ERROR'}, str(re))
200 class ProjectApply(Operator):
201 """Project edited image back onto the object"""
202 bl_idname = "image.project_apply"
203 bl_label = "Project Apply"
204 bl_options = {'REGISTER'}
206 def execute(self, context):
207 image_name = ProjectEdit._proj_hack[0] # TODO, deal with this nicer
210 image = bpy.data.images[image_name]
213 traceback.print_exc()
214 self.report({'ERROR'}, "Could not find image '%s'" % image_name)
218 bpy.ops.paint.project_image(image=image_name)