absolute path to a file

Paul St George email at paulstgeorge.com
Mon Aug 19 16:06:00 EDT 2019


On 19/08/2019 14:16, Cameron Simpson wrote:
> On 19Aug2019 08:52, Paul St George <email at paulstgeorge.com> wrote:
>> On 19/08/2019 01:31, Cameron Simpson wrote:
>>> On 18Aug2019 17:29, Paul St George <email at paulstgeorge.com> wrote:
>>>> On 18/08/2019 02:03, Cameron Simpson wrote:
>>>> 1: Is image01.tif a real existing file when you ran this code?
>>>> Yes. image01.tif is real, existing and apparent.
>>> But in what directory? What is its _actual_ full path as you expect 
>>> it to be?
>>
>> Aha. The Blender file that I am using to test this on has two images 
>> used as textures. They reside at:
>> /Users/Lion/Desktop/test8/image01.tif
>> /Users/Lion/Desktop/images/image02.tif
>>
>> The Blender file is at /Users/Lion/Desktop/test8/tifftest8.blend
> 
> There's a remark on that web page I mentioned that suggests that the 
> leading '//' indicates the filename is relative to the Blender model, so 
> the context directory for the '//' is likely /Users/Lion/Desktop/test8.

Yes. That makes sense. The reason I was testing with two images, one at 
/Users/Lion/Desktop/test8/image01.tif and the other at 
/Users/Lion/Desktop/images/image02.tif is that I cannot rely on images 
being in the same folder as the Blender file.

So, let's assume the context directory is /Users/Lion/Desktop/test8
and see how we get on below.

> 
>>>> (Chris and Peter lead me to believe that Blender has a special kind 
>>>> of relative path. The double slashes replace the path to the blend 
>>>> file’s directory.) realpath has done something but I know not what.
> 
> realpath needs a UNIX path. Your //image01.tif isn't a UNIX path, it is 
> a special Blender path. First you need to convert it. By replacing '//' 
> with the blend file's directory. Then you can call realpath. If you 
> still need to.

Understood. Now. Thanks!
> 
> [...snip...]

Did you just [...snip...] yourself?

>>> So you might want to write an unBlenderiser (untested example):
>>>
>>>  from os.path import isabs, join as joinpath
>>>
>>>  def unblenderise(filename, context_dir=None):
>>>    # transmute Blender "relative" path
>>>    if filename.startswith('//'):
>>>      filename = filename[2:]
>>>    if not isabs(filename) and context_dir is not None:
>>>      # attach the filename to `context_dir` if supplied
>>>      filename = joinpath(context_dir, filename)
>>>    return filename
>>>
>>> The idea here is to get back a meaningful UNIX path from a Blender 
>>> path. It first strips a leading '//'. Next, _if_ the filename is 
>>> relative _and_ you supplied the optional context_dir (eg the 
>>> directory used for a file brwoser dialogue box), then it prepends 
>>> that context directory.
>>>
>>> This _does not_ call abspath or realpath or anything, it just returns 
>>> a filename which can be used with them.
>>>
>>> The idea is that if you know where image01.tif lives, you could 
>>> supply that as the context directory.
>>
>> Yes! Until Peter Otten's timely intervention, I was trying to do this 
>> and had managed to join the 
>> path_to_the_folder_that_contains_the_Blender_file to 
>> the_name_of_the_image (stripped of its preceding slashes).
>>
>> Your unblenderise looks much better than my nascent saneblender so 
>> thank you. I will explore more!
> 
> Looks like you want wd=os.path.dirname(path_of_blend_file).

Thank you!
> 
>> Does it depend on knowing where image01.tif lives and manually 
>> supplying that?
> 
> Sort of.
> 
> What you've got is '//image01.tif', which is Blender's special notation 
> indicating a filename relative to the blend file's directory. All the 
> Python library stuff expects an OS path (OS==UNIX on a Mac). So you want 
> to convert that into a UNIX path.  For example:
> 
>     from os.path import dirname
> 
>     # Get this from somewhere just hardwiring it for the example.
>     # Maybe from your 'n' object below?
>     blend_file = '/Users/Lion/Desktop/test8/tifftest8.blend'
Is this setting a relative path?
> 
>     blender_image_file = n.image.filename
> 
>     unix_image_file = unblenderise(blender_image_file, dirname(blend_file))
> 
> Now you have a UNIX path. If blend_file is an absolute path, 
> unix_image_path will also be an absolute path. But if blend_file is a 
> relative path (eg you opened up "tifftest8.blend") unix_image_path will 
> be a relative path.


Does unix_image_path = unix_image_file?

Two possibilities here.
blend_file (and so unix_image_file) is an absolute path OR blend_file 
(and so unix_image_file) is a relative path.

I just want to check my understanding. If I supply the path to 
blend_file then it is absolute, and if I ask Python to generate the path 
to blend_file from within Blender it is relative. Have I got it?

> 
> You don't need to use realpath or abspath on that _unless_ you need to 
> reference the file from any directory (i.e. _not_ relative to where you 
> currently are).

If I decided not to supply the path and so ended up with a relative UNIX 
path, I could now use realpath or abspath to find the absolute path. 
Have I still got it?

#
I combined your unblenderise and your use of it (see below). Is my 
attempt error free?

It works very well. So thank you! I tested it with a Blend file that had 
two images, one in the same folder as the Blend file and the other was 
in a folder on the Desktop called 'images'.

The initial results were:
Plane uses image01.tif saved at //image01.tif which is at 
/Users/Lion/Desktop/test8/image01.tif

Plane uses image02.tif saved at //../images/image02.tif which is at 
/Users/Lion/Desktop/test8/../images/image02.tif

BUT as you say, this was easily sorted by using os.path.realpath or 
os.path.abspath. Both worked equally well.

Plane uses image01.tif saved at //image01.tif which is at 
/Users/Lion/Desktop/test8/image01.tif
Plane uses image02.tif saved at //../images/image02.tif which is at 
/Users/Lion/Desktop/images/image02.tif

So, everything now works. Thank you again. I am just a little unclear on 
the absolute and relative, hence my questions.
> 
> Cheers,
> Cameron Simpson <cs at cskk.id.au>

#some of this can be tidied later
import bpy
import os

from os.path import realpath
from os.path import isabs, join as joinpath
from os.path import dirname



def unblenderise(filename, context_dir=None):

  if filename.startswith('//'):
   filename = filename[2:]
  if not isabs(filename) and context_dir is not None:
# attach the filename to `context_dir` if supplied
   filename = joinpath(context_dir, filename)
  return filename


blend_file = '/Users/Lion/Desktop/test8/tifftest8.blend'


texture_list = []

for obj in bpy.context.scene.objects:
     for s in obj.material_slots:
         if s.material and s.material.use_nodes:
             for n in s.material.node_tree.nodes:
                 if n.type == 'TEX_IMAGE':
                     texture_list += [n.image]
                     print(obj.name,'uses',n.image.name,'saved 
at',n.image.filepath, 'which is at', unblenderise(n.image.filepath, 
dirname(blend_file)))





print('Texture list:',texture_list)





More information about the Python-list mailing list