capradeepgujaran commited on
Commit
dd3e782
·
verified ·
1 Parent(s): 47b5d26

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +73 -48
app.py CHANGED
@@ -328,59 +328,40 @@ class CertificateGenerator:
328
  fonts: Dict[str, ImageFont.FreeTypeFont],
329
  name: str,
330
  course_name: str,
331
- score: float
 
332
  ):
 
333
  # Add "CERTIFICATE OF COMPLETION" text
334
- draw.text((60, 140), "CERTIFICATE OF COMPLETION", font=fonts['subtitle'], fill='#666666')
335
 
336
  # Add course name (large and bold)
337
  course_name = course_name.strip() or "Assessment"
338
- text_width = draw.textlength(course_name, fonts['title'])
339
- max_width = self.certificate_size[0] - 120 # Leave margins
340
- if text_width > max_width:
341
- words = course_name.split()
342
- lines = []
343
- current_line = []
344
- current_width = 0
345
- for word in words:
346
- word_width = draw.textlength(word + " ", fonts['title'])
347
- if current_width + word_width <= max_width:
348
- current_line.append(word)
349
- current_width += word_width
350
- else:
351
- lines.append(" ".join(current_line))
352
- current_line = [word]
353
- current_width = word_width
354
- if current_line:
355
- lines.append(" ".join(current_line))
356
- course_name = "\n".join(lines)
357
-
358
- draw.multiline_text((60, 200), course_name, font=fonts['title'], fill='#1C1D1F', spacing=10)
359
 
360
  # Add instructor info
361
- draw.text((60, 300), "Instructor", font=fonts['subtitle'], fill='#666666')
362
- draw.text((60, 330), "CertifyMe AI", font=fonts['text'], fill='#1C1D1F')
363
 
364
  # Add participant name (large)
365
  name = name.strip() or "Participant"
366
- draw.text((60, 420), name, font=fonts['name'], fill='#1C1D1F')
367
 
368
- # Add date and score info with spacing
369
  date_str = datetime.now().strftime("%b. %d, %Y")
370
 
371
  # Date section
372
- draw.text((60, 500), "Date", font=fonts['subtitle'], fill='#666666')
373
- draw.text((60, 530), date_str, font=fonts['text'], fill='#1C1D1F')
374
 
375
  # Score section
376
- draw.text((300, 500), "Score", font=fonts['subtitle'], fill='#666666')
377
- draw.text((300, 530), f"{float(score):.1f}%", font=fonts['text'], fill='#1C1D1F')
378
-
379
- # Footer section with certificate number and reference
380
  certificate_id = f"Certificate no: {datetime.now().strftime('%Y%m%d')}-{abs(hash(name)) % 10000:04d}"
381
  ref_number = f"Reference Number: {abs(hash(name + date_str)) % 10000:04d}"
382
 
383
- # Draw footer text aligned to left and right
384
  draw.text((60, 720), certificate_id, font=fonts['subtitle'], fill='#666666')
385
  draw.text((1140, 720), ref_number, font=fonts['subtitle'], fill='#666666', anchor="ra")
386
 
@@ -395,26 +376,52 @@ class CertificateGenerator:
395
  print(f"Error adding logo: {e}")
396
 
397
  def _add_photo(self, certificate: Image.Image, photo_path: str):
 
398
  try:
 
399
  photo = Image.open(photo_path)
 
 
 
 
400
  # Create circular mask
401
- size = (100, 100)
402
  mask = Image.new('L', size, 0)
403
  draw = ImageDraw.Draw(mask)
404
  draw.ellipse((0, 0, size[0], size[1]), fill=255)
405
 
406
- # Resize photo maintaining aspect ratio
407
- photo.thumbnail(size)
408
-
409
- # Create a circular photo
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
410
  output = Image.new('RGBA', size, (0, 0, 0, 0))
411
  output.paste(photo, (0, 0))
412
  output.putalpha(mask)
413
 
414
- # Position in top-right corner with padding
415
- certificate.paste(output, (1000, 50), mask=output)
 
 
 
 
 
416
  except Exception as e:
417
- print(f"Error adding photo: {e}")
418
 
419
  def generate(
420
  self,
@@ -424,27 +431,45 @@ class CertificateGenerator:
424
  company_logo: Optional[str] = None,
425
  participant_photo: Optional[str] = None
426
  ) -> str:
 
427
  try:
428
  certificate = self._create_base_certificate()
429
  draw = ImageDraw.Draw(certificate)
430
 
431
- # Add professional border
432
  self._add_professional_border(draw)
433
 
 
 
 
 
 
 
 
 
 
434
  fonts = self._load_fonts()
435
- self._add_content(draw, fonts, str(name), str(course_name), float(score))
436
 
 
 
 
 
 
 
 
 
 
 
 
437
  if company_logo:
438
  self._add_logo(certificate, company_logo)
439
 
440
- if participant_photo:
441
- self._add_photo(certificate, participant_photo)
442
-
443
  return self._save_certificate(certificate)
 
444
  except Exception as e:
445
  print(f"Error generating certificate: {e}")
446
  return None
447
-
448
  def _create_base_certificate(self) -> Image.Image:
449
  return Image.new('RGB', self.certificate_size, self.background_color)
450
 
 
328
  fonts: Dict[str, ImageFont.FreeTypeFont],
329
  name: str,
330
  course_name: str,
331
+ score: float,
332
+ y_offset: int = 140
333
  ):
334
+ """Add content with adjusted vertical positioning"""
335
  # Add "CERTIFICATE OF COMPLETION" text
336
+ draw.text((60, y_offset), "CERTIFICATE OF COMPLETION", font=fonts['subtitle'], fill='#666666')
337
 
338
  # Add course name (large and bold)
339
  course_name = course_name.strip() or "Assessment"
340
+ draw.text((60, y_offset + 60), course_name, font=fonts['title'], fill='#1C1D1F')
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
341
 
342
  # Add instructor info
343
+ draw.text((60, y_offset + 160), "Instructor", font=fonts['subtitle'], fill='#666666')
344
+ draw.text((60, y_offset + 190), "CertifyMe AI", font=fonts['text'], fill='#1C1D1F')
345
 
346
  # Add participant name (large)
347
  name = name.strip() or "Participant"
348
+ draw.text((60, y_offset + 280), name, font=fonts['name'], fill='#1C1D1F')
349
 
350
+ # Add date and score info
351
  date_str = datetime.now().strftime("%b. %d, %Y")
352
 
353
  # Date section
354
+ draw.text((60, y_offset + 360), "Date", font=fonts['subtitle'], fill='#666666')
355
+ draw.text((60, y_offset + 390), date_str, font=fonts['text'], fill='#1C1D1F')
356
 
357
  # Score section
358
+ draw.text((300, y_offset + 360), "Score", font=fonts['subtitle'], fill='#666666')
359
+ draw.text((300, y_offset + 390), f"{float(score):.1f}%", font=fonts['text'], fill='#1C1D1F')
360
+
361
+ # Footer section
362
  certificate_id = f"Certificate no: {datetime.now().strftime('%Y%m%d')}-{abs(hash(name)) % 10000:04d}"
363
  ref_number = f"Reference Number: {abs(hash(name + date_str)) % 10000:04d}"
364
 
 
365
  draw.text((60, 720), certificate_id, font=fonts['subtitle'], fill='#666666')
366
  draw.text((1140, 720), ref_number, font=fonts['subtitle'], fill='#666666', anchor="ra")
367
 
 
376
  print(f"Error adding logo: {e}")
377
 
378
  def _add_photo(self, certificate: Image.Image, photo_path: str):
379
+ """Add a circular profile photo centered at the top of the certificate"""
380
  try:
381
+ # Open and convert photo
382
  photo = Image.open(photo_path)
383
+
384
+ # Define size for circular photo
385
+ size = (120, 120) # Slightly larger size
386
+
387
  # Create circular mask
 
388
  mask = Image.new('L', size, 0)
389
  draw = ImageDraw.Draw(mask)
390
  draw.ellipse((0, 0, size[0], size[1]), fill=255)
391
 
392
+ # Resize photo maintaining aspect ratio and center crop
393
+ aspect = photo.width / photo.height
394
+ if aspect > 1:
395
+ # Width is greater, resize based on height
396
+ new_height = size[1]
397
+ new_width = int(new_height * aspect)
398
+ photo = photo.resize((new_width, new_height), Image.Resampling.LANCZOS)
399
+ # Center crop
400
+ left = (new_width - size[0]) // 2
401
+ photo = photo.crop((left, 0, left + size[0], size[1]))
402
+ else:
403
+ # Height is greater, resize based on width
404
+ new_width = size[0]
405
+ new_height = int(new_width / aspect)
406
+ photo = photo.resize((new_width, new_height), Image.Resampling.LANCZOS)
407
+ # Center crop
408
+ top = (new_height - size[1]) // 2
409
+ photo = photo.crop((0, top, size[0], top + size[1]))
410
+
411
+ # Create output image with transparency
412
  output = Image.new('RGBA', size, (0, 0, 0, 0))
413
  output.paste(photo, (0, 0))
414
  output.putalpha(mask)
415
 
416
+ # Calculate center position for photo
417
+ photo_x = (certificate.width - size[0]) // 2
418
+ photo_y = 40 # Distance from top
419
+
420
+ # Paste the circular photo
421
+ certificate.paste(output, (photo_x, photo_y), mask=output)
422
+
423
  except Exception as e:
424
+ print(f"Error adding photo: {str(e)}")
425
 
426
  def generate(
427
  self,
 
431
  company_logo: Optional[str] = None,
432
  participant_photo: Optional[str] = None
433
  ) -> str:
434
+ """Generate certificate with improved layout"""
435
  try:
436
  certificate = self._create_base_certificate()
437
  draw = ImageDraw.Draw(certificate)
438
 
439
+ # Add professional border first
440
  self._add_professional_border(draw)
441
 
442
+ # Add photo if provided (now centered)
443
+ if participant_photo:
444
+ self._add_photo(certificate, participant_photo)
445
+ # Adjust vertical spacing for content when photo is present
446
+ content_start_y = 180 # Increased to accommodate photo
447
+ else:
448
+ content_start_y = 140 # Original spacing when no photo
449
+
450
+ # Load fonts
451
  fonts = self._load_fonts()
 
452
 
453
+ # Add content with adjusted vertical position
454
+ self._add_content(
455
+ draw,
456
+ fonts,
457
+ str(name),
458
+ str(course_name),
459
+ float(score),
460
+ y_offset=content_start_y
461
+ )
462
+
463
+ # Add company logo if provided
464
  if company_logo:
465
  self._add_logo(certificate, company_logo)
466
 
 
 
 
467
  return self._save_certificate(certificate)
468
+
469
  except Exception as e:
470
  print(f"Error generating certificate: {e}")
471
  return None
472
+
473
  def _create_base_certificate(self) -> Image.Image:
474
  return Image.new('RGB', self.certificate_size, self.background_color)
475