How to ResourceSave an import plugin created Image object?

Godot Version

v4.5.1.stable.arch_linux

Question

Hi community, I am trying to make a custom image importer, that remaps one image’s colours to the positions of where said colour is on another image. So far, I (think I) managed to make the biggest part of logic, but I fail in saving the resource.

# ...
func _get_save_extension() -> String:
	return "..." # What do I need to put here?


func _get_resource_type() -> String:
	return "..." # What do I need to put here?

# ...

func _import(source_file: String, save_path: String, options: Dictionary, platform_variants: Array[String], gen_files: Array[String]) -> Error:
#region Prepare UV-Map
	var uv_map := Image.load_from_file(options.uv_map)
	if uv_map == null:
		return ERR_CANT_ACQUIRE_RESOURCE

	var uv_size := uv_map.get_size()
	var color_positions: Dictionary[Color, Color]

	for y in uv_size.y:
		for x in uv_size.x:
			color_positions[uv_map.get_pixel(x, y)] = Color(x, y, 0, 1)
#endregion

#region Generate new Image
	var image := Image.load_from_file(source_file)
	var size: Vector2i = image.get_size()
	var new_image := Image.create(image.get_width(), image.get_height(), image.has_mipmaps(), image.get_format())
	new_image.copy_from(image)

	for y in size.y:
		for x in size.x:
			var color := image.get_pixel(x, y)
			new_image.set_pixel(x, y, color_positions[color])
#endregion

	# How do I save the image?
	return ResourceSaver.save(new_image, "%s.%s" % [save_path, _get_save_extension()])

My main questions are:

  • What format does it need?
    • I see that other imported PNGs get saved as ctex in .godot/imported/
    • They seem to be CompressedTexture2Ds
    • So the question is, what do I need to return in the methods _get_save_extension() and _get_resource_type()?
  • How do I save my custom Image with the ResourceSaver?

You won’t be able to save it as a CompressedTexture2D because this resource creation is internal to Godot and not exposed to scripting. You’ll need to use a ImageTexture instead. For the _get_save_extension() you can use return "res" and for the _get_resource_type() the type of the Resource which is return "Texture2D" in this case.

You may be able to use the PortableCompressedTexture2D resource instead but I’ve not tested it.

You can also return "tres” for the extension if you want it to be saved in a human-readable format.

Thanks, before receiving your answer but after posting, I found this GitHub issue about a very similar issue:

I did use the PortableCompressedTexture2D, as simply using the CompressedTexture2D did indeed not work out.

The linked solution worked for me. Use PortableCompressedTexture2D for the resource and .res for the file type.

I ran into some weird issues using ImageTexture for custom loading of SVGs and I want to document them for posterity.

If you use ImageTexture for the resource, the importer will work normally exactly once per reboot of Godot 4.7. When importing again, it will also run the default texture importer as well as the custom one. It then overwrites all in-memory pointers to the texture with the default output, but it only writes the custom generated one to disk. So it will use the correct one after a reboot. Changing the importer priority and order had no effect.

Godot handles ImageTexture importers correctly for file types that don’t already have an asset importer. So it will work as expected if you rename the .svg. to .foo.