Welcome to mirror list, hosted at ThFree Co, Russian Federation.

image_utils.py « bpy_extras « modules « scripts « release - git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: eaf5922a19901bd43c2ff1faded4cfb9f4c8e6e9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
# SPDX-License-Identifier: GPL-2.0-or-later

# <pep8-80 compliant>

__all__ = (
    "load_image",
)


# limited replacement for BPyImage.comprehensiveImageLoad
def load_image(
        imagepath,
        dirname="",
        place_holder=False,
        recursive=False,
        ncase_cmp=True,
        convert_callback=None,
        verbose=False,
        relpath=None,
        check_existing=False,
        force_reload=False,
):
    """
    Return an image from the file path with options to search multiple paths
    and return a placeholder if its not found.

    :arg filepath: The image filename
       If a path precedes it, this will be searched as well.
    :type filepath: string
    :arg dirname: is the directory where the image may be located - any file at
       the end will be ignored.
    :type dirname: string
    :arg place_holder: if True a new place holder image will be created.
       this is useful so later you can relink the image to its original data.
    :type place_holder: bool
    :arg recursive: If True, directories will be recursively searched.
       Be careful with this if you have files in your root directory because
       it may take a long time.
    :type recursive: bool
    :arg ncase_cmp: on non windows systems, find the correct case for the file.
    :type ncase_cmp: bool
    :arg convert_callback: a function that takes an existing path and returns
       a new one. Use this when loading image formats blender may not support,
       the CONVERT_CALLBACK can take the path for a GIF (for example),
       convert it to a PNG and return the PNG's path.
       For formats blender can read, simply return the path that is given.
    :type convert_callback: function
    :arg relpath: If not None, make the file relative to this path.
    :type relpath: None or string
    :arg check_existing: If true,
       returns already loaded image datablock if possible
       (based on file path).
    :type check_existing: bool
    :arg force_reload: If true,
       force reloading of image (only useful when `check_existing`
       is also enabled).
    :type force_reload: bool
    :return: an image or None
    :rtype: :class:`bpy.types.Image`
    """
    import os
    import bpy

    # -------------------------------------------------------------------------
    # Utility Functions

    def _image_load_placeholder(path):
        name = path
        if type(path) is str:
            name = name.encode("utf-8", "replace")
        name = name.decode("utf-8", "replace")
        name = os.path.basename(name)

        image = bpy.data.images.new(name, 128, 128)
        # allow the path to be resolved later
        image.filepath = path
        image.source = 'FILE'
        return image

    def _image_load(path):
        import bpy

        if convert_callback:
            path = convert_callback(path)

        # Ensure we're not relying on the 'CWD' to resolve the path.
        if not os.path.isabs(path):
            path = os.path.abspath(path)

        try:
            image = bpy.data.images.load(path, check_existing=check_existing)
        except RuntimeError:
            image = None

        if verbose:
            if image:
                print("    image loaded '%s'" % path)
            else:
                print("    image load failed '%s'" % path)

        # image path has been checked so the path could not be read for some
        # reason, so be sure to return a placeholder
        if place_holder and image is None:
            image = _image_load_placeholder(path)

        if image:
            if force_reload:
                image.reload()
            if relpath is not None:
                # make relative
                from bpy.path import relpath as relpath_fn
                # can't always find the relative path
                # (between drive letters on windows)
                try:
                    filepath_rel = relpath_fn(path, start=relpath)
                except ValueError:
                    filepath_rel = None

                if filepath_rel is not None:
                    image.filepath_raw = filepath_rel

        return image

    def _recursive_search(paths, filename_check):
        for path in paths:
            for dirpath, _dirnames, filenames in os.walk(path):

                # skip '.svn'
                if dirpath[0] in {".", b'.'}:
                    continue

                for filename in filenames:
                    if filename_check(filename):
                        yield os.path.join(dirpath, filename)

    # -------------------------------------------------------------------------

    imagepath = bpy.path.native_pathsep(imagepath)

    if verbose:
        print("load_image('%s', '%s', ...)" % (imagepath, dirname))

    if os.path.exists(imagepath):
        return _image_load(imagepath)

    variants = [imagepath]

    if dirname:
        variants += [
            os.path.join(dirname, imagepath),
            os.path.join(dirname, bpy.path.basename(imagepath)),
        ]

    for filepath_test in variants:
        if ncase_cmp:
            ncase_variants = (
                filepath_test,
                bpy.path.resolve_ncase(filepath_test),
            )
        else:
            ncase_variants = (filepath_test, )

        for nfilepath in ncase_variants:
            if os.path.exists(nfilepath):
                return _image_load(nfilepath)

    if recursive:
        search_paths = []

        for dirpath_test in (os.path.dirname(imagepath), dirname):
            if os.path.exists(dirpath_test):
                search_paths.append(dirpath_test)
        search_paths[:] = bpy.path.reduce_dirs(search_paths)

        imagepath_base = bpy.path.basename(imagepath)
        if ncase_cmp:
            imagepath_base = imagepath_base.lower()

            def image_filter(fn):
                return (imagepath_base == fn.lower())
        else:
            def image_filter(fn):
                return (imagepath_base == fn)

        nfilepath = next(_recursive_search(search_paths, image_filter), None)
        if nfilepath is not None:
            return _image_load(nfilepath)

    # None of the paths exist so return placeholder
    if place_holder:
        return _image_load_placeholder(imagepath)

    # TODO comprehensiveImageLoad also searched in bpy.config.textureDir
    return None