Diversified into JPEG and PNG
This commit is contained in:
parent
410c9a6aaf
commit
90e5bd61ed
6 changed files with 183 additions and 61 deletions
BIN
.DS_Store
vendored
Normal file
BIN
.DS_Store
vendored
Normal file
Binary file not shown.
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -13,3 +13,5 @@ wheels/
|
|||
participants.csv
|
||||
cert.png
|
||||
CrimsonText-Bold.ttf
|
||||
certificates/
|
||||
cert.jpg
|
||||
|
|
87
jpeg.py
Normal file
87
jpeg.py
Normal file
|
@ -0,0 +1,87 @@
|
|||
import csv
|
||||
from PIL import Image, ImageDraw, ImageFont
|
||||
import os
|
||||
import concurrent.futures
|
||||
from functools import partial
|
||||
import time
|
||||
|
||||
def generate_certificate(template_path, font_path, name, output_path, index, font_size=50, text_color="black", y_offset=0):
|
||||
# Open the certificate template image
|
||||
with Image.open(template_path) as image:
|
||||
# For JPG compatibility, convert to RGB instead of RGBA
|
||||
image = image.convert("RGB")
|
||||
draw = ImageDraw.Draw(image)
|
||||
|
||||
# Load the specified font at the desired size
|
||||
font = ImageFont.truetype(font_path, font_size)
|
||||
|
||||
# Image dimensions
|
||||
image_width, image_height = image.size
|
||||
|
||||
# Calculate the bounding box for the text
|
||||
bbox = draw.textbbox((0, 0), name, font=font)
|
||||
text_width = bbox[2] - bbox[0]
|
||||
text_height = bbox[3] - bbox[1]
|
||||
|
||||
# Calculate coordinates for centered text
|
||||
x = (image_width - text_width) / 2
|
||||
y = (image_height - text_height) / 2 + y_offset
|
||||
|
||||
# Draw the text onto the certificate image
|
||||
draw.text((x, y), name, fill=text_color, font=font)
|
||||
|
||||
# Save the image as JPG
|
||||
output_filename = os.path.join(output_path, f"certificate_{index:03d}.jpg")
|
||||
image.save(output_filename, quality=95) # Set JPG quality
|
||||
print(f"Saved certificate for {name} as {output_filename}")
|
||||
|
||||
def process_certificate(row, i, template_path, font_path, output_folder, font_size, text_color, y_offset):
|
||||
name = row["name"].upper()
|
||||
generate_certificate(template_path, font_path, name, output_folder, i, font_size, text_color, y_offset)
|
||||
|
||||
def main():
|
||||
start_time = time.time()
|
||||
template_path = "cert.jpg" # Certificate template image filename (JPG format)
|
||||
font_path = "CrimsonText-Bold.ttf" # Path to the font file (TTF or OTF)
|
||||
csv_file = "participants.csv" # CSV file containing the name list
|
||||
output_folder = "certificates" # Output folder for generated certificates
|
||||
font_size = 92
|
||||
text_color = "black"
|
||||
y_offset = -82
|
||||
|
||||
# Optimal number of workers
|
||||
cpu_count = os.cpu_count()
|
||||
max_workers = min(32, (cpu_count + 4) if cpu_count is not None else 4)
|
||||
|
||||
if not os.path.exists(output_folder):
|
||||
os.makedirs(output_folder)
|
||||
|
||||
# Read all data from CSV at once
|
||||
with open(csv_file, newline='', encoding='utf-8') as csvfile:
|
||||
reader = csv.DictReader(csvfile)
|
||||
participants = list(reader)
|
||||
|
||||
# Create a partial function with all the fixed parameters
|
||||
process_func = partial(
|
||||
process_certificate,
|
||||
template_path=template_path,
|
||||
font_path=font_path,
|
||||
output_folder=output_folder,
|
||||
font_size=font_size,
|
||||
text_color=text_color,
|
||||
y_offset=y_offset
|
||||
)
|
||||
|
||||
# Process certificates in parallel
|
||||
with concurrent.futures.ThreadPoolExecutor(max_workers=max_workers) as executor:
|
||||
# Submit all tasks
|
||||
futures = [executor.submit(process_func, row, i) for i, row in enumerate(participants, start=1)]
|
||||
|
||||
# Wait for all to complete
|
||||
concurrent.futures.wait(futures)
|
||||
|
||||
elapsed_time = time.time() - start_time
|
||||
print(f"Completed generating {len(participants)} certificates in {elapsed_time:.2f} seconds")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
61
main.py
61
main.py
|
@ -1,61 +0,0 @@
|
|||
import csv
|
||||
from PIL import Image, ImageDraw, ImageFont
|
||||
|
||||
def generate_certificate(template_path, font_path, output_folder, name, font_size=50, text_color="black", y_offset=0):
|
||||
# Open the certificate template image
|
||||
with Image.open(template_path) as image:
|
||||
# Convert image to RGBA if not already (to support transparency if needed)
|
||||
image = image.convert("RGBA")
|
||||
draw = ImageDraw.Draw(image)
|
||||
|
||||
# Load the Inter Semi Bold font at the desired size
|
||||
font = ImageFont.truetype(font_path, font_size)
|
||||
|
||||
# Get image dimensions
|
||||
image_width, image_height = image.size
|
||||
|
||||
# Determine the size of the text to be drawn
|
||||
# Note: textsize may not be pixel-perfect for all fonts; textbbox is available in newer Pillow versions.
|
||||
text_width, text_height = draw.textsize(name, font=font)
|
||||
|
||||
# Calculate coordinates for centered text
|
||||
x = (image_width - text_width) / 2
|
||||
# Adjust y coordinate; here we center vertically then apply optional y_offset (e.g., for slight nudging)
|
||||
y = (image_height - text_height) / 2 + y_offset
|
||||
|
||||
# Draw the name onto the certificate image
|
||||
draw.text((x, y), name, fill=text_color, font=font)
|
||||
|
||||
return image
|
||||
|
||||
def main():
|
||||
# File paths and settings -- update these as needed
|
||||
template_path = "cert" # Path to your certificate image template
|
||||
font_path = "CrimsonText-Bold.ttf" # Path to the Inter Semi Bold TTF file
|
||||
csv_file = "names.csv" # Path to the CSV file containing names
|
||||
output_folder = "certificates" # Folder to save generated certificate images
|
||||
font_size = 50 # Adjust font size based on your template
|
||||
text_color = "black" # Text color; change as necessary
|
||||
y_offset = 0 # Adjust vertical offset if the text is not in the desired location
|
||||
|
||||
# Create output folder if it doesn't exist
|
||||
import os
|
||||
if not os.path.exists(output_folder):
|
||||
os.makedirs(output_folder)
|
||||
|
||||
# Read names from CSV
|
||||
with open(csv_file, newline='', encoding='utf-8') as csvfile:
|
||||
reader = csv.DictReader(csvfile)
|
||||
for i, row in enumerate(reader, start=1):
|
||||
# Get name from first column (index 0)
|
||||
name = row[0] # First column contains the names
|
||||
# Generate a personalized certificate image with the name
|
||||
certificate_image = generate_certificate(template_path, font_path, output_folder, name, font_size, text_color, y_offset)
|
||||
|
||||
# Save the certificate with a unique filename (you could also include the name in the filename)
|
||||
output_filename = os.path.join(output_folder, f"certificate_{i:03d}.png")
|
||||
certificate_image.save(output_filename)
|
||||
print(f"Saved certificate for {name} as {output_filename}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
86
png.py
Normal file
86
png.py
Normal file
|
@ -0,0 +1,86 @@
|
|||
import csv
|
||||
from PIL import Image, ImageDraw, ImageFont
|
||||
import os
|
||||
import concurrent.futures
|
||||
from functools import partial
|
||||
import time
|
||||
|
||||
def generate_certificate(template_path, font_path, name, output_path, index, font_size=50, text_color="black", y_offset=0):
|
||||
# Open the certificate template image
|
||||
with Image.open(template_path) as image:
|
||||
image = image.convert("RGBA")
|
||||
draw = ImageDraw.Draw(image)
|
||||
|
||||
# Load the specified font at the desired size
|
||||
font = ImageFont.truetype(font_path, font_size)
|
||||
|
||||
# Image dimensions
|
||||
image_width, image_height = image.size
|
||||
|
||||
# Calculate the bounding box for the text
|
||||
bbox = draw.textbbox((0, 0), name, font=font)
|
||||
text_width = bbox[2] - bbox[0]
|
||||
text_height = bbox[3] - bbox[1]
|
||||
|
||||
# Calculate coordinates for centered text
|
||||
x = (image_width - text_width) / 2
|
||||
y = (image_height - text_height) / 2 + y_offset
|
||||
|
||||
# Draw the text onto the certificate image
|
||||
draw.text((x, y), name, fill=text_color, font=font)
|
||||
|
||||
# Save the image directly
|
||||
output_filename = os.path.join(output_path, f"certificate_{index:03d}.png")
|
||||
image.save(output_filename)
|
||||
print(f"Saved certificate for {name} as {output_filename}")
|
||||
|
||||
def process_certificate(row, i, template_path, font_path, output_folder, font_size, text_color, y_offset):
|
||||
name = row["name"].upper()
|
||||
generate_certificate(template_path, font_path, name, output_folder, i, font_size, text_color, y_offset)
|
||||
|
||||
def main():
|
||||
start_time = time.time()
|
||||
template_path = "cert.png" # Certificate template image filename
|
||||
font_path = "CrimsonText-Bold.ttf" # Path to the font file (TTF or OTF)
|
||||
csv_file = "participants.csv" # CSV file containing the name list
|
||||
output_folder = "certificates" # Output folder for generated certificates
|
||||
font_size = 92
|
||||
text_color = "black"
|
||||
y_offset = -82
|
||||
|
||||
# Optimal number of workers
|
||||
cpu_count = os.cpu_count()
|
||||
max_workers = min(32, (cpu_count + 4) if cpu_count is not None else 4)
|
||||
|
||||
if not os.path.exists(output_folder):
|
||||
os.makedirs(output_folder)
|
||||
|
||||
# Read all data from CSV at once
|
||||
with open(csv_file, newline='', encoding='utf-8') as csvfile:
|
||||
reader = csv.DictReader(csvfile)
|
||||
participants = list(reader)
|
||||
|
||||
# Create a partial function with all the fixed parameters
|
||||
process_func = partial(
|
||||
process_certificate,
|
||||
template_path=template_path,
|
||||
font_path=font_path,
|
||||
output_folder=output_folder,
|
||||
font_size=font_size,
|
||||
text_color=text_color,
|
||||
y_offset=y_offset
|
||||
)
|
||||
|
||||
# Process certificates in parallel
|
||||
with concurrent.futures.ThreadPoolExecutor(max_workers=max_workers) as executor:
|
||||
# Submit all tasks
|
||||
futures = [executor.submit(process_func, row, i) for i, row in enumerate(participants, start=1)]
|
||||
|
||||
# Wait for all to complete
|
||||
concurrent.futures.wait(futures)
|
||||
|
||||
elapsed_time = time.time() - start_time
|
||||
print(f"Completed generating {len(participants)} certificates in {elapsed_time:.2f} seconds")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
8
uv.lock
generated
Normal file
8
uv.lock
generated
Normal file
|
@ -0,0 +1,8 @@
|
|||
version = 1
|
||||
revision = 1
|
||||
requires-python = ">=3.12"
|
||||
|
||||
[[package]]
|
||||
name = "img-cert-maker"
|
||||
version = "0.1.0"
|
||||
source = { virtual = "." }
|
Loading…
Add table
Reference in a new issue