batch_import.py 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. # ##### BEGIN GPL LICENSE BLOCK #####
  2. #
  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.
  7. #
  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.
  12. #
  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.
  16. #
  17. # ##### END GPL LICENSE BLOCK #####
  18. # <pep8 compliant>
  19. """
  20. Example Usage:
  21. ./blender.bin --background --python tests/python/batch_import.py -- \
  22. --operator="bpy.ops.import_scene.obj" \
  23. --path="/fe/obj" \
  24. --match="*.obj" \
  25. --start=0 --end=10 \
  26. --save_path=/tmp/test
  27. ./blender.bin --background --python tests/python/batch_import.py -- \
  28. --operator="bpy.ops.import_scene.autodesk_3ds" \
  29. --path="/fe/" \
  30. --match="*.3ds" \
  31. --start=0 --end=1000 \
  32. --save_path=/tmp/test
  33. ./blender.bin --background --addons io_curve_svg --python tests/python/batch_import.py -- \
  34. --operator="bpy.ops.import_curve.svg" \
  35. --path="/usr/" \
  36. --match="*.svg" \
  37. --start=0 --end=1000 \
  38. --save_path=/tmp/test
  39. """
  40. import os
  41. import sys
  42. def batch_import(
  43. operator="",
  44. path="",
  45. save_path="",
  46. match="",
  47. start=0,
  48. end=sys.maxsize,
  49. ):
  50. import addon_utils
  51. _reset_all = addon_utils.reset_all # XXX, hack
  52. _disable_all = addon_utils.disable_all # XXX, hack
  53. import fnmatch
  54. path = os.path.normpath(path)
  55. path = os.path.abspath(path)
  56. match_upper = match.upper()
  57. def pattern_match(a):
  58. return fnmatch.fnmatchcase(a.upper(), match_upper)
  59. def file_generator(path):
  60. for dirpath, dirnames, filenames in os.walk(path):
  61. # skip '.git'
  62. dirnames[:] = [d for d in dirnames if not d.startswith(".")]
  63. for filename in filenames:
  64. if pattern_match(filename):
  65. yield os.path.join(dirpath, filename)
  66. print("Collecting %r files in %s" % (match, path), end="")
  67. files = list(file_generator(path))
  68. files_len = len(files)
  69. end = min(end, len(files))
  70. print(" found %d" % files_len, end="")
  71. files.sort()
  72. files = files[start:end]
  73. if len(files) != files_len:
  74. print(" using a subset in (%d, %d), total %d" % (start, end, len(files)), end="")
  75. import bpy
  76. op = eval(operator)
  77. tot_done = 0
  78. tot_fail = 0
  79. for i, f in enumerate(files):
  80. print(" %s(filepath=%r) # %d of %d" % (operator, f, i + start, len(files)))
  81. # hack so loading the new file doesn't undo our loaded addons
  82. addon_utils.reset_all = lambda: None # XXX, hack
  83. addon_utils.disable_all = lambda: None # XXX, hack
  84. bpy.ops.wm.read_factory_settings(use_empty=True)
  85. addon_utils.reset_all = _reset_all # XXX, hack
  86. addon_utils.disable_all = _disable_all # XXX, hack
  87. result = op(filepath=f)
  88. if 'FINISHED' in result:
  89. tot_done += 1
  90. else:
  91. tot_fail += 1
  92. if save_path:
  93. fout = os.path.join(save_path, os.path.relpath(f, path))
  94. fout_blend = os.path.splitext(fout)[0] + ".blend"
  95. print("\tSaving: %r" % fout_blend)
  96. fout_dir = os.path.dirname(fout_blend)
  97. os.makedirs(fout_dir, exist_ok=True)
  98. bpy.ops.wm.save_as_mainfile(filepath=fout_blend)
  99. print("finished, done:%d, fail:%d" % (tot_done, tot_fail))
  100. def main():
  101. import optparse
  102. # get the args passed to blender after "--", all of which are ignored by blender specifically
  103. # so python may receive its own arguments
  104. argv = sys.argv
  105. if "--" not in argv:
  106. argv = [] # as if no args are passed
  107. else:
  108. argv = argv[argv.index("--") + 1:] # get all args after "--"
  109. # When --help or no args are given, print this help
  110. usage_text = "Run blender in background mode with this script:"
  111. usage_text += " blender --background --python " + __file__ + " -- [options]"
  112. parser = optparse.OptionParser(usage=usage_text)
  113. # Example background utility, add some text and renders or saves it (with options)
  114. # Possible types are: string, int, long, choice, float and complex.
  115. parser.add_option("-o", "--operator", dest="operator", help="This text will be used to render an image", type="string")
  116. parser.add_option("-p", "--path", dest="path", help="Path to use for searching for files", type='string')
  117. parser.add_option("-m", "--match", dest="match", help="Wildcard to match filename", type="string")
  118. parser.add_option("-s", "--save_path", dest="save_path", help="Save the input file to a blend file in a new location", metavar='string')
  119. parser.add_option("-S", "--start", dest="start", help="From collected files, start with this index", metavar='int')
  120. parser.add_option("-E", "--end", dest="end", help="From collected files, end with this index", metavar='int')
  121. options, _args = parser.parse_args(argv) # In this example we wont use the args
  122. if not argv:
  123. parser.print_help()
  124. return
  125. if not options.operator:
  126. print("Error: --operator=\"some string\" argument not given, aborting.")
  127. parser.print_help()
  128. return
  129. if options.start is None:
  130. options.start = 0
  131. if options.end is None:
  132. options.end = sys.maxsize
  133. # Run the example function
  134. batch_import(operator=options.operator,
  135. path=options.path,
  136. save_path=options.save_path,
  137. match=options.match,
  138. start=int(options.start),
  139. end=int(options.end),
  140. )
  141. print("batch job finished, exiting")
  142. if __name__ == "__main__":
  143. main()