Blender  V2.59
ui_snapshot.py
Go to the documentation of this file.
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()