extends Object
class_name Thumbnail
@warning_ignore("shadowed_global_identifier")
static func _load(p: String, hash: PackedByteArray, error_if_hash_mismatch := true) -> Image:
if FileAccess.file_exists(p):
var f := FileAccess.open(p, FileAccess.READ)
var img := Image.new()
var buf := f.get_buffer(f.get_length())
if buf:
var dict: Dictionary = bytes_to_var(buf)
var e := img.load_png_from_buffer(dict.b)
if e != OK:
push_error("error: ", e)
return null
if dict.h != hash:
if error_if_hash_mismatch:
push_error("error loading thumbnail %s: hash (thumbnail hash) %s != (file hash) %s" % [p, dict.h.hex_encode(), hash.hex_encode()])
return null
return img
return null
static func hash_f(p: String) -> PackedByteArray:
var file := FileAccess.open(p, FileAccess.READ)
return hash_b(file.get_buffer(file.get_length()))
static func hash_b(b: PackedByteArray) -> PackedByteArray:
var h := HashingContext.new()
h.start(HashingContext.HASH_SHA1)
h.update(b)
return h.finish()
static func create_thumb(parent: Node, node: Node3D, size := Vector2i(64, 64), world := World3D.new()) -> Image:
var port := SubViewport.new()
port.size = size
port.msaa_3d = Viewport.MSAA_4X
port.screen_space_aa = Viewport.SCREEN_SPACE_AA_FXAA
port.own_world_3d = true
port.world_3d = world
parent.add_child(port)
port.add_child(node)
port.render_target_update_mode = SubViewport.UPDATE_ONCE
await RenderingServer.frame_post_draw
var img: Image = port.get_texture().get_image()
port.queue_free()
return img
@warning_ignore("shadowed_global_identifier")
static func save(img: Image, p: String, hash: PackedByteArray) -> Error:
if !DirAccess.dir_exists_absolute(p.get_base_dir()):
DirAccess.make_dir_recursive_absolute(p.get_base_dir())
var file := FileAccess.open(p, FileAccess.WRITE)
if file == null:
return FileAccess.get_open_error()
file.store_buffer(var_to_bytes({ b = img.save_png_to_buffer(), h = hash }))
return OK