Spaces:
Sleeping
Sleeping
File size: 6,428 Bytes
389d620 becda8d 389d620 becda8d 5e3a0aa 389d620 55b2419 becda8d 377a3b2 55b2419 377a3b2 55b2419 389d620 55b2419 377a3b2 55b2419 becda8d 43c1eae bec86a9 5e3a0aa 389d620 55b2419 389d620 377a3b2 389d620 becda8d c75581b 43c1eae c75581b 5e3a0aa c75581b 43c1eae becda8d 43c1eae c75581b 43c1eae a40fc41 43c1eae c75581b 43c1eae 5e3a0aa c75581b 5e3a0aa 43c1eae c75581b 5e3a0aa 43c1eae c75581b 389d620 bec86a9 389d620 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 |
import streamlit as st
import os
from PIL import Image
import random
from io import BytesIO
import datetime
import base64
# Function to arrange images dynamically
def arrange_images(image_files, canvas_size=(3000, 3000)):
if not image_files:
return None
# Initialize layout
positions = [] # Keeps track of image positions (x1, y1, x2, y2)
canvas = Image.new("RGBA", canvas_size, "white")
def get_center(pos):
"""Calculate center of a bounding box (x1, y1, x2, y2)."""
return ((pos[0] + pos[2]) // 2, (pos[1] + pos[3]) // 2)
def does_overlap(new_box, existing_boxes):
"""Check if a new bounding box overlaps any existing boxes."""
for box in existing_boxes:
if (
new_box[0] < box[2]
and new_box[2] > box[0]
and new_box[1] < box[3]
and new_box[3] > box[1]
):
return True
return False
# Place the first image at the center of the canvas
first_img_path = os.path.join(map_dir, image_files[0])
with Image.open(first_img_path) as img:
width, height = img.size
x1 = (canvas_size[0] - width) // 2
y1 = (canvas_size[1] - height) // 2
x2, y2 = x1 + width, y1 + height
positions.append((x1, y1, x2, y2))
canvas.paste(img, (x1, y1))
# Place remaining images
for img_file in image_files[1:]:
placed = False
img_path = os.path.join(map_dir, img_file)
with Image.open(img_path) as img:
width, height = img.size
while not placed:
# Choose a random existing image to connect to
target_box = random.choice(positions)
target_center = get_center(target_box)
# Randomly choose a side of the target image
side = random.choice(["top", "bottom", "left", "right"])
# Calculate the new image's position based on the chosen side
if side == "top":
x1 = target_center[0] - width // 2
y1 = target_box[1] - height
elif side == "bottom":
x1 = target_center[0] - width // 2
y1 = target_box[3]
elif side == "left":
x1 = target_box[0] - width
y1 = target_center[1] - height // 2
elif side == "right":
x1 = target_box[2]
y1 = target_center[1] - height // 2
x2, y2 = x1 + width, y1 + height
# Check for overlap
if not does_overlap((x1, y1, x2, y2), positions):
# Place the image
positions.append((x1, y1, x2, y2))
canvas.paste(img, (x1, y1))
placed = True
# Save canvas to memory
buffer = BytesIO()
canvas.save(buffer, format="PNG")
buffer.seek(0)
return buffer, canvas
# Function to create a base64 download link
def create_download_link(image_bytes, filename):
b64 = base64.b64encode(image_bytes.getvalue()).decode()
href = f'<a href="data:image/png;base64,{b64}" download="{filename}">📥 Download {filename}</a>'
return href
# Streamlit App
st.title("Dynamic Dungeon Map Generator")
st.write("Automatically generates dungeon maps by arranging PNG images dynamically.")
# Directory for images
map_dir = "." # Top-level directory
# Canvas size and scroll offsets
canvas_size = 3000
scroll_offset = {"x": 0, "y": 0}
# Initialize session state
if "layout_image" not in st.session_state:
st.session_state["layout_image"] = None
if "canvas" not in st.session_state:
st.session_state["canvas"] = None
if "saved" not in st.session_state:
st.session_state["saved"] = False
if "saved_filename" not in st.session_state:
st.session_state["saved_filename"] = None
# Generate map if not saved and layout_image is empty
if st.session_state["layout_image"] is None or not st.session_state["saved"]:
image_files = [f for f in os.listdir(map_dir) if f.endswith(".png")]
if image_files:
layout_image, canvas = arrange_images(image_files, canvas_size=(canvas_size, canvas_size))
st.session_state["layout_image"] = layout_image
st.session_state["canvas"] = canvas
# Display map
if st.session_state["layout_image"] is not None:
st.image(
st.session_state["layout_image"],
caption="Generated Dungeon Map Layout",
use_container_width=True,
output_format="PNG",
clamp=True,
)
# Save map button
if st.button("💾 Save Map"):
now = datetime.datetime.now()
filename = f"dungeon_map_{now.strftime('%Y%m%d_%H%M%S')}.png"
st.session_state["canvas"].save(filename)
st.session_state["saved"] = True
st.session_state["saved_filename"] = filename
st.success(f"Map saved as {filename}")
# Generate Base64 download link
buffer = BytesIO()
st.session_state["canvas"].save(buffer, format="PNG")
buffer.seek(0)
st.markdown(create_download_link(buffer, filename), unsafe_allow_html=True)
# Regenerate map button
if st.button("🗺️ Regenerate Map"):
image_files = [f for f in os.listdir(map_dir) if f.endswith(".png")]
if image_files:
layout_image, canvas = arrange_images(image_files, canvas_size=(canvas_size, canvas_size))
st.session_state["layout_image"] = layout_image
st.session_state["canvas"] = canvas
st.session_state["saved"] = False # Mark as unsaved
st.session_state["saved_filename"] = None
st.experimental_rerun()
# WASD Controls for scrolling
st.sidebar.title("Scroll Map")
scroll_buttons = st.sidebar.columns(3)
if scroll_buttons[0].button("⬅️"):
scroll_offset["x"] -= 100
if scroll_buttons[1].button("⬆️"):
scroll_offset["y"] -= 100
if scroll_buttons[2].button("➡️"):
scroll_offset["x"] += 100
if st.sidebar.button("⬇️"):
scroll_offset["y"] += 100
# Sidebar for file upload
st.sidebar.title("Options")
uploaded_file = st.sidebar.file_uploader("Upload a PNG file", type="png")
if uploaded_file:
# Save uploaded file to the directory
with open(os.path.join(map_dir, uploaded_file.name), "wb") as f:
f.write(uploaded_file.getbuffer())
st.sidebar.success("File uploaded successfully! Refresh the app to include it in the dungeon map.")
|