This site is currently in read-only mode during migration to a new platform.
You cannot post questions, answers or comments, as they would be lost during the migration otherwise.
+1 vote

I am trying to open a .png file in Godot, then draw on it, then save the result as a new .png file.
When I run my code, I see the png file I've chosen, and I see the arc I've drawn over it, and it saves a png file to the location I picked, BUT the file saved doesn't have the arc I've drawn on it. It's just a copy of the original, unaltered png file.

Here is my code

extends TextureRect


var page_path = 'user://my_drawings/a_drawing.png'



func _ready():

    ##################LOADING A PNG FILE TO A TEXTURE RECT
    #here is the path to the png image...
    print('the page path is ',page_path)
    #then create an empty Image object...
    var image = Image.new()
    #load the .png file to it...
    var err = image.load(page_path)
    if err != OK:
        print('page image load failed!')
    #then create a new ImageTexture object...
    var image_texture = ImageTexture.new()
    #create it from the Image you made earlier...
    image_texture.create_from_image(image, Image.FORMAT_RGBA8)
    #and assign it to the TextureRect Object...
    texture = image_texture



    ##################DRAWING MORE STUFF ONTO THE TEXTURE RECT...
    #don't know what to do here...
    #the idea is just to test drawing something on it...to see the difference...


#here's an arc i'm drawing on top of it to test saving the result...
func draw_circle_arc(center, radius, angle_from, angle_to, color):
    var nb_points = 32
    var points_arc = PoolVector2Array()

    for i in range(nb_points + 1):
        var angle_point = deg2rad(angle_from + i * (angle_to-angle_from) / nb_points - 90)
        points_arc.push_back(center + Vector2(cos(angle_point), sin(angle_point)) * radius)

    for index_point in range(nb_points):
        draw_line(points_arc[index_point], points_arc[index_point + 1], color)

#_draw should only happen once...so i'll test the save process after _draw is called...
func _draw():
    var center = Vector2(100, 100)
    var radius = 80
    var angle_from = 75
    var angle_to = 195
    var color = Color(1.0, 0.0, 0.0)
    draw_circle_arc(center, radius, angle_from, angle_to, color)

    ###################SAVING THE TEXTURERECT TEXTURE AS A PNG FILE...
    #now, let's see if we can save the texture located in the drawpad to a new file...
    var export_img = get_texture().get_data()
    export_img.flip_y()
    var export_path = 'user://export_img.png'
    export_img.save_png(export_path)
    print('export img saved!')

TL:DR
What do I need to do in order to
1) Load a .png file into my Godot game (it has an alpha channel)
2) draw new stuff onto it
3) save the result as a new png file (which also has an alpha channel).

I don't want to save the entire screen (like a screenshot) as a png. I just want to save the image as it is displayed by the TextureRect (it's in a particular region of my overall screen). Plus I want to preserve the alpha channel in the original image, and taking a screenshot of everything would get rid of that precious alpha channel.

in Engine by (18 points)
edited by

It seems that you did only draw on the screen but not into the texture/image.

You can change the contents of an Image using set_pixel() but this is probably to tedious.

You could also render the texture and draw to a viewport and get & save the image data of that viewport. That view port can either be a custom one (i.e. in the resolution of the source image) or just the default (=screen).

3 Answers

+2 votes

Does anyone get this to work?
I'm trying to do the samething.
If I replace the viewport with this texture, I can draw to a texture and save it to disk,
but I loose transparency.
...a bit lost...

by (52 points)

I really like this solution, going to give it a try and I'll post an answer if I can figure it out!

It's been a while, but here is the solution

image.convert(Image.FORMAT_RGBA8)
+2 votes

Here's a way to record a viewport (the root viewport by default) to a PNG file. From there it's just about putting everything in the scene however you want it.

extends Node


export(NodePath) var viewport_path = null


onready var target_viewport = get_node(viewport_path) if viewport_path else get_tree().root.get_viewport()


func save_to(path):
    var img = target_viewport.get_texture().get_data()
    img.flip_y()
    return img.save_png(path)
by (97 points)
0 votes

Here's a way to record a viewport (the root viewport by default) to a PNG file. From there it's just about putting everything in the scene with the appropriate blending modes.

extends Node


export(NodePath) var viewport_path = null


onready var target_viewport = get_node(viewport_path) if viewport_path else get_tree().root.get_viewport()


func save_to(path):
    var img = target_viewport.get_texture().get_data()
    img.flip_y()
    return img.save_png(path)
by (97 points)
Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read Frequently asked questions and How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to [email protected] with your username.