Spaces:
Sleeping
Sleeping
capradeepgujaran
commited on
Commit
•
13df159
1
Parent(s):
6a51b6d
Update app.py
Browse files
app.py
CHANGED
@@ -300,8 +300,63 @@ class CertificateGenerator:
|
|
300 |
[(1160, 780 - corner_size), (1160, 780)]
|
301 |
]
|
302 |
|
303 |
-
|
304 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
305 |
|
306 |
def _add_content(
|
307 |
self,
|
@@ -311,45 +366,49 @@ class CertificateGenerator:
|
|
311 |
course_name: str,
|
312 |
score: float
|
313 |
):
|
314 |
-
#
|
315 |
-
|
316 |
-
draw.text((
|
317 |
-
|
318 |
-
# Clean inputs
|
319 |
-
name = str(name).strip() or "Participant"
|
320 |
-
course_name = str(course_name).strip() or "Assessment"
|
321 |
-
|
322 |
-
# Main content
|
323 |
-
content = [
|
324 |
-
(300, "This is to certify that", 'black'),
|
325 |
-
(380, name, self.border_color),
|
326 |
-
(460, "has successfully completed", 'black'),
|
327 |
-
(540, course_name, self.border_color),
|
328 |
-
(620, f"with a score of {float(score):.1f}%", 'black'),
|
329 |
-
(700, datetime.now().strftime("%B %d, %Y"), 'black')
|
330 |
-
]
|
331 |
|
332 |
-
|
333 |
-
|
334 |
-
|
335 |
-
|
336 |
-
|
337 |
-
|
338 |
-
|
339 |
-
|
340 |
-
|
341 |
-
|
342 |
-
|
343 |
-
|
344 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
345 |
|
346 |
-
def
|
347 |
try:
|
348 |
-
|
349 |
-
|
350 |
-
|
|
|
|
|
351 |
except Exception as e:
|
352 |
-
print(f"Error adding
|
353 |
|
354 |
def _save_certificate(self, certificate: Image.Image) -> str:
|
355 |
temp_file = tempfile.NamedTemporaryFile(delete=False, suffix='.png')
|
|
|
300 |
[(1160, 780 - corner_size), (1160, 780)]
|
301 |
]
|
302 |
|
303 |
+
class CertificateGenerator:
|
304 |
+
def __init__(self):
|
305 |
+
self.certificate_size = (1200, 800)
|
306 |
+
self.border_color = '#FFFFFF' # White background
|
307 |
+
self.background_color = '#FFFFFF'
|
308 |
+
|
309 |
+
# Install fonts if needed
|
310 |
+
FontManager.install_fonts()
|
311 |
+
self.font_paths = FontManager.get_font_paths()
|
312 |
+
|
313 |
+
def _load_fonts(self) -> Dict[str, ImageFont.FreeTypeFont]:
|
314 |
+
"""Load fonts with fallbacks"""
|
315 |
+
fonts = {}
|
316 |
+
try:
|
317 |
+
if self.font_paths['regular'] and self.font_paths['bold']:
|
318 |
+
fonts['title'] = ImageFont.truetype(self.font_paths['bold'], 36) # Smaller for course name
|
319 |
+
fonts['subtitle'] = ImageFont.truetype(self.font_paths['regular'], 14) # For labels
|
320 |
+
fonts['text'] = ImageFont.truetype(self.font_paths['regular'], 20) # For regular text
|
321 |
+
fonts['name'] = ImageFont.truetype(self.font_paths['bold'], 32) # For participant name
|
322 |
+
else:
|
323 |
+
raise ValueError("No suitable fonts found")
|
324 |
+
except Exception as e:
|
325 |
+
print(f"Font loading error: {e}. Using default font.")
|
326 |
+
default = ImageFont.load_default()
|
327 |
+
fonts = {
|
328 |
+
'title': default,
|
329 |
+
'subtitle': default,
|
330 |
+
'text': default,
|
331 |
+
'name': default
|
332 |
+
}
|
333 |
+
return fonts
|
334 |
+
|
335 |
+
def generate(
|
336 |
+
self,
|
337 |
+
score: float,
|
338 |
+
name: str,
|
339 |
+
course_name: str,
|
340 |
+
company_logo: Optional[str] = None,
|
341 |
+
participant_photo: Optional[str] = None
|
342 |
+
) -> str:
|
343 |
+
try:
|
344 |
+
certificate = self._create_base_certificate()
|
345 |
+
draw = ImageDraw.Draw(certificate)
|
346 |
+
|
347 |
+
fonts = self._load_fonts()
|
348 |
+
self._add_content(draw, fonts, str(name), str(course_name), float(score))
|
349 |
+
|
350 |
+
if company_logo:
|
351 |
+
self._add_logo(certificate, company_logo)
|
352 |
+
|
353 |
+
return self._save_certificate(certificate)
|
354 |
+
except Exception as e:
|
355 |
+
print(f"Error generating certificate: {e}")
|
356 |
+
return None
|
357 |
+
|
358 |
+
def _create_base_certificate(self) -> Image.Image:
|
359 |
+
return Image.new('RGB', self.certificate_size, self.background_color)
|
360 |
|
361 |
def _add_content(
|
362 |
self,
|
|
|
366 |
course_name: str,
|
367 |
score: float
|
368 |
):
|
369 |
+
# Add certificate ID at top right
|
370 |
+
certificate_id = f"Certificate no: {datetime.now().strftime('%Y%m%d')}-{abs(hash(name)) % 10000:04d}"
|
371 |
+
draw.text((1100, 40), certificate_id, font=fonts['subtitle'], fill='#666666', anchor="ra")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
372 |
|
373 |
+
# Add "CERTIFICATE OF COMPLETION" text
|
374 |
+
draw.text((60, 120), "CERTIFICATE OF COMPLETION", font=fonts['subtitle'], fill='#666666')
|
375 |
+
|
376 |
+
# Add course name (large and bold)
|
377 |
+
course_name = course_name.strip() or "Assessment"
|
378 |
+
draw.multiline_text((60, 180), course_name, font=fonts['title'], fill='#1C1D1F', spacing=10)
|
379 |
+
|
380 |
+
# Add instructor info
|
381 |
+
draw.text((60, 280), "Instructor", font=fonts['subtitle'], fill='#666666')
|
382 |
+
draw.text((60, 310), "CertifyMe AI", font=fonts['text'], fill='#1C1D1F')
|
383 |
+
|
384 |
+
# Add participant name (large)
|
385 |
+
name = name.strip() or "Participant"
|
386 |
+
draw.text((60, 400), name, font=fonts['name'], fill='#1C1D1F')
|
387 |
+
|
388 |
+
# Add date and score info with spacing
|
389 |
+
date_str = datetime.now().strftime("%b. %d, %Y")
|
390 |
+
|
391 |
+
# Date section
|
392 |
+
draw.text((60, 480), "Date", font=fonts['subtitle'], fill='#666666')
|
393 |
+
draw.text((60, 510), date_str, font=fonts['text'], fill='#1C1D1F')
|
394 |
+
|
395 |
+
# Score section
|
396 |
+
draw.text((300, 480), "Score", font=fonts['subtitle'], fill='#666666')
|
397 |
+
draw.text((300, 510), f"{float(score):.1f}%", font=fonts['text'], fill='#1C1D1F')
|
398 |
+
|
399 |
+
# Add reference number at bottom
|
400 |
+
ref_number = f"Reference Number: {abs(hash(name + date_str)) % 10000:04d}"
|
401 |
+
draw.text((60, 700), ref_number, font=fonts['subtitle'], fill='#666666')
|
402 |
|
403 |
+
def _add_logo(self, certificate: Image.Image, logo_path: str):
|
404 |
try:
|
405 |
+
logo = Image.open(logo_path)
|
406 |
+
# Resize logo to appropriate size
|
407 |
+
logo.thumbnail((150, 80))
|
408 |
+
# Position in top-left corner
|
409 |
+
certificate.paste(logo, (50, 30))
|
410 |
except Exception as e:
|
411 |
+
print(f"Error adding logo: {e}")
|
412 |
|
413 |
def _save_certificate(self, certificate: Image.Image) -> str:
|
414 |
temp_file = tempfile.NamedTemporaryFile(delete=False, suffix='.png')
|