1 # ##### BEGIN GPL LICENSE BLOCK #####
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.
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.
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.
17 # ##### END GPL LICENSE BLOCK #####
26 # limited replacement for BPyImage.comprehensiveImageLoad
27 def load_image(imagepath,
32 convert_callback=None,
39 Return an image from the file path with options to search multiple paths
40 and return a placeholder if its not found.
42 :arg filepath: The image filename
43 If a path precedes it, this will be searched as well.
44 :type filepath: string
45 :arg dirname: is the directory where the image may be located - any file at
46 the end will be ignored.
48 :arg place_holder: if True a new place holder image will be created.
49 this is useful so later you can relink the image to its original data.
50 :type place_holder: bool
51 :arg recursive: If True, directories will be recursively searched.
52 Be careful with this if you have files in your root directory because
53 it may take a long time.
55 :arg ncase_cmp: on non windows systems, find the correct case for the file.
57 :arg convert_callback: a function that takes an existing path and returns
58 a new one. Use this when loading image formats blender may not support,
59 the CONVERT_CALLBACK can take the path for a GIF (for example),
60 convert it to a PNG and return the PNG's path.
61 For formats blender can read, simply return the path that is given.
62 :type convert_callback: function
63 :arg relpath: If not None, make the file relative to this path.
64 :type relpath: None or string
65 :arg check_existing: If true,
66 returns already loaded image datablock if possible
68 :type check_existing: bool
69 :arg force_reload: If true,
70 force reloading of image (only useful when `check_existing`
72 :type force_reload: bool
73 :return: an image or None
74 :rtype: :class:`bpy.types.Image`
79 # -------------------------------------------------------------------------
82 def _image_load_placeholder(path):
83 name = bpy.path.basename(path)
84 if type(name) == bytes:
85 name = name.decode("utf-8", "replace")
86 image = bpy.data.images.new(name, 128, 128)
87 # allow the path to be resolved later
92 def _image_load(path):
96 path = convert_callback(path)
99 image = bpy.data.images.load(path, check_existing)
105 print(" image loaded '%s'" % path)
107 print(" image load failed '%s'" % path)
109 # image path has been checked so the path could not be read for some
110 # reason, so be sure to return a placeholder
111 if place_holder and image is None:
112 image = _image_load_placeholder(path)
117 if relpath is not None:
119 from bpy.path import relpath as relpath_fn
120 # can't always find the relative path
121 # (between drive letters on windows)
123 filepath_rel = relpath_fn(path, start=relpath)
127 if filepath_rel is not None:
128 image.filepath_raw = filepath_rel
132 def _recursive_search(paths, filename_check):
134 for dirpath, dirnames, filenames in os.walk(path):
137 if dirpath[0] in {".", b'.'}:
140 for filename in filenames:
141 if filename_check(filename):
142 yield os.path.join(dirpath, filename)
144 # -------------------------------------------------------------------------
147 print("load_image('%s', '%s', ...)" % (imagepath, dirname))
149 if os.path.exists(imagepath):
150 return _image_load(imagepath)
152 variants = [imagepath]
155 variants += [os.path.join(dirname, imagepath),
156 os.path.join(dirname, bpy.path.basename(imagepath)),
159 for filepath_test in variants:
161 ncase_variants = (filepath_test,
162 bpy.path.resolve_ncase(filepath_test),
165 ncase_variants = (filepath_test, )
167 for nfilepath in ncase_variants:
168 if os.path.exists(nfilepath):
169 return _image_load(nfilepath)
174 for dirpath_test in (os.path.dirname(imagepath), dirname):
175 if os.path.exists(dirpath_test):
176 search_paths.append(dirpath_test)
177 search_paths[:] = bpy.path.reduce_dirs(search_paths)
179 imagepath_base = bpy.path.basename(imagepath)
181 imagepath_base = imagepath_base.lower()
183 def image_filter(fn):
184 return (imagepath_base == fn.lower())
186 def image_filter(fn):
187 return (imagepath_base == fn)
189 nfilepath = next(_recursive_search(search_paths, image_filter), None)
190 if nfilepath is not None:
191 return _image_load(nfilepath)
193 # None of the paths exist so return placeholder
195 return _image_load_placeholder(imagepath)
197 # TODO comprehensiveImageLoad also searched in bpy.config.textureDir