0
$\begingroup$

Using python, I remapped some images using image.user_remap(new_image). The images are assigned correctly, but the user count is wrong.

How can I force to check if an Image really has users without restarting the file?

Currently it is somewhat random which Images are image.users==1 and which don't. Some which are actually used return 0 and other which don't return 1.

If I save the file like this and restart, actually being used images will be missing, leaving unassigned UV textures in my mesh. However, activating every Image will set image.users to 1, regardless of wether they really have users or not. This way image.users will be correct after saving and restarting, but I need to rely on this data without restarting Blender.

Please see the attached file. After running the script, user counts will be wrong. Wrong Images will be deleted after restarting. https://www.dropbox.com/s/4jywkbwadnnqgl4/Test2.blend?dl=0

Here is a list that shows which images I wish to keep and remove.

Kept images
(old name                   new name)
CrackedSand2.tga.001        crackedsand2.tga
Desertrocku.tga             Desertrocku.tga
Desertrocku2.tga.001        desertrocku2.tga
G3_Desert_Rock.tga          G3_Desert_Rock.tga
G3_PlainSand_02.tga         g3_plainsand_02.tga
G3_PlainSand_Blut.tga       G3_PlainSand_Blut.tga
G3_PlainSand_Blut2.tga      G3_PlainSand_Blut2.tga
ROCK6.tga                   ROCK6.tga
ROCK6u.tga                  ROCK6u.tga
SandDunesBig.tga            SandDunesBig.tga

Removed images
G3_PlainSand_02.tga.001
G3_PlainSand_02.tga.002

Pattern: Remove ".001" etc. suffixes. Note that the case is supposed to be set to lower case for used images after line #20, but this fails to work correctly because the user count is wrong already.

$\endgroup$
  • $\begingroup$ Do you have an example file "ready to test"? $\endgroup$ – lemon Apr 6 '17 at 15:22
  • $\begingroup$ @lemon I added a file. At the bottom of the script is what I can do to keep all imags saved until next restart. $\endgroup$ – Dimali Apr 6 '17 at 15:42
  • $\begingroup$ What if you change line #7 to "for i, image in enumerate( bpy.data.images ):" and line #15 to "elif i != correct_index :" ? If that's it (please check), I think that could be reported in the bug tracker. $\endgroup$ – lemon Apr 6 '17 at 17:30
  • $\begingroup$ In complement, the kept ids may need to have use_fake_user too (depending on the original, maybe, or both itself and the original) $\endgroup$ – lemon Apr 6 '17 at 17:38
  • $\begingroup$ If I understand you correctly, then you mean it should be avoided to remap an ID to itself. What I did: #14 if correct_index == -1: ... #15 elif index == correct_index: pass # 16 else: image.user_remap... The result is different, but still not correct. The faces have the desired image assigned, but the user count ist wrong as before. Might this be a bug of the recently introduced user_remap function? Working with fake_users will be my last resort, but feels more like a hack. $\endgroup$ – Dimali Apr 6 '17 at 19:20
1
$\begingroup$

The subject is more a Python problem than a Blender problem except for some points I'll try to explain below:

Original code:

def cleanup_images(case='none'):
    import os.path
    for image in bpy.data.images:
        filename =  os.path.basename(image.filepath)
        correct_index = bpy.data.images.find(filename)

        if correct_index == -1:
            image.name = filename
        else:
            #May remap an image on itself
            image.user_remap(bpy.data.images[correct_index])

The problem of that is an image can be remapped on itself, and if you do that, the image looses its user = 1 which becomes 0 (this is the point to report to the bug tracker in my opinion or at least documented).

Second attempt, I though that enumerating may be the solution:

def cleanup_images(case='none'):
    #rename all images to their filename
    import os.path
    for i, image in enumerate( bpy.data.images ):
        filename =  os.path.basename(image.filepath)
        correct_index = bpy.data.images.find(filename)

        if correct_index == -1:
            image.name = filename
        elif i != correct_index:
            image.user_remap(bpy.data.images[correct_index])

But this does not work, very possibly because user_remap may change the indexes so that some images continue to remap on themselves.

Correct code:

def cleanup_images(case='none'):
    #rename all images to their filename
    import os.path
    for image in bpy.data.images:
        filename =  os.path.basename(image.filepath)
        correct_index = bpy.data.images.find(filename)

        if correct_index == -1:
            image.name = filename
        else:
            correct_image = bpy.data.images[correct_index]
            if image != correct_image:
                image.user_remap(correct_image)

We no longer use index but direct objects comparison to apply user_remap.

For information, an alternative approach with no use of indexes:

def cleanup_images2( case = 'none' ):
    from collections import defaultdict
    import os.path

    #Organize images by filepath
    toClean = defaultdict( list )
    for i in bpy.data.images:
        toClean[i.filepath].append( i )

    for key, value in toClean.items():
        #image to keep is the first
        toKeep = value[0]
        #the other ones are remapped to the first
        for i in [i for i in value if i != toKeep]:
            i.user_remap( toKeep )
        toKeep.name = os.path.basename( toKeep.filepath )
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.