Godot Version
Godot 4.5.1
Question
Hi, I’m porting one of my games to HTML5 and I’m having a problem.
By default, HTML5 browsers don’t allow exporting .PNG files to system folders for security reasons, and the only option is to export the file via a download. The problem is that when I click the export button, nothing happens and no download folder opens.
func _on_cloudy_button_pressed():
print("🔴 BUTTON PRESSED!")
cancel_loading_if_in_progress()
stop_all_audio()
cloudy_audio.play()
print("🔴 CALLING export_drawing_to_png()")
export_drawing_to_png()
print("🔴 RETURNED FROM export_drawing_to_png()")
func request_storage_permissions():
if OS.get_name() == "Android":
OS.request_permissions()
func export_drawing_to_png():
print("🟠 === STARTING EXPORT ===")
print("🟠 OS.get_name():", OS.get_name())
print("🟠 OS.has_feature('web'):", OS.has_feature("web"))
var tile_size = tilemap_layer.tile_set.tile_size
var tilemap_size = (max_bounds - min_bounds + Vector2i.ONE) * tile_size
print("🟠 Tilemap size:", tilemap_size)
# Create the viewport for capturing the TileMap rendering
var viewport := SubViewport.new()
viewport.size = tilemap_size
viewport.render_target_clear_mode = SubViewport.CLEAR_MODE_ALWAYS
viewport.render_target_update_mode = SubViewport.UPDATE_ONCE
viewport.transparent_bg = false
viewport.disable_3d = true
# Duplicate the TileMap into a temporary container
var container := Node2D.new()
var tilemap_copy := tilemap_layer.duplicate()
tilemap_copy.position = -min_bounds * tile_size
container.add_child(tilemap_copy)
viewport.add_child(container)
add_child(viewport)
print("🟠 Waiting for frame...")
await RenderingServer.frame_post_draw
print("🟠 Frame complete")
var image = viewport.get_texture().get_image()
print("🟠 Image captured, size:", image.get_size() if image else "NULL")
# Clean up
remove_child(viewport)
viewport.queue_free()
var timestamp := Time.get_datetime_string_from_system().replace(":", "-").replace(" ", "_")
var filename := "export_tilemap_" + timestamp + ".png"
print("🟠 Filename:", filename)
print("🟠 Checking platform...")
# ===== HTML5 CHECK =====
if OS.has_feature("web"):
print("🌐 HTML5 DETECTED - Calling export_png_html5()")
export_png_html5(image, filename)
print("🌐 Returned from export_png_html5()")
return
# ===== NATIVE PLATFORMS =====
print("💻 Native platform - using file save")
var base_dir: String
if OS.get_name() == "Android":
base_dir = OS.get_system_dir(OS.SYSTEM_DIR_DOCUMENTS)
if base_dir.is_empty():
base_dir = OS.get_user_data_dir()
else:
base_dir = OS.get_system_dir(OS.SYSTEM_DIR_PICTURES)
var drawing_dir := base_dir.path_join("Drawing")
if not DirAccess.dir_exists_absolute(drawing_dir):
var dir_result = DirAccess.make_dir_recursive_absolute(drawing_dir)
if dir_result != OK:
print("❌ Failed to create directory:", drawing_dir, " Error:", dir_result)
return
var file_path := drawing_dir.path_join(filename)
print("📁 Attempting to save to:", file_path)
var err := image.save_png(file_path)
if err == OK:
print("✅ Export PNG succeeded:", file_path)
if OS.get_name() == "Android":
var accessible_path = "/storage/emulated/0/Pictures/Drawing/" + filename
var copy_err = image.save_png(accessible_path)
if copy_err == OK:
print("✅ Also saved to accessible location:", accessible_path)
else:
print("⚠️ Could not save to accessible location:", copy_err)
else:
print("❌ Error during PNG export:", err)
print("📁 Tried path:", file_path)
func export_png_html5(image: Image, filename: String):
var separator = "=".repeat(50)
print(separator)
print("HTML5 EXPORT FUNCTION CALLED")
print(separator)
if image == null:
print("ERROR: Image is null!")
return
print("Image size:", image.get_size())
print("Converting to PNG buffer...")
var png_data := image.save_png_to_buffer()
print("PNG buffer size:", png_data.size())
if png_data.size() == 0:
print("ERROR: PNG buffer is empty!")
return
print("Converting to base64...")
var base64 := Marshalls.raw_to_base64(png_data)
print("Base64 length:", base64.length())
print("First 100 chars:", base64.substr(0, 100))
print("Executing JavaScript alert test...")
JavaScriptBridge.eval("alert('TEST FROM GODOT - If you see this, JavaScript works!');")
print(separator)