sameernotes commited on
Commit
9ae949c
Β·
verified Β·
1 Parent(s): 11872ae

Update src/streamlit_app.py

Browse files
Files changed (1) hide show
  1. src/streamlit_app.py +232 -86
src/streamlit_app.py CHANGED
@@ -1,9 +1,6 @@
1
  import streamlit as st
2
  import qrcode
3
- from qrcode.image.styledpil import StyledPilImage
4
- from qrcode.image.styles.moduledrawers import RoundedModuleDrawer, CircleModuleDrawer, SquareModuleDrawer
5
- from qrcode.image.styles.colorfills import SolidFillColorMask, RadialGradiantColorMask, SquareGradiantColorMask
6
- from PIL import Image, ImageDraw
7
  import io
8
  import base64
9
 
@@ -50,10 +47,62 @@ st.markdown("""
50
  margin: 1rem 0;
51
  box-shadow: 0 2px 4px rgba(0,0,0,0.1);
52
  }
 
 
 
 
 
 
 
 
 
 
53
  </style>
54
  """, unsafe_allow_html=True)
55
 
56
- def create_qr_code(data, fill_color, back_color, border, box_size, error_correction, style_type):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
57
  """Generate QR code with custom styling"""
58
 
59
  # Error correction levels
@@ -75,40 +124,105 @@ def create_qr_code(data, fill_color, back_color, border, box_size, error_correct
75
  qr.add_data(data)
76
  qr.make(fit=True)
77
 
78
- # Style configurations
79
- if style_type == "Standard":
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
80
  img = qr.make_image(fill_color=fill_color, back_color=back_color)
81
- elif style_type == "Rounded":
82
- img = qr.make_image(
83
- image_factory=StyledPilImage,
84
- module_drawer=RoundedModuleDrawer(),
85
- fill_color=fill_color,
86
- back_color=back_color
87
- )
88
- elif style_type == "Circular":
89
- img = qr.make_image(
90
- image_factory=StyledPilImage,
91
- module_drawer=CircleModuleDrawer(),
92
- fill_color=fill_color,
93
- back_color=back_color
94
- )
95
- elif style_type == "Gradient":
96
- img = qr.make_image(
97
- image_factory=StyledPilImage,
98
- color_mask=RadialGradiantColorMask(),
99
- fill_color=fill_color,
100
- back_color=back_color
101
- )
102
 
103
  return img
104
 
105
- def get_download_link(img, filename):
106
- """Generate download link for the QR code"""
107
- buffered = io.BytesIO()
108
- img.save(buffered, format="PNG")
109
- img_str = base64.b64encode(buffered.getvalue()).decode()
110
- href = f'<a href="data:image/png;base64,{img_str}" download="{filename}" class="download-btn">πŸ“₯ Download QR Code</a>'
111
- return href
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
112
 
113
  # Main header
114
  st.markdown("""
@@ -128,36 +242,10 @@ with st.sidebar:
128
 
129
  content_type = st.selectbox(
130
  "Content Type",
131
- ["Text", "URL", "Email", "Phone", "SMS", "WiFi"]
132
  )
133
 
134
- if content_type == "Text":
135
- qr_data = st.text_area("Enter your text:", height=100)
136
- elif content_type == "URL":
137
- qr_data = st.text_input("Enter URL:", placeholder="https://example.com")
138
- elif content_type == "Email":
139
- email = st.text_input("Email address:")
140
- subject = st.text_input("Subject (optional):")
141
- body = st.text_area("Message (optional):", height=80)
142
- qr_data = f"mailto:{email}?subject={subject}&body={body}" if email else ""
143
- elif content_type == "Phone":
144
- qr_data = st.text_input("Phone number:", placeholder="+1234567890")
145
- if qr_data:
146
- qr_data = f"tel:{qr_data}"
147
- elif content_type == "SMS":
148
- phone = st.text_input("Phone number:", placeholder="+1234567890")
149
- message = st.text_area("Message:", height=80)
150
- qr_data = f"sms:{phone}?body={message}" if phone else ""
151
- elif content_type == "WiFi":
152
- ssid = st.text_input("Network Name (SSID):")
153
- password = st.text_input("Password:", type="password")
154
- security = st.selectbox("Security Type", ["WPA", "WEP", "nopass"])
155
- hidden = st.checkbox("Hidden Network")
156
- if ssid:
157
- qr_data = f"WIFI:T:{security};S:{ssid};P:{password};H:{'true' if hidden else 'false'};;"
158
- else:
159
- qr_data = ""
160
-
161
  st.markdown('</div>', unsafe_allow_html=True)
162
 
163
  # Style Settings
@@ -166,7 +254,7 @@ with st.sidebar:
166
 
167
  style_type = st.selectbox(
168
  "QR Style",
169
- ["Standard", "Rounded", "Circular", "Gradient"]
170
  )
171
 
172
  col1, col2 = st.columns(2)
@@ -175,17 +263,23 @@ with st.sidebar:
175
  with col2:
176
  back_color = st.color_picker("Background Color", "#FFFFFF")
177
 
 
 
 
 
178
  st.markdown('</div>', unsafe_allow_html=True)
179
 
180
  # Advanced Settings
181
  st.markdown('<div class="sidebar-section">', unsafe_allow_html=True)
182
  st.markdown("### βš™οΈ Advanced Settings")
183
 
184
- box_size = st.slider("Module Size", 1, 20, 10)
185
- border = st.slider("Border Width", 1, 10, 4)
186
  error_correction = st.selectbox(
187
  "Error Correction Level",
188
- ["L (~7%)", "M (~15%)", "Q (~25%)", "H (~30%)"]
 
 
189
  )
190
 
191
  st.markdown('</div>', unsafe_allow_html=True)
@@ -197,15 +291,21 @@ with col1:
197
  if qr_data:
198
  try:
199
  # Generate QR code
200
- qr_img = create_qr_code(
201
- qr_data, fill_color, back_color, border,
202
- box_size, error_correction, style_type
203
- )
 
204
 
205
  # Display QR code
206
  st.markdown("### πŸ“± Your QR Code")
207
  st.image(qr_img, caption="Generated QR Code", use_container_width=True)
208
 
 
 
 
 
 
209
  # Download section
210
  st.markdown("""
211
  <div class="download-section">
@@ -215,42 +315,88 @@ with col1:
215
  """, unsafe_allow_html=True)
216
 
217
  # Download button
218
- filename = f"qrcode_{content_type.lower()}.png"
219
- st.markdown(get_download_link(qr_img, filename), unsafe_allow_html=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
220
 
221
  except Exception as e:
222
- st.error(f"Error generating QR code: {str(e)}")
 
223
  else:
224
- st.info("πŸ‘ˆ Please enter content in the sidebar to generate your QR code")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
225
 
226
  with col2:
227
- st.markdown("### πŸ“‹ Features")
228
 
229
  features = [
230
  "🎨 Multiple visual styles",
231
- "🌈 Custom colors",
232
  "πŸ“± Various content types",
233
  "βš™οΈ Advanced settings",
234
- "πŸ“₯ Instant download",
235
- "πŸ”§ Error correction levels"
 
 
236
  ]
237
 
238
  for feature in features:
239
  st.markdown(f'<div class="feature-box">{feature}</div>', unsafe_allow_html=True)
240
 
241
- st.markdown("### πŸ’‘ Tips")
242
- st.info("""
243
- **Higher Error Correction** = More resilient to damage but larger QR code
244
-
245
- **Larger Module Size** = Easier to scan but bigger file
 
 
 
 
246
 
247
- **Good Contrast** = Better scanning reliability
 
 
 
 
 
248
  """)
249
 
250
  # Footer
251
  st.markdown("---")
252
  st.markdown("""
253
  <div style="text-align: center; color: #666; padding: 2rem;">
254
- <p>πŸš€ Built with Streamlit | πŸ’ Made with love for QR code enthusiasts</p>
 
255
  </div>
256
  """, unsafe_allow_html=True)
 
1
  import streamlit as st
2
  import qrcode
3
+ from PIL import Image, ImageDraw, ImageFont
 
 
 
4
  import io
5
  import base64
6
 
 
47
  margin: 1rem 0;
48
  box-shadow: 0 2px 4px rgba(0,0,0,0.1);
49
  }
50
+
51
+ .stDownloadButton > button {
52
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
53
+ color: white;
54
+ border: none;
55
+ border-radius: 10px;
56
+ padding: 0.5rem 2rem;
57
+ font-weight: bold;
58
+ width: 100%;
59
+ }
60
  </style>
61
  """, unsafe_allow_html=True)
62
 
63
+ def hex_to_rgb(hex_color):
64
+ """Convert hex color to RGB tuple"""
65
+ hex_color = hex_color.lstrip('#')
66
+ return tuple(int(hex_color[i:i+2], 16) for i in (0, 2, 4))
67
+
68
+ def create_gradient_image(size, start_color, end_color, direction='horizontal'):
69
+ """Create a gradient image"""
70
+ image = Image.new('RGB', size)
71
+ draw = ImageDraw.Draw(image)
72
+
73
+ if direction == 'horizontal':
74
+ for x in range(size[0]):
75
+ ratio = x / size[0]
76
+ r = int(start_color[0] * (1 - ratio) + end_color[0] * ratio)
77
+ g = int(start_color[1] * (1 - ratio) + end_color[1] * ratio)
78
+ b = int(start_color[2] * (1 - ratio) + end_color[2] * ratio)
79
+ draw.line([(x, 0), (x, size[1])], fill=(r, g, b))
80
+ else: # vertical
81
+ for y in range(size[1]):
82
+ ratio = y / size[1]
83
+ r = int(start_color[0] * (1 - ratio) + end_color[0] * ratio)
84
+ g = int(start_color[1] * (1 - ratio) + end_color[1] * ratio)
85
+ b = int(start_color[2] * (1 - ratio) + end_color[2] * ratio)
86
+ draw.line([(0, y), (size[0], y)], fill=(r, g, b))
87
+
88
+ return image
89
+
90
+ def create_rounded_qr(qr_img, corner_radius=20):
91
+ """Create rounded corners for QR code"""
92
+ # Create mask for rounded corners
93
+ size = qr_img.size
94
+ mask = Image.new('L', size, 0)
95
+ draw = ImageDraw.Draw(mask)
96
+ draw.rounded_rectangle([(0, 0), size], corner_radius, fill=255)
97
+
98
+ # Apply mask
99
+ qr_rounded = Image.new('RGBA', size, (255, 255, 255, 0))
100
+ qr_rounded.paste(qr_img, (0, 0))
101
+ qr_rounded.putalpha(mask)
102
+
103
+ return qr_rounded
104
+
105
+ def create_qr_code(data, fill_color, back_color, border, box_size, error_correction, style_type, gradient_end_color=None):
106
  """Generate QR code with custom styling"""
107
 
108
  # Error correction levels
 
124
  qr.add_data(data)
125
  qr.make(fit=True)
126
 
127
+ # Generate base QR code
128
+ if style_type == "Gradient" and gradient_end_color:
129
+ # Create gradient background
130
+ img = qr.make_image(fill_color='black', back_color='white')
131
+
132
+ # Create gradient
133
+ start_rgb = hex_to_rgb(fill_color)
134
+ end_rgb = hex_to_rgb(gradient_end_color)
135
+ gradient = create_gradient_image(img.size, start_rgb, end_rgb, 'horizontal')
136
+
137
+ # Apply gradient to QR code
138
+ img_array = img.load()
139
+ gradient_array = gradient.load()
140
+
141
+ for x in range(img.size[0]):
142
+ for y in range(img.size[1]):
143
+ if img_array[x, y] == 0: # Black pixel (QR code data)
144
+ img_array[x, y] = gradient_array[x, y]
145
+ else: # White pixel (background)
146
+ img_array[x, y] = hex_to_rgb(back_color)
147
+ else:
148
  img = qr.make_image(fill_color=fill_color, back_color=back_color)
149
+
150
+ # Apply style modifications
151
+ if style_type == "Rounded":
152
+ img = create_rounded_qr(img, corner_radius=box_size*2)
153
+ elif style_type == "With Logo Space":
154
+ # Create space in center for logo
155
+ draw = ImageDraw.Draw(img)
156
+ center_x, center_y = img.size[0] // 2, img.size[1] // 2
157
+ logo_size = min(img.size) // 6
158
+ draw.rectangle([
159
+ center_x - logo_size//2, center_y - logo_size//2,
160
+ center_x + logo_size//2, center_y + logo_size//2
161
+ ], fill=back_color, outline=fill_color, width=2)
 
 
 
 
 
 
 
 
162
 
163
  return img
164
 
165
+ def get_qr_data_by_type(content_type):
166
+ """Get QR data based on content type"""
167
+ if content_type == "Text":
168
+ return st.text_area("Enter your text:", height=100, placeholder="Hello World!")
169
+
170
+ elif content_type == "URL":
171
+ url = st.text_input("Enter URL:", placeholder="https://example.com")
172
+ if url and not url.startswith(('http://', 'https://')):
173
+ url = 'https://' + url
174
+ return url
175
+
176
+ elif content_type == "Email":
177
+ email = st.text_input("Email address:", placeholder="contact@example.com")
178
+ subject = st.text_input("Subject (optional):")
179
+ body = st.text_area("Message (optional):", height=80)
180
+ if email:
181
+ params = []
182
+ if subject:
183
+ params.append(f"subject={subject}")
184
+ if body:
185
+ params.append(f"body={body}")
186
+ return f"mailto:{email}{'?' + '&'.join(params) if params else ''}"
187
+ return ""
188
+
189
+ elif content_type == "Phone":
190
+ phone = st.text_input("Phone number:", placeholder="+1234567890")
191
+ return f"tel:{phone}" if phone else ""
192
+
193
+ elif content_type == "SMS":
194
+ phone = st.text_input("Phone number:", placeholder="+1234567890")
195
+ message = st.text_area("Message:", height=80, placeholder="Hello!")
196
+ if phone:
197
+ return f"sms:{phone}{'?body=' + message if message else ''}"
198
+ return ""
199
+
200
+ elif content_type == "WiFi":
201
+ ssid = st.text_input("Network Name (SSID):", placeholder="MyWiFi")
202
+ password = st.text_input("Password:", type="password")
203
+ security = st.selectbox("Security Type", ["WPA", "WEP", "nopass"])
204
+ hidden = st.checkbox("Hidden Network")
205
+ if ssid:
206
+ return f"WIFI:T:{security};S:{ssid};P:{password};H:{'true' if hidden else 'false'};;"
207
+ return ""
208
+
209
+ elif content_type == "vCard":
210
+ name = st.text_input("Full Name:", placeholder="John Doe")
211
+ phone = st.text_input("Phone:", placeholder="+1234567890")
212
+ email = st.text_input("Email:", placeholder="john@example.com")
213
+ organization = st.text_input("Organization (optional):", placeholder="Company Inc.")
214
+
215
+ if name:
216
+ vcard = f"BEGIN:VCARD\nVERSION:3.0\nFN:{name}\n"
217
+ if phone:
218
+ vcard += f"TEL:{phone}\n"
219
+ if email:
220
+ vcard += f"EMAIL:{email}\n"
221
+ if organization:
222
+ vcard += f"ORG:{organization}\n"
223
+ vcard += "END:VCARD"
224
+ return vcard
225
+ return ""
226
 
227
  # Main header
228
  st.markdown("""
 
242
 
243
  content_type = st.selectbox(
244
  "Content Type",
245
+ ["Text", "URL", "Email", "Phone", "SMS", "WiFi", "vCard"]
246
  )
247
 
248
+ qr_data = get_qr_data_by_type(content_type)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
249
  st.markdown('</div>', unsafe_allow_html=True)
250
 
251
  # Style Settings
 
254
 
255
  style_type = st.selectbox(
256
  "QR Style",
257
+ ["Standard", "Rounded", "Gradient", "With Logo Space"]
258
  )
259
 
260
  col1, col2 = st.columns(2)
 
263
  with col2:
264
  back_color = st.color_picker("Background Color", "#FFFFFF")
265
 
266
+ gradient_end_color = None
267
+ if style_type == "Gradient":
268
+ gradient_end_color = st.color_picker("Gradient End Color", "#333333")
269
+
270
  st.markdown('</div>', unsafe_allow_html=True)
271
 
272
  # Advanced Settings
273
  st.markdown('<div class="sidebar-section">', unsafe_allow_html=True)
274
  st.markdown("### βš™οΈ Advanced Settings")
275
 
276
+ box_size = st.slider("Module Size", 5, 20, 10, help="Size of each QR code square")
277
+ border = st.slider("Border Width", 1, 10, 4, help="White border around QR code")
278
  error_correction = st.selectbox(
279
  "Error Correction Level",
280
+ ["L (~7%)", "M (~15%)", "Q (~25%)", "H (~30%)"],
281
+ index=1,
282
+ help="Higher levels = more damage resistance but larger code"
283
  )
284
 
285
  st.markdown('</div>', unsafe_allow_html=True)
 
291
  if qr_data:
292
  try:
293
  # Generate QR code
294
+ with st.spinner("🎨 Generating your beautiful QR code..."):
295
+ qr_img = create_qr_code(
296
+ qr_data, fill_color, back_color, border,
297
+ box_size, error_correction, style_type, gradient_end_color
298
+ )
299
 
300
  # Display QR code
301
  st.markdown("### πŸ“± Your QR Code")
302
  st.image(qr_img, caption="Generated QR Code", use_container_width=True)
303
 
304
+ # Convert to bytes for download
305
+ img_buffer = io.BytesIO()
306
+ qr_img.save(img_buffer, format="PNG")
307
+ img_bytes = img_buffer.getvalue()
308
+
309
  # Download section
310
  st.markdown("""
311
  <div class="download-section">
 
315
  """, unsafe_allow_html=True)
316
 
317
  # Download button
318
+ filename = f"qrcode_{content_type.lower()}_{style_type.lower().replace(' ', '_')}.png"
319
+ st.download_button(
320
+ label="πŸ“₯ Download QR Code",
321
+ data=img_bytes,
322
+ file_name=filename,
323
+ mime="image/png",
324
+ use_container_width=True
325
+ )
326
+
327
+ # QR Code Info
328
+ st.info(f"""
329
+ **QR Code Details:**
330
+ - Content Type: {content_type}
331
+ - Style: {style_type}
332
+ - Size: {qr_img.size[0]}x{qr_img.size[1]} pixels
333
+ - Error Correction: {error_correction}
334
+ """)
335
 
336
  except Exception as e:
337
+ st.error(f"❌ Error generating QR code: {str(e)}")
338
+ st.info("πŸ’‘ Try adjusting your content or settings")
339
  else:
340
+ # Welcome message with example
341
+ st.markdown("""
342
+ ### πŸ‘‹ Welcome to QR Code Generator!
343
+
344
+ πŸ‘ˆ **Get started by entering content in the sidebar**
345
+
346
+ #### 🌟 What you can create:
347
+ - **Text QR codes** for messages
348
+ - **URL QR codes** for websites
349
+ - **Contact QR codes** (vCard format)
350
+ - **WiFi QR codes** for easy connection
351
+ - **Email & SMS QR codes**
352
+
353
+ #### 🎨 Styling options:
354
+ - Custom colors
355
+ - Rounded corners
356
+ - Gradient effects
357
+ - Logo space preparation
358
+ """)
359
 
360
  with col2:
361
+ st.markdown("### ✨ Features")
362
 
363
  features = [
364
  "🎨 Multiple visual styles",
365
+ "🌈 Custom colors & gradients",
366
  "πŸ“± Various content types",
367
  "βš™οΈ Advanced settings",
368
+ "πŸ“₯ Instant PNG download",
369
+ "πŸ”§ Error correction levels",
370
+ "πŸ“‡ vCard contact support",
371
+ "πŸ“Ά WiFi QR codes"
372
  ]
373
 
374
  for feature in features:
375
  st.markdown(f'<div class="feature-box">{feature}</div>', unsafe_allow_html=True)
376
 
377
+ st.markdown("### πŸ’‘ Pro Tips")
378
+ st.success("""
379
+ **🎯 Best Practices:**
380
+ - Use high contrast colors
381
+ - Test with your phone camera
382
+ - Higher error correction for outdoor use
383
+ - Larger module size for distant scanning
384
+ - Keep URLs short for simpler codes
385
+ """)
386
 
387
+ st.markdown("### πŸ“Š Error Correction Guide")
388
+ st.info("""
389
+ - **L (7%)**: Good for clean environments
390
+ - **M (15%)**: Standard recommendation
391
+ - **Q (25%)**: Better for rough handling
392
+ - **H (30%)**: Best for outdoor/damaged codes
393
  """)
394
 
395
  # Footer
396
  st.markdown("---")
397
  st.markdown("""
398
  <div style="text-align: center; color: #666; padding: 2rem;">
399
+ <p>πŸš€ Built with Streamlit | πŸ’ Made for QR code enthusiasts</p>
400
+ <p><small>πŸ’‘ Tip: Bookmark this page for quick QR code generation!</small></p>
401
  </div>
402
  """, unsafe_allow_html=True)