Export Continuous Blocks of Tiles in a Tilemap as Images

Godot Version

4.2.1.stable.official

Question/Context

(The driving force behind this admittedly strange question is that I’m looking to make a whole bunch of textures for a Game unrelated to Godot)

I have a texture atlas that has about 256 unique tiles to them, and my idea was to set up a tilemap that I can use as a canvas, then have a script that goes through the whole tilemap, looking for each unique, continuous, arbitrary rectangle/square of tiles to export as a png, also with it’s inverted variant if possible; All my tiles are monochrome.

Would this be a good use of Godot, or is there better software out there that can do the trick more effectively?

Yeah, should be possible. There are a couple ways to do it.

I did it in a dirty and quick way by using a transparent SubViewport and getting the Image from its Texture2D, generating a BitMap from that Image and getting the opaque polygons (the parts of the image that aren’t transparent) with BitMap.opaque_to_polygons(), creating a Rect2 that encloses each polygon and getting the region of the Image with Image.get_region(). Finally saving the final image image as a png

Example:


The scene (The Sprite2D is there to test if it’s generating the BitMap correctly)

The script:

extends Node


@onready var sub_viewport: SubViewport = $SubViewportContainer/SubViewport


func _ready() -> void:
	# Set viewport as transparent
	sub_viewport.transparent_bg = true
	# await for the viewport to render
	await RenderingServer.frame_post_draw
	# get its image
	var image = sub_viewport.get_texture().get_image()
	# create a BitMap from that image
	var bitmap = BitMap.new()
	bitmap.create_from_image_alpha(image)
	# get the polygons of that image
	var polygons = bitmap.opaque_to_polygons(Rect2(Vector2.ZERO, image.get_size()))
	var index = 0
	# for each polygon, create a rectangle and clip that rectangle from the image and save it
	for polygon in polygons:
		var rect = Rect2()
		rect.position = polygon[0]
		for point in polygon:
			rect = rect.expand(point)

		var output_image = image.get_region(rect)
		output_image.save_png('res://clipped_%02d.png' % index)
		index += 1
	
	# check that the bitmap is correct
	$Sprite2D.texture = ImageTexture.create_from_image(bitmap.convert_to_image())

And the result:
clipped_00 clipped_01 clipped_02 clipped_03 clipped_04 clipped_05clipped_06 clipped_07 clipped_08

If you want flipped images you can use Image.flip_x() and Image.flip_y() or rotate it with Image.rotate_90() and Image.rotate_180()

If the tiles have transparent parts this method won’t work you’ll not need to create a BitMap to create the Rect2 but you’ll need to create the Rect2 using TileMap.get_used_cells() I’ll leave that to you if that’s the case :sweat_smile:

I think this also depends on how skilled you are already with Godot or other things. If you feel comfortable in Godot, then it is a great tool for this task! However, if you know another language and are more comfortable with that, then it would be worth looking into libraries/frameworks to use that for your task.