Image format is undone by save to disk?

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By humbletang

I have a simple test scene that should produce an image with a transparent background but the png’s that are saved are in the format RGB8 . I followed the instructions from https://forum.godotengine.org/62220/make-image-background-transparent?show=62220#q62220 but haven’t had their success.

I’ve made the default environment a custom color that is (0,0,0,0) and a single unshaded cube with a camera pointing at it.

On the camera I have the following script attached.

extends Camera


# Declare member variables here. Examples:
# var a = 2
# var b = "text"


# Called when the node enters the scene tree for the first time.
func _ready():
	var im = get_viewport().get_texture().get_data()
	im.convert(Image.FORMAT_RGBA8)
	print(im.get_format())
	im.flip_y()
	im.save_png("res://test_ready.png")
	pass # Replace with function body.


# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta):
	var im = get_viewport().get_texture().get_data()
	im.convert(Image.FORMAT_RGBA8)
	print(im.get_format())
	im.flip_y()
	im.save_png("res://test_process.png")

	pass

for some reason I can see that the image created during the ready function is the right format, but the one made during process is back to RGB8

Any assistance with this is greatly appreciated!

You’ve removed the code from the _process() function and double-checked the output, right?

Ertain | 2022-08-20 01:43

Hiya Ertain, help me a bit to understand what code you want me to remove from the _process() function. Do you mean to essentially have this?

# Called when the node enters the scene tree for the first time.
func _ready():
    var im = get_viewport().get_texture().get_data()
    im.convert(Image.FORMAT_RGBA8)
    print(im.get_format())
    im.flip_y()
    im.save_png("res://test_ready.png")
    pass # Replace with function body.


# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta):    
    pass

if so, I just also want to make sure I get what you mean by the output. The test_ready.png image still shows up blank, but has the right format according to the godot inspector tab, but I don’t have any output from the _process function to check.

What would you advise to trouble shoot further?

humbletang | 2022-08-21 19:46

The script may have to be put on a node that loads after the Camera node. The whole scene (the cube, the camera, and the environment) may have to be loaded before the image can be saved. My guess is that the node in question has to be closer to the SceneTree root than most other nodes. Maybe also change up the code a bit, maybe write something like this:

func _ready():
    var im: Image = get_viewport().get_texture().get_data()
    im.convert(Image.FORMAT_RGBA8)
    im.flip_y()
    # BTW, in the finished game, the `user://` directory has to be used instead of the `res://` path.
    im.save_png("res://test_ready.png")

Ertain | 2022-08-21 22:35

Thanks for sticking with me on this. I’ve tried having the node with the script ahead of or after the camera and the difference isn’t noticeable.

I also assume that if the saving occurs during the _process function then we can assume that if we run the scene for a few moments and it appears in the popup window then we can conclude the scene is finished loading right? I do see an image showing my cube from the perspective of the camera after doing this, but this is where the output image switches back t being rgb8 (https://imgur.com/a/QYJMnuH).

Did I miss the heart of your suggestion?

humbletang | 2022-08-22 17:42

I have something similar to this in one of my games. The thing is, the screenshot (i.e. the data from the Viewport) is taken after the player has played the level. So it looks like the image has to be taken after a few cycles. Perhaps waiting a few seconds before trying to save the image would help.

From the looks of this entry in the documentation, it looks like the script has to yield a few frames before saving the picture. We can try code like this:

func _ready():
    # May have to yield many of these frames before the image can be saved.
    yield(VisualServer, "frame_post_draw")
    var im: Image = get_viewport().get_texture().get_data()
    im.convert(Image.FORMAT_RGBA8)
    im.flip_y()
    im.save_png("res://test_ready.png")

Ertain | 2022-08-22 22:58

Thanks for all the suggestions!

Gave that a shot also. Tried a couple of backgrounds but the format remained the same
Imgur: The magic of the Internet

It might be worth mentioning that this happens to me on both windows and linux machines that I’ve tried.

Out of curiousity, does this leave you with an image that has the alpha channel added to it?

I’m going to link a zip of my project as is in case there’s something else that I’m leaving out you happen to spot (if you are ok with this method of sharing my project).

https://drive.google.com/file/d/1NIrJotg2Rr_fcSDMo3hytUXNQKMr5p3F/view?usp=sharing

humbletang | 2022-08-23 00:24