Ren'Py Script to read all images in a folder and put in a .rpy file

Armagedon13

Newbie
May 24, 2018
74
181
i'm testing some script to make a script to read all images in a folder and put it in a .rpy script and maybe make some mod making more easy


Code:
   asset_folder = "Mods"
    asset_extensions = (".png", ".jpg")  # Add any additional image extensions here.

    # Get a list of all image files in the asset folder and its subfolders.
    image_paths = []
    for root, dirs, files in os.walk(asset_folder):
        for file in files:
            if file.lower().endswith(asset_extensions):
                image_paths.append(os.path.join(root, file))

    # Create a dictionary of image names and lists of image paths.
    images = {}
    for image_path in image_paths:
        image_name = os.path.splitext(os.path.basename(image_path))[0]
        if image_name in images:
            images[image_name].append(image_path)
        else:
            images[image_name] = [image_path]

    # Write the images to a .rpy script.
    with open("Mod_images.rpy", "w") as f:
        for image_name, image_paths in images.items():
            f.write(f'image {image_name} = ')
            if len(image_paths) == 1:
                f.write(f'"{image_paths[0]}"\n')
            else:
                f.write("[")
                for image_path in image_paths:
                    f.write(f'"{image_path}", ')
                f.write("]\n")
throw this:

File "game/Mod.rpy", line 44: invalid syntax
f.write(f'image {image_name} = ')

Ren'Py Version: Ren'Py 6.99.13.2919
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,978
16,233
i'm testing some script to make a script to read all images in a folder and put it in a .rpy script and maybe make some mod making more easy
Hmm, ok, I'll address the error first:


File "game/Mod.rpy", line 44: invalid syntax
f.write(f'image {image_name} = ')

Ren'Py Version: Ren'Py 6.99.13.2919
You are using a Python 3.x type of string, with a more than five years old version of Ren'Py (updated 36 times since) that use Python 2.x. There's no way for this to works.
It should be f.write( "image {} = ".format( image_name ) ).



Now that this is said, there's many things to say regarding the rest of the code, as well as the intent behind it.


Python:
    asset_folder = "Mods"
    asset_extensions = (".png", ".jpg")  # Add any additional image extensions here.

    # Get a list of all image files in the asset folder and its subfolders.
    image_paths = []
    for root, dirs, files in os.walk(asset_folder):
        for file in files:
            if file.lower().endswith(asset_extensions):
                image_paths.append(os.path.join(root, file))
Relying on os present one small advantage, it works with files located somewhere elsewhere than in the "game/images" and "game/gui" folders.
But relying on present one big advantage, it will include images located in RPA archives. Those images have to be in a sub folder of either "game/images" or "game/gui", what is a really small constraint in regard of the advantage gave by the RPA archive.


Python:
    # Create a dictionary of image names and lists of image paths.
    images = {}
    for image_path in image_paths:
        image_name = os.path.splitext(os.path.basename(image_path))[0]
        if image_name in images:
            images[image_name].append(image_path)
        else:
            images[image_name] = [image_path]
Why separate this ? It could perfectly be done when building the file list:
/!\ wrote in the fly /!\
Python:
    images = []
    for root, dirs, files in os.walk(asset_folder):
        for file in files:
            if file.lower().endswith(asset_extensions):
                name = os.path.splitext( file )[0]
                if name in images:
                    images[name].append( os.path.join(root, file) )
                else:
                    images[name] = [ os.path.join(root, file) ]

Code:
    # Write the images to a .rpy script.
    with open("Mod_images.rpy", "w") as f:
        for image_name, image_paths in images.items():
            f.write(f'image {image_name} = ')
            if len(image_paths) == 1:
                f.write(f'"{image_paths[0]}"\n')
            else:
                f.write("[")
                for image_path in image_paths:
                    f.write(f'"{image_path}", ')
                f.write("]\n")
Firstly, what do you expect something like image fileName = [ "path/name.ext", "path/name.ext" ] to do exactly ?
Surprisingly Ren'Py accept the syntax, not surprisingly, it only care about the first image in the list.

Secondly, what is the interest of this "Mod_images.rpy" file ?
There's no need to declare an image for it to be available, this process . It's only images that you want available with an alternate name, or for which you want to directly apply a transform, that need to be declared. And in those two cases, it's something that you can't automatize with such script.


I'm all for people trying to mod Ren'Py, it's a fun thing to do. But for it to stay something fun, and also for it to be efficient, knowing the basis of Ren'Py is mandatory.
I mean, you'll not tweak the motor of your car with no knowledge about motors. It would be ridiculous and dangerous. Therefore, why do you want to do it that way with a software ?

I'll not say that it's wasted time, because you learned few things ; there's newer versions of Ren'Py, there's a function to use in place of os.walk, there's no need to declare an image.
Yet it's time that you could have used to do something more interesting ; like reading the documentation by example.
 
  • Like
Reactions: Armagedon13

79flavors

Well-Known Member
Respected User
Jun 14, 2018
1,611
2,258
Erm... you don't need to.

RenPy does this sort of stuff automatically. Albeit with a few things that people sometimes miss.

If you have an image called /game/images/image1.png, it will automatically be available within the game as a displayable called image1 (the folder name is ignored... usually).

The main quirk people overlook is that that generated displayables are always lowercase. So /game/images/Backgrounds/Night/Paris.jpg would result in a displayable called paris NOT Paris.
(which it is why it's a good idea to keep your filenames lowercase - so it never trips you up).

Since RenPy is doing it automatically, I'm not entirely sure what your code adds to the equation. Even in terms of modding, where something like an init 1: or naming the mod file so it is processed after the game's normal script could provide the same ability to override one displayable with a replacement.
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,978
16,233
Even in terms of modding, where something like an init 1: or naming the mod file so it is processed after the game's normal script could provide the same ability to override one displayable with a replacement.
I want to add that in terms of modding I advocate against this practice.

A mod should be as transparent as possible, replacing instead of overriding.

Even when it come to images it's something possible. can perfectly be used to hook on show and scene statements, and have a code that will transpose the asked images into the modded ones:
/!\ wrote on the fly /!\
Python:
init python:
    def myShow( name, **kwargs ):
        if hasattr( store, "replacementImages" ) and name in store.replacementImages:
            name = store.replacementImages[name]
        renpy.show( name, **kwargs )

    config.show = myShow

define replacementImages = { "someImage": "someImageModded",
                             "otherImage": "otherImageModded",
                             [...] }
This ensure a better compatibility, offer more flexibility for the modder, and you can let the player choose what he want to be modded, and what he want to keep "as it". Of course, it's a bit more works for the modder, but generally players like it.
It would mess a bit with Ren'Py prediction, but even this can be worked around if it's really needed.


Edit: a typo in the code.
 
Last edited: