py api
[blender.git] / release / scripts / bpymodules / BPyImage.py
1 # --------------------------------------------------------------------------
2 # BPyImage.py version 0.15
3 # --------------------------------------------------------------------------
4 # helper functions to be used by other scripts
5 # --------------------------------------------------------------------------
6 # ***** BEGIN GPL LICENSE BLOCK *****
7 #
8 # This program is free software; you can redistribute it and/or
9 # modify it under the terms of the GNU General Public License
10 # as published by the Free Software Foundation; either version 2
11 # of the License, or (at your option) any later version.
12 #
13 # This program is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 # GNU General Public License for more details.
17 #
18 # You should have received a copy of the GNU General Public License
19 # along with this program; if not, write to the Free Software Foundation,
20 # Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
21 #
22 # ***** END GPL LICENCE BLOCK *****
23 # --------------------------------------------------------------------------
24
25 #===========================================================================#
26 # Comprehensive image loader, will search and find the image                #
27 # Will return a blender image or a new image if the image is missing        #
28 #===========================================================================#
29 import bpy
30 from Blender import sys
31 try:
32         import os
33 except:
34         os=None
35
36 #==============================================#
37 # Return directory, where the file is          #
38 #==============================================#
39 def stripFile(path):
40         lastSlash = max(path.rfind('\\'), path.rfind('/'))
41         if lastSlash != -1:
42                 path = path[:lastSlash]
43                 newpath= '%s%s' % (path, sys.sep)
44         else:
45                 newpath= path
46         return newpath
47
48 #==============================================#
49 # Strips the slashes from the back of a string #
50 #==============================================#
51 def stripPath(path):
52         return path.split('/')[-1].split('\\')[-1]
53
54 #====================================================#
55 # Strips the prefix off the name before writing      #
56 #====================================================#
57 def stripExt(name): # name is a string
58         index = name.rfind('.')
59         if index != -1:
60                 return name[ : index ]
61         else:
62                 return name
63
64 def getExt(name):
65         index = name.rfind('.')
66         if index != -1:
67                 return name[index+1:]
68         return name
69
70 #====================================================#
71 # Adds a slash to the end of a path if its not there #
72 #====================================================#
73 def addSlash(path):
74         if not path:
75                 return ''
76         
77         elif path.endswith('\\') or path.endswith('/'):
78                 return path
79         return path + sys.sep
80
81
82 def comprehensiveImageLoad(imagePath, filePath, PLACE_HOLDER= True, RECURSIVE=True, VERBOSE=False):
83         '''
84         imagePath: The image filename
85                 If a path precedes it, this will be searched as well.
86                 
87         filePath: is the directory where the image may be located - any file at teh end will be ignored.
88         
89         PLACE_HOLDER: if True a new place holder image will be created.
90                 this is usefull so later you can relink the image to its original data.
91         
92         VERBOSE: If True debug info will be printed.
93         
94         RECURSIVE: If True, directories will be recursivly searched.
95                 Be carefull with this if you have files in your root directory because it may take a long time.
96         '''
97         
98         if VERBOSE: print 'img:', imagePath, 'file:', filePath
99         # When we have the file load it with this. try/except niceness.
100         def imageLoad(path):
101                 #if path.endswith('\\') or path.endswith('/'):
102                 #       raise 'INVALID PATH'
103                 try:
104                         img = bpy.images.new(filename=path)
105                         if VERBOSE: print '\t\tImage loaded "%s"' % path
106                         return img
107                 except:
108                         if VERBOSE:
109                                 if sys.exists(path): print '\t\tImage failed loading "%s", mabe its not a format blender can read.' % (path)
110                                 else: print '\t\tImage not found, making a place holder "%s"' % (path)
111                         if PLACE_HOLDER:
112                                 img= bpy.images.new(stripPath(path),4,4)
113                                 img.filename= path
114                                 return img #blank image
115                         else:
116                                 return None
117                         
118         # Image formats blender can read
119         IMAGE_EXT = ['jpg', 'jpeg', 'png', 'tga', 'bmp', 'rgb', 'sgi', 'bw', 'iff', 'lbm', # Blender Internal
120         'gif', 'psd', 'tif', 'tiff', 'pct', 'pict', 'pntg', 'qtif'] # Quacktime, worth a try.
121         
122         imageFileName =  stripPath(imagePath) # image path only
123         imageFileName_lower =  imageFileName.lower() # image path only
124         
125         if VERBOSE: print '\tSearchingExisting Images for "%s"' % imagePath
126         for i in bpy.images:
127                 if stripPath(i.filename.lower()) == imageFileName_lower:
128                         if VERBOSE: print '\t\tUsing existing image.'
129                         return i
130         
131         
132         if VERBOSE: print '\tAttempting to load "%s"' % imagePath
133         if sys.exists(imagePath):
134                 if VERBOSE: print '\t\tFile found where expected "%s".' % imagePath
135                 return imageLoad(imagePath)
136         
137         
138         
139         imageFileName_noext = stripExt(imageFileName) # With no extension.
140         imageFileName_noext_lower = stripExt(imageFileName_lower) # With no extension.
141         imageFilePath = stripFile(imagePath)
142         
143         # Remove relative path from image path
144         if imageFilePath.startswith('./') or imageFilePath.startswith('.\\'):
145                 imageFilePath = imageFilePath[2:]
146         
147         
148         # Attempt to load from obj path.
149         tmpPath = stripFile(filePath) + stripPath(imageFileName)
150         if sys.exists(tmpPath):
151                 if VERBOSE: print '\t\tFile found in path (1)"%s".' % tmpPath
152                 return imageLoad(tmpPath)
153         
154         
155         # os needed if we go any further.
156         if not os:
157                 if VERBOSE: print '\t\tCreating a placeholder with a face path: "%s".' % imagePath
158                 return imageLoad(imagePath) # Will jus treturn a placeholder.
159         
160         
161         # We have os.
162         # GATHER PATHS.
163         paths = {} # Store possible paths we may use, dict for no doubles.
164         tmpPath = addSlash(sys.expandpath('//')) # Blenders path
165         if sys.exists(tmpPath):
166                 if VERBOSE: print '\t\tSearching in %s' % tmpPath
167                 paths[tmpPath] = [os.listdir(tmpPath)] # Orig name for loading 
168                 paths[tmpPath].append([f.lower() for f in paths[tmpPath][0]]) # Lower case list.
169                 paths[tmpPath].append([stripExt(f) for f in paths[tmpPath][1]]) # Lower case no ext
170         else:
171                 if VERBOSE: print '\tNo Path: "%s"' % tmpPath
172         
173         tmpPath = imageFilePath
174         if sys.exists(tmpPath):
175                 if VERBOSE: print '\t\tSearching in %s' % tmpPath
176                 paths[tmpPath] = [os.listdir(tmpPath)] # Orig name for loading 
177                 paths[tmpPath].append([f.lower() for f in paths[tmpPath][0]]) # Lower case list.
178                 paths[tmpPath].append([stripExt(f) for f in paths[tmpPath][1]]) # Lower case no ext
179         else:
180                 if VERBOSE: print '\tNo Path: "%s"' % tmpPath
181
182         tmpPath = stripFile(filePath)
183         if sys.exists(tmpPath):
184                 if VERBOSE: print '\t\tSearching in %s' % tmpPath
185                 paths[tmpPath] = [os.listdir(tmpPath)] # Orig name for loading 
186                 paths[tmpPath].append([f.lower() for f in paths[tmpPath][0]]) # Lower case list.
187                 paths[tmpPath].append([stripExt(f) for f in paths[tmpPath][1]]) # Lower case no ext
188         else:
189                 if VERBOSE: print '\tNo Path: "%s"' % tmpPath
190
191         tmpPath = addSlash(bpy.config.textureDir)
192         if tmpPath and sys.exists(tmpPath):
193                 if VERBOSE: print '\t\tSearching in %s' % tmpPath
194                 paths[tmpPath] = [os.listdir(tmpPath)] # Orig name for loading 
195                 paths[tmpPath].append([f.lower() for f in paths[tmpPath][0]]) # Lower case list.
196                 paths[tmpPath].append([stripExt(f) for f in paths[tmpPath][1]]) # Lower case no ext
197         else:
198                 if VERBOSE: print '\tNo Path: "%s"' % tmpPath
199         
200         # Add path if relative image patrh was given.
201         tmp_paths= paths.keys()
202         for k in tmp_paths:
203                 tmpPath = k + imageFilePath
204                 if sys.exists(tmpPath):
205                         paths[tmpPath] = [os.listdir(tmpPath)] # Orig name for loading 
206                         paths[tmpPath].append([f.lower() for f in paths[tmpPath][0]]) # Lower case list.
207                         paths[tmpPath].append([stripExt(f) for f in paths[tmpPath][1]]) # Lower case no ext
208                 else:
209                         if VERBOSE: print '\tNo Path: "%s"' % tmpPath
210         # DONE
211         # 
212         for path, files in paths.iteritems():
213                 if sys.exists(path + imageFileName):
214                         if VERBOSE: print '\tFound image at path: "%s" file" "%s"' % (path, imageFileName)
215                         return imageLoad(path + imageFileName)
216                 
217                 # If the files not there then well do a case insensitive seek.
218                 filesOrigCase = files[0]
219                 filesLower = files[1]
220                 filesLowerNoExt = files[2]
221                 
222                 # We are going to try in index the file directly, if its not there just keep on
223                 
224                 index = None
225                 try:
226                         # Is it just a case mismatch?
227                         index = filesLower.index(imageFileName_lower)
228                 except:
229                         try:
230                                 # Have the extensions changed?
231                                 index = filesLowerNoExt.index(imageFileName_noext_lower)
232                                 
233                                 ext = getExt( filesLower[index] ) # Get the extension of the file that matches all but ext.
234                                 
235                                 # Check that the ext is useable eg- not a 3ds file :)
236                                 if ext.lower() not in IMAGE_EXT:
237                                         index = None
238                         
239                         except:
240                                 index = None
241                 
242                 if index != None:
243                         tmpPath = path + filesOrigCase[index]
244                         img = imageLoad( tmpPath )
245                         if img != None:
246                                 if VERBOSE: print '\t\tImage Found "%s"' % tmpPath
247                                 return img
248         
249         if RECURSIVE:
250                 # IMAGE NOT FOUND IN ANY OF THE DIRS!, DO A RECURSIVE SEARCH.
251                 if VERBOSE: print '\t\tImage Not Found in any of the dirs, doing a recusrive search'
252                 for path in paths.iterkeys():
253                         # Were not going to use files
254                         if path == '/' or len(path) == 3 and path[1:] == ':\\':
255                                 continue
256                         
257                         # print path , 'ASS'
258                         
259                         #------------------
260                         # finds the file starting at the root.
261                         #       def findImage(findRoot, imagePath):
262                         #W---------------
263                         
264                         # ROOT, DIRS, FILES
265                         pathWalk = os.walk(path)
266                         pathList = [True]
267                         
268                         matchList = [] # Store a list of (match, size), choose the biggest.
269                         while True:
270                                 try:
271                                         pathList  = pathWalk.next()
272                                 except:
273                                         break
274                                 
275                                 for file in pathList[2]:
276                                         file_lower = file.lower()
277                                         # FOUND A MATCH
278                                         if (file_lower == imageFileName_lower) or\
279                                         (stripExt(file_lower) == imageFileName_noext_lower and getExt(file_lower) in IMAGE_EXT):
280                                                 name = pathList[0] + sys.sep + file
281                                                 size = os.path.getsize(name)
282                                                 if VERBOSE: print '\t\t\tfound:', name 
283                                                 matchList.append( (name, size) )
284                         
285                         if matchList:
286                                 # Sort by file size
287                                 matchList.sort(lambda A, B: cmp(B[1], A[1]) )
288                                 
289                                 if VERBOSE: print '\t\tFound "%s"' % matchList[0][0]
290                                 
291                                 # Loop through all we have found
292                                 img = None
293                                 for match in matchList:
294                                         img = imageLoad(match[0]) # 0 - first, 0 - pathname
295                                         if img != None:
296                                                 break
297                                 return img
298         
299         # No go.
300         if VERBOSE: print '\t\tImage Not Found after looking everywhere! "%s"' % imagePath
301         return imageLoad(imagePath) # Will jus treturn a placeholder.