saifisvibinn
Initial commit: Certificate Generator App with FastAPI and React
d19cc77
import fitz
import os
def hex_to_rgb(hex_color):
hex_color = hex_color.lstrip('#')
return tuple(int(hex_color[i:i+2], 16)/255 for i in (0, 2, 4))
def generate_certificate_pdf(name, template_bytes, output_path, name_color_hex="#000000", font_size=60, x=None, y=None, fontname="helv", fontfile=None):
"""
Generates a certificate PDF by overlaying text.
If x and y are provided, uses those coordinates.
Otherwise, searches for <fullName> placeholder.
"""
doc = fitz.open(stream=template_bytes, filetype="pdf")
name_color = hex_to_rgb(name_color_hex)
for page in doc:
target_x, target_y = x, y
# If no manual coordinates, try to find placeholder
if target_x is None or target_y is None:
found = False
for inst in page.search_for("<fullName>"):
rect = fitz.Rect(inst)
# Calculate center of the placeholder
name_width = fitz.get_text_length(name, fontsize=font_size, fontname=fontname, fontfile=fontfile)
target_x = rect.x0 + (rect.width - name_width) / 2
# For Y: use baseline position (rect.y1 is bottom of box)
target_y = rect.y0 + rect.height / 2 + font_size / 3
found = True
break
if not found:
# Fallback default if nothing found and no coordinates
page_width = page.rect.width
page_height = page.rect.height
rect_width = int(page_width * 0.6)
x0_default = int((page_width - rect_width) / 2)
name_width = fitz.get_text_length(name, fontsize=font_size, fontname=fontname, fontfile=fontfile)
target_x = x0_default + (rect_width - name_width) / 2
# Place at 60% down the page
target_y = page_height * 0.6
# Insert text (ensure coordinates are within page bounds)
if target_x is not None and target_y is not None:
# Calculate text dimensions for centering
if fontfile and os.path.exists(fontfile):
font = fitz.Font(fontfile=fontfile)
else:
font = fitz.Font(fontname)
name_width = font.text_length(name, fontsize=font_size)
# Adjust x to center the text
insert_x = target_x - (name_width / 2)
# Adjust y from center to baseline (approximate)
# Center is target_y. Baseline is typically target_y + font_size/3
insert_y = target_y + (font_size / 3)
# Clamp coordinates to page bounds
page_rect = page.rect
insert_x = max(10, min(insert_x, page_rect.width - name_width - 10))
insert_y = max(font_size, min(insert_y, page_rect.height - 10))
page.insert_text(
(insert_x, insert_y),
name,
fontsize=font_size,
color=name_color,
fontname=fontname,
fontfile=fontfile
)
doc.save(output_path)
doc.close()
return output_path
def get_pdf_preview_image(template_bytes, name="Sample Name", name_color_hex="#000000", font_size=60, x=None, y=None, fontname="helv", fontfile=None):
"""
Generates a preview image (PNG) of the first page of the certificate.
Returns bytes of the PNG image.
"""
doc = fitz.open(stream=template_bytes, filetype="pdf")
name_color = hex_to_rgb(name_color_hex)
page = doc[0] # Preview only first page
target_x, target_y = x, y
# Logic similar to generation, but just for one page and return image
if target_x is None or target_y is None:
found = False
for inst in page.search_for("<fullName>"):
rect = fitz.Rect(inst)
name_width = fitz.get_text_length(name, fontsize=font_size, fontname=fontname, fontfile=fontfile)
target_x = rect.x0 + (rect.width - name_width) / 2
target_y = rect.y0 + rect.height / 2 + font_size / 3
found = True
break
if not found:
page_width = page.rect.width
page_height = page.rect.height
rect_width = int(page_width * 0.6)
x0_default = int((page_width - rect_width) / 2)
name_width = fitz.get_text_length(name, fontsize=font_size, fontname=fontname, fontfile=fontfile)
target_x = x0_default + (rect_width - name_width) / 2
import fitz
import os
def hex_to_rgb(hex_color):
hex_color = hex_color.lstrip('#')
return tuple(int(hex_color[i:i+2], 16)/255 for i in (0, 2, 4))
def generate_certificate_pdf(name, template_bytes, output_path, name_color_hex="#000000", font_size=60, x=None, y=None, fontname="helv", fontfile=None):
"""
Generates a certificate PDF by overlaying text.
If x and y are provided, uses those coordinates.
Otherwise, searches for <fullName> placeholder.
"""
doc = fitz.open(stream=template_bytes, filetype="pdf")
name_color = hex_to_rgb(name_color_hex)
for page in doc:
target_x, target_y = x, y
# If no manual coordinates, try to find placeholder
if target_x is None or target_y is None:
found = False
for inst in page.search_for("<fullName>"):
rect = fitz.Rect(inst)
# Calculate center of the placeholder
if fontfile and os.path.exists(fontfile):
font = fitz.Font(fontfile=fontfile)
else:
font = fitz.Font(fontname)
name_width = font.text_length(name, fontsize=font_size)
target_x = rect.x0 + (rect.width - name_width) / 2
# For Y: use baseline position (rect.y1 is bottom of box)
target_y = rect.y0 + rect.height / 2 + font_size / 3
found = True
break
if not found:
# Fallback default if nothing found and no coordinates
page_width = page.rect.width
page_height = page.rect.height
rect_width = int(page_width * 0.6)
x0_default = int((page_width - rect_width) / 2)
if fontfile and os.path.exists(fontfile):
font = fitz.Font(fontfile=fontfile)
else:
font = fitz.Font(fontname)
name_width = font.text_length(name, fontsize=font_size)
target_x = x0_default + (rect_width - name_width) / 2
# Place at 60% down the page
target_y = page_height * 0.6
# Insert text (ensure coordinates are within page bounds)
if target_x is not None and target_y is not None:
# Calculate text dimensions for centering
if fontfile and os.path.exists(fontfile):
font = fitz.Font(fontfile=fontfile)
else:
font = fitz.Font(fontname)
name_width = font.text_length(name, fontsize=font_size)
# Adjust x to center the text
insert_x = target_x - (name_width / 2)
# Adjust y from center to baseline (approximate)
# Center is target_y. Baseline is typically target_y + font_size/3
insert_y = target_y + (font_size / 3)
# Clamp coordinates to page bounds
page_rect = page.rect
insert_x = max(10, min(insert_x, page_rect.width - name_width - 10))
insert_y = max(font_size, min(insert_y, page_rect.height - 10))
page.insert_text(
(insert_x, insert_y),
name,
fontsize=font_size,
color=name_color,
fontname=fontname,
fontfile=fontfile
)
doc.save(output_path)
doc.close()
return output_path
def get_pdf_preview_image(template_bytes, name="Sample Name", name_color_hex="#000000", font_size=60, x=None, y=None, fontname="helv", fontfile=None):
"""
Generates a preview image (PNG) of the first page of the certificate.
Returns bytes of the PNG image.
"""
doc = fitz.open(stream=template_bytes, filetype="pdf")
name_color = hex_to_rgb(name_color_hex)
page = doc[0] # Preview only first page
target_x, target_y = x, y
# Logic similar to generation, but just for one page and return image
if target_x is None or target_y is None:
found = False
for inst in page.search_for("<fullName>"):
rect = fitz.Rect(inst)
if fontfile and os.path.exists(fontfile):
font = fitz.Font(fontfile=fontfile)
else:
font = fitz.Font(fontname)
name_width = font.text_length(name, fontsize=font_size)
target_x = rect.x0 + (rect.width - name_width) / 2
target_y = rect.y0 + rect.height / 2 + font_size / 3
found = True
break
if not found:
page_width = page.rect.width
page_height = page.rect.height
rect_width = int(page_width * 0.6)
x0_default = int((page_width - rect_width) / 2)
if fontfile and os.path.exists(fontfile):
font = fitz.Font(fontfile=fontfile)
else:
font = fitz.Font(fontname)
name_width = font.text_length(name, fontsize=font_size)
target_x = x0_default + (rect_width - name_width) / 2
target_y = page_height * 0.6
if target_x is not None and target_y is not None:
# Calculate text dimensions for centering
if fontfile and os.path.exists(fontfile):
font = fitz.Font(fontfile=fontfile)
else:
font = fitz.Font(fontname)
name_width = font.text_length(name, fontsize=font_size)
# Adjust x to center the text
insert_x = target_x - (name_width / 2)
# Adjust y from center to baseline (approximate)
# Center is target_y. Baseline is typically target_y + font_size/3
insert_y = target_y + (font_size / 3)
# Clamp coordinates to page bounds
page_rect = page.rect
insert_x = max(10, min(insert_x, page_rect.width - name_width - 10))
insert_y = max(font_size, min(insert_y, page_rect.height - 10))
page.insert_text(
(insert_x, insert_y),
name,
fontsize=font_size,
color=name_color,
fontname=fontname,
fontfile=fontfile
)
pix = page.get_pixmap()
img_bytes = pix.tobytes("png")
doc.close()
return img_bytes