Import PNG as FORMAT_LA8

Godot Version

4.6

Question

I don’t think there’s any way to make Godot import a PNG file as any format other than RGBA8 (or I assume RGBA16 for 16 -bit pngs)?

I want to reduce the footprint of my game as much as possible (and vram use), and I only need luminance and alpha in my images - i actually really only need 3 bits (white, black and alpha).

Is there a good way to handle this? Can I make a custom import plugin that changes how PNGs are imported, so I can import as FORMAT_LA8?

Also, is there an even more ‘packed’ way to handle what are essentially bitmaps but with a third bit for transparency?

You could write your own texture storage format; you’d need to write a conversion tool to translate your source images to that format, and write a loader for Godot, but it’s not insurmountable. You could start with something that has (say):

// In C, but use the language you want...

typedef struct
{
  uint32_t magic; // 'L2A1' or something for sanity checking
  uint16_t x;     // pixmap width
  uint16_t y;     // pixmap height
} L2A1_FILE_HEADER;

You could then follow that immediately in the file with a 2 bit luminance map that’s (x * y / 4) bytes in size, rounded up and zero padded, and then a 1 bit alpha map that’s (x * y / 8) bytes, rounded up and zero padded.

Your Godot loader could scribble that into an appropriate texture and send it off to the GPU.

2 Likes

It’s possible but what are you doing with the texture? You could try to import it as VRAM compressed unless you are using it for data in a shader.

Either way, if you want to go the import plugin path then you’ll need to make a plugin and use an EditorImportPlugin

Example:

@tool
extends EditorPlugin


var png_import: CustomPNGImport


func _enable_plugin() -> void:
	# Add autoloads here.
	pass


func _disable_plugin() -> void:
	# Remove autoloads here.
	pass


func _enter_tree() -> void:
	png_import = CustomPNGImport.new()
	add_import_plugin(png_import, false)


func _exit_tree() -> void:
	if png_import:
		remove_import_plugin(png_import)
		png_import = null


class CustomPNGImport extends EditorImportPlugin:

	func _get_importer_name():
		return "custom.png.import"

	func _get_visible_name():
		return "Custom PNG"

	func _get_recognized_extensions():
		return ["png"]

	func _get_save_extension():
		return "res"

	func _get_resource_type():
		return "Texture"

	func _get_preset_count():
		return 1

	func _get_preset_name(preset_index):
		return "Default"

	#func _get_import_options(path, preset_index):
		#return [{"name": "my_option", "default_value": false}]

	func _import(source_file, save_path, options, platform_variants, gen_files):
		var png = Image.load_from_file(source_file)
		png.convert(Image.FORMAT_LA8)
		var texture = ImageTexture.create_from_image(png)

		var filename = save_path + "." + _get_save_extension()
		return ResourceSaver.save(texture, filename)

A new Custom PNG option will appear in the Import As: dropdown in the Import dock when you select a png file.

1 Like

Ah, great I didn’t realize you could switch between different importers for the same file extension. That makes sense. Thanks for the example.

That sounds like a fun project!