seawolf2357 commited on
Commit
5fa2101
Β·
verified Β·
1 Parent(s): 7fd946e

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +572 -102
app.py CHANGED
@@ -15,7 +15,7 @@ def create_border_decoration(qr_image, decoration_style="Flowers"):
15
  width, height = qr_image.size
16
 
17
  # νŒ¨λ”©μ„ 더 μž‘κ²Œ μ‘°μ •
18
- padding = 20 # νŒ¨λ”©μ„ 30μ—μ„œ 20으둜 μ€„μž„
19
  new_width = width + (padding * 2)
20
  new_height = height + (padding * 2)
21
 
@@ -28,9 +28,9 @@ def create_border_decoration(qr_image, decoration_style="Flowers"):
28
  # Get draw object
29
  draw = ImageDraw.Draw(decorated_image)
30
 
31
- # μž₯식 크기 μ„€μ • - 간격을 더 쒁게
32
- deco_size = 8 # μž₯식 크기λ₯Ό 12μ—μ„œ 8둜 μ€„μž„
33
- gap = deco_size * 1.5 # 간격을 2λ°°μ—μ„œ 1.5배둜 μ€„μž„
34
 
35
  # ν…Œλ‘λ¦¬λ₯Ό 따라 μ λ“€μ˜ μœ„μΉ˜ 계산
36
  border_points = []
@@ -53,85 +53,75 @@ def create_border_decoration(qr_image, decoration_style="Flowers"):
53
 
54
  # 각 μŠ€νƒ€μΌμ— λ”°λ₯Έ μž₯식 그리기
55
  for x, y in border_points:
56
- if decoration_style == "Flowers": # 꽃 νŒ¨ν„΄
57
- # κ½ƒμžŽ
58
  for angle in range(0, 360, 45):
59
  x1 = x + deco_size * cos(radians(angle))
60
  y1 = y + deco_size * sin(radians(angle))
61
  draw.ellipse([x1-4, y1-4, x1+4, y1+4], fill='pink')
62
- # 꽃 쀑심
63
  draw.ellipse([x-3, y-3, x+3, y+3], fill='yellow')
64
 
65
- elif decoration_style == "Hearts": # ν•˜νŠΈ νŒ¨ν„΄
66
- # μž‘μ€ ν•˜νŠΈλ“€μ„ μ—°μ†μœΌλ‘œ 그리기
67
  heart_size = 6
68
  draw.ellipse([x-heart_size, y-heart_size, x, y], fill='red')
69
  draw.ellipse([x, y-heart_size, x+heart_size, y], fill='red')
70
  draw.polygon([(x-heart_size, y), (x+heart_size, y), (x, y+heart_size)], fill='red')
71
 
72
- elif decoration_style == "Waves": # μ›¨μ΄λΈŒ νŒ¨ν„΄
73
  wave_size = 10
74
  draw.arc([x-wave_size, y-wave_size//2, x+wave_size, y+wave_size//2],
75
  0, 180, fill='lightblue', width=2)
76
  draw.arc([x-wave_size, y, x+wave_size, y+wave_size],
77
  0, 180, fill='blue', width=2)
78
 
79
- elif decoration_style == "Leaves": # 잎 νŒ¨ν„΄
80
  leaf_size = 8
81
- # 메인 잎
82
  draw.ellipse([x-leaf_size, y-leaf_size//2, x+leaf_size, y+leaf_size//2],
83
  fill='lightgreen')
84
- # μž‘μ€ 잎
85
  draw.ellipse([x-leaf_size//2, y-leaf_size, x+leaf_size//2, y+leaf_size],
86
  fill='darkgreen')
87
 
88
- elif decoration_style == "Stars": # 별 νŒ¨ν„΄
89
  star_size = 6
90
  points = []
91
  for i in range(5):
92
  angle = i * 72
93
- # μ™Έκ³½ 점
94
  x1 = x + star_size * cos(radians(angle))
95
  y1 = y + star_size * sin(radians(angle))
96
  points.append((x1, y1))
97
- # λ‚΄λΆ€ 점
98
  x2 = x + (star_size/2) * cos(radians(angle + 36))
99
  y2 = y + (star_size/2) * sin(radians(angle + 36))
100
  points.append((x2, y2))
101
  draw.polygon(points, fill='gold')
102
 
103
- elif decoration_style == "Chains": # 체인 νŒ¨ν„΄
104
  chain_size = 8
105
  draw.ellipse([x-chain_size, y-chain_size//2, x+chain_size, y+chain_size//2],
106
  outline='gray', width=2)
107
 
108
- elif decoration_style == "Bubbles": # 버블 νŒ¨ν„΄
109
  bubble_sizes = [6, 4, 2]
110
  for size in bubble_sizes:
111
  draw.ellipse([x-size, y-size, x+size, y+size],
112
  outline='skyblue', width=1)
113
 
114
- elif decoration_style == "Vines": # 덩꡴ νŒ¨ν„΄
115
  vine_size = 10
116
- # 메인 덩꡴
117
  draw.arc([x-vine_size, y-vine_size, x+vine_size, y+vine_size],
118
  0, 180, fill='green', width=2)
119
- # μž‘μ€ 잎
120
  draw.ellipse([x-3, y-3, x+3, y+3], fill='lightgreen')
121
 
122
- elif decoration_style == "Diamonds": # 닀이아λͺ¬λ“œ νŒ¨ν„΄
123
  diamond_size = 6
124
  points = [
125
- (x, y-diamond_size), # 상단
126
- (x+diamond_size, y), # 우츑
127
- (x, y+diamond_size), # ν•˜λ‹¨
128
- (x-diamond_size, y) # 쒌츑
129
  ]
130
  draw.polygon(points, outline='purple', width=1)
131
 
132
- elif decoration_style == "Lace": # 레이슀 νŒ¨ν„΄
133
  lace_size = 8
134
- # 레이슀 μ›ν˜• νŒ¨ν„΄
135
  draw.arc([x-lace_size, y-lace_size, x+lace_size, y+lace_size],
136
  0, 180, fill='gray', width=1)
137
  draw.arc([x-lace_size//2, y-lace_size//2, x+lace_size//2, y+lace_size//2],
@@ -142,7 +132,6 @@ def create_border_decoration(qr_image, decoration_style="Flowers"):
142
  def rgba_to_rgb(rgba_color):
143
  """Convert RGBA color string to RGB hex color"""
144
  if rgba_color.startswith('rgba'):
145
- # Extract numbers from rgba string
146
  values = rgba_color.strip('rgba()').split(',')
147
  r = int(float(values[0]))
148
  g = int(float(values[1]))
@@ -180,7 +169,7 @@ def create_qr(content, qr_type, fill_color, back_color, box_size, border_size, e
180
  # QR 이미지 생성
181
  qr_img = qr.make_image(fill_color=fill_color, back_color=back_color)
182
 
183
- # Add border decoration if specified and not "No Decoration"
184
  if border_decoration != "No Decoration":
185
  qr_img = create_border_decoration(qr_img, border_decoration)
186
 
@@ -189,16 +178,32 @@ def create_qr(content, qr_type, fill_color, back_color, box_size, border_size, e
189
  random_id = random.randint(1000, 9999)
190
  filename = f"qrfile/qr_{timestamp}_{random_id}.png"
191
 
192
- # 디렉토리 확인 및 생성
193
  os.makedirs("qrfile", exist_ok=True)
194
-
195
- # 이미지 μ €μž₯
196
  qr_img.save(filename)
197
  cleanup_old_files("qrfile/", max_files=100)
198
 
199
- return filename, formatted_data
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
200
 
201
- # 데이터 ν¬λ§·νŒ… ν•¨μˆ˜
202
  def format_data(content, qr_type):
203
  if not content:
204
  return ""
@@ -217,7 +222,6 @@ def format_data(content, qr_type):
217
 
218
  return format_rules[qr_type](content.strip())
219
 
220
- # 파일 정리 ν•¨μˆ˜
221
  def cleanup_old_files(directory, max_files):
222
  files = [f for f in os.listdir(directory) if f.endswith('.png')]
223
  if len(files) > max_files:
@@ -238,83 +242,514 @@ def format_example_text(qr_type):
238
  "Location": "β€’ Coordinates: 37.7749,-122.4194\nβ€’ With zoom: 37.7749,-122.4194,15z",
239
  "Wi-Fi": "β€’ Network name only: MyWiFiNetwork\nβ€’ With password: WIFI:S:MyNetwork;P:password;;",
240
  "Text": "β€’ Simple text: Hello World!\nβ€’ Multiple lines: Line 1\\nLine 2",
241
- "vCard": "β€’ Basic:\nFN:John Doe\nTEL:+1234567890\nEMAIL:john@example.com\nβ€’ Extended:\nFN:John Doe\nTEL:+1234567890\nEMAIL:john@example.com\nADR:;;123 Street;City;State;12345;Country"
242
  }
243
  return examples.get(qr_type, "Enter your content here...")
244
 
245
 
246
- def create_interface():
247
- theme = gr.themes.Soft(
248
- primary_hue="blue",
249
- secondary_hue="indigo",
250
- ).set(
251
- body_background_fill="*neutral_50",
252
- block_background_fill="*neutral_100",
253
- button_primary_background_fill="*primary_500",
254
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
255
 
256
- with gr.Blocks(theme=theme, title="QR Canvas") as demo:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
257
 
258
-
 
 
 
 
 
 
 
 
 
 
 
 
 
259
  gr.Markdown(
260
  """
261
- # 🎯 QR CANVAS+
262
- Create customized QR codes for various purposes with professional styling options.
263
- """
264
  )
265
 
266
- gr.HTML("""<a href="https://visitorbadge.io/status?path=https%3A%2F%2Fginipick-QR-Canvas.hf.space">
267
- <img src="https://api.visitorbadge.io/api/visitors?path=https%3A%2F%2Fginipick-QR-Canvas.hf.space&countColor=%23263759" />
268
- </a>""")
 
 
269
 
270
- with gr.Row():
271
- with gr.Column(scale=2):
 
272
  qr_type = gr.Dropdown(
273
  choices=["URL", "Email", "Phone", "SMS", "WhatsApp", "Location", "Wi-Fi", "Text", "vCard"],
274
  value="URL",
275
- label="QR Code Type"
276
  )
277
 
278
  content = gr.Textbox(
279
- label="Content",
280
  placeholder="Enter your content here...",
281
  lines=3
282
  )
283
 
284
  example_format = gr.Textbox(
285
  value=format_example_text("URL"),
286
- label="Format Examples",
287
  interactive=False,
288
- lines=6
 
289
  )
290
 
291
- with gr.Row():
292
  fill_color = gr.ColorPicker(
293
- label="QR Code Color",
294
  value="#000000"
295
  )
296
  back_color = gr.ColorPicker(
297
- label="Background Color",
298
  value="#FFFFFF"
299
  )
300
-
301
-
302
-
303
 
304
  with gr.Row():
305
  box_size = gr.Slider(
306
  minimum=1,
307
- maximum=30, # μ΅œλŒ€κ°’μ„ 20μ—μ„œ 30으둜 증가
308
- value=15, # 기본값을 10μ—μ„œ 15둜 증가
309
  step=1,
310
- label="QR Code Size"
311
  )
312
  border_size = gr.Slider(
313
  minimum=0,
314
- maximum=5, # μ΅œλŒ€κ°’μ„ 10μ—μ„œ 5둜 κ°μ†Œ
315
- value=2, # 기본값을 4μ—μ„œ 2둜 κ°μ†Œ
316
  step=1,
317
- label="Border Size"
318
  )
319
 
320
  error_correction = gr.Dropdown(
@@ -325,12 +760,12 @@ def create_interface():
325
  "High (30%)"
326
  ],
327
  value="Medium (15%)",
328
- label="Error Correction Level"
329
  )
330
 
331
  border_decoration = gr.Dropdown(
332
  choices=[
333
- "No Decoration", # λͺ…μ‹œμ μΈ "μž₯식 μ—†μŒ" μ˜΅μ…˜
334
  "Flowers",
335
  "Hearts",
336
  "Waves",
@@ -342,27 +777,77 @@ def create_interface():
342
  "Diamonds",
343
  "Lace"
344
  ],
345
- value="No Decoration", # κΈ°λ³Έκ°’μœΌλ‘œ "No Decoration" μ„€μ •
346
- label="Border Decoration Style"
347
  )
348
 
349
-
350
-
351
  generate_btn = gr.Button(
352
- "Generate QR Code",
353
- variant="primary"
 
 
354
  )
 
 
 
 
 
 
 
 
 
 
355
 
356
- with gr.Column(scale=1):
 
357
  output_image = gr.Image(
358
- label="Generated QR Code",
359
- type="filepath"
 
 
360
  )
 
361
  output_data = gr.Textbox(
362
- label="Formatted Data",
363
- interactive=False
 
 
 
 
 
 
 
 
 
364
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
365
 
 
366
  def update_example(qr_type):
367
  return format_example_text(qr_type)
368
 
@@ -384,27 +869,12 @@ def create_interface():
384
  error_correction,
385
  border_decoration
386
  ],
387
- outputs=[output_image, output_data]
388
- )
389
-
390
- gr.Markdown(
391
- """
392
- ### πŸ“ Instructions
393
- 1. Select the QR code type from the dropdown menu
394
- 2. Enter your content following the format examples shown
395
- 3. Customize the appearance using the color pickers and sliders
396
- 4. Click 'Generate QR Code' to create your custom QR code
397
-
398
- ### πŸ’‘ Tips
399
- - Use higher error correction levels for better scan reliability
400
- - Ensure sufficient contrast between QR code and background colors
401
- - Keep the content concise for better readability
402
- - Follow the format examples for best results
403
- """
404
  )
405
 
406
  return demo
407
 
 
408
  if __name__ == "__main__":
409
  try:
410
  os.makedirs("qrfile", exist_ok=True)
 
15
  width, height = qr_image.size
16
 
17
  # νŒ¨λ”©μ„ 더 μž‘κ²Œ μ‘°μ •
18
+ padding = 20
19
  new_width = width + (padding * 2)
20
  new_height = height + (padding * 2)
21
 
 
28
  # Get draw object
29
  draw = ImageDraw.Draw(decorated_image)
30
 
31
+ # μž₯식 크기 μ„€μ •
32
+ deco_size = 8
33
+ gap = deco_size * 1.5
34
 
35
  # ν…Œλ‘λ¦¬λ₯Ό 따라 μ λ“€μ˜ μœ„μΉ˜ 계산
36
  border_points = []
 
53
 
54
  # 각 μŠ€νƒ€μΌμ— λ”°λ₯Έ μž₯식 그리기
55
  for x, y in border_points:
56
+ if decoration_style == "Flowers":
 
57
  for angle in range(0, 360, 45):
58
  x1 = x + deco_size * cos(radians(angle))
59
  y1 = y + deco_size * sin(radians(angle))
60
  draw.ellipse([x1-4, y1-4, x1+4, y1+4], fill='pink')
 
61
  draw.ellipse([x-3, y-3, x+3, y+3], fill='yellow')
62
 
63
+ elif decoration_style == "Hearts":
 
64
  heart_size = 6
65
  draw.ellipse([x-heart_size, y-heart_size, x, y], fill='red')
66
  draw.ellipse([x, y-heart_size, x+heart_size, y], fill='red')
67
  draw.polygon([(x-heart_size, y), (x+heart_size, y), (x, y+heart_size)], fill='red')
68
 
69
+ elif decoration_style == "Waves":
70
  wave_size = 10
71
  draw.arc([x-wave_size, y-wave_size//2, x+wave_size, y+wave_size//2],
72
  0, 180, fill='lightblue', width=2)
73
  draw.arc([x-wave_size, y, x+wave_size, y+wave_size],
74
  0, 180, fill='blue', width=2)
75
 
76
+ elif decoration_style == "Leaves":
77
  leaf_size = 8
 
78
  draw.ellipse([x-leaf_size, y-leaf_size//2, x+leaf_size, y+leaf_size//2],
79
  fill='lightgreen')
 
80
  draw.ellipse([x-leaf_size//2, y-leaf_size, x+leaf_size//2, y+leaf_size],
81
  fill='darkgreen')
82
 
83
+ elif decoration_style == "Stars":
84
  star_size = 6
85
  points = []
86
  for i in range(5):
87
  angle = i * 72
 
88
  x1 = x + star_size * cos(radians(angle))
89
  y1 = y + star_size * sin(radians(angle))
90
  points.append((x1, y1))
 
91
  x2 = x + (star_size/2) * cos(radians(angle + 36))
92
  y2 = y + (star_size/2) * sin(radians(angle + 36))
93
  points.append((x2, y2))
94
  draw.polygon(points, fill='gold')
95
 
96
+ elif decoration_style == "Chains":
97
  chain_size = 8
98
  draw.ellipse([x-chain_size, y-chain_size//2, x+chain_size, y+chain_size//2],
99
  outline='gray', width=2)
100
 
101
+ elif decoration_style == "Bubbles":
102
  bubble_sizes = [6, 4, 2]
103
  for size in bubble_sizes:
104
  draw.ellipse([x-size, y-size, x+size, y+size],
105
  outline='skyblue', width=1)
106
 
107
+ elif decoration_style == "Vines":
108
  vine_size = 10
 
109
  draw.arc([x-vine_size, y-vine_size, x+vine_size, y+vine_size],
110
  0, 180, fill='green', width=2)
 
111
  draw.ellipse([x-3, y-3, x+3, y+3], fill='lightgreen')
112
 
113
+ elif decoration_style == "Diamonds":
114
  diamond_size = 6
115
  points = [
116
+ (x, y-diamond_size),
117
+ (x+diamond_size, y),
118
+ (x, y+diamond_size),
119
+ (x-diamond_size, y)
120
  ]
121
  draw.polygon(points, outline='purple', width=1)
122
 
123
+ elif decoration_style == "Lace":
124
  lace_size = 8
 
125
  draw.arc([x-lace_size, y-lace_size, x+lace_size, y+lace_size],
126
  0, 180, fill='gray', width=1)
127
  draw.arc([x-lace_size//2, y-lace_size//2, x+lace_size//2, y+lace_size//2],
 
132
  def rgba_to_rgb(rgba_color):
133
  """Convert RGBA color string to RGB hex color"""
134
  if rgba_color.startswith('rgba'):
 
135
  values = rgba_color.strip('rgba()').split(',')
136
  r = int(float(values[0]))
137
  g = int(float(values[1]))
 
169
  # QR 이미지 생성
170
  qr_img = qr.make_image(fill_color=fill_color, back_color=back_color)
171
 
172
+ # Add border decoration if specified
173
  if border_decoration != "No Decoration":
174
  qr_img = create_border_decoration(qr_img, border_decoration)
175
 
 
178
  random_id = random.randint(1000, 9999)
179
  filename = f"qrfile/qr_{timestamp}_{random_id}.png"
180
 
 
181
  os.makedirs("qrfile", exist_ok=True)
 
 
182
  qr_img.save(filename)
183
  cleanup_old_files("qrfile/", max_files=100)
184
 
185
+ # 정보 둜그 생성
186
+ info_log = f"""βœ… QR CODE GENERATED!
187
+ {'=' * 50}
188
+ πŸ“‹ QR Code Info:
189
+ β€’ Type: {qr_type}
190
+ β€’ Content: {content[:40]}{'...' if len(content) > 40 else ''}
191
+ {'=' * 50}
192
+ 🎨 Style Settings:
193
+ β€’ QR Color: {fill_color}
194
+ β€’ Background: {back_color}
195
+ β€’ Size: {box_size}
196
+ β€’ Border: {border_size}
197
+ β€’ Decoration: {border_decoration}
198
+ {'=' * 50}
199
+ πŸ”§ Technical:
200
+ β€’ Error Correction: {error_correction}
201
+ β€’ Formatted Data: {formatted_data[:50]}{'...' if len(formatted_data) > 50 else ''}
202
+ {'=' * 50}
203
+ πŸ’Ύ Ready to download!"""
204
+
205
+ return filename, formatted_data, info_log
206
 
 
207
  def format_data(content, qr_type):
208
  if not content:
209
  return ""
 
222
 
223
  return format_rules[qr_type](content.strip())
224
 
 
225
  def cleanup_old_files(directory, max_files):
226
  files = [f for f in os.listdir(directory) if f.endswith('.png')]
227
  if len(files) > max_files:
 
242
  "Location": "β€’ Coordinates: 37.7749,-122.4194\nβ€’ With zoom: 37.7749,-122.4194,15z",
243
  "Wi-Fi": "β€’ Network name only: MyWiFiNetwork\nβ€’ With password: WIFI:S:MyNetwork;P:password;;",
244
  "Text": "β€’ Simple text: Hello World!\nβ€’ Multiple lines: Line 1\\nLine 2",
245
+ "vCard": "β€’ Basic:\nFN:John Doe\nTEL:+1234567890\nEMAIL:john@example.com"
246
  }
247
  return examples.get(qr_type, "Enter your content here...")
248
 
249
 
250
+ # ============================================
251
+ # 🎨 Comic Classic Theme - Toon Playground
252
+ # ============================================
253
+
254
+ css = """
255
+ /* ===== 🎨 Google Fonts Import ===== */
256
+ @import url('https://fonts.googleapis.com/css2?family=Bangers&family=Comic+Neue:wght@400;700&display=swap');
257
+
258
+ /* ===== 🎨 Comic Classic λ°°κ²½ - λΉˆν‹°μ§€ 페이퍼 + λ„νŠΈ νŒ¨ν„΄ ===== */
259
+ .gradio-container {
260
+ background-color: #FEF9C3 !important;
261
+ background-image:
262
+ radial-gradient(#1F2937 1px, transparent 1px) !important;
263
+ background-size: 20px 20px !important;
264
+ min-height: 100vh !important;
265
+ font-family: 'Comic Neue', cursive, sans-serif !important;
266
+ }
267
+
268
+ /* ===== ν—ˆκΉ…νŽ˜μ΄μŠ€ 상단 μš”μ†Œ μˆ¨κΉ€ ===== */
269
+ .huggingface-space-header,
270
+ #space-header,
271
+ .space-header,
272
+ [class*="space-header"],
273
+ .svelte-1ed2p3z,
274
+ .space-header-badge,
275
+ .header-badge,
276
+ [data-testid="space-header"],
277
+ .svelte-kqij2n,
278
+ .svelte-1ax1toq,
279
+ .embed-container > div:first-child {
280
+ display: none !important;
281
+ visibility: hidden !important;
282
+ height: 0 !important;
283
+ width: 0 !important;
284
+ overflow: hidden !important;
285
+ opacity: 0 !important;
286
+ pointer-events: none !important;
287
+ }
288
+
289
+ /* ===== Footer μ™„μ „ μˆ¨κΉ€ ===== */
290
+ footer,
291
+ .footer,
292
+ .gradio-container footer,
293
+ .built-with,
294
+ [class*="footer"],
295
+ .gradio-footer,
296
+ .main-footer,
297
+ div[class*="footer"],
298
+ .show-api,
299
+ .built-with-gradio,
300
+ a[href*="gradio.app"],
301
+ a[href*="huggingface.co/spaces"] {
302
+ display: none !important;
303
+ visibility: hidden !important;
304
+ height: 0 !important;
305
+ padding: 0 !important;
306
+ margin: 0 !important;
307
+ }
308
+
309
+ /* ===== 메인 μ»¨ν…Œμ΄λ„ˆ ===== */
310
+ #col-container {
311
+ max-width: 1200px;
312
+ margin: 0 auto;
313
+ }
314
+
315
+ /* ===== 🎨 헀더 타이틀 - μ½”λ―Ή μŠ€νƒ€μΌ ===== */
316
+ .header-text h1 {
317
+ font-family: 'Bangers', cursive !important;
318
+ color: #1F2937 !important;
319
+ font-size: 3.5rem !important;
320
+ font-weight: 400 !important;
321
+ text-align: center !important;
322
+ margin-bottom: 0.5rem !important;
323
+ text-shadow:
324
+ 4px 4px 0px #FACC15,
325
+ 6px 6px 0px #1F2937 !important;
326
+ letter-spacing: 3px !important;
327
+ -webkit-text-stroke: 2px #1F2937 !important;
328
+ }
329
+
330
+ /* ===== 🎨 μ„œλΈŒνƒ€μ΄ν‹€ ===== */
331
+ .subtitle {
332
+ text-align: center !important;
333
+ font-family: 'Comic Neue', cursive !important;
334
+ font-size: 1.2rem !important;
335
+ color: #1F2937 !important;
336
+ margin-bottom: 1.5rem !important;
337
+ font-weight: 700 !important;
338
+ }
339
+
340
+ /* ===== 🎨 μΉ΄λ“œ/νŒ¨λ„ - λ§Œν™” ν”„λ ˆμž„ μŠ€νƒ€μΌ ===== */
341
+ .gr-panel,
342
+ .gr-box,
343
+ .gr-form,
344
+ .block,
345
+ .gr-group {
346
+ background: #FFFFFF !important;
347
+ border: 3px solid #1F2937 !important;
348
+ border-radius: 8px !important;
349
+ box-shadow: 6px 6px 0px #1F2937 !important;
350
+ transition: all 0.2s ease !important;
351
+ }
352
+
353
+ .gr-panel:hover,
354
+ .block:hover {
355
+ transform: translate(-2px, -2px) !important;
356
+ box-shadow: 8px 8px 0px #1F2937 !important;
357
+ }
358
+
359
+ /* ===== 🎨 μž…λ ₯ ν•„λ“œ (Textbox) ===== */
360
+ textarea,
361
+ input[type="text"],
362
+ input[type="number"] {
363
+ background: #FFFFFF !important;
364
+ border: 3px solid #1F2937 !important;
365
+ border-radius: 8px !important;
366
+ color: #1F2937 !important;
367
+ font-family: 'Comic Neue', cursive !important;
368
+ font-size: 1rem !important;
369
+ font-weight: 700 !important;
370
+ transition: all 0.2s ease !important;
371
+ }
372
+
373
+ textarea:focus,
374
+ input[type="text"]:focus,
375
+ input[type="number"]:focus {
376
+ border-color: #3B82F6 !important;
377
+ box-shadow: 4px 4px 0px #3B82F6 !important;
378
+ outline: none !important;
379
+ }
380
+
381
+ textarea::placeholder {
382
+ color: #9CA3AF !important;
383
+ font-weight: 400 !important;
384
+ }
385
+
386
+ /* ===== 🎨 λ“œλ‘­λ‹€μš΄ μŠ€νƒ€μΌ ===== */
387
+ select,
388
+ .gr-dropdown,
389
+ .gr-dropdown select {
390
+ background: #FFFFFF !important;
391
+ border: 3px solid #1F2937 !important;
392
+ border-radius: 8px !important;
393
+ color: #1F2937 !important;
394
+ font-family: 'Comic Neue', cursive !important;
395
+ font-weight: 700 !important;
396
+ padding: 8px 12px !important;
397
+ box-shadow: 3px 3px 0px #1F2937 !important;
398
+ transition: all 0.2s ease !important;
399
+ }
400
+
401
+ select:focus,
402
+ .gr-dropdown:focus {
403
+ border-color: #3B82F6 !important;
404
+ box-shadow: 4px 4px 0px #3B82F6 !important;
405
+ }
406
+
407
+ /* ===== 🎨 Primary λ²„νŠΌ - μ½”λ―Ή 블루 ===== */
408
+ .gr-button-primary,
409
+ button.primary,
410
+ .gr-button.primary,
411
+ .generate-btn {
412
+ background: #3B82F6 !important;
413
+ border: 3px solid #1F2937 !important;
414
+ border-radius: 8px !important;
415
+ color: #FFFFFF !important;
416
+ font-family: 'Bangers', cursive !important;
417
+ font-weight: 400 !important;
418
+ font-size: 1.3rem !important;
419
+ letter-spacing: 2px !important;
420
+ padding: 14px 28px !important;
421
+ box-shadow: 5px 5px 0px #1F2937 !important;
422
+ transition: all 0.1s ease !important;
423
+ text-shadow: 1px 1px 0px #1F2937 !important;
424
+ }
425
+
426
+ .gr-button-primary:hover,
427
+ button.primary:hover,
428
+ .gr-button.primary:hover,
429
+ .generate-btn:hover {
430
+ background: #2563EB !important;
431
+ transform: translate(-2px, -2px) !important;
432
+ box-shadow: 7px 7px 0px #1F2937 !important;
433
+ }
434
+
435
+ .gr-button-primary:active,
436
+ button.primary:active,
437
+ .gr-button.primary:active,
438
+ .generate-btn:active {
439
+ transform: translate(3px, 3px) !important;
440
+ box-shadow: 2px 2px 0px #1F2937 !important;
441
+ }
442
+
443
+ /* ===== 🎨 Secondary λ²„νŠΌ - μ½”λ―Ή λ ˆλ“œ ===== */
444
+ .gr-button-secondary,
445
+ button.secondary {
446
+ background: #EF4444 !important;
447
+ border: 3px solid #1F2937 !important;
448
+ border-radius: 8px !important;
449
+ color: #FFFFFF !important;
450
+ font-family: 'Bangers', cursive !important;
451
+ font-weight: 400 !important;
452
+ font-size: 1.1rem !important;
453
+ letter-spacing: 1px !important;
454
+ box-shadow: 4px 4px 0px #1F2937 !important;
455
+ transition: all 0.1s ease !important;
456
+ text-shadow: 1px 1px 0px #1F2937 !important;
457
+ }
458
+
459
+ .gr-button-secondary:hover,
460
+ button.secondary:hover {
461
+ background: #DC2626 !important;
462
+ transform: translate(-2px, -2px) !important;
463
+ box-shadow: 6px 6px 0px #1F2937 !important;
464
+ }
465
+
466
+ /* ===== 🎨 둜그 좜λ ₯ μ˜μ—­ ===== */
467
+ .info-log textarea {
468
+ background: #1F2937 !important;
469
+ color: #10B981 !important;
470
+ font-family: 'Courier New', monospace !important;
471
+ font-size: 0.9rem !important;
472
+ font-weight: 400 !important;
473
+ border: 3px solid #10B981 !important;
474
+ border-radius: 8px !important;
475
+ box-shadow: 4px 4px 0px #10B981 !important;
476
+ }
477
+
478
+ /* ===== 🎨 컬러 피컀 μŠ€νƒ€μΌ ===== */
479
+ .gr-colorpicker,
480
+ input[type="color"] {
481
+ border: 3px solid #1F2937 !important;
482
+ border-radius: 8px !important;
483
+ box-shadow: 3px 3px 0px #1F2937 !important;
484
+ width: 60px !important;
485
+ height: 40px !important;
486
+ cursor: pointer !important;
487
+ }
488
+
489
+ .gr-colorpicker:hover,
490
+ input[type="color"]:hover {
491
+ transform: translate(-2px, -2px) !important;
492
+ box-shadow: 5px 5px 0px #1F2937 !important;
493
+ }
494
+
495
+ /* ===== 🎨 μŠ¬λΌμ΄λ” μŠ€νƒ€μΌ ===== */
496
+ input[type="range"] {
497
+ accent-color: #3B82F6 !important;
498
+ height: 8px !important;
499
+ }
500
+
501
+ .gr-slider {
502
+ background: #FFFFFF !important;
503
+ }
504
+
505
+ /* ===== 🎨 μ˜ˆμ‹œ ν…μŠ€νŠΈ λ°•μŠ€ ===== */
506
+ .example-box textarea {
507
+ background: #FEF3C7 !important;
508
+ border: 2px dashed #F59E0B !important;
509
+ border-radius: 8px !important;
510
+ color: #92400E !important;
511
+ font-family: 'Comic Neue', cursive !important;
512
+ font-size: 0.9rem !important;
513
+ }
514
+
515
+ /* ===== 🎨 QR μ½”λ“œ 좜λ ₯ μ˜μ—­ ===== */
516
+ .qr-output,
517
+ .gr-image {
518
+ border: 4px solid #1F2937 !important;
519
+ border-radius: 8px !important;
520
+ box-shadow: 8px 8px 0px #1F2937 !important;
521
+ overflow: hidden !important;
522
+ background: #FFFFFF !important;
523
+ }
524
+
525
+ /* ===== 🎨 μ•„μ½”λ””μ–Έ - 말풍선 μŠ€νƒ€μΌ ===== */
526
+ .gr-accordion {
527
+ background: #FACC15 !important;
528
+ border: 3px solid #1F2937 !important;
529
+ border-radius: 8px !important;
530
+ box-shadow: 4px 4px 0px #1F2937 !important;
531
+ }
532
+
533
+ .gr-accordion-header {
534
+ color: #1F2937 !important;
535
+ font-family: 'Comic Neue', cursive !important;
536
+ font-weight: 700 !important;
537
+ font-size: 1.1rem !important;
538
+ }
539
+
540
+ /* ===== 🎨 라벨 μŠ€νƒ€μΌ ===== */
541
+ label,
542
+ .gr-input-label,
543
+ .gr-block-label {
544
+ color: #1F2937 !important;
545
+ font-family: 'Comic Neue', cursive !important;
546
+ font-weight: 700 !important;
547
+ font-size: 1rem !important;
548
+ }
549
+
550
+ span.gr-label {
551
+ color: #1F2937 !important;
552
+ }
553
+
554
+ /* ===== 🎨 정보 ν…μŠ€νŠΈ ===== */
555
+ .gr-info,
556
+ .info {
557
+ color: #6B7280 !important;
558
+ font-family: 'Comic Neue', cursive !important;
559
+ font-size: 0.9rem !important;
560
+ }
561
+
562
+ /* ===== 🎨 Instructions μ„Ήμ…˜ ===== */
563
+ .instructions-box {
564
+ background: linear-gradient(135deg, #EFF6FF 0%, #DBEAFE 100%) !important;
565
+ border: 3px solid #3B82F6 !important;
566
+ border-radius: 12px !important;
567
+ padding: 1.5rem !important;
568
+ box-shadow: 6px 6px 0px #1F2937 !important;
569
+ margin-top: 1.5rem !important;
570
+ }
571
+
572
+ .instructions-box h3 {
573
+ font-family: 'Bangers', cursive !important;
574
+ color: #1F2937 !important;
575
+ font-size: 1.3rem !important;
576
+ margin-bottom: 0.5rem !important;
577
+ }
578
+
579
+ .instructions-box ul,
580
+ .instructions-box ol {
581
+ font-family: 'Comic Neue', cursive !important;
582
+ color: #1F2937 !important;
583
+ font-weight: 700 !important;
584
+ }
585
+
586
+ /* ===== 🎨 Tips μ„Ήμ…˜ ===== */
587
+ .tips-box {
588
+ background: linear-gradient(135deg, #FEF3C7 0%, #FDE68A 100%) !important;
589
+ border: 3px solid #F59E0B !important;
590
+ border-radius: 12px !important;
591
+ padding: 1.5rem !important;
592
+ box-shadow: 6px 6px 0px #1F2937 !important;
593
+ margin-top: 1rem !important;
594
+ }
595
+
596
+ /* ===== 🎨 μŠ€ν¬λ‘€λ°” - μ½”λ―Ή μŠ€νƒ€μΌ ===== */
597
+ ::-webkit-scrollbar {
598
+ width: 12px;
599
+ height: 12px;
600
+ }
601
+
602
+ ::-webkit-scrollbar-track {
603
+ background: #FEF9C3;
604
+ border: 2px solid #1F2937;
605
+ }
606
+
607
+ ::-webkit-scrollbar-thumb {
608
+ background: #3B82F6;
609
+ border: 2px solid #1F2937;
610
+ border-radius: 0px;
611
+ }
612
+
613
+ ::-webkit-scrollbar-thumb:hover {
614
+ background: #EF4444;
615
+ }
616
+
617
+ /* ===== 🎨 선택 ν•˜μ΄λΌμ΄νŠΈ ===== */
618
+ ::selection {
619
+ background: #FACC15;
620
+ color: #1F2937;
621
+ }
622
+
623
+ /* ===== 🎨 링크 μŠ€νƒ€μΌ ===== */
624
+ a {
625
+ color: #3B82F6 !important;
626
+ text-decoration: none !important;
627
+ font-weight: 700 !important;
628
+ }
629
+
630
+ a:hover {
631
+ color: #EF4444 !important;
632
+ }
633
+
634
+ /* ===== 🎨 Row/Column 간격 ===== */
635
+ .gr-row {
636
+ gap: 1.5rem !important;
637
+ }
638
+
639
+ .gr-column {
640
+ gap: 1rem !important;
641
+ }
642
+
643
+ /* ===== 🎨 컬러 피컀 Row ===== */
644
+ .color-picker-row {
645
+ display: flex !important;
646
+ gap: 1rem !important;
647
+ align-items: center !important;
648
+ }
649
+
650
+ /* ===== λ°˜μ‘ν˜• μ‘°μ • ===== */
651
+ @media (max-width: 768px) {
652
+ .header-text h1 {
653
+ font-size: 2.2rem !important;
654
+ text-shadow:
655
+ 3px 3px 0px #FACC15,
656
+ 4px 4px 0px #1F2937 !important;
657
+ }
658
 
659
+ .gr-button-primary,
660
+ button.primary {
661
+ padding: 12px 20px !important;
662
+ font-size: 1.1rem !important;
663
+ }
664
+
665
+ .gr-panel,
666
+ .block {
667
+ box-shadow: 4px 4px 0px #1F2937 !important;
668
+ }
669
+ }
670
+
671
+ /* ===== 🎨 닀크λͺ¨λ“œ λΉ„ν™œμ„±ν™” ===== */
672
+ @media (prefers-color-scheme: dark) {
673
+ .gradio-container {
674
+ background-color: #FEF9C3 !important;
675
+ }
676
+ }
677
+ """
678
 
679
+
680
+ def create_interface():
681
+ with gr.Blocks(fill_height=True, css=css, title="QR Canvas+") as demo:
682
+
683
+ # HOME Badge
684
+ gr.HTML("""
685
+ <div style="text-align: center; margin: 20px 0 10px 0;">
686
+ <a href="https://www.humangen.ai" target="_blank" style="text-decoration: none;">
687
+ <img src="https://img.shields.io/static/v1?label=🏠 HOME&message=HUMANGEN.AI&color=0000ff&labelColor=ffcc00&style=for-the-badge" alt="HOME">
688
+ </a>
689
+ </div>
690
+ """)
691
+
692
+ # Header Title
693
  gr.Markdown(
694
  """
695
+ # 🎯 QR CANVAS+ GENERATOR πŸ“±
696
+ """,
697
+ elem_classes="header-text"
698
  )
699
 
700
+ gr.Markdown(
701
+ """
702
+ <p class="subtitle">🎨 Create customized QR codes with professional styling & decorations! ✨</p>
703
+ """,
704
+ )
705
 
706
+ with gr.Row(equal_height=False):
707
+ # Left column - Input Settings
708
+ with gr.Column(scale=2, min_width=450):
709
  qr_type = gr.Dropdown(
710
  choices=["URL", "Email", "Phone", "SMS", "WhatsApp", "Location", "Wi-Fi", "Text", "vCard"],
711
  value="URL",
712
+ label="πŸ“‹ QR Code Type"
713
  )
714
 
715
  content = gr.Textbox(
716
+ label="✏️ Content",
717
  placeholder="Enter your content here...",
718
  lines=3
719
  )
720
 
721
  example_format = gr.Textbox(
722
  value=format_example_text("URL"),
723
+ label="πŸ“ Format Examples",
724
  interactive=False,
725
+ lines=4,
726
+ elem_classes="example-box"
727
  )
728
 
729
+ with gr.Row(elem_classes="color-picker-row"):
730
  fill_color = gr.ColorPicker(
731
+ label="🎨 QR Code Color",
732
  value="#000000"
733
  )
734
  back_color = gr.ColorPicker(
735
+ label="πŸ–ΌοΈ Background Color",
736
  value="#FFFFFF"
737
  )
 
 
 
738
 
739
  with gr.Row():
740
  box_size = gr.Slider(
741
  minimum=1,
742
+ maximum=30,
743
+ value=15,
744
  step=1,
745
+ label="πŸ“ QR Code Size"
746
  )
747
  border_size = gr.Slider(
748
  minimum=0,
749
+ maximum=5,
750
+ value=2,
751
  step=1,
752
+ label="πŸ”² Border Size"
753
  )
754
 
755
  error_correction = gr.Dropdown(
 
760
  "High (30%)"
761
  ],
762
  value="Medium (15%)",
763
+ label="πŸ”§ Error Correction Level"
764
  )
765
 
766
  border_decoration = gr.Dropdown(
767
  choices=[
768
+ "No Decoration",
769
  "Flowers",
770
  "Hearts",
771
  "Waves",
 
777
  "Diamonds",
778
  "Lace"
779
  ],
780
+ value="No Decoration",
781
+ label="🌸 Border Decoration Style"
782
  )
783
 
 
 
784
  generate_btn = gr.Button(
785
+ "🎯 GENERATE QR CODE! πŸ“±",
786
+ variant="primary",
787
+ size="lg",
788
+ elem_classes="generate-btn"
789
  )
790
+
791
+ with gr.Accordion("πŸ“œ Generation Log", open=True):
792
+ info_log = gr.Textbox(
793
+ label="",
794
+ placeholder="Enter content and click generate to see info...",
795
+ lines=14,
796
+ max_lines=20,
797
+ interactive=False,
798
+ elem_classes="info-log"
799
+ )
800
 
801
+ # Right column - Output
802
+ with gr.Column(scale=1, min_width=350):
803
  output_image = gr.Image(
804
+ label="πŸ–ΌοΈ Generated QR Code",
805
+ type="filepath",
806
+ height=400,
807
+ elem_classes="qr-output"
808
  )
809
+
810
  output_data = gr.Textbox(
811
+ label="πŸ“„ Formatted Data",
812
+ interactive=False,
813
+ lines=2
814
+ )
815
+
816
+ gr.Markdown(
817
+ """
818
+ <p style="text-align: center; margin-top: 15px; font-weight: 700; color: #1F2937;">
819
+ πŸ’‘ Right-click on the QR code to save!
820
+ </p>
821
+ """
822
  )
823
+
824
+ # Instructions Section
825
+ gr.Markdown(
826
+ """
827
+ <div class="instructions-box">
828
+ <h3>πŸ“ INSTRUCTIONS</h3>
829
+ <ol>
830
+ <li>Select the QR code type from the dropdown menu</li>
831
+ <li>Enter your content following the format examples shown</li>
832
+ <li>Customize the appearance using the color pickers and sliders</li>
833
+ <li>Choose a border decoration style (optional)</li>
834
+ <li>Click 'GENERATE QR CODE' to create your custom QR code</li>
835
+ </ol>
836
+ </div>
837
+
838
+ <div class="tips-box">
839
+ <h3>πŸ’‘ TIPS</h3>
840
+ <ul>
841
+ <li>Use higher error correction levels for better scan reliability</li>
842
+ <li>Ensure sufficient contrast between QR code and background colors</li>
843
+ <li>Keep the content concise for better readability</li>
844
+ <li>Follow the format examples for best results</li>
845
+ </ul>
846
+ </div>
847
+ """
848
+ )
849
 
850
+ # Event handlers
851
  def update_example(qr_type):
852
  return format_example_text(qr_type)
853
 
 
869
  error_correction,
870
  border_decoration
871
  ],
872
+ outputs=[output_image, output_data, info_log]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
873
  )
874
 
875
  return demo
876
 
877
+
878
  if __name__ == "__main__":
879
  try:
880
  os.makedirs("qrfile", exist_ok=True)