Spaces:
Sleeping
Sleeping
| 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 | |