201 lines
		
	
	
		
			6.0 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			201 lines
		
	
	
		
			6.0 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| # ##### 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,
 | |
| #  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 | |
| #
 | |
| # ##### END GPL LICENSE BLOCK #####
 | |
| 
 | |
| # <pep8 compliant>
 | |
| 
 | |
| """
 | |
| Example Usage:
 | |
| 
 | |
| ./blender.bin --background --python tests/python/batch_import.py -- \
 | |
|     --operator="bpy.ops.import_scene.obj" \
 | |
|     --path="/fe/obj" \
 | |
|     --match="*.obj" \
 | |
|     --start=0 --end=10 \
 | |
|     --save_path=/tmp/test
 | |
| 
 | |
| ./blender.bin --background --python tests/python/batch_import.py -- \
 | |
|     --operator="bpy.ops.import_scene.autodesk_3ds" \
 | |
|     --path="/fe/" \
 | |
|     --match="*.3ds" \
 | |
|     --start=0 --end=1000 \
 | |
|     --save_path=/tmp/test
 | |
| 
 | |
| ./blender.bin --background --addons io_curve_svg --python tests/python/batch_import.py -- \
 | |
|     --operator="bpy.ops.import_curve.svg" \
 | |
|     --path="/usr/" \
 | |
|     --match="*.svg" \
 | |
|     --start=0 --end=1000 \
 | |
|     --save_path=/tmp/test
 | |
| 
 | |
| """
 | |
| 
 | |
| import os
 | |
| import sys
 | |
| 
 | |
| 
 | |
| def batch_import(
 | |
|     operator="",
 | |
|     path="",
 | |
|     save_path="",
 | |
|     match="",
 | |
|     start=0,
 | |
|     end=sys.maxsize,
 | |
| ):
 | |
|     import addon_utils
 | |
|     _reset_all = addon_utils.reset_all  # XXX, hack
 | |
|     _disable_all = addon_utils.disable_all  # XXX, hack
 | |
| 
 | |
|     import fnmatch
 | |
| 
 | |
|     path = os.path.normpath(path)
 | |
|     path = os.path.abspath(path)
 | |
| 
 | |
|     match_upper = match.upper()
 | |
| 
 | |
|     def pattern_match(a):
 | |
|         return fnmatch.fnmatchcase(a.upper(), match_upper)
 | |
| 
 | |
|     def file_generator(path):
 | |
|         for dirpath, dirnames, filenames in os.walk(path):
 | |
|             # skip '.git'
 | |
|             dirnames[:] = [d for d in dirnames if not d.startswith(".")]
 | |
| 
 | |
|             for filename in filenames:
 | |
|                 if pattern_match(filename):
 | |
|                     yield os.path.join(dirpath, filename)
 | |
| 
 | |
|     print("Collecting %r files in %s" % (match, path), end="")
 | |
| 
 | |
|     files = list(file_generator(path))
 | |
|     files_len = len(files)
 | |
|     end = min(end, len(files))
 | |
|     print(" found %d" % files_len, end="")
 | |
| 
 | |
|     files.sort()
 | |
|     files = files[start:end]
 | |
|     if len(files) != files_len:
 | |
|         print(" using a subset in (%d, %d), total %d" % (start, end, len(files)), end="")
 | |
| 
 | |
|     import bpy
 | |
|     op = eval(operator)
 | |
| 
 | |
|     tot_done = 0
 | |
|     tot_fail = 0
 | |
| 
 | |
|     for i, f in enumerate(files):
 | |
|         print("    %s(filepath=%r) # %d of %d" % (operator, f, i + start, len(files)))
 | |
| 
 | |
|         # hack so loading the new file doesn't undo our loaded addons
 | |
|         addon_utils.reset_all = lambda: None  # XXX, hack
 | |
|         addon_utils.disable_all = lambda: None  # XXX, hack
 | |
| 
 | |
|         bpy.ops.wm.read_factory_settings(use_empty=True)
 | |
| 
 | |
|         addon_utils.reset_all = _reset_all  # XXX, hack
 | |
|         addon_utils.disable_all = _disable_all  # XXX, hack
 | |
| 
 | |
|         result = op(filepath=f)
 | |
| 
 | |
|         if 'FINISHED' in result:
 | |
|             tot_done += 1
 | |
|         else:
 | |
|             tot_fail += 1
 | |
| 
 | |
|         if save_path:
 | |
|             fout = os.path.join(save_path, os.path.relpath(f, path))
 | |
|             fout_blend = os.path.splitext(fout)[0] + ".blend"
 | |
| 
 | |
|             print("\tSaving: %r" % fout_blend)
 | |
| 
 | |
|             fout_dir = os.path.dirname(fout_blend)
 | |
|             os.makedirs(fout_dir, exist_ok=True)
 | |
| 
 | |
|             bpy.ops.wm.save_as_mainfile(filepath=fout_blend)
 | |
| 
 | |
|     print("finished, done:%d,  fail:%d" % (tot_done, tot_fail))
 | |
| 
 | |
| 
 | |
| def main():
 | |
|     import optparse
 | |
| 
 | |
|     # get the args passed to blender after "--", all of which are ignored by blender specifically
 | |
|     # so python may receive its own arguments
 | |
|     argv = sys.argv
 | |
| 
 | |
|     if "--" not in argv:
 | |
|         argv = []  # as if no args are passed
 | |
|     else:
 | |
|         argv = argv[argv.index("--") + 1:]  # get all args after "--"
 | |
| 
 | |
|     # When --help or no args are given, print this help
 | |
|     usage_text = "Run blender in background mode with this script:"
 | |
|     usage_text += "  blender --background --python " + __file__ + " -- [options]"
 | |
| 
 | |
|     parser = optparse.OptionParser(usage=usage_text)
 | |
| 
 | |
|     # Example background utility, add some text and renders or saves it (with options)
 | |
|     # Possible types are: string, int, long, choice, float and complex.
 | |
|     parser.add_option(
 | |
|         "-o",
 | |
|         "--operator",
 | |
|         dest="operator",
 | |
|         help="This text will be used to render an image",
 | |
|         type="string")
 | |
|     parser.add_option("-p", "--path", dest="path", help="Path to use for searching for files", type='string')
 | |
|     parser.add_option("-m", "--match", dest="match", help="Wildcard to match filename", type="string")
 | |
|     parser.add_option(
 | |
|         "-s",
 | |
|         "--save_path",
 | |
|         dest="save_path",
 | |
|         help="Save the input file to a blend file in a new location",
 | |
|         metavar='string')
 | |
|     parser.add_option("-S", "--start", dest="start", help="From collected files, start with this index", metavar='int')
 | |
|     parser.add_option("-E", "--end", dest="end", help="From collected files, end with this index", metavar='int')
 | |
| 
 | |
|     options, _args = parser.parse_args(argv)  # In this example we wont use the args
 | |
| 
 | |
|     if not argv:
 | |
|         parser.print_help()
 | |
|         return
 | |
| 
 | |
|     if not options.operator:
 | |
|         print("Error: --operator=\"some string\" argument not given, aborting.")
 | |
|         parser.print_help()
 | |
|         return
 | |
| 
 | |
|     if options.start is None:
 | |
|         options.start = 0
 | |
| 
 | |
|     if options.end is None:
 | |
|         options.end = sys.maxsize
 | |
| 
 | |
|     # Run the example function
 | |
|     batch_import(operator=options.operator,
 | |
|                  path=options.path,
 | |
|                  save_path=options.save_path,
 | |
|                  match=options.match,
 | |
|                  start=int(options.start),
 | |
|                  end=int(options.end),
 | |
|                  )
 | |
| 
 | |
|     print("batch job finished, exiting")
 | |
| 
 | |
| 
 | |
| if __name__ == "__main__":
 | |
|     main()
 |