|
Blender
V2.59
|
00001 # $Id: ui_snapshot.py 36820 2011-05-22 12:28:23Z campbellbarton $ 00002 # ***** BEGIN GPL LICENSE BLOCK ***** 00003 # 00004 # This program is free software; you can redistribute it and/or 00005 # modify it under the terms of the GNU General Public License 00006 # as published by the Free Software Foundation; either version 2 00007 # of the License, or (at your option) any later version. 00008 # 00009 # This program is distributed in the hope that it will be useful, 00010 # but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 # GNU General Public License for more details. 00013 # 00014 # You should have received a copy of the GNU General Public License 00015 # along with this program; if not, write to the Free Software Foundation, 00016 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00017 # 00018 # Contributor(s): Campbell Barton 00019 # 00020 # ***** END GPL LICENSE BLOCK ***** 00021 00022 # screenshot panels, corrently only works for render, scene and world. 00023 # needs some further work to setup blender contexts for all possible panels. 00024 00025 import os 00026 00027 REMOVE_CMP_IMAGES = True 00028 TEMP_DIR = "/tmp" 00029 00030 PROPERTY_MAPPING = { 00031 "armature_edit": 'DATA', 00032 "bone": 'BONE', 00033 "bone_constraint": '', 00034 "constraint": '', 00035 "curve_edit": '', 00036 "data": '', 00037 "imagepaint": '', 00038 "lattice_edit": 'DATA', 00039 "material": 'MATERIAL', 00040 "mball_edit": '', 00041 "mesh_edit": '', 00042 "modifier": '', 00043 "object": 'OBJECT', 00044 "objectmode": '', 00045 "particle": '', 00046 "particlemode": '', 00047 "physics": '', 00048 "posemode": '', # toolbar 00049 "render": 'RENDER', 00050 "scene": 'SCENE', 00051 "surface_edit": '', 00052 "text_edit": '', 00053 "texture": '', 00054 "vertexpaint": '', 00055 "weightpaint": '', 00056 "world": 'WORLD', 00057 } 00058 00059 # format: % (new, blank, out) 00060 magick_command = 'convert "%s" "%s" \( -clone 0 -clone 1 -compose difference -composite -threshold 0 \) -delete 1 -alpha off -compose copy_opacity -composite -trim "%s" ' 00061 00062 import bpy 00063 00064 00065 def clear_startup_blend(): 00066 import bpy 00067 if bpy.ops.object.mode_set.poll(): 00068 bpy.ops.object.mode_set(mode='OBJECT') 00069 00070 import bpy 00071 00072 for scene in bpy.data.scenes: 00073 for obj in scene.objects: 00074 scene.objects.unlink(obj) 00075 00076 00077 def force_redraw(): 00078 bpy.ops.wm.redraw_timer(type='DRAW_WIN_SWAP', iterations=1) 00079 00080 def fake_poll(cls, context): 00081 return True 00082 00083 def screenshot(path): 00084 force_redraw() 00085 bpy.ops.screen.screenshot(filepath=path) 00086 00087 def context_setup(bl_context, class_name): 00088 if bl_context == "object": 00089 bpy.ops.object.add(type='EMPTY') 00090 elif bl_context == "bone": 00091 bpy.ops.object.armature_add() 00092 bpy.ops.object.mode_set(mode='EDIT') 00093 elif bl_context == "armature_edit": 00094 bpy.ops.object.armature_add() 00095 bpy.ops.object.mode_set(mode='EDIT') 00096 elif bl_context == "posemode": 00097 bpy.ops.object.armature_add() 00098 bpy.ops.object.mode_set(mode='POSE') 00099 elif bl_context == "lattice_edit": 00100 bpy.ops.object.add(type='LATTICE') 00101 bpy.ops.object.mode_set(mode='EDIT') 00102 elif bl_context == "material": 00103 bpy.ops.object.add(type='MESH') 00104 bpy.context.object.data.materials.append(bpy.data.materials.new("Material")) 00105 bpy.ops.object.mode_set(mode='EDIT') 00106 00107 00108 def main(): 00109 panel_subclasses = [] 00110 00111 for cls_name in dir(bpy.types): 00112 cls = getattr(bpy.types, cls_name) 00113 if issubclass(cls, bpy.types.Panel): 00114 if bpy.types.Panel is cls: 00115 continue 00116 00117 panel_subclasses.append((cls, getattr(cls, "poll", None))) 00118 00119 for cls, poll in panel_subclasses: 00120 cls.poll = classmethod(fake_poll) 00121 cls.bl_options = set() # so we dont get 'DEFAULT_CLOSED' 00122 bpy.utils.unregister_class(cls) 00123 00124 # collect context types 00125 button_contexts = {None} 00126 for cls, poll in panel_subclasses: 00127 button_contexts.add(getattr(cls, "bl_context", None)) 00128 button_contexts.remove(None) 00129 00130 # get the properties space 00131 space_props = None 00132 for sa in bpy.context.screen.areas: 00133 space = sa.spaces.active 00134 if space.type == 'PROPERTIES': 00135 space_props = space 00136 break 00137 if space_props is None: 00138 raise Exception("no properties space type found") 00139 00140 for bl_context in sorted(button_contexts): 00141 print(list(sorted(button_contexts))) 00142 # TODO 00143 # if bl_context in PROPERTY_SKIP: 00144 # continue 00145 00146 ## TESTING ONLY 00147 #if bl_context != "material": 00148 # continue 00149 00150 prop_context = PROPERTY_MAPPING[bl_context] 00151 if not prop_context: 00152 print(" TODO, skipping", bl_context) 00153 continue 00154 00155 space_props.context = prop_context 00156 00157 for cls, poll in panel_subclasses: 00158 if cls.bl_space_type == 'PROPERTIES': 00159 if cls.bl_region_type == 'WINDOW': 00160 if cls.bl_context == bl_context: 00161 00162 clear_startup_blend() 00163 context_setup(bl_context, cls.__name__) 00164 00165 file_base = os.path.join(TEMP_DIR, "%s_%s" % (bl_context, "_" + cls.__name__.replace(".", "_"))) 00166 file_old = file_base + "_old.png" 00167 file_new = file_base + "_new.png" 00168 file_crop = file_base + ".png" 00169 00170 screenshot(file_old) 00171 00172 # we need a new unique name so old 'closed' settings dont get applied 00173 idname = getattr(cls, "bl_idname", cls.__name__.split(".")[-1]) 00174 cls.bl_idname = idname + "_" 00175 00176 bpy.utils.register_class(cls) 00177 00178 screenshot(file_new) 00179 00180 bpy.utils.unregister_class(cls) 00181 00182 # screenshot magic 00183 from os import system 00184 system(magick_command % (file_new, file_old, file_crop)) 00185 00186 if REMOVE_CMP_IMAGES: 00187 from os import remove 00188 remove(file_old) 00189 remove(file_new) 00190 00191 00192 if __name__ == "__main__": 00193 main()