JAMESPARK3 commited on
Commit
69ca09d
ยท
verified ยท
1 Parent(s): 3b7fb1b

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +335 -272
app.py CHANGED
@@ -1,13 +1,10 @@
1
  import streamlit as st
2
  import os
3
- import time
4
- import random
5
- from PIL import Image
6
  import glob
7
- from streamlit_autorefresh import st_autorefresh
8
  import base64
9
  from streamlit.components.v1 import html
10
- import io
11
 
12
  # ํŽ˜์ด์ง€ ์„ค์ •
13
  st.set_page_config(
@@ -17,223 +14,130 @@ st.set_page_config(
17
  initial_sidebar_state="collapsed"
18
  )
19
 
20
- # CSS ์Šคํƒ€์ผ ์ •์˜
21
  st.markdown("""
22
  <style>
23
- .main-content {
24
- padding: 0;
25
- max-width: 100%;
26
- }
27
- .stApp {
28
- margin: 0;
29
- padding: 0;
30
- }
31
-
32
- /* ๋ฐฐ๊ฒฝ ์ด๋ฏธ์ง€ ์Šคํƒ€์ผ๋กœ ์ˆ˜์ • */
33
  .full-view {
34
- width: 100vw;
35
- height: 100vh;
36
  position: fixed;
37
  top: 0;
38
  left: 0;
39
- z-index: 9999;
40
- background-color: #000;
41
- background-size: cover;
42
  background-position: center;
43
  background-repeat: no-repeat;
44
- display: flex;
45
- flex-direction: column;
46
- justify-content: flex-end;
47
- align-items: flex-end;
48
- padding: 20px;
49
  }
50
 
51
- /* ์ „ํ™˜ ๋ฒ„ํŠผ ์Šคํƒ€์ผ */
 
 
 
 
 
 
 
 
 
 
 
52
  .view-toggle {
53
- background: rgba(0,0,0,0.5);
54
  color: white;
55
  border: none;
56
- padding: 5px 10px;
57
  margin: 5px;
58
  border-radius: 4px;
59
  cursor: pointer;
60
  font-size: 14px;
61
  }
62
-
63
- /* ํ•˜๋‹จ ์ปจํŠธ๋กค ํŒจ๋„ */
64
- .controls-panel {
65
- display: flex;
66
- gap: 10px;
67
- margin-top: 10px;
68
  }
69
 
70
- /* ์ธ๋„ค์ผ ์Šคํƒ€์ผ */
71
- .thumbnail-container {
72
- display: flex;
73
- align-items: center;
74
- margin-bottom: 5px;
75
  }
76
- .thumbnail-container img {
77
- max-width: 60px;
78
- max-height: 60px;
79
- object-fit: contain;
80
- margin-right: 10px;
81
- border-radius: 4px;
82
- border: 1px solid #ddd;
 
83
  }
84
 
85
- /* ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ˆ˜์ • */
86
  @keyframes fadeIn {
87
- 0% { opacity: 0; }
88
- 100% { opacity: 1; }
89
  }
90
  @keyframes zoomIn {
91
- 0% { transform: scale(0.8); opacity: 0; }
92
- 100% { transform: scale(1); opacity: 1; }
93
  }
94
  @keyframes slideIn {
95
- 0% { transform: translateY(-50px); opacity: 0; }
96
- 100% { transform: translateY(0); opacity: 1; }
97
  }
98
  @keyframes rotateIn {
99
- 0% { transform: rotate(-10deg) scale(0.8); opacity: 0; }
100
- 100% { transform: rotate(0) scale(1); opacity: 1; }
101
  }
102
 
103
- .animate-fade {
104
- animation: fadeIn 1s ease-out forwards;
 
 
105
  }
106
- .animate-zoom {
107
- animation: zoomIn 1s ease-out forwards;
 
108
  }
109
- .animate-slide {
110
- animation: slideIn 1s ease-out forwards;
 
 
111
  }
112
- .animate-rotate {
113
- animation: rotateIn 1s ease-out forwards;
 
 
 
114
  }
115
  </style>
116
  """, unsafe_allow_html=True)
117
 
118
- # ์ดˆ๊ธฐ ์„ค์ • ๋ฐ ์ƒํƒœ ๊ด€๋ฆฌ
119
- if 'contents' not in st.session_state:
120
- # contents ํด๋” ๋‚ด์˜ ๋ชจ๋“  ์ด๋ฏธ์ง€ ํŒŒ์ผ ๋กœ๋“œ
121
- if not os.path.exists('contents'):
122
- os.makedirs('contents')
123
-
124
- image_files = glob.glob('contents/*.jpg') + glob.glob('contents/*.jpeg') + glob.glob('contents/*.png')
125
- st.session_state.contents = image_files
126
-
127
- if 'current_image_index' not in st.session_state:
128
- st.session_state.current_image_index = 0
129
-
130
- if 'animation_type' not in st.session_state:
131
- st.session_state.animation_type = 'animate-fade'
132
-
133
- if 'activate_fullscreen' not in st.session_state:
134
- st.session_state.activate_fullscreen = False
135
-
136
- if 'fit_mode' not in st.session_state:
137
- st.session_state.fit_mode = 'cover' # ๊ธฐ๋ณธ๊ฐ’์€ ํ™”๋ฉด์— ๊ฝ‰ ์ฐจ๊ฒŒ
138
-
139
- # ์—ฌ๊ธฐ์— ์ถ”๊ฐ€ํ•˜์„ธ์š”!
140
- if 'app_loaded' not in st.session_state:
141
- st.session_state.app_loaded = False
142
-
143
- # ์Šฌ๋ผ์ด๋“œ์‡ผ ์ž๋™ ์‹œ์ž‘ ๋กœ์ง
144
- if not st.session_state.app_loaded and not st.session_state.get('preview_mode', False):
145
- if st.session_state.contents: # ์ด๋ฏธ์ง€๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ์—๋งŒ ์ž๋™ ์‹œ์ž‘
146
- st.session_state.preview_mode = True
147
- st.session_state.preview_start_time = time.time()
148
- st.session_state.activate_fullscreen = True
149
- st.session_state.app_loaded = True # ์•ฑ์ด ๋กœ๋“œ๋˜์—ˆ์Œ์„ ํ‘œ์‹œ
150
-
151
- # ์ด๋ฏธ์ง€ ์ธ๋„ค์ผ ์ƒ์„ฑ ํ•จ์ˆ˜
152
- def create_thumbnail(image_path, size=(60, 60)):
153
- try:
154
- img = Image.open(image_path)
155
- img.thumbnail(size)
156
- buffered = io.BytesIO()
157
- img.save(buffered, format=img.format or "JPEG")
158
- return buffered.getvalue()
159
- except Exception as e:
160
- st.error(f"์ธ๋„ค์ผ ์ƒ์„ฑ ์˜ค๋ฅ˜: {e}")
161
- return None
162
-
163
- # ์ด๋ฏธ์ง€ ์ˆœ์„œ ๋ณ€๊ฒฝ ํ•จ์ˆ˜๋“ค
164
- def move_up(index):
165
- if index > 0:
166
- st.session_state.contents[index], st.session_state.contents[index-1] = st.session_state.contents[index-1], st.session_state.contents[index]
167
-
168
- def move_down(index):
169
- if index < len(st.session_state.contents) - 1:
170
- st.session_state.contents[index], st.session_state.contents[index+1] = st.session_state.contents[index+1], st.session_state.contents[index]
171
-
172
- def move_to_top(index):
173
- if index > 0:
174
- item = st.session_state.contents.pop(index)
175
- st.session_state.contents.insert(0, item)
176
-
177
- def move_to_bottom(index):
178
- if index < len(st.session_state.contents) - 1:
179
- item = st.session_state.contents.pop(index)
180
- st.session_state.contents.append(item)
181
-
182
- # ์ž๋™ ์ „์ฒดํ™”๋ฉด ๋ชจ๋“œ๋ฅผ ์œ„ํ•œ JavaScript ํ•จ์ˆ˜
183
  def inject_fullscreen_js():
184
  js_code = """
185
  <script>
186
- // ์ „์ฒดํ™”๋ฉด ๋ชจ๋“œ ํ™œ์„ฑํ™” ํ•จ์ˆ˜
187
- function activateFullscreen() {
188
- // ์ „์ฒดํ™”๋ฉด ๋ฒ„ํŠผ ์ฐพ๊ธฐ (Streamlit์˜ ๊ธฐ๋ณธ ์ „์ฒดํ™”๋ฉด ๋ฒ„ํŠผ)
189
- const fullscreenButton = window.parent.document.querySelector('button[title="View fullscreen"]');
190
-
191
- if (fullscreenButton) {
192
- // ๋ฒ„ํŠผ์ด ์žˆ์œผ๋ฉด ํด๋ฆญ
193
- fullscreenButton.click();
194
- } else {
195
- // ๋ฒ„ํŠผ์„ ์ฐพ์„ ์ˆ˜ ์—†์œผ๋ฉด ๋ธŒ๋ผ์šฐ์ € API ์‚ฌ์šฉ
196
- var elem = document.documentElement;
197
  if (elem.requestFullscreen) {
198
  elem.requestFullscreen();
199
- } else if (elem.mozRequestFullScreen) { /* Firefox */
200
- elem.mozRequestFullScreen();
201
- } else if (elem.webkitRequestFullscreen) { /* Chrome, Safari & Opera */
202
- elem.webkitRequestFullscreen();
203
- } else if (elem.msRequestFullscreen) { /* IE/Edge */
204
  elem.msRequestFullscreen();
 
 
 
 
205
  }
206
  }
207
  }
208
-
209
- // 1์ดˆ ํ›„ ์ „์ฒดํ™”๋ฉด ํ™œ์„ฑํ™”
210
  setTimeout(function() {
211
- activateFullscreen();
212
  }, 1000);
213
  </script>
214
  """
215
  html(js_code, height=0, width=0)
216
 
217
- # ์• ๋‹ˆ๋ฉ”์ด์…˜ JS๋ฅผ ์ฃผ์ž…ํ•˜๋Š” ํ•จ์ˆ˜
218
- def inject_animation_js(animation_type):
219
- js_code = f"""
220
- <script>
221
- // ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ ์šฉ
222
- function applyAnimation() {{
223
- const imageContainer = document.querySelector('.full-view img');
224
- if (imageContainer) {{
225
- imageContainer.classList.remove('animate-fade', 'animate-zoom', 'animate-slide', 'animate-rotate');
226
- void imageContainer.offsetWidth; // ๊ฐ•์ œ ๋ฆฌํ”Œ๋กœ์šฐ
227
- imageContainer.classList.add('{animation_type}');
228
- }}
229
- }}
230
-
231
- // ํŽ˜์ด์ง€ ๋กœ๋“œ ํ›„ ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ ์šฉ
232
- setTimeout(applyAnimation, 100);
233
- </script>
234
- """
235
- html(js_code, height=0, width=0)
236
-
237
  # ๋ฐฐ๊ฒฝ ์ด๋ฏธ์ง€ ํ‘œ์‹œ ๋ฐฉ์‹ ์ „ํ™˜์„ ์œ„ํ•œ JavaScript ํ•จ์ˆ˜
238
  def inject_background_toggle_js():
239
  js_code = """
@@ -269,149 +173,286 @@ def inject_background_toggle_js():
269
  """
270
  html(js_code, height=0, width=0)
271
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
272
 
273
- # ์‚ฌ์ด๋“œ๋ฐ”์— ๊ด€๋ฆฌ ๊ธฐ๋Šฅ ์ถ”๊ฐ€
274
  with st.sidebar:
275
- st.title("์ปจํ…์ธ  ๊ด€๋ฆฌ")
276
 
277
  # ์ด๋ฏธ์ง€ ์—…๋กœ๋“œ
278
- uploaded_files = st.file_uploader("์ด๋ฏธ์ง€ ์ถ”๊ฐ€", type=["jpg", "jpeg", "png"], accept_multiple_files=True)
 
 
279
  if uploaded_files:
280
- for file in uploaded_files:
281
- # ํŒŒ์ผ ์ €์žฅ
282
- file_path = os.path.join('contents', file.name)
 
 
 
 
 
 
283
  with open(file_path, "wb") as f:
284
- f.write(file.getbuffer())
285
 
286
- # ๋ชฉ๋ก์— ์ถ”๊ฐ€ (์ค‘๋ณต ํ™•์ธ)
287
  if file_path not in st.session_state.contents:
288
  st.session_state.contents.append(file_path)
289
 
290
  st.success(f"{len(uploaded_files)}๊ฐœ ์ด๋ฏธ์ง€๊ฐ€ ์ถ”๊ฐ€๋˜์—ˆ์Šต๋‹ˆ๋‹ค.")
291
 
292
- # ํ˜„์žฌ ์ฝ˜ํ…์ธ  ๋ชฉ๋ก ๋ฐ ์‚ญ์ œ ๊ธฐ๋Šฅ
293
- st.subheader("ํ˜„์žฌ ์ปจํ…์ธ  ๋ชฉ๋ก ๋ฐ ์ˆœ์„œ ๊ด€๋ฆฌ")
294
 
295
  if not st.session_state.contents:
296
- st.info("์ปจํ…์ธ ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ์ด๋ฏธ์ง€๋ฅผ ์ถ”๊ฐ€ํ•ด์ฃผ์„ธ์š”.")
297
  else:
298
- # ํ‘œ์‹œ ์ˆœ์„œ ๊ด€๋ฆฌ
299
  for i, img_path in enumerate(st.session_state.contents):
300
- img_name = os.path.basename(img_path)
301
-
302
- # ์ธ๋„ค์ผ๊ณผ ํŒŒ์ผ๋ช…์„ ํฌํ•จํ•œ HTML ์ƒ์„ฑ
303
- thumbnail_data = create_thumbnail(img_path)
304
- if thumbnail_data:
305
- thumbnail_b64 = base64.b64encode(thumbnail_data).decode()
306
- st.markdown(f"""
307
- <div class="thumbnail-container">
308
- <img src="data:image/jpeg;base64,{thumbnail_b64}" alt="{img_name}" />
309
- <div>{i+1}. {img_name}</div>
310
- </div>
311
- """, unsafe_allow_html=True)
312
- else:
313
- st.write(f"{i+1}. {img_name}")
314
 
315
- # ์ˆœ์„œ ๋ฒ„ํŠผ๋“ค
316
- col1, col2 = st.columns(2)
317
  with col1:
318
- if st.button("โ†‘ ์œ„๋กœ", key=f"up_{i}", help="ํ•œ ์œ„์น˜ ์œ„๋กœ ์ด๋™"):
319
- move_up(i)
320
- st.rerun()
321
 
322
  with col2:
323
- if st.button("โ†“ ์•„๋ž˜๋กœ", key=f"down_{i}", help="ํ•œ ์œ„์น˜ ์•„๋ž˜๋กœ ์ด๋™"):
324
- move_down(i)
 
325
  st.rerun()
326
-
327
- col3, col4 = st.columns(2)
328
- with col3:
329
- if st.button("โค’ ๋งจ์œ„๋กœ", key=f"top_{i}", help="๋งจ ์œ„๋กœ ์ด๋™"):
330
- move_to_top(i)
331
- st.rerun()
332
-
333
- with col4:
334
- if st.button("โค“ ๋งจ์•„๋ž˜๋กœ", key=f"bottom_{i}", help="๋งจ ์•„๋ž˜๋กœ ์ด๋™"):
335
- move_to_bottom(i)
336
- st.rerun()
337
-
338
- # ์‚ญ์ œ ๋ฒ„ํŠผ
339
- if st.button("๐Ÿ—‘๏ธ ์‚ญ์ œ", key=f"del_{i}", help="์ด๋ฏธ์ง€ ์‚ญ์ œ"):
340
- if os.path.exists(img_path):
341
- # ํŒŒ์ผ ์‚ญ์ œ ์—ฌ๋ถ€ ํ™•์ธ
342
- if st.session_state.contents.count(img_path) == 1:
343
- os.remove(img_path)
344
 
345
- # ๋ชฉ๋ก์—์„œ ์ œ๊ฑฐ
346
- st.session_state.contents.remove(img_path)
347
-
348
- # ํ˜„์žฌ ์ด๋ฏธ์ง€ ์ธ๋ฑ์Šค ์กฐ์ •
349
- if st.session_state.current_image_index >= len(st.session_state.contents):
350
- st.session_state.current_image_index = 0
351
 
352
- st.rerun()
 
 
 
353
 
354
  st.markdown("<hr>", unsafe_allow_html=True)
355
 
356
- # ์• ๋‹ˆ๋ฉ”์ด์…˜ ํšจ๊ณผ ์„ ํƒ
357
- st.subheader("ํ™”๋ฉด ์ „ํ™˜ ํšจ๊ณผ")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
358
  animation_options = {
359
- "animate-fade": "ํŽ˜์ด๋“œ ์ธ",
360
- "animate-zoom": "์คŒ ์ธ",
361
- "animate-slide": "์Šฌ๋ผ์ด๋“œ ์ธ",
362
- "animate-rotate": "ํšŒ์ „ ์ธ"
363
  }
364
- selected_animation = st.selectbox(
365
- "ํ™”๋ฉด ์ „ํ™˜ ์• ๋‹ˆ๋ฉ”์ด์…˜",
 
366
  options=list(animation_options.keys()),
367
  format_func=lambda x: animation_options[x],
368
- index=list(animation_options.keys()).index(st.session_state.animation_type)
369
  )
 
370
  if selected_animation != st.session_state.animation_type:
371
  st.session_state.animation_type = selected_animation
372
 
373
  # ์žฌ์ƒ ์„ค์ •
374
  st.subheader("์žฌ์ƒ ์„ค์ •")
375
- preview_interval = st.slider("ํ‘œ์‹œ ๊ฐ„๊ฒฉ (์ดˆ)", 2, 10, 5)
376
 
377
- # ํ‘œ์‹œ ์˜ต์…˜
378
- fit_options = {"cover": "ํ™”๋ฉด์— ๊ฝ‰ ์ฐจ๊ฒŒ", "contain": "์›๋ณธ ๋น„์œจ ์œ ์ง€"}
379
- selected_fit = st.selectbox(
 
 
 
 
380
  "์ด๋ฏธ์ง€ ํ‘œ์‹œ ๋ฐฉ์‹",
381
  options=list(fit_options.keys()),
382
  format_func=lambda x: fit_options[x],
383
- index=list(fit_options.keys()).index(st.session_state.fit_mode)
384
  )
 
385
  if selected_fit != st.session_state.fit_mode:
386
  st.session_state.fit_mode = selected_fit
387
 
388
- # ๋ฏธ๋ฆฌ๋ณด๊ธฐ ์‹œ์ž‘ ๋ฒ„ํŠผ
389
- if st.button("์ „์ฒดํ™”๋ฉด ๋ฏธ๋ฆฌ๋ณด๊ธฐ ์‹œ์ž‘", use_container_width=True):
390
- st.session_state.preview_mode = True
391
- st.session_state.preview_start_time = time.time()
392
- st.session_state.activate_fullscreen = True
393
- st.rerun()
394
-
395
- # ์ „์ฒดํ™”๋ฉด ๋ชจ๋“œ ํ™œ์„ฑํ™” (์กฐ๊ฑด๋ถ€)
396
- if st.session_state.get('activate_fullscreen', False):
397
- inject_fullscreen_js()
398
- st.session_state.activate_fullscreen = False # ํ•œ ๋ฒˆ๋งŒ ์‹คํ–‰๋˜๋„๋ก ๋ฆฌ์…‹
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
399
 
400
  # ๋ฉ”์ธ ์ปจํ…์ธ  ์˜์—ญ
401
  if st.session_state.get('preview_mode', False):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
402
  # ์ž๋™ ์ƒˆ๋กœ๊ณ ์นจ์„ ์œ„ํ•œ ์นด์šดํ„ฐ
403
  count = st_autorefresh(interval=preview_interval * 1000, key="refreshInterval")
404
 
405
  # ๋ฐฐ๊ฒฝ ์ด๋ฏธ์ง€ ์ „ํ™˜ JS ์‚ฝ์ž… (๋จผ์ € ์‹คํ–‰๋˜์–ด์•ผ ํ•จ)
406
  inject_background_toggle_js()
407
 
 
 
 
 
408
  # ํ˜„์žฌ ์ธ๋ฑ์Šค ์—…๋ฐ์ดํŠธ
409
  if count > 0 and st.session_state.contents:
410
- st.session_state.current_image_index = (st.session_state.current_image_index + 1) % len(st.session_state.contents)
 
 
411
 
412
  # ํ™”๋ฉด์— ๋ฐฐ๊ฒฝ ์ด๋ฏธ์ง€๋กœ ํ‘œ์‹œ
413
  if st.session_state.contents:
414
- full_img_path = st.session_state.contents[st.session_state.current_image_index]
 
 
 
 
415
 
416
  # ์›น์—์„œ ์ ‘๊ทผ ๊ฐ€๋Šฅํ•œ ์ด๋ฏธ์ง€ URL๋กœ ๋ณ€ํ™˜ (Base64 ์ธ์ฝ”๋”ฉ ์‚ฌ์šฉ)
417
  with open(full_img_path, "rb") as img_file:
@@ -420,7 +461,7 @@ if st.session_state.get('preview_mode', False):
420
  # ์ด๋ฏธ์ง€ ํ™•์žฅ์ž ๊ฐ€์ ธ์˜ค๊ธฐ (๊ธฐ๋ณธ๊ฐ’์€ jpeg)
421
  file_ext = os.path.splitext(full_img_path)[1][1:] or "jpeg"
422
 
423
- # ๋ฐฐ๊ฒฝ ์ด๋ฏธ์ง€ ์„ค์ •๊ณผ ์ปจํŠธ๋กค ๋ฒ„ํŠผ์ด ํฌํ•จ๋œ HTML ์ƒ์„ฑ
424
  background_html = f"""
425
  <div class="full-view animate-{st.session_state.animation_type}"
426
  style="background-image: url('data:image/{file_ext};base64,{img_data}');
@@ -455,8 +496,22 @@ if st.session_state.get('preview_mode', False):
455
  window.applyBackgroundAnimation('animate-{st.session_state.animation_type}');
456
  }}
457
  }}, 1500);
 
 
 
 
 
 
 
 
 
 
 
 
 
458
  </script>
459
  """
 
460
 
461
  # HTML ์ง์ ‘ ์‚ฝ์ž…
462
  st.markdown(background_html, unsafe_allow_html=True)
@@ -469,28 +524,36 @@ if st.session_state.get('preview_mode', False):
469
  footer {visibility: hidden;}
470
  </style>
471
  """, unsafe_allow_html=True)
472
-
473
-
474
- else:
475
- st.info("ํ‘œ์‹œํ•  ์ด๋ฏธ์ง€๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ์ด๋ฏธ์ง€๋ฅผ ์ถ”๊ฐ€ํ•ด์ฃผ์„ธ์š”.")
476
- if st.button("๋ฏธ๋ฆฌ๋ณด๊ธฐ ์ข…๋ฃŒ"):
477
- st.session_state.preview_mode = False
478
- st.rerun()
479
-
480
  else:
481
- # ์ผ๋ฐ˜ ๋ชจ๋“œ - ์ผ๋ฐ˜ ๊ด€๋ฆฌ ํ™”๋ฉด
482
- st.title("๋””์Šคํ”Œ๋ ˆ์ด ์ปจํ…์ธ  ๊ด€๋ฆฌ")
483
 
484
  if not st.session_state.contents:
485
- st.info("์‚ฌ์ด๋“œ๋ฐ”์—์„œ ์ด๋ฏธ์ง€๋ฅผ ์ถ”๊ฐ€ํ•˜์„ธ์š”.")
486
  else:
487
- st.write("์‚ฌ์ด๋“œ๋ฐ”์—์„œ ์ด๋ฏธ์ง€๋ฅผ ๊ด€๋ฆฌํ•˜๊ณ  ์•„๋ž˜ ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜์—ฌ ์ „์ฒดํ™”๋ฉด ๋ฏธ๋ฆฌ๋ณด๊ธฐ๋ฅผ ์‹œ์ž‘ํ•˜์„ธ์š”.")
488
-
489
- # ์ด๋ฏธ์ง€ ๋ฏธ๋ฆฌ๋ณด๊ธฐ ๊ทธ๋ฆฌ๋“œ
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
490
  cols = st.columns(4)
491
  for i, img_path in enumerate(st.session_state.contents):
492
- if i < len(cols):
493
- cols[i].image(img_path, caption=os.path.basename(img_path), width=200)
494
- else:
495
- break
496
 
 
1
  import streamlit as st
2
  import os
 
 
 
3
  import glob
4
+ import time
5
  import base64
6
  from streamlit.components.v1 import html
7
+ from streamlit_autorefresh import st_autorefresh
8
 
9
  # ํŽ˜์ด์ง€ ์„ค์ •
10
  st.set_page_config(
 
14
  initial_sidebar_state="collapsed"
15
  )
16
 
17
+ # ์ „์—ญ CSS ์„ค์ •
18
  st.markdown("""
19
  <style>
20
+ /* ์ „์ฒด ํ™”๋ฉด ๋ฐฐ๊ฒฝ ์ด๋ฏธ์ง€ ์Šคํƒ€์ผ */
 
 
 
 
 
 
 
 
 
21
  .full-view {
 
 
22
  position: fixed;
23
  top: 0;
24
  left: 0;
25
+ width: 100vw;
26
+ height: 100vh;
 
27
  background-position: center;
28
  background-repeat: no-repeat;
29
+ background-color: black;
30
+ transition: opacity 1s ease-in-out;
31
+ z-index: 9998;
 
 
32
  }
33
 
34
+ /* ์ปจํŠธ๋กค ํŒจ๋„ ์Šคํƒ€์ผ */
35
+ .controls-panel {
36
+ position: fixed;
37
+ bottom: 20px;
38
+ right: 20px;
39
+ z-index: 9999;
40
+ opacity: 0.2;
41
+ transition: opacity 0.3s;
42
+ }
43
+ .controls-panel:hover {
44
+ opacity: 1;
45
+ }
46
  .view-toggle {
47
+ background-color: rgba(0, 0, 0, 0.5);
48
  color: white;
49
  border: none;
50
+ padding: 8px 16px;
51
  margin: 5px;
52
  border-radius: 4px;
53
  cursor: pointer;
54
  font-size: 14px;
55
  }
56
+ .view-toggle:hover {
57
+ background-color: rgba(0, 0, 0, 0.8);
 
 
 
 
58
  }
59
 
60
+ /* ์• ๋‹ˆ๋ฉ”์ด์…˜ ํšจ๊ณผ */
61
+ .animate-fade {
62
+ animation: fadeIn 2s;
 
 
63
  }
64
+ .animate-zoom {
65
+ animation: zoomIn 2s;
66
+ }
67
+ .animate-slide {
68
+ animation: slideIn 2s;
69
+ }
70
+ .animate-rotate {
71
+ animation: rotateIn 2s;
72
  }
73
 
 
74
  @keyframes fadeIn {
75
+ from { opacity: 0; }
76
+ to { opacity: 1; }
77
  }
78
  @keyframes zoomIn {
79
+ from { transform: scale(0.7); opacity: 0; }
80
+ to { transform: scale(1); opacity: 1; }
81
  }
82
  @keyframes slideIn {
83
+ from { transform: translateY(20%); opacity: 0; }
84
+ to { transform: translateY(0); opacity: 1; }
85
  }
86
  @keyframes rotateIn {
87
+ from { transform: rotate(-10deg) scale(0.9); opacity: 0; }
88
+ to { transform: rotate(0) scale(1); opacity: 1; }
89
  }
90
 
91
+ /* ์ด๋ฏธ์ง€ ๊ด€๋ฆฌ ๊ทธ๋ฆฌ๋“œ ์Šคํƒ€์ผ */
92
+ .image-item {
93
+ position: relative;
94
+ margin-bottom: 10px;
95
  }
96
+ .image-item img {
97
+ width: 100%;
98
+ border-radius: 4px;
99
  }
100
+ .image-actions {
101
+ position: absolute;
102
+ top: 5px;
103
+ right: 5px;
104
  }
105
+ .image-name {
106
+ font-size: 12px;
107
+ overflow: hidden;
108
+ text-overflow: ellipsis;
109
+ white-space: nowrap;
110
  }
111
  </style>
112
  """, unsafe_allow_html=True)
113
 
114
+ # ์ „์ฒด ํ™”๋ฉด JS ํ•จ์ˆ˜
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
115
  def inject_fullscreen_js():
116
  js_code = """
117
  <script>
118
+ function toggleFullScreen() {
119
+ var elem = document.documentElement;
120
+ if (!document.fullscreenElement && !document.mozFullScreenElement &&
121
+ !document.webkitFullscreenElement && !document.msFullscreenElement) {
 
 
 
 
 
 
 
122
  if (elem.requestFullscreen) {
123
  elem.requestFullscreen();
124
+ } else if (elem.msRequestFullscreen) {
 
 
 
 
125
  elem.msRequestFullscreen();
126
+ } else if (elem.mozRequestFullScreen) {
127
+ elem.mozRequestFullScreen();
128
+ } else if (elem.webkitRequestFullscreen) {
129
+ elem.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT);
130
  }
131
  }
132
  }
133
+ // ์ „์ฒด ํ™”๋ฉด ํ™œ์„ฑํ™” ์‹œ๋„
 
134
  setTimeout(function() {
135
+ toggleFullScreen();
136
  }, 1000);
137
  </script>
138
  """
139
  html(js_code, height=0, width=0)
140
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
141
  # ๋ฐฐ๊ฒฝ ์ด๋ฏธ์ง€ ํ‘œ์‹œ ๋ฐฉ์‹ ์ „ํ™˜์„ ์œ„ํ•œ JavaScript ํ•จ์ˆ˜
142
  def inject_background_toggle_js():
143
  js_code = """
 
173
  """
174
  html(js_code, height=0, width=0)
175
 
176
+ # ์ดˆ๊ธฐ ์„ค์ • ๋ฐ ์ƒํƒœ ๊ด€๋ฆฌ
177
+ if 'contents' not in st.session_state:
178
+ # contents ํด๋” ๋‚ด์˜ ๋ชจ๋“  ์ด๋ฏธ์ง€ ํŒŒ์ผ ๋กœ๋“œ
179
+ if not os.path.exists('contents'):
180
+ os.makedirs('contents')
181
+
182
+ image_files = glob.glob('contents/*.jpg') + glob.glob('contents/*.jpeg') + glob.glob('contents/*.png')
183
+ st.session_state.contents = image_files
184
+
185
+ if 'current_image_index' not in st.session_state:
186
+ st.session_state.current_image_index = 0
187
+
188
+ if 'animation_type' not in st.session_state:
189
+ st.session_state.animation_type = 'animate-fade'
190
+
191
+ if 'activate_fullscreen' not in st.session_state:
192
+ st.session_state.activate_fullscreen = False
193
+
194
+ if 'fit_mode' not in st.session_state:
195
+ st.session_state.fit_mode = 'cover' # ๊ธฐ๋ณธ๊ฐ’์€ ํ™”๋ฉด์— ๊ฝ‰ ์ฐจ๊ฒŒ
196
+
197
+ if 'app_loaded' not in st.session_state:
198
+ st.session_state.app_loaded = False
199
+
200
+ if 'fixed_image_enabled' not in st.session_state:
201
+ st.session_state.fixed_image_enabled = False
202
+
203
+ if 'fixed_image_path' not in st.session_state:
204
+ st.session_state.fixed_image_path = None
205
+
206
+ # ์Šฌ๋ผ์ด๋“œ์‡ผ ์ž๋™ ์‹œ์ž‘ ๋กœ์ง
207
+ if not st.session_state.app_loaded and not st.session_state.get('preview_mode', False):
208
+ if st.session_state.contents: # ์ด๋ฏธ์ง€๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ์—๋งŒ ์ž๋™ ์‹œ์ž‘
209
+ st.session_state.preview_mode = True
210
+ st.session_state.preview_start_time = time.time()
211
+ st.session_state.activate_fullscreen = True
212
+ st.session_state.app_loaded = True # ์•ฑ์ด ๋กœ๋“œ๋˜์—ˆ์Œ์„ ํ‘œ์‹œ
213
 
214
+ # ์‚ฌ์ด๋“œ๋ฐ” - ์ด๋ฏธ์ง€ ๊ด€๋ฆฌ
215
  with st.sidebar:
216
+ st.title("๐Ÿ“ธ ๋””์Šคํ”Œ๋ ˆ์ด ์„ค์ •")
217
 
218
  # ์ด๋ฏธ์ง€ ์—…๋กœ๋“œ
219
+ st.subheader("์ด๋ฏธ์ง€ ์ถ”๊ฐ€")
220
+ uploaded_files = st.file_uploader("์ด๋ฏธ์ง€ ํŒŒ์ผ์„ ์—…๋กœ๋“œํ•˜์„ธ์š”", type=["jpg", "jpeg", "png"], accept_multiple_files=True)
221
+
222
  if uploaded_files:
223
+ for uploaded_file in uploaded_files:
224
+ # contents ๋””๋ ‰ํ† ๋ฆฌ๊ฐ€ ์—†์œผ๋ฉด ์ƒ์„ฑ
225
+ if not os.path.exists('contents'):
226
+ os.makedirs('contents')
227
+
228
+ # ์ €์žฅ ๊ฒฝ๋กœ ์ƒ์„ฑ
229
+ file_path = os.path.join('contents', uploaded_file.name)
230
+
231
+ # ์ด๋ฏธ์ง€ ์ €์žฅ
232
  with open(file_path, "wb") as f:
233
+ f.write(uploaded_file.getvalue())
234
 
235
+ # ์ €์žฅ๋œ ์ด๋ฏธ์ง€๋ฅผ ๋ชฉ๋ก์— ์ถ”๊ฐ€ (์ค‘๋ณต ๋ฐฉ์ง€)
236
  if file_path not in st.session_state.contents:
237
  st.session_state.contents.append(file_path)
238
 
239
  st.success(f"{len(uploaded_files)}๊ฐœ ์ด๋ฏธ์ง€๊ฐ€ ์ถ”๊ฐ€๋˜์—ˆ์Šต๋‹ˆ๋‹ค.")
240
 
241
+ # ์ด๋ฏธ์ง€ ๋ชฉ๋ก ๋ฐ ๊ด€๋ฆฌ
242
+ st.subheader("์ด๋ฏธ์ง€ ์ˆœ์„œ ์กฐ์ •")
243
 
244
  if not st.session_state.contents:
245
+ st.info("๋“ฑ๋ก๋œ ์ด๋ฏธ์ง€๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ์ด๋ฏธ์ง€๋ฅผ ์ถ”๊ฐ€ํ•ด์ฃผ์„ธ์š”.")
246
  else:
247
+ # ์ด๋ฏธ์ง€ ๋ชฉ๋ก ํ‘œ์‹œ ๋ฐ ์ˆœ์„œ ์กฐ์ •
248
  for i, img_path in enumerate(st.session_state.contents):
249
+ col1, col2 = st.columns([3, 1])
 
 
 
 
 
 
 
 
 
 
 
 
 
250
 
 
 
251
  with col1:
252
+ st.text(os.path.basename(img_path))
253
+ st.image(img_path, width=150)
 
254
 
255
  with col2:
256
+ # ์œ„๋กœ ์ด๋™ ๋ฒ„ํŠผ
257
+ if i > 0 and st.button("๐Ÿ‘†", key=f"up_{i}"):
258
+ st.session_state.contents[i], st.session_state.contents[i-1] = st.session_state.contents[i-1], st.session_state.contents[i]
259
  st.rerun()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
260
 
261
+ # ์•„๋ž˜๋กœ ์ด๋™ ๋ฒ„ํŠผ
262
+ if i < len(st.session_state.contents) - 1 and st.button("๐Ÿ‘‡", key=f"down_{i}"):
263
+ st.session_state.contents[i], st.session_state.contents[i+1] = st.session_state.contents[i+1], st.session_state.contents[i]
264
+ st.rerun()
 
 
265
 
266
+ # ์‚ญ์ œ ๋ฒ„ํŠผ
267
+ if st.button("๐Ÿ—‘๏ธ", key=f"delete_{i}"):
268
+ del st.session_state.contents[i]
269
+ st.rerun()
270
 
271
  st.markdown("<hr>", unsafe_allow_html=True)
272
 
273
+ # ์ด๋ฏธ์ง€ ๊ณ ์ • ์„ค์ •
274
+ st.subheader("์ด๋ฏธ์ง€ ๊ณ ์ • ์„ค์ •")
275
+ fixed_image_enabled = st.checkbox(
276
+ "ํ•œ ์ด๋ฏธ์ง€๋งŒ ๊ณ ์ •ํ•˜์—ฌ ํ‘œ์‹œ",
277
+ value=st.session_state.fixed_image_enabled,
278
+ help="์ฒดํฌํ•˜๋ฉด ์„ ํƒํ•œ ์ด๋ฏธ์ง€๋งŒ ๊ณ„์† ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค. ์Šฌ๋ผ์ด๋“œ์‡ผ๊ฐ€ ์ค‘์ง€๋ฉ๋‹ˆ๋‹ค."
279
+ )
280
+
281
+ # ์ฒดํฌ๋ฐ•์Šค ์ƒํƒœ๊ฐ€ ๋ณ€๊ฒฝ๋˜์—ˆ์„ ๋•Œ ์„ธ์…˜ ์ƒํƒœ ์—…๋ฐ์ดํŠธ
282
+ if fixed_image_enabled != st.session_state.fixed_image_enabled:
283
+ st.session_state.fixed_image_enabled = fixed_image_enabled
284
+ # ๊ณ ์ • ๋ชจ๋“œ๊ฐ€ ๋น„ํ™œ์„ฑํ™”๋˜๋ฉด ์Šฌ๋ผ์ด๋“œ์‡ผ ์žฌ๊ฐœ
285
+ if not fixed_image_enabled and st.session_state.get('preview_mode', False):
286
+ st.session_state.preview_start_time = time.time()
287
+
288
+ # ์ด๋ฏธ์ง€ ๊ณ ์ • ๋ชจ๋“œ๊ฐ€ ํ™œ์„ฑํ™”๋œ ๊ฒฝ์šฐ์—๋งŒ ์ด๋ฏธ์ง€ ์„ ํƒ ๋“œ๋กญ๋‹ค์šด ํ‘œ์‹œ
289
+ if st.session_state.fixed_image_enabled:
290
+ # ์ด๋ฏธ์ง€ ํŒŒ์ผ ๊ฒฝ๋กœ์—์„œ ํŒŒ์ผ๋ช…๋งŒ ์ถ”์ถœํ•˜์—ฌ ํ‘œ์‹œ ์˜ต์…˜ ์ƒ์„ฑ
291
+ image_options = {img_path: os.path.basename(img_path) for img_path in st.session_state.contents}
292
+
293
+ # ์„ ํƒ๋œ ์ด๋ฏธ์ง€๊ฐ€ ์—†๊ฑฐ๋‚˜ ๋ชฉ๋ก์— ์—†๋Š” ๊ฒฝ์šฐ ์ฒซ ๋ฒˆ์งธ ์ด๋ฏธ์ง€ ์„ ํƒ
294
+ default_index = 0
295
+ if st.session_state.fixed_image_path in image_options:
296
+ default_index = list(image_options.keys()).index(st.session_state.fixed_image_path)
297
+
298
+ # ์ด๋ฏธ์ง€ ์„ ํƒ ๋“œ๋กญ๋‹ค์šด
299
+ if st.session_state.contents: # ์ด๋ฏธ์ง€๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ์—๋งŒ ๋“œ๋กญ๋‹ค์šด ํ‘œ์‹œ
300
+ selected_image = st.selectbox(
301
+ "๊ณ ์ •ํ•  ์ด๋ฏธ์ง€ ์„ ํƒ",
302
+ options=list(image_options.keys()),
303
+ format_func=lambda x: image_options[x],
304
+ index=default_index
305
+ )
306
+
307
+ # ์„ ํƒ๋œ ์ด๋ฏธ์ง€ ์ €์žฅ
308
+ st.session_state.fixed_image_path = selected_image
309
+
310
+ # ์„ ํƒ๋œ ์ด๋ฏธ์ง€ ๋ฏธ๋ฆฌ๋ณด๊ธฐ ํ‘œ์‹œ
311
+ st.image(selected_image, caption="์„ ํƒ๋œ ์ด๋ฏธ์ง€", width=200)
312
+ else:
313
+ st.warning("ํ‘œ์‹œํ•  ์ด๋ฏธ์ง€๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ์ด๋ฏธ์ง€๋ฅผ ์ถ”๊ฐ€ํ•ด์ฃผ์„ธ์š”.")
314
+
315
+ # ์• ๋‹ˆ๋ฉ”์ด์…˜ ํšจ๊ณผ ์„ ํƒ (๊ณ„์†)
316
  animation_options = {
317
+ 'animate-fade': 'ํŽ˜์ด๋“œ ์ธ/์•„์›ƒ',
318
+ 'animate-zoom': '์คŒ ์ธ/์•„์›ƒ',
319
+ 'animate-slide': '์Šฌ๋ผ์ด๋“œ',
320
+ 'animate-rotate': 'ํšŒ์ „'
321
  }
322
+
323
+ selected_animation = st.radio(
324
+ "์ „ํ™˜ ํšจ๊ณผ ์„ ํƒ",
325
  options=list(animation_options.keys()),
326
  format_func=lambda x: animation_options[x],
327
+ index=list(animation_options.keys()).index(st.session_state.animation_type) if st.session_state.animation_type in animation_options else 0
328
  )
329
+
330
  if selected_animation != st.session_state.animation_type:
331
  st.session_state.animation_type = selected_animation
332
 
333
  # ์žฌ์ƒ ์„ค์ •
334
  st.subheader("์žฌ์ƒ ์„ค์ •")
 
335
 
336
+ # ์ด๋ฏธ์ง€ ํ‘œ์‹œ ๋ชจ๋“œ ์„ ํƒ
337
+ fit_options = {
338
+ 'cover': 'ํ™”๋ฉด์— ๊ฝ‰ ์ฐจ๊ฒŒ',
339
+ 'contain': '์›๋ณธ ๋น„์œจ ์œ ์ง€'
340
+ }
341
+
342
+ selected_fit = st.radio(
343
  "์ด๋ฏธ์ง€ ํ‘œ์‹œ ๋ฐฉ์‹",
344
  options=list(fit_options.keys()),
345
  format_func=lambda x: fit_options[x],
346
+ index=list(fit_options.keys()).index(st.session_state.fit_mode) if st.session_state.fit_mode in fit_options else 0
347
  )
348
+
349
  if selected_fit != st.session_state.fit_mode:
350
  st.session_state.fit_mode = selected_fit
351
 
352
+ # ์Šฌ๋ผ์ด๋“œ์‡ผ ๊ฐ„๊ฒฉ ์„ค์ •
353
+ preview_interval = st.slider("์ด๋ฏธ์ง€ ์ „ํ™˜ ๊ฐ„๊ฒฉ (์ดˆ)", min_value=1, max_value=60, value=10)
354
+
355
+ # ์Šฌ๋ผ์ด๋“œ์‡ผ ์‹œ์ž‘/์ข…๋ฃŒ ๋ฒ„ํŠผ
356
+ col1, col2 = st.columns(2)
357
+
358
+ with col1:
359
+ if st.button("๐Ÿ–ผ๏ธ ๋ฏธ๋ฆฌ๋ณด๊ธฐ ์‹œ์ž‘", use_container_width=True):
360
+ st.session_state.preview_mode = True
361
+ st.session_state.preview_start_time = time.time()
362
+ st.session_state.activate_fullscreen = False
363
+ st.rerun()
364
+
365
+ with col2:
366
+ if st.button("๐Ÿ” ์ „์ฒดํ™”๋ฉด ๋ณด๊ธฐ", use_container_width=True):
367
+ st.session_state.preview_mode = True
368
+ st.session_state.preview_start_time = time.time()
369
+ st.session_state.activate_fullscreen = True
370
+ st.rerun()
371
+
372
+ # ๋ฏธ๋ฆฌ๋ณด๊ธฐ ๋ชจ๋“œ์ธ ๊ฒฝ์šฐ ์ข…๋ฃŒ ๋ฒ„ํŠผ ํ‘œ์‹œ
373
+ if st.session_state.get('preview_mode', False):
374
+ if st.button("โน๏ธ ๋ฏธ๋ฆฌ๋ณด๊ธฐ ์ข…๋ฃŒ", use_container_width=True):
375
+ st.session_state.preview_mode = False
376
+ st.session_state.activate_fullscreen = False
377
+ st.rerun()
378
 
379
  # ๋ฉ”์ธ ์ปจํ…์ธ  ์˜์—ญ
380
  if st.session_state.get('preview_mode', False):
381
+ # ํ—ˆ๊น…ํŽ˜์ด์Šค UI ์š”์†Œ ์ˆจ๊ธฐ๊ธฐ ์œ„ํ•œ CSS ์ถ”๊ฐ€
382
+ st.markdown("""
383
+ <style>
384
+ /* ํ—ˆ๊น…ํŽ˜์ด์Šค ํ—ค๋” ๋ฐ ๊ด€๋ จ UI ์š”์†Œ ์ˆจ๊ธฐ๊ธฐ */
385
+ div.css-1avcm0n {display: none !important;} /* ์ƒ๋‹จ ํ—ค๋” */
386
+ div.css-14xtw13 {display: none !important;} /* ๊ณต๊ฐ„ */
387
+ section.css-1lcbmhc {display: none !important;} /* ์‚ฌ์ด๋“œ๋ฐ” */
388
+ div.css-1dp5vir {display: none !important;} /* ๊ธฐํƒ€ UI ์š”์†Œ */
389
+ div.e1nzilvr5 {display: none !important;}
390
+ div.viewerBadge_link__1S137 {display: none !important;}
391
+ div.css-1bgch32 {display: none !important;}
392
+
393
+ /* Streamlit ์š”์†Œ ์ˆจ๊ธฐ๊ธฐ */
394
+ #MainMenu {visibility: hidden !important;}
395
+ header {visibility: hidden !important;}
396
+ footer {visibility: hidden !important;}
397
+
398
+ /* iframe ๊ด€๋ จ ์„ค์ • */
399
+ iframe {border: none !important;}
400
+
401
+ /* ์•ฑ ์ปจํ…Œ์ด๋„ˆ ์ „์ฒด ํ™”๋ฉด ์„ค์ • */
402
+ .main .block-container {
403
+ padding: 0 !important;
404
+ max-width: 100% !important;
405
+ }
406
+ .stApp {
407
+ margin: 0 !important;
408
+ padding: 0 !important;
409
+ height: 100vh !important;
410
+ width: 100vw !important;
411
+ overflow: hidden !important;
412
+ }
413
+
414
+ /* ์ „์ฒด ํ™”๋ฉด ์„ค์ • ๊ฐ•ํ™” */
415
+ body {
416
+ margin: 0 !important;
417
+ padding: 0 !important;
418
+ overflow: hidden !important;
419
+ }
420
+
421
+ /* ๋ฐฐ๊ฒฝ ์ด๋ฏธ์ง€ ์ปจํ…Œ์ด๋„ˆ ์ˆ˜์ • */
422
+ .full-view {
423
+ position: fixed !important;
424
+ top: 0 !important;
425
+ left: 0 !important;
426
+ width: 100vw !important;
427
+ height: 100vh !important;
428
+ z-index: 9999 !important;
429
+ }
430
+ </style>
431
+ """, unsafe_allow_html=True)
432
+
433
  # ์ž๋™ ์ƒˆ๋กœ๊ณ ์นจ์„ ์œ„ํ•œ ์นด์šดํ„ฐ
434
  count = st_autorefresh(interval=preview_interval * 1000, key="refreshInterval")
435
 
436
  # ๋ฐฐ๊ฒฝ ์ด๋ฏธ์ง€ ์ „ํ™˜ JS ์‚ฝ์ž… (๋จผ์ € ์‹คํ–‰๋˜์–ด์•ผ ํ•จ)
437
  inject_background_toggle_js()
438
 
439
+ # ์ „์ฒดํ™”๋ฉด ํ™œ์„ฑํ™” ํ•„์š”์‹œ ์‹คํ–‰
440
+ if st.session_state.activate_fullscreen:
441
+ inject_fullscreen_js()
442
+
443
  # ํ˜„์žฌ ์ธ๋ฑ์Šค ์—…๋ฐ์ดํŠธ
444
  if count > 0 and st.session_state.contents:
445
+ # ์ด๋ฏธ์ง€ ๊ณ ์ • ๋ชจ๋“œ๊ฐ€ ํ™œ์„ฑํ™”๋˜์ง€ ์•Š์€ ๊ฒฝ์šฐ์—๋งŒ ์ด๋ฏธ์ง€ ๋ณ€๊ฒฝ
446
+ if not st.session_state.fixed_image_enabled:
447
+ st.session_state.current_image_index = (st.session_state.current_image_index + 1) % len(st.session_state.contents)
448
 
449
  # ํ™”๋ฉด์— ๋ฐฐ๊ฒฝ ์ด๋ฏธ์ง€๋กœ ํ‘œ์‹œ
450
  if st.session_state.contents:
451
+ # ์ด๋ฏธ์ง€ ๊ณ ์ • ๋ชจ๋“œ๊ฐ€ ํ™œ์„ฑํ™”๋œ ๊ฒฝ์šฐ ๊ณ ์ • ์ด๋ฏธ์ง€ ์‚ฌ์šฉ, ์•„๋‹ˆ๋ฉด ํ˜„์žฌ ์ธ๋ฑ์Šค ์ด๋ฏธ์ง€ ์‚ฌ์šฉ
452
+ if st.session_state.fixed_image_enabled and st.session_state.fixed_image_path:
453
+ full_img_path = st.session_state.fixed_image_path
454
+ else:
455
+ full_img_path = st.session_state.contents[st.session_state.current_image_index]
456
 
457
  # ์›น์—์„œ ์ ‘๊ทผ ๊ฐ€๋Šฅํ•œ ์ด๋ฏธ์ง€ URL๋กœ ๋ณ€ํ™˜ (Base64 ์ธ์ฝ”๋”ฉ ์‚ฌ์šฉ)
458
  with open(full_img_path, "rb") as img_file:
 
461
  # ์ด๋ฏธ์ง€ ํ™•์žฅ์ž ๊ฐ€์ ธ์˜ค๊ธฐ (๊ธฐ๋ณธ๊ฐ’์€ jpeg)
462
  file_ext = os.path.splitext(full_img_path)[1][1:] or "jpeg"
463
 
464
+ # ๋ฐฐ๊ฒฝ ์ด๋ฏธ์ง€ ์„ค์ •๊ณผ ์ปจํŠธ๋กค ๋ฒ„ํŠผ์ด ํฌํ•จ๋œ HTML ์ƒ์„ฑ
465
  background_html = f"""
466
  <div class="full-view animate-{st.session_state.animation_type}"
467
  style="background-image: url('data:image/{file_ext};base64,{img_data}');
 
496
  window.applyBackgroundAnimation('animate-{st.session_state.animation_type}');
497
  }}
498
  }}, 1500);
499
+
500
+ // ํ—ˆ๊น…ํŽ˜์ด์Šค ์š”์†Œ ์ˆจ๊ธฐ๊ธฐ ๊ฐ•ํ™”
501
+ function hideHuggingfaceElements() {{
502
+ const huggingfaceElements = document.querySelectorAll('.css-1avcm0n, .css-14xtw13, .css-1lcbmhc, .css-1dp5vir, .e1nzilvr5, .viewerBadge_link__1S137, .css-1bgch32');
503
+ huggingfaceElements.forEach(el => {{
504
+ if(el) el.style.display = 'none';
505
+ }});
506
+ }}
507
+
508
+ // ์—ฌ๋Ÿฌ ๋ฒˆ ์‹œ๋„ํ•˜์—ฌ UI ์š”์†Œ ์ˆจ๊ธฐ๊ธฐ
509
+ setTimeout(hideHuggingfaceElements, 1000);
510
+ setTimeout(hideHuggingfaceElements, 2000);
511
+ setTimeout(hideHuggingfaceElements, 5000);
512
  </script>
513
  """
514
+
515
 
516
  # HTML ์ง์ ‘ ์‚ฝ์ž…
517
  st.markdown(background_html, unsafe_allow_html=True)
 
524
  footer {visibility: hidden;}
525
  </style>
526
  """, unsafe_allow_html=True)
 
 
 
 
 
 
 
 
527
  else:
528
+ # ์ผ๋ฐ˜ ๋ชจ๋“œ - ์•ฑ ์†Œ๊ฐœ ๋ฐ ์‚ฌ์šฉ๋ฒ•
529
+ st.title("๐Ÿ–ผ๏ธ ๋””์ง€ํ„ธ ๋””์Šคํ”Œ๋ ˆ์ด ์ปจํ…์ธ  ๊ด€๋ฆฌ")
530
 
531
  if not st.session_state.contents:
532
+ st.warning("โš ๏ธ ๋“ฑ๋ก๋œ ์ด๋ฏธ์ง€๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ์‚ฌ์ด๋“œ๋ฐ”์—์„œ ์ด๋ฏธ์ง€๋ฅผ ์ถ”๊ฐ€ํ•ด์ฃผ์„ธ์š”.")
533
  else:
534
+ st.success(f"โœ… {len(st.session_state.contents)}๊ฐœ์˜ ์ด๋ฏธ์ง€๊ฐ€ ๋“ฑ๋ก๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.")
535
+
536
+ st.markdown("""
537
+ ### ์‚ฌ์šฉ ๋ฐฉ๋ฒ•
538
+ 1. ์™ผ์ชฝ ์‚ฌ์ด๋“œ๋ฐ”์—์„œ ์ด๋ฏธ์ง€๋ฅผ ์ถ”๊ฐ€ํ•˜์„ธ์š”.
539
+ 2. ์ด๋ฏธ์ง€ ์ˆœ์„œ๋ฅผ ์กฐ์ •ํ•˜๊ณ  ์ „ํ™˜ ํšจ๊ณผ๋ฅผ ์„ ํƒํ•˜์„ธ์š”.
540
+ 3. ์žฌ์ƒ ์„ค์ •์—์„œ ์ด๋ฏธ์ง€ ํ‘œ์‹œ ๋ฐฉ์‹๊ณผ ์ „ํ™˜ ๊ฐ„๊ฒฉ์„ ์„ค์ •ํ•˜์„ธ์š”.
541
+ 4. ๋ฏธ๋ฆฌ๋ณด๊ธฐ ์‹œ์ž‘ ๋˜๋Š” ์ „์ฒดํ™”๋ฉด ๋ณด๊ธฐ ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜์—ฌ ์Šฌ๋ผ์ด๋“œ์‡ผ๋ฅผ ์‹œ์ž‘ํ•˜์„ธ์š”.
542
+
543
+ ### ๊ธฐ๋Šฅ ์†Œ๊ฐœ
544
+ - **์ด๋ฏธ์ง€ ์ˆœ์„œ ์กฐ์ •**: ๐Ÿ‘†๐Ÿ‘‡ ๋ฒ„ํŠผ์œผ๋กœ ์ด๋ฏธ์ง€ ์ˆœ์„œ๋ฅผ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
545
+ - **์ด๋ฏธ์ง€ ๊ณ ์ •**: ํŠน์ • ์ด๋ฏธ์ง€ ํ•˜๋‚˜๋งŒ ๊ณ„์† ํ‘œ์‹œํ•˜๋„๋ก ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
546
+ - **์ „ํ™˜ ํšจ๊ณผ**: ํŽ˜์ด๋“œ, ์คŒ, ์Šฌ๋ผ์ด๋“œ, ํšŒ์ „ ํšจ๊ณผ๋ฅผ ์„ ํƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
547
+ - **ํ‘œ์‹œ ๋ฐฉ์‹**: ํ™”๋ฉด์— ๊ฝ‰ ์ฐจ๊ฒŒ ๋˜๋Š” ์›๋ณธ ๋น„์œจ์„ ์œ ์ง€ํ•˜๋ฉฐ ํ‘œ์‹œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
548
+ - **์ž๋™ ์ „ํ™˜**: ์„ค์ •ํ•œ ๊ฐ„๊ฒฉ์œผ๋กœ ์ด๋ฏธ์ง€๊ฐ€ ์ž๋™ ์ „ํ™˜๋ฉ๋‹ˆ๋‹ค.
549
+
550
+ ### ์ด๋ฏธ์ง€ ๋ฏธ๋ฆฌ๋ณด๊ธฐ
551
+ """)
552
+
553
+ # ์ด๋ฏธ์ง€ ๊ทธ๋ฆฌ๋“œ๋กœ ํ‘œ์‹œ
554
+ if st.session_state.contents:
555
  cols = st.columns(4)
556
  for i, img_path in enumerate(st.session_state.contents):
557
+ with cols[i % 4]:
558
+ st.image(img_path, caption=os.path.basename(img_path), use_column_width=True)
 
 
559