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 19# <pep8-80 compliant> 20 21__all__ = ( 22 "load_image", 23) 24 25 26# limited replacement for BPyImage.comprehensiveImageLoad 27def load_image( 28 imagepath, 29 dirname="", 30 place_holder=False, 31 recursive=False, 32 ncase_cmp=True, 33 convert_callback=None, 34 verbose=False, 35 relpath=None, 36 check_existing=False, 37 force_reload=False, 38): 39 """ 40 Return an image from the file path with options to search multiple paths 41 and return a placeholder if its not found. 42 43 :arg filepath: The image filename 44 If a path precedes it, this will be searched as well. 45 :type filepath: string 46 :arg dirname: is the directory where the image may be located - any file at 47 the end will be ignored. 48 :type dirname: string 49 :arg place_holder: if True a new place holder image will be created. 50 this is useful so later you can relink the image to its original data. 51 :type place_holder: bool 52 :arg recursive: If True, directories will be recursively searched. 53 Be careful with this if you have files in your root directory because 54 it may take a long time. 55 :type recursive: bool 56 :arg ncase_cmp: on non windows systems, find the correct case for the file. 57 :type ncase_cmp: bool 58 :arg convert_callback: a function that takes an existing path and returns 59 a new one. Use this when loading image formats blender may not support, 60 the CONVERT_CALLBACK can take the path for a GIF (for example), 61 convert it to a PNG and return the PNG's path. 62 For formats blender can read, simply return the path that is given. 63 :type convert_callback: function 64 :arg relpath: If not None, make the file relative to this path. 65 :type relpath: None or string 66 :arg check_existing: If true, 67 returns already loaded image datablock if possible 68 (based on file path). 69 :type check_existing: bool 70 :arg force_reload: If true, 71 force reloading of image (only useful when `check_existing` 72 is also enabled). 73 :type force_reload: bool 74 :return: an image or None 75 :rtype: :class:`bpy.types.Image` 76 """ 77 import os 78 import bpy 79 80 # ------------------------------------------------------------------------- 81 # Utility Functions 82 83 def _image_load_placeholder(path): 84 name = path 85 if type(path) is str: 86 name = name.encode("utf-8", "replace") 87 name = name.decode("utf-8", "replace") 88 name = os.path.basename(name) 89 90 image = bpy.data.images.new(name, 128, 128) 91 # allow the path to be resolved later 92 image.filepath = path 93 image.source = 'FILE' 94 return image 95 96 def _image_load(path): 97 import bpy 98 99 if convert_callback: 100 path = convert_callback(path) 101 102 # Ensure we're not relying on the 'CWD' to resolve the path. 103 if not os.path.isabs(path): 104 path = os.path.abspath(path) 105 106 try: 107 image = bpy.data.images.load(path, check_existing=check_existing) 108 except RuntimeError: 109 image = None 110 111 if verbose: 112 if image: 113 print(" image loaded '%s'" % path) 114 else: 115 print(" image load failed '%s'" % path) 116 117 # image path has been checked so the path could not be read for some 118 # reason, so be sure to return a placeholder 119 if place_holder and image is None: 120 image = _image_load_placeholder(path) 121 122 if image: 123 if force_reload: 124 image.reload() 125 if relpath is not None: 126 # make relative 127 from bpy.path import relpath as relpath_fn 128 # can't always find the relative path 129 # (between drive letters on windows) 130 try: 131 filepath_rel = relpath_fn(path, start=relpath) 132 except ValueError: 133 filepath_rel = None 134 135 if filepath_rel is not None: 136 image.filepath_raw = filepath_rel 137 138 return image 139 140 def _recursive_search(paths, filename_check): 141 for path in paths: 142 for dirpath, _dirnames, filenames in os.walk(path): 143 144 # skip '.svn' 145 if dirpath[0] in {".", b'.'}: 146 continue 147 148 for filename in filenames: 149 if filename_check(filename): 150 yield os.path.join(dirpath, filename) 151 152 # ------------------------------------------------------------------------- 153 154 imagepath = bpy.path.native_pathsep(imagepath) 155 156 if verbose: 157 print("load_image('%s', '%s', ...)" % (imagepath, dirname)) 158 159 if os.path.exists(imagepath): 160 return _image_load(imagepath) 161 162 variants = [imagepath] 163 164 if dirname: 165 variants += [ 166 os.path.join(dirname, imagepath), 167 os.path.join(dirname, bpy.path.basename(imagepath)), 168 ] 169 170 for filepath_test in variants: 171 if ncase_cmp: 172 ncase_variants = ( 173 filepath_test, 174 bpy.path.resolve_ncase(filepath_test), 175 ) 176 else: 177 ncase_variants = (filepath_test, ) 178 179 for nfilepath in ncase_variants: 180 if os.path.exists(nfilepath): 181 return _image_load(nfilepath) 182 183 if recursive: 184 search_paths = [] 185 186 for dirpath_test in (os.path.dirname(imagepath), dirname): 187 if os.path.exists(dirpath_test): 188 search_paths.append(dirpath_test) 189 search_paths[:] = bpy.path.reduce_dirs(search_paths) 190 191 imagepath_base = bpy.path.basename(imagepath) 192 if ncase_cmp: 193 imagepath_base = imagepath_base.lower() 194 195 def image_filter(fn): 196 return (imagepath_base == fn.lower()) 197 else: 198 def image_filter(fn): 199 return (imagepath_base == fn) 200 201 nfilepath = next(_recursive_search(search_paths, image_filter), None) 202 if nfilepath is not None: 203 return _image_load(nfilepath) 204 205 # None of the paths exist so return placeholder 206 if place_holder: 207 return _image_load_placeholder(imagepath) 208 209 # TODO comprehensiveImageLoad also searched in bpy.config.textureDir 210 return None 211