awacke1 commited on
Commit
8585bf9
·
verified ·
1 Parent(s): 52c9995

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +127 -68
app.py CHANGED
@@ -1,88 +1,147 @@
1
  import streamlit as st
2
  import os
3
  from PIL import Image
4
- import base64
5
  from io import BytesIO
 
 
6
 
7
  # Adjust Streamlit layout to wide mode
8
  st.set_page_config(layout="wide")
9
 
10
- # Generate Map as an Image
11
- def generate_map(image_files, canvas_size=(3000, 3000)):
12
- canvas = Image.new("RGBA", canvas_size, "white")
13
  if not image_files:
14
- return canvas
 
 
 
15
 
16
- grid_size = int(len(image_files) ** 0.5) + 1 # Calculate grid size
17
- img_size = canvas_size[0] // grid_size # Size for each image cell
 
18
 
19
- for idx, img_file in enumerate(image_files):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
  img_path = os.path.join(map_dir, img_file)
 
21
  with Image.open(img_path) as img:
22
- # Maintain aspect ratio
23
- img.thumbnail((img_size, img_size), Image.ANTIALIAS)
 
 
 
 
24
 
25
- # Calculate grid position
26
- row, col = divmod(idx, grid_size)
27
- x = col * img_size
28
- y = row * img_size
 
 
 
 
 
 
 
 
29
 
30
- # Paste the image on the canvas
31
- canvas.paste(img, (x, y), mask=img if img.mode == "RGBA" else None)
32
 
33
- return canvas
 
 
 
34
 
35
- # Encode Image as Base64 for Leaflet
36
- def encode_image_to_base64(image):
37
  buffer = BytesIO()
38
- image.save(buffer, format="PNG")
39
- encoded = base64.b64encode(buffer.getvalue()).decode()
40
- return encoded
 
 
 
 
 
 
 
 
 
41
 
42
  # Directory for images
43
- map_dir = "." # Replace with your directory containing images
44
- image_files = [f for f in os.listdir(map_dir) if f.endswith(".png")]
45
-
46
- # Generate the map
47
- canvas_size = (3000, 3000)
48
- canvas = generate_map(image_files, canvas_size)
49
- encoded_image = encode_image_to_base64(canvas)
50
-
51
- # Leaflet HTML Template
52
- leaflet_html = f"""
53
- <!DOCTYPE html>
54
- <html>
55
- <head>
56
- <link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/leaflet.css" />
57
- <script src="https://unpkg.com/[email protected]/dist/leaflet.js"></script>
58
- <style>
59
- #map {{
60
- height: 100vh;
61
- }}
62
- </style>
63
- </head>
64
- <body>
65
- <div id="map"></div>
66
- <script>
67
- // Initialize the map
68
- var map = L.map('map').setView([0, 0], 1);
69
-
70
- // Add the image overlay
71
- var bounds = [[-1500, -1500], [1500, 1500]];
72
- var image = L.imageOverlay("data:image/png;base64,{encoded_image}", bounds).addTo(map);
73
-
74
- // Set the map view to the bounds of the image
75
- map.fitBounds(bounds);
76
-
77
- // Add zoom controls
78
- L.control.zoom({{
79
- position: 'topright'
80
- }}).addTo(map);
81
- </script>
82
- </body>
83
- </html>
84
- """
85
-
86
- # Embed Leaflet Map in Streamlit
87
- st.title("Interactive Dungeon Map")
88
- st.components.v1.html(leaflet_html, height=600)
 
 
 
 
 
 
 
 
 
1
  import streamlit as st
2
  import os
3
  from PIL import Image
4
+ import random
5
  from io import BytesIO
6
+ import datetime
7
+ import base64
8
 
9
  # Adjust Streamlit layout to wide mode
10
  st.set_page_config(layout="wide")
11
 
12
+ # Function to arrange images dynamically
13
+ def arrange_images(image_files, canvas_size=(3000, 3000)):
 
14
  if not image_files:
15
+ return None
16
+
17
+ positions = [] # Keeps track of image positions (x1, y1, x2, y2)
18
+ canvas = Image.new("RGBA", canvas_size, "white")
19
 
20
+ def get_center(pos):
21
+ """Calculate center of a bounding box (x1, y1, x2, y2)."""
22
+ return ((pos[0] + pos[2]) // 2, (pos[1] + pos[3]) // 2)
23
 
24
+ def does_overlap(new_box, existing_boxes):
25
+ """Check if a new bounding box overlaps any existing boxes."""
26
+ for box in existing_boxes:
27
+ if (
28
+ new_box[0] < box[2]
29
+ and new_box[2] > box[0]
30
+ and new_box[1] < box[3]
31
+ and new_box[3] > box[1]
32
+ ):
33
+ return True
34
+ return False
35
+
36
+ # Place the first image at the center of the canvas
37
+ first_img_path = os.path.join(map_dir, image_files[0])
38
+ with Image.open(first_img_path) as img:
39
+ width, height = img.size
40
+ x1 = (canvas_size[0] - width) // 2
41
+ y1 = (canvas_size[1] - height) // 2
42
+ x2, y2 = x1 + width, y1 + height
43
+ positions.append((x1, y1, x2, y2))
44
+ canvas.paste(img, (x1, y1))
45
+
46
+ # Place remaining images
47
+ for img_file in image_files[1:]:
48
+ placed = False
49
  img_path = os.path.join(map_dir, img_file)
50
+
51
  with Image.open(img_path) as img:
52
+ width, height = img.size
53
+
54
+ while not placed:
55
+ target_box = random.choice(positions)
56
+ target_center = get_center(target_box)
57
+ side = random.choice(["top", "bottom", "left", "right"])
58
 
59
+ if side == "top":
60
+ x1 = target_center[0] - width // 2
61
+ y1 = target_box[1] - height
62
+ elif side == "bottom":
63
+ x1 = target_center[0] - width // 2
64
+ y1 = target_box[3]
65
+ elif side == "left":
66
+ x1 = target_box[0] - width
67
+ y1 = target_center[1] - height // 2
68
+ elif side == "right":
69
+ x1 = target_box[2]
70
+ y1 = target_center[1] - height // 2
71
 
72
+ x2, y2 = x1 + width, y1 + height
 
73
 
74
+ if not does_overlap((x1, y1, x2, y2), positions):
75
+ positions.append((x1, y1, x2, y2))
76
+ canvas.paste(img, (x1, y1))
77
+ placed = True
78
 
 
 
79
  buffer = BytesIO()
80
+ canvas.save(buffer, format="PNG")
81
+ buffer.seek(0)
82
+ return buffer, canvas
83
+
84
+ # Function to create a base64 download link
85
+ def create_download_link(image_bytes, filename):
86
+ b64 = base64.b64encode(image_bytes.getvalue()).decode()
87
+ href = f'<a href="data:image/png;base64,{b64}" download="{filename}">📥 Download {filename}</a>'
88
+ return href
89
+
90
+ # Streamlit App
91
+ st.title("Dynamic Dungeon Map Generator")
92
 
93
  # Directory for images
94
+ map_dir = "."
95
+ canvas_size = 3000
96
+
97
+ # Initialize session state
98
+ if "layout_image" not in st.session_state:
99
+ st.session_state["layout_image"] = None
100
+ if "canvas" not in st.session_state:
101
+ st.session_state["canvas"] = None
102
+
103
+ # Generate map if layout_image is empty
104
+ if st.session_state["layout_image"] is None:
105
+ image_files = [f for f in os.listdir(map_dir) if f.endswith(".png")]
106
+ if image_files:
107
+ layout_image, canvas = arrange_images(image_files, canvas_size=(canvas_size, canvas_size))
108
+ st.session_state["layout_image"] = layout_image
109
+ st.session_state["canvas"] = canvas
110
+
111
+ # Display map with scroll and zoom controls
112
+ if st.session_state["layout_image"] is not None:
113
+ st.image(
114
+ st.session_state["layout_image"],
115
+ caption="Generated Dungeon Map Layout",
116
+ use_container_width=True,
117
+ output_format="PNG",
118
+ clamp=True,
119
+ )
120
+
121
+ # Sidebar Controls
122
+ st.sidebar.title("Map Controls")
123
+ if st.sidebar.button("💾 Save Map"):
124
+ now = datetime.datetime.now()
125
+ filename = f"dungeon_map_{now.strftime('%Y%m%d_%H%M%S')}.png"
126
+ st.session_state["canvas"].save(filename)
127
+ st.sidebar.success(f"Map saved as {filename}")
128
+
129
+ if st.sidebar.button("🗺️ Regenerate Map"):
130
+ image_files = [f for f in os.listdir(map_dir) if f.endswith(".png")]
131
+ if image_files:
132
+ layout_image, canvas = arrange_images(image_files, canvas_size=(canvas_size, canvas_size))
133
+ st.session_state["layout_image"] = layout_image
134
+ st.session_state["canvas"] = canvas
135
+ st.rerun()
136
+
137
+ # Zoom controls
138
+ st.sidebar.title("Zoom")
139
+ zoom_level = st.sidebar.slider("Zoom Level", min_value=0.5, max_value=2.0, value=1.0, step=0.1)
140
+ st.image(
141
+ st.session_state["layout_image"],
142
+ caption="Zoomed Dungeon Map Layout",
143
+ use_container_width=False,
144
+ output_format="PNG",
145
+ clamp=True,
146
+ width=int(canvas_size * zoom_level),
147
+ )