extends Node signal screenshot_captured() signal _image_data_extracted(data: PackedByteArray) signal _image_write_complete(path: String) var base_dir: String var is_taking_screenshot: bool = false func _ready() -> void: process_mode = Node.PROCESS_MODE_ALWAYS func _physics_process(_delta: float) -> void: #checks if game is running in editor or if its an executable if Input.is_action_just_pressed("screenshot"): if Engine.is_editor_hint() || OS.has_feature("editor"): take_screenshot() base_dir = "res://" else: take_screenshot() base_dir = OS.get_executable_path().get_base_dir() func take_screenshot() -> void: #screenshot guard clause, don't take the screenshot if it's in the middle of taking one if is_taking_screenshot: return #if a directory doesnt exist make one if !DirAccess.dir_exists_absolute(base_dir + "screenshots"): var dir: DirAccess = DirAccess.open(base_dir); dir.make_dir("screenshots") #turn the game window into a texture is_taking_screenshot = true var vp_texture: ViewportTexture = get_tree().get_root().get_window().get_texture() var vp_texture_data: PackedByteArray = await image_extract_data(vp_texture) var _screenshot_path: String = await image_write(vp_texture_data, vp_texture.get_size()) is_taking_screenshot = false func image_extract_data(texture: Texture2D) -> PackedByteArray: var rd_rid: RID = RenderingServer.texture_get_rd_texture(texture.get_rid()) var rd: RenderingDevice = RenderingServer.get_rendering_device() rd.texture_get_data_async(rd_rid, 0, _image_data_extracted.emit) return await _image_data_extracted func image_write(data: PackedByteArray, size: Vector2i) -> String: # Assign thread from pool, then clean up thread and notify caller when done var task_id: int = WorkerThreadPool.add_task(_image_write_task.bind(data, size), false, "Saving Screenshot") _image_write_complete.connect(_on_image_write_complete.bind(task_id), CONNECT_ONE_SHOT) return await _image_write_complete func _image_write_task(data: PackedByteArray, size: Vector2i) -> void: screenshot_captured.emit.call_deferred() var screenshot_dir: String = base_dir + "screenshots" var datetime: Dictionary = Time.get_datetime_dict_from_system() #the filepath to the new file including the image var file_path: String = screenshot_dir.path_join("Screenshot_%04d-%02d-%02d_%02d-%02d-%02d.png" % [datetime.year,datetime.month,datetime.day,datetime.hour,datetime.minute,datetime.second]) var image: Image = Image.create_from_data(size.x, size.y, false, Image.FORMAT_RGBA8, data) #the A channel acts as a mask, so to allow the skybox to render this removes the alpha cause the data is still there image.convert(Image.FORMAT_RGB8) #save image using filepath image.save_png(file_path) _image_write_complete.emit.call_deferred(file_path) func _on_image_write_complete(_path: String, task_id: int) -> void: WorkerThreadPool.wait_for_task_completion(task_id)
or share this direct link: