How to batch rename embedded (linked) textures in a scene?

is there a way to batch rename all textures that are used by the all objects in a given scene? Background of this question is as follows:
I’m creating a set of models that all will be textured (diff, roughness, normal), and all textures will be of 4k size. After creation, i want to have a copy of the 4K textures in 2k size. Therefore, i export all textures by using “File” --> “External data” --> “Unpack all into files”.
Then, i use irfan view to batch resize and rename all textures, giving them the suffix “_2k”. But when i re-link the files, the file connection in the shader nodes is lost. They need to be re-linked manually. Doing this manually is ok for a small amount of textures, but this time i will have about 100 textures.

So, how can i achieve to rename all textures without loosing the connection to the shader nodes? Some advice will be very helpful.
Thank you in advance!

So you have a scene with materials that all have various textures and you wish to change all the texture files in all the materials from ‘X:\Some_Path\some_name_4k.ext’ to ‘X:\Some_Path\some_name_2k.ext’? Is that correct?

Hi MartinZ,

yes, that is correct. The resizing is an indipendent step from the renaming, so the task is the one you exactly explain. More important is to do so WITHOUT having the shader nodes losing their connection to the texture files. If you rename the textures on the operating system, blender does not know what has happened.

Means that the shader node before the renaming operation is related to ‘X:\Some_Path\some_name_4k.ext’, and after the renaming operation to the file 'X:\Some_Path\some_name_2k.

Thanks,

Do the 4k textures all really have “_4k” as the last charcters in the filename? And do the 2k textures really end in exactly “_2k”? WHat I’m getting at is a python script that loops through all nodes and replaces ‘4k’ with ‘2k’. It gets tricky if the 4k don’t ALL actually end in ‘4k’

If you are doing the simplest case of replacing the characters ‘4k’ with ‘2k’, a script like this will work.


import bpy

# the main looping code snippet is modified from
# https://blender.stackexchange.com/questions/80773/how-to-get-the-name-of-image-of-image-texture-with-python

print('----------------------------------------')
print('Starting the replacer script....')

texture_list = []
count_replaced_files = 0

find_chars = '4k'
replace_chars = '2k'

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)
                    if find_chars in n.image.name:
                        count_replaced_files += 1
                        old_name = n.image.name
                        new_name = n.image.name
                        new_name = new_name.replace(find_chars,replace_chars)
                        n.image.name = new_name
                        info_string = old_name + ' has been replaced with ' + new_name
                        print(info_string)
                        
print(str(count_replaced_files))
print('File were replaced')
print('Finished')
print('----------------------------------------')

#print(texture_list)

Probably not needed anymore, but just for information, it’s also possible to resize the textures in Blender, using bpy.data.images[‘imagename’].scale=[new x, new y]; which can also be included into the script Photox posted.

You robbed me of the pleasure of writing it :smiley:

Hi Secrop,

in which line does this code line to be placed?

Hi Photox,
thank you very much for this ! I’ll give it a try right away. By the way, just for the sake of understanding as i do not know much about coding: Would this code rename “4K” into “2K”, regardless of the position of the string? For example, would the filename “Texture_4Kidding_4K” renamed to “Texture_2Kidding_2K” ?

MartinZ, Sorry, Yonk!

You’re welcome karl, and yes it would replace all instances of the substring. If you wanted to avoid that, or only match at the end of the filename, you would need a few more lines of code. Be careful with the script and work on a saved blend copy, it has the potential to wreck havoc! If you need minor tweaks, post back and Martin can have first crack at it.

hi MartinZ, Photox,

i’m sorry, but the script did not do anything at all. Maybe i did something wrong. I use a scene with nine objects, all textured. For the sake of testing, only one texture ends with “_4k.png”. I added the script and started it, but nothing changed. Please refer to the screenshot below:


Any ideas? Some advice would be nice. Thank you.

4K UPPERCASE, not 4k

find_chars = ‘4K’
replace_chars = ‘2K’

Hi Photox and MartinZ,
thank you for your help. With the Uppercase correction everything worked as expected.

Thanks a lot!